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))
 }

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM