IC的帆哥 - fft https://icfgblog.com/index.php/tag/fft/ chisel中级技巧 https://icfgblog.com/index.php/Digital/282.html 2021-10-22T09:59:00+08:00 过了一遍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测试代码中还有一些高效操作,还没有完全掌握,得慢慢消化。