Skip to main content

Common Misunderstandings

These are the most frequent points of confusion when reading or writing IDL for the first time.

Bits<N> width must be known at compile time

N must be a literal, a named constant, or a constant expression — it cannot be a variable. The width is a structural property of the hardware being described, resolved during elaboration before any instruction executes.

Bits<32>    word;             # OK: literal
Bits<MXLEN> reg; # OK: configuration constant
Bits<1> bit = word[31];

# Bits<bit> x; # error: bit is a variable

See Data Types and Variables & Constants.

Case determines the kind of identifier — it is not just style

A name that starts with a lowercase letter is always a mutable variable or a function. A name that starts with an uppercase letter is always a constant or a type (enum, bitfield, struct). This is enforced by the compiler:

Bits<8> value = 0;     # mutable variable (lowercase)
Bits<8> Value = 0; # constant (uppercase) — different thing entirely

You cannot name a mutable variable Count or a constant mxlen.

See Naming Rules.

Integers are not implicitly boolean

if (x) is a compilation error. An if condition must have type Boolean. You must write an explicit comparison:

XReg src1 = X[xs1];

if (src1 != 0) { ... } # correct
# if (src1) { ... } # compilation error

This applies everywhere a boolean is required: if, for conditions, and the ?: ternary condition.

There are no compound assignment operators

+=, -=, &=, |=, <<=, etc. do not exist. Write the full expression on the right-hand side:

count = count + 1;
mask = mask & 0xFF;

Enumeration members are not in the surrounding scope

Unlike C enums, you cannot reference Sv39 — you must fully qualify it with the enum name and :::

SatpMode mode = SatpMode::Sv39;   # correct
# SatpMode mode = Sv39; # compilation error

See Enumerations.

$signed changes widening, not the stored bits

$signed(x) does not permanently change the type of x. It tells the compiler to sign-extend x when it needs to be widened to match a wider operand, instead of zero-extending. The bits in x are unchanged; only the extension behavior changes.

Bits<2> b = 3;         # 0b11 — unsigned 3, or signed -1

Bits<4> a = 1;
Bits<4> e = a + b; # b zero-extends to 0b0011 = 3. 1+3 = 4
Bits<4> f = a + $signed(b); # b sign-extends to 0b1111 = 15. 1+15 wraps to 0

For comparison operators like < and <=, mixing a signed and an unsigned operand is a type error. Apply $signed to both operands when comparing signed values.

See Type Conversions.

raise() does not return

A call to raise() terminates the current instruction's execution immediately. Any code after it in the same block does not execute. There is no exception value to check — the exception is raised and execution ends:

if (access_fault) {
raise(ExceptionCode::LoadAccessFault, vaddr);
# code here never runs
}

See Standard Library.

Enum auto-assigned values follow the previous member, not position

When an enum member has no explicit value, it gets the value of the previous member plus one — not its declaration position:

enum Example {
First 1
Second 2
Zero 0
Third # value is 1 (0 + 1), NOT 3
}

Third gets value 1, not 3, because it follows Zero. Always assign values explicitly when the sequence is non-trivial.

See Enumerations.

Narrowing assignments silently discard high bits

Assigning a wider value into a narrower variable truncates the high bits without a warning:

Bits<32> wide   = 0xDEADBEEF;
Bits<8> narrow = wide; # narrow = 0xEF — upper 24 bits gone

Extract the bits you need explicitly before assigning:

Bits<8> low_byte  = wide[7:0];    # 0xEF
Bits<8> high_byte = wide[31:24]; # 0xDE

See Type Conversions.

Negative literals may lose their sign bit

A Verilog-style literal with an explicit width that is too narrow to hold the value silently truncates:

Bits<4> x = 4'd-1;   # -1 in 4 bits = 0b1111 = 15 (unsigned) — OK
Bits<3> y = 4'd-1; # truncates to 3 bits: 0b111 = 7 — sign bit lost

When encoding negative values, ensure the width is sufficient to hold the sign bit. Or use the 2's complement positive equivalent:

Bits<4> neg_one = 4'b1111;   # explicit 2's complement representation

See Literals.