diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b758116c..ad92367a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -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 diff --git a/src/main/scala/Batch.scala b/src/main/scala/Batch.scala index 8c19cfa7..f5635c98 100644 --- a/src/main/scala/Batch.scala +++ b/src/main/scala/Batch.scala @@ -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 diff --git a/src/main/scala/DPIC.scala b/src/main/scala/DPIC.scala index 4da46647..1ae6a1dd 100644 --- a/src/main/scala/DPIC.scala +++ b/src/main/scala/DPIC.scala @@ -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 { diff --git a/src/main/scala/Gateway.scala b/src/main/scala/Gateway.scala index d88319e3..70453bd7 100644 --- a/src/main/scala/Gateway.scala +++ b/src/main/scala/Gateway.scala @@ -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 { diff --git a/src/test/csrc/common/perf.cpp b/src/test/csrc/common/perf.cpp index 54bc48ae..682e2cc1 100644 --- a/src/test/csrc/common/perf.cpp +++ b/src/test/csrc/common/perf.cpp @@ -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); diff --git a/src/test/csrc/common/perf.h b/src/test/csrc/common/perf.h index 29b005c7..ede90f27 100644 --- a/src/test/csrc/common/perf.h +++ b/src/test/csrc/common/perf.h @@ -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,