classCompAextendsModule{ val io = IO(newBundle { val a = Input(UInt(8.W)) val b = Input(UInt(8.W)) val x = Output(UInt(8.W)) val y = Output(UInt(8.W)) }) }
classCompBextendsModule{ val io = IO(newBundle { val in1 = Input(UInt(8.W)) val in2 = Input(UInt(8.W)) val out = Output(UInt(8.W)) }) }
以下是在顶层模块中实例化两个部件,并进行连线的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
classCompCextendsModule{ val io = IO(newBundle { val in_a = Input(UInt(8.W)) val in_b = Input(UInt(8.W)) val in_c = Input(UInt(8.W)) val out_x = Output(UInt(8.W)) val out_y = Output(UInt(8.W)) }) val compA = Module(newCompA()) val compB = Module(newCompB()) compA.io.a := io.in_a compA.io.b := io.in_b io.out_x := compA.io.x compB.io.in1 := compA.io.y compB.io.in2 := io.in_c io.out_y := compB.io.out }
组件通过new关键字来创建,并且需要被包裹在一个对于Module的调用中。
对于组件的引用存储在一个本地变量,例如,compA中,可以通过io域来访问组件的IO端口。
实例:ALU
1 2 3 4 5 6 7 8 9 10 11 12 13 14
import chisel3.util._ classAluextendsModule{ val io = IO(newBundle{ val a = Input(UInt(16.W)) val b = Input(UInt(16.W)) val fn = Input(UInt(2.W)) val y = Output(UInt(16.W)) }) io.y := 0.U// 需要赋初值 switch(io.fn) { is(0.U) { io.y := io.a + io.b } // ................. } }
Chisel可以使用Scala的很多特性来编写TB,例如,可以使用软件来编写硬件的功能,并且在仿真时和真正的硬件行为进行比较。例如,在[Martin Schoeberl. Lipsi: Probably the smallest processor in the world. In Architecture of Computing Systems – ARCS 2018, pages 18–30. Springer International Publishing, 2018.]中,实现一个处理器并进行测试。
需要导入的包有:
1 2
import chisel3._ import chisel3.iotesters._
对电路进行测试,需要包含三个元素:
用于测试的单元
测试逻辑
测试对象,包含开始测试的main方法
DUT(被测对象)
1 2 3 4 5 6 7 8 9
classDeviceUnderTestextendsModule{ val io = IO(newBundle { val a = Input(UInt(2.W)) val b = Input(UInt(2.W)) val out = Output(UInt(2.W)) } ) io.out := io.a & io.b }
import org. scalatest ._ classExampleSpecextendsFlatSpecwithMatchers{ "Integers" should "add" in { val i = 2 val j = 3 i + j should be (5) } }
事实上,我们可以将Chisel的测试包裹到Scala中去。
1 2 3 4 5 6 7
classSimpleSpecextendsFlatSpecwithMatchers{ "Tester" should "pass" in { chisel3. iotesters .Driver (() => newDeviceUnderTest ()) { c => newTester(c) } should be (true) } }
这样做的好处是,可以使用
1
sbt "testOnly SimpleSpec"
来运行单个测试。
波形图
要生成波形图,应该在进行测试时添加一定的参数。
1 2 3 4 5 6 7 8
classWaveformSpecextendsFlatSpecwithMatchers{ "Waveform" should "pass" in { Driver.execute(Array("--generate -vcd-output", "on"), () => newDeviceUnderTest ()) { c => newWaveformTester (c) } should be (true) } }
生成的vcd波形图文件可以使用GTKWake或者Modelsim打开。
printf调试
在Chisel中写printf语句,在时钟的上升沿会触发printf语句。
1 2 3 4 5 6 7 8 9
classDeviceUnderTestPrintfextendsModule{ val io = IO(newBundle { val a = Input(UInt (2.W)) val b = Input(UInt (2.W)) val out = Output(UInt (2.W)) }) io.out := io.a & io.b printf("dut: %d %d %d\n", io.a, io.b, io.out) }