classParamAdder(n: Int) extendsModule{ val io = IO(newBundle{ val a = Input(UInt(n.W)) val b = Input(UInt(n.W)) val c = Output(UInt(n.W)) }) io.c := io.a + io.b } val add_8 = Module(newParamAdder(8))
classParameterizedWidthAdder(in0Width: Int, in1Width: Int, sumWidth: Int) extendsModule{ require(in0Width >= 0) require(in1Width >= 0) require(sumWidth >= 0) val io = IO(newBundle { val in0 = Input(UInt(in0Width.W)) val in1 = Input(UInt(in1Width.W)) val sum = Output(UInt(sumWidth.W)) }) // a +& b includes the carry, a + b does not io.sum := io.in0 +& io.in1 }
classSort4(ascending: Boolean) extendsModule{ val io = IO(newBundle { val in0 = Input(UInt(16.W)) val in1 = Input(UInt(16.W)) val in2 = Input(UInt(16.W)) val in3 = Input(UInt(16.W)) val out0 = Output(UInt(16.W)) val out1 = Output(UInt(16.W)) val out2 = Output(UInt(16.W)) val out3 = Output(UInt(16.W)) }) // this comparison funtion decides < or > based on the module's parameterization defcomp(l: UInt, r: UInt): Bool = { if (ascending) { l < r } else { l > r } }
val row10 = Wire(UInt(16.W)) val row11 = Wire(UInt(16.W)) val row12 = Wire(UInt(16.W)) val row13 = Wire(UInt(16.W))
when(comp(io.in0, io.in1)) { row10 := io.in0 // preserve first two elements row11 := io.in1 }.otherwise { row10 := io.in1 // swap first two elements row11 := io.in0 }
val tVal = Wire(newComplexIO) val fVal = Wire(newComplexIO) val resB = myMux(selB, tVal, fVal)
我们可以使用cloneType方法来获取某个数据的类型。
1 2 3 4 5 6 7 8
def myMux[ T <: Data](sel: Bool, tPath: T, fPath: T): T = { val ret = Wire(fPath.cloneType) // 获取数据类型 ret := fPath when(sel) { ret := tPath } ret // 返回一个“硬件” }
However, when we use a constructor parameter, this parameter becomes a public field of the class. When Chisel needs to clone the type of the Bundle, e.g., when it is used in a Vec, this public field is in the way.
为了避免上述情况,可以使用以下的方法定义:
1 2 3 4
classPort[ T <: Data ](dt: T) extendsBundle{ val address = UInt(8.W) val data = dt.cloneType }
此时,我们可以定义路由模块了:
1 2 3 4 5 6
classNocRouter2[ T <: Data ](dt: T, n: Int) extendsModule{ val io = IO(newBundle { val inPort = Input(Vec(n, dt)) val outPort = Output(Vec(n, dt)) }) }
实例化代码:
1
val router = Module(newNocRouter2(newPort(newPayload), 2))
可选的IO端口
常用于有时可以选择去除某些调试信号。
注意到如果val是None,那么就没有这个信号了。
1 2 3 4 5 6 7 8 9 10 11 12
classHalfFullAdder(val hasCarry: Boolean) extendsModule{ val io = IO(newBundle { val a = Input(UInt(1.W)) val b = Input(UInt(1.W)) val carryIn = if (hasCarry) Some(Input(UInt(1.W))) elseNone val s = Output(UInt(1.W)) val carryOut = Output(UInt(1.W)) }) val sum = io.a +& io.b +& io.carryIn.getOrElse(0.U) io.s := sum(0) io.carryOut := sum(1) }
import chisel3.iotesters.PeekPokeTester import org.scalatest._ classTickerTester[ T <: Ticker ]( dut: T, n: Int) extends PeekPokeTester(dut: T) { // -1 is the notion that we have not yet seen the first tick var count = -1 for (i <- 0 to n * 3) { if (count > 0) { expect(dut.io.tick , 0) } if (count == 0) { expect(dut.io.tick , 1) } val t = peek(dut.io.tick) // On a tick we reset the tester counter to N-1, // otherwise we decrement the tester counter if (t == 1) { count = n-1 } else { count -= 1 } step (1) } }
模式匹配机制
Scala的模式匹配机制在Chisel中非常常见,Scala提供了强大的模式匹配机制,包括:
类似于C语言的switch语句的匹配功能
对于不同值的任意组合进行匹配
对于变量的类型进行匹配,这一点非常好用,例如:
用于迭代的值来自于列表,而列表中对象的类型不尽相同
变量是某个超类的成员,但并不知道其子类是什么
通过正则表达式匹配字符串的子串
值匹配
1 2 3 4 5 6 7 8 9 10 11 12 13
// y is an integer variable defined somewhere else in the code val y = 7 /// ... val x = y match { case0 => "zero"// 可以写在同一行里 case1 => // 可以不写在同一行里 "one"// 在下一个case之前都是这个case的代码 case2 => { // 可以添加大括号,但通常不是必要的 "two" } case _ => "many"// _可以匹配所有的值 } println("y is " + x)
模式匹配是按照从上到下的顺序的,一旦发生成功匹配,就不会进行接下来的搜索
通配符_的作用是匹配其他值,用于处理没有匹配上的情况
多值匹配
1 2 3 4 5 6 7 8 9
defanimalType(biggerThanBreadBox: Boolean, meanAsCanBe: Boolean): String = { (biggerThanBreadBox, meanAsCanBe) match { case (true, true) => "wolverine" case (true, false) => "elephant" case (false, true) => "shrew" case (false, false) => "puppy" } } println(animalType(true, true))
多值匹配的语法如上所示。
类型匹配
1 2 3 4 5 6 7 8 9
val sequence = Seq("a", 1, 0.0) sequence.foreach { x => x match { case s: String => println(s"$x is a String") case s: Int => println(s"$x is an Int") case s: Double => println(s"$x is a Double") case _ => println(s"$x is an unknown type!") } }
Scala是强类型语言,类型匹配是一种强大的机制。
如果想匹配多种类型,可以这样写,注意此时需要使用通配符_。
1 2 3 4 5 6 7
val sequence = Seq("a", 1, 0.0) sequence.foreach { x => x match { case _: Int | _: Double => println(s"$x is a number!") case _ => println(s"$x is an unknown type!") } }
使用实例
1 2 3 4 5 6 7 8 9 10 11 12
classDelayBy1(resetValue: Option[UInt] = None) extendsModule{ val io = IO(newBundle { val in = Input( UInt(16.W)) val out = Output(UInt(16.W)) }) val reg = resetValue match { caseSome(r) => RegInit(r) caseNone => Reg(UInt()) } reg := io.in io.out := reg }
// Mealy machine has caseclassBinaryMealyParams( // number of states nStates: Int, // initial state s0: Int, // function describing state transition stateTransition: (Int, Boolean) =>Int, //functiondescribingoutput output: (Int, Boolean) => Int ) { require(nStates >= 0) require(s0 < nStates && s0 >= 0) }
classBinaryMealy(val mp: BinaryMealyParams) extendsModule{ val io = IO(newBundle { val in = Input(Bool()) val out = Output(UInt()) })
val state = RegInit(UInt(), mp.s0.U)
// output zero if no states io.out := 0.U for (i <- 0 until mp.nStates) { when (state === i.U) { when (io.in) { state := mp.stateTransition(i, true).U io.out := mp.output(i, true).U }.otherwise { state := mp.stateTransition(i, false).U io.out := mp.output(i, false).U } } } }