chisel中级技巧
过了一遍chisel book和chisel tutorial的内容,学了chisel基本搭电路的语法,能把verilog的代码翻译成chisel,但在翻译的过程中发现仅有这些基本技能还不够,完全没有发挥出scala这种高级语言的优势,知乎看到一篇用Chisel快速搭建FFT流水线电路,发现好多方便的操作,总结下来有以下几点:
- local parameter
- 同类线网Bundle
- 实例化模块
一、局部变量local parameter
verilog 经常会有局部变量,有些定义位宽,有些定义循环次数,chisel里也能用val 定义变量,但总感觉“不干净”,而且不好复用,有什么办法呢?scala的trait很好用!
可以在Config.scala里定义参数:
package FFT
trait HasDataConfig {
val DataWidth = 32
val BinaryPoint = 16
}
trait HasElaborateConfig {
val FFTLength = 512
val useGauss = false
val supportIFFT = false
}
然后定义时,在需要这些局部变量的模块加上with就可以访问,非常方便:
//用with增加局部变量
class MyComplex extends Bundle with HasDataConfig {
val re = FixedPoint(DataWidth.W, BinaryPoint.BP)
val im = FixedPoint(DataWidth.W, BinaryPoint.BP)
}
二、Bundle线网
实际电路的输入输出其实会分数据线和控制线,还有一些信号属于同类型的,但verilog只能一视同仁,只能在命名上加以区分,但chisel里的Bundle类可以把相同的信号“绑”在一起,既便于阅读,也便于调用。
先定义一个复数的Bundle,然后在Switch模块里就可以直接调用MyComplex,而无需再定义实部虚部,更加简洁。
//Bundle“绑定”相同类型的信号
class MyComplex extends Bundle with HasDataConfig {
val re = FixedPoint(DataWidth.W, BinaryPoint.BP)
val im = FixedPoint(DataWidth.W, BinaryPoint.BP)
}
class Switch extends Module {
val io = IO(new Bundle{
val in1 = Input(new MyComplex)
val in2 = Input(new MyComplex)
val sel = Input(Bool())
val out1 = Output(new MyComplex)
val out2 = Output(new MyComplex)
})
io.out1 := Mux(io.sel, io.in2, io.in1)
io.out2 := Mux(io.sel, io.in1, io.in2)
}
三、伴生对象之工厂方法
别被这个名词唬了,verilog调用子模块时,都需要再连线,很繁琐,代码又长又臭。chisel伴生对象的工厂方法可以很好解决这个问题。
class Switch extends Module {
val io = IO(new Bundle{
val in1 = Input(new MyComplex)
val in2 = Input(new MyComplex)
val sel = Input(Bool())
val out1 = Output(new MyComplex)
val out2 = Output(new MyComplex)
})
io.out1 := Mux(io.sel, io.in2, io.in1)
io.out2 := Mux(io.sel, io.in1, io.in2)
}
//定义伴生对象,apply方法
object Switch {
def apply(in1: MyComplex, in2: MyComplex, sel: Bool): (MyComplex, MyComplex) = {
val inst = Module(new Switch)
inst.io.in1 := in1
inst.io.in2 := in2
inst.io.sel := sel
(inst.io.out1, inst.io.out2)
}
}
这样就可以很方便例化模型,不需要再连线,元素访问也很简单:
//不需要再连线
val sw12 = Switch(in1,in2,swCtrl)
//元素访问
val out1 = sw12._1
val out2 = sw12._2
除此之外,用map生成正弦余弦rom,scala测试代码中还有一些高效操作,还没有完全掌握,得慢慢消化。