TriState
Introduction
Tri-state signals are weird to handle in many cases:
They are not really kind of digital things
And except for IO, they aren’t used for digital design
The tristate concept doesn’t fit naturally in the SpinalHDL internal graph.
SpinalHDL provides two different abstractions for tristate signals. The TriState
bundle and Analog and inout signals.
Both serve different purposes:
TriState should be used for most purposes, especially within a design. The bundle contains an additional signal to carry the current direction.
Analog
andinout
should be used for drivers on the device boundary and in some other special cases. See the referenced documentation page for more details.
As stated above, the recommended approach is to use TriState
within a design. On the top-level the TriState
bundle is then assigned to an analog inout to get the
synthesis tools to infer the correct I/O driver. This can be done automatically done via the InOutWrapper or manually if needed.
TriState
The TriState bundle is defined as following :
case class TriState[T <: Data](dataType : HardType[T]) extends Bundle with IMasterSlave{
val read,write : T = dataType()
val writeEnable = Bool()
override def asMaster(): Unit = {
out(write,writeEnable)
in(read)
}
}
A master can use the read
signal to read the outside value, the writeEnable
to enable the output,
and finally use write
to set the value that is driven on the output.
There is an example of usage:
val io = new Bundle{
val dataBus = master(TriState(Bits(32 bits)))
}
io.dataBus.writeEnable := True
io.dataBus.write := 0x12345678
when(io.dataBus.read === 42){
}
TriStateArray
In some case, you need to have the control over the output enable of each individual pin (Like for GPIO). In this range of cases, you can use the TriStateArray bundle.
It is defined as following :
case class TriStateArray(width : BitCount) extends Bundle with IMasterSlave{
val read,write,writeEnable = Bits(width)
override def asMaster(): Unit = {
out(write,writeEnable)
in(read)
}
}
It is the same than the TriState bundle, except that the writeEnable
is an Bits to control each output buffer.
There is an example of usage :
val io = new Bundle{
val dataBus = master(TriStateArray(32 bits)
}
io.dataBus.writeEnable := 0x87654321
io.dataBus.write := 0x12345678
when(io.dataBus.read === 42){
}