val path = System.getProperty("user.dir") + "/source/load-ivy.sc" interp.load.module(ammonite.ops.Path(java.nio.file.FileSystems.getDefault().getPath(path))) import chisel3._ import chisel3.util._ import chisel3.tester._ import chisel3.tester.RawTester.test import dotvisualizer._ // Chisel Code: Declare a new module definition class Passthrough extends Module { val io = IO(new Bundle { val in = Input(UInt(4.W)) val out = Output(UInt(4.W)) }) io.out := io.in } // Scala Code: Elaborate our Chisel design by translating it to Verilog // Don't worry about understanding this code; it is very complicated Scala println(getVerilog(new Passthrough)) // Chisel Code, but pass in a parameter to set widths of ports class PassthroughGenerator(width: Int) extends Module { val io = IO(new Bundle { val in = Input(UInt(width.W)) val out = Output(UInt(width.W)) }) io.out := io.in } // Let's now generate modules with different widths println(getVerilog(new PassthroughGenerator(10))) println(getVerilog(new PassthroughGenerator(20))) // Scala Code: `test` runs the unit test. // test takes a user Module and has a code block that applies pokes and expects to the // circuit under test (c) test(new Passthrough()) { c => c.io.in.poke(0.U) // Set our input to value 0 c.io.out.expect(0.U) // Assert that the output correctly has 0 c.io.in.poke(1.U) // Set our input to value 1 c.io.out.expect(1.U) // Assert that the output correctly has 1 c.io.in.poke(2.U) // Set our input to value 2 c.io.out.expect(2.U) // Assert that the output correctly has 2 } println("SUCCESS!!") // Scala Code: if we get here, our tests passed! // Test with width 10 test(???) { c => ??? } // Test with width 20 test(???) { c => ??? } println("SUCCESS!!") // Scala Code: if we get here, our tests passed! // Viewing the Verilog for debugging println(getVerilog(new Passthrough)) // Viewing the firrtl for debugging println(getFirrtl(new Passthrough)) class PrintingModule extends Module { val io = IO(new Bundle { val in = Input(UInt(4.W)) val out = Output(UInt(4.W)) }) io.out := io.in printf("Print during simulation: Input is %d\n", io.in) // chisel printf has its own string interpolator too printf(p"Print during simulation: IO is $io\n") println(s"Print during generation: Input is ${io.in}") } test(new PrintingModule ) { c => c.io.in.poke(3.U) c.clock.step(5) // circuit will print println(s"Print during testing: Input is ${c.io.in.peek()}") }