zoukankan      html  css  js  c++  java
  • 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属性

  • 相关阅读:
    插入数据Oracle异常ORA-01502: 索引或这类索引的分区处于不可用状态
    关于分布式系统的数据一致性问题
    C#网络编程系列文章之Socket实现异步TCP服务器
    大型网站架构与分布式架构
    序列化表单为json
    学习wcf
    C# 知识梳理
    Java前端控制器模式
    Java策略模式
    Java责任链模式
  • 原文地址:https://www.cnblogs.com/JamesDYX/p/10080227.html
Copyright © 2011-2022 走看看