Bundle
Description
The Bundle
is a composite type that defines a group of named signals (of any SpinalHDL basic type) under a single name.
A Bundle
can be used to model data structures, buses, and interfaces.
Declaration
The syntax to declare a bundle is as follows:
case class myBundle extends Bundle {
val bundleItem0 = AnyType
val bundleItem1 = AnyType
val bundleItemN = AnyType
}
For example, a bundle holding a color could be defined as:
case class Color(channelWidth: Int) extends Bundle {
val r, g, b = UInt(channelWidth bits)
}
You can find an APB3 definition among the Spinal HDL examples.
Operators
The following operators are available for the Bundle
type:
Comparison
Operator |
Description |
Return type |
---|---|---|
x === y |
Equality |
Bool |
x =/= y |
Inequality |
Bool |
val color1 = Color(8)
color1.r := 0
color1.g := 0
color1.b := 0
val color2 = Color(8)
color2.r := 0
color2.g := 0
color2.b := 0
myBool := color1 === color2
Type cast
Operator |
Description |
Return |
---|---|---|
x.asBits |
Binary cast to Bits |
Bits(w(x) bits) |
val color1 = Color(8)
val myBits := color1.asBits
Convert Bits back to Bundle
The .assignFromBits
operator can be viewed as the reverse of .asBits
.
Operator |
Description |
Return |
---|---|---|
x.assignFromBits(y) |
Convert Bits (y) to Bundle(x) |
Unit |
x.assignFromBits(y, hi, lo) |
Convert Bits (y) to Bundle(x) with high/low boundary |
Unit |
The following example saves a Bundle called CommonDataBus into a circular buffer (3rd party memory), reads the Bits out later and converts them back to CommonDataBus format.
case class TestBundle () extends Component {
val io = new Bundle {
val we = in Bool()
val addrWr = in UInt (7 bits)
val dataIn = slave (CommonDataBus())
val addrRd = in UInt (7 bits)
val dataOut = master (CommonDataBus())
}
val mm = Ram3rdParty_1w_1rs (G_DATA_WIDTH = io.dataIn.getBitsWidth,
G_ADDR_WIDTH = io.addrWr.getBitsWidth,
G_VENDOR = "Intel_Arria10_M20K")
mm.io.clk_in := clockDomain.readClockWire
mm.io.clk_out := clockDomain.readClockWire
mm.io.we := io.we
mm.io.addr_wr := io.addrWr.asBits
mm.io.d := io.dataIn.asBits
mm.io.addr_rd := io.addrRd.asBits
io.dataOut.assignFromBits(mm.io.q)
}
IO Element direction
When you define a Bundle
inside the IO definition of your component, you need to specify its direction.
in/out
If all elements of your bundle go in the same direction you can use in(MyBundle())
or out(MyBundle())
.
For example:
val io = new Bundle {
val input = in (Color(8))
val output = out(Color(8))
}
master/slave
If your interface obeys to a master/slave topology, you can use the IMasterSlave
trait. Then you have to implement the function def asMaster(): Unit
to set the direction of each element from the master’s perspective. Then you can use the master(MyBundle())
and slave(MyBundle())
syntax in the IO definition.
For example:
case class HandShake(payloadWidth: Int) extends Bundle with IMasterSlave {
val valid = Bool()
val ready = Bool()
val payload = Bits(payloadWidth bits)
// You have to implement this asMaster function.
// This function should set the direction of each signals from an master point of view
override def asMaster(): Unit = {
out(valid, payload)
in(ready)
}
}
val io = new Bundle {
val input = slave(HandShake(8))
val output = master(HandShake(8))
}