You're reading an pre-release version of this documentation.
For the latest stable release version, please have a look at master.

Bits

The Bits type is a vector of bits without conveying any arithmetic meaning.

Declaration

The syntax to declare a bit vector is as follows (everything between [] is optional):

Syntax

Description

Bits [()]

Create Bits, bit count is inferred from the widest assignment statement after construction

Bits(x bits)

Create Bits with x bits

B(value: Int[, x bits])
B(value: BigInt[, x bits])

Create Bits with x bits assigned with ‘value’

B”[[size’]base]value”

Create Bits assigned with ‘value’ (base: ‘h’, ‘d’, ‘o’, ‘b’)

B([x bits,] elements: Element*)

Create Bits assigned with the value specified by elements

val myBits1 = Bits(32 bits)
val myBits2 = B(25, 8 bits)
val myBits3 = B"8'xFF"   // Base could be x,h (base 16)
                         //               d   (base 10)
                         //               o   (base 8)
                         //               b   (base 2)
val myBits4 = B"1001_0011"  // _ can be used for readability

// Bits with all ones ("11111111")
val myBits5 = B(8 bits, default -> True)

// initialize with "10111000" through a few elements
val myBits6 = B(8 bits, (7 downto 5) -> B"101", 4 -> true, 3 -> True, default -> false)

// "10000000" (For assignment purposes, you can omit the B)
val myBits7 = Bits(8 bits)
myBits7 := (7 -> true, default -> false)

When inferring the width of a Bits the sizes of assigned values still have to match the final size of the signal:

// Declaration
val myBits = Bits()     // the size is inferred from the widest assignment
// ....
// .resized needed to prevent WIDTH MISMATCH error as the constants
// width does not match size that is inferred from assignment below
myBits := B("1010").resized  // auto-widen Bits(4 bits) to Bits(6 bits)
when(condxMaybe) {
  // Bits(6 bits) is inferred for myBits, this is the widest assignment
  myBits := B("110000")
}

Operators

The following operators are available for the Bits type:

Logic

Operator

Description

Return type

~x

Bitwise NOT

Bits(w(x) bits)

x & y

Bitwise AND

Bits(w(xy) bits)

x | y

Bitwise OR

Bits(w(xy) bits)

x ^ y

Bitwise XOR

Bits(w(xy) bits)

x.xorR

XOR all bits of x

Bool

x.orR

OR all bits of x

Bool

x.andR

AND all bits of x

Bool

y = 1 // Int
x >> y
Logical shift right, y: Int
Result may reduce width

Bits(w(x) - y bits)

y = U(1) // UInt
x >> y
Logical shift right, y: UInt
Result is same width

Bits(w(x) bits)

y = 1 // Int
x << y
Logical shift left, y: Int
Result may increase width

Bits(w(x) + y bits)

y = U(1) // UInt
x << y
Logical shift left, y: UInt
Result may increase width

Bits(w(x) + max(y) bits)

x |>> y

Logical shift right, y: Int/UInt
Result is same width

Bits(w(x) bits)

x |<< y

Logical shift left, y: Int/UInt
Result is same width

Bits(w(x) bits)

x.rotateLeft(y)

Logical left rotation, y: UInt/Int
Result is same width

Bits(w(x) bits)

x.rotateRight(y)

Logical right rotation, y: UInt/Int
Result is same width

Bits(w(x) bits)

x.clearAll[()]

Clear all bits

modifies x

x.setAll[()]

Set all bits

modifies x

x.setAllTo(value: Boolean)

Set all bits to the given Boolean value

modifies x

x.setAllTo(value: Bool)

Set all bits to the given Bool value

modifies x

// Bitwise operator
val a, b, c = Bits(32 bits)
c := ~(a & b) // Inverse(a AND b)

val all_1 = a.andR // Check that all bits are equal to 1

// Logical shift
val bits_10bits = bits_8bits << 2  // shift left (results in 10 bits)
val shift_8bits = bits_8bits |<< 2 // shift left (results in 8 bits)

// Logical rotation
val myBits = bits_8bits.rotateLeft(3) // left bit rotation

// Set/clear
val a = B"8'x42"
when(cond) {
  a.setAll() // set all bits to True when cond is True
}

Comparison

Operator

Description

Return type

x === y

Equality

Bool

x =/= y

Inequality

Bool

when(myBits === 3) {
  // ...
}

val notMySpecialValue = myBits_32 =/= B"32'x44332211"

Type cast

Operator

Description

Return

x.asBits

Binary cast to Bits

Bits(w(x) bits)

x.asUInt

Binary cast to UInt

UInt(w(x) bits)

x.asSInt

Binary cast to SInt

SInt(w(x) bits)

x.asBools

Cast to an array of Bools

Vec(Bool(), w(x))

x.asBool

Extract LSB of x

Bool(x.lsb)

B(x: T)

Cast Data to Bits

Bits(w(x) bits)

To cast a Bool, UInt or an SInt into a Bits, you can use B(something) or B(something[, x bits]):

// cast a Bits to SInt
val mySInt = myBits.asSInt

// create a Vector of bool
val myVec = myBits.asBools

// Cast a SInt to Bits
val myBits = B(mySInt)

// Cast the same SInt to Bits but resize to 3 bits
//  (will expand/truncate as necessary, retaining LSB)
val myBits = B(mySInt, 3 bits)

Bit extraction

All of the bit extraction operations can be used to read a bit / group of bits. Like in other HDLs the extraction operators can also be used to assign a part of a Bits.

All of the bit extraction operations can be used to read a bit / group of bits. Like in other HDLs They can also be used to select a range of bits to be written.

Operator

Description

Return

x(y: Int)

Static bit access of y-th bit

Bool

x(x: UInt)

Variable bit access of y-th bit

Bool

x(offset: Int, width bits)

Fixed part select of fixed width, offset is LSB index

Bits(width bits)

x(offset: UInt, width bits)

Variable part-select of fixed width, offset is LSB index

Bits(width bits)

x(range: Range)

Access a range of bits. Ex : myBits(4 downto 2)

Bits(range.size bits)

x.subdivideIn(y slices, [strict: Boolean])

Subdivide x into y slices, y: Int

Vec(Bits(…), y)

x.subdivideIn(y bits, [strict: Boolean])

Subdivide x in multiple slices of y bits, y: Int

Vec(Bits(y bit), …)

x.msb

Access most significant bit of x (highest index)

Bool

x.lsb

Access lowest significant bit of x (index 0)

Bool

Some basic examples:

// get the element at the index 4
val myBool = myBits(4)
// assign element 1
myBits(1) := True

// index dynamically
val index = UInt(2 bit)
val indexed = myBits(index, 2 bit)

// range index
val myBits_8bit = myBits_16bit(7 downto 0)
val myBits_7bit = myBits_16bit(0 to 6)
val myBits_6bit = myBits_16bit(0 until 6)
// assign to myBits_16bit(3 downto 0)
myBits_8bit(3 downto 0) := myBits_4bit

// equivalent slices, no reversing occurs
val a = myBits_16bit(8 downto 4)
val b = myBits_16bit(4 to 8)

// read / assign the msb / leftmost bit / x.high bit
val isNegative = myBits_16bit.msb
myBits_16bit.msb := False

Subdivide details

Both overloads of subdivideIn have an optional parameter strict (i.e. subdivideIn(slices: SlicesCount, strict: Boolean = true)). If strict is true an error will be raised if the input could not be divided into equal parts. If set to false the last element may be smaller than the other (equal sized) elements.

// Subdivide
val sel = UInt(2 bits)
val myBitsWord = myBits_128bits.subdivideIn(32 bits)(sel)
    // sel = 3 => myBitsWord = myBits_128bits(127 downto 96)
    // sel = 2 => myBitsWord = myBits_128bits( 95 downto 64)
    // sel = 1 => myBitsWord = myBits_128bits( 63 downto 32)
    // sel = 0 => myBitsWord = myBits_128bits( 31 downto  0)

 // If you want to access in reverse order you can do:
 val myVector   = myBits_128bits.subdivideIn(32 bits).reverse
 val myRevBitsWord = myVector(sel)

 // We can also assign through subdivides
 val output8 = Bits(8 bit)
 val pieces = output8.subdivideIn(2 slices)
 // assign to output8
 pieces(0) := 0xf
 pieces(1) := 0x5

Misc

In contrast to the bit extraction operations listed above it’s not possible to use the return values to assign to the original signal.

Operator

Description

Return

x.getWidth

Return bitcount

Int

x.bitsRange

Return the range (0 to x.high)

Range

x.valueRange

Return the range of minimum to maximum x values, interpreted as an unsigned integer (0 to 2 ** width - 1).

Range

x.high

Return the index of the MSB (highest allowed zero-based index for x)

Int

x.reversed

Return a copy of x with reverse bit order, MSB<>LSB are mirrored.

Bits(w(x) bits)

x ## y

Concatenate, x->high, y->low

Bits(w(x) + w(y) bits)

x #* n

Repeat x n-times

Bits(w(x) * n bits)

x.resize(y)

Return a resized representation of x, if enlarged, it is extended with zero padding at MSB as necessary, y: Int

Bits(y bits)

x.resized

Return a version of x which is allowed to be automatically resized were needed. The resize operation is deferred until the point of assignment later. The resize may widen or truncate, retaining the LSB.

Bits(w(x) bits)

x.resizeLeft(x)

Resize by keeping MSB at the same place, x:Int The resize may widen or truncate, retaining the MSB.

Bits(x bits)

x.getZero

Return a new instance of Bits that is assigned a constant value of zeros the same width as x.

Bits(0, w(x) bits)

x.getAllTrue

Return a new instance of Bits that is assigned a constant value of ones the same width as x.

Bits(w(x) bits).setAll()

Note

validRange can only be used for types where the minimum and maximum values fit into a signed 32-bit integer. (This is a limitation given by the Scala scala.collection.immutable.Range type which uses Int)

println(myBits_32bits.getWidth) // 32

// Concatenation
myBits_24bits := bits_8bits_1 ## bits_8bits_2 ## bits_8bits_3
// or
myBits_24bits := Cat(bits_8bits_1, bits_8bits_2, bits_8bits_3)

// Resize
myBits_32bits := B"32'x112233344"
myBits_8bits  := myBits_32bits.resized       // automatic resize (myBits_8bits = 0x44)
myBits_8bits  := myBits_32bits.resize(8)     // resize to 8 bits (myBits_8bits = 0x44)
myBits_8bits  := myBits_32bits.resizeLeft(8) // resize to 8 bits (myBits_8bits = 0x11)

MaskedLiteral

MaskedLiteral values are bit vectors with don’t care values denoted with -. They can be used for direct comparison or for switch statements and mux es.

val myBits = B"1101"

val test1 = myBits === M"1-01" // True
val test2 = myBits === M"0---" // False
val test3 = myBits === M"1--1" // True