diff --git a/Images/Source/adder outputs.svg b/Images/Source/adder outputs.svg new file mode 100644 index 0000000..c0412c5 --- /dev/null +++ b/Images/Source/adder outputs.svg @@ -0,0 +1,672 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + Reg_A = 0 + 1 1 + + + + + + + Reg_A = 1 + 1 1 + + + + + + + Reg_A = 2 + 1 1 + + + + + + + Reg_A = 3 + 1 1 + + + + + + + Reg_A = 4 + 1 1 + + + + + + + Reg_A = 5 + 1 1 + Cycle 0 + Cycle 1 + Cycle 2 + Cycle 3 + Cycle 4 + Cycle 5 + + diff --git a/Images/Source/drawing2.svg b/Images/Source/drawing2.svg new file mode 100644 index 0000000..79a48e3 --- /dev/null +++ b/Images/Source/drawing2.svg @@ -0,0 +1,49726 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + 1 + + + + + + + Reg_A + 1 + output + + Reg_A + + HDL + + + + HDL + Circuit description + + + + + Simulator + + + + + + + + + Reg_A + 1 + output + + + Scala code + + + Word + + + + + Worder + + + + + + + + Reg_A + 1 + output + + Chisel graph + + + + Chisel graph builder + + + + + + Synthesizer + + + + + + + + Reg_A + 3 + output 3 + DataIn + dataIn + dataOut + + + + Simulator + + + Synthesizer + + + + + FPGA + + + Compiler errors + + Build errors + + + + diff --git a/Images/inkscape.png b/Images/inkscape.png new file mode 100644 index 0000000..7e78801 Binary files /dev/null and b/Images/inkscape.png differ diff --git a/Images/simulatedAdder.png b/Images/simulatedAdder.png new file mode 100644 index 0000000..5f6a74d Binary files /dev/null and b/Images/simulatedAdder.png differ diff --git a/Images/svgs.png b/Images/svgs.png new file mode 100644 index 0000000..8fd848b Binary files /dev/null and b/Images/svgs.png differ diff --git a/circuitRendering.org b/circuitRendering.org new file mode 100644 index 0000000..36187dc --- /dev/null +++ b/circuitRendering.org @@ -0,0 +1,105 @@ +* Rendering your circuit + This system is very WIP, and is therefore pretty janktastic. + The general idea of the circuit renderer is that you create a vector drawing of your circuit + with special labels for the circuit state you want to render. + The only svg program I have tested this with is inkscape, and I recommend against using other + drawing programs. + + As an example we will use a very simple circuit: + [[./Images/inkscape.jpg]] + + This circuit has a register, and we want to see how its state evolves, thus we add a label. + The name of the register is "Reg_A", which will be replaced by the actual value as the circuit + is simulated. We indicate this by adding "_field" as a postfix. + + Next we make a test for our circuit + + #+begin_src scala + class Adder() extends Module { + val io = IO( + new Bundle { + val reg_a = Output(UInt(32.W)) + } + ) + + val reg_a = RegInit(0.U(8.W)) + reg_a := reg_a + 1.U + + io.reg_a := reg_a + } + #+end_src + + Next we create a test, using an extension of PeekPokeTester + #+begin_src scala + class AdderTester(c: Adder) extends PeekPokeTesterLogger(c) { + // ^^^^^^^^^^^^^^^^^^^^^^^ This is an extension of the regular peek poke tester + + + // Tells us which signals should be logged + override def ioLoggers = List(c.io) + + for(ii <- 0 until 10){ + step(1) + } + + // Writes the log to disk + writeLog + } + #+end_src + + When the addertester is run it will record the state of ~c.io~ for every timestep and store it. + When testing is done, calling writeLog will search for an SVG whose name matches the tested device in + the resources folder. + For adder this corresponds to [[./src/test/resources/svgs/Adder.svg][src/test/resources/svgs/Adder.svg]] + The svg is loaded, and every value with the ~_field~ postfix is replaced with the recorded value sharing + its name. + In the simple adder circuit the only value in io is ~reg_a~ which matches ~Reg_A_field~. + + By running + ~testOnly Ex0.SVGSpec~ 10 svg files will be created, showing the state of the circuit for every step + + You can now see the output svgs in the [[./svgOutputs/][svgOutputs]] folder. + #+CAPTION: The simulated adders + [[./Images/simulatedAdder.png]] + + If you want to view them as pngs and you have inkscape installed you can run ./convert.sh to get png + output instead. + + For a more fully fledged example take a look at + [[./src/test/scala/SVGNestedSpec.scala][src/test/scala/SVGNestedSpec.scala]] + + which can be run with + ~testOnly Ex0.SVGSNestedSpec~ + +* Should I use this? What's the approach? + The time invested in drawing a circuit, laying out fields etc is likely not worth it. + However, for the 5-stage RISCV pipeline the answer is definitely a yes! + In order to get a feel for this approach I recommend trying to debug the matrix multiplier + unit (last exercise) with this approach. + To do so you need to do the following steps: + + (Or you could repurpose the SVGSNestedSpec) + +** Draw the circuit in inkscape + You can add as much detail as you want here, the only thing the parser looks for is + text fields that are postfixed with "_field" + The fields I would be interested in are the row and column counters, and the dot product + accumulator state. + Save the svg as + /src/test/resources/svgs/MatMul.svg + +** Wire the debug IO + The peek poke logger can only observe the top level IO modules, so the signals you want to + record must be made available. + This approach is shown in the chisel introduction. + +** Create the test runner + Your tester should extend PeekPokeTesterLogger. + In your test you need to override the ioLoggers function to record the ports you want to + monitor (typically io, maybe a special debug port) + + At the end of your test add writeLog in order to actually write the svgs + +** Run your test + If everything goes smooth you can now take a look at the SVG output, or if you have inkscape + render it as an svg diff --git a/src/test/resources/svgs/SumOrSquare.svg b/src/test/resources/svgs/SumOrSquare.svg new file mode 100644 index 0000000..9bf717f --- /dev/null +++ b/src/test/resources/svgs/SumOrSquare.svg @@ -0,0 +1,651 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + 1 1 1 + 1 + 0 + + + + + + + + + counter_b_field + 1 + + 0 + + + + + + + + + + + + + + + + + + + + + counter_a_field sum_field square_field out_field + diff --git a/src/test/scala/SVGNestedSpec.scala b/src/test/scala/SVGNestedSpec.scala new file mode 100644 index 0000000..eb2a986 --- /dev/null +++ b/src/test/scala/SVGNestedSpec.scala @@ -0,0 +1,95 @@ +package Ex0 + +import chisel3._ +import chisel3.experimental._ +import chisel3.iotesters.PeekPokeTester +import org.scalatest.{Matchers, FlatSpec} +import TestUtils._ + +import scala.collection.immutable.{ Vector => _ } + +class SVGSNestedSpec extends FlatSpec with Matchers { + + behavior of "SumOrSquare" + + it should "Make some sweet pngs" in { + wrapTester( + chisel3.iotesters.Driver(() => new SumOrSquare(5, 7)) { c => + new SumOrSquareTester(c) + } should be(true) + ) + } + +} + +class MyCounter(countTo: Int) extends MultiIOModule { + val io = IO( new Bundle { + val out = Output(UInt(32.W)) + }) + + val debug = IO( new Bundle { + val counterState = Output(UInt(32.W)) + }) + + val reg_a = RegInit(0.U(8.W)) + val incremented = reg_a + 1.U + + when(incremented === countTo.U){ + reg_a := 0.U + }.otherwise{ + reg_a := reg_a + 1.U + } + + io.out := incremented + + debug.counterState := reg_a +} + + +class SumOrSquare(countToA: Int, countToB: Int) extends MultiIOModule { + val io = IO( new Bundle { + val out = Output(UInt(32.W)) + }) + + + val debug = IO( new Bundle { + val counter_a = Output(UInt(32.W)) + val counter_b = Output(UInt(32.W)) + val square = Output(UInt(32.W)) + val sum = Output(UInt(32.W)) + }) + + + val counterA = Module(new MyCounter(countToA)) + val counterB = Module(new MyCounter(countToB)) + + val sum = counterA.io.out + counterA.io.out + val square = counterA.io.out * counterA.io.out + + when(counterB.io.out % 2.U === 0.U){ + io.out := sum + }.otherwise{ + io.out := square + } + + + debug.counter_a := counterA.debug.counterState + debug.counter_b := counterB.debug.counterState + debug.square := square + debug.sum := sum +} + + +class SumOrSquareTester(c: SumOrSquare) extends PeekPokeTesterLogger(c) { + override def ioLoggers = List( + "" -> c.debug, + "" -> c.io + ) + + for(ii <- 0 until 10){ + step(1) + } + + writeLog +} +