From f9cbcaf20f1f574098c0e8fe00604747b5dab8d4 Mon Sep 17 00:00:00 2001 From: supersurviveur Date: Tue, 11 Nov 2025 19:12:12 +0100 Subject: [PATCH] Add BSwitch macro and update gtkwave config --- build.sc | 12 +++++ common/config.gtkw | 2 +- macros/src/utils/BSwitchMacro.scala | 77 +++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 macros/src/utils/BSwitchMacro.scala diff --git a/build.sc b/build.sc index 3093bbb..ccfc53b 100644 --- a/build.sc +++ b/build.sc @@ -13,6 +13,17 @@ import mill.bsp._ // to properly generate and handle test directories and output files. // See: https://github.com/com-lihaoyi/mill/issues/3840 +object macros extends ScalaModule { + def scalaVersion = "2.13.16" + def scalacOptions = Seq[String]() + override def ivyDeps = Agg( + ivy"org.chipsalliance::chisel:7.2.0" + ) + override def scalacPluginIvyDeps = Agg( + ivy"org.chipsalliance:::chisel-plugin:7.2.0" + ) +} + object `TPchisel` extends SbtModule { m => override def millSourcePath = super.millSourcePath / os.up override def scalaVersion = "2.13.16" @@ -27,6 +38,7 @@ object `TPchisel` extends SbtModule { m => "-Ywarn-dead-code", "-Ywarn-unused" ) + override def moduleDeps = Seq(macros) override def ivyDeps = Agg( ivy"org.chipsalliance::chisel:7.2.0" ) diff --git a/common/config.gtkw b/common/config.gtkw index 4d03d84..578db16 100644 --- a/common/config.gtkw +++ b/common/config.gtkw @@ -17,7 +17,7 @@ TOP.svsimTestbench.dut.core.wbVal[31:0] TOP.svsimTestbench.dut.core.clock TOP.svsimTestbench.dut.core.reset @22 -TOP.svsimTestbench.dut.io_x31[31:0] +TOP.svsimTestbench.dut.io_x31[63:0] @28 TOP.svsimTestbench.dut.io_valid_x31 TOP.svsimTestbench.dut.core.rdValid diff --git a/macros/src/utils/BSwitchMacro.scala b/macros/src/utils/BSwitchMacro.scala new file mode 100644 index 0000000..d300903 --- /dev/null +++ b/macros/src/utils/BSwitchMacro.scala @@ -0,0 +1,77 @@ +package macros.utils + +import scala.language.experimental.macros +import scala.reflect.macros.blackbox._ +import chisel3._ +import chisel3.experimental.SourceInfo +import chisel3.util.BitPat + +object bis { + + /** Executes `block` if the bswitch condition matchs `v`. + */ + def apply(v: BitPat)(block: => Any): Unit = { + locally((v, block)) + require( + false, + "The 'bis' keyword may not be used outside of a bswitch." + ) + } +} + +class BSwitchContext( + cond: UInt, + whenContext: Option[WhenContext], + lits: Set[BitPat] +) { + def bis( + pat: BitPat + )(block: => Any)(implicit + sourceInfo: SourceInfo + ): BSwitchContext = { + require( + !lits.exists(w => { + w.overlap(pat) + }), + "all bis conditions must be mutually exclusive!" + ) + + // def instead of val so that logic ends up in legal place + def p = (cond === pat) + whenContext match { + case Some(w) => + new BSwitchContext( + cond, + Some(w.elsewhen(p)(block)), + lits + pat + ) + case None => + new BSwitchContext( + cond, + Some(when(p)(block)), + lits + pat + ) + } + } +} + +object bswitch { + def apply[T <: Element](cond: T)(x: => Any): Unit = macro impl + def impl(c: Context)(cond: c.Tree)(x: c.Tree): c.Tree = { + import c.universe._ + val q"..$body" = x + val res = body.foldLeft( + q"""new macros.utils.BSwitchContext($cond, None, Set.empty)""" + ) { case (acc, tree) => + tree match { + case q"macros.utils.bis.apply( ..$params )( ..$body )" => + q"$acc.bis( ..$params )( ..$body )" + case _ => + throw new Exception( + s"Cannot include blocks that do not begin with bis() in bswitch." + ) + } + } + q"""{ $res }""" + } +}