| @@ -1,4 +1,5 @@ | |||||
| #!/bin/bash | #!/bin/bash | ||||
| mkdir ./pngs/svgOutput | |||||
| parallel inkscape -f {} -e pngs/{.} ::: svgOutput/*.svg | parallel inkscape -f {} -e pngs/{.} ::: svgOutput/*.svg | ||||
| mv ./pngs/svgOutput/* ./pngs/ | mv ./pngs/svgOutput/* ./pngs/ | ||||
| @@ -49,7 +49,7 @@ | |||||
| This shouldn't come as a suprise, displaying text is less complex than creating digital circuits. | This shouldn't come as a suprise, displaying text is less complex than creating digital circuits. | ||||
| A very simplified version of this is shown here: | A very simplified version of this is shown here: | ||||
| #+CAPTION: Placeholder graphic | #+CAPTION: Placeholder graphic | ||||
| [[./Images/toolchain.png]] | |||||
| [[./Images/toolchain1.png]] | |||||
| * Scala and Chisel | * Scala and Chisel | ||||
| @@ -353,7 +353,13 @@ | |||||
| #+end_src | #+end_src | ||||
| Which can yield two different circuits depending on the opSel argument: | Which can yield two different circuits depending on the opSel argument: | ||||
| True: | |||||
| [[./Images/ScalaCond1.png]] | [[./Images/ScalaCond1.png]] | ||||
| False: | |||||
| [[./Images/ScalaCond2.png]] | [[./Images/ScalaCond2.png]] | ||||
| @@ -842,3 +848,9 @@ | |||||
| Just don't bank your money on the correctness, it might fail in rare circumstances making debugging | Just don't bank your money on the correctness, it might fail in rare circumstances making debugging | ||||
| a nightmare) | a nightmare) | ||||
| ** Visualizing circuit state (Optional) | |||||
| In order to make debugging easier it is helpful to render the state of the circuit to see where | |||||
| errors happen. | |||||
| A prototype for this is included in this project, read more about it here | |||||
| [[./circuitRendering.org][Here]] | |||||
| @@ -14,7 +14,6 @@ class SVGSpec extends FlatSpec with Matchers { | |||||
| behavior of "Adder" | behavior of "Adder" | ||||
| it should "Make some sweet pngs" in { | it should "Make some sweet pngs" in { | ||||
| // FileUtils.getSvg("Adder") | |||||
| wrapTester( | wrapTester( | ||||
| chisel3.iotesters.Driver(() => new Adder()) { c => | chisel3.iotesters.Driver(() => new Adder()) { c => | ||||
| new AdderTester(c) | new AdderTester(c) | ||||
| @@ -32,7 +31,7 @@ class Adder() extends Module { | |||||
| ) | ) | ||||
| val reg_a = RegInit(0.U(8.W)) | val reg_a = RegInit(0.U(8.W)) | ||||
| reg_a := reg_a + 1.U | |||||
| reg_a := reg_a + 2.U | |||||
| io.reg_a := reg_a | io.reg_a := reg_a | ||||
| } | } | ||||
| @@ -40,7 +39,8 @@ class Adder() extends Module { | |||||
| object AdderTests { | object AdderTests { | ||||
| class AdderTester(c: Adder) extends PeekPokeTesterLogger(c) { | class AdderTester(c: Adder) extends PeekPokeTesterLogger(c) { | ||||
| override def ioLoggers = List(c.io) | |||||
| // ^^^^^^^^^^^^^^^^^^^^^^^ This is an extension of the regular peek poke tester | |||||
| override def ioLoggers = List("" -> c.io) | |||||
| for(ii <- 0 until 10){ | for(ii <- 0 until 10){ | ||||
| step(1) | step(1) | ||||
| @@ -49,3 +49,5 @@ object AdderTests { | |||||
| writeLog | writeLog | ||||
| } | } | ||||
| } | } | ||||
| @@ -45,11 +45,23 @@ object TestUtils { | |||||
| } | } | ||||
| abstract class PeekPokeTesterLogger[T <: MultiIOModule](dut: T) extends PeekPokeTester(dut){ | abstract class PeekPokeTesterLogger[T <: MultiIOModule](dut: T) extends PeekPokeTester(dut){ | ||||
| def ioLoggers: List[chisel3.Bundle] | |||||
| /** | |||||
| * Defines which io ports should be recorded, and if they should be prefixed with a string. | |||||
| * Prefixing with a string allows you to add rudimentary namespacing | |||||
| */ | |||||
| def ioLoggers: List[(String, chisel3.Bundle)] | |||||
| import scala.collection.mutable._ | import scala.collection.mutable._ | ||||
| private val log = ArrayBuffer[LinkedHashMap[String, BigInt]]() | private val log = ArrayBuffer[LinkedHashMap[String, BigInt]]() | ||||
| override def step(n: Int): Unit = { | override def step(n: Int): Unit = { | ||||
| ioLoggers.foreach{ ioLogger => log.append(peek(ioLogger)) } | |||||
| val entry = ioLoggers.map{ case (label, ioLogger) => | |||||
| val bundleValues = peek(ioLogger).toList | |||||
| .map{ case(key, value) => (label + key, value) } | |||||
| .toMap | |||||
| bundleValues | |||||
| } | |||||
| log.append(entry.foldLeft(LinkedHashMap[String, BigInt]())(_ ++ _)) | |||||
| super.step(n) | super.step(n) | ||||
| } | } | ||||
| def getLog = log | def getLog = log | ||||
| @@ -106,11 +118,17 @@ object FileUtils { | |||||
| new File(getClass.getClassLoader.getResource(name).getPath) | new File(getClass.getClassLoader.getResource(name).getPath) | ||||
| } | } | ||||
| def getSvgDir: File = | |||||
| new File(getClass.getClassLoader.getResource("svgs").getPath) | |||||
| def getSvgDir: File = { | |||||
| val f = new File(getClass.getClassLoader.getResource("svgs").getPath) | |||||
| say(f) | |||||
| f | |||||
| } | |||||
| def getAllSvgs: List[File] = | |||||
| getListOfFilesRecursive(getSvgDir.getPath).filter( f => f.getPath.endsWith(".svg") ) | |||||
| def getAllSvgs: List[File] = { | |||||
| val fs = getListOfFilesRecursive(getSvgDir.getPath).filter( f => f.getPath.endsWith(".svg") ) | |||||
| say(fs) | |||||
| fs | |||||
| } | |||||
| import scala.concurrent.ExecutionContext | import scala.concurrent.ExecutionContext | ||||
| @@ -121,8 +139,6 @@ object FileUtils { | |||||
| def writeSvg(source: String, cycle: Int): Pipe[IO,String,Unit] = { | def writeSvg(source: String, cycle: Int): Pipe[IO,String,Unit] = { | ||||
| import sys.process._ | import sys.process._ | ||||
| say("pwd".!) | |||||
| // val svgDir = getSvgDir.toPath.toString + s"/${source}Output" | |||||
| val svgDir = "pwd".!!.filter(_ >= ' ') + s"/svgOutput" | val svgDir = "pwd".!!.filter(_ >= ' ') + s"/svgOutput" | ||||
| (new File(svgDir)).mkdir() | (new File(svgDir)).mkdir() | ||||
| val svgDest = new File(svgDir + s"/$cycle.svg").toPath | val svgDest = new File(svgDir + s"/$cycle.svg").toPath | ||||