Batch: pack Batch param to facilitate migration between DPIC/PCIe (#474)
To facilitate Batch migration between DPIC and PCIe, we pack Batch param to an aligned array, and parse it inside software. In transmission, we only need to pass single hardware data, as svBitVecVal[] or uint8_t[], and then view it as generated struct in software. Note we put also step inside BatchInfo and call simv_nstep inside, Step will be also exposed to Top all the time for Verilator and Timeout Check. We also add isFPGA to GatewayConfig and generate BYTELEN macro for FPGA. Co-authored-by: Kami <fengkehan@bosc.ac.cn>
This commit is contained in:
parent
4245818be8
commit
fbd72a2e71
|
@ -240,7 +240,7 @@ jobs:
|
|||
make difftest_verilog PROFILE=../build/generated-src/difftest_profile.json NUMCORES=1 CONFIG=EL MFC=1
|
||||
make emu WITH_CHISELDB=0 WITH_CONSTANTIN=0 IOTRACE_ZSTD=1 -j2
|
||||
./build/emu -b 0 -e 0 -i ../ready-to-run/microbench.bin --diff ../ready-to-run/riscv64-nemu-interpreter-so --iotrace-name ../iotrace
|
||||
|
||||
|
||||
test-difftest-fuzzing:
|
||||
# This test runs on ubuntu-20.04 for two reasons:
|
||||
# (1) riscv-arch-test can be built with riscv-linux-gnu toolchain 9.4.0,
|
||||
|
@ -389,14 +389,14 @@ jobs:
|
|||
./build/simv +workload=./ready-to-run/microbench.bin +e=0 +no-diff +max-cycles=100000
|
||||
./build/simv +workload=./ready-to-run/microbench.bin +e=0 +diff=./ready-to-run/riscv64-nemu-interpreter-so
|
||||
|
||||
- name: Verilator Build with VCS Top (with DutZone GlobalEnable Squash Replay Batch PerfCnt)
|
||||
- name: Verilator Build with VCS Top (with GlobalEnable Squash Replay Batch PerfCnt)
|
||||
run: |
|
||||
cd $GITHUB_WORKSPACE/../xs-env
|
||||
source ./env.sh
|
||||
cd $GITHUB_WORKSPACE/../xs-env/NutShell
|
||||
source ./env.sh
|
||||
make clean
|
||||
make simv MILL_ARGS="--difftest-config ZESRBP" DIFFTEST_PERFCNT=1 VCS=verilator -j2
|
||||
make simv MILL_ARGS="--difftest-config ESRBP" DIFFTEST_PERFCNT=1 VCS=verilator -j2
|
||||
./build/simv +workload=./ready-to-run/microbench.bin +e=0 +no-diff +max-cycles=100000
|
||||
./build/simv +workload=./ready-to-run/microbench.bin +e=0 +diff=./ready-to-run/riscv64-nemu-interpreter-so
|
||||
|
||||
|
|
|
@ -41,8 +41,8 @@ class BatchIO(dataType: UInt, infoType: UInt) extends Bundle {
|
|||
val info = infoType
|
||||
}
|
||||
|
||||
class BatchOutput(data: UInt, info: UInt, config: GatewayConfig) extends Bundle {
|
||||
val io = new BatchIO(chiselTypeOf(data), chiselTypeOf(info))
|
||||
class BatchOutput(dataType: UInt, infoType: UInt, config: GatewayConfig) extends Bundle {
|
||||
val io = new BatchIO(dataType, infoType)
|
||||
val enable = Bool()
|
||||
val step = UInt(config.stepWidth.W)
|
||||
}
|
||||
|
@ -131,9 +131,7 @@ class BatchEndpoint(bundles: Seq[Valid[DifftestBundle]], config: GatewayConfig,
|
|||
}
|
||||
|
||||
val BatchInterval = WireInit(0.U.asTypeOf(new BatchInfo))
|
||||
val BatchFinish = WireInit(0.U.asTypeOf(new BatchInfo))
|
||||
BatchInterval.id := Batch.getTemplate.length.U
|
||||
BatchFinish.id := (Batch.getTemplate.length + 1).U
|
||||
val step_data = dataCollect_vec.last
|
||||
val step_info = Cat(infoCollect_vec.last, BatchInterval.asUInt)
|
||||
val step_data_len = dataLenCollect_vec.last
|
||||
|
@ -188,7 +186,10 @@ class BatchEndpoint(bundles: Seq[Valid[DifftestBundle]], config: GatewayConfig,
|
|||
}
|
||||
}
|
||||
|
||||
val out = IO(Output(new BatchOutput(state_data, state_info, config)))
|
||||
val BatchFinish = Wire(new BatchInfo)
|
||||
BatchFinish.id := (Batch.getTemplate.length + 1).U
|
||||
BatchFinish.num := state_step_cnt
|
||||
val out = IO(Output(new BatchOutput(chiselTypeOf(state_data), chiselTypeOf(state_info), config)))
|
||||
out.io.data := state_data
|
||||
out.io.info := state_info | BatchFinish.asUInt << (state_info_len << 3)
|
||||
out.enable := should_tick
|
||||
|
|
|
@ -30,23 +30,28 @@ abstract class DPICBase(config: GatewayConfig) extends ExtModule with HasExtModu
|
|||
val clock = IO(Input(Clock()))
|
||||
val enable = IO(Input(Bool()))
|
||||
val dut_zone = Option.when(config.hasDutZone)(IO(Input(UInt(config.dutZoneWidth.W))))
|
||||
val step = Option.when(config.hasInternalStep)(IO(Input(UInt(config.stepWidth.W))))
|
||||
|
||||
def getDirectionString(data: Data): String = {
|
||||
if (DataMirror.directionOf(data) == ActualDirection.Input) "input " else "output"
|
||||
}
|
||||
|
||||
def getDPICArgString(argName: String, data: Data, isC: Boolean): String = {
|
||||
def getDPICArgString(argName: String, data: Data, isC: Boolean, isDPIC: Boolean = true): String = {
|
||||
val typeString = data.getWidth match {
|
||||
case 1 => if (isC) "uint8_t" else "bit"
|
||||
case width if width > 1 && width <= 8 => if (isC) "uint8_t" else "byte"
|
||||
case width if width > 8 && width <= 32 => if (isC) "uint32_t" else "int"
|
||||
case width if width > 32 && width <= 64 => if (isC) "uint64_t" else "longint"
|
||||
case width if width > 64 => if (isC) "const svBitVecVal" else s"bit[${width - 1}:0]"
|
||||
case width if width > 64 =>
|
||||
if (isC)
|
||||
if (isDPIC) "const svBitVecVal" else "uint8_t"
|
||||
else s"bit[${width - 1}:0]"
|
||||
}
|
||||
if (isC) {
|
||||
val width = data.getWidth
|
||||
if (width > 64) f"$typeString $argName[${width / 32}]" else f"$typeString%-8s $argName"
|
||||
val suffix = if (width > 64) {
|
||||
if (isDPIC) s"[${(width + 31) / 32}]" else s"[${(width + 7) / 8}]"
|
||||
} else ""
|
||||
f"$typeString%-8s $argName$suffix"
|
||||
} else {
|
||||
val directionString = getDirectionString(data)
|
||||
f"$directionString $typeString%8s $argName"
|
||||
|
@ -63,7 +68,6 @@ abstract class DPICBase(config: GatewayConfig) extends ExtModule with HasExtModu
|
|||
def modPorts: Seq[Seq[(String, Data)]] = {
|
||||
var ports = commonPorts
|
||||
if (config.hasDutZone) ports ++= Seq(("dut_zone", dut_zone.get))
|
||||
if (config.hasInternalStep) ports ++= Seq(("step", step.get))
|
||||
ports.map(Seq(_))
|
||||
}
|
||||
|
||||
|
@ -74,7 +78,7 @@ abstract class DPICBase(config: GatewayConfig) extends ExtModule with HasExtModu
|
|||
def dpicFuncProto: String =
|
||||
s"""
|
||||
|extern "C" void $dpicFuncName (
|
||||
| ${dpicFuncArgs.flatten.map(arg => getDPICArgString(arg._1, arg._2, true)).mkString(",\n ")}
|
||||
| ${dpicFuncArgs.flatten.map(arg => getDPICArgString(arg._1, arg._2, true, !config.isFPGA)).mkString(",\n ")}
|
||||
|)""".stripMargin
|
||||
def getPacketDecl(gen: DifftestBundle, prefix: String, config: GatewayConfig): String = {
|
||||
val dut_zone = if (config.hasDutZone) "dut_zone" else "0"
|
||||
|
@ -94,20 +98,12 @@ abstract class DPICBase(config: GatewayConfig) extends ExtModule with HasExtModu
|
|||
|""".stripMargin
|
||||
}
|
||||
|
||||
def internalStep: String = if (config.hasInternalStep)
|
||||
"""
|
||||
|extern void simv_nstep(uint8_t step);
|
||||
|simv_nstep(step);
|
||||
|""".stripMargin
|
||||
else ""
|
||||
|
||||
def dpicFunc: String =
|
||||
s"""
|
||||
|$dpicFuncProto {
|
||||
| if (!diffstate_buffer) return;
|
||||
|$perfCnt
|
||||
| ${dpicFuncAssigns.mkString("\n ")}
|
||||
| $internalStep
|
||||
|}
|
||||
|""".stripMargin
|
||||
|
||||
|
@ -192,7 +188,7 @@ class DPIC[T <: DifftestBundle](gen: T, config: GatewayConfig) extends DPICBase(
|
|||
}
|
||||
|
||||
class DPICBatch(template: Seq[DifftestBundle], batchIO: BatchIO, config: GatewayConfig) extends DPICBase(config) {
|
||||
val io = IO(Input(batchIO))
|
||||
val io = IO(Input(UInt(batchIO.getWidth.W)))
|
||||
|
||||
def getDPICBundleUnpack(gen: DifftestBundle): String = {
|
||||
val unpack = ListBuffer.empty[String]
|
||||
|
@ -210,7 +206,7 @@ class DPICBatch(template: Seq[DifftestBundle], batchIO: BatchIO, config: Gateway
|
|||
unpack.toSeq.mkString("\n ")
|
||||
}
|
||||
|
||||
override def modPorts = super.modPorts ++ Seq(Seq(("io_data", io.data)), Seq(("io_info", io.info)))
|
||||
override def modPorts = super.modPorts ++ Seq(Seq(("io", io)))
|
||||
|
||||
override def desiredName: String = "DifftestBatch"
|
||||
override def dpicFuncAssigns: Seq[String] = {
|
||||
|
@ -225,34 +221,42 @@ class DPICBatch(template: Seq[DifftestBundle], batchIO: BatchIO, config: Gateway
|
|||
""".stripMargin
|
||||
}.mkString("")
|
||||
|
||||
def parseInfo(io_info: Data): (String, Int) = {
|
||||
def parse(gen: BatchIO): (String, Int) = {
|
||||
val info = new BatchInfo
|
||||
val infoLen = io_info.getWidth / info.getWidth
|
||||
val infoDecl =
|
||||
val infoLen = gen.info.getWidth / info.getWidth
|
||||
val structDecl =
|
||||
s"""
|
||||
| static struct {
|
||||
| ${info.elements.toSeq.map { case (name, data) => getDPICArgString(name, data, true) }
|
||||
| typedef struct {
|
||||
| ${info.elements.toSeq.map { case (name, data) => getDPICArgString(name, data, true, false) }
|
||||
.mkString(";\n ")};
|
||||
| } info[$infoLen];
|
||||
| } BatchInfo;
|
||||
| typedef struct {
|
||||
| ${gen.elements.toSeq.map { case (name, data) =>
|
||||
if (name == "info") s"BatchInfo info[$infoLen]" else getDPICArgString(name, data, true, false)
|
||||
}.mkString(";\n ")};
|
||||
| } BatchPack;
|
||||
| BatchPack* batch = (BatchPack*)io;
|
||||
| BatchInfo* info = batch->info;
|
||||
| uint8_t* data = batch->data;
|
||||
|""".stripMargin
|
||||
(infoDecl, infoLen)
|
||||
(structDecl, infoLen)
|
||||
}
|
||||
val (infoDecl, infoLen) = parseInfo(io.info)
|
||||
val (batchDecl, infoLen) = parse(batchIO)
|
||||
Seq(s"""
|
||||
| enum DifftestBundleType {
|
||||
| ${bundleEnum.mkString(",\n ")}
|
||||
| };
|
||||
|
|
||||
| uint64_t offset = 0;
|
||||
| extern void simv_nstep(uint8_t step);
|
||||
| uint32_t dut_index = 0;
|
||||
| $infoDecl
|
||||
| memcpy(info, io_info, sizeof(info));
|
||||
| uint8_t* data = (uint8_t*)io_data;
|
||||
| $batchDecl
|
||||
| for (int i = 0; i < $infoLen; i++) {
|
||||
| uint8_t id = info[i].id;
|
||||
| uint8_t num = info[i].num;
|
||||
| uint32_t coreid, index, address;
|
||||
| if (id == BatchFinish) {
|
||||
|#ifdef CONFIG_DIFFTEST_INTERNAL_STEP
|
||||
| simv_nstep(num);
|
||||
|#endif // CONFIG_DIFFTEST_INTERNAL_STEP
|
||||
| break;
|
||||
| }
|
||||
| else if (id == BatchInterval && i != 0) {
|
||||
|
@ -288,8 +292,7 @@ private class DummyDPICBatchWrapper(
|
|||
dpic.clock := clock
|
||||
dpic.enable := control.enable
|
||||
if (config.hasDutZone) dpic.dut_zone.get := control.dut_zone.get
|
||||
if (config.hasInternalStep) dpic.step.get := control.step.get
|
||||
dpic.io := io
|
||||
dpic.io := io.asUInt
|
||||
}
|
||||
|
||||
object DPIC {
|
||||
|
|
|
@ -46,13 +46,14 @@ case class GatewayConfig(
|
|||
traceLoad: Boolean = false,
|
||||
hierarchicalWiring: Boolean = false,
|
||||
exitOnAssertions: Boolean = false,
|
||||
isFPGA: Boolean = false,
|
||||
) {
|
||||
def dutZoneSize: Int = if (hasDutZone) 2 else 1
|
||||
def dutZoneWidth: Int = log2Ceil(dutZoneSize)
|
||||
def dutBufLen: Int = if (isBatch) batchSize else 1
|
||||
def maxStep: Int = if (isBatch) batchSize else 1
|
||||
def stepWidth: Int = log2Ceil(maxStep + 1)
|
||||
def batchArgByteLen: (Int, Int) = if (isNonBlock) (3900, 92) else (7800, 192)
|
||||
def batchArgByteLen: (Int, Int) = if (isNonBlock) (3900, 100) else (7800, 200)
|
||||
def hasDeferredResult: Boolean = isNonBlock || hasInternalStep
|
||||
def needTraceInfo: Boolean = hasReplay
|
||||
def needEndpoint: Boolean =
|
||||
|
@ -64,7 +65,12 @@ case class GatewayConfig(
|
|||
macros += s"CONFIG_DIFFTEST_${style.toUpperCase}"
|
||||
macros += s"CONFIG_DIFFTEST_ZONESIZE $dutZoneSize"
|
||||
macros += s"CONFIG_DIFFTEST_BUFLEN $dutBufLen"
|
||||
if (isBatch) macros ++= Seq("CONFIG_DIFFTEST_BATCH", s"CONFIG_DIFFTEST_BATCH_SIZE ${batchSize}")
|
||||
if (isBatch)
|
||||
macros ++= Seq(
|
||||
"CONFIG_DIFFTEST_BATCH",
|
||||
s"CONFIG_DIFFTEST_BATCH_SIZE ${batchSize}",
|
||||
s"CONFIG_DIFFTEST_BATCH_BYTELEN ${batchArgByteLen._1 + batchArgByteLen._2}",
|
||||
)
|
||||
if (isSquash) macros ++= Seq("CONFIG_DIFFTEST_SQUASH", s"CONFIG_DIFFTEST_SQUASH_STAMPSIZE 4096") // Stamp Width 12
|
||||
if (hasReplay) macros ++= Seq("CONFIG_DIFFTEST_REPLAY", s"CONFIG_DIFFTEST_REPLAY_SIZE ${replaySize}")
|
||||
if (hasDeferredResult) macros += "CONFIG_DIFFTEST_DEFERRED_RESULT"
|
||||
|
@ -84,6 +90,7 @@ case class GatewayConfig(
|
|||
def check(): Unit = {
|
||||
if (hasReplay) require(isSquash)
|
||||
if (hasInternalStep) require(isBatch)
|
||||
if (isBatch) require(!hasDutZone)
|
||||
// TODO: support dump and load together
|
||||
require(!(traceDump && traceLoad))
|
||||
}
|
||||
|
@ -127,6 +134,7 @@ object Gateway {
|
|||
case 'L' => config = config.copy(traceLoad = true)
|
||||
case 'H' => config = config.copy(hierarchicalWiring = true)
|
||||
case 'X' => config = config.copy(exitOnAssertions = true)
|
||||
case 'F' => config = config.copy(isFPGA = true)
|
||||
case x => println(s"Unknown Gateway Config $x")
|
||||
}
|
||||
config.check()
|
||||
|
@ -224,18 +232,8 @@ class GatewayEndpoint(instanceWithDelay: Seq[(DifftestBundle, Int)], config: Gat
|
|||
|
||||
if (config.isBatch) {
|
||||
val batch = Batch(squashed, config)
|
||||
if (config.hasInternalStep) {
|
||||
step := batch.step
|
||||
control.step.get := batch.step
|
||||
} else {
|
||||
step := RegNext(batch.step, 0.U)
|
||||
}
|
||||
step := RegNext(batch.step, 0.U) // expose Batch step to check timeout
|
||||
control.enable := batch.enable
|
||||
if (config.hasDutZone) {
|
||||
zoneControl.get.enable := batch.enable
|
||||
control.dut_zone.get := zoneControl.get.dut_zone
|
||||
}
|
||||
|
||||
GatewaySink.batch(Batch.getTemplate, control, batch.io, config)
|
||||
} else {
|
||||
val squashed_enable = VecInit(squashed.map(_.valid).toSeq).asUInt.orR
|
||||
|
@ -281,7 +279,6 @@ object GatewaySink {
|
|||
class GatewaySinkControl(config: GatewayConfig) extends Bundle {
|
||||
val enable = Bool()
|
||||
val dut_zone = Option.when(config.hasDutZone)(UInt(config.dutZoneWidth.W))
|
||||
val step = Option.when(config.hasInternalStep)(UInt(config.stepWidth.W))
|
||||
}
|
||||
|
||||
object Preprocess {
|
||||
|
|
|
@ -44,8 +44,11 @@ void difftest_perfcnt_finish(uint64_t cycleCnt) {
|
|||
diffstate_perfcnt_finish(perf_run_msec);
|
||||
printf(">>> Other Difftest Func\n");
|
||||
const char *func_name[DIFFTEST_PERF_NUM] = {
|
||||
"simv_nstep", "difftest_ram_read", "difftest_ram_write", "flash_read", "sd_set_addr", "sd_read",
|
||||
"jtag_tick", "put_pixel", "vmem_sync", "pte_helper", "amo_helper",
|
||||
#ifndef CONFIG_DIFFTEST_INTERNAL_STEP
|
||||
"simv_nstep",
|
||||
#endif // CONFIG_DIFFTEST_INTERNAL_STEP
|
||||
"difftest_ram_read", "difftest_ram_write", "flash_read", "sd_set_addr", "sd_read",
|
||||
"jtag_tick", "put_pixel", "vmem_sync", "pte_helper", "amo_helper",
|
||||
};
|
||||
for (int i = 0; i < DIFFTEST_PERF_NUM; i++) {
|
||||
difftest_perfcnt_print(func_name[i], difftest_calls[i], difftest_bytes[i], perf_run_msec);
|
||||
|
|
|
@ -27,7 +27,9 @@ static inline void difftest_perfcnt_print(const char *name, long long calls, lon
|
|||
void difftest_perfcnt_init();
|
||||
void difftest_perfcnt_finish(uint64_t cycleCnt);
|
||||
enum DIFFTEST_PERF {
|
||||
#ifndef CONFIG_DIFFTEST_INTERNAL_STEP
|
||||
perf_simv_nstep,
|
||||
#endif // CONFIG_DIFFTEST_INTERNAL_STEP
|
||||
perf_difftest_ram_read,
|
||||
perf_difftest_ram_write,
|
||||
perf_flash_read,
|
||||
|
|
Loading…
Reference in New Issue