diff --git a/.gitignore b/.gitignore index 32ea314..6d76934 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,20 @@ +*.* +* +!*/ +!Makefile +!*.mk +!*.scala +!*.[cSh] +!*.v +!*.cpp +!*.cc +!.gitignore +!.scalafmt.conf +!.mill-version +!build.sc +!README.md +build/ + # mill out/ .bsp/ @@ -5,4 +22,4 @@ out/ .idea_modules/ test_run_dir/ -build/ +!build.sh diff --git a/.mill-version b/.mill-version new file mode 100644 index 0000000..d225a9b --- /dev/null +++ b/.mill-version @@ -0,0 +1,2 @@ +0.11.2 + diff --git a/Makefile b/Makefile index fa6b95c..84af3a0 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,12 @@ 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) @@ -26,3 +29,9 @@ 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/README.md b/README.md index 0a27c83..906c4e2 100644 --- a/README.md +++ b/README.md @@ -29,3 +29,9 @@ 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/VGCD__main.cpp b/VGCD__main.cpp new file mode 100644 index 0000000..43ed2c2 --- /dev/null +++ b/VGCD__main.cpp @@ -0,0 +1,41 @@ +// Verilated -*- C++ -*- +// DESCRIPTION: main() calling loop, created with Verilator --main + +#include "verilated.h" +#include "VGCD.h" + +//====================== + +int main(int argc, char** argv, char**) { + // Setup context, defaults, and parse command line + Verilated::debug(0); + const std::unique_ptr contextp{new VerilatedContext}; + contextp->commandArgs(argc, argv); + + // Construct the Verilated model, from Vtop.h generated from Verilating + const std::unique_ptr topp{new VGCD{contextp.get()}}; + topp->clock = 0; + topp->reset = 1; + topp->eval(); + topp->clock = 1; + topp->reset = 1; + topp->eval(); + topp->clock = 0; + topp->reset = 0; + // Simulate until $finish + while (!contextp->gotFinish()) { + // Evaluate model + topp->eval(); + // Advance time + contextp->timeInc(1); + topp->clock = ~topp->clock; + } + + if (!contextp->gotFinish()) { + VL_DEBUG_IF(VL_PRINTF("+ Exiting without $finish; no events left\n");); + } + + // Final model cleanup + topp->final(); + return 0; +} diff --git a/build.sc b/build.sc index 7ef4e51..4049288 100644 --- a/build.sc +++ b/build.sc @@ -7,24 +7,29 @@ import mill.scalalib.TestModule.Utest import mill.bsp._ object playground extends ScalaModule with ScalafmtModule { m => - override def scalaVersion = "2.13.8" + val useChisel5 = true + override def scalaVersion = "2.13.10" override def scalacOptions = Seq( "-language:reflectiveCalls", "-deprecation", "-feature", - "-Xcheckinit", - "-P:chiselplugin:genBundleElements" + "-Xcheckinit" ) override def ivyDeps = Agg( - ivy"edu.berkeley.cs::chisel3:3.5.4", + if (useChisel5) ivy"org.chipsalliance::chisel:6.0.0-RC2" else + ivy"edu.berkeley.cs::chisel3:3.6.0", ) override def scalacPluginIvyDeps = Agg( - ivy"edu.berkeley.cs:::chisel3-plugin:3.5.4", + if (useChisel5) ivy"org.chipsalliance:::chisel-plugin:6.0.0-RC2" else + ivy"edu.berkeley.cs:::chisel3-plugin:3.6.0", ) - object test extends Tests with Utest { + object test extends ScalaTests with Utest { override def ivyDeps = m.ivyDeps() ++ Agg( - ivy"com.lihaoyi::utest:0.7.10", - ivy"edu.berkeley.cs::chiseltest:0.5.4", + ivy"com.lihaoyi::utest:0.8.1", ) } + 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/build.sh b/build.sh new file mode 100755 index 0000000..77f62e7 --- /dev/null +++ b/build.sh @@ -0,0 +1,15 @@ +#set -x + +TOP=GCD +BUILD_DIR=obj_dir + +echo "Building ${TOP}..." +rm -rf ${BUILD_DIR} +mkdir -p ${BUILD_DIR} +verilator --cc --exe --main --timing $1 +cp ./VGCD__main.cpp ${BUILD_DIR} +#--prof-cfuncs +make -C ${BUILD_DIR} -f V${TOP}.mk -j16 -s +echo "Running ./${BUILD_DIR}/V${TOP}..." +./${BUILD_DIR}/V${TOP} + diff --git a/playground/src/Elaborate.scala b/playground/src/Elaborate.scala index 67345a1..6a95895 100644 --- a/playground/src/Elaborate.scala +++ b/playground/src/Elaborate.scala @@ -1,3 +1,7 @@ +import circt.stage._ + object Elaborate extends App { - (new chisel3.stage.ChiselStage).execute(args, Seq(chisel3.stage.ChiselGeneratorAnnotation(() => new GCD()))) + def top = new GCD() + val generator = Seq(chisel3.stage.ChiselGeneratorAnnotation(() => top)) + (new ChiselStage).execute(args, generator :+ CIRCTTargetAnnotation(CIRCTTarget.Verilog)) } diff --git a/playground/src/GCD.scala b/playground/src/GCD.scala index 42c4ce0..4a9a83b 100644 --- a/playground/src/GCD.scala +++ b/playground/src/GCD.scala @@ -1,29 +1,42 @@ 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 { +trait HasTestIO { this: 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 in0 = Input(UInt(16.W)) + val in1 = Input(UInt(16.W)) + val in2 = Input(UInt(16.W)) + val result = Output(UInt(16.W)) }) + dontTouch(io) + + def calc: UInt = io.in0 + (io.in1.asSInt / io.in2.asSInt).asUInt +} + +class Test1 extends Module with HasTestIO { + val result = RegNext(calc) + + io.result := result +} - val x = Reg(UInt()) - val y = Reg(UInt()) - when(x > y) { x := x - y }.otherwise { y := y - x } +class Test2 extends Module with HasTestIO { + val result = Reg(UInt(16.W)) + result := calc - when(io.loadingValues) { - x := io.value1 - y := io.value2 - } + io.result := result +} - io.outputGCD := x - io.outputValid := y === 0.U +/** + * 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 tests = Seq(Module(new Test1), Module(new Test2)) + tests.foreach(_.io.in0 := 0xFFFF.U) + tests.foreach(_.io.in1 := 0xFFFF.U) + tests.foreach(_.io.in2 := 0x0002.U) + printf(p"result0: ${Hexadecimal(tests(0).io.result)}\n") + printf(p"result1: ${Hexadecimal(tests(1).io.result)}\n") + assert(tests(0).io.result === tests(1).io.result) } diff --git a/playground/test/src/GCDSpec.scala b/playground/test/src/GCDSpec.scala deleted file mode 100644 index c6084a3..0000000 --- a/playground/test/src/GCDSpec.scala +++ /dev/null @@ -1,48 +0,0 @@ -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() - } - } - } -} diff --git a/utils/firtool b/utils/firtool new file mode 100755 index 0000000..1ece37d --- /dev/null +++ b/utils/firtool @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +firtool.elf.strip --lowering-options=disallowLocalVariables,disallowPackedArrays,locationInfoStyle=wrapInAtSquareBracket $@ diff --git a/utils/firtool.elf.strip b/utils/firtool.elf.strip new file mode 100755 index 0000000..749b297 Binary files /dev/null and b/utils/firtool.elf.strip differ