From 37c144d66d665448b4fa842f25a788ab6422c327 Mon Sep 17 00:00:00 2001 From: Liphen Date: Tue, 7 Nov 2023 13:41:15 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0chisel=E6=A1=86=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- chisel/.gitignore | 22 ++++++++ chisel/.scalafmt.conf | 33 ++++++++++++ chisel/Makefile | 37 +++++++++++++ chisel/README.md | 37 +++++++++++++ chisel/build.sc | 37 +++++++++++++ chisel/playground/src/DecoupledGCD.scala | 69 ++++++++++++++++++++++++ chisel/playground/src/Elaborate.scala | 7 +++ chisel/playground/src/GCD.scala | 29 ++++++++++ chisel/playground/test/src/GCDSpec.scala | 48 +++++++++++++++++ 9 files changed, 319 insertions(+) create mode 100644 chisel/.gitignore create mode 100644 chisel/.scalafmt.conf create mode 100644 chisel/Makefile create mode 100644 chisel/README.md create mode 100644 chisel/build.sc create mode 100644 chisel/playground/src/DecoupledGCD.scala create mode 100644 chisel/playground/src/Elaborate.scala create mode 100644 chisel/playground/src/GCD.scala create mode 100644 chisel/playground/test/src/GCDSpec.scala diff --git a/chisel/.gitignore b/chisel/.gitignore new file mode 100644 index 0000000..a507599 --- /dev/null +++ b/chisel/.gitignore @@ -0,0 +1,22 @@ +*.* +* +!*/ +!Makefile +!*.mk +!*.scala +!*.[cSh] +!*.v +!*.cpp +!*.cc +!.gitignore +!.scalafmt.conf +!build.sc +!README.md +build/ + +# mill +out/ +.bsp/ +.idea/ +.idea_modules/ +test_run_dir/ diff --git a/chisel/.scalafmt.conf b/chisel/.scalafmt.conf new file mode 100644 index 0000000..5b136d5 --- /dev/null +++ b/chisel/.scalafmt.conf @@ -0,0 +1,33 @@ +version = 2.6.4 + +maxColumn = 120 +align = most +continuationIndent.defnSite = 2 +assumeStandardLibraryStripMargin = true +docstrings = ScalaDoc +lineEndings = preserve +includeCurlyBraceInSelectChains = false +danglingParentheses = true + +align.tokens.add = [ + { + code = ":" + }, + { + code = ":=" + }, + { + code = "=" + } + +] + +newlines.alwaysBeforeCurlyBraceLambdaParams = false +newlines.alwaysBeforeMultilineDef = false +newlines.implicitParamListModifierForce = [before] + +verticalMultiline.atDefnSite = true + +optIn.annotationNewlines = true + +rewrite.rules = [SortImports, PreferCurlyFors, AvoidInfix] diff --git a/chisel/Makefile b/chisel/Makefile new file mode 100644 index 0000000..84af3a0 --- /dev/null +++ b/chisel/Makefile @@ -0,0 +1,37 @@ +BUILD_DIR = ./build + +export PATH := $(PATH):$(abspath ./utils) + +test: + mill -i __.test + +verilog: + $(call git_commit, "generate verilog") + mkdir -p $(BUILD_DIR) + mill -i __.test.runMain Elaborate -td $(BUILD_DIR) + +help: + mill -i __.test.runMain Elaborate --help + +compile: + mill -i __.compile + +bsp: + mill -i mill.bsp.BSP/install + +reformat: + mill -i __.reformat + +checkformat: + mill -i __.checkFormat + +clean: + -rm -rf $(BUILD_DIR) + +.PHONY: test verilog help compile bsp reformat checkformat clean + +sim: + $(call git_commit, "sim RTL") # DO NOT REMOVE THIS LINE!!! + @echo "Write this Makefile by yourself." + +-include ../Makefile diff --git a/chisel/README.md b/chisel/README.md new file mode 100644 index 0000000..906c4e2 --- /dev/null +++ b/chisel/README.md @@ -0,0 +1,37 @@ +Chisel Project Template +======================= + +Another version of the [Chisel template](https://github.com/ucb-bar/chisel-template) supporting mill. +mill is another Scala/Java build tool without obscure DSL like SBT. It is much faster than SBT. + +Contents at a glance: + +* `.gitignore` - helps Git ignore junk like generated files, build products, and temporary files. +* `build.sc` - instructs mill to build the Chisel project +* `Makefile` - rules to call mill +* `playground/src/GCD.scala` - GCD source file +* `playground/src/DecoupledGCD.scala` - another GCD source file +* `playground/src/Elaborate.scala` - wrapper file to call chisel command with the GCD module +* `playground/test/src/GCDSpec.scala` - GCD tester + +Feel free to rename or delete files under `playground/` or use them as a reference/template. + +## Getting Started + +First, install mill by referring to the documentation [here](https://com-lihaoyi.github.io/mill). + +To run all tests in this design (recommended for test-driven development): +```bash +make test +``` + +To generate Verilog: +```bash +make verilog +``` + +## Change FIRRTL Compiler + +You can change the FIRRTL compiler between SFC (Scala-based FIRRTL compiler) and +MFC (MLIR-based FIRRTL compiler) by modifying the `useMFC` variable in `playground/src/Elaborate.scala`. +The latter one requires `firtool`, which is included under `utils/`. diff --git a/chisel/build.sc b/chisel/build.sc new file mode 100644 index 0000000..2768db8 --- /dev/null +++ b/chisel/build.sc @@ -0,0 +1,37 @@ +// import Mill dependency +import mill._ +import mill.scalalib._ +import mill.scalalib.scalafmt.ScalafmtModule +import mill.scalalib.TestModule.ScalaTest +// support BSP +import mill.bsp._ + +object playground extends ScalaModule with ScalafmtModule { m => + val useChisel5 = true + override def scalaVersion = "2.13.10" + override def scalacOptions = Seq( + "-language:reflectiveCalls", + "-deprecation", + "-feature", + "-Xcheckinit" + ) + override def ivyDeps = Agg( + if (useChisel5) ivy"org.chipsalliance::chisel:5.0.0" else + ivy"edu.berkeley.cs::chisel3:3.6.0", + ) + override def scalacPluginIvyDeps = Agg( + if (useChisel5) ivy"org.chipsalliance:::chisel-plugin:5.0.0" else + ivy"edu.berkeley.cs:::chisel3-plugin:3.6.0", + ) + object test extends ScalaTests with ScalaTest { + override def ivyDeps = m.ivyDeps() ++ Agg( + ivy"com.lihaoyi::utest:0.8.1", + if (useChisel5) ivy"edu.berkeley.cs::chiseltest:5.0.0" else + ivy"edu.berkeley.cs::chiseltest:0.6.0", + ) + } + def repositoriesTask = T.task { Seq( + coursier.MavenRepository("https://maven.aliyun.com/repository/central"), + coursier.MavenRepository("https://repo.scala-sbt.org/scalasbt/maven-releases"), + ) ++ super.repositoriesTask() } +} diff --git a/chisel/playground/src/DecoupledGCD.scala b/chisel/playground/src/DecoupledGCD.scala new file mode 100644 index 0000000..8fd0456 --- /dev/null +++ b/chisel/playground/src/DecoupledGCD.scala @@ -0,0 +1,69 @@ +import chisel3._ +import chisel3.util.Decoupled + +class GcdInputBundle(val w: Int) extends Bundle { + val value1 = UInt(w.W) + val value2 = UInt(w.W) +} + +class GcdOutputBundle(val w: Int) extends Bundle { + val value1 = UInt(w.W) + val value2 = UInt(w.W) + val gcd = UInt(w.W) +} + +/** + * Compute Gcd using subtraction method. + * Subtracts the smaller from the larger until register y is zero. + * value input register x is then the Gcd. + * Unless first input is zero then the Gcd is y. + * Can handle stalls on the producer or consumer side + */ +class DecoupledGcd(width: Int) extends Module { + val input = IO(Flipped(Decoupled(new GcdInputBundle(width)))) + val output = IO(Decoupled(new GcdOutputBundle(width))) + + val xInitial = Reg(UInt()) + val yInitial = Reg(UInt()) + val x = Reg(UInt()) + val y = Reg(UInt()) + val busy = RegInit(false.B) + val resultValid = RegInit(false.B) + + input.ready := !busy + output.valid := resultValid + output.bits := DontCare + + when(busy) { + when(x > y) { + x := x - y + }.otherwise { + y := y - x + } + when(x === 0.U || y === 0.U) { + when(x === 0.U) { + output.bits.gcd := y + }.otherwise { + output.bits.gcd := x + } + + output.bits.value1 := xInitial + output.bits.value2 := yInitial + resultValid := true.B + + when(output.ready && resultValid) { + busy := false.B + resultValid := false.B + } + } + }.otherwise { + when(input.valid) { + val bundle = input.deq() + x := bundle.value1 + y := bundle.value2 + xInitial := bundle.value1 + yInitial := bundle.value2 + busy := true.B + } + } +} diff --git a/chisel/playground/src/Elaborate.scala b/chisel/playground/src/Elaborate.scala new file mode 100644 index 0000000..6a95895 --- /dev/null +++ b/chisel/playground/src/Elaborate.scala @@ -0,0 +1,7 @@ +import circt.stage._ + +object Elaborate extends App { + def top = new GCD() + val generator = Seq(chisel3.stage.ChiselGeneratorAnnotation(() => top)) + (new ChiselStage).execute(args, generator :+ CIRCTTargetAnnotation(CIRCTTarget.Verilog)) +} diff --git a/chisel/playground/src/GCD.scala b/chisel/playground/src/GCD.scala new file mode 100644 index 0000000..42c4ce0 --- /dev/null +++ b/chisel/playground/src/GCD.scala @@ -0,0 +1,29 @@ +import chisel3._ + +/** + * Compute GCD using subtraction method. + * Subtracts the smaller from the larger until register y is zero. + * value in register x is then the GCD + */ +class GCD extends Module { + val io = IO(new Bundle { + val value1 = Input(UInt(16.W)) + val value2 = Input(UInt(16.W)) + val loadingValues = Input(Bool()) + val outputGCD = Output(UInt(16.W)) + val outputValid = Output(Bool()) + }) + + val x = Reg(UInt()) + val y = Reg(UInt()) + + when(x > y) { x := x - y }.otherwise { y := y - x } + + when(io.loadingValues) { + x := io.value1 + y := io.value2 + } + + io.outputGCD := x + io.outputValid := y === 0.U +} diff --git a/chisel/playground/test/src/GCDSpec.scala b/chisel/playground/test/src/GCDSpec.scala new file mode 100644 index 0000000..c6084a3 --- /dev/null +++ b/chisel/playground/test/src/GCDSpec.scala @@ -0,0 +1,48 @@ +import chisel3._ +import chiseltest._ +import chisel3.experimental.BundleLiterals._ + +import utest._ + +/** + * This is a trivial example of how to run this Specification + * From within sbt use: + * {{{ + * testOnly gcd.GcdDecoupledTester + * }}} + * From a terminal shell use: + * {{{ + * sbt 'testOnly gcd.GcdDecoupledTester' + * }}} + */ +object GCDSpec extends ChiselUtestTester { + val tests = Tests { + test("GCD") { + testCircuit(new DecoupledGcd(16)) { + dut => + dut.input.initSource() + dut.input.setSourceClock(dut.clock) + dut.output.initSink() + dut.output.setSinkClock(dut.clock) + val testValues = for {x <- 0 to 10; y <- 0 to 10} yield (x, y) + val inputSeq = testValues.map { case (x, y) => (new GcdInputBundle(16)).Lit(_.value1 -> x.U, _.value2 -> y.U) } + val resultSeq = testValues.map { case (x, y) => + (new GcdOutputBundle(16)).Lit(_.value1 -> x.U, _.value2 -> y.U, _.gcd -> BigInt(x).gcd(BigInt(y)).U) + } + fork { + // push inputs into the calculator, stall for 11 cycles one third of the way + val (seq1, seq2) = inputSeq.splitAt(resultSeq.length / 3) + dut.input.enqueueSeq(seq1) + dut.clock.step(11) + dut.input.enqueueSeq(seq2) + }.fork { + // retrieve computations from the calculator, stall for 10 cycles one half of the way + val (seq1, seq2) = resultSeq.splitAt(resultSeq.length / 2) + dut.output.expectDequeueSeq(seq1) + dut.clock.step(10) + dut.output.expectDequeueSeq(seq2) + }.join() + } + } + } +}