diff --git a/0_demo.ipynb b/0_demo.ipynb
index 9b5b022..b036e3b 100644
--- a/0_demo.ipynb
+++ b/0_demo.ipynb
@@ -65,7 +65,7 @@
"\n",
"Take the following example of a 3-point moving average implemented in the style of a FIR filter.\n",
"\n",
- " \n",
+ " \n",
"\n",
"Chisel provides similar base primitives as synthesizable Verilog and *can* be used as such! Run next cell to declare our Chisel module."
]
@@ -207,6 +207,13 @@
"\n",
"[Return to the top.](#top)"
]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
}
],
"metadata": {
@@ -222,7 +229,7 @@
"mimetype": "text/x-scala",
"name": "scala",
"nbconvert_exporter": "script",
- "version": "2.12.8"
+ "version": "2.12.10"
}
},
"nbformat": 4,
diff --git a/2.1_first_module.ipynb b/2.1_first_module.ipynb
index 7c38ef5..cc89299 100644
--- a/2.1_first_module.ipynb
+++ b/2.1_first_module.ipynb
@@ -31,10 +31,8 @@
},
{
"cell_type": "code",
- "execution_count": null,
- "metadata": {
- "collapsed": false
- },
+cleaclear "execution_count": null,
+ "metadata": {},
"outputs": [],
"source": [
"val path = System.getProperty(\"user.dir\") + \"/source/load-ivy.sc\"\n",
@@ -51,14 +49,14 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"import chisel3._\n",
"import chisel3.util._\n",
- "import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}"
+ "import chisel3.tester._\n",
+ "import chisel3.tester.RawTester.test\n",
+ "import dotvisualizer._"
]
},
{
@@ -76,9 +74,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"// Chisel Code: Declare a new module definition\n",
@@ -131,9 +127,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"// Scala Code: Elaborate our Chisel design by translating it to Verilog\n",
@@ -154,9 +148,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"// Chisel Code, but pass in a parameter to set widths of ports\n",
@@ -200,26 +192,26 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"// Scala Code: Calling Driver to instantiate Passthrough + PeekPokeTester and execute the test.\n",
"// Don't worry about understanding this code; it is very complicated Scala.\n",
"// Think of it more as boilerplate to run a Chisel test.\n",
- "val testResult = Driver(() => new Passthrough()) {\n",
- " c => new PeekPokeTester(c) {\n",
- " poke(c.io.in, 0) // Set our input to value 0\n",
- " expect(c.io.out, 0) // Assert that the output correctly has 0\n",
- " poke(c.io.in, 1) // Set our input to value 1\n",
- " expect(c.io.out, 1) // Assert that the output correctly has 1\n",
- " poke(c.io.in, 2) // Set our input to value 2\n",
- " expect(c.io.out, 2) // Assert that the output correctly has 2\n",
- " }\n",
+ "test(new Passthrough()) { c =>\n",
+ " c.io.in.poke(0.U) // Set our input to value 0\n",
+ " c.io.out.expect(0.U) // Assert that the output correctly has 0\n",
+ " c.io.in.poke(1.U) // Set our input to value 1\n",
+ " c.io.out.expect(1.U) // Assert that the output correctly has 1\n",
+ " c.io.in.poke(2.U) // Set our input to value 2\n",
+ " c.io.out.expect(2.U) // Assert that the output correctly has 2\n",
"}\n",
- "assert(testResult) // Scala Code: if testResult == false, will throw an error\n",
- "println(\"SUCCESS!!\") // Scala Code: if we get here, our tests passed!"
+ "println(\"SUCCESS!!\") // Scala Code: if we get here, our tests passed!\n",
+ "\n",
+ "(new stage.DiagrammerStage).execute(\n",
+ " Array(\"--target-dir\", \"diagrams\"),\n",
+ " Seq(chisel3.stage.ChiselGeneratorAnnotation(() => new Passthrough()))\n",
+ ")"
]
},
{
@@ -228,7 +220,11 @@
"source": [
"What's going on? The test accepts a `Passthrough` module, assigns values to the module's inputs, and checks its outputs. To set an input, we call `poke`. To check an output, we call `expect`. If we don't want to compare the output to an expected value (no assertion), we can `peek` the output instead.\n",
"\n",
- "If all `expect` statements are true, then our boilerplate code will return true (see `testResult`)."
+ "If all `expect` statements are true, then our boilerplate code will return pass.\n",
+ "\n",
+ ">Note that the `poke` and `expect` use chisel hardware literal notation. Both operations expect literals of the correct type.\n",
+ "If `poke`ing a `UInt()` you must supply a `UInt` literal (example: `c.io.in.poke(10.U)`, likewise if the input is a `Bool()` the `poke` would expect either `true.B` or `false.B`.\n",
+ "\n"
]
},
{
@@ -242,16 +238,27 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": true
- },
+ "metadata": {},
"outputs": [],
"source": [
- "val test10result = ???\n",
+ "// Test with width 10\n",
+ "\n",
+ "// Test with width 20\n",
"\n",
- "val test20result = ???\n",
+ "test(new PassthroughGenerator(10)) { c =>\n",
+ " c.io.in.poke(0.U)\n",
+ " c.io.out.expect(0.U)\n",
+ " c.io.in.poke(1023.U)\n",
+ " c.io.out.expect(1023.U)\n",
+ "}\n",
+ "\n",
+ "test(new PassthroughGenerator(20)) { c =>\n",
+ " c.io.in.poke(0.U)\n",
+ " c.io.out.expect(0.U)\n",
+ " c.io.in.poke(1048575.U)\n",
+ " c.io.out.expect(1048575.U)\n",
+ "}\n",
"\n",
- "assert((test10result == true) && (test20result == true))\n",
"println(\"SUCCESS!!\") // Scala Code: if we get here, our tests passed!"
]
},
@@ -264,22 +271,18 @@
"Solution (click to toggle displaying it) \n",
"\n",
"\n",
- "val test10result = Driver(() => new PassthroughGenerator(10)) {\n",
- " c => new PeekPokeTester(c) {\n",
- " poke(c.io.in, 0)\n",
- " expect(c.io.out, 0)\n",
- " poke(c.io.in, 1023)\n",
- " expect(c.io.out, 1023)\n",
- " }\n",
+ "test(new PassthroughGenerator(10)) { c =>\n",
+ " c.io.in.poke(0.U)\n",
+ " c.io.out.expect(0.U)\n",
+ " c.io.in.poke(1023.U)\n",
+ " c.io.out.expect(1023.U)\n",
"}\n",
"\n",
- "val test20result = Driver(() => new PassthroughGenerator(20)) {\n",
- " c => new PeekPokeTester(c) {\n",
- " poke(c.io.in, 0)\n",
- " expect(c.io.out, 0)\n",
- " poke(c.io.in, 1048575)\n",
- " expect(c.io.out, 1048575)\n",
- " }\n",
+ "test(new PassthroughGenerator(20)) { c =>\n",
+ " c.io.in.poke(0.U)\n",
+ " c.io.out.expect(0.U)\n",
+ " c.io.in.poke(1048575.U)\n",
+ " c.io.out.expect(1048575.U)\n",
"}\n",
"\n",
" "
@@ -300,9 +303,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": true
- },
+ "metadata": {},
"outputs": [],
"source": [
"// Viewing the Verilog for debugging\n",
@@ -312,9 +313,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": true
- },
+ "metadata": {},
"outputs": [],
"source": [
"// Viewing the firrtl for debugging\n",
@@ -352,9 +351,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": true
- },
+ "metadata": {},
"outputs": [],
"source": [
"class PrintingModule extends Module {\n",
@@ -371,14 +368,20 @@
" println(s\"Print during generation: Input is ${io.in}\")\n",
"}\n",
"\n",
- "class PrintingModuleTester(c: PrintingModule) extends PeekPokeTester(c) {\n",
- " poke(c.io.in, 3)\n",
- " step(5) // circuit will print\n",
+ "test(new PrintingModule ) { c =>\n",
+ " c.io.in.poke(3.U)\n",
+ " c.clock.step(5) // circuit will print\n",
" \n",
- " println(s\"Print during testing: Input is ${peek(c.io.in)}\")\n",
- "}\n",
- "chisel3.iotesters.Driver( () => new PrintingModule ) { c => new PrintingModuleTester(c) }"
+ " println(s\"Print during testing: Input is ${c.io.in.peek()}\")\n",
+ "}"
]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
}
],
"metadata": {
@@ -394,7 +397,7 @@
"mimetype": "text/x-scala",
"name": "scala",
"nbconvert_exporter": "script",
- "version": "2.12.8"
+ "version": "2.12.10"
}
},
"nbformat": 4,
diff --git a/2.2_comb_logic.ipynb b/2.2_comb_logic.ipynb
index 44d1795..2418a2d 100644
--- a/2.2_comb_logic.ipynb
+++ b/2.2_comb_logic.ipynb
@@ -45,7 +45,8 @@
"source": [
"import chisel3._\n",
"import chisel3.util._\n",
- "import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}"
+ "import chisel3.tester._\n",
+ "import chisel3.tester.RawTester.test"
]
},
{
@@ -179,12 +180,11 @@
"metadata": {},
"outputs": [],
"source": [
- "class MyOperatorsTester(c: MyOperators) extends PeekPokeTester(c) {\n",
- " expect(c.io.out_add, 5)\n",
- " expect(c.io.out_sub, 1)\n",
- " expect(c.io.out_mul, 8)\n",
+ "test(new MyOperators) {c =>\n",
+ " c.io.out_add.expect(5.U)\n",
+ " c.io.out_sub.expect(1.U)\n",
+ " c.io.out_mul.expect(8.U)\n",
"}\n",
- "assert(Driver(() => new MyOperators) {c => new MyOperatorsTester(c)})\n",
"println(\"SUCCESS!!\")"
]
},
@@ -215,11 +215,11 @@
"}\n",
"\n",
"println(getVerilog(new MyOperatorsTwo))\n",
- "class MyOperatorsTwoTester(c: MyOperatorsTwo) extends PeekPokeTester(c) {\n",
- " expect(c.io.out_mux, 3)\n",
- " expect(c.io.out_cat, 5)\n",
+ "\n",
+ "test(new MyOperatorsTwo) { c =>\n",
+ " c.io.out_mux.expect(3.U)\n",
+ " c.io.out_cat.expect(5.U)\n",
"}\n",
- "assert(Driver(() => new MyOperatorsTwo) {c => new MyOperatorsTwoTester(c)})\n",
"println(\"SUCCESS!!\")"
]
},
@@ -267,20 +267,20 @@
"\n",
" ???\n",
"}\n",
- "class MACTester(c: MAC) extends PeekPokeTester(c) {\n",
+ "\n",
+ "test(new MAC) { c =>\n",
" val cycles = 100\n",
" import scala.util.Random\n",
" for (i <- 0 until cycles) {\n",
" val in_a = Random.nextInt(16)\n",
" val in_b = Random.nextInt(16)\n",
" val in_c = Random.nextInt(16)\n",
- " poke(c.io.in_a, in_a)\n",
- " poke(c.io.in_b, in_b)\n",
- " poke(c.io.in_c, in_c)\n",
- " expect(c.io.out, in_a*in_b+in_c)\n",
+ " c.io.in_a.poke(in_a.U)\n",
+ " c.io.in_b.poke(in_b.U)\n",
+ " c.io.in_c.poke(in_c.U)\n",
+ " c.io.out.expect((in_a * in_b + in_c).U)\n",
" }\n",
"}\n",
- "assert(Driver(() => new MAC) {c => new MACTester(c)})\n",
"println(\"SUCCESS!!\")"
]
},
@@ -342,30 +342,30 @@
" val pe1_data = Output(UInt(16.W))\n",
" })\n",
"\n",
- " ??? \n",
+ " ???\n",
"}\n",
- "class ArbiterTester(c: Arbiter) extends PeekPokeTester(c) {\n",
+ "\n",
+ "test(new Arbiter) { c =>\n",
" import scala.util.Random\n",
" val data = Random.nextInt(65536)\n",
- " poke(c.io.fifo_data, data)\n",
+ " c.io.fifo_data.poke(data.U)\n",
" \n",
" for (i <- 0 until 8) {\n",
- " poke(c.io.fifo_valid, (i>>0)%2)\n",
- " poke(c.io.pe0_ready, (i>>1)%2)\n",
- " poke(c.io.pe1_ready, (i>>2)%2)\n",
+ " c.io.fifo_valid.poke((((i >> 0) % 2) != 0).B)\n",
+ " c.io.pe0_ready.poke((((i >> 1) % 2) != 0).B)\n",
+ " c.io.pe1_ready.poke((((i >> 2) % 2) != 0).B)\n",
"\n",
- " expect(c.io.fifo_ready, i>1)\n",
- " expect(c.io.pe0_valid, i==3 || i==7)\n",
- " expect(c.io.pe1_valid, i==5)\n",
+ " c.io.fifo_ready.expect((i > 1).B)\n",
+ " c.io.pe0_valid.expect((i == 3 || i == 7).B)\n",
+ " c.io.pe1_valid.expect((i == 5).B)\n",
" \n",
" if (i == 3 || i ==7) {\n",
- " expect(c.io.pe0_data, data)\n",
+ " c.io.pe0_data.expect((data).U)\n",
" } else if (i == 5) {\n",
- " expect(c.io.pe1_data, data)\n",
+ " c.io.pe1_data.expect((data).U)\n",
" }\n",
" }\n",
"}\n",
- "assert(Driver(() => new Arbiter) {c => new ArbiterTester(c)})\n",
"println(\"SUCCESS!!\")"
]
},
@@ -425,34 +425,34 @@
"\n",
" ???\n",
"}\n",
- "class ParameterizedAdderTester(c: ParameterizedAdder, saturate: Boolean) extends PeekPokeTester(c) {\n",
- " // 100 random tests\n",
- " val cycles = 100\n",
- " import scala.util.Random\n",
- " import scala.math.min\n",
- " for (i <- 0 until cycles) {\n",
- " val in_a = Random.nextInt(16)\n",
- " val in_b = Random.nextInt(16)\n",
- " poke(c.io.in_a, in_a)\n",
- " poke(c.io.in_b, in_b)\n",
+ "\n",
+ "for (saturate <- Seq(true, false)) {\n",
+ " test(new ParameterizedAdder(saturate)) { c =>\n",
+ " // 100 random tests\n",
+ " val cycles = 100\n",
+ " import scala.util.Random\n",
+ " import scala.math.min\n",
+ " for (i <- 0 until cycles) {\n",
+ " val in_a = Random.nextInt(16)\n",
+ " val in_b = Random.nextInt(16)\n",
+ " c.io.in_a.poke(in_a.U)\n",
+ " c.io.in_b.poke(in_b.U)\n",
+ " if (saturate) {\n",
+ " c.io.out.expect(min(in_a + in_b, 15).U)\n",
+ " } else {\n",
+ " c.io.out.expect(((in_a + in_b) % 16).U)\n",
+ " }\n",
+ " }\n",
+ " \n",
+ " // ensure we test saturation vs. truncation\n",
+ " c.io.in_a.poke(15.U)\n",
+ " c.io.in_b.poke(15.U)\n",
" if (saturate) {\n",
- " expect(c.io.out, min(in_a+in_b, 15))\n",
+ " c.io.out.expect(15.U)\n",
" } else {\n",
- " expect(c.io.out, (in_a+in_b)%16)\n",
+ " c.io.out.expect(14.U)\n",
" }\n",
" }\n",
- " \n",
- " // ensure we test saturation vs. truncation\n",
- " poke(c.io.in_a, 15)\n",
- " poke(c.io.in_b, 15)\n",
- " if (saturate) {\n",
- " expect(c.io.out, 15)\n",
- " } else {\n",
- " expect(c.io.out, 14)\n",
- " }\n",
- "}\n",
- "for (saturate <- Seq(true, false)) {\n",
- " assert(Driver(() => new ParameterizedAdder(saturate)) {c => new ParameterizedAdderTester(c, saturate)})\n",
"}\n",
"println(\"SUCCESS!!\")"
]
@@ -496,10 +496,9 @@
"codemirror_mode": "text/x-scala",
"file_extension": ".scala",
"mimetype": "text/x-scala",
- "name": "scala211",
+ "name": "scala",
"nbconvert_exporter": "script",
- "pygments_lexer": "scala",
- "version": "2.11.11"
+ "version": "2.12.10"
}
},
"nbformat": 4,
diff --git a/2.3_control_flow.ipynb b/2.3_control_flow.ipynb
index 462ca11..93918d0 100644
--- a/2.3_control_flow.ipynb
+++ b/2.3_control_flow.ipynb
@@ -31,9 +31,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"val path = System.getProperty(\"user.dir\") + \"/source/load-ivy.sc\"\n",
@@ -43,14 +41,13 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"import chisel3._\n",
"import chisel3.util._\n",
- "import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}"
+ "import chisel3.tester._\n",
+ "import chisel3.tester.RawTester.test"
]
},
{
@@ -69,9 +66,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class LastConnect extends Module {\n",
@@ -85,16 +80,8 @@
" io.out := 4.U\n",
"}\n",
"\n",
- "// Chisel Code: Declare a new tester for modules\n",
- "class LastConnectTester(c: LastConnect) extends PeekPokeTester(c) {\n",
- " expect(c.io.out, 4) // Assert that the output correctly has 4\n",
- "}\n",
- "\n",
"// Test LastConnect\n",
- "val works = Driver(() => new LastConnect) {\n",
- " c => new LastConnectTester(c)\n",
- "}\n",
- "assert(works) // Scala Code: if works == false, will throw an error\n",
+ "test(new LastConnect) { c => c.io.out.expect(4.U) } // Assert that the output correctly has 4\n",
"println(\"SUCCESS!!\") // Scala Code: if we get here, our tests passed!"
]
},
@@ -134,9 +121,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"// Max3 returns the max of its 3 arguments\n",
@@ -157,29 +142,25 @@
" }\n",
"}\n",
"\n",
- "// verify that the max of the three inputs is correct\n",
- "class Max3Tester(c: Max3) extends PeekPokeTester(c) {\n",
- " poke(c.io.in1, 6)\n",
- " poke(c.io.in2, 4) \n",
- " poke(c.io.in3, 2) \n",
- " expect(c.io.out, 6) // input 1 should be biggest\n",
- " poke(c.io.in2, 7) \n",
- " expect(c.io.out, 7) // now input 2 is\n",
- " poke(c.io.in3, 11) \n",
- " expect(c.io.out, 11) // and now input 3\n",
- " poke(c.io.in3, 3) \n",
- " expect(c.io.out, 7) // show that decreasing an input works as well\n",
- " poke(c.io.in1, 9)\n",
- " poke(c.io.in2, 9)\n",
- " poke(c.io.in3, 6)\n",
- " expect(c.io.out, 9) // still get max with tie\n",
- "}\n",
- "\n",
"// Test Max3\n",
- "val works = Driver(() => new Max3) {\n",
- " c => new Max3Tester(c)\n",
+ "test(new Max3) { c =>\n",
+ " // verify that the max of the three inputs is correct\n",
+ " c.io.in1.poke(6.U)\n",
+ " c.io.in2.poke(4.U)\n",
+ " c.io.in3.poke(2.U)\n",
+ " c.io.out.expect(6.U) // input 1 should be biggest\n",
+ " c.io.in2.poke(7.U)\n",
+ " c.io.out.expect(7.U) // now input 2 is\n",
+ " c.io.in3.poke(11.U)\n",
+ " c.io.out.expect(11.U) // and now input 3\n",
+ " c.io.in3.poke(3.U)\n",
+ " c.io.out.expect(7.U) // show that decreasing an input works as well\n",
+ " c.io.in1.poke(9.U)\n",
+ " c.io.in2.poke(9.U)\n",
+ " c.io.in3.poke(6.U)\n",
+ " c.io.out.expect(9.U) // still get max with tie\n",
"}\n",
- "assert(works) // Scala Code: if works == false, will throw an error\n",
+ "\n",
"println(\"SUCCESS!!\") // Scala Code: if we get here, our tests passed!"
]
},
@@ -206,7 +187,6 @@
"cell_type": "code",
"execution_count": null,
"metadata": {
- "collapsed": false,
"scrolled": true
},
"outputs": [],
@@ -283,41 +263,37 @@
" }\n",
"}\n",
"\n",
- "// verify the inputs are sorted\n",
- "class Sort4Tester(c: Sort4) extends PeekPokeTester(c) {\n",
- " poke(c.io.in0, 3)\n",
- " poke(c.io.in1, 6)\n",
- " poke(c.io.in2, 9)\n",
- " poke(c.io.in3, 12)\n",
- " expect(c.io.out0, 3)\n",
- " expect(c.io.out1, 6)\n",
- " expect(c.io.out2, 9)\n",
- " expect(c.io.out3, 12)\n",
- "\n",
- " poke(c.io.in0, 13)\n",
- " poke(c.io.in1, 4)\n",
- " poke(c.io.in2, 6)\n",
- " poke(c.io.in3, 1)\n",
- " expect(c.io.out0, 1)\n",
- " expect(c.io.out1, 4)\n",
- " expect(c.io.out2, 6)\n",
- " expect(c.io.out3, 13)\n",
- " \n",
- " poke(c.io.in0, 13)\n",
- " poke(c.io.in1, 6)\n",
- " poke(c.io.in2, 4)\n",
- " poke(c.io.in3, 1)\n",
- " expect(c.io.out0, 1)\n",
- " expect(c.io.out1, 4)\n",
- " expect(c.io.out2, 6)\n",
- " expect(c.io.out3, 13)\n",
- "}\n",
"\n",
"// Here's the tester\n",
- "val works = iotesters.Driver(() => new Sort4) {\n",
- "c => new Sort4Tester(c)\n",
+ "test(new Sort4) { c =>\n",
+ " // verify the inputs are sorted\n",
+ " c.io.in0.poke(3.U)\n",
+ " c.io.in1.poke(6.U)\n",
+ " c.io.in2.poke(9.U)\n",
+ " c.io.in3.poke(12.U)\n",
+ " c.io.out0.expect(3.U)\n",
+ " c.io.out1.expect(6.U)\n",
+ " c.io.out2.expect(9.U)\n",
+ " c.io.out3.expect(12.U)\n",
+ "\n",
+ " c.io.in0.poke(13.U)\n",
+ " c.io.in1.poke(4.U)\n",
+ " c.io.in2.poke(6.U)\n",
+ " c.io.in3.poke(1.U)\n",
+ " c.io.out0.expect(1.U)\n",
+ " c.io.out1.expect(4.U)\n",
+ " c.io.out2.expect(6.U)\n",
+ " c.io.out3.expect(13.U)\n",
+ "\n",
+ " c.io.in0.poke(13.U)\n",
+ " c.io.in1.poke(6.U)\n",
+ " c.io.in2.poke(4.U)\n",
+ " c.io.in3.poke(1.U)\n",
+ " c.io.out0.expect(1.U)\n",
+ " c.io.out1.expect(4.U)\n",
+ " c.io.out2.expect(6.U)\n",
+ " c.io.out3.expect(13.U)\n",
"}\n",
- "assert(works) // Scala Code: if works == false, will throw an error\n",
"println(\"SUCCESS!!\") // Scala Code: if we get here, our tests passed!\n"
]
},
@@ -331,31 +307,24 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
- "// verify the all possible ordering of 4 numbers are sorted\n",
- "class BetterSort4Tester(c: Sort4) extends PeekPokeTester(c) {\n",
+ "// Here's the tester\n",
+ "test(new Sort4) { c =>\n",
+ " // verify the all possible ordering of 4 numbers are sorted\n",
" List(1, 2, 3, 4).permutations.foreach { case i0 :: i1 :: i2 :: i3 :: Nil =>\n",
" println(s\"Sorting $i0 $i1 $i2 $i3\")\n",
- " poke(c.io.in0, i0)\n",
- " poke(c.io.in1, i1)\n",
- " poke(c.io.in2, i2)\n",
- " poke(c.io.in3, i3)\n",
- " expect(c.io.out0, 1)\n",
- " expect(c.io.out1, 2)\n",
- " expect(c.io.out2, 3)\n",
- " expect(c.io.out3, 4)\n",
+ " c.io.in0.poke(i0.U)\n",
+ " c.io.in1.poke(i1.U)\n",
+ " c.io.in2.poke(i2.U)\n",
+ " c.io.in3.poke(i3.U)\n",
+ " c.io.out0.expect(1.U)\n",
+ " c.io.out1.expect(2.U)\n",
+ " c.io.out2.expect(3.U)\n",
+ " c.io.out3.expect(4.U)\n",
" }\n",
"}\n",
- "\n",
- "// Here's the tester\n",
- "val works = iotesters.Driver(() => new Sort4) {\n",
- "c => new BetterSort4Tester(c)\n",
- "}\n",
- "assert(works) // Scala Code: if works == false, will throw an error\n",
"println(\"SUCCESS!!\") // Scala Code: if we get here, our tests passed!"
]
},
@@ -382,9 +351,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"def poly0(x: Int): Int = ???\n",
@@ -425,9 +392,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"def poly(select: Int, x: Int): Int = {\n",
@@ -472,9 +437,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"// compute the polynomial\n",
@@ -495,20 +458,18 @@
"\n",
"// verify that the computation is correct\n",
"class PolynomialTester(c: Polynomial) extends PeekPokeTester(c) {\n",
+ "}\n",
+ "\n",
+ "// Test Polynomial\n",
+ "test(new Polynomial) { c =>\n",
" for(x <- 0 to 20) {\n",
" for(select <- 0 to 2) {\n",
- " poke(c.io.select, select)\n",
- " poke(c.io.x, x)\n",
- " expect(c.io.fOfX, poly(select, x))\n",
+ " c.io.select.poke(select.U)\n",
+ " c.io.x.poke(x.S)\n",
+ " c.io.fOfX.expect(poly(select, x).S)\n",
" }\n",
" }\n",
"}\n",
- "\n",
- "// Test Polynomial\n",
- "val works = Driver(() => new Polynomial) {\n",
- " c => new PolynomialTester(c)\n",
- "}\n",
- "assert(works) // Scala Code: if works == false, will throw an error\n",
"println(\"SUCCESS!!\") // Scala Code: if we get here, our tests passed!"
]
},
@@ -549,9 +510,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"// state map\n",
@@ -605,9 +564,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"// life gets hard-er\n",
@@ -622,30 +579,27 @@
" \n",
" val idle :: coding :: writing :: grad :: Nil = Enum(4)\n",
" \n",
- " io.nextState := idle\n",
" ???\n",
"}\n",
"\n",
- "// verify that the hardware matches the golden model\n",
- "class GradLifeSim(c: GradLife) extends PeekPokeTester(c) {\n",
+ "\n",
+ "// Test\n",
+ "test(new GradLife) { c =>\n",
+ " // verify that the hardware matches the golden model\n",
" for (state <- 0 to 3) {\n",
" for (coffee <- List(true, false)) {\n",
" for (idea <- List(true, false)) {\n",
" for (pressure <- List(true, false)) {\n",
- " poke(c.io.state, state)\n",
- " poke(c.io.coffee, coffee)\n",
- " poke(c.io.idea, idea)\n",
- " poke(c.io.pressure, pressure)\n",
- " expect(c.io.nextState, gradLife(state, coffee, idea, pressure))\n",
+ " c.io.state.poke(state.U)\n",
+ " c.io.coffee.poke(coffee.B)\n",
+ " c.io.idea.poke(idea.B)\n",
+ " c.io.pressure.poke(pressure.B)\n",
+ " c.io.nextState.expect(gradLife(state, coffee, idea, pressure).U)\n",
" }\n",
" }\n",
" }\n",
" }\n",
"}\n",
- "\n",
- "// Test\n",
- "val works = Driver(() => new GradLife) {c => new GradLifeSim(c)}\n",
- "assert(works) // Scala Code: if works == false, will throw an error\n",
"println(\"SUCCESS!!\") // Scala Code: if we get here, our tests passed!"
]
},
@@ -695,10 +649,9 @@
"codemirror_mode": "text/x-scala",
"file_extension": ".scala",
"mimetype": "text/x-scala",
- "name": "scala211",
+ "name": "scala",
"nbconvert_exporter": "script",
- "pygments_lexer": "scala",
- "version": "2.11.11"
+ "version": "2.12.10"
}
},
"nbformat": 4,
diff --git a/2.4_sequential_logic.ipynb b/2.4_sequential_logic.ipynb
index 6a2f932..83982db 100644
--- a/2.4_sequential_logic.ipynb
+++ b/2.4_sequential_logic.ipynb
@@ -30,9 +30,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": true
- },
+ "metadata": {},
"outputs": [],
"source": [
"val path = System.getProperty(\"user.dir\") + \"/source/load-ivy.sc\"\n",
@@ -42,14 +40,13 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"import chisel3._\n",
"import chisel3.util._\n",
- "import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}"
+ "import chisel3.tester._\n",
+ "import chisel3.tester.RawTester.test"
]
},
{
@@ -71,9 +68,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class RegisterModule extends Module {\n",
@@ -87,14 +82,13 @@
" io.out := register\n",
"}\n",
"\n",
- "class RegisterModuleTester(c: RegisterModule) extends PeekPokeTester(c) {\n",
+ "test(new RegisterModule) { c =>\n",
" for (i <- 0 until 100) {\n",
- " poke(c.io.in, i)\n",
- " step(1)\n",
- " expect(c.io.out, i+1)\n",
+ " c.io.in.poke(i.U)\n",
+ " c.clock.step(1)\n",
+ " c.io.out.expect((i + 1).U)\n",
" }\n",
"}\n",
- "assert(chisel3.iotesters.Driver(() => new RegisterModule) { c => new RegisterModuleTester(c) })\n",
"println(\"SUCCESS!!\")"
]
},
@@ -125,9 +119,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"println(getVerilog(new RegisterModule))"
@@ -159,9 +151,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class RegNextModule extends Module {\n",
@@ -174,14 +164,13 @@
" io.out := RegNext(io.in + 1.U)\n",
"}\n",
"\n",
- "class RegNextModuleTester(c: RegNextModule) extends PeekPokeTester(c) {\n",
+ "test(new RegNextModule) { c =>\n",
" for (i <- 0 until 100) {\n",
- " poke(c.io.in, i)\n",
- " step(1)\n",
- " expect(c.io.out, i+1)\n",
+ " c.io.in.poke(i.U)\n",
+ " c.clock.step(1)\n",
+ " c.io.out.expect((i + 1).U)\n",
" }\n",
"}\n",
- "assert(chisel3.iotesters.Driver(() => new RegNextModule) { c => new RegNextModuleTester(c) })\n",
"println(\"SUCCESS!!\")"
]
},
@@ -195,9 +184,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"println(getVerilog(new RegNextModule))"
@@ -235,9 +222,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class RegInitModule extends Module {\n",
@@ -281,9 +266,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class FindMax extends Module {\n",
@@ -298,23 +281,22 @@
" }\n",
" io.max := max\n",
"}\n",
- "assert(chisel3.iotesters.Driver(() => new FindMax) {\n",
- " c => new PeekPokeTester(c) {\n",
- " expect(c.io.max, 0)\n",
- " poke(c.io.in, 1)\n",
- " step(1)\n",
- " expect(c.io.max, 1)\n",
- " poke(c.io.in, 3)\n",
- " step(1)\n",
- " expect(c.io.max, 3)\n",
- " poke(c.io.in, 2)\n",
- " step(1)\n",
- " expect(c.io.max, 3)\n",
- " poke(c.io.in, 24)\n",
- " step(1)\n",
- " expect(c.io.max, 24)\n",
- " }\n",
- "})\n",
+ "\n",
+ "test(new FindMax) { c =>\n",
+ " c.io.max.expect(0.U)\n",
+ " c.io.in.poke(1.U)\n",
+ " c.clock.step(1)\n",
+ " c.io.max.expect(1.U)\n",
+ " c.io.in.poke(3.U)\n",
+ " c.clock.step(1)\n",
+ " c.io.max.expect(3.U)\n",
+ " c.io.in.poke(2.U)\n",
+ " c.clock.step(1)\n",
+ " c.io.max.expect(3.U)\n",
+ " c.io.in.poke(24.U)\n",
+ " c.clock.step(1)\n",
+ " c.io.max.expect(24.U)\n",
+ "}\n",
"println(\"SUCCESS!!\")"
]
},
@@ -341,9 +323,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class Comb extends Module {\n",
@@ -383,9 +363,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class MyShiftRegister(val init: Int = 1) extends Module {\n",
@@ -399,20 +377,17 @@
" ???\n",
"}\n",
"\n",
- "class MyShiftRegisterTester(c: MyShiftRegister) extends PeekPokeTester(c) {\n",
+ "test(new MyShiftRegister()) { c =>\n",
" var state = c.init\n",
" for (i <- 0 until 10) {\n",
" // poke in LSB of i (i % 2)\n",
- " poke(c.io.in, i % 2)\n",
+ " c.io.in.poke(((i % 2) != 0).B)\n",
" // update expected state\n",
" state = ((state * 2) + (i % 2)) & 0xf\n",
- " step(1)\n",
- " expect(c.io.out, state)\n",
+ " c.clock.step(1)\n",
+ " c.io.out.expect(state.U)\n",
" }\n",
"}\n",
- "assert(chisel3.iotesters.Driver(() => new MyShiftRegister()) {\n",
- " c => new MyShiftRegisterTester(c)\n",
- "})\n",
"println(\"SUCCESS!!\")"
]
},
@@ -442,9 +417,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"// n is the output width (number of delays - 1)\n",
@@ -461,30 +434,26 @@
" ???\n",
"}\n",
"\n",
- "class MyOptionalShiftRegisterTester(c: MyOptionalShiftRegister) extends PeekPokeTester(c) {\n",
- " val inSeq = Seq(0, 1, 1, 1, 0, 1, 1, 0, 0, 1)\n",
- " var state = c.init\n",
- " var i = 0\n",
- " poke(c.io.en, 1)\n",
- " while (i < 10 * c.n) {\n",
- " // poke in repeated inSeq\n",
- " val toPoke = inSeq(i % inSeq.length)\n",
- " poke(c.io.in, toPoke)\n",
- " // update expected state\n",
- " state = ((state * 2) + toPoke) & BigInt(\"1\"*c.n, 2)\n",
- " step(1)\n",
- " expect(c.io.out, state)\n",
- "\n",
- " i += 1\n",
- " }\n",
- "}\n",
- "\n",
"// test different depths\n",
"for (i <- Seq(3, 4, 8, 24, 65)) {\n",
" println(s\"Testing n=$i\")\n",
- " assert(chisel3.iotesters.Driver(() => new MyOptionalShiftRegister(n = i)) {\n",
- " c => new MyOptionalShiftRegisterTester(c)\n",
- " })\n",
+ " test(new MyOptionalShiftRegister(n = i)) { c =>\n",
+ " val inSeq = Seq(0, 1, 1, 1, 0, 1, 1, 0, 0, 1)\n",
+ " var state = c.init\n",
+ " var i = 0\n",
+ " c.io.en.poke(true.B)\n",
+ " while (i < 10 * c.n) {\n",
+ " // poke in repeated inSeq\n",
+ " val toPoke = inSeq(i % inSeq.length)\n",
+ " c.io.in.poke((toPoke != 0).B)\n",
+ " // update expected state\n",
+ " state = ((state * 2) + toPoke) & BigInt(\"1\"*c.n, 2)\n",
+ " c.clock.step(1)\n",
+ " c.io.out.expect(state.U)\n",
+ "\n",
+ " i += 1\n",
+ " }\n",
+ " }\n",
"}\n",
"println(\"SUCCESS!!\")"
]
@@ -533,7 +502,6 @@
"cell_type": "code",
"execution_count": null,
"metadata": {
- "collapsed": false,
"scrolled": true
},
"outputs": [],
@@ -613,10 +581,9 @@
"codemirror_mode": "text/x-scala",
"file_extension": ".scala",
"mimetype": "text/x-scala",
- "name": "scala211",
+ "name": "scala",
"nbconvert_exporter": "script",
- "pygments_lexer": "scala",
- "version": "2.11.11"
+ "version": "2.12.10"
}
},
"nbformat": 4,
diff --git a/2.5_exercise.ipynb b/2.5_exercise.ipynb
index bfe848e..91e2114 100644
--- a/2.5_exercise.ipynb
+++ b/2.5_exercise.ipynb
@@ -13,7 +13,7 @@
"source": [
"# Module 2.5: Putting it all Together: An FIR Filter\n",
"**Prev: [Sequential Logic](2.4_sequential_logic.ipynb)** \n",
- "**Next: [Generators: Parameters](3.1_parameters.ipynb)**\n",
+ "**Next: [ChiselTest (was chisel-testers2)](2.6_chiseltest.ipynb)**\n",
"\n",
"## Motivation\n",
"Now that you've learned the basics of Chisel, let's use that knowledge to build a FIR (finite impulse response) filter module! FIR filters are very common in digital signal processing applications. Also, the FIR filter will reappear frequently in module 3, so it's important that you don't filter out this module by skipping ahead! If you are unfamiliar with FIR filters, head over to the article on [trusty Wikipedia](https://en.wikipedia.org/wiki/Finite_impulse_response) to learn more.\n",
@@ -24,9 +24,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"val path = System.getProperty(\"user.dir\") + \"/source/load-ivy.sc\"\n",
@@ -36,14 +34,13 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"import chisel3._\n",
"import chisel3.util._\n",
- "import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}"
+ "import chisel3.tester._\n",
+ "import chisel3.tester.RawTester.test"
]
},
{
@@ -84,7 +81,6 @@
"cell_type": "code",
"execution_count": null,
"metadata": {
- "collapsed": false,
"nbpresent": {
"id": "26e4a686-0397-4306-985c-813909256c95"
}
@@ -105,7 +101,6 @@
"cell_type": "code",
"execution_count": null,
"metadata": {
- "collapsed": false,
"nbpresent": {
"id": "ddf24b7b-09a2-46f0-b1d8-cb2ca7976b4b"
}
@@ -113,84 +108,74 @@
"outputs": [],
"source": [
"// Simple sanity check: a element with all zero coefficients should always produce zero\n",
- "Driver(() => new My4ElementFir(0, 0, 0, 0)) {\n",
- " c => new PeekPokeTester(c) {\n",
- " poke(c.io.in, 0)\n",
- " expect(c.io.out, 0)\n",
- " step(1)\n",
- " poke(c.io.in, 4)\n",
- " expect(c.io.out, 0)\n",
- " step(1)\n",
- " poke(c.io.in, 5)\n",
- " expect(c.io.out, 0)\n",
- " step(1)\n",
- " poke(c.io.in, 2)\n",
- " expect(c.io.out, 0)\n",
- " }\n",
+ "test(new My4ElementFir(0, 0, 0, 0)) { c =>\n",
+ " c.io.in.poke(0.U)\n",
+ " c.io.out.expect(0.U)\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(4.U)\n",
+ " c.io.out.expect(0.U)\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(5.U)\n",
+ " c.io.out.expect(0.U)\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(2.U)\n",
+ " c.io.out.expect(0.U)\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"// Simple 4-point moving average\n",
- "Driver(() => new My4ElementFir(1, 1, 1, 1)) {\n",
- " c => new PeekPokeTester(c) {\n",
- " poke(c.io.in, 1)\n",
- " expect(c.io.out, 1) // 1, 0, 0, 0\n",
- " step(1)\n",
- " poke(c.io.in, 4)\n",
- " expect(c.io.out, 5) // 4, 1, 0, 0\n",
- " step(1)\n",
- " poke(c.io.in, 3)\n",
- " expect(c.io.out, 8) // 3, 4, 1, 0\n",
- " step(1)\n",
- " poke(c.io.in, 2)\n",
- " expect(c.io.out, 10) // 2, 3, 4, 1\n",
- " step(1)\n",
- " poke(c.io.in, 7)\n",
- " expect(c.io.out, 16) // 7, 2, 3, 4\n",
- " step(1)\n",
- " poke(c.io.in, 0)\n",
- " expect(c.io.out, 12) // 0, 7, 2, 3\n",
- " }\n",
+ "test(new My4ElementFir(1, 1, 1, 1)) { c =>\n",
+ " c.io.in.poke(1.U)\n",
+ " c.io.out.expect(1.U) // 1, 0, 0, 0\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(4.U)\n",
+ " c.io.out.expect(5.U) // 4, 1, 0, 0\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(3.U)\n",
+ " c.io.out.expect(8.U) // 3, 4, 1, 0\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(2.U)\n",
+ " c.io.out.expect(10.U) // 2, 3, 4, 1\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(7.U)\n",
+ " c.io.out.expect(16.U) // 7, 2, 3, 4\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(0.U)\n",
+ " c.io.out.expect(12.U) // 0, 7, 2, 3\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"// Nonsymmetric filter\n",
- "Driver(() => new My4ElementFir(1, 2, 3, 4)) {\n",
- " c => new PeekPokeTester(c) {\n",
- " poke(c.io.in, 1)\n",
- " expect(c.io.out, 1) // 1*1, 0*2, 0*3, 0*4\n",
- " step(1)\n",
- " poke(c.io.in, 4)\n",
- " expect(c.io.out, 6) // 4*1, 1*2, 0*3, 0*4\n",
- " step(1)\n",
- " poke(c.io.in, 3)\n",
- " expect(c.io.out, 14) // 3*1, 4*2, 1*3, 0*4\n",
- " step(1)\n",
- " poke(c.io.in, 2)\n",
- " expect(c.io.out, 24) // 2*1, 3*2, 4*3, 1*4\n",
- " step(1)\n",
- " poke(c.io.in, 7)\n",
- " expect(c.io.out, 36) // 7*1, 2*2, 3*3, 4*4\n",
- " step(1)\n",
- " poke(c.io.in, 0)\n",
- " expect(c.io.out, 32) // 0*1, 7*2, 2*3, 3*4\n",
- " }\n",
+ "test(new My4ElementFir(1, 2, 3, 4)) { c =>\n",
+ " c.io.in.poke(1.U)\n",
+ " c.io.out.expect(1.U) // 1*1, 0*2, 0*3, 0*4\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(4.U)\n",
+ " c.io.out.expect(6.U) // 4*1, 1*2, 0*3, 0*4\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(3.U)\n",
+ " c.io.out.expect(14.U) // 3*1, 4*2, 1*3, 0*4\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(2.U)\n",
+ " c.io.out.expect(24.U) // 2*1, 3*2, 4*3, 1*4\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(7.U)\n",
+ " c.io.out.expect(36.U) // 7*1, 2*2, 3*3, 4*4\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(0.U)\n",
+ " c.io.out.expect(32.U) // 0*1, 7*2, 2*3, 3*4\n",
"}"
]
},
@@ -241,9 +226,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class MyManyDynamicElementVecFir(length: Int) extends Module {\n",
@@ -259,7 +242,9 @@
" taps.zip(taps.tail).foreach { case (a, b) => when (io.valid) { b := a } }\n",
"\n",
" io.out := taps.zip(io.consts).map { case (a, b) => a * b }.reduce(_ + _)\n",
- "}"
+ "}\n",
+ "\n",
+ "visualize(() => new MyManyDynamicElementVecFir(4))"
]
},
{
@@ -292,9 +277,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"import dspblocks._\n",
@@ -452,7 +435,7 @@
"mimetype": "text/x-scala",
"name": "scala",
"nbconvert_exporter": "script",
- "version": "2.12.8"
+ "version": "2.12.10"
}
},
"nbformat": 4,
diff --git a/2.6_testers2.ipynb b/2.6_chiseltest.ipynb
similarity index 98%
rename from 2.6_testers2.ipynb
rename to 2.6_chiseltest.ipynb
index c1f90f3..ba8c7d7 100644
--- a/2.6_testers2.ipynb
+++ b/2.6_chiseltest.ipynb
@@ -11,9 +11,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "##### Module 2.6: ChiselTest (formerly Testers2)\n",
- "**Prev: [Control Flow](2.3_control_flow.ipynb)** \n",
- "**Next: [Sequential Logic](2.4_sequential_logic.ipynb)**\n",
+ "##### Module 2.6: More on ChiselTest\n",
+ "**Prev: [Putting it all Together: An FIR Filter](2.5_exercise.ipynb)** \n",
+ "**Next: [Generators: Parameters](3.1_parameters.ipynb)**\n",
"\n",
"## Motivation\n",
"The Chisel team has been working on an improved testing framework. \"ChiselTest\", it provides the following improvements .\n",
@@ -526,7 +526,7 @@
"mimetype": "text/x-scala",
"name": "scala",
"nbconvert_exporter": "script",
- "version": "2.12.8"
+ "version": "2.12.10"
}
},
"nbformat": 4,
diff --git a/2.7_dspblock_example.ipynb b/2.7_dspblock_example.ipynb
new file mode 100644
index 0000000..67e37f4
--- /dev/null
+++ b/2.7_dspblock_example.ipynb
@@ -0,0 +1,269 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Module 2.7 DspBlock Example\n",
+ "**Prev: [ChiselTest (was chisel-testers2)](2.6_chiseltest.ipynb)** \n",
+ "**Next: [Generators: Parameters](3.1_parameters.ipynb)**\n",
+ "\n",
+ "## Motivation\n",
+ "Now that you've learned the basics of Chisel, let's use that knowledge to build a FIR (finite impulse response) filter module! FIR filters are very common in digital signal processing applications. Also, the FIR filter will reappear frequently in module 3, so it's important that you don't filter out this module by skipping ahead! If you are unfamiliar with FIR filters, head over to the article on [trusty Wikipedia](https://en.wikipedia.org/wiki/Finite_impulse_response) to learn more.\n",
+ "\n",
+ "## Setup"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "val path = System.getProperty(\"user.dir\") + \"/source/load-ivy.sc\"\n",
+ "interp.load.module(ammonite.ops.Path(java.nio.file.FileSystems.getDefault().getPath(path)))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import chisel3._\n",
+ "import chisel3.util._\n",
+ "import chisel3.tester._\n",
+ "import chisel3.tester.RawTester.test\n",
+ "import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "---\n",
+ "# DspBlock\n",
+ "\n",
+ "Integrating DSP components into a larger system can be challenging and error prone.\n",
+ "The [rocket section of the dsptools repository](https://github.com/ucb-bar/dsptools/tree/master/rocket) consists of useful generators that should help with such tasks.\n",
+ "\n",
+ "One of the core abstractions is the notion of a `DspBlock`.\n",
+ "A `DspBlock` has:\n",
+ "* AXI-4 Stream input and output\n",
+ "* Memory-mapped status and control (in this example, AXI4)\n",
+ "\n",
+ " \n",
+ "\n",
+ "`DspBlock`s use diplomatic interfaces from rocket.\n",
+ "[This site](https://www.lowrisc.org/docs/diplomacy/) has a good overview of the basic of diplomacy, but don't worry too much about how it's working for this example.\n",
+ "Diplomacy really shines when you're connecting a lot of different blocks together to form a complex SoC.\n",
+ "In this example, we're just making a single peripheral.\n",
+ "The `StandaloneBlock` traits are mixed in to make diplomatic interfaces work as top-level IOs.\n",
+ "You only need them when the `DspBlock` is being used as a top level interface without any diplomatic connections.\n",
+ "\n",
+ "We will re-use the MyManyDynamicElemetVecFir from section 2.5 here."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "class MyManyDynamicElementVecFir(length: Int) extends Module {\n",
+ " val io = IO(new Bundle {\n",
+ " val in = Input(UInt(8.W))\n",
+ " val valid = Input(Bool())\n",
+ " val out = Output(UInt(8.W))\n",
+ " val consts = Input(Vec(length, UInt(8.W)))\n",
+ " })\n",
+ " \n",
+ " // Such concision! You'll learn what all this means later.\n",
+ " val taps = Seq(io.in) ++ Seq.fill(io.consts.length - 1)(RegInit(0.U(8.W)))\n",
+ " taps.zip(taps.tail).foreach { case (a, b) => when (io.valid) { b := a } }\n",
+ "\n",
+ " io.out := taps.zip(io.consts).map { case (a, b) => a * b }.reduce(_ + _)\n",
+ "}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The following code wraps the FIR filter in AXI4 interfaces.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import dspblocks._\n",
+ "import freechips.rocketchip.amba.axi4._\n",
+ "import freechips.rocketchip.amba.axi4stream._\n",
+ "import freechips.rocketchip.config._\n",
+ "import freechips.rocketchip.diplomacy._\n",
+ "import freechips.rocketchip.regmapper._\n",
+ "\n",
+ "//\n",
+ "// Base class for all FIRBlocks.\n",
+ "// This can be extended to make TileLink, AXI4, APB, AHB, etc. flavors of the FIR filter\n",
+ "//\n",
+ "abstract class FIRBlock[D, U, EO, EI, B <: Data](val nFilters: Int, val nTaps: Int)(implicit p: Parameters)\n",
+ "// HasCSR means that the memory interface will be using the RegMapper API to define status and control registers\n",
+ "extends DspBlock[D, U, EO, EI, B] with HasCSR {\n",
+ " // diplomatic node for the streaming interface\n",
+ " // identity node means the output and input are parameterized to be the same\n",
+ " val streamNode = AXI4StreamIdentityNode()\n",
+ " \n",
+ " // define the what hardware will be elaborated\n",
+ " lazy val module = new LazyModuleImp(this) {\n",
+ " // get streaming input and output wires from diplomatic node\n",
+ " val (in, _) = streamNode.in(0)\n",
+ " val (out, _) = streamNode.out(0)\n",
+ "\n",
+ " require(in.params.n >= nFilters,\n",
+ " s\"\"\"AXI-4 Stream port must be big enough for all \n",
+ " |the filters (need $nFilters,, only have ${in.params.n})\"\"\".stripMargin)\n",
+ "\n",
+ " // make registers to store taps\n",
+ " val taps = Reg(Vec(nFilters, Vec(nTaps, UInt(8.W))))\n",
+ "\n",
+ " // memory map the taps, plus the first address is a read-only field that says how many filter lanes there are\n",
+ " val mmap = Seq(\n",
+ " RegField.r(64, nFilters.U, RegFieldDesc(\"nFilters\", \"Number of filter lanes\"))\n",
+ " ) ++ taps.flatMap(_.map(t => RegField(8, t, RegFieldDesc(\"tap\", \"Tap\"))))\n",
+ "\n",
+ " // generate the hardware for the memory interface\n",
+ " // in this class, regmap is abstract (unimplemented). mixing in something like AXI4HasCSR or TLHasCSR\n",
+ " // will define regmap for the particular memory interface\n",
+ " regmap(mmap.zipWithIndex.map({case (r, i) => i * 8 -> Seq(r)}): _*)\n",
+ "\n",
+ " // make the FIR lanes and connect inputs and taps\n",
+ " val outs = for (i <- 0 until nFilters) yield {\n",
+ " val fir = Module(new MyManyDynamicElementVecFir(nTaps))\n",
+ " \n",
+ " fir.io.in := in.bits.data((i+1)*8, i*8)\n",
+ " fir.io.valid := in.valid && out.ready\n",
+ " fir.io.consts := taps(i) \n",
+ " fir.io.out\n",
+ " }\n",
+ "\n",
+ " val output = if (outs.length == 1) {\n",
+ " outs.head\n",
+ " } else {\n",
+ " outs.reduce((x: UInt, y: UInt) => Cat(y, x))\n",
+ " }\n",
+ "\n",
+ " out.bits.data := output\n",
+ " in.ready := out.ready\n",
+ " out.valid := in.valid\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// make AXI4 flavor of FIRBlock\n",
+ "abstract class AXI4FIRBlock(nFilters: Int, nTaps: Int)(implicit p: Parameters) extends FIRBlock[AXI4MasterPortParameters, AXI4SlavePortParameters, AXI4EdgeParameters, AXI4EdgeParameters, AXI4Bundle](nFilters, nTaps) with AXI4DspBlock with AXI4HasCSR {\n",
+ " override val mem = Some(AXI4RegisterNode(\n",
+ " AddressSet(0x0, 0xffffL), beatBytes = 8\n",
+ " ))\n",
+ "}\n",
+ "\n",
+ "// running the code below will show what firrtl is generated\n",
+ "// note that LazyModules aren't really chisel modules- you need to call \".module\" on them when invoking the chisel driver\n",
+ "// also note that AXI4StandaloneBlock is mixed in- if you forget it, you will get weird diplomacy errors because the memory\n",
+ "// interface expects a master and the streaming interface expects to be connected. AXI4StandaloneBlock will add top level IOs\n",
+ "// println(chisel3.Driver.emit(() => LazyModule(new AXI4FIRBlock(1, 8)(Parameters.empty) with AXI4StandaloneBlock).module))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Testing\n",
+ "\n",
+ "Testing `DspBlock`s is a little different.\n",
+ "Now we're dealing with memory interfaces and `LazyModule`s.\n",
+ "dsptools has some features that help test `DspBlock`s.\n",
+ "\n",
+ "One important feature is `MemMasterModel`.\n",
+ "The trait defines functions like `memReadWord` and `memWriteWord`- generic functions for generating memory traffic.\n",
+ "This allows you to write one generic test that can be specialized to the memory interface you are using- for example, you write one test and then specialize it for the TileLink and AXI4 interfaces.\n",
+ "\n",
+ "The code below tests the `FIRBlock` this way."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import dsptools.tester.MemMasterModel\n",
+ "import freechips.rocketchip.amba.axi4\n",
+ "\n",
+ "abstract class FIRBlockTester[D, U, EO, EI, B <: Data](c: FIRBlock[D, U, EO, EI, B]) extends PeekPokeTester(c.module) with MemMasterModel {\n",
+ " // check that address 0 is the number of filters\n",
+ " require(memReadWord(0) == c.nFilters)\n",
+ " // write 1 to all the taps\n",
+ " for (i <- 0 until c.nFilters * c.nTaps) {\n",
+ " memWriteWord(8 + i * 8, 1)\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// specialize the generic tester for axi4\n",
+ "class AXI4FIRBlockTester(c: AXI4FIRBlock with AXI4StandaloneBlock) extends FIRBlockTester(c) with AXI4MasterModel {\n",
+ " def memAXI = c.ioMem.get\n",
+ "}\n",
+ "\n",
+ "// invoking testers on lazymodules is a little strange.\n",
+ "// note that the firblocktester takes a lazymodule, not a module (it calls .module in \"extends PeekPokeTester()\").\n",
+ "val lm = LazyModule(new AXI4FIRBlock(1, 8)(Parameters.empty) with AXI4StandaloneBlock)\n",
+ "chisel3.iotesters.Driver(() => lm.module) { _ => new AXI4FIRBlockTester(lm) }"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Exercise: TileLink** \n",
+ "\n",
+ "Add a version of `FIRBlock` that uses TileLink for its memory interconnect, and extend the `FIRBlockTester` to use TileLink."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "---\n",
+ "# You're done!\n",
+ "\n",
+ "[Return to the top.](#top)"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Scala",
+ "language": "scala",
+ "name": "scala"
+ },
+ "language_info": {
+ "codemirror_mode": "text/x-scala",
+ "file_extension": ".scala",
+ "mimetype": "text/x-scala",
+ "name": "scala",
+ "nbconvert_exporter": "script",
+ "version": "2.12.10"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/3.1_parameters.ipynb b/3.1_parameters.ipynb
index a692586..cb60d23 100644
--- a/3.1_parameters.ipynb
+++ b/3.1_parameters.ipynb
@@ -12,7 +12,7 @@
"metadata": {},
"source": [
"# Module 3.1: Generators: Parameters\n",
- "**Prev: [FIR Filter](2.5_fir.ipynb)** \n",
+ "**Prev: [ChiselTest (was chisel-testers2)](2.6_chiseltest.ipynb)** \n",
"**Next: [Generators: Collections](3.2_collections.ipynb)**\n",
"\n",
"## Motivation\n",
@@ -43,7 +43,8 @@
"source": [
"import chisel3._\n",
"import chisel3.util._\n",
- "import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}"
+ "import chisel3.tester._\n",
+ "import chisel3.tester.RawTester.test"
]
},
{
@@ -213,70 +214,65 @@
" }\n",
"}\n",
"\n",
- "// verify the inputs are sorted\n",
- "class Sort4AscendingTester(c: Sort4) extends PeekPokeTester(c) {\n",
- " poke(c.io.in0, 3)\n",
- " poke(c.io.in1, 6)\n",
- " poke(c.io.in2, 9)\n",
- " poke(c.io.in3, 12)\n",
- " expect(c.io.out0, 3)\n",
- " expect(c.io.out1, 6)\n",
- " expect(c.io.out2, 9)\n",
- " expect(c.io.out3, 12)\n",
- "\n",
- " poke(c.io.in0, 13)\n",
- " poke(c.io.in1, 4)\n",
- " poke(c.io.in2, 6)\n",
- " poke(c.io.in3, 1)\n",
- " expect(c.io.out0, 1)\n",
- " expect(c.io.out1, 4)\n",
- " expect(c.io.out2, 6)\n",
- " expect(c.io.out3, 13)\n",
- "\n",
- " poke(c.io.in0, 13)\n",
- " poke(c.io.in1, 6)\n",
- " poke(c.io.in2, 4)\n",
- " poke(c.io.in3, 1)\n",
- " expect(c.io.out0, 1)\n",
- " expect(c.io.out1, 4)\n",
- " expect(c.io.out2, 6)\n",
- " expect(c.io.out3, 13)\n",
"\n",
- "}\n",
- "class Sort4DescendingTester(c: Sort4) extends PeekPokeTester(c) {\n",
- " poke(c.io.in0, 3)\n",
- " poke(c.io.in1, 6)\n",
- " poke(c.io.in2, 9)\n",
- " poke(c.io.in3, 12)\n",
- " expect(c.io.out0, 12)\n",
- " expect(c.io.out1, 9)\n",
- " expect(c.io.out2, 6)\n",
- " expect(c.io.out3, 3)\n",
- "\n",
- " poke(c.io.in0, 13)\n",
- " poke(c.io.in1, 4)\n",
- " poke(c.io.in2, 6)\n",
- " poke(c.io.in3, 1)\n",
- " expect(c.io.out0, 13)\n",
- " expect(c.io.out1, 6)\n",
- " expect(c.io.out2, 4)\n",
- " expect(c.io.out3, 1)\n",
- " \n",
- " poke(c.io.in0, 1)\n",
- " poke(c.io.in1, 6)\n",
- " poke(c.io.in2, 4)\n",
- " poke(c.io.in3, 13)\n",
- " expect(c.io.out0, 13)\n",
- " expect(c.io.out1, 6)\n",
- " expect(c.io.out2, 4)\n",
- " expect(c.io.out3, 1)\n",
- "\n",
- "}\n",
"\n",
"// Here are the testers\n",
- "val worksAscending = iotesters.Driver(() => new Sort4(true)) { c => new Sort4AscendingTester(c) }\n",
- "val worksDescending = iotesters.Driver(() => new Sort4(false)) { c => new Sort4DescendingTester(c) }\n",
- "assert(worksAscending && worksDescending) // Scala Code: if works == false, will throw an error\n",
+ "test(new Sort4(true)) { c => \n",
+ " c.io.in0.poke(3.U)\n",
+ " c.io.in1.poke(6.U)\n",
+ " c.io.in2.poke(9.U)\n",
+ " c.io.in3.poke(12.U)\n",
+ " c.io.out0.expect(3.U)\n",
+ " c.io.out1.expect(6.U)\n",
+ " c.io.out2.expect(9.U)\n",
+ " c.io.out3.expect(12.U)\n",
+ "\n",
+ " c.io.in0.poke(13.U)\n",
+ " c.io.in1.poke(4.U)\n",
+ " c.io.in2.poke(6.U)\n",
+ " c.io.in3.poke(1.U)\n",
+ " c.io.out0.expect(1.U)\n",
+ " c.io.out1.expect(4.U)\n",
+ " c.io.out2.expect(6.U)\n",
+ " c.io.out3.expect(13.U)\n",
+ "\n",
+ " c.io.in0.poke(13.U)\n",
+ " c.io.in1.poke(6.U)\n",
+ " c.io.in2.poke(4.U)\n",
+ " c.io.in3.poke(1.U)\n",
+ " c.io.out0.expect(1.U)\n",
+ " c.io.out1.expect(4.U)\n",
+ " c.io.out2.expect(6.U)\n",
+ " c.io.out3.expect(13.U)\n",
+ "}\n",
+ "test(new Sort4(false)) { c =>\n",
+ " c.io.in0.poke(3.U)\n",
+ " c.io.in1.poke(6.U)\n",
+ " c.io.in2.poke(9.U)\n",
+ " c.io.in3.poke(12.U)\n",
+ " c.io.out0.expect(12.U)\n",
+ " c.io.out1.expect(9.U)\n",
+ " c.io.out2.expect(6.U)\n",
+ " c.io.out3.expect(3.U)\n",
+ "\n",
+ " c.io.in0.poke(13.U)\n",
+ " c.io.in1.poke(4.U)\n",
+ " c.io.in2.poke(6.U)\n",
+ " c.io.in3.poke(1.U)\n",
+ " c.io.out0.expect(13.U)\n",
+ " c.io.out1.expect(6.U)\n",
+ " c.io.out2.expect(4.U)\n",
+ " c.io.out3.expect(1.U)\n",
+ "\n",
+ " c.io.in0.poke(1.U)\n",
+ " c.io.in1.poke(6.U)\n",
+ " c.io.in2.poke(4.U)\n",
+ " c.io.in3.poke(13.U)\n",
+ " c.io.out0.expect(13.U)\n",
+ " c.io.out1.expect(6.U)\n",
+ " c.io.out2.expect(4.U)\n",
+ " c.io.out3.expect(1.U)\n",
+ "}\n",
"println(\"SUCCESS!!\") // Scala Code: if we get here, our tests passed!"
]
},
@@ -605,71 +601,68 @@
" io.carryOut := sum(1)\n",
"}\n",
"\n",
- "class HalfAdderTester(c: HalfFullAdder) extends PeekPokeTester(c) {\n",
+ "test(new HalfFullAdder(false)) { c =>\n",
" require(!c.hasCarry, \"DUT must be half adder\")\n",
" // 0 + 0 = 0\n",
- " poke(c.io.a, 0)\n",
- " poke(c.io.b, 0)\n",
- " expect(c.io.s, 0)\n",
- " expect(c.io.carryOut, 0)\n",
+ " c.io.a.poke(0.U)\n",
+ " c.io.b.poke(0.U)\n",
+ " c.io.s.expect(0.U)\n",
+ " c.io.carryOut.expect(0.U)\n",
" // 0 + 1 = 1\n",
- " poke(c.io.b, 1)\n",
- " expect(c.io.s, 1)\n",
- " expect(c.io.carryOut, 0)\n",
+ " c.io.b.poke(1.U)\n",
+ " c.io.s.expect(1.U)\n",
+ " c.io.carryOut.expect(0.U)\n",
" // 1 + 1 = 2\n",
- " poke(c.io.a, 1)\n",
- " expect(c.io.s, 0)\n",
- " expect(c.io.carryOut, 1)\n",
+ " c.io.a.poke(1.U)\n",
+ " c.io.s.expect(0.U)\n",
+ " c.io.carryOut.expect(1.U)\n",
" // 1 + 0 = 1\n",
- " poke(c.io.b, 0)\n",
- " expect(c.io.s, 1)\n",
- " expect(c.io.carryOut, 0)\n",
+ " c.io.b.poke(0.U)\n",
+ " c.io.s.expect(1.U)\n",
+ " c.io.carryOut.expect(0.U)\n",
"}\n",
"\n",
- "class FullAdderTester(c: HalfFullAdder) extends PeekPokeTester(c) {\n",
+ "test(new HalfFullAdder(true)) { c =>\n",
" require(c.hasCarry, \"DUT must be half adder\")\n",
- " poke(c.io.carryIn.get, 0)\n",
+ " c.io.carryIn.get.poke(0.U)\n",
" // 0 + 0 + 0 = 0\n",
- " poke(c.io.a, 0)\n",
- " poke(c.io.b, 0)\n",
- " expect(c.io.s, 0)\n",
- " expect(c.io.carryOut, 0)\n",
+ " c.io.a.poke(0.U)\n",
+ " c.io.b.poke(0.U)\n",
+ " c.io.s.expect(0.U)\n",
+ " c.io.carryOut.expect(0.U)\n",
" // 0 + 0 + 1 = 1\n",
- " poke(c.io.b, 1)\n",
- " expect(c.io.s, 1)\n",
- " expect(c.io.carryOut, 0)\n",
+ " c.io.b.poke(1.U)\n",
+ " c.io.s.expect(1.U)\n",
+ " c.io.carryOut.expect(0.U)\n",
" // 0 + 1 + 1 = 2\n",
- " poke(c.io.a, 1)\n",
- " expect(c.io.s, 0)\n",
- " expect(c.io.carryOut, 1)\n",
+ " c.io.a.poke(1.U)\n",
+ " c.io.s.expect(0.U)\n",
+ " c.io.carryOut.expect(1.U)\n",
" // 0 + 1 + 0 = 1\n",
- " poke(c.io.b, 0)\n",
- " expect(c.io.s, 1)\n",
- " expect(c.io.carryOut, 0)\n",
+ " c.io.b.poke(0.U)\n",
+ " c.io.s.expect(1.U)\n",
+ " c.io.carryOut.expect(0.U)\n",
"\n",
- " poke(c.io.carryIn.get, 1)\n",
+ " c.io.carryIn.get.poke(1.U)\n",
" // 1 + 0 + 0 = 1\n",
- " poke(c.io.a, 0)\n",
- " poke(c.io.b, 0)\n",
- " expect(c.io.s, 1)\n",
- " expect(c.io.carryOut, 0)\n",
+ " c.io.a.poke(0.U)\n",
+ " c.io.b.poke(0.U)\n",
+ " c.io.s.expect(1.U)\n",
+ " c.io.carryOut.expect(0.U)\n",
" // 1 + 0 + 1 = 2\n",
- " poke(c.io.b, 1)\n",
- " expect(c.io.s, 0)\n",
- " expect(c.io.carryOut, 1)\n",
+ " c.io.b.poke(1.U)\n",
+ " c.io.s.expect(0.U)\n",
+ " c.io.carryOut.expect(1.U)\n",
" // 1 + 1 + 1 = 3\n",
- " poke(c.io.a, 1)\n",
- " expect(c.io.s, 1)\n",
- " expect(c.io.carryOut, 1)\n",
+ " c.io.a.poke(1.U)\n",
+ " c.io.s.expect(1.U)\n",
+ " c.io.carryOut.expect(1.U)\n",
" // 1 + 1 + 0 = 2\n",
- " poke(c.io.b, 0)\n",
- " expect(c.io.s, 0)\n",
- " expect(c.io.carryOut, 1)\n",
+ " c.io.b.poke(0.U)\n",
+ " c.io.s.expect(0.U)\n",
+ " c.io.carryOut.expect(1.U)\n",
"}\n",
"\n",
- "val worksHalf = iotesters.Driver(() => new HalfFullAdder(false)) { c => new HalfAdderTester(c) }\n",
- "val worksFull = iotesters.Driver(() => new HalfFullAdder(true)) { c => new FullAdderTester(c) }\n",
- "assert(worksHalf && worksFull) // Scala Code: if works == false, will throw an error\n",
"println(\"SUCCESS!!\") // Scala Code: if we get here, our tests passed!"
]
},
@@ -906,36 +899,35 @@
"\n",
"val testParams = BinaryMealyParams(nStates, s0, stateTransition, output)\n",
"\n",
- "class BinaryMealyTester(c: BinaryMealy) extends PeekPokeTester(c) {\n",
- " poke(c.io.in, false)\n",
- " expect(c.io.out, 0)\n",
- " step(1)\n",
- " poke(c.io.in, false)\n",
- " expect(c.io.out, 0)\n",
- " step(1)\n",
- " poke(c.io.in, false)\n",
- " expect(c.io.out, 0)\n",
- " step(1)\n",
- " poke(c.io.in, true)\n",
- " expect(c.io.out, 1)\n",
- " step(1)\n",
- " poke(c.io.in, true)\n",
- " expect(c.io.out, 0)\n",
- " step(1)\n",
- " poke(c.io.in, false)\n",
- " expect(c.io.out, 1)\n",
- " step(1)\n",
- " poke(c.io.in, true)\n",
- " expect(c.io.out, 1)\n",
- " step(1)\n",
- " poke(c.io.in, false)\n",
- " expect(c.io.out, 1)\n",
- " step(1)\n",
- " poke(c.io.in, true)\n",
- " expect(c.io.out, 1)\n",
+ "test(new BinaryMealy(testParams)) { c =>\n",
+ " c.io.in.poke(false.B)\n",
+ " c.io.out.expect(0.U)\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(false.B)\n",
+ " c.io.out.expect(0.U)\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(false.B)\n",
+ " c.io.out.expect(0.U)\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(true.B)\n",
+ " c.io.out.expect(1.U)\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(true.B)\n",
+ " c.io.out.expect(0.U)\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(false.B)\n",
+ " c.io.out.expect(1.U)\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(true.B)\n",
+ " c.io.out.expect(1.U)\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(false.B)\n",
+ " c.io.out.expect(1.U)\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(true.B)\n",
+ " c.io.out.expect(1.U)\n",
"}\n",
- "val works = iotesters.Driver(() => new BinaryMealy(testParams)) { c => new BinaryMealyTester(c) }\n",
- "assert(works) // Scala Code: if works == false, will throw an error\n",
+ "\n",
"println(\"SUCCESS!!\") // Scala Code: if we get here, our tests passed!"
]
},
@@ -960,10 +952,9 @@
"codemirror_mode": "text/x-scala",
"file_extension": ".scala",
"mimetype": "text/x-scala",
- "name": "scala211",
+ "name": "scala",
"nbconvert_exporter": "script",
- "pygments_lexer": "scala",
- "version": "2.11.11"
+ "version": "2.12.10"
}
},
"nbformat": 4,
diff --git a/3.2_collections.ipynb b/3.2_collections.ipynb
index 6fa97ae..b8ae42a 100644
--- a/3.2_collections.ipynb
+++ b/3.2_collections.ipynb
@@ -49,7 +49,8 @@
"source": [
"import chisel3._\n",
"import chisel3.util._\n",
- "import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}\n",
+ "import chisel3.tester._\n",
+ "import chisel3.tester.RawTester.test\n",
"import scala.collection._"
]
},
@@ -202,21 +203,20 @@
"source": [
"val goldenModel = new ScalaFirFilter(Seq(1, 1, 1, 1))\n",
"\n",
- "Driver(() => new My4ElementFir(1, 1, 1, 1)) {\n",
- " c => new PeekPokeTester(c) {\n",
+ "test(new My4ElementFir(1, 1, 1, 1)) { c =>\n",
" for(i <- 0 until 100) {\n",
- " val input = scala.util.Random.nextInt(8)\n",
+ " val input = scala.util.Random.nextInt(8)\n",
"\n",
- " val goldenModelResult = goldenModel.poke(input)\n",
+ " val goldenModelResult = goldenModel.poke(input)\n",
"\n",
- " poke(c.io.in, input)\n",
+ " c.io.in.poke(input.U)\n",
"\n",
- " expect(c.io.out, goldenModelResult, s\"i $i, input $input, gm $goldenModelResult, ${peek(c.io.out)}\")\n",
+ " c.io.out.expect(goldenModelResult.U, s\"i $i, input $input, gm $goldenModelResult, ${c.io.out.peek().litValue}\")\n",
"\n",
- " step(1)\n",
+ " c.clock.step(1)\n",
" }\n",
- " }\n",
- "}"
+ "\n",
+ "}\n"
]
},
{
@@ -314,20 +314,18 @@
"source": [
"val goldenModel = new ScalaFirFilter(Seq(1, 1, 1, 1))\n",
"\n",
- "Driver(() => new MyManyElementFir(Seq(1, 1, 1, 1), 8)) {\n",
- " c => new PeekPokeTester(c) {\n",
+ "test(new MyManyElementFir(Seq(1, 1, 1, 1), 8)) { c =>\n",
" for(i <- 0 until 100) {\n",
" val input = scala.util.Random.nextInt(8)\n",
"\n",
" val goldenModelResult = goldenModel.poke(input)\n",
"\n",
- " poke(c.io.in, input)\n",
+ " c.io.in.poke(input.U)\n",
"\n",
- " expect(c.io.out, goldenModelResult, s\"i $i, input $input, gm $goldenModelResult, ${peek(c.io.out)}\")\n",
+ " c.io.out.expect(goldenModelResult.U, s\"i $i, input $input, gm $goldenModelResult, ${c.io.out.peek().litValue}\")\n",
"\n",
- " step(1)\n",
+ " c.clock.step(1)\n",
" }\n",
- " }\n",
"}"
]
},
@@ -356,29 +354,27 @@
" * run for at least twice as many samples as taps\n",
" */\n",
"def runOneTest(taps: Seq[Int]) {\n",
- " val goldenModel = new ScalaFirFilter(taps)\n",
+ " val goldenModel = new ScalaFirFilter(taps)\n",
"\n",
- " Driver(() => new MyManyElementFir(taps, 32)) {\n",
- " c => new PeekPokeTester(c) {\n",
- " for(i <- 0 until 2 * taps.length) {\n",
- " val input = r()\n",
+ " test(new MyManyElementFir(taps, 32)) { c =>\n",
+ " for(i <- 0 until 2 * taps.length) {\n",
+ " val input = r()\n",
"\n",
- " val goldenModelResult = goldenModel.poke(input)\n",
+ " val goldenModelResult = goldenModel.poke(input)\n",
"\n",
- " poke(c.io.in, input)\n",
+ " c.io.in.poke(input.U)\n",
"\n",
- " expect(c.io.out, goldenModelResult, s\"i $i, input $input, gm $goldenModelResult, ${peek(c.io.out)}\")\n",
+ " c.io.out.expect(goldenModelResult.U, s\"i $i, input $input, gm $goldenModelResult, ${c.io.out.peek().litValue}\")\n",
"\n",
- " step(1)\n",
- " }\n",
+ " c.clock.step(1)\n",
+ " }\n",
" }\n",
- " }\n",
"}\n",
"\n",
"for(tapSize <- 2 until 100 by 10) {\n",
- " val taps = Seq.fill(tapSize)(r()) // create a sequence of random coefficients\n",
+ " val taps = Seq.fill(tapSize)(r()) // create a sequence of random coefficients\n",
"\n",
- " runOneTest(taps)\n",
+ " runOneTest(taps)\n",
"}"
]
},
@@ -411,21 +407,19 @@
"\n",
"val goldenModel = new ScalaFirFilter(taps)\n",
"\n",
- "Driver(() => new MyManyElementFir(taps, 32)) {\n",
- " c => new PeekPokeTester(c) {\n",
+ "test(new MyManyElementFir(taps, 32)) { c =>\n",
" for(i <- 0 until 100) {\n",
- " val input = r()\n",
+ " val input = r()\n",
"\n",
- " val goldenModelResult = goldenModel.poke(input)\n",
+ " val goldenModelResult = goldenModel.poke(input)\n",
"\n",
- " poke(c.io.in, input)\n",
+ " c.io.in.poke(input.U)\n",
"\n",
- " expect(c.io.out, goldenModelResult, s\"i $i, input $input, gm $goldenModelResult, ${peek(c.io.out)}\")\n",
+ " c.io.out.expect(goldenModelResult.U, s\"i $i, input $input, gm $goldenModelResult, ${c.io.out.peek().litValue}\")\n",
"\n",
- " step(1)\n",
+ " c.clock.step(1)\n",
" }\n",
- " }\n",
- "}"
+ "}\n"
]
},
{
@@ -489,25 +483,23 @@
"source": [
"val goldenModel = new ScalaFirFilter(Seq(1, 1, 1, 1))\n",
"\n",
- "Driver(() => new MyManyDynamicElementVecFir(4)) {\n",
- " c => new PeekPokeTester(c) {\n",
- " poke(c.io.consts(0), 1)\n",
- " poke(c.io.consts(1), 1)\n",
- " poke(c.io.consts(2), 1)\n",
- " poke(c.io.consts(3), 1)\n",
+ "test(new MyManyDynamicElementVecFir(4)) { c =>\n",
+ " c.io.consts(0).poke(1.U)\n",
+ " c.io.consts(1).poke(1.U)\n",
+ " c.io.consts(2).poke(1.U)\n",
+ " c.io.consts(3).poke(1.U)\n",
" for(i <- 0 until 100) {\n",
- " val input = scala.util.Random.nextInt(8)\n",
+ " val input = scala.util.Random.nextInt(8)\n",
"\n",
- " val goldenModelResult = goldenModel.poke(input)\n",
+ " val goldenModelResult = goldenModel.poke(input)\n",
"\n",
- " poke(c.io.in, input)\n",
+ " c.io.in.poke(input.U)\n",
"\n",
- " expect(c.io.out, goldenModelResult, s\"i $i, input $input, gm $goldenModelResult, ${peek(c.io.out)}\")\n",
+ " c.io.out.expect(goldenModelResult.U, s\"i $i, input $input, gm $goldenModelResult, ${c.io.out.peek().litValue}\")\n",
"\n",
- " step(1)\n",
+ " c.clock.step(1)\n",
" }\n",
- " }\n",
- "}"
+ "}\n"
]
},
{
@@ -547,6 +539,7 @@
" // A Register of a vector of UInts\n",
" val reg = RegInit(VecInit(Seq.fill(32)(0.U(32.W))))\n",
"\n",
+ " \n",
"}"
]
},
@@ -556,35 +549,34 @@
"metadata": {},
"outputs": [],
"source": [
- "chisel3.iotesters.Driver(() => new RegisterFile(2) ) { c => new PeekPokeTester(c) {\n",
- " def readExpect(addr: Int, value: Int, port: Int = 0): Unit = {\n",
- " poke(c.io.raddr(port), addr)\n",
- " expect(c.io.rdata(port), value)\n",
- " }\n",
- " def write(addr: Int, value: Int): Unit = {\n",
- " poke(c.io.wen, 1)\n",
- " poke(c.io.wdata, value)\n",
- " poke(c.io.waddr, addr)\n",
- " step(1)\n",
- " poke(c.io.wen, 0)\n",
- " }\n",
- " // everything should be 0 on init\n",
- " for (i <- 0 until 32) {\n",
- " readExpect(i, 0, port = 0)\n",
- " readExpect(i, 0, port = 1)\n",
- " }\n",
- "\n",
- " // write 5 * addr + 3\n",
- " for (i <- 0 until 32) {\n",
- " write(i, 5 * i + 3)\n",
- " }\n",
+ "test(new RegisterFile(2) ) { c =>\n",
+ " def readExpect(addr: Int, value: Int, port: Int = 0): Unit = {\n",
+ " c.io.raddr(port).poke(addr.U)\n",
+ " c.io.rdata(port).expect(value.U)\n",
+ " }\n",
+ " def write(addr: Int, value: Int): Unit = {\n",
+ " c.io.wen.poke(true.B)\n",
+ " c.io.wdata.poke(value.U)\n",
+ " c.io.waddr.poke(addr.U)\n",
+ " c.clock.step(1)\n",
+ " c.io.wen.poke(false.B)\n",
+ " }\n",
+ " // everything should be 0 on init\n",
+ " for (i <- 0 until 32) {\n",
+ " readExpect(i, 0, port = 0)\n",
+ " readExpect(i, 0, port = 1)\n",
+ " }\n",
"\n",
- " // check that the writes worked\n",
- " for (i <- 0 until 32) {\n",
- " readExpect(i, if (i == 0) 0 else 5 * i + 3, port = i % 2)\n",
- " }\n",
+ " // write 5 * addr + 3\n",
+ " for (i <- 0 until 32) {\n",
+ " write(i, 5 * i + 3)\n",
+ " }\n",
"\n",
- "}}"
+ " // check that the writes worked\n",
+ " for (i <- 0 until 32) {\n",
+ " readExpect(i, if (i == 0) 0 else 5 * i + 3, port = i % 2)\n",
+ " }\n",
+ "}"
]
},
{
@@ -631,10 +623,9 @@
"codemirror_mode": "text/x-scala",
"file_extension": ".scala",
"mimetype": "text/x-scala",
- "name": "scala211",
+ "name": "scala",
"nbconvert_exporter": "script",
- "pygments_lexer": "scala",
- "version": "2.11.11"
+ "version": "2.12.10"
}
},
"nbformat": 4,
diff --git a/3.2_interlude.ipynb b/3.2_interlude.ipynb
index 0f93fee..5a4c61c 100644
--- a/3.2_interlude.ipynb
+++ b/3.2_interlude.ipynb
@@ -39,7 +39,8 @@
"source": [
"import chisel3._\n",
"import chisel3.util._\n",
- "import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}"
+ "import chisel3.tester._\n",
+ "import chisel3.tester.RawTester.test"
]
},
{
@@ -84,7 +85,7 @@
"metadata": {},
"outputs": [],
"source": [
- "Driver(() => new Module {\n",
+ "test(new Module {\n",
" // Example circuit using a Queue\n",
" val io = IO(new Bundle {\n",
" val in = Flipped(Decoupled(UInt(8.W)))\n",
@@ -92,47 +93,46 @@
" })\n",
" val queue = Queue(io.in, 2) // 2-element queue\n",
" io.out <> queue\n",
- " }) { c => new PeekPokeTester(c) {\n",
- " // Example testsequence showing the use and behavior of Queue\n",
- " poke(c.io.out.ready, 0)\n",
- " poke(c.io.in.valid, 1) // Enqueue an element\n",
- " poke(c.io.in.bits, 42)\n",
+ " }) { c =>\n",
+ " c.io.out.ready.poke(false.B)\n",
+ " c.io.in.valid.poke(true.B) // Enqueue an elemen.Ut\n",
+ " c.io.in.bits.poke(42.U)\n",
" println(s\"Starting:\")\n",
- " println(s\"\\tio.in: ready=${peek(c.io.in.ready)}\")\n",
- " println(s\"\\tio.out: valid=${peek(c.io.out.valid)}, bits=${peek(c.io.out.bits)}\")\n",
- " step(1)\n",
- " \n",
- " poke(c.io.in.valid, 1) // Enqueue another element\n",
- " poke(c.io.in.bits, 43)\n",
+ " println(s\"\\tio.in: ready=${c.io.in.ready.peek().litValue}\")\n",
+ " println(s\"\\tio.out: valid=${c.io.out.valid.peek().litValue}, bits=${c.io.out.bits.peek().litValue}\")\n",
+ " c.clock.step(1)\n",
+ "\n",
+ " c.io.in.valid.poke(true.B) // Enqueue another elemen.Ut\n",
+ " c.io.in.bits.poke(43.U)\n",
" // What do you think io.out.valid and io.out.bits will be?\n",
" println(s\"After first enqueue:\")\n",
- " println(s\"\\tio.in: ready=${peek(c.io.in.ready)}\")\n",
- " println(s\"\\tio.out: valid=${peek(c.io.out.valid)}, bits=${peek(c.io.out.bits)}\")\n",
- " step(1)\n",
- " \n",
- " poke(c.io.in.valid, 1) // Read a element, attempt to enqueue\n",
- " poke(c.io.in.bits, 44)\n",
- " poke(c.io.out.ready, 1)\n",
+ " println(s\"\\tio.in: ready=${c.io.in.ready.peek().litValue}\")\n",
+ " println(s\"\\tio.out: valid=${c.io.out.valid.peek().litValue}, bits=${c.io.out.bits.peek().litValue}\")\n",
+ " c.clock.step(1)\n",
+ "\n",
+ " c.io.in.valid.poke(true.B) // Read a element, attempt to enqueu.Ue\n",
+ " c.io.in.bits.poke(44.U)\n",
+ " c.io.out.ready.poke(true.B)\n",
" // What do you think io.in.ready will be, and will this enqueue succeed, and what will be read?\n",
" println(s\"On first read:\")\n",
- " println(s\"\\tio.in: ready=${peek(c.io.in.ready)}\")\n",
- " println(s\"\\tio.out: valid=${peek(c.io.out.valid)}, bits=${peek(c.io.out.bits)}\")\n",
- " step(1)\n",
- " \n",
- " poke(c.io.in.valid, 0) // Read elements out\n",
- " poke(c.io.out.ready, 1)\n",
+ " println(s\"\\tio.in: ready=${c.io.in.ready.peek().litValue}\")\n",
+ " println(s\"\\tio.out: valid=${c.io.out.valid.peek().litValue}, bits=${c.io.out.bits.peek().litValue}\")\n",
+ " c.clock.step(1)\n",
+ "\n",
+ " c.io.in.valid.poke(false.B) // Read elements ou.Ut\n",
+ " c.io.out.ready.poke(true.B)\n",
" // What do you think will be read here?\n",
" println(s\"On second read:\")\n",
- " println(s\"\\tio.in: ready=${peek(c.io.in.ready)}\")\n",
- " println(s\"\\tio.out: valid=${peek(c.io.out.valid)}, bits=${peek(c.io.out.bits)}\")\n",
- " step(1)\n",
- " \n",
+ " println(s\"\\tio.in: ready=${c.io.in.ready.peek().litValue}\")\n",
+ " println(s\"\\tio.out: valid=${c.io.out.valid.peek().litValue}, bits=${c.io.out.bits.peek().litValue}\")\n",
+ " c.clock.step(1)\n",
+ "\n",
" // Will a third read produce anything?\n",
" println(s\"On third read:\")\n",
- " println(s\"\\tio.in: ready=${peek(c.io.in.ready)}\")\n",
- " println(s\"\\tio.out: valid=${peek(c.io.out.valid)}, bits=${peek(c.io.out.bits)}\")\n",
- " step(1)\n",
- "} }"
+ " println(s\"\\tio.in: ready=${c.io.in.ready.peek().litValue}\")\n",
+ " println(s\"\\tio.out: valid=${c.io.out.valid.peek().litValue}, bits=${c.io.out.bits.peek().litValue}\")\n",
+ " c.clock.step(1)\n",
+ "}"
]
},
{
@@ -156,7 +156,7 @@
"metadata": {},
"outputs": [],
"source": [
- "Driver(() => new Module {\n",
+ "test(new Module {\n",
" // Example circuit using a priority arbiter\n",
" val io = IO(new Bundle {\n",
" val in = Flipped(Vec(2, Decoupled(UInt(8.W))))\n",
@@ -166,30 +166,30 @@
" val arbiter = Module(new Arbiter(UInt(8.W), 2)) // 2 to 1 Priority Arbiter\n",
" arbiter.io.in <> io.in\n",
" io.out <> arbiter.io.out\n",
- " }) { c => new PeekPokeTester(c) {\n",
- " poke(c.io.in(0).valid, 0)\n",
- " poke(c.io.in(1).valid, 0)\n",
+ " }) { c =>\n",
+ " c.io.in(0).valid.poke(false.B)\n",
+ " c.io.in(1).valid.poke(false.B)\n",
" println(s\"Start:\")\n",
- " println(s\"\\tin(0).ready=${peek(c.io.in(0).ready)}, in(1).ready=${peek(c.io.in(1).ready)}\")\n",
- " println(s\"\\tout.valid=${peek(c.io.out.valid)}, out.bits=${peek(c.io.out.bits)}\")\n",
- " poke(c.io.in(1).valid, 1) // Valid input 1\n",
- " poke(c.io.in(1).bits, 42)\n",
+ " println(s\"\\tin(0).ready=${c.io.in(0).ready.peek().litValue}, in(1).ready=${c.io.in(1).ready.peek().litValue}\")\n",
+ " println(s\"\\tout.valid=${c.io.out.valid.peek().litValue}, out.bits=${c.io.out.bits.peek().litValue}\")\n",
+ " c.io.in(1).valid.poke(true.B) // Valid input 1\n",
+ " c.io.in(1).bits.poke(42.U)\n",
" // What do you think the output will be?\n",
" println(s\"valid input 1:\")\n",
- " println(s\"\\tin(0).ready=${peek(c.io.in(0).ready)}, in(1).ready=${peek(c.io.in(1).ready)}\")\n",
- " println(s\"\\tout.valid=${peek(c.io.out.valid)}, out.bits=${peek(c.io.out.bits)}\")\n",
- " poke(c.io.in(0).valid, 1) // Valid inputs 0 and 1\n",
- " poke(c.io.in(0).bits, 43)\n",
+ " println(s\"\\tin(0).ready=${c.io.in(0).ready.peek().litValue}, in(1).ready=${c.io.in(1).ready.peek().litValue}\")\n",
+ " println(s\"\\tout.valid=${c.io.out.valid.peek().litValue}, out.bits=${c.io.out.bits.peek().litValue}\")\n",
+ " c.io.in(0).valid.poke(true.B) // Valid inputs 0 and 1\n",
+ " c.io.in(0).bits.poke(43.U)\n",
" // What do you think the output will be? Which inputs will be ready?\n",
" println(s\"valid inputs 0 and 1:\")\n",
- " println(s\"\\tin(0).ready=${peek(c.io.in(0).ready)}, in(1).ready=${peek(c.io.in(1).ready)}\")\n",
- " println(s\"\\tout.valid=${peek(c.io.out.valid)}, out.bits=${peek(c.io.out.bits)}\")\n",
- " poke(c.io.in(1).valid, 0) // Valid input 0\n",
+ " println(s\"\\tin(0).ready=${c.io.in(0).ready.peek().litValue}, in(1).ready=${c.io.in(1).ready.peek().litValue}\")\n",
+ " println(s\"\\tout.valid=${c.io.out.valid.peek().litValue}, out.bits=${c.io.out.bits.peek().litValue}\")\n",
+ " c.io.in(1).valid.poke(false.B) // Valid input 0\n",
" // What do you think the output will be?\n",
" println(s\"valid input 0:\")\n",
- " println(s\"\\tin(0).ready=${peek(c.io.in(0).ready)}, in(1).ready=${peek(c.io.in(1).ready)}\")\n",
- " println(s\"\\tout.valid=${peek(c.io.out.valid)}, out.bits=${peek(c.io.out.bits)}\")\n",
- "} }"
+ " println(s\"\\tin(0).ready=${c.io.in(0).ready.peek().litValue}, in(1).ready=${c.io.in(1).ready.peek().litValue}\")\n",
+ " println(s\"\\tout.valid=${c.io.out.valid.peek().litValue}, out.bits=${c.io.out.bits.peek().litValue}\")\n",
+ "}"
]
},
{
@@ -213,27 +213,28 @@
"metadata": {},
"outputs": [],
"source": [
- "Driver(() => new Module {\n",
+ "test(new Module {\n",
" // Example circuit using Reverse\n",
" val io = IO(new Bundle {\n",
" val in = Input(UInt(8.W))\n",
" val out = Output(UInt(8.W))\n",
" })\n",
" io.out := PopCount(io.in)\n",
- " }) { c => new PeekPokeTester(c) {\n",
+ " }) { c =>\n",
" // Integer.parseInt is used create an Integer from a binary specification\n",
- " poke(c.io.in, Integer.parseInt(\"00000000\", 2))\n",
- " println(s\"in=0b${peek(c.io.in).toInt.toBinaryString}, out=${peek(c.io.out)}\")\n",
- " \n",
- " poke(c.io.in, Integer.parseInt(\"00001111\", 2))\n",
- " println(s\"in=0b${peek(c.io.in).toInt.toBinaryString}, out=${peek(c.io.out)}\")\n",
- " \n",
- " poke(c.io.in, Integer.parseInt(\"11001010\", 2))\n",
- " println(s\"in=0b${peek(c.io.in).toInt.toBinaryString}, out=${peek(c.io.out)}\")\n",
- " \n",
- " poke(c.io.in, Integer.parseInt(\"11111111\", 2))\n",
- " println(s\"in=0b${peek(c.io.in).toInt.toBinaryString}, out=${peek(c.io.out)}\")\n",
- "} }"
+ " c.io.in.poke(Integer.parseInt(\"00000000\", 2).U)\n",
+ " println(s\"in=0b${c.io.in.peek().litValue.toInt.toBinaryString}, out=${c.io.out.peek().litValue}\")\n",
+ "\n",
+ " c.io.in.poke(Integer.parseInt(\"00001111\", 2).U)\n",
+ " println(s\"in=0b${c.io.in.peek().litValue.toInt.toBinaryString}, out=${c.io.out.peek().litValue}\")\n",
+ "\n",
+ " c.io.in.poke(Integer.parseInt(\"11001010\", 2).U)\n",
+ " println(s\"in=0b${c.io.in.peek().litValue.toInt.toBinaryString}, out=${c.io.out.peek().litValue}\")\n",
+ "\n",
+ " c.io.in.poke(Integer.parseInt(\"11111111\", 2).U)\n",
+ " println(s\"in=0b${c.io.in.peek().litValue.toInt.toBinaryString}, out=${c.io.out.peek().litValue}\")\n",
+ "\n",
+ "}"
]
},
{
@@ -242,27 +243,27 @@
"metadata": {},
"outputs": [],
"source": [
- "Driver(() => new Module {\n",
+ "test(new Module {\n",
" // Example circuit using Reverse\n",
" val io = IO(new Bundle {\n",
" val in = Input(UInt(8.W))\n",
" val out = Output(UInt(8.W))\n",
" })\n",
" io.out := Reverse(io.in)\n",
- " }) { c => new PeekPokeTester(c) {\n",
+ " }) { c =>\n",
" // Integer.parseInt is used create an Integer from a binary specification\n",
- " poke(c.io.in, Integer.parseInt(\"01010101\", 2))\n",
- " println(s\"in=0b${peek(c.io.in).toInt.toBinaryString}, out=0b${peek(c.io.out).toInt.toBinaryString}\")\n",
- " \n",
- " poke(c.io.in, Integer.parseInt(\"00001111\", 2))\n",
- " println(s\"in=0b${peek(c.io.in).toInt.toBinaryString}, out=0b${peek(c.io.out).toInt.toBinaryString}\")\n",
- " \n",
- " poke(c.io.in, Integer.parseInt(\"11110000\", 2))\n",
- " println(s\"in=0b${peek(c.io.in).toInt.toBinaryString}, out=0b${peek(c.io.out).toInt.toBinaryString}\")\n",
- " \n",
- " poke(c.io.in, Integer.parseInt(\"11001010\", 2))\n",
- " println(s\"in=0b${peek(c.io.in).toInt.toBinaryString}, out=0b${peek(c.io.out).toInt.toBinaryString}\")\n",
- "} }"
+ " c.io.in.poke(Integer.parseInt(\"01010101\", 2).U)\n",
+ " println(s\"in=0b${c.io.in.peek().litValue.toInt.toBinaryString}, out=0b${c.io.out.peek().litValue.toInt.toBinaryString}\")\n",
+ "\n",
+ " c.io.in.poke(Integer.parseInt(\"00001111\", 2).U)\n",
+ " println(s\"in=0b${c.io.in.peek().litValue.toInt.toBinaryString}, out=0b${c.io.out.peek().litValue.toInt.toBinaryString}\")\n",
+ "\n",
+ " c.io.in.poke(Integer.parseInt(\"11110000\", 2).U)\n",
+ " println(s\"in=0b${c.io.in.peek().litValue.toInt.toBinaryString}, out=0b${c.io.out.peek().litValue.toInt.toBinaryString}\")\n",
+ "\n",
+ " c.io.in.poke(Integer.parseInt(\"11001010\", 2).U)\n",
+ " println(s\"in=0b${c.io.in.peek().litValue.toInt.toBinaryString}, out=0b${c.io.out.peek().litValue.toInt.toBinaryString}\")\n",
+ "}"
]
},
{
@@ -283,26 +284,26 @@
"metadata": {},
"outputs": [],
"source": [
- "Driver(() => new Module {\n",
+ "test(new Module {\n",
" // Example circuit using UIntToOH\n",
" val io = IO(new Bundle {\n",
" val in = Input(UInt(4.W))\n",
" val out = Output(UInt(16.W))\n",
" })\n",
" io.out := UIntToOH(io.in)\n",
- " }) { c => new PeekPokeTester(c) {\n",
- " poke(c.io.in, 0)\n",
- " println(s\"in=${peek(c.io.in)}, out=0b${peek(c.io.out).toInt.toBinaryString}\")\n",
- "\n",
- " poke(c.io.in, 1)\n",
- " println(s\"in=${peek(c.io.in)}, out=0b${peek(c.io.out).toInt.toBinaryString}\")\n",
- " \n",
- " poke(c.io.in, 8)\n",
- " println(s\"in=${peek(c.io.in)}, out=0b${peek(c.io.out).toInt.toBinaryString}\")\n",
- " \n",
- " poke(c.io.in, 15)\n",
- " println(s\"in=${peek(c.io.in)}, out=0b${peek(c.io.out).toInt.toBinaryString}\")\n",
- "} }"
+ " }) { c =>\n",
+ " c.io.in.poke(0.U)\n",
+ " println(s\"in=${c.io.in.peek().litValue}, out=0b${c.io.out.peek().litValue.toInt.toBinaryString}\")\n",
+ "\n",
+ " c.io.in.poke(1.U)\n",
+ " println(s\"in=${c.io.in.peek().litValue}, out=0b${c.io.out.peek().litValue.toInt.toBinaryString}\")\n",
+ "\n",
+ " c.io.in.poke(8.U)\n",
+ " println(s\"in=${c.io.in.peek().litValue}, out=0b${c.io.out.peek().litValue.toInt.toBinaryString}\")\n",
+ "\n",
+ " c.io.in.poke(15.U)\n",
+ " println(s\"in=${c.io.in.peek().litValue}, out=0b${c.io.out.peek().litValue.toInt.toBinaryString}\")\n",
+ "}"
]
},
{
@@ -311,32 +312,32 @@
"metadata": {},
"outputs": [],
"source": [
- "Driver(() => new Module {\n",
+ "test(new Module {\n",
" // Example circuit using OHToUInt\n",
" val io = IO(new Bundle {\n",
" val in = Input(UInt(16.W))\n",
" val out = Output(UInt(4.W))\n",
" })\n",
" io.out := OHToUInt(io.in)\n",
- " }) { c => new PeekPokeTester(c) {\n",
- " poke(c.io.in, Integer.parseInt(\"0000 0000 0000 0001\".replace(\" \", \"\"), 2))\n",
- " println(s\"in=0b${peek(c.io.in).toInt.toBinaryString}, out=${peek(c.io.out)}\")\n",
- "\n",
- " poke(c.io.in, Integer.parseInt(\"0000 0000 1000 0000\".replace(\" \", \"\"), 2))\n",
- " println(s\"in=0b${peek(c.io.in).toInt.toBinaryString}, out=${peek(c.io.out)}\")\n",
- " \n",
- " poke(c.io.in, Integer.parseInt(\"1000 0000 0000 0001\".replace(\" \", \"\"), 2))\n",
- " println(s\"in=0b${peek(c.io.in).toInt.toBinaryString}, out=${peek(c.io.out)}\")\n",
- " \n",
+ "}) { c =>\n",
+ " c.io.in.poke(Integer.parseInt(\"0000 0000 0000 0001\".replace(\" \", \"\"), 2).U)\n",
+ " println(s\"in=0b${c.io.in.peek().litValue.toInt.toBinaryString}, out=${c.io.out.peek().litValue}\")\n",
+ "\n",
+ " c.io.in.poke(Integer.parseInt(\"0000 0000 1000 0000\".replace(\" \", \"\"), 2).U)\n",
+ " println(s\"in=0b${c.io.in.peek().litValue.toInt.toBinaryString}, out=${c.io.out.peek().litValue}\")\n",
+ "\n",
+ " c.io.in.poke(Integer.parseInt(\"1000 0000 0000 0001\".replace(\" \", \"\"), 2).U)\n",
+ " println(s\"in=0b${c.io.in.peek().litValue.toInt.toBinaryString}, out=${c.io.out.peek().litValue}\")\n",
+ "\n",
" // Some invalid inputs:\n",
" // None high\n",
- " poke(c.io.in, Integer.parseInt(\"0000 0000 0000 0000\".replace(\" \", \"\"), 2))\n",
- " println(s\"in=0b${peek(c.io.in).toInt.toBinaryString}, out=${peek(c.io.out)}\")\n",
- " \n",
+ " c.io.in.poke(Integer.parseInt(\"0000 0000 0000 0000\".replace(\" \", \"\"), 2).U)\n",
+ " println(s\"in=0b${c.io.in.peek().litValue.toInt.toBinaryString}, out=${c.io.out.peek().litValue}\")\n",
+ "\n",
" // Multiple high\n",
- " poke(c.io.in, Integer.parseInt(\"0001 0100 0010 0000\".replace(\" \", \"\"), 2))\n",
- " println(s\"in=0b${peek(c.io.in).toInt.toBinaryString}, out=${peek(c.io.out)}\")\n",
- "} }"
+ " c.io.in.poke(Integer.parseInt(\"0001 0100 0010 0000\".replace(\" \", \"\"), 2).U)\n",
+ " println(s\"in=0b${c.io.in.peek().litValue.toInt.toBinaryString}, out=${c.io.out.peek().litValue}\")\n",
+ "}\n"
]
},
{
@@ -361,7 +362,7 @@
"metadata": {},
"outputs": [],
"source": [
- "Driver(() => new Module {\n",
+ "test(new Module {\n",
" // Example circuit using PriorityMux\n",
" val io = IO(new Bundle {\n",
" val in_sels = Input(Vec(2, Bool()))\n",
@@ -369,25 +370,25 @@
" val out = Output(UInt(8.W))\n",
" })\n",
" io.out := PriorityMux(io.in_sels, io.in_bits)\n",
- " }) { c => new PeekPokeTester(c) {\n",
- " poke(c.io.in_bits(0), 10)\n",
- " poke(c.io.in_bits(1), 20)\n",
- " \n",
+ " }) { c =>\n",
+ " c.io.in_bits(0).poke(10.U)\n",
+ " c.io.in_bits(1).poke(20.U)\n",
+ "\n",
" // Select higher index only\n",
- " poke(c.io.in_sels(0), 0)\n",
- " poke(c.io.in_sels(1), 1)\n",
- " println(s\"in_sels=${peek(c.io.in_sels)}, out=${peek(c.io.out)}\")\n",
- " \n",
+ " c.io.in_sels(0).poke(false.B)\n",
+ " c.io.in_sels(1).poke(true.B)\n",
+ " println(s\"in_sels=${c.io.in_sels(0).peek().litValue}, out=${c.io.out.peek().litValue}\")\n",
+ "\n",
" // Select both - arbitration needed\n",
- " poke(c.io.in_sels(0), 1)\n",
- " poke(c.io.in_sels(1), 1)\n",
- " println(s\"in_sels=${peek(c.io.in_sels)}, out=${peek(c.io.out)}\")\n",
- " \n",
+ " c.io.in_sels(0).poke(true.B)\n",
+ " c.io.in_sels(1).poke(true.B)\n",
+ " println(s\"in_sels=${c.io.in_sels(0).peek().litValue}, out=${c.io.out.peek().litValue}\")\n",
+ "\n",
" // Select lower index only\n",
- " poke(c.io.in_sels(0), 1)\n",
- " poke(c.io.in_sels(1), 0)\n",
- " println(s\"in_sels=${peek(c.io.in_sels)}, out=${peek(c.io.out)}\")\n",
- "} }"
+ " c.io.in_sels(0).poke(true.B)\n",
+ " c.io.in_sels(1).poke(false.B)\n",
+ " println(s\"in_sels=${c.io.in_sels(0).peek().litValue}, out=${c.io.out.peek().litValue}\")\n",
+ "}"
]
},
{
@@ -396,7 +397,7 @@
"metadata": {},
"outputs": [],
"source": [
- "Driver(() => new Module {\n",
+ "test(new Module {\n",
" // Example circuit using Mux1H\n",
" val io = IO(new Bundle {\n",
" val in_sels = Input(Vec(2, Bool()))\n",
@@ -404,30 +405,30 @@
" val out = Output(UInt(8.W))\n",
" })\n",
" io.out := Mux1H(io.in_sels, io.in_bits)\n",
- " }) { c => new PeekPokeTester(c) {\n",
- " poke(c.io.in_bits(0), 10)\n",
- " poke(c.io.in_bits(1), 20)\n",
- " \n",
+ " }) { c =>\n",
+ " c.io.in_bits(0).poke(10.U)\n",
+ " c.io.in_bits(1).poke(20.U)\n",
+ "\n",
" // Select index 1\n",
- " poke(c.io.in_sels(0), 0)\n",
- " poke(c.io.in_sels(1), 1)\n",
- " println(s\"in_sels=${peek(c.io.in_sels)}, out=${peek(c.io.out)}\")\n",
- " \n",
+ " c.io.in_sels(0).poke(false.B)\n",
+ " c.io.in_sels(1).poke(true.B)\n",
+ " println(s\"in_sels=${c.io.in_sels(0).peek().litValue}, out=${c.io.out.peek().litValue}\")\n",
+ "\n",
" // Select index 0\n",
- " poke(c.io.in_sels(0), 1)\n",
- " poke(c.io.in_sels(1), 0)\n",
- " println(s\"in_sels=${peek(c.io.in_sels)}, out=${peek(c.io.out)}\")\n",
- " \n",
+ " c.io.in_sels(0).poke(true.B)\n",
+ " c.io.in_sels(1).poke(false.B)\n",
+ " println(s\"in_sels=${c.io.in_sels(0).peek().litValue}, out=${c.io.out.peek().litValue}\")\n",
+ "\n",
" // Select none (invalid)\n",
- " poke(c.io.in_sels(0), 0)\n",
- " poke(c.io.in_sels(1), 0)\n",
- " println(s\"in_sels=${peek(c.io.in_sels)}, out=${peek(c.io.out)}\")\n",
- " \n",
+ " c.io.in_sels(0).poke(false.B)\n",
+ " c.io.in_sels(1).poke(false.B)\n",
+ " println(s\"in_sels=${c.io.in_sels(0).peek().litValue}, out=${c.io.out.peek().litValue}\")\n",
+ "\n",
" // Select both (invalid)\n",
- " poke(c.io.in_sels(0), 1)\n",
- " poke(c.io.in_sels(1), 1)\n",
- " println(s\"in_sels=${peek(c.io.in_sels)}, out=${peek(c.io.out)}\")\n",
- "} }"
+ " c.io.in_sels(0).poke(true.B)\n",
+ " c.io.in_sels(1).poke(true.B)\n",
+ " println(s\"in_sels=${c.io.in_sels(0).peek().litValue}, out=${c.io.out.peek().litValue}\")\n",
+ "}"
]
},
{
@@ -446,7 +447,7 @@
"metadata": {},
"outputs": [],
"source": [
- "Driver(() => new Module {\n",
+ "test(new Module {\n",
" // Example circuit using Mux1H\n",
" val io = IO(new Bundle {\n",
" val count = Input(Bool())\n",
@@ -457,24 +458,24 @@
" counter.inc()\n",
" }\n",
" io.out := counter.value\n",
- " }) { c => new PeekPokeTester(c) {\n",
- " poke(c.io.count, 1)\n",
- " println(s\"start: counter value=${peek(c.io.out)}\")\n",
- " \n",
- " step(1)\n",
- " println(s\"step 1: counter value=${peek(c.io.out)}\")\n",
- " \n",
- " step(1)\n",
- " println(s\"step 2: counter value=${peek(c.io.out)}\")\n",
- " \n",
- " poke(c.io.count, 0)\n",
- " step(1)\n",
- " println(s\"step without increment: counter value=${peek(c.io.out)}\")\n",
- " \n",
- " poke(c.io.count, 1)\n",
- " step(1)\n",
- " println(s\"step again: counter value=${peek(c.io.out)}\")\n",
- "} }"
+ " }) { c =>\n",
+ " c.io.count.poke(true.B)\n",
+ " println(s\"start: counter value=${c.io.out.peek().litValue}\")\n",
+ "\n",
+ " c.clock.step(1)\n",
+ " println(s\"step 1: counter value=${c.io.out.peek().litValue}\")\n",
+ "\n",
+ " c.clock.step(1)\n",
+ " println(s\"step 2: counter value=${c.io.out.peek().litValue}\")\n",
+ "\n",
+ " c.io.count.poke(false.B)\n",
+ " c.clock.step(1)\n",
+ " println(s\"step without increment: counter value=${c.io.out.peek().litValue}\")\n",
+ "\n",
+ " c.io.count.poke(true.B)\n",
+ " c.clock.step(1)\n",
+ " println(s\"step again: counter value=${c.io.out.peek().litValue}\")\n",
+ "}"
]
},
{
@@ -499,10 +500,9 @@
"codemirror_mode": "text/x-scala",
"file_extension": ".scala",
"mimetype": "text/x-scala",
- "name": "scala211",
+ "name": "scala",
"nbconvert_exporter": "script",
- "pygments_lexer": "scala",
- "version": "2.11.11"
+ "version": "2.12.10"
}
},
"nbformat": 4,
diff --git a/3.3_higher-order_functions.ipynb b/3.3_higher-order_functions.ipynb
index c09c79a..602cb55 100644
--- a/3.3_higher-order_functions.ipynb
+++ b/3.3_higher-order_functions.ipynb
@@ -24,9 +24,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": true
- },
+ "metadata": {},
"outputs": [],
"source": [
"val path = System.getProperty(\"user.dir\") + \"/source/load-ivy.sc\"\n",
@@ -36,14 +34,13 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": true
- },
+ "metadata": {},
"outputs": [],
"source": [
"import chisel3._\n",
"import chisel3.util._\n",
- "import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}"
+ "import chisel3.tester._\n",
+ "import chisel3.tester.RawTester.test"
]
},
{
@@ -113,9 +110,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": true
- },
+ "metadata": {},
"outputs": [],
"source": [
"println(List(1, 2, 3, 4).map(x => x + 1)) // explicit argument list in function\n",
@@ -143,9 +138,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": true
- },
+ "metadata": {},
"outputs": [],
"source": [
"// Now you try: \n",
@@ -172,9 +165,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": true
- },
+ "metadata": {},
"outputs": [],
"source": [
"println(List(1, 2, 3, 4).zipWithIndex) // note indices start at zero\n",
@@ -195,9 +186,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": true
- },
+ "metadata": {},
"outputs": [],
"source": [
"println(List(1, 2, 3, 4).reduce((a, b) => a + b)) // returns the sum of all the elements\n",
@@ -208,9 +197,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": true
- },
+ "metadata": {},
"outputs": [],
"source": [
"// Important note: reduce will fail with an empty list\n",
@@ -227,9 +214,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": true
- },
+ "metadata": {},
"outputs": [],
"source": [
"// Now you try: \n",
@@ -255,9 +240,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": true
- },
+ "metadata": {},
"outputs": [],
"source": [
"println(List(1, 2, 3, 4).fold(0)(_ + _)) // equivalent to the sum using reduce\n",
@@ -309,9 +292,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": true
- },
+ "metadata": {},
"outputs": [],
"source": [
"class MyRoutingArbiter(numChannels: Int) extends Module {\n",
@@ -320,49 +301,45 @@
" val out = Decoupled(UInt(8.W))\n",
" } )\n",
"\n",
- " // Your code here\n",
+ " // YOUR CODE BELOW\n",
" ???\n",
"}\n",
"\n",
- "// verify that the computation is correct\n",
- "class MyRoutingArbiterTester(c: MyRoutingArbiter) extends PeekPokeTester(c) {\n",
- " // Set input defaults\n",
- " for(i <- 0 until 4) {\n",
- " poke(c.io.in(i).valid, 0)\n",
- " poke(c.io.in(i).bits, i)\n",
- " poke(c.io.out.ready, 1)\n",
- " }\n",
- " \n",
- " expect(c.io.out.valid, 0)\n",
- " \n",
- " // Check single input valid behavior with backpressure\n",
- " for (i <- 0 until 4) {\n",
- " poke(c.io.in(i).valid, 1)\n",
- " expect(c.io.out.valid, 1)\n",
- " expect(c.io.out.bits, i)\n",
- " \n",
- " poke(c.io.out.ready, 0)\n",
- " expect(c.io.in(i).ready, 0)\n",
- " \n",
- " poke(c.io.out.ready, 1)\n",
- " poke(c.io.in(i).valid, 0)\n",
- " }\n",
- " \n",
- " // Basic check of multiple input ready behavior with backpressure\n",
- " poke(c.io.in(1).valid, 1)\n",
- " poke(c.io.in(2).valid, 1)\n",
- " expect(c.io.out.bits, 1)\n",
- " expect(c.io.in(1).ready, 1)\n",
- " expect(c.io.in(0).ready, 0)\n",
- " \n",
- " poke(c.io.out.ready, 0)\n",
- " expect(c.io.in(1).ready, 0)\n",
- "}\n",
+ "test(new MyRoutingArbiter(4)) { c =>\n",
+ " // verify that the computation is correct\n",
+ " // Set input defaults\n",
+ " for(i <- 0 until 4) {\n",
+ " c.io.in(i).valid.poke(false.B)\n",
+ " c.io.in(i).bits.poke(i.U)\n",
+ " c.io.out.ready.poke(true.B)\n",
+ " }\n",
+ "\n",
+ " c.io.out.valid.expect(false.B)\n",
+ "\n",
+ " // Check single input valid behavior with backpressure\n",
+ " for (i <- 0 until 4) {\n",
+ " c.io.in(i).valid.poke(true.B)\n",
+ " c.io.out.valid.expect(true.B)\n",
+ " c.io.out.bits.expect(i.U)\n",
"\n",
- "val works = Driver(() => new MyRoutingArbiter(4)) {\n",
- " c => new MyRoutingArbiterTester(c)\n",
+ " c.io.out.ready.poke(false.B)\n",
+ " c.io.in(i).ready.expect(false.B)\n",
+ "\n",
+ " c.io.out.ready.poke(true.B)\n",
+ " c.io.in(i).valid.poke(false.B)\n",
+ " }\n",
+ "\n",
+ " // Basic check of multiple input ready behavior with backpressure\n",
+ " c.io.in(1).valid.poke(true.B)\n",
+ " c.io.in(2).valid.poke(true.B)\n",
+ " c.io.out.bits.expect(1.U)\n",
+ " c.io.in(1).ready.expect(true.B)\n",
+ " c.io.in(0).ready.expect(false.B)\n",
+ "\n",
+ " c.io.out.ready.poke(false.B)\n",
+ " c.io.in(1).ready.expect(false.B)\n",
"}\n",
- "assert(works) // Scala Code: if works == false, will throw an error\n",
+ "\n",
"println(\"SUCCESS!!\") // Scala Code: if we get here, our tests passed!"
]
},
@@ -377,7 +354,7 @@
"
\n",
"class MyRoutingArbiter(numChannels: Int) extends Module {\n",
" val io = IO(new Bundle {\n",
- " val in = Vec(Flipped(Decoupled(UInt(8.W))), numChannels)\n",
+ " val in = Vec(numChannels, Flipped(Decoupled(UInt(8.W))))\n",
" val out = Decoupled(UInt(8.W))\n",
" } )\n",
"\n",
@@ -416,10 +393,9 @@
"codemirror_mode": "text/x-scala",
"file_extension": ".scala",
"mimetype": "text/x-scala",
- "name": "scala211",
+ "name": "scala",
"nbconvert_exporter": "script",
- "pygments_lexer": "scala",
- "version": "2.11.11"
+ "version": "2.12.10"
}
},
"nbformat": 4,
diff --git a/3.4_functional_programming.ipynb b/3.4_functional_programming.ipynb
index 753b281..c3407b2 100644
--- a/3.4_functional_programming.ipynb
+++ b/3.4_functional_programming.ipynb
@@ -24,9 +24,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"val path = System.getProperty(\"user.dir\") + \"/source/load-ivy.sc\"\n",
@@ -43,14 +41,13 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"import chisel3._\n",
"import chisel3.util._\n",
- "import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}\n",
+ "import chisel3.tester._\n",
+ "import chisel3.tester.RawTester.test\n",
"import chisel3.experimental._\n",
"import chisel3.internal.firrtl.KnownBinaryPoint"
]
@@ -70,9 +67,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"// No inputs or outputs (two versions).\n",
@@ -109,9 +104,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"// These are normal functions.\n",
@@ -143,9 +136,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"// create our function\n",
@@ -178,9 +169,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"import scala.util.Random\n",
@@ -212,9 +201,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"val myList = List(5, 6, 7, 8)\n",
@@ -245,9 +232,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"val exList = List(1, 5, 7, 100)\n",
@@ -318,9 +303,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"// get some math functions\n",
@@ -355,9 +338,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"// our FIR has parameterized window length, IO bitwidth, and windowing function\n",
@@ -385,7 +366,9 @@
"\n",
" // connect output\n",
" io.out := result\n",
- "}"
+ "}\n",
+ "\n",
+ "visualize(() => new MyFir(7, 12, TriangularWindow))"
]
},
{
@@ -403,9 +386,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"// math imports\n",
@@ -420,40 +401,45 @@
"val window = TriangularWindow\n",
"\n",
"// test our FIR\n",
- "Driver(() => new MyFir(length, bitwidth, window)) {\n",
- " c => new PeekPokeTester(c) {\n",
+ "test(new MyFir(length, bitwidth, window)) { c =>\n",
" \n",
" // test data\n",
" val n = 100 // input length\n",
" val sine_freq = 10\n",
" val samp_freq = 100\n",
- " \n",
+ "\n",
" // sample data, scale to between 0 and 2^bitwidth\n",
" val max_value = pow(2, bitwidth)-1\n",
" val sine = (0 until n).map(i => (max_value/2 + max_value/2*sin(2*Pi*sine_freq/samp_freq*i)).toInt)\n",
" //println(s\"input = ${sine.toArray.deep.mkString(\", \")}\")\n",
- " \n",
+ "\n",
" // coefficients\n",
" val coeffs = window(length, bitwidth)\n",
" //println(s\"coeffs = ${coeffs.toArray.deep.mkString(\", \")}\")\n",
"\n",
" // use breeze filter as golden model; need to reverse coefficients\n",
- " val expected = filter(DenseVector(sine.toArray), \n",
- " FIRKernel1D(DenseVector(coeffs.reverse.toArray), 1.0, \"\"), \n",
- " OptOverhang.None)\n",
- " //println(s\"exp_out = ${expected.toArray.deep.mkString(\", \")}\")\n",
+ " val expected = filter(\n",
+ " DenseVector(sine.toArray),\n",
+ " FIRKernel1D(DenseVector(coeffs.reverse.toArray), 1.0, \"\"),\n",
+ " OptOverhang.None\n",
+ " )\n",
+ " expected.toArray // seems to be necessary\n",
+ " //println(s\"exp_out = ${expected.toArray.deep.mkString(\", \")}\") // this seems to be necessary\n",
"\n",
" // push data through our FIR and check the result\n",
- " reset(5)\n",
+ " c.reset.poke(true.B)\n",
+ " c.clock.step(5)\n",
+ " c.reset.poke(false.B)\n",
" for (i <- 0 until n) {\n",
- " poke(c.io.in, sine(i))\n",
- " if (i >= length-1) { // wait for all registers to be initialized since we didn't zero-pad the data\n",
- " expect(c.io.out, expected(i-length+1))\n",
- " //println(s\"cycle $i, got ${peek(c.io.out)}, expect ${expected(i-length+1)}\")\n",
- " }\n",
- " step(1)\n",
+ " c.io.in.poke(sine(i).U)\n",
+ " if (i >= length-1) { // wait for all registers to be initialized since we didn't zero-pad the data\n",
+ " val expectValue = expected(i-length+1)\n",
+ " //println(s\"expected value is $expectValue\")\n",
+ " c.io.out.expect(expected(i-length+1).U)\n",
+ " //println(s\"cycle $i, got ${peek(c.io.out)}, expect ${expected(i-length+1)}\")\n",
+ " }\n",
+ " c.clock.step(1)\n",
" }\n",
- " }\n",
"}"
]
},
@@ -476,9 +462,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class Neuron(inputs: Int, act: FixedPoint => FixedPoint) extends Module {\n",
@@ -536,9 +520,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"val Step: FixedPoint => FixedPoint = ???\n",
@@ -571,31 +553,29 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"// test our Neuron \n",
- "Driver(() => new Neuron(2, Step)) {\n",
- " c => new PeekPokeTester(c) {\n",
- " \n",
+ "test(new Neuron(2, Step)) { c =>\n",
" val inputs = Seq(Seq(-1, -1), Seq(-1, 1), Seq(1, -1), Seq(1, 1))\n",
- " \n",
+ "\n",
" // make this a sequence of two values\n",
" val weights = ???\n",
"\n",
" // push data through our Neuron and check the result (AND gate)\n",
- " reset(5)\n",
+ " c.reset.poke(true.B)\n",
+ " c.clock.step(5)\n",
+ " c.reset.poke(false.B)\n",
" for (i <- inputs) {\n",
- " pokeFixedPoint(c.io.in(0), i(0))\n",
- " pokeFixedPoint(c.io.in(1), i(1))\n",
- " pokeFixedPoint(c.io.weights(0), weights(0))\n",
- " pokeFixedPoint(c.io.weights(1), weights(1))\n",
- " expectFixedPoint(c.io.out, if (i(0) + i(1) > 0) 1 else 0, \"ERROR\")\n",
- " step(1)\n",
+ " c.io.in(0).poke(i(0).F(8.BP))\n",
+ " c.io.in(1).poke(i(1).F(8.BP))\n",
+ " c.io.weights(0).poke(weights(0).F(16.W, 8.BP))\n",
+ " c.io.weights(1).poke(weights(1).F(16.W, 8.BP))\n",
+ " c.io.out.expect((if (i(0) + i(1) > 0) 1 else 0).F(16.W, 8.BP))\n",
+ " c.clock.step(1)\n",
" }\n",
- " }\n",
+ " \n",
"}"
]
},
@@ -635,7 +615,7 @@
"mimetype": "text/x-scala",
"name": "scala",
"nbconvert_exporter": "script",
- "version": "2.12.8"
+ "version": "2.12.10"
}
},
"nbformat": 4,
diff --git a/3.5_object_oriented_programming.ipynb b/3.5_object_oriented_programming.ipynb
index dac28d0..8c1e22f 100644
--- a/3.5_object_oriented_programming.ipynb
+++ b/3.5_object_oriented_programming.ipynb
@@ -27,9 +27,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"val path = System.getProperty(\"user.dir\") + \"/source/load-ivy.sc\"\n",
@@ -39,15 +37,14 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"import chisel3._\n",
"import chisel3.util._\n",
- "import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}\n",
- "import chisel3.experimental._"
+ "import chisel3.experimental._\n",
+ "import chisel3.tester._\n",
+ "import chisel3.tester.RawTester.test"
]
},
{
@@ -72,9 +69,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"abstract class MyAbstractClass {\n",
@@ -106,9 +101,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"trait HasFunction {\n",
@@ -148,9 +141,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"object MyObject {\n",
@@ -175,9 +166,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"object Lion {\n",
@@ -205,9 +194,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"object Animal {\n",
@@ -291,9 +278,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class Nail(length: Int) // Regular class\n",
@@ -328,9 +313,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"case class SomeGeneratorParameters(\n",
@@ -373,9 +356,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class NoGlitchCounterIO(bitwidth: Int) extends Bundle {\n",
@@ -430,9 +411,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class GrayCounter(val bitwidth: Int) extends NoGlitchCounter(bitwidth) {\n",
@@ -447,9 +426,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"import scala.math.pow\n",
@@ -472,7 +449,7 @@
" }\n",
" }._1\n",
" }\n",
- "}"
+ "}\n"
]
},
{
@@ -485,35 +462,31 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"// test our gray coder\n",
"val bitwidth = 4\n",
- "Driver(() => new GrayCoder(bitwidth)) {\n",
- " c => new PeekPokeTester(c) {\n",
- " \n",
- " def toBinary(i: Int, digits: Int = 8) =\n",
- " String.format(\"%\" + digits + \"s\", i.toBinaryString).replace(' ', '0')\n",
- "\n",
+ "test(new GrayCoder(bitwidth)) { c =>\n",
+ " def toBinary(i: Int, digits: Int = 8) = {\n",
+ " String.format(\"%\" + digits + \"s\", i.toBinaryString).replace(' ', '0')\n",
+ " }\n",
" println(\"Encoding:\")\n",
" for (i <- 0 until pow(2, bitwidth).toInt) {\n",
- " poke(c.io.in, i)\n",
- " poke(c.io.encode, true)\n",
- " step(1)\n",
- " println(s\"In = ${toBinary(i, bitwidth)}, Out = ${toBinary(peek(c.io.out).toInt, bitwidth)}\")\n",
+ " c.io.in.poke(i.U)\n",
+ " c.io.encode.poke(true.B)\n",
+ " c.clock.step(1)\n",
+ " println(s\"In = ${toBinary(i, bitwidth)}, Out = ${toBinary(c.io.out.peek().litValue.toInt, bitwidth)}\")\n",
" }\n",
- " \n",
+ "\n",
" println(\"Decoding:\")\n",
" for (i <- 0 until pow(2, bitwidth).toInt) {\n",
- " poke(c.io.in, i)\n",
- " poke(c.io.encode, false)\n",
- " step(1)\n",
- " println(s\"In = ${toBinary(i, bitwidth)}, Out = ${toBinary(peek(c.io.out).toInt, bitwidth)}\")\n",
+ " c.io.in.poke(i.U)\n",
+ " c.io.encode.poke(false.B)\n",
+ " c.clock.step(1)\n",
+ " println(s\"In = ${toBinary(i, bitwidth)}, Out = ${toBinary(c.io.out.peek().litValue.toInt, bitwidth)}\")\n",
" }\n",
- " }\n",
+ "\n",
"}"
]
},
@@ -527,9 +500,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class AsyncFIFO(depth: Int = 16) extends Module {\n",
@@ -593,10 +564,9 @@
"codemirror_mode": "text/x-scala",
"file_extension": ".scala",
"mimetype": "text/x-scala",
- "name": "scala211",
+ "name": "scala",
"nbconvert_exporter": "script",
- "pygments_lexer": "scala",
- "version": "2.11.11"
+ "version": "2.12.10"
}
},
"nbformat": 4,
diff --git a/3.6_types.ipynb b/3.6_types.ipynb
index 35ef870..1a4d834 100644
--- a/3.6_types.ipynb
+++ b/3.6_types.ipynb
@@ -30,9 +30,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"val path = System.getProperty(\"user.dir\") + \"/source/load-ivy.sc\"\n",
@@ -42,14 +40,13 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"import chisel3._\n",
"import chisel3.util._\n",
- "import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}"
+ "import chisel3.tester._\n",
+ "import chisel3.tester.RawTester.test"
]
},
{
@@ -68,9 +65,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"println(10.getClass)\n",
@@ -88,9 +83,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class MyClass {\n",
@@ -110,9 +103,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"def double(s: String): String = s + s\n",
@@ -132,9 +123,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"var counter = 0\n",
@@ -238,9 +227,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class TypeConvertDemo extends Module {\n",
@@ -251,13 +238,12 @@
" io.out := io.in//.asTypeOf(io.out)\n",
"}\n",
"\n",
- "Driver(() => new TypeConvertDemo) { c =>\n",
- " new PeekPokeTester(c) {\n",
- " poke(c.io.in, 3)\n",
- " expect(c.io.out, 3)\n",
- " poke(c.io.in, 15)\n",
- " expect(c.io.out, -1)\n",
- " }}"
+ "test(new TypeConvertDemo) { c =>\n",
+ " c.io.in.poke(3.U)\n",
+ " c.io.out.expect(3.S)\n",
+ " c.io.in.poke(15.U)\n",
+ " c.io.out.expect(-1.S)\n",
+ "}"
]
},
{
@@ -279,14 +265,12 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class ConstantSum(in1: Data, in2: Data) extends Module {\n",
" val io = IO(new Bundle {\n",
- " val out = Output(in1.cloneType)\n",
+ " val out = Output(chiselTypeOf(in1)) // in case in1 is literal then just get its type\n",
" })\n",
" (in1, in2) match {\n",
" case (x: UInt, y: UInt) => io.out := x + y\n",
@@ -311,9 +295,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class InputIsZero extends Module {\n",
@@ -359,9 +341,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"case class SomeGeneratorParameters(\n",
@@ -416,9 +396,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class Boat(val name: String, val length: Int)\n",
@@ -457,9 +435,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"// Helper function to make this cell a bit less tedious.\n",
@@ -528,12 +504,10 @@
"source": [
"class Bundle1 extends Bundle {\n",
" val a = UInt(8.W)\n",
- " override def cloneType = (new Bundle1).asInstanceOf[this.type]\n",
"}\n",
"\n",
"class Bundle2 extends Bundle1 {\n",
" val b = UInt(16.W)\n",
- " override def cloneType = (new Bundle2).asInstanceOf[this.type]\n",
"}\n",
"\n",
"class BadTypeModule extends Module {\n",
@@ -549,10 +523,10 @@
" //io.out := io.c // won't work due to different types\n",
"\n",
" // Okay, but Chisel will truncate the input width to 1 to match the output.\n",
- " io.out := io.in\n",
+ "// io.out := io.in\n",
"\n",
- " // Compiles; Chisel will connect the common subelements of the two Bundles (in this case, 'a').\n",
- " io.bundleOut := io.bundleIn\n",
+ "// // Compiles; Chisel will connect the common subelements of the two Bundles (in this case, 'a').\n",
+ "// io.bundleOut := io.bundleIn\n",
"}\n",
"\n",
"println(getVerilog(new BadTypeModule))"
@@ -574,9 +548,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"val seq1 = Seq(\"1\", \"2\", \"3\") // Type is Seq[String]\n",
@@ -594,9 +566,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"//val default = Seq() // Error!\n",
@@ -619,9 +589,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"def time[T](block: => T): T = {\n",
@@ -684,16 +652,14 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class ShiftRegisterIO[T <: Data](gen: T, n: Int) extends Bundle {\n",
" require (n >= 0, \"Shift register must have non-negative shift\")\n",
" \n",
- " val in = Input(gen.cloneType)\n",
- " val out = Output(Vec(n + 1, gen.cloneType)) // + 1 because in is included in out\n",
+ " val in = Input(gen)\n",
+ " val out = Output(Vec(n + 1, gen)) // + 1 because in is included in out\n",
" override def cloneType: this.type = (new ShiftRegisterIO(gen, n)).asInstanceOf[this.type]\n",
"}\n",
"\n",
@@ -706,17 +672,22 @@
" }\n",
"}\n",
"\n",
- "class ShiftRegisterTester[T <: Bits](c: ShiftRegister[T]) extends PeekPokeTester(c) {\n",
+ "// test(new ShiftRegister(UInt(4.W), 5)) { c =>\n",
+ "// println(s\"Testing ShiftRegister of type ${c.io.in} and depth ${c.io.out.length}\")\n",
+ "// for (i <- 0 until 10) {\n",
+ "// c.io.in.poke(i.U) // magic literal creation\n",
+ "// println(s\"$i: ${c.io.out.indices.map { index => c.io.out(i).peek().litValue} }\")\n",
+ "// c.clock.step(1)\n",
+ "// }\n",
+ "// }\n",
+ "visualize(() => new ShiftRegister(SInt(6.W), 3))\n",
+ "test(new ShiftRegister(SInt(6.W), 3)) { c => \n",
" println(s\"Testing ShiftRegister of type ${c.io.in} and depth ${c.io.out.length}\")\n",
" for (i <- 0 until 10) {\n",
- " poke(c.io.in, i)\n",
- " println(s\"$i: ${peek(c.io.out)}\")\n",
- " step(1)\n",
- " }\n",
- "}\n",
- "\n",
- "Driver(() => new ShiftRegister(UInt(4.W), 5)) { c => new ShiftRegisterTester(c) }\n",
- "Driver(() => new ShiftRegister(SInt(6.W), 3)) { c => new ShiftRegisterTester(c) }"
+ " c.io.in.poke(i.S) // magic literal creation\n",
+ " println(s\"$i: ${c.io.out.indices.map { index => c.io.out(index).peek().litValue} }\")\n",
+ " c.clock.step(1)\n",
+ " }}"
]
},
{
@@ -753,9 +724,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"import chisel3.experimental._\n",
@@ -763,10 +732,10 @@
"\n",
"class Mac[T <: Data : Ring](genIn : T, genOut: T) extends Module {\n",
" val io = IO(new Bundle {\n",
- " val a = Input(genIn.cloneType)\n",
- " val b = Input(genIn.cloneType)\n",
- " val c = Input(genIn.cloneType)\n",
- " val out = Output(genOut.cloneType)\n",
+ " val a = Input(genIn)\n",
+ " val b = Input(genIn)\n",
+ " val c = Input(genIn)\n",
+ " val out = Output(genOut)\n",
" })\n",
" io.out := io.a * io.b + io.c\n",
"}\n",
@@ -794,9 +763,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"object Mac {\n",
@@ -830,12 +797,8 @@
"Solution (click to toggle displaying) \n",
"\n",
"\n",
- "object Mac {\n",
- " def apply\\[T <: Data : Ring\\](a: T, b: T, c: T): T = {\n",
- " // you can also instantiate the Mac from above and connect the IOs to arguments\n",
+ "\n",
" a * b + c\n",
- " }\n",
- "}\n",
"\n",
" "
]
@@ -855,15 +818,13 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class Integrator[T <: Data : Ring](genIn: T, genReg: T) extends Module {\n",
" val io = IO(new Bundle {\n",
- " val in = Input(genIn.cloneType)\n",
- " val out = Output(genReg.cloneType)\n",
+ " val in = Input(genIn)\n",
+ " val out = Output(genReg)\n",
" })\n",
" \n",
" val reg = RegInit(genReg, Ring[T].zero) // init to zero\n",
@@ -871,20 +832,18 @@
" io.out := reg\n",
"}\n",
"\n",
- "class IntegratorSIntTester(c: Integrator[SInt]) extends PeekPokeTester(c) {\n",
- " poke(c.io.in, 3)\n",
- " expect(c.io.out, 0)\n",
- " step(1)\n",
- " poke(c.io.in, -4)\n",
- " expect(c.io.out, 3)\n",
- " step(1)\n",
- " poke(c.io.in, 6)\n",
- " expect(c.io.out, -1)\n",
- " step(1)\n",
- " expect(c.io.out, 5)\n",
- "}\n",
- "\n",
- "chisel3.iotesters.Driver(() => new Integrator(SInt(4.W), SInt(8.W))) { c => new IntegratorSIntTester(c) }"
+ "test(new Integrator(SInt(4.W), SInt(8.W))) { c =>\n",
+ " c.io.in.poke(3.S)\n",
+ " c.io.out.expect(0.S)\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(-4.S)\n",
+ " c.io.out.expect(3.S)\n",
+ " c.clock.step(1)\n",
+ " c.io.in.poke(6.S)\n",
+ " c.io.out.expect(-1.S)\n",
+ " c.clock.step(1)\n",
+ " c.io.out.expect(5.S)\n",
+ "}"
]
},
{
@@ -950,9 +909,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"println(getVerilog(new Mac(DspComplex(SInt(4.W), SInt(4.W)), DspComplex(SInt(6.W), SInt(6.W))) ))"
@@ -975,9 +932,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"class SignMagnitude(val magnitudeWidth: Option[Int] = None) extends Bundle {\n",
@@ -1001,7 +956,6 @@
" def *(that: SignMagnitude): SignMagnitude = {\n",
" // Implement this!\n",
" }\n",
- " override def cloneType: this.type = new SignMagnitude(magnitudeWidth).asInstanceOf[this.type]\n",
"}\n",
"trait SignMagnitudeRing extends Ring[SignMagnitude] {\n",
" def plus(f: SignMagnitude, g: SignMagnitude): SignMagnitude = {\n",
@@ -1038,34 +992,23 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
- "class SignMagnitudeMACTester(c: Mac[SignMagnitude]) extends PeekPokeTester(c) {\n",
- " // 3 * 3 + 2 = 11\n",
- " poke(c.io.a.sign, 0)\n",
- " poke(c.io.a.magnitude, 3)\n",
- " poke(c.io.b.sign, 0)\n",
- " poke(c.io.b.magnitude, 3)\n",
- " poke(c.io.c.sign, 0)\n",
- " poke(c.io.c.magnitude, 2)\n",
- " expect(c.io.out.sign, 0)\n",
- " expect(c.io.out.magnitude, 11)\n",
- " // 3 * 3 - 2 = 7\n",
- " poke(c.io.c.sign, 1)\n",
- " expect(c.io.out.sign, 0)\n",
- " expect(c.io.out.magnitude, 7)\n",
- " // 3 * (-3) - 2 = -11\n",
- " poke(c.io.b.sign, 1)\n",
- " expect(c.io.out.sign, 1)\n",
- " expect(c.io.out.magnitude, 11)\n",
- "}\n",
- "val works = iotesters.Driver(() => new Mac(new SignMagnitude(Some(4)), new SignMagnitude(Some(5)))) {\n",
- " c => new SignMagnitudeMACTester(c)\n",
+ "import chisel3.experimental.BundleLiterals._\n",
+ "\n",
+ "test(new Mac(new SignMagnitude(Some(4)), new SignMagnitude(Some(5)))) { c =>\n",
+ " c.io.a.poke(chiselTypeOf(c.io.a).Lit(_.sign -> false.B, _.magnitude -> 3.U))\n",
+ " c.io.b.poke(chiselTypeOf(c.io.b).Lit(_.sign -> false.B, _.magnitude -> 3.U))\n",
+ " c.io.c.poke(chiselTypeOf(c.io.c).Lit(_.sign -> false.B, _.magnitude -> 2.U))\n",
+ " c.io.out.expect(chiselTypeOf(c.io.out).Lit(_.sign -> false.B, _.magnitude -> 11.U))\n",
+ "\n",
+ " c.io.c.sign.poke(true.B)\n",
+ " c.io.out.expect(chiselTypeOf(c.io.out).Lit(_.sign -> false.B, _.magnitude -> 7.U))\n",
+ "\n",
+ " c.io.b.sign.poke(true.B)\n",
+ " c.io.out.expect(chiselTypeOf(c.io.out).Lit(_.sign -> true.B, _.magnitude -> 11.U))\n",
"}\n",
- "assert(works) // Scala Code: if works == false, will throw an error\n",
"println(\"SUCCESS!!\") // Scala Code: if we get here, our tests passed!"
]
},
@@ -1079,9 +1022,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"println(getVerilog(new Mac(new SignMagnitude(Some(4)), new SignMagnitude(Some(5)))))"
@@ -1097,9 +1038,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"println(getVerilog(new Mac(DspComplex(new SignMagnitude(Some(4)), new SignMagnitude(Some(4))), DspComplex(new SignMagnitude(Some(5)), new SignMagnitude(Some(5))))))"
@@ -1143,6 +1082,13 @@
"\n",
" "
]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
}
],
"metadata": {
@@ -1155,10 +1101,9 @@
"codemirror_mode": "text/x-scala",
"file_extension": ".scala",
"mimetype": "text/x-scala",
- "name": "scala211",
+ "name": "scala",
"nbconvert_exporter": "script",
- "pygments_lexer": "scala",
- "version": "2.11.11"
+ "version": "2.12.10"
}
},
"nbformat": 4,
diff --git a/source/load-ivy.sc b/source/load-ivy.sc
index 1669177..be3ee19 100644
--- a/source/load-ivy.sc
+++ b/source/load-ivy.sc
@@ -10,13 +10,15 @@ interp.configureCompiler(x => x.settings.source.value = scala.tools.nsc.settings
// System.setProperty("https.proxyHost", "proxy.example.com")
// System.setProperty("https.proxyPort", "3128")
-import $ivy.`edu.berkeley.cs::chisel3:3.2.0`
-import $ivy.`edu.berkeley.cs::chisel-iotesters:1.3.0`
-import $ivy.`edu.berkeley.cs::chisel-testers2:0.1.0`
-import $ivy.`edu.berkeley.cs::dsptools:1.2.0`
+import $ivy.`edu.berkeley.cs::chisel3:3.4-SNAPSHOT`
+import $ivy.`edu.berkeley.cs::chisel-iotesters:1.5-SNAPSHOT`
+import $ivy.`edu.berkeley.cs::chiseltest:0.3-SNAPSHOT`
+import $ivy.`edu.berkeley.cs::dsptools:1.4-SNAPSHOT`
import $ivy.`org.scalanlp::breeze:0.13.2`
import $ivy.`edu.berkeley.cs::rocket-dsptools:1.2.0`
-import $ivy.`edu.berkeley.cs::firrtl-diagrammer:1.1.0`
+import $ivy.`edu.berkeley.cs::firrtl-diagrammer:1.3-SNAPSHOT`
+
+import $ivy.`org.scalatest::scalatest:3.2.2`
// Convenience function to invoke Chisel and grab emitted Verilog.
def getVerilog(dut: => chisel3.core.UserModule): String = {
@@ -91,91 +93,76 @@ def stringifyAST(firrtlAST: firrtl.ir.Circuit): String = {
}
// Returns path to module viz and hierarchy viz
-def generateVisualizations(gen: () => chisel3.RawModule): (String, String) = {
- import dotvisualizer._
- import dotvisualizer.transforms._
-
- import java.io._
- import firrtl._
- import firrtl.annotations._
-
- import almond.interpreter.api.DisplayData
- import almond.api.helpers.Display
-
- import chisel3._
- import chisel3.experimental._
- import firrtl.ir.Module
- import sys.process._
-
- val targetDir = "build"
- val chiselIR = chisel3.Driver.elaborate(gen)
- val firrtlIR = chisel3.Driver.emit(chiselIR)
- val config = Config(targetDir = "build", firrtlSource = firrtlIR)
-
- val sourceFirrtl = {
- if(config.firrtlSource.nonEmpty) {
- config.firrtlSource
- }
- else {
- scala.io.Source.fromFile(config.firrtlSourceFile).getLines().mkString("\n")
- }
- }
+def generateVisualizations(gen: () => chisel3.RawModule, targetModule: String = ""): (String, String) = {
+ import dotvisualizer._
+ import dotvisualizer.transforms._
- val ast = Parser.parse(sourceFirrtl)
- val uniqueTop = ast.main + ast.hashCode().toHexString
- val cmdRegex = "cmd[0-9]+([A-Za-z]+.*)".r
- val readableTop = ast.main match {
- case cmdRegex(n) => n
- case other => other
- }
- val newTop = readableTop
-
- val newModules: Seq[firrtl.ir.DefModule] = ast.modules.map {
- case m: Module if m.name == ast.main => m.copy(name = newTop)
- case other => other
- }
-
- val newAst = ast.copy(main = newTop, modules = newModules)
-
- val controlAnnotations: Seq[Annotation] = config.toAnnotations
+ import java.io._
+ import firrtl._
+ import firrtl.annotations._
+
+ import almond.interpreter.api.DisplayData
+ import almond.api.helpers.Display
+
+ import chisel3._
+ import chisel3.stage._
+ import chisel3.experimental._
+ import firrtl.ir.Module
+ import sys.process._
+
+ val sourceFirrtl = scala.Console.withOut(new PrintStream(new ByteArrayOutputStream())) {
+ (new ChiselStage).emitChirrtl(gen())
+ }
+ val ast = Parser.parse(sourceFirrtl)
- val loweredAst = ToLoFirrtl.lower(newAst)
+ val uniqueTopName = ast.main + ast.hashCode().toHexString
- FileUtils.makeDirectory(targetDir)
+ val targetDir = s"diagrams/$uniqueTopName/"
- FirrtlDiagrammer.addCss(targetDir)
+ val cmdRegex = "cmd[0-9]+([A-Za-z]+.*)".r
+ val readableTop = ast.main match {
+ case cmdRegex(n) => n
+ case other => other
+ }
+ val newTop = readableTop
- val circuitState = CircuitState(loweredAst, LowForm, controlAnnotations)
+ // Console hack prevents unnecessary chatter appearing in cell
+ scala.Console.withOut(new PrintStream(new ByteArrayOutputStream())) {
+ val sourceFirrtl = (new ChiselStage).emitChirrtl(gen())
- if(config.justTopLevel) {
- val justTopLevelTransform = new ModuleLevelDiagrammer
- justTopLevelTransform.execute(circuitState)
- } else {
- val x = new MakeDiagramGroup
- x.execute(circuitState)
+ val newModules: Seq[firrtl.ir.DefModule] = ast.modules.map {
+ case m: Module if m.name == ast.main => m.copy(name = newTop)
+ case other => other
}
+ val newAst = ast.copy(main = newTop, modules = newModules)
- s"cp build/${readableTop}.dot.svg build/${uniqueTop}.dot.svg"!!
+ val controlAnnotations: Seq[Annotation] = Seq(
+ firrtl.stage.FirrtlSourceAnnotation(sourceFirrtl),
+ firrtl.options.TargetDirAnnotation(targetDir),
+ dotvisualizer.stage.OpenCommandAnnotation("")
+ )
- s"cp build/${readableTop}_hierarchy.dot.svg build/${uniqueTop}_hierarchy.dot.svg"!!
-
- val moduleView = targetDir + "/" + uniqueTop + ".dot.svg"
- val x = """ """
-
- val instanceView = targetDir + "/" + uniqueTop + "_hierarchy.dot.svg"
- val y = """ """
- (x, y)
+ (new dotvisualizer.stage.DiagrammerStage).execute(Array.empty, controlAnnotations)
+ }
+ val moduleView = s"""$targetDir/$newTop.dot.svg"""
+ val instanceView = s"""$targetDir/${newTop}_hierarchy.dot.svg"""
-}
+ val svgModuleText = FileUtils.getText(moduleView)
+ val svgInstanceText = FileUtils.getText(instanceView)
+
+ val x = s"""$svgModuleText
"""
+ val y = s""" width="100%" height="100%" overflow="scroll">$svgInstanceText
"""
+ (x, y)
+}
def visualize(gen: () => chisel3.RawModule): Unit = {
- val (moduleView, instanceView) = generateVisualizations(gen)
- html(moduleView)
+ val (moduleView, instanceView) = generateVisualizations(gen)
+ html(moduleView)
}
def visualizeHierarchy(gen: () => chisel3.RawModule): Unit = {
- val (moduleView, instanceView) = generateVisualizations(gen)
- html(instanceView)
+ val (moduleView, instanceView) = generateVisualizations(gen)
+ html(instanceView)
}