Chisel 學習筆記(七)
集合
在Chisel中,我們既可以使用Scala中自帶的集合,包括List,Seq,ArrayBuffer——List的使用方式在學習筆記(一)中有所體現;Seq與List類似,但是在Chisel中,我們更常使用Seq來表述某個模塊的參數;ArrayBuffer的特性是不用描述出長度,且通過+就可以簡單的添加元素(-可以刪除元素),較為方便——也可以使用Chisel中所有的特殊集合Vec,Vec與其他Scala中的集合功能類似,但是可以更貼合Chisel。
List,Seq,ArrayBuffer
正如上文所說
- List是最原初的列表類,當然也有各種操作,不過較為繁瑣
- Seq經常作為Chisel中構造函數的參數
- 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的操作,主要是以下兩種情況:
- 在Bundle中,特別是IO Bundle中,scala中的集合不再起作用
- 在某些需要用到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))
}
}