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属性

posted @ 2018-12-06 23:00  JamesDYX  阅读(1750)  评论(0编辑  收藏  举报