From 666a1ec8ddf31476044a5aa46257b3f12a5423e5 Mon Sep 17 00:00:00 2001 From: Kunlin You Date: Wed, 6 Mar 2024 13:18:02 +0800 Subject: [PATCH] Support parseArgs for GatewayConfig (#301) We add an parseArgs interface of difftest for style and GatewayConfig. User can pass DifftestArgs from top module which extends App trait, and it will return filter args for subsequent parsing. Now, we support use "--difftest-config ..." to specify GatewayConfig, each letter represents an optimization measure. Corresponding change for NutShell/XiangShan will be added with next time bump difftest. --- .github/workflows/main.yml | 45 ++++++-------------------------- src/main/scala/Difftest.scala | 48 ++++++++++++++++++++--------------- src/main/scala/Gateway.scala | 27 +++++++++++++++----- 3 files changed, 57 insertions(+), 63 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 86cad7b69..c861d6acc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -169,10 +169,8 @@ jobs: cd $GITHUB_WORKSPACE/../xs-env/NutShell source ./env.sh make clean - sed -i 's/isBatch: Boolean = false/isBatch: Boolean = true/' difftest/src/main/scala/Gateway.scala - make emu -j2 + make emu MILL_ARGS="--difftest-config B" -j2 ./build/emu -b 0 -e 0 -i ./ready-to-run/microbench.bin --diff ./ready-to-run/riscv64-nemu-interpreter-so - cd difftest && git restore src - name: Difftest with Global DPI-C Enable run: | @@ -181,10 +179,8 @@ jobs: cd $GITHUB_WORKSPACE/../xs-env/NutShell source ./env.sh make clean - sed -i 's/hasGlobalEnable: Boolean = false/hasGlobalEnable: Boolean = true/' difftest/src/main/scala/Gateway.scala - make emu -j2 + make emu MILL_ARGS="--difftest-config E" -j2 ./build/emu -b 0 -e 0 -i ./ready-to-run/microbench.bin --diff ./ready-to-run/riscv64-nemu-interpreter-so - cd difftest && git restore src - name: Difftest with Squash and Global Enable run: | @@ -193,11 +189,8 @@ jobs: cd $GITHUB_WORKSPACE/../xs-env/NutShell source ./env.sh make clean - sed -i 's/hasGlobalEnable: Boolean = false/hasGlobalEnable: Boolean = true/' difftest/src/main/scala/Gateway.scala - sed -i 's/isSquash: Boolean = false/isSquash: Boolean = true/' difftest/src/main/scala/Gateway.scala - make emu -j2 + make emu MILL_ARGS="--difftest-config ES" -j2 ./build/emu -b 0 -e 0 -i ./ready-to-run/microbench.bin --diff ./ready-to-run/riscv64-nemu-interpreter-so - cd difftest && git restore src - name: Difftest with Squash Batch and Global Enable run: | @@ -206,12 +199,8 @@ jobs: cd $GITHUB_WORKSPACE/../xs-env/NutShell source ./env.sh make clean - sed -i 's/isSquash: Boolean = false/isSquash: Boolean = true/' difftest/src/main/scala/Gateway.scala - sed -i 's/isBatch: Boolean = false/isBatch: Boolean = true/' difftest/src/main/scala/Gateway.scala - sed -i 's/hasGlobalEnable: Boolean = false/hasGlobalEnable: Boolean = true/' difftest/src/main/scala/Gateway.scala - make emu -j2 + make emu MILL_ARGS="--difftest-config ESB" -j2 ./build/emu -b 0 -e 0 -i ./ready-to-run/microbench.bin --diff ./ready-to-run/riscv64-nemu-interpreter-so - cd difftest && git restore src test-difftest-fuzzing: # This test runs on ubuntu-20.04 for two reasons: @@ -315,11 +304,9 @@ jobs: cd $GITHUB_WORKSPACE/../xs-env/NutShell source ./env.sh make clean - sed -i 's/hasDutZone: Boolean = false/hasDutZone: Boolean = true/' difftest/src/main/scala/Gateway.scala - make simv DIFFTEST_PERFCNT=1 VCS=verilator -j2 + make simv MILL_ARGS="--difftest-config Z" 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 - cd difftest && git restore src - name: Verilator Build with VCS Top (with Batch InternalStep PerfCnt) run: | @@ -328,12 +315,9 @@ jobs: cd $GITHUB_WORKSPACE/../xs-env/NutShell source ./env.sh make clean - sed -i 's/isBatch: Boolean = false/isBatch: Boolean = true/' difftest/src/main/scala/Gateway.scala - sed -i 's/hasInternalStep: Boolean = false/hasInternalStep: Boolean = true/' difftest/src/main/scala/Gateway.scala - make simv DIFFTEST_PERFCNT=1 VCS=verilator -j2 + make simv MILL_ARGS="--difftest-config BI" 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 - cd difftest && git restore src - name: Verilator Build with VCS Top (with DutZone GlobalEnable Squash SquashReplay Batch PerfCnt) run: | @@ -342,15 +326,9 @@ jobs: cd $GITHUB_WORKSPACE/../xs-env/NutShell source ./env.sh make clean - sed -i 's/hasDutZone: Boolean = false/hasDutZone: Boolean = true/' difftest/src/main/scala/Gateway.scala - sed -i 's/hasGlobalEnable: Boolean = false/hasGlobalEnable: Boolean = true/' difftest/src/main/scala/Gateway.scala - sed -i 's/isSquash: Boolean = false/isSquash: Boolean = true/' difftest/src/main/scala/Gateway.scala - sed -i 's/squashReplay: Boolean = false/squashReplay: Boolean = true/' difftest/src/main/scala/Gateway.scala - sed -i 's/isBatch: Boolean = false/isBatch: Boolean = true/' difftest/src/main/scala/Gateway.scala - make simv DIFFTEST_PERFCNT=1 VCS=verilator -j2 + make simv MILL_ARGS="--difftest-config ZESRB" 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 - cd difftest && git restore src - name: Verilator Build with VCS Top (with GlobalEnable Squash SquashReplay Batch InternalStep NonBlock PerfCnt) run: | @@ -359,16 +337,9 @@ jobs: cd $GITHUB_WORKSPACE/../xs-env/NutShell source ./env.sh make clean - sed -i 's/hasGlobalEnable: Boolean = false/hasGlobalEnable: Boolean = true/' difftest/src/main/scala/Gateway.scala - sed -i 's/isSquash: Boolean = false/isSquash: Boolean = true/' difftest/src/main/scala/Gateway.scala - sed -i 's/squashReplay: Boolean = false/squashReplay: Boolean = true/' difftest/src/main/scala/Gateway.scala - sed -i 's/isBatch: Boolean = false/isBatch: Boolean = true/' difftest/src/main/scala/Gateway.scala - sed -i 's/hasInternalStep: Boolean = false/hasInternalStep: Boolean = true/' difftest/src/main/scala/Gateway.scala - sed -i 's/isNonBlock: Boolean = false/isNonBlock: Boolean = true/' difftest/src/main/scala/Gateway.scala - make simv DIFFTEST_PERFCNT=1 VCS=verilator -j2 + make simv MILL_ARGS="--difftest-config ESRBIN" 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 - cd difftest && git restore src - name: Verilator Build with VCS Top (with workload-list) run : | diff --git a/src/main/scala/Difftest.scala b/src/main/scala/Difftest.scala index 2a6eae088..d5644a0e3 100644 --- a/src/main/scala/Difftest.scala +++ b/src/main/scala/Difftest.scala @@ -22,6 +22,7 @@ import difftest.gateway.{Gateway, GatewayConfig} import java.nio.charset.StandardCharsets import java.nio.file.{Files, Paths} +import scala.annotation.tailrec import scala.collection.mutable.ListBuffer trait DifftestWithCoreid { @@ -259,20 +260,33 @@ trait DifftestModule[T <: DifftestBundle] { object DifftestModule { private val enabled = true - private val instances = ListBuffer.empty[(DifftestBundle, String)] + private val instances = ListBuffer.empty[DifftestBundle] private val cppMacros = ListBuffer.empty[String] private val vMacros = ListBuffer.empty[String] + def parseArgs(args: Array[String]): Array[String] = { + @tailrec + def nextOption(args: Array[String], list: List[String]): Array[String] = { + list match { + case Nil => args + case "--difftest-config" :: config :: tail => + Gateway.setConfig(config) + nextOption(args.patch(args.indexOf("--difftest-config"), Nil, 2), tail) + case option :: tail => nextOption(args, tail) + } + } + nextOption(args, args.toList) + } + def apply[T <: DifftestBundle]( gen: T, - style: String = "dpic", dontCare: Boolean = false, delay: Int = 0, ): T = { val difftest: T = Wire(gen) if (enabled) { - register(gen, style) - val sink = Gateway(gen, style) + register(gen) + val sink = Gateway(gen) sink := Delayer(difftest, delay) sink.coreid := difftest.coreid } @@ -282,22 +296,19 @@ object DifftestModule { difftest } - def register[T <: DifftestBundle](gen: T, style: String): Int = { + def register[T <: DifftestBundle](gen: T): Int = { val id = instances.length - val element = (gen, style) - instances += element + instances += gen id } - def finish(cpu: String, cppHeader: Option[String] = Some("dpic")): DifftestTopIO = { + def finish(cpu: String): DifftestTopIO = { val gateway = Gateway.collect() cppMacros ++= gateway.cppMacros vMacros ++= gateway.vMacros instances ++= gateway.instances - if (cppHeader.isDefined) { - generateCppHeader(cpu, cppHeader.get, gateway.structPacked.getOrElse(false)) - } + generateCppHeader(cpu, gateway.structPacked.getOrElse(false)) generateVeriogHeader() if (enabled) { @@ -326,7 +337,7 @@ object DifftestModule { difftest } - def generateCppHeader(cpu: String, style: String, structPacked: Boolean): Unit = { + def generateCppHeader(cpu: String, structPacked: Boolean): Unit = { val difftestCpp = ListBuffer.empty[String] difftestCpp += "#ifndef __DIFFSTATE_H__" difftestCpp += "#define __DIFFSTATE_H__" @@ -341,18 +352,15 @@ object DifftestModule { difftestCpp += s"#define CPU_$cpu_s" difftestCpp += "" - val headerInstances = instances.filter(_._2 == style) - - val numCores = headerInstances.count(_._1.isUniqueIdentifier) - if (headerInstances.nonEmpty) { + val numCores = instances.count(_.isUniqueIdentifier) + if (instances.nonEmpty) { difftestCpp += s"#define NUM_CORES $numCores" difftestCpp += "" } - val uniqBundles = headerInstances.groupBy(_._1.desiredModuleName) + val uniqBundles = instances.groupBy(_.desiredModuleName) // Create cpp declaration for each bundle type uniqBundles.values - .map(_.map(_._1)) .foreach(bundles => { val bundleType = bundles.head difftestCpp += bundleType.toCppDeclMacro @@ -372,8 +380,8 @@ object DifftestModule { // create top-level difftest struct difftestCpp += "typedef struct {" - for ((className, cppInstances) <- uniqBundles.toSeq.sortBy(_._2.head._1.order)) { - val bundleType = cppInstances.head._1 + for ((className, cppInstances) <- uniqBundles.toSeq.sortBy(_._2.head.order)) { + val bundleType = cppInstances.head val instanceName = bundleType.desiredCppName val cppIsArray = bundleType.isInstanceOf[DifftestWithIndex] || bundleType.isFlatten val nInstances = cppInstances.length diff --git a/src/main/scala/Gateway.scala b/src/main/scala/Gateway.scala index 79334bca8..341237dd2 100644 --- a/src/main/scala/Gateway.scala +++ b/src/main/scala/Gateway.scala @@ -37,8 +37,6 @@ case class GatewayConfig( hasInternalStep: Boolean = false, isNonBlock: Boolean = false, ) { - if (squashReplay) require(isSquash) - if (hasInternalStep) require(isBatch) def dutZoneSize: Int = if (hasDutZone) 2 else 1 def dutZoneWidth: Int = log2Ceil(dutZoneSize) def dutBufLen: Int = if (isBatch) batchSize else 1 @@ -70,12 +68,16 @@ case class GatewayConfig( if (hasInternalStep) macros += "CONFIG_DIFFTEST_INTERNAL_STEP" macros.toSeq } + def check(): Unit = { + if (squashReplay) require(isSquash) + if (hasInternalStep) require(isBatch) + } } case class GatewayResult( cppMacros: Seq[String] = Seq(), vMacros: Seq[String] = Seq(), - instances: Seq[(DifftestBundle, String)] = Seq(), + instances: Seq[DifftestBundle] = Seq(), structPacked: Option[Boolean] = None, step: Option[UInt] = None, ) { @@ -94,8 +96,21 @@ object Gateway { private val instances = ListBuffer.empty[DifftestBundle] private var config = GatewayConfig() - def apply[T <: DifftestBundle](gen: T, style: String): T = { - config = GatewayConfig(style = style) + def setConfig(cfg: String): Unit = { + cfg.foreach { + case 'E' => config = config.copy(hasGlobalEnable = true) + case 'S' => config = config.copy(isSquash = true) + case 'R' => config = config.copy(squashReplay = true) + case 'Z' => config = config.copy(hasDutZone = true) + case 'B' => config = config.copy(isBatch = true) + case 'I' => config = config.copy(hasInternalStep = true) + case 'N' => config = config.copy(isNonBlock = true) + case x => println(s"Unknown Gateway Config $x") + } + config.check() + } + + def apply[T <: DifftestBundle](gen: T): T = { if (config.needEndpoint) { register(WireInit(0.U.asTypeOf(gen))) } else { @@ -133,7 +148,7 @@ object Gateway { } class GatewayEndpoint(signals: Seq[DifftestBundle], config: GatewayConfig) extends Module { - val instances = if (config.needTraceInfo) Seq((new DiffTraceInfo(config), config.style)) else Seq() + val instances = if (config.needTraceInfo) Seq(new DiffTraceInfo(config)) else Seq() val in = WireInit(0.U.asTypeOf(MixedVec(signals.map(_.cloneType)))) val in_pack = WireInit(0.U.asTypeOf(MixedVec(signals.map(gen => UInt(gen.getWidth.W))))) for ((data, id) <- in_pack.zipWithIndex) {