Chisel datatypes are used to specify the type of values held in state
elements or flowing on wires. While hardware designs ultimately
operate on vectors of binary digits, other more abstract
representations for values allow clearer specifications and help the
tools generate more optimal circuits. In Chisel, a raw collection of
bits is represented by the
Bits type. Signed and unsigned integers
are considered subsets of fixed-point numbers and are represented by
UInt respectively. Signed fixed-point
numbers, including integers, are represented using two’s-complement
format. Boolean values are represented as type
that these types are distinct from Scala’s builtin types such as
There is a new experimental type Interval which gives the developer more control of the type by allowing the definition of an IntervalRange. See: Interval Type
Additionally, Chisel defines
Bundles for making
collections of values with named fields (similar to
other languages), and
Vecs for indexable collections of
Bundles and Vecs will be covered later.
Constant or literal values are expressed using Scala integers or strings passed to constructors for the types:
1.U // decimal 1-bit lit from Scala Int. "ha".U // hexadecimal 4-bit lit from string. "o12".U // octal 4-bit lit from string. "b1010".U // binary 4-bit lit from string. 5.S // signed decimal 4-bit lit from Scala Int. -8.S // negative decimal 4-bit lit from Scala Int. 5.U // unsigned decimal 3-bit lit from Scala Int. 8.U(4.W) // 4-bit unsigned decimal, value 8. -152.S(32.W) // 32-bit signed decimal, value -152. true.B // Bool lits from Scala lits. false.B
Underscores can be used as separators in long string literals to aid readability, but are ignored when creating the value, e.g.:
"h_dead_beef".U // 32-bit lit of type UInt
By default, the Chisel compiler will size each constant to the minimum
number of bits required to hold the constant, including a sign bit for
signed types. Bit widths can also be specified explicitly on
literals, as shown below. Note that (
.W is used to cast a Scala Int
to a Chisel width)
"ha".asUInt(8.W) // hexadecimal 8-bit lit of type UInt "o12".asUInt(6.W) // octal 6-bit lit of type UInt "b1010".asUInt(12.W) // binary 12-bit lit of type UInt 5.asSInt(7.W) // signed decimal 7-bit lit of type SInt 5.asUInt(8.W) // unsigned decimal 8-bit lit of type UInt
For literals of type
UInt, the value is
zero-extended to the desired bit width. For literals of type
SInt, the value is sign-extended to fill the desired bit width.
If the given bit width is too small to hold the argument value, then a
Chisel error is generated.
We are working on a more concise literal syntax for Chisel using symbolic prefix operators, but are stymied by the limitations of Scala operator overloading and have not yet settled on a syntax that is actually more readable than constructors taking strings.
We have also considered allowing Scala literals to be automatically converted to Chisel types, but this can cause type ambiguity and requires an additional import.
The SInt and UInt types will also later support an optional exponent field to allow Chisel to automatically produce optimized fixed-point arithmetic circuits.
We can also cast types in Chisel:
val sint = 3.S(4.W) // 4-bit SInt val uint = sint.asUInt // cast SInt to UInt uint.asSInt // cast UInt to SInt
asSInt with an explicit width can not be used to cast (convert) between Chisel datatypes.
No width parameter is accepted, as Chisel will automatically pad or truncate as required when the objects are connected.
We can also perform casts on clocks, though you should be careful about this, since clocking (especially in ASIC) requires special attention:
val bool: Bool = false.B // always-low wire val clock = bool.asClock // always-low clock clock.asUInt // convert clock to UInt (width 1) clock.asUInt.asBool // convert clock to Bool (Chisel 3.2+) clock.asUInt.toBool // convert clock to Bool (Chisel 3.0 and 3.1 only)
(Experimental, Chisel 3.1+)
Chisel supports an
Analog type (equivalent to Verilog
inout) that can be used to support arbitrary nets in Chisel. This includes analog wires, tri-state/bi-directional wires, and power nets (with appropriate annotations).
Analog is an undirectioned type, and so it is possible to connect multiple
Analog nets together using the
attach operator. It is possible to connect an
Analog once using
<> but illegal to do it more than once.
val a = IO(Analog(1.W)) val b = IO(Analog(1.W)) val c = IO(Analog(1.W)) // Legal attach(a, b) attach(a, c) // Legal a <> b // Illegal - connects 'a' multiple times a <> b a <> c