Chisel Cheatsheet
Chisel Cheatsheet
Anonymous bundle Bundle with directions (default direction Operator Explanation Width
For Operators: c, p , x, y are Chisel Data; n, m are Scala Ints w(x), val myB = new Bundle( is Output)
!x Logical NOT 1
Class MyBundle extends Bundle {
w(y) are the widths of x, y (respectively) val myBool = Bool()
val in = Input(Bool()) x && y Logical AND 1
val myInt = UInt(5.W)
minVal(x), maxVal(x) are the minimum or maximum possible ) val myInt = Output(UInt(5.W))
x || y Logical OR 1
values of x Bundle class }
Create IO from bundle x(n) Extract bit, 0 is LSB 1
class MyBundle extends Bundle {
val myBool = Bool() val x = IO(new MyBundle) x(hi, lo) Extract bitfield hi - lo +1
val myInt = UInt(5.W) Recursively flip input/output in io x << y Dynamic left shift w(x) + maxVal(y)
Chisel Keywords at a glance } val fx = IO(Flipped(new MyBundle)
Bool, UInt, SInt, ChiselEnum, Clock, Reset, AsyncReset, Bundle, Vec, Record val myB = new MyBundle x >> y Dynamic right shift w(x) - minVal(y)
Reg, Mem, Wire, IO Input, Output, Flipped Extending a Bundle Coerce direction to all the same direction x << n Static left shift w(x) + n
when, elsewhen, otherwise, switch, is Module, RawModule, ExtModule class MyExtendedBundle val fx = IO(Output(new MyBundle) x >> n Static right shift w(x) - n
extends MyBundle {
val newField = UInt(10.W) Fill(n, x) Replicate x, n times n * w(x)
} Access elements via dots
Use Scala val to create wires, instances, etc. val int1 = myB.myInt Cat(x, y) Concatenate bits w(x) + w(y)
val x = Wire(UInt()) myB.myBool := true.B Mux(c, x, y) If c, then x; else y max(w(x), w(y))
val y = x // drive wire y from wire x ~x Bitwise NOT w(x)
More constructors Explanation Vec Constructors: x & y Bitwise AND max(w(x), w(y))
Bool() Bool generator Vec(size: Int, typeGen: Data) // create a vec of typeGen x | y Bitwise OR max(w(x), w(y))
true.B or false.B Bool literals VecInit.fill(size: Int, hwGen: Data) // create Vec and initialize to hwGen
x ^ y Bitwise XOR max(w(x), w(y))
UInt() Unsigned integer VecInit.tabulate(size: Int) { i => hwGen: Data } // hwGen can use i for element creation
Note: Always create Reg(Vec*(...)), never Vec*(...Reg()) (reg of vec not vec of reg) x === y Equality(triple equals) 1
UInt(32.W) Unsigned integer 32 bit
Accessing Vec elements x =/= y Inequality 1
29.U(6.W) Unsigned literal 29 6 bits
"hdead".U Unsigned literal 0xDEAD 16 bits x := myVec(index: UInt) or myVec(index: Int) x + y Addition max(w(x),w(y))
BigInt("12346789ABCDEF", 16).U Make large UInt literal myVec(index: UInt) or myVec(index: Int) := y x +% y Addition max(w(x),w(y))
(Don’t use S cala Int to create large Example: vec init of a register file of 31 UInt registers of
literals)
x +& y Addition max(w(x),w(y))+1
32bits width
SInt() Signed integer val regfile = RegInit(VecInit(Seq.fill(31)(0.U(32.W)))) x - y Subtraction max(w(x),w(y))
SInt(64.W) Signed integer 64 bit x -% y Subtraction max(w(x),w(y))
-3.S Signed integer literal Special methods on Vec Explanation x -& y Subtraction max(w(x),w(y))+1
3.S(2.W) Signed 2-bit value (-1) .forall(p: T => Bool): Bool AND-reduce p on all elts
x * y Multiplication w(x)+w(y)
.exists(p: T => Bool): Bool Bool literals
Construct State elements, registers .contains(x: T): Bool True if this contains x x / y Division w(x)
Constructor Explanation .count(p: T => Bool): UInt count elts where p is True x % y Modulus bits(maxVal(y)-1)
Reg(UInt()) Creates a UInt register .indexWhere(p: T => Bool): UInt index where p is true.B x > y Greater than 1
RegInit(7.U(32.W)) 32-bit Reg with initial value of 7 .lastIndexWhere (p: T => Bool): UInt last index where p is true.B x >= y Greater than or equal 1
RegNext(nextValue) Reg updated on rising clock, no initial .onlyIndexWhere(p: T => Bool): UInt last index where p is true.B
value x < y Less than 1
RegNext(nextValue, 3.U(32.W)) Reg updated on rising clock Connections Explanation (c is consumer, p is producer) x <= y Less than or equal 1
but with initial value 3 c := p Basic connect, p drives c x >> y Arithmetic right shift w(x) - minVal(y)
RegEnable(nextVal, enable) Reg updated on rising clock c :#= p (coercing mono-direction): connects all members of p to c; regardless of x >> n Arithmetic right shift w(x) - n
with an enable gate alignment
x.andR AND-reduce 1
RegEnable(next, init, enable) Reg updated on rising clock c :<= p (aligned-direction): connects all aligned (non-flipped) c members from p
with an init and enable x.orR OR-reduce 1
c :>= p (flipped-direction): connects all flipped p members from c x.xorR XOR-reduce max(w(x), w(y))
ChiselEnum c :<>= p (bi-direction operator): connects all aligned c members from p; all flipped p
members from c
object Op extends ChiselEnum { when (foo === Op.load)
val load = Value(0x03.U) {...}
.squeeze allow truncation
val imm = Value(0x13.U) .elsewhen(foo===Op.imm) .waive allow missing connections
. . . {...}
val jal = Value(0x6f.U)
}
Chisel 3.6 Cheatsheet (v0) (page 2) Standard Library – Bit checks. Standard Library – Interfaces.
Operator Return Explanation
Chisel Code Generation PopCount(in:Bits) UInt number of hot (= 1) bits in in DecoupledIO(gen: Data): Wrap bundle with a ready valid interface
Functions provide block abstractions for code. Scala functions that PopCount(in:Seq[Bool]) UInt number of hot (= 1) bits in in Interface: .ready read only Bool,.valid Bool, .bits payload data
instantiate or return Chisel types are code generators. Reverse(in:UInt) UInt Reverses the bit order of in ValidIO(gen: Data) Wrap gen with a valid interface
Interface: .valid Bool, .bits
UIntToOH(in:UInt, [width:Int]) Bits the one-hot encoding of in width
Also: Scala’s if and for can be used to control hardware generation Queue(gen: Data, entries: Int, pipe: Boolean, flow: Boolean, useSyncReadMem:
(optional, else inferred) output
and are equivalent to Verilog’s if/for width Boolean, hasFlush: Boolean)
OHToUInt(in:Bits) UInt the UInt representation of Interface: io.enq: Flipped(ReadyValid[gen]), io.deq: ReadyValid[gen]
one-hot in Example:
val number = Reg(if(canBeNegative) SInt() else UInt ())
OHToUInt(in: Seq[Bool]) UInt the UInt representation of val q = (new Queue(UInt(), 16))
will create a Register of type SInt or UInt depending on the value of a Scala
one-hot in q.io.enq <> producer.io.out
variable.
PriorityEncoder(in:Bits) UInt the position the least significant 1 consumer. Module io.in <> q.io .deq
Use the ‘when’ construct instead of individual muxing Pipe(enqValid:Bool, enqBits:Data, [latency:Int]) or
when(condition1) { in in
x := y PriorityEncoder(in:Iterable[Bool]) UInt the position the least significant 1 Pipe(enq:ValidIO, [latency:Int]): Module delaying input
}.elseWhen (condition2) { in in Interface: io.in: Flipped(ReadyValid[gen]), io.out: ReadyValid[gen]
x := x & y PriorityEncoderOH(in:Bits) UInt the position of the hot bit in in Example:
z := y val foo = Module(new Pipe(UInt(8.W)), 4)
}.otherwise { Mux1H(sel: Seq[Bool], in: Seq[Data]) Data One hot mux
pipe.io.enq := producer.io
x := z Mux1H(sel: UInt, Seq[Data]) Data One hot mux consumer.io := pipe.io.deq
}
Mux1H(sel:UInt, in: UInt) Data One hot mux Arbiter(gen: Data, n: Int): Connect multiple producers to one consumer
Use when construct instead of individual muxing
class Delay(n: Int, payloadType: Data) extends Module {
PriorityMux(in:Iterable[(Bool,Bits]) Bits Priority Mux Interface: io.in Vec of inputs (Flipped(ReadyValid[gen]), io.out: ReadyValid[gen])
val in = IO(Input(payloadType)) PriorityMux(sel:Bits/Iterable[Bool], Bits A mux tree with either a one-hot Variants: RRArbiter (round robin) LockingArbiter
val out = IO(Output(payloadType)) in:Iterable[Bits]) select or multiple selects (where Example:
out := (0 until n).foldLeft(in) { val arb = Module(new Arbiter(UInt(), 2))
case (last, x) => RegNext(last) }
the first inputs are prioritized)
arb.io.in(0) <> producer0.io.out
}
Standard Library – Stateful. arb.io.in(1) <> producer1.io.out
Parameterize Modules consumer.io.in <> arb.io.out
Insert n registers between input and output of type payload, using Counter(n:Int): Counter (simple)
scala collection methods Example:
class Delay(n: Int, payloadType: Data) extends Module { val c = new Counter(n)
val in = IO(Input(payloadType))
val wrap = WireInit(false.B)
val out = IO(Output(payloadType))
when(cond) { wrap := c.inc() } // .inc returns true when wrap occurs
Definition & Instance
out := (0 until n).foldLeft(in) {
case (last, x) => RegNext(last) } Counter(cond: UInt, n:Int): (UInt, Bool) @instantiable
} Example: class Child extends Module {
val countOn = true.B // increment counter every clock cycle @public val in = IO(Input(Bool())
Instantiate and connect to SubModules val (counterValue, counterWrap) = Counter(countOn, 4) @public val out = IO(Output(Bool())
class Parent(n: Int, payloadType: Data) extends Module { when (counterValue === 3.U) { out := in
val in = IO(Input(payloadType)) }
...
val out = IO(Output(payloadType))
val child = Module(new Delay(n, payloadType)) } class Parent(n: Int, payloadType: Data) extends Module {
child.in := in Counter(r: Range, enable: Bool, reset: Bool) (UInt, Bool) val childDef = Definition(new Delay(n, payloadType))
out := child.out Example: val in = IO(Input(payloadType))
} val (counterValue, counterWrap) = Counter(0 until 10 by 2) val out = IO(Output(payloadType))
val child = Instance(childDef)
when (counterValue === 4.U) {
child.in := in
... out := child.out
Casting } }
.asTypeOf is hardware cast (works for HW data or Chisel Types)
LFSR(width: Int, increment: Bool, seed: Option[BigInt]): UInt
0.U.asTypeOf(new MyBundle()) Example:
val pseudoRandomNumber = LFSR(16)
chiselTypeOf(...) copy type of HW along with parameters and directions ShiftRegister(in: Data, n: Int[, en: Bool]): Data add n registers
val foo = IO(chiselTypeOf(bar))
Example:
val regDelayTwo = ShiftRegister(nextVal, 2, ena)