1. Bool is one bit; UInt is a row of bits
Every port and wire in Chisel carries a value of a Chisel type. The two types this chapter needs are
Bool(), a single bit whose literals are true.B and false.B, and UInt(n.W), an unsigned number
n bits wide whose literals are written 5.U or "hc5".U. A Bool is also a 1-bit UInt, so it can
drive a UInt sink. Both types describe hardware signals whose values are modeled during simulation; the
Scala Boolean and Int that steer elaboration are different things, as
the first chapter
showed.
| Type | Width | Literals | Typical use |
|---|---|---|---|
Bool() | 1 | true.B, false.B | a condition, a flag, a single wire |
UInt(8.W) | 8 | 197.U, "hc5".U, "b1100_0101".U | data, counts, addresses |
Widths, the signed type SInt, and the width every literal gets are the subject of
Widths, SInt, and arithmetic. This chapter needs
only the fact that an 8-bit UInt is eight wires, numbered 7 down to 0.
2. Expressions build circuits
A combinational circuit computes its outputs from its current inputs alone, with no memory of earlier
cycles. In Chisel you describe it with expressions and connections, and elaboration turns each
operator into a node of the circuit graph. (a & b) | (~c & d) is a tree: input wires at the leaves,
operators inside, and the final | at the root. During elaboration, each operator call adds one node
to the circuit graph and returns that node's output.
val t = io.a & io.b // one AND node
io.x := t | io.c // t feeds an OR node
io.y := t ^ io.d // t also feeds an XOR node| Code | What it builds |
|---|---|
io.a & io.b | One AND node |
val t = ... | No hardware; a Scala name for the AND node's output |
t | io.c and t ^ io.d | Two more nodes that share t as an input |
A val lets one node feed several later expressions. That sharing, called fan-out, turns a tree into
a general directed acyclic graph. During simulation the whole graph is recomputed whenever an input
changes.
3. Operators
Every operator below is a piece of hardware with a fixed result width. The width comes from the operand widths alone, during elaboration: not from the values, and not from the port the result is later connected to. Each subsection gives the hardware, the width, and what to write when the obvious spelling does something else. Section 3.5 runs most of them at once.
3.1 Bitwise and logical operators
A bitwise operator builds one gate per bit position: x & y on two 8-bit values is eight AND gates
side by side, and bit 3 of the result depends only on bit 3 of each operand. A logical operator treats
each operand as one truth value.
Syntax
~x x & y x | y x ^ y // bitwise
!b b && c b || c // logicalval enable = io.valid && !io.stall // Bool
val masked = io.data & "h0f".U // keeps the low 4 bits of an 8-bit value
val flipped = ~io.data // inverts all 8 bits| Operator | Hardware | Operands | Result width |
|---|---|---|---|
~x | One inverter per bit | UInt, SInt, Bool | w(x); on a Bool, a Bool |
x & y, x | y, x ^ y | One gate per bit position | Two UInt, two SInt, or Bool | max(w(x), w(y)) |
b && c, b || c | One AND or OR gate | Bool only | 1 |
!x | An inverter on a Bool; on a UInt, a test for zero | Bool, UInt | 1 |
Operands of different widths. Before a bitwise operator combines two operands, the narrower one is
widened to the width of the wider one. A UInt gets zeros on top, so in io.data & "h0f".U the
4-bit literal 1111 becomes 0000_1111 and clears the high nibble of data. An SInt gets
copies of its sign bit: OR-ing a 4-bit -1 (1111) into an 8-bit 0 gives 1111_1111, not
0000_1111.
! and && on a UInt. && and || exist only on Bool. With two UInt operands the
Scala compiler stops with value && is not a member of chisel3.UInt. ! is looser: on a UInt it
compiles and means "is zero", true only when every bit is 0. Say which test you mean instead:
val isZero = io.count === 0.U // what !io.count computes
val nonZero = io.count =/= 0.U // the same as io.count.orR: some bit is 1On a Bool, ~b and !b build the same inverter and both return a Bool. Use ! in conditions
so they read as logic.
3.2 Arithmetic
Arithmetic operators build adders, subtractors, multipliers, and dividers.
Syntax
x + y x - y x +% y x -% y // wrapping: max(w(x), w(y)) bits
x +& y x -& y // expanding: one bit more
x * y x / y x % y| Operator | Hardware | Result width | What happens to a result that does not fit |
|---|---|---|---|
x + y, x - y | Adder, subtractor | max(w(x), w(y)) | The carry or borrow out is dropped: the result wraps |
x +% y, x -% y | The same circuit | max(w(x), w(y)) | Wraps. The % spells out that wrapping is intended |
x +& y, x -& y | Adder or subtractor with its carry out | max(w(x), w(y)) + 1 | Kept in the extra bit |
x * y | Multiplier | w(x) + w(y) | Cannot happen: every product fits |
x / y | Divider | w(x) for UInt, w(x) + 1 for SInt | Cannot happen |
x % y | Divider, remainder output | min(w(x), w(y)) | Cannot happen |
Wrapping. 200.U(8.W) + 100.U(8.W) is 44. The true sum, 300, needs nine bits, and + keeps
eight. +& keeps the ninth and gives 300. A wider port on the left of := does not bring the carry
back, because the 8-bit sum already exists before the connection sees it.
Unsigned underflow. A UInt has no negative values, so 0.U(4.W) - 1.U is not -1: the
subtraction wraps to 1111, which is 15. -& gives five bits, 1_1111 = 31. The extra bit is a
borrow, not a sign; the result is still unsigned. A negative result needs SInt operands, the topic
of the next chapter.
Signed division is one bit wider because -128 / -1 is +128, which does not fit in eight signed
bits.
*, / and % are large circuits. Each is one character in the source, but a multiplier is an
array of partial-product adders, and a divider whose divisor is a signal is far larger and slower than
an adder. Use them where the design needs them, not as shorthand. For an unsigned x, a constant power-of-two divisor
needs no divider: x / 4.U has the same value as x >> 2, which is only wiring, so write the
shift. A divisor such as 3 has no shift equivalent.
The next chapter
collects these widths in one table and runs + against +& on its own.
3.3 Shifts
The type of the shift amount decides what hardware a shift becomes.
Syntax
x << 3 x >> 3 // Scala Int amount, fixed during elaboration
x << n x >> n // UInt amount, chosen during simulationExpression, x is 8 bits, n is UInt(3.W) | Hardware | Result width |
|---|---|---|
x << 3 | Wiring: every bit moves up 3 places, zeros fill the bottom | w(x) + 3 = 11 |
x >> 3 | Wiring: the low 3 bits are dropped | w(x) - 3 = 5 |
x << n | A shifter: one multiplexer per output bit | w(x) + 2^w(n) - 1 = 15 |
x >> n | A shifter | w(x) = 8 |
A shift never drops a high bit on its own: << widens its result instead. If you need the result in
the original width, select the bits you want, as in (x << 3)(7, 0). A shift right by a Scala Int
removes bits; in Chisel 6.7, shifting an 8-bit value right by 8 or more leaves a result 0 bits wide.
A shift by a UInt has to make room for the largest amount the signal can carry: 7 for a 3-bit n,
so 8 + 7 = 15 bits. A 4-bit n raises that to 8 + 15 = 23 bits. Keep a shift amount as narrow as its
largest real value.
>> on an SInt is an arithmetic shift: the vacated high bits are filled with copies of the
sign bit, so a negative value stays negative. The bits 1100_0101 are 197 as a UInt and -59 as an
SInt; shifted right by 2 they become 49 and -15. << fills with zeros on both types. In the
example below, x.asSInt reads the same 8 bits of a UInt as an SInt; casts are covered in
the next chapter.
x.rotateLeft(k) and x.rotateRight(k) rotate a UInt: the bits pushed out at one end come back
in at the other, and the width stays w(x).
3.4 Comparisons
A comparison builds a comparator and always produces a Bool, whatever the operand widths.
Syntax
x === y x =/= y x < y x <= y x > y x >= yval isZero = io.count === 0.U
val notThree = io.x =/= 3.U
val inRange = io.temp >= 20.U && io.temp < 30.UEquality is written === and inequality =/=, with three characters. Scala reserves == for
comparing Scala objects: io.x == io.y asks whether the two port objects are the same object during
elaboration, and returns a Scala Boolean that cannot drive hardware.
Signed and unsigned. The type decides how the bits are compared. 1111_1000 against
0000_1111 is 248 < 15, false, as two UInt, and -8 < 15, true, as two SInt. Chisel does not
compare a UInt with an SInt: io.u < io.s stops the Scala compiler with
type mismatch; found: chisel3.SInt, required: chisel3.UInt. Convert one side first, for example
io.u.zext < io.s, so the code says which reading you want.
3.5 Run it: shifts, arithmetic, and comparison
ShiftArith.scala computes the operators from 3.2 to 3.4 on two 8-bit inputs x and y and a
3-bit shift amount n. During elaboration it prints the width of each result on two WIDTH lines.
The testbench then pokes four input sets and prints one labelled SIMULATE line per operator group.
import chisel3._
class ShiftArith extends Module {
val io = IO(new Bundle {
val x = Input(UInt(8.W))
val y = Input(UInt(8.W))
val n = Input(UInt(3.W))
val shlConst = Output(UInt(11.W))
val shrConst = Output(UInt(5.W))
val shlDyn = Output(UInt(15.W))
val shrDyn = Output(UInt(8.W))
val sraConst = Output(SInt(6.W))
val sraDyn = Output(SInt(8.W))
val sum = Output(UInt(8.W))
val sumWide = Output(UInt(9.W))
val diff = Output(UInt(8.W))
val diffWide = Output(UInt(9.W))
val prod = Output(UInt(16.W))
val quot = Output(UInt(8.W))
val rem = Output(UInt(8.W))
val quarter = Output(UInt(8.W))
val ltU = Output(Bool())
val ltS = Output(Bool())
})
// A Scala Int shift amount is fixed during elaboration: only wiring.
val shlConst = io.x << 3
val shrConst = io.x >> 3
// A UInt shift amount builds a shifter; << leaves room for the largest amount.
val shlDyn = io.x << io.n
val shrDyn = io.x >> io.n
// >> on an SInt copies the sign bit into the vacated high bits.
val sraConst = io.x.asSInt >> 2
val sraDyn = io.x.asSInt >> io.n
// + and - wrap at the wider operand's width; +& and -& keep one more bit.
val sum = io.x + io.y
val sumWide = io.x +& io.y
val diff = io.x - io.y
val diffWide = io.x -& io.y
// * keeps every product bit; / and % build a divider.
val prod = io.x * io.y
val quot = io.x / io.y
val rem = io.x % io.y
val quarter = io.x / 4.U
// The same bits compare differently as UInt and as SInt.
val ltU = io.x < io.y
val ltS = io.x.asSInt < io.y.asSInt
println(s"WIDTH x<<3=${shlConst.getWidth} x>>3=${shrConst.getWidth} x<<n=${shlDyn.getWidth} " +
s"x>>n=${shrDyn.getWidth} s>>2=${sraConst.getWidth} s>>n=${sraDyn.getWidth}")
println(s"WIDTH x+y=${sum.getWidth} x+&y=${sumWide.getWidth} x-y=${diff.getWidth} x-&y=${diffWide.getWidth} " +
s"x*y=${prod.getWidth} x/y=${quot.getWidth} x%y=${rem.getWidth} x<y=${ltU.getWidth}")
io.shlConst := shlConst
io.shrConst := shrConst
io.shlDyn := shlDyn
io.shrDyn := shrDyn
io.sraConst := sraConst
io.sraDyn := sraDyn
io.sum := sum
io.sumWide := sumWide
io.diff := diff
io.diffWide := diffWide
io.prod := prod
io.quot := quot
io.rem := rem
io.quarter := quarter
io.ltU := ltU
io.ltS := ltS
}import chisel3._
import chiseltest._
import chiseltest.RawTester.test
object Main extends App {
test(new ShiftArith) { dut =>
def set(x: Int, y: Int, n: Int): Unit = {
dut.io.x.poke(x.U)
dut.io.y.poke(y.U)
dut.io.n.poke(n.U)
}
def v(p: Data) = p.peek().litValue
set(0xc5, 3, 2)
println(s"SIMULATE shift x=197 n=2 x<<3=${v(dut.io.shlConst)} x>>3=${v(dut.io.shrConst)} " +
s"x<<n=${v(dut.io.shlDyn)} x>>n=${v(dut.io.shrDyn)}")
println(s"SIMULATE sint x.asSInt=-59 n=2 s>>2=${v(dut.io.sraConst)} s>>n=${v(dut.io.sraDyn)}")
println(s"SIMULATE divide x=197 y=3 x/y=${v(dut.io.quot)} x%y=${v(dut.io.rem)} " +
s"x/4=${v(dut.io.quarter)} x>>n=${v(dut.io.shrDyn)}")
set(200, 100, 0)
println(s"SIMULATE add x=200 y=100 x+y=${v(dut.io.sum)} x+&y=${v(dut.io.sumWide)} x*y=${v(dut.io.prod)}")
set(0, 1, 0)
println(s"SIMULATE sub x=0 y=1 x-y=${v(dut.io.diff)} x-&y=${v(dut.io.diffWide)}")
set(0xf8, 0x0f, 0)
println(s"SIMULATE compare x=f8 y=0f x<y=${v(dut.io.ltU)} x.asSInt<y.asSInt=${v(dut.io.ltS)}")
}
}Check
The sub line pokes x = 0 and y = 1 into the 8-bit UInt inputs. What will x-y show?
What to look at in the output. Press Run and read the lines against this table.
| Line | Look at | What it shows |
|---|---|---|
First WIDTH | x<<3=11, x<<n=15, x>>n=8 | A constant << grows by the amount; a UInt amount grows by 2^w(n) - 1; >> by a UInt keeps w(x) |
Second WIDTH | x+y=8, x+&y=9, x*y=16, x<y=1 | Widths depend on operand widths only |
shift | x<<3=1576, x<<n=788 | The constant shift is fixed; the UInt amount, 2 here, is picked during simulation |
sint | s>>2=-15 beside x>>n=49 on the shift line | The same bits shifted right as SInt and as UInt: the sign bit is copied |
divide | x/y=65, x%y=2, x/4=49, x>>n=49 | 197 = 3 × 65 + 2; division by 4 equals a shift by 2 |
add | x+y=44, x+&y=300, x*y=20000 | + wrapped, +& kept the carry, * kept all 16 bits |
sub | x-y=255, x-&y=511 | UInt underflow wraps; the extra bit of -& is not a sign |
compare | x<y=0, x.asSInt<y.asSInt=1 | The same bits: 248 vs 15 unsigned, -8 vs 15 signed |
The WIDTH lines come first because elaboration finishes before the simulation starts.
Try it yourself. Change n to UInt(4.W) and run again. The first WIDTH line now reports
x<<n=23, because the largest amount is 15. The shlDyn port is still 15 bits wide, so the
connection silently drops the top 8 bits. The SIMULATE values do not change, because 788 fits in 15
bits; a larger n would lose bits without any warning.
3.6 Operator precedence
Chisel operators are Scala methods, so they follow Scala's precedence, not Verilog's. Scala ranks an operator by its first character. From tightest to loosest:
| First character | Chisel operators in this group |
|---|---|
Prefix ~, ! | ~x, !b bind tightest |
*, /, % | *, /, % |
+, - | +, -, +&, -&, +%, -% |
<, > | <<, >>, <, <=, >, >= |
= | ===, =/= |
& | &, && |
^ | ^ |
| | |, || |
| Assignment | := binds loosest, so the whole right-hand side is evaluated first |
Operators in the same group group from left to right. These cases need parentheses:
| You write | Scala reads | Write instead |
|---|---|---|
io.x & io.y === io.y | io.x & (io.y === io.y) | (io.x & io.y) === io.y |
a < b << 1 | (a < b) << 1: shift and compare share a group | a < (b << 1) |
x << n + 1, n a Scala Int | x << (n + 1) | (x << n) + 1.U |
a + b >> 1, an average | (a + b) >> 1, as intended, but + already dropped the carry | (a +& b) >> 1 |
Caution. Every wrong version above compiles and quietly computes something else. With
a = 200 and b = 100, a + b >> 1 gives 22 and (a +& b) >> 1 gives 150. a < b << 1
connected to a Bool keeps bit 0 of (a < b) << 1, which is always 0. Section 4 runs the first case.
3.7 Bit fields
A bit field selects some bits of a value. Bits are numbered from the least significant bit, starting at 0.
Syntax
x(i) // bit i, a Bool
x(hi, lo) // bits hi down to lo, width hi - lo + 1val data = io.data // 8 bits
data(0) // the LSB
data(7) // the MSB
data(7, 4) // the high nibble, 4 bitsThe high index comes first. With Scala Int indices, the selection is decided during elaboration and
costs no logic, only wiring.
3.8 Cat and Fill
Cat joins values into a wider one; Fill repeats a value. Both live in chisel3.util, so a file
that uses them imports that package.
Syntax
import chisel3.util._
Cat(a, b, ...) // a ends up in the most significant bits
Fill(n, x) // x repeated n timesCat("b11".U, "b0001".U(4.W)) // 11_0001, 6 bits
Fill(3, "b10".U) // 10_10_10, 6 bits| Expression | Result width |
|---|---|
Cat(a, b) | w(a) + w(b) |
Fill(n, x) | n * w(x) |
Cat follows the reading order of the source: the first argument becomes the leftmost, most
significant part, the way you read a binary number from left to right.
3.9 Reduction operators
A reduction folds every bit of a value into a single Bool.
Syntax
x.andR // true when all bits are 1
x.orR // true when any bit is 1
x.xorR // true when the number of 1s is oddval allOnes = io.data.andR
val nonZero = io.data.orR
val oddCount = io.data.xorR // the even-parity bit for io.data4. Example: the operator set
Ops.scala applies one operator per output to two 8-bit inputs, x and y. Read the three commented
groups: bit fields, Cat, and reductions. The testbench pokes three input pairs and prints every
output in hexadecimal, two hex digits for the 8-bit values.
import chisel3._
import chisel3.util.Cat
class Ops extends Module {
val io = IO(new Bundle {
val x = Input(UInt(8.W))
val y = Input(UInt(8.W))
val and = Output(UInt(8.W))
val or = Output(UInt(8.W))
val xor = Output(UInt(8.W))
val notX = Output(UInt(8.W))
val hiX = Output(UInt(4.W))
val msbX = Output(Bool())
val swap = Output(UInt(8.W))
val allX = Output(Bool())
val anyX = Output(Bool())
val parX = Output(Bool())
val same = Output(Bool())
})
io.and := io.x & io.y
io.or := io.x | io.y
io.xor := io.x ^ io.y
io.notX := ~io.x
// A bit field is written (high, low); bit 0 is the least significant.
io.hiX := io.x(7, 4)
io.msbX := io.x(7)
// Cat places its first argument in the most significant bits.
io.swap := Cat(io.x(3, 0), io.x(7, 4))
// Reductions fold every bit of x into one Bool.
io.allX := io.x.andR
io.anyX := io.x.orR
io.parX := io.x.xorR
// === builds a comparator; Scala == would compare Scala objects.
io.same := io.x === io.y
}import chisel3._
import chiseltest._
import chiseltest.RawTester.test
object Main extends App {
test(new Ops) { dut =>
for ((x, y) <- Seq((0xc5, 0x0f), (0xff, 0xff), (0x00, 0x80))) {
dut.io.x.poke(x.U)
dut.io.y.poke(y.U)
def v(p: Data) = p.peek().litValue
println(f"SIMULATE x=$x%02x y=$y%02x and=${v(dut.io.and)}%02x or=${v(dut.io.or)}%02x " +
f"xor=${v(dut.io.xor)}%02x not=${v(dut.io.notX)}%02x hi=${v(dut.io.hiX)}%x " +
f"msb=${v(dut.io.msbX)} swap=${v(dut.io.swap)}%02x all=${v(dut.io.allX)} " +
f"any=${v(dut.io.anyX)} par=${v(dut.io.parX)} same=${v(dut.io.same)}")
}
}
}Practice this concept
Use this concept in a short Chisel problem as your next step.
Predict before you run. Work out the first row by hand for x = 0xc5 and y = 0x0f. In binary,
x is 1100_0101 and y is 0000_1111. What are and, or, xor, and not? What does swap
become, given that Cat puts its first argument on top? x contains four 1s: what are all, any,
and par?
Check
What is x ^ y for x = 0xc5 and y = 0x0f, in hex?
Check
swap is Cat(io.x(3, 0), io.x(7, 4)). For x = 0xc5, what does it show?
Check
x = 0xc5 has four 1 bits. What is par, that is x.xorR?
Check the result. Press Run and compare the first output row with this table.
| Output | Computation | Value |
|---|---|---|
and | 1100_0101 & 0000_1111 | 05 |
or | 1100_0101 | 0000_1111 | cf |
xor | 1100_0101 ^ 0000_1111 | ca |
not | ~1100_0101 | 3a |
hi | x(7, 4) | c |
msb | x(7) | 1 |
swap | Cat(x(3, 0), x(7, 4)): 0101 then 1100 | 5c |
all, any, par | Four 1s: not all, at least one, an even count | 0, 1, 0 |
same | x === y | 0 |
The other two rows test the edges. With 0xff, andR is true and xor is zero. With 0x00, orR
is false and not is all ones. swap shows Cat order directly: the low nibble came first in the
argument list and now occupies the high nibble.
Try it yourself.
- Replace
===with==. The Scala compiler stops with a type mismatch that reportsfound: Booleanandrequired: chisel3.Data. Scala compared the two port objects, got a plainBoolean, and:=cannot connect that to hardware. - Change the last line to
io.same := io.x & io.y === io.y, meaning "every bit ofyis also set inx". The first row now reportssame=1, although0x05is not0x0f. Precedence made itio.x & (io.y === io.y): the comparison is always true, so the result isx & 1, and connecting that to aBoolkeeps bit 0 ofx, which is 1 for0xc5. Writing(io.x & io.y) === io.yrestores the expected 0.
5. Change the order of Cat
In the lab, change the swap line to Cat(io.x(7, 4), io.x(3, 0)) and run again.
Check
With Cat(io.x(7, 4), io.x(3, 0)), what does swap show for x = 0xc5?
Nothing checks the argument order of Cat; a reversed order shows up only as wrong values. Read Cat
the way you read a binary number: left to right, most significant first.
6. Apply it: a frame with a parity bit
The Practice problem below asks for an 8-bit frame from 7 data bits: data unchanged in bits 6 to
0 and an even-parity bit in bit 7, chosen so that the whole frame has an even number of ones. Two
operators from this chapter are enough: one reduction decides the parity bit, and Cat places it
above the data.
Check
For data = 0x55, which is 101_0101, what is the parity bit the frame needs?
7. Common mistakes
7.1 == instead of ===
// Wrong: compares Scala objects and returns a Scala Boolean
io.same := io.x == io.y
// Right: builds a comparator
io.same := io.x === io.yThe compiler reports type mismatch; found: Boolean, required: chisel3.Data.
7.2 Leaving out parentheses around a comparison
// Wrong: parsed as io.x & (io.y === io.y)
io.covers := io.x & io.y === io.y
// Right
io.covers := (io.x & io.y) === io.yScala's === binds tighter than &, ^, and |. The wrong version compiles and returns bit 0 of
x.
7.3 Reading Cat backwards
// Wrong if you wanted lo in the low bits: lo ends up on top
val word = Cat(lo, hi)
// Right: the first argument is the most significant part
val word = Cat(hi, lo)Cat reads like a binary number written left to right. Nothing checks the order, so the mistake
shows up only as wrong values.
8. Summary
| Topic | Key point |
|---|---|
Bool(), UInt(n.W) | One bit; n unsigned bits. A Bool is also a 1-bit UInt |
| Expressions | Each operator adds a node; a val names a node so several expressions can share it |
&, |, ^, ~ | Gates per bit position; the result is as wide as the wider operand |
&&, ||, ! | Gates on Bool; ! on a UInt tests for zero, so write === 0.U |
| Arithmetic | +, - wrap at max width; +&, -& keep one more bit; * is w(x) + w(y); /, % build a divider |
| Shifts | A Scala Int amount is wiring and << widens by it; a UInt amount builds a shifter; >> on SInt copies the sign |
| Comparisons | Return a Bool; === and =/=, since Scala == compares objects; UInt and SInt are not compared directly |
| Precedence | Scala rules by first character: === binds tighter than &, and << shares a group with <, so use parentheses |
| Bit fields | x(i), x(hi, lo); bit 0 is the LSB, high index first; wiring, not logic |
Cat, Fill | Cat puts its first argument on top; Fill(n, x) repeats x |
| Reductions | andR, orR, xorR fold all bits into one Bool: all, any, odd count |
9. Check your understanding
-
In
Cat(x(3, 0), x(7, 4)), which argument ends up in bits 7 to 4, and why?Show answer
x(3, 0), the first argument.Catplaces its first argument in the most significant bits. -
What is the width and value of
Fill(2, "b101".U)?Show answer
6 bits,
101101.Fillrepeats the 3-bit value twice. -
How does Scala parse
io.x & io.y === io.y, and what does the expression compute for an 8-bitx?Show answer
As
io.x & (io.y === io.y), because===binds tighter than&. The comparison is always true, so the result isx & 1: bit 0 ofx, zero-extended. Parentheses aroundio.x & io.ygive the intended comparison. -
What does
io.x == io.yreturn, and why can it not driveio.same?Show answer
A Scala
Boolean:==asks during elaboration whether the two port objects are the same object.:=needs hardware on its right, so the compiler reportsfound: Boolean, required: chisel3.Data.===builds the comparator.
The Practice problem below builds an 8-bit frame from seven data bits plus an even-parity bit in bit 7. The starter connects the data straight through, so bit 7 is always 0 and frames with an odd number of 1s break the parity rule.