Chisel 学习笔记(七)

Chisel 学习笔记(七)

集合

在Chisel中,我们既可以使用Scala中自带的集合,包括List,Seq,ArrayBuffer——List的使用方式在学习笔记(一)中有所体现;Seq与List类似,但是在Chisel中,我们更常使用Seq来表述某个模块的参数;ArrayBuffer的特性是不用描述出长度,且通过+就可以简单的添加元素(-可以删除元素),较为方便——也可以使用Chisel中所有的特殊集合Vec,Vec与其他Scala中的集合功能类似,但是可以更贴合Chisel。

List,Seq,ArrayBuffer

正如上文所说

  1. List是最原初的列表类,当然也有各种操作,不过较为繁琐
  2. Seq经常作为Chisel中构造函数的参数
  3. ArrayBuffer有着更简便的对集合的操作

List&Seq

class ScalaFirFilter(taps: Seq[Int]) {
  var pseudoRegisters = List.fill(taps.length)(0)		//构造一个taps.length长度的数组,将初始设为0

  def poke(value: Int): Int = {
    pseudoRegisters = value :: pseudoRegisters.take(taps.length - 1)	//取出pseudoRegister中前taps.length-1个元素,并在列表头插入value的值
    var accumulator = 0
    for(i <- taps.indices) {
      accumulator += taps(i) * pseudoRegisters(i)	//对Seq和List中元素的访问方式一样
    }
    accumulator
  }
}

Seq&ArrayBuffer

在Chisel中,更常用的是通过Seq传参

class MyManyElementFir(consts: Seq[Int], bitWidth: Int) extends Module {	//参数为一个不定长的Seq集合
  val io = IO(new Bundle {
    val in = Input(UInt(bitWidth.W))
    val out = Output(UInt(bitWidth.W))
  })

  val regs = mutable.ArrayBuffer[UInt]()	//ArrayBuffer的使用,先初始化成空
  for(i <- 0 until consts.length) {
      if(i == 0) regs += io.in							//通过加法可以很方便地添加元素到ArrayBuffer末尾
      else       regs += RegNext(regs(i - 1), 0.U)
  }
  
  val muls = mutable.ArrayBuffer[UInt]()
  for(i <- 0 until consts.length) {
      muls += regs(i) * consts(i).U
  }

  val scan = mutable.ArrayBuffer[UInt]()
  for(i <- 0 until consts.length) {
      if(i == 0) scan += muls(i)
      else scan += muls(i) + scan(i - 1)		//对元素的访问与Seq,List一样
  }

  io.out := scan.last
}

Chisel的特性——Vec

Vec也是集合,且是为Chisel专门打造的。在某些情况下,scala中的集合并不支持Chisel的操作,主要是以下两种情况:

  1. 在Bundle中,特别是IO Bundle中,scala中的集合不再起作用
  2. 在某些需要用到Chisel特性进行访问或更改的操作中,例如处理器的寄存器堆设计,scala中的集合不再起作用

Vec的使用如下

class MyManyDynamicElementVecFir(length: Int) extends Module {
 val io = IO(new Bundle {
   val in = Input(UInt(8.W))
   val out = Output(UInt(8.W))
   val consts = Input(Vec(length, UInt(8.W)))
 })

 val regs = RegInit(Vec.fill(length - 1)(0.U(8.W)))	//对Vec的初始化和List操作类似,说明长度和初始值
//val regs = RegInit(VecInit(Seq.fill(length - 1)(0.U(8.W))))    最新一版中的Vec初始化要这样写
 for(i <- 0 until length - 1) {
     if(i == 0) regs(i) := io.in									//对Vec中元素的访问也和List一样
     else       regs(i) := regs(i - 1)
 }
 
 val muls = Wire(Vec(length, UInt(8.W)))		//对一组导线的定义
 for(i <- 0 until length) {
     if(i == 0) muls(i) := io.in * io.consts(i)
     else       muls(i) := regs(i - 1) * io.consts(i)
 }

 val scan = Wire(Vec(length, UInt(8.W)))
 for(i <- 0 until length) {
     if(i == 0) scan(i) := muls(i)
     else scan(i) := muls(i) + scan(i - 1)
 }

 io.out := scan(length - 1)
}

RISC-V中寄存器堆的实现

package Passthrough

import chisel3._

class RegisterFile (readPorts: Int) extends Module{
 val io = IO(new Bundle{
   val wen = Input(Bool())
   val waddr = Input(UInt(5.W))
   val wdata = Input(UInt(32.W))
   val raddr = Input(Vec(readPorts, UInt(5.W)))
   val rdata = Output(Vec(readPorts, UInt(32.W)))
 })

//  val regs = RegInit(Vec(32, UInt(32.W)).fromBits(0.U)) 另外一种初始化方法
 val regs = RegInit(VecInit(Seq.fill(32)(0.U(32.W))))

 when(io.wen & io.waddr=/=0.U){
   regs(io.waddr) := io.wdata
 }

 for(i<-0 until readPorts){
   io.rdata(i) := regs(io.raddr(i))
 }

}

猜你喜欢

转载自www.cnblogs.com/JamesDYX/p/10082385.html