Chisel Basics
Chisel Basics
John Wawrzynek
with
Chris Yarp (GSI)
– Notes:
‣ The associated logic circuits are not “executed”. They are active always (like
continuous assignment in Verilog).
‣ The “variables”, a and b, are “named wires”, and were given names here
because they are inputs to the circuit. Other wires don’t need names.
‣ Here we assumed that the inputs, and therefore all generated wires, are one
bit wide, but the same expression would work for wider wires. The logic
operators used here are “bitwise”. There are corresponding operations for
booleans.
– The keyword val comes from Scala. It is a way to declare a program variable
that can only be assigned once - a constant.
– This way out can be generated at one place in the circuit and then “fanned-
out” to other places where out appears.
// fan-out
val z =(a & out) | (out & b)
– Here the function inputs and output are assigned the type Bits. More on types
soon.
– Now, wherever we use the XOR function, we get a copy of the associated logic.
Think of the function as a “constructor”.
// Constructing multiple copies
val z =(x & XOR(x,y)) | (XOR(x,y) & y)
the type of out was inferred from the types of a and b and the operators.
– If you want to make sure, or if there is not enough information around for the
inference engine, you can always specify the type explicitly:
– By default Chisel will size your literal to the minimum necessary width.
– Alternatively, you can specify a width value as a second argument:
Bits("ha", 8) // hexadecimal 8-bit literal of type Bits, 0-extended
SInt(-5, 32) // 32-bit decimal literal of type Fix, sign-extended
SInt(-5, width = 32) // handy if lots of parameters
– Error reported if specified width value is less than needed.
Lecture 02, HDLs/Chisel 12 CS250, UC Berkeley Sp16
Builtin Operators
– Chisel defines a set of hardware operators for the builtin types.
z = x + y wz = max(wx, wy)
z = x - y wz = max(wx, wy)
z = x <bitwise-op> y wz = max(wx, wy)
z = Mux(c, x, y) wz = max(wx, wy)
z = w * y wz = wx + wy
z = x << n wz = wx + maxNum(n)
z = x >> n wz = wx - minNum(n)
z = Cat(x, y) wz = wx + wy
z = Fill(n, x) wz = wx * maxNum(n)
io.out := m3.io.out
}
object Mux2 {
– object Mux2 creates a
def apply (select: Bits, in0: Bits, in1: Bits) = {
val m = new Mux2() Scala singleton object on
m.io.in0 := in0 the Mux2 component
m.io.in1 := in1 class.
m.io.select := select
m.io.out // return the output – apply defines a method
} for creation of a Mux2
}
instance
class Mux4 extends Component {
val io = new Bundle {
val in0 = Bits(width=1, dir=INPUT)
val in1 = Bits(width=1, dir=INPUT)
val in2 = Bits(width=1, dir=INPUT)
val in3 = Bits(width=1, dir=INPUT)
val select = Bits(width=2, dir=INPUT)
val out = Bits(1, OUTPUT)
};
io.out := Mux2(io.select(1),
Mux2(io.select(0), io.in0, io.in1),
Mux2(io.select(0), io.in2, io.in3))
}
– This circuit has an output that is a copy of the input signal delayed by one clock
cycle.
– Note, we do not have to specify the type of Reg as it will be automatically
inferred from its input when instantiated in this way.
– In Chisel, clock and reset are global signals that are implicitly included where
needed
– Example use. Rising-edge detector that takes a boolean signal in and outputs
true when the current value is true and the previous value is false:
– When a value is assigned in multiple when blocks, the last when block that is true
takes precedence
r := SInt(3); s := SInt(3) – Leads to: c1 c2 r s
when (c1) { r := SInt(1); s := SInt(1) } 0 0 3 3
when (c2) { r := SInt(2) } 0 1 2 3
1 0 1 1
– See tutorial for more examples, and variations on this them.
1 1 2 1
/ Bulk connections
class Block extends Module {
val io = new FilterIO() Block
x y
val f1 = new Filter() x f1 y x f2 y
val f2 = new Filter()
– “<>” bulk connects bundles of opposite gender, connecting leaf ports of the same
name to each other.
– “<>” also promotes child component interfaces to parent component interfaces.
Memory Blocks
Polymorphism and Parameterization
Higher-order Functions