Chisel 学习笔记(六)
Chisel 学习笔记(六)
参数
样例1
classclass ParameterizedWidthAdderParamet (in0Width: Int, in1Width: Int, sumWidth: Int) extends Module {
require(in0Width >= 0)
require(in1Width >= 0)
require(sumWidth >= 0)
val io = IO(new Bundle {
val in0 = Input(UInt(in0Width.W))
val in1 = Input(UInt(in1Width.W))
val sum = Output(UInt(sumWidth.W))
})
// a +& b 包括进位, a + b 则不包括
io.sum := io.in0 +& io.in1
}
上述样例中的require关键字表示对参数做了一些限制,这种操作在我们只想实例化某些特定情况的参数、者要保证参数互斥或有意义时使用
可选或默认的参数
可选的参数可以通过Option关键字实现,观察如下代码
class DelayBy1(resetValue: Option[UInt] = None) extends Module {
val io = IO(new Bundle {
val in = Input( UInt(16.W))
val out = Output(UInt(16.W))
})
val reg = if (resetValue.isDefined) { // resetValue = Some(number)
RegInit(resetValue.get)
} else { //resetValue = None
Reg(UInt())
}
reg := io.in
io.out := reg
}
利用Option类,实现可选的Chisel类生成,即当有初始设定值时,resetValue.isDefined为真
这样做可以使得代码更美观
match/case语句
Scala中提供了类似于C语言的case语句,且提供了更加便捷的功能,包括异种类型变量的匹配,基本语法如下
下方代码将匹配到的值返回给x
val y = 7
/// ...
val x = y match {
case 0 => "zero" // One common syntax, preferred if fits in one line
case 1 => // Another common syntax, preferred if does not fit in one line.
"one" // Note the code block continues until the next case
case 2 => { // Another syntax, but curly braces are not required
"two"
}
case _ => "many" // _ is a wildcard that matches all values
}
需要注意的是,case a =>后为匹配到则执行的语句,且不会像c那样一直执行到底,执行完一个case就结束match。
其次,match是顺序匹配的,从上向下一次匹配。
case _ 代表其他情况。
并且多个变量可以同时匹配,如下
defdef animalTypeanimalT (biggerThanBreadBox: Boolean, meanAsCanBe: Boolean): String = {
(biggerThanBreadBox, meanAsCanBe) match {
case (true, true) => "wolverine"
case (true, false) => "elephant"
case (false, true) => "shrew"
case (false, false) => "puppy"
}
}
Scala中的match也提供对类型的匹配
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!")
}
}
如果想一次匹配多个类型,则需要这样写
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!")
}
}
但是对类型的匹配只能精确到最顶层,对下层类型的匹配是不允许的,比如下方代码就是不符合规则的
val sequence = Seq(Seq("a"), Seq(1), Seq(0.0))
sequence.foreach { x =>
x match {
case s: Seq[String] => println(s"$x is a String")
case s: Seq[Int] => println(s"$x is an Int")
case s: Seq[Double] => println(s"$x is a Double")
}
}
实例
对“可选或默认的参数”中的例子,也可以这样写
class DelayBy1(resetValue: Option[UInt] = None) extends Module {
val io = IO(new Bundle {
val in = Input( UInt(16.W))
val out = Output(UInt(16.W))
})
val reg = resetValue match {
case Some(r) => RegInit(r)
case None => Reg(UInt())
}
reg := io.in
io.out := reg
}
可选的IO
参数可选的情况我们在上方讨论过,下面看一下IO模块可选时的情况(使用Some关键字)
以是否包含低位进位的全加器来说,有如下两种实现方式
class HalfFullAdder(val hasCarry: Boolean) extends Module {
val io = IO(new Bundle {
val a = Input(UInt(1.W))
val b = Input(UInt(1.W))
val carryIn = if (hasCarry) Some(Input(UInt(1.W))) else None
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)
}
classclass HalfFullAdderHalfFul (val hasCarry: Boolean) extends Module {
val io = IO(new Bundle {
val a = Input(UInt(1.W))
val b = Input(UInt(1.W))
val carryIn = Input(if (hasCarry) UInt(1.W) else UInt(0.W))
val s = Output(UInt(1.W))
val carryOut = Output(UInt(1.W))
})
val sum = io.a +& io.b +& io.carryIn
io.s := sum(0)
io.carryOut := sum(1)
}
第二种实现方式避免了使用getOrElse,对于Chisel,0宽度的数字是允许的,生成verilog时会被直接剪枝,任何使用0位宽的变量会被当作0
隐式声明
隐式的声明可以帮助代码在不同情况下省去冗余的部分,使用implicit关键字即可做到,观察如下代码
object CatDog {
implicit val numberOfCats: Int = 3
def tooManyCats(nDogs: Int)(implicit nCats: Int): Boolean = nCats > nDogs
val imp = tooManyCats(2) //隐式传参,结果为真
val exp = tooManyCats(2)(1) // 显示传参,结果为假
}
这段代码在第一行隐式地说明了猫的数量,需要注意的是,在一段代码块中,对于一种类型只能有一条隐式说明
在随后定义的函数中,有两个参数列表,分别是参数列表和隐式参数列表,隐式参数列表在未显示说明时,会找到该代码段的隐式说明语句,即numberOfCats。
因此,imp的值是真,exp的值是假。
对于这段代码,必须有一个隐式说明的整型值,否则函数定义会因找不到隐式的值而出错
隐式转换
利用定义“隐式”,我们可以将两个不相关的量做隐式转换,而不要求父子类关系,如下代码所示
class Animal(val name: String, val species: String)
class Human(val name: String)
implicit def human2animal(h: Human): Animal = new Animal(h.name, "Homo sapiens")
val me = new Human("Adam")
println(me.species)
通过隐式转换,使Human类有了species属性