This page lists some tips for Chisel that I could glean here and there.
Bidirectional signal
Bidirectionnal signals are not possible inside an FPGA or an ASIC. But it can be usefull on the boundary to drive signal like tristate buffer.
To use Bidirectionnal signal use Analog() in conjonction with RawModule or BlackBox :
class TopDesign extends RawModule {
val tristatebuf = Analog(1.W)
...
}
Connexion is made with bulk connector ‘<>’ :
tristatebuf <> myblackbox.io.tristate
dontTouch : keep register names in verilog
Tip from stackoverflow.
Sometimes, we have to keep register in verilog emitted code. But Chisel obtimize it and it often disapear. To keep it, use dontTouch() :
val version = dontTouch(RegInit(1.U(8.W)))
Get following in verilog module:
reg [7:0] version; // @[wbgpio.scala 20:34]
...
if (reset) begin
version <= 8'h1;
end
DontCare output signals
All module output must be defined to avoid this kind of warning :
[error] (run-main-0) firrtl.passes.CheckInitialization$RefNotInitializedException: : [module ChisNesPad] Reference io is not fully initialized.
[error] : io.data.valid <= VOID
[error] firrtl.passes.CheckInitialization$RefNotInitializedException: : [module ChisNesPad] Reference io is not fully initialized.
[error] : io.data.valid <= VOID
[error] Nonzero exit code: 1
[error] (Compile / runMain) Nonzero exit code: 1
[error] Total time: 12 s, completed 10 déc. 2019 13:25:11
But at the begining of a design, we don’t know what to write. To avoid this error we can use DontCare
object :
io.data.valid := DontCare
Keep signal and variables names in Verilog
See the good response from Jack Koening on stackoverflow.
UInt() to Vec()
An UInt() can be converted to a Vec of Bool() with asBools:
val foo = Vec(5, Bool())
val bar = UInt(5.W)
foo := bar.asBools
Initialize Vec() of Reg()
Split an UInt() in a Vec() of «sub» UInt()
Question asked on stackoverflow.
If we have a 16 bits register declared like that.
val counterReg = RegInit(0.U(16.W))
And we want to do indexed dibit assignment on module output like that :
//..
val io = IO(new Bundle {
val dibit = Output(UInt(2.W))
})
//..
var indexReg = RegInit(0.U(4.W))
//..
io.dibit = vectorizedCounter(indexReg) //xxx doesn't work
We could do it like that:
io.dibit := (counterReg >> indexReg)(1, 0)
Initialize Vec() of Reg()
val initRegOfVec = RegInit(VecInit(Seq.fill(4)(0.U(32.W))))
Concatenate value in one UInt()
Of course we can use Cat(), but it take only 2 parameters. With ‘##’ we can chain more signals:
val a = Reg(UInt(1.W))
val b = Reg(UInt(1.W))
val c = Reg(UInt(1.W))
val y = Reg(UInt(3.W))
y := a ## b ## c
With a Vec() declared like it :
val outputReg = RegInit(0.U((dibitCount*2).W)
val valueVecReg = RegInit(VecInit(Seq.fill(dibitCount)(0.U(2.W))))
ouptutReg := valueVecReg.reduce(_ ## _)
Initialize Bundle
Question asked on stackoverflow. Same question on stackoverflow but with ‘1’ initialization.
If we have a Bundle declared like that :
class RValue (val cSize: Int = 16) extends Bundle {
val rvalue = Output(UInt(cSize.W))
val er = Output(UInt((cSize/2).W))
val part = Output(Bool()) /* set if value is partial */
}
And we want to make a register with initialized value we can use the new interface named BundleLiterals:
import chisel3.experimental.BundleLiterals._
...
val valueReg = RegInit((new RValue(cSize)).Lit(
_.rvalue -> 1.U,
_.er -> 2.U,
_.part -> true.B)
Or if we just want to initialize to all 0 values we can do that :
val valueReg = RegInit(0.U.asTypeOf(new RValue(cSize))
Test some chisel code in live
Question asked on stackoverflow.
It can be usefull to be able to test code in console before launching the big compilation. It’s possible in directory where your project build.sbt is :
$ cd myproject/
$ sbt
sbt:myproject> console
scala>
And once in the scala console chisel import can be done :
scala> import chisel3._
import chisel3._
scala> val plop = "b0010101010001".U(13.W)
plop: chisel3.UInt = UInt<13>(1361)
Type Ctrl+D to quit.
For more simplicity it’s also possible to use the Scaties website in live.
For more Chisel Cookbook
See :