├── project ├── plugins.sbt └── build.properties ├── src ├── main │ ├── resources │ │ └── gcd │ │ │ ├── ResilientRegisterAnnos.json │ │ │ ├── EasyRandom.cpp │ │ │ ├── SoftErrorAnnos.json │ │ │ └── SoftErrorFlopModel.v │ └── scala │ │ └── gcd │ │ ├── tools │ │ ├── ResilientRegisterFlow.scala │ │ ├── MajorityGate.scala │ │ ├── PartializeConnects.scala │ │ ├── RemoveTrivialPartialConnects.scala │ │ ├── InsertSoftErrorModels.scala │ │ └── ResilientRegisters.scala │ │ └── GCD.scala └── test │ └── scala │ └── gcd │ ├── GCDMain.scala │ └── GCDUnitTest.scala ├── Makefile ├── .gitignore ├── scalastyle-config.xml ├── scalastyle-test-config.xml └── README.md /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | logLevel := Level.Warn -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version = 1.3.2 2 | -------------------------------------------------------------------------------- /src/main/resources/gcd/ResilientRegisterAnnos.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "class":"gcd.tools.ResilientRegisterAnnotation", 4 | "target":"~GCD|GCD>x" 5 | }, 6 | { 7 | "class":"gcd.tools.ResilientRegisterAnnotation", 8 | "target":"~GCD|GCD>y" 9 | } 10 | ] 11 | -------------------------------------------------------------------------------- /src/main/resources/gcd/EasyRandom.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "svdpi.h" 6 | 7 | extern int easy_random(void) { 8 | static bool initialized = false; 9 | if (!initialized) { 10 | srand(time(NULL)); 11 | initialized = true; 12 | } 13 | return rand(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/scala/gcd/tools/ResilientRegisterFlow.scala: -------------------------------------------------------------------------------- 1 | // See README.md for license details. 2 | 3 | package gcd.tools 4 | 5 | import firrtl._ 6 | 7 | class ResilientRegisterFlow extends SeqTransform { 8 | def inputForm = LowForm 9 | def outputForm = LowForm 10 | 11 | def transforms = Seq(ResilientRegisters, new ResolveAndCheck(), passes.SplitExpressions, InsertSoftErrorModels, new ResolveAndCheck()) 12 | } 13 | -------------------------------------------------------------------------------- /src/main/resources/gcd/SoftErrorAnnos.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "class":"gcd.tools.SoftErrorRegisterAnnotation", 4 | "target":"~GCD|GCD>x", 5 | "errorPPM":1000 6 | }, 7 | { 8 | "class":"gcd.tools.SoftErrorRegisterAnnotation", 9 | "target":"~GCD|GCD>y", 10 | "errorPPM":1000 11 | }, 12 | { 13 | "class":"firrtl.transforms.BlackBoxPathAnno", 14 | "target":"GCD.SoftErrorFlopModel", 15 | "path":"src/main/resources/gcd/SoftErrorFlopModel.v" 16 | }, 17 | { 18 | "class":"firrtl.transforms.BlackBoxPathAnno", 19 | "target":"GCD.SoftErrorFlopModel", 20 | "path":"src/main/resources/gcd/EasyRandom.cpp" 21 | } 22 | ] 23 | -------------------------------------------------------------------------------- /src/main/resources/gcd/SoftErrorFlopModel.v: -------------------------------------------------------------------------------- 1 | module SoftErrorFlopModel #(parameter WIDTH=1, parameter ERROR_PPM=10) 2 | ( 3 | input clock, 4 | input [WIDTH-1:0] D, 5 | output reg [WIDTH-1:0] Q 6 | ); 7 | 8 | import "DPI-C" function int easy_random (); 9 | 10 | genvar i; 11 | generate 12 | always @(posedge clock) begin 13 | for (i = 0; i < WIDTH; i = i + 1) begin 14 | Q[i] <= D[i]; 15 | if (({easy_random()} % 1000000) < ERROR_PPM) 16 | Q[i] <= ~D[i]; // Random bit flip 17 | end 18 | end 19 | endgenerate 20 | 21 | endmodule // SoftErrorFlopModel 22 | 23 | -------------------------------------------------------------------------------- /src/main/scala/gcd/tools/MajorityGate.scala: -------------------------------------------------------------------------------- 1 | // See README.md for license details. 2 | 3 | package gcd.tools 4 | 5 | import firrtl._ 6 | import firrtl.ir._ 7 | 8 | object MajorityGate { 9 | private def and(a: Expression, b: Expression) = DoPrim(PrimOps.And, Seq(a, b), Nil, a.tpe) 10 | private def or(a: Expression, b: Expression) = DoPrim(PrimOps.Or, Seq(a, b), Nil, a.tpe) 11 | 12 | def apply(a: Expression, b: Expression, c: Expression): Expression = { 13 | // To make this reusable, we can't rely on it being called from a low-form pass 14 | require(a.tpe == b.tpe && b.tpe == c.tpe) 15 | require(a.tpe.isInstanceOf[GroundType]) 16 | or(or(and(a, b), and(b, c)), and(a, c)) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/scala/gcd/tools/PartializeConnects.scala: -------------------------------------------------------------------------------- 1 | // See README.md for license details. 2 | 3 | package gcd.tools 4 | 5 | import firrtl._ 6 | import firrtl.ir._ 7 | import firrtl.Mappers._ 8 | 9 | class PartializeConnects extends Transform { 10 | val inputForm = LowForm 11 | val outputForm = HighForm 12 | 13 | def transformStmt(stmt: Statement): Statement = stmt match { 14 | case Connect(info, loc, expr) => 15 | PartialConnect(info, loc, expr) 16 | case s => s.map(transformStmt) 17 | } 18 | 19 | def transformMod(m: DefModule): DefModule = m.map(transformStmt) 20 | 21 | def execute(state: CircuitState): CircuitState = { 22 | val transformed = state.circuit.map(transformMod) 23 | state.copy(circuit = transformed) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/scala/gcd/tools/RemoveTrivialPartialConnects.scala: -------------------------------------------------------------------------------- 1 | // See README.md for license details. 2 | 3 | package gcd.tools 4 | 5 | import firrtl._ 6 | import firrtl.ir._ 7 | import firrtl.Mappers._ 8 | 9 | class RemoveTrivialPartialConnects extends Transform { 10 | val inputForm = HighForm 11 | val outputForm = HighForm 12 | 13 | def transformStmt(stmt: Statement): Statement = stmt match { 14 | case PartialConnect(info, l, r) if (l.tpe == r.tpe) => 15 | Connect(info, l, r) 16 | case s => s.map(transformStmt) 17 | } 18 | 19 | def transformMod(m: DefModule): DefModule = m.map(transformStmt) 20 | 21 | def execute(state: CircuitState): CircuitState = { 22 | val transformed = state.circuit.map(transformMod) 23 | state.copy(circuit = transformed) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/scala/gcd/GCD.scala: -------------------------------------------------------------------------------- 1 | // See README.md for license details. 2 | 3 | package gcd 4 | 5 | import chisel3._ 6 | 7 | /** 8 | * Compute GCD using subtraction method. 9 | * Subtracts the smaller from the larger until register y is zero. 10 | * value in register x is then the GCD 11 | */ 12 | class GCD extends Module { 13 | val io = IO(new Bundle { 14 | val value1 = Input(UInt(16.W)) 15 | val value2 = Input(UInt(16.W)) 16 | val loadingValues = Input(Bool()) 17 | val outputGCD = Output(UInt(16.W)) 18 | val outputValid = Output(Bool()) 19 | }) 20 | 21 | val x = Reg(UInt()) 22 | val y = Reg(UInt()) 23 | 24 | when(x > y) { x := x - y } 25 | .otherwise { y := y - x } 26 | 27 | when(io.loadingValues) { 28 | x := io.value1 29 | y := io.value2 30 | } 31 | 32 | io.outputGCD := x 33 | io.outputValid := y === 0.U 34 | } 35 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: test test-partialize-connects test-partialize-and-remove test-errors test-resilient test-resilient-errors 2 | 3 | test: 4 | sbt 'test:runMain gcd.GCDMain --backend-name verilator' 5 | 6 | test-partialize-connects: 7 | sbt 'test:runMain gcd.GCDMain --backend-name verilator -fct gcd.tools.PartializeConnects' 8 | 9 | test-partialize-and-remove: 10 | sbt 'test:runMain gcd.GCDMain --backend-name verilator -fct gcd.tools.PartializeConnects gcd.tools.RemoveTrivialPartialConnects' 11 | 12 | test-errors: 13 | sbt 'test:runMain gcd.GCDMain --backend-name verilator -fct gcd.tools.ResilientRegisterFlow -faf src/main/resources/gcd/SoftErrorAnnos.json' 14 | 15 | test-resilient: 16 | sbt 'test:runMain gcd.GCDMain --backend-name verilator -fct gcd.tools.ResilientRegisterFlow -faf src/main/resources/gcd/ResilientRegisterAnnos.json' 17 | 18 | test-resilient-errors: 19 | sbt 'test:runMain gcd.GCDMain --backend-name verilator -fct gcd.tools.ResilientRegisterFlow -faf src/main/resources/gcd/ResilientRegisterAnnos.json -faf src/main/resources/gcd/SoftErrorAnnos.json' 20 | 21 | -------------------------------------------------------------------------------- /src/test/scala/gcd/GCDMain.scala: -------------------------------------------------------------------------------- 1 | // See README.md for license details. 2 | 3 | package gcd 4 | 5 | import chisel3._ 6 | 7 | /** 8 | * This provides an alternate way to run tests, by executing then as a main 9 | * From sbt (Note: the test: prefix is because this main is under the test package hierarchy): 10 | * {{{ 11 | * test:runMain gcd.GCDMain 12 | * }}} 13 | * To see all command line options use: 14 | * {{{ 15 | * test:runMain gcd.GCDMain --help 16 | * }}} 17 | * To run with verilator: 18 | * {{{ 19 | * test:runMain gcd.GCDMain --backend-name verilator 20 | * }}} 21 | * To run with verilator from your terminal shell use: 22 | * {{{ 23 | * sbt 'test:runMain gcd.GCDMain --backend-name verilator' 24 | * }}} 25 | */ 26 | object GCDMain extends App { 27 | iotesters.Driver.execute(args, () => new GCD) { 28 | c => new GCDUnitTester(c) 29 | } 30 | } 31 | 32 | /** 33 | * This provides a way to run the firrtl-interpreter REPL (or shell) 34 | * on the lowered firrtl generated by your circuit. You will be placed 35 | * in an interactive shell. This can be very helpful as a debugging 36 | * technique. Type help to see a list of commands. 37 | * 38 | * To run from sbt 39 | * {{{ 40 | * test:runMain gcd.GCDRepl 41 | * }}} 42 | * To run from sbt and see the half a zillion options try 43 | * {{{ 44 | * test:runMain gcd.GCDRepl --help 45 | * }}} 46 | */ 47 | object GCDRepl extends App { 48 | iotesters.Driver.executeFirrtlRepl(args, () => new GCD) 49 | } -------------------------------------------------------------------------------- /src/main/scala/gcd/tools/InsertSoftErrorModels.scala: -------------------------------------------------------------------------------- 1 | // See README.md for license details. 2 | 3 | package gcd.tools 4 | 5 | import firrtl._ 6 | import firrtl.ir._ 7 | import firrtl.Mappers._ 8 | import firrtl.annotations._ 9 | 10 | import collection.mutable 11 | 12 | case class SoftErrorRegisterAnnotation(target: ReferenceTarget, errorPPM: BigInt) extends SingleTargetAnnotation[ReferenceTarget] { 13 | require(target.component.isEmpty) 14 | def duplicate(newTarget: ReferenceTarget): SoftErrorRegisterAnnotation = { 15 | this.copy(target = newTarget) 16 | } 17 | } 18 | 19 | object SoftErrorModel { 20 | val defname = "SoftErrorFlopModel" 21 | def clock = Port(NoInfo, "clock", Input, ClockType) 22 | def d = Port(NoInfo, "D", Input, UIntType(UnknownWidth)) 23 | def q = Port(NoInfo, "Q", Output, UIntType(UnknownWidth)) 24 | def decl(dType: Type, errorPPM: BigInt, name: String): ExtModule = { 25 | dType match { 26 | case UIntType(IntWidth(w)) => 27 | val ports = Seq(clock, d.copy(tpe = dType), q.copy(tpe = dType)) 28 | ExtModule(NoInfo, name, ports, defname, Seq(IntParam("WIDTH", w), IntParam("ERROR_PPM", errorPPM))) 29 | case _ => 30 | throw new Exception("Soft error models current support only UIntType of known width") 31 | } 32 | } 33 | } 34 | 35 | object InsertSoftErrorModels extends Transform { 36 | val inputForm = LowForm 37 | val outputForm = LowForm 38 | 39 | private def replaceRegRefs(mt: ModuleTarget, bbInfo: Map[ReferenceTarget, (String, BigInt)])(expr: Expression): Expression = { 40 | expr match { 41 | case WRef(name, tpe, RegKind, SourceFlow) if (bbInfo.contains(mt.ref(name))) => 42 | WSubField(WRef(name), "Q") 43 | case e => e.map(replaceRegRefs(mt, bbInfo)) 44 | } 45 | } 46 | 47 | private def replaceRegisters(mt: ModuleTarget, bbInfo: Map[ReferenceTarget, (String, BigInt)], bbDecls: mutable.Set[ExtModule])(stmt: Statement): Statement = { 48 | stmt.map(replaceRegRefs(mt, bbInfo)) match { 49 | case DefRegister(info, name, tpe, clock, reset, init) if (bbInfo.contains(mt.ref(name))) => 50 | require(reset == UIntLiteral(0), "Soft error models currently do not support reset values") 51 | val (moduleName, errorPPM) = bbInfo(mt.ref(name)) 52 | val decl = SoftErrorModel.decl(tpe, errorPPM, moduleName) 53 | val inst = WDefInstance(info, name, moduleName, UnknownType) 54 | val conn = Connect(info, WSubField(WRef(inst), SoftErrorModel.clock.name), clock) 55 | bbDecls += decl 56 | Block(Seq(inst, conn)) 57 | case Connect(info, WRef(name, tpe, RegKind, SinkFlow), rhs) if (bbInfo.contains(mt.ref(name))) => 58 | Connect(info, WSubField(WRef(name), "D"), rhs) 59 | case s => s.map(replaceRegisters(mt, bbInfo, bbDecls)) 60 | } 61 | } 62 | 63 | def execute(state: CircuitState): CircuitState = { 64 | val moduleNS = Namespace(state.circuit) 65 | val softErrorRegInfo = state.annotations.collect { 66 | case SoftErrorRegisterAnnotation(rt, errorPPM) => 67 | require(rt.isLocal) 68 | rt -> (moduleNS.newName(SoftErrorModel.defname), errorPPM) 69 | } 70 | 71 | val bbInfo = softErrorRegInfo.toMap 72 | val bbDecls = new mutable.LinkedHashSet[ExtModule] 73 | 74 | val transformedModules = state.circuit.modules.map { 75 | case m => 76 | val mt = ModuleTarget(state.circuit.main, m.name) 77 | m.map(replaceRegisters(mt, bbInfo, bbDecls)) 78 | } 79 | 80 | val transformedCircuit = state.circuit.copy(modules = transformedModules ++ bbDecls) 81 | val filteredAnnos = state.annotations.filterNot(_.isInstanceOf[SoftErrorRegisterAnnotation]) 82 | state.copy(transformedCircuit, outputForm, filteredAnnos, None) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/scala/gcd/tools/ResilientRegisters.scala: -------------------------------------------------------------------------------- 1 | // See README.md for license details. 2 | 3 | package gcd.tools 4 | 5 | import firrtl._ 6 | import firrtl.ir._ 7 | import firrtl.Mappers._ 8 | import firrtl.annotations._ 9 | 10 | case class ResilientRegisterAnnotation(target: ReferenceTarget) extends SingleTargetAnnotation[ReferenceTarget] { 11 | def duplicate(newTarget: ReferenceTarget): ResilientRegisterAnnotation = { 12 | this.copy(target = newTarget) 13 | } 14 | } 15 | 16 | object ResilientRegisters extends Transform with ResolvedAnnotationPaths { 17 | val inputForm = LowForm 18 | val outputForm = LowForm 19 | 20 | val annotationClasses = Seq(classOf[ResilientRegisterAnnotation]) 21 | 22 | type TripleCopyNameMap = Map[String, Tuple3[String, String, String]] 23 | 24 | private def renameReg(reg: DefRegister, newName: String): DefRegister = { 25 | val renamed = reg.copy(name = newName) 26 | if (renamed.reset == UIntLiteral(0)) { 27 | renamed.copy(init = WRef(renamed)) 28 | } else { 29 | renamed 30 | } 31 | } 32 | 33 | private def makeRegTriples(copyNameMap: TripleCopyNameMap)(stmt: Statement): Statement = { 34 | stmt match { 35 | case reg: DefRegister if (copyNameMap.contains(reg.name)) => 36 | // Make three copies of the register with new names 37 | val (name0, name1, name2) = copyNameMap(reg.name) 38 | val c0 = renameReg(reg, name0) 39 | val c1 = renameReg(reg, name1) 40 | val c2 = renameReg(reg, name2) 41 | // Make a majority-valued node that shares the register's original name 42 | val majExpr = MajorityGate(WRef(c0), WRef(c1), WRef(c2)) 43 | val majNode = DefNode(reg.info, reg.name, majExpr) 44 | Block(Seq(c0, c1, c2, majNode)) 45 | case Connect(info, WRef(name, tpe, RegKind, SinkFlow), rhs) if (copyNameMap.contains(name)) => 46 | val (name0, name1, name2) = copyNameMap(name) 47 | val conn0 = Connect(info, WRef(name0, tpe, RegKind, SinkFlow), rhs) 48 | val conn1 = Connect(info, WRef(name1, tpe, RegKind, SinkFlow), rhs) 49 | val conn2 = Connect(info, WRef(name2, tpe, RegKind, SinkFlow), rhs) 50 | Block(Seq(conn0, conn1, conn2)) 51 | case s => s.map(makeRegTriples(copyNameMap)) 52 | } 53 | } 54 | 55 | private def regTripleNames(ns: Namespace, regName: String): (String, String, String) = { 56 | (ns.newName(s"${regName}_copy_0"), ns.newName(s"${regName}_copy_1"), ns.newName(s"${regName}_copy_2")) 57 | } 58 | 59 | def execute(state: CircuitState): CircuitState = { 60 | val resilientRegTargets = state.annotations.collect { 61 | case ResilientRegisterAnnotation(target) => 62 | require(target.isLocal) 63 | target 64 | } 65 | 66 | val resilientRegsByModule = resilientRegTargets.groupBy(_.module) 67 | 68 | // We need to record that we've split each register into three new ones 69 | val renames = RenameMap() 70 | 71 | val transformedModules = state.circuit.modules.map { 72 | case m: DefModule if (resilientRegsByModule.contains(m.name)) => 73 | val ns = Namespace(m) 74 | val resilientRegs = resilientRegsByModule(m.name) 75 | val copyMap = resilientRegs.map(rTarget => rTarget -> regTripleNames(ns, rTarget.ref)).toMap 76 | val copyNameMap = copyMap.map { case (k, v) => k.ref -> v } 77 | copyMap.foreach { 78 | case (oldTarget, (copyName0, copyName1, copyName2)) => 79 | val newTargets = Seq(copyName0, copyName1, copyName2).map(name => oldTarget.copy(ref = name)) 80 | renames.record(oldTarget, newTargets) 81 | } 82 | m.map(makeRegTriples(copyNameMap)) 83 | case m => m 84 | } 85 | 86 | val transformedCircuit = state.circuit.copy(modules = transformedModules) 87 | val filteredAnnos = state.annotations.filterNot(_.isInstanceOf[ResilientRegisterAnnotation]) 88 | state.copy(transformedCircuit, outputForm, filteredAnnos, Some(renames)) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/test/scala/gcd/GCDUnitTest.scala: -------------------------------------------------------------------------------- 1 | // See README.md for license details. 2 | 3 | package gcd 4 | 5 | import java.io.File 6 | 7 | import chisel3.iotesters 8 | import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester} 9 | 10 | class GCDUnitTester(c: GCD) extends PeekPokeTester(c) { 11 | /** 12 | * compute the gcd and the number of steps it should take to do it 13 | * 14 | * @param a positive integer 15 | * @param b positive integer 16 | * @return the GCD of a and b 17 | */ 18 | def computeGcd(a: Int, b: Int): (Int, Int) = { 19 | var x = a 20 | var y = b 21 | var depth = 1 22 | while(y > 0 ) { 23 | if (x > y) { 24 | x -= y 25 | } 26 | else { 27 | y -= x 28 | } 29 | depth += 1 30 | } 31 | (x, depth) 32 | } 33 | 34 | private val gcd = c 35 | 36 | for(i <- 1 to 40 by 3) { 37 | for (j <- 1 to 40 by 7) { 38 | poke(gcd.io.value1, i) 39 | poke(gcd.io.value2, j) 40 | poke(gcd.io.loadingValues, 1) 41 | step(1) 42 | poke(gcd.io.loadingValues, 0) 43 | 44 | val (expected_gcd, steps) = computeGcd(i, j) 45 | 46 | step(steps - 1) // -1 is because we step(1) already to toggle the enable 47 | expect(gcd.io.outputGCD, expected_gcd) 48 | expect(gcd.io.outputValid, 1) 49 | } 50 | } 51 | } 52 | 53 | /** 54 | * This is a trivial example of how to run this Specification 55 | * From within sbt use: 56 | * {{{ 57 | * testOnly gcd.GCDTester 58 | * }}} 59 | * From a terminal shell use: 60 | * {{{ 61 | * sbt 'testOnly gcd.GCDTester' 62 | * }}} 63 | */ 64 | class GCDTester extends ChiselFlatSpec { 65 | // Disable this until we fix isCommandAvailable to swallow stderr along with stdout 66 | private val backendNames = if(firrtl.FileUtils.isCommandAvailable(Seq("verilator", "--version"))) { 67 | Array("firrtl", "verilator") 68 | } 69 | else { 70 | Array("firrtl") 71 | } 72 | for ( backendName <- backendNames ) { 73 | "GCD" should s"calculate proper greatest common denominator (with $backendName)" in { 74 | Driver(() => new GCD, backendName) { 75 | c => new GCDUnitTester(c) 76 | } should be (true) 77 | } 78 | } 79 | 80 | "Basic test using Driver.execute" should "be used as an alternative way to run specification" in { 81 | iotesters.Driver.execute(Array(), () => new GCD) { 82 | c => new GCDUnitTester(c) 83 | } should be (true) 84 | } 85 | 86 | if(backendNames.contains("verilator")) { 87 | "using --backend-name verilator" should "be an alternative way to run using verilator" in { 88 | iotesters.Driver.execute(Array("--backend-name", "verilator"), () => new GCD) { 89 | c => new GCDUnitTester(c) 90 | } should be(true) 91 | } 92 | } 93 | 94 | "running with --is-verbose" should "show more about what's going on in your tester" in { 95 | iotesters.Driver.execute(Array("--is-verbose"), () => new GCD) { 96 | c => new GCDUnitTester(c) 97 | } should be(true) 98 | } 99 | 100 | /** 101 | * By default verilator backend produces vcd file, and firrtl and treadle backends do not. 102 | * Following examples show you how to turn on vcd for firrtl and treadle and how to turn it off for verilator 103 | */ 104 | 105 | "running with --generate-vcd-output on" should "create a vcd file from your test" in { 106 | iotesters.Driver.execute( 107 | Array("--generate-vcd-output", "on", "--target-dir", "test_run_dir/make_a_vcd", "--top-name", "make_a_vcd"), 108 | () => new GCD 109 | ) { 110 | 111 | c => new GCDUnitTester(c) 112 | } should be(true) 113 | 114 | new File("test_run_dir/make_a_vcd/make_a_vcd.vcd").exists should be (true) 115 | } 116 | 117 | "running with --generate-vcd-output off" should "not create a vcd file from your test" in { 118 | iotesters.Driver.execute( 119 | Array("--generate-vcd-output", "off", "--target-dir", "test_run_dir/make_no_vcd", "--top-name", "make_no_vcd", 120 | "--backend-name", "verilator"), 121 | () => new GCD 122 | ) { 123 | 124 | c => new GCDUnitTester(c) 125 | } should be(true) 126 | 127 | new File("test_run_dir/make_no_vcd/make_a_vcd.vcd").exists should be (false) 128 | 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Project Specific stuff 2 | test_run_dir/* 3 | ### XilinxISE template 4 | # intermediate build files 5 | *.bgn 6 | *.bit 7 | *.bld 8 | *.cmd_log 9 | *.drc 10 | *.ll 11 | *.lso 12 | *.msd 13 | *.msk 14 | *.ncd 15 | *.ngc 16 | *.ngd 17 | *.ngr 18 | *.pad 19 | *.par 20 | *.pcf 21 | *.prj 22 | *.ptwx 23 | *.rbb 24 | *.rbd 25 | *.stx 26 | *.syr 27 | *.twr 28 | *.twx 29 | *.unroutes 30 | *.ut 31 | *.xpi 32 | *.xst 33 | *_bitgen.xwbt 34 | *_envsettings.html 35 | *_map.map 36 | *_map.mrp 37 | *_map.ngm 38 | *_map.xrpt 39 | *_ngdbuild.xrpt 40 | *_pad.csv 41 | *_pad.txt 42 | *_par.xrpt 43 | *_summary.html 44 | *_summary.xml 45 | *_usage.xml 46 | *_xst.xrpt 47 | 48 | # project-wide generated files 49 | *.gise 50 | par_usage_statistics.html 51 | usage_statistics_webtalk.html 52 | webtalk.log 53 | webtalk_pn.xml 54 | 55 | # generated folders 56 | iseconfig/ 57 | xlnx_auto_0_xdb/ 58 | xst/ 59 | _ngo/ 60 | _xmsgs/ 61 | ### Eclipse template 62 | *.pydevproject 63 | .metadata 64 | .gradle 65 | bin/ 66 | tmp/ 67 | *.tmp 68 | *.bak 69 | *.swp 70 | *~.nib 71 | local.properties 72 | .settings/ 73 | .loadpath 74 | 75 | # Eclipse Core 76 | .project 77 | 78 | # External tool builders 79 | .externalToolBuilders/ 80 | 81 | # Locally stored "Eclipse launch configurations" 82 | *.launch 83 | 84 | # CDT-specific 85 | .cproject 86 | 87 | # JDT-specific (Eclipse Java Development Tools) 88 | .classpath 89 | 90 | # Java annotation processor (APT) 91 | .factorypath 92 | 93 | # PDT-specific 94 | .buildpath 95 | 96 | # sbteclipse plugin 97 | .target 98 | 99 | # TeXlipse plugin 100 | .texlipse 101 | ### C template 102 | # Object files 103 | *.o 104 | *.ko 105 | *.obj 106 | *.elf 107 | 108 | # Precompiled Headers 109 | *.gch 110 | *.pch 111 | 112 | # Libraries 113 | *.lib 114 | *.a 115 | *.la 116 | *.lo 117 | 118 | # Shared objects (inc. Windows DLLs) 119 | *.dll 120 | *.so 121 | *.so.* 122 | *.dylib 123 | 124 | # Executables 125 | *.exe 126 | *.out 127 | *.app 128 | *.i*86 129 | *.x86_64 130 | *.hex 131 | 132 | # Debug files 133 | *.dSYM/ 134 | ### SBT template 135 | # Simple Build Tool 136 | # http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html#configuring-version-control 137 | 138 | target/ 139 | lib_managed/ 140 | src_managed/ 141 | project/boot/ 142 | .history 143 | .cache 144 | ### Emacs template 145 | # -*- mode: gitignore; -*- 146 | *~ 147 | \#*\# 148 | /.emacs.desktop 149 | /.emacs.desktop.lock 150 | *.elc 151 | auto-save-list 152 | tramp 153 | .\#* 154 | 155 | # Org-mode 156 | .org-id-locations 157 | *_archive 158 | 159 | # flymake-mode 160 | *_flymake.* 161 | 162 | # eshell files 163 | /eshell/history 164 | /eshell/lastdir 165 | 166 | # elpa packages 167 | /elpa/ 168 | 169 | # reftex files 170 | *.rel 171 | 172 | # AUCTeX auto folder 173 | /auto/ 174 | 175 | # cask packages 176 | .cask/ 177 | ### Vim template 178 | [._]*.s[a-w][a-z] 179 | [._]s[a-w][a-z] 180 | *.un~ 181 | Session.vim 182 | .netrwhist 183 | *~ 184 | ### JetBrains template 185 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio 186 | 187 | *.iml 188 | 189 | ## Directory-based project format: 190 | .idea/ 191 | # if you remove the above rule, at least ignore the following: 192 | 193 | # User-specific stuff: 194 | # .idea/workspace.xml 195 | # .idea/tasks.xml 196 | # .idea/dictionaries 197 | 198 | # Sensitive or high-churn files: 199 | # .idea/dataSources.ids 200 | # .idea/dataSources.xml 201 | # .idea/sqlDataSources.xml 202 | # .idea/dynamic.xml 203 | # .idea/uiDesigner.xml 204 | 205 | # Gradle: 206 | # .idea/gradle.xml 207 | # .idea/libraries 208 | 209 | # Mongo Explorer plugin: 210 | # .idea/mongoSettings.xml 211 | 212 | ## File-based project format: 213 | *.ipr 214 | *.iws 215 | 216 | ## Plugin-specific files: 217 | 218 | # IntelliJ 219 | /out/ 220 | 221 | # mpeltonen/sbt-idea plugin 222 | .idea_modules/ 223 | 224 | # JIRA plugin 225 | atlassian-ide-plugin.xml 226 | 227 | # Crashlytics plugin (for Android Studio and IntelliJ) 228 | com_crashlytics_export_strings.xml 229 | crashlytics.properties 230 | crashlytics-build.properties 231 | ### C++ template 232 | # Compiled Object files 233 | *.slo 234 | *.lo 235 | *.o 236 | *.obj 237 | 238 | # Precompiled Headers 239 | *.gch 240 | *.pch 241 | 242 | # Compiled Dynamic libraries 243 | *.so 244 | *.dylib 245 | *.dll 246 | 247 | # Fortran module files 248 | *.mod 249 | 250 | # Compiled Static libraries 251 | *.lai 252 | *.la 253 | *.a 254 | *.lib 255 | 256 | # Executables 257 | *.exe 258 | *.out 259 | *.app 260 | ### OSX template 261 | .DS_Store 262 | .AppleDouble 263 | .LSOverride 264 | 265 | # Icon must end with two \r 266 | Icon 267 | 268 | # Thumbnails 269 | ._* 270 | 271 | # Files that might appear in the root of a volume 272 | .DocumentRevisions-V100 273 | .fseventsd 274 | .Spotlight-V100 275 | .TemporaryItems 276 | .Trashes 277 | .VolumeIcon.icns 278 | 279 | # Directories potentially created on remote AFP share 280 | .AppleDB 281 | .AppleDesktop 282 | Network Trash Folder 283 | Temporary Items 284 | .apdisk 285 | ### Xcode template 286 | # Xcode 287 | # 288 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 289 | 290 | ## Build generated 291 | build/ 292 | DerivedData 293 | 294 | ## Various settings 295 | *.pbxuser 296 | !default.pbxuser 297 | *.mode1v3 298 | !default.mode1v3 299 | *.mode2v3 300 | !default.mode2v3 301 | *.perspectivev3 302 | !default.perspectivev3 303 | xcuserdata 304 | 305 | ## Other 306 | *.xccheckout 307 | *.moved-aside 308 | *.xcuserstate 309 | ### Scala template 310 | *.class 311 | *.log 312 | 313 | # sbt specific 314 | .cache 315 | .history 316 | .lib/ 317 | dist/* 318 | target/ 319 | lib_managed/ 320 | src_managed/ 321 | project/boot/ 322 | project/plugins/project/ 323 | 324 | # Scala-IDE specific 325 | .scala_dependencies 326 | .worksheet 327 | ### Java template 328 | *.class 329 | 330 | # Mobile Tools for Java (J2ME) 331 | .mtj.tmp/ 332 | 333 | # Package Files # 334 | *.jar 335 | *.war 336 | *.ear 337 | 338 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 339 | hs_err_pid* 340 | 341 | -------------------------------------------------------------------------------- /scalastyle-config.xml: -------------------------------------------------------------------------------- 1 | 2 | Scalastyle standard configuration 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | No lines ending with a ; 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | |\|\||&&|:=|<>|<=|>=|!=|===|<<|>>|##|unary_(~|\-%?|!))$]]> 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /scalastyle-test-config.xml: -------------------------------------------------------------------------------- 1 | 2 | Scalastyle configuration for Chisel3 unit tests 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | No lines ending with a ; 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | |\|\||&&|:=|<>|<=|>=|!=|===|<<|>>|##|unary_(~|\-%?|!))$]]> 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Chisel Project Template 2 | ======================= 3 | 4 | You've done the Chisel [tutorials](https://github.com/ucb-bar/chisel-tutorial), and now you 5 | are ready to start your own chisel project. The following procedure should get you started 6 | with a clean running [Chisel3](https://github.com/freechipsproject/chisel3) project. 7 | 8 | > More and more users are finding IntelliJ to be a powerful tool for Chisel coding. See the 9 | [IntelliJ Installation Guide](https://github.com/ucb-bar/chisel-template/wiki/IntelliJ-Installation-Guide) for how to install it. 10 | 11 | ## Make your own Chisel3 project 12 | ### How to get started 13 | The first thing you want to do is clone this repo into a directory of your own. I'd recommend creating a chisel projects directory somewhere 14 | ```sh 15 | mkdir ~/ChiselProjects 16 | cd ~/ChiselProjects 17 | 18 | git clone https://github.com/ucb-bar/chisel-template.git MyChiselProject 19 | cd MyChiselProject 20 | ``` 21 | ### Make your project into a fresh git repo 22 | There may be more elegant way to do it, but the following works for me. **Note:** this project comes with a magnificent 339 line (at this writing) .gitignore file. 23 | You may want to edit that first in case we missed something, whack away at it, or start it from scratch. 24 | 25 | #### Clear out the old git stuff 26 | ```sh 27 | rm -rf .git 28 | git init 29 | git add .gitignore * 30 | ``` 31 | 32 | #### Rename project in build.sbt file 33 | Use your favorite text editor to change the first line of the **build.sbt** file 34 | (it ships as ```name := "chisel-module-template"```) to correspond 35 | to your project.
36 | Perhaps as ```name := "my-chisel-project"``` 37 | 38 | #### Clean up the README.md file 39 | Again use you editor of choice to make the README specific to your project. 40 | Be sure to update (or delete) the License section and add a LICENSE file of your own. 41 | 42 | #### Commit your changes 43 | ``` 44 | git commit -m 'Starting MyChiselProject' 45 | ``` 46 | Connecting this up to github or some other remote host is an exercise left to the reader. 47 | 48 | ### Did it work? 49 | You should now have a project based on Chisel3 that can be run.
50 | So go for it, at the command line in the project root. 51 | ```sh 52 | sbt 'testOnly gcd.GCDTester -- -z Basic' 53 | ``` 54 | >This tells the test harness to only run the test in GCDTester that contains the word Basic 55 | There are a number of other examples of ways to run tests in there, but we just want to see that 56 | one works. 57 | 58 | You should see a whole bunch of output that ends with something like the following lines 59 | ``` 60 | [info] [0.001] SEED 1540570744913 61 | test GCD Success: 168 tests passed in 1107 cycles in 0.067751 seconds 16339.24 Hz 62 | [info] [0.050] RAN 1102 CYCLES PASSED 63 | [info] GCDTester: 64 | [info] GCD 65 | [info] Basic test using Driver.execute 66 | [info] - should be used as an alternative way to run specification 67 | [info] using --backend-name verilator 68 | [info] running with --is-verbose 69 | [info] running with --generate-vcd-output on 70 | [info] running with --generate-vcd-output off 71 | [info] ScalaTest 72 | [info] Run completed in 3 seconds, 184 milliseconds. 73 | [info] Total number of tests run: 1 74 | [info] Suites: completed 1, aborted 0 75 | [info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0 76 | [info] All tests passed. 77 | [info] Passed: Total 1, Failed 0, Errors 0, Passed 1 78 | [success] Total time: 5 s, completed Oct 26, 2018 9:19:07 AM 79 | ``` 80 | If you see the above then... 81 | 82 | ### It worked! 83 | You are ready to go. We have a few recommended practices and things to do. 84 | * Use packages and following conventions for [structure](http://www.scala-sbt.org/0.13/docs/Directories.html) and [naming](http://docs.scala-lang.org/style/naming-conventions.html) 85 | * Package names should be clearly reflected in the testing hierarchy 86 | * Build tests for all your work. 87 | * This template includes a dependency on the Chisel3 IOTesters, this is a reasonable starting point for most tests 88 | * You can remove this dependency in the build.sbt file if necessary 89 | * Change the name of your project in the build.sbt file 90 | * Change your README.md 91 | 92 | There are [instructions for generating Verilog](https://github.com/freechipsproject/chisel3/wiki/Frequently-Asked-Questions#get-me-verilog) on the Chisel wiki. 93 | 94 | Some backends (verilator for example) produce VCD files by default, while other backends (firrtl and treadle) do not. 95 | You can control the generation of VCD files with the `--generate-vcd-output` flag. 96 | 97 | To run the simulation and generate a VCD output file regardless of the backend: 98 | ```bash 99 | sbt 'test:runMain gcd.GCDMain --generate-vcd-output on' 100 | ``` 101 | 102 | To run the simulation and suppress the generation of a VCD output file: 103 | ```bash 104 | sbt 'test:runMain gcd.GCDMain --generate-vcd-output off' 105 | ``` 106 | 107 | ## Development/Bug Fixes 108 | This is the release version of chisel-template. If you have bug fixes or 109 | changes you would like to see incorporated in this repo, please checkout 110 | the master branch and submit pull requests against it. 111 | 112 | ## License 113 | This is free and unencumbered software released into the public domain. 114 | 115 | Anyone is free to copy, modify, publish, use, compile, sell, or 116 | distribute this software, either in source code form or as a compiled 117 | binary, for any purpose, commercial or non-commercial, and by any 118 | means. 119 | 120 | In jurisdictions that recognize copyright laws, the author or authors 121 | of this software dedicate any and all copyright interest in the 122 | software to the public domain. We make this dedication for the benefit 123 | of the public at large and to the detriment of our heirs and 124 | successors. We intend this dedication to be an overt act of 125 | relinquishment in perpetuity of all present and future rights to this 126 | software under copyright law. 127 | 128 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 129 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 130 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 131 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 132 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 133 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 134 | OTHER DEALINGS IN THE SOFTWARE. 135 | 136 | For more information, please refer to 137 | --------------------------------------------------------------------------------