VHDL equivalences
Entity and architecture
In SpinalHDL, a VHDL entity and architecture are both defined inside a Component
.
Here is an example of a component which has 3 inputs (a
, b
, c
) and an output (result
). This component also has an offset
construction parameter (like a VHDL generic).
case class MyComponent(offset: Int) extends Component {
val io = new Bundle{
val a, b, c = in UInt(8 bits)
val result = out UInt(8 bits)
}
io.result := a + b + c + offset
}
Then to instantiate that component, you don’t need to bind it:
case class TopLevel extends Component {
...
val mySubComponent = MyComponent(offset = 5)
...
mySubComponent.io.a := 1
mySubComponent.io.b := 2
mySubComponent.io.c := 3
??? := mySubComponent.io.result
...
}
Data types
SpinalHDL data types are similar to the VHDL ones:
VHDL |
SpinalHDL |
---|---|
std_logic |
Bool |
std_logic_vector |
Bits |
unsigned |
UInt |
signed |
SInt |
unsigned
you have to give the range of bits unsigned(7 downto 0)
,UInt(8 bits)
.VHDL |
SpinalHDL |
---|---|
records |
Bundle |
array |
Vec |
enum |
SpinalEnum |
Here is an example of the SpinalHDL Bundle
definition. channelWidth
is a construction parameter, like VHDL generics, but for data structures:
case class RGB(channelWidth: Int) extends Bundle {
val r, g, b = UInt(channelWidth bits)
}
Then for example, to instantiate a Bundle
, you need to write val myColor = RGB(channelWidth=8)
.
Signal
Here is an example about signal instantiations:
case class MyComponent(offset: Int) extends Component {
val io = new Bundle {
val a, b, c = UInt(8 bits)
val result = UInt(8 bits)
}
val ab = UInt(8 bits)
ab := a + b
val abc = ab + c // You can define a signal directly with its value
io.result := abc + offset
}
Assignments
In SpinalHDL, the :=
assignment operator is equivalent to the VHDL signal assignment (<=
):
val myUInt = UInt(8 bits)
myUInt := 6
Conditional assignments are done like in VHDL by using if
/case
statements:
val clear = Bool()
val counter = Reg(UInt(8 bits))
when(clear) {
counter := 0
}.elsewhen(counter === 76) {
counter := 79
}.otherwise {
counter(7) := ! counter(7)
}
switch(counter) {
is(42) {
counter := 65
}
default {
counter := counter + 1
}
}
Literals
Literals are a little bit different than in VHDL:
val myBool = Bool()
myBool := False
myBool := True
myBool := Bool(4 > 7)
val myUInt = UInt(8 bits)
myUInt := "0001_1100"
myUInt := "xEE"
myUInt := 42
myUInt := U(54,8 bits)
myUInt := ((3 downto 0) -> myBool, default -> true)
when(myUInt === U(myUInt.range -> true)) {
myUInt(3) := False
}
Registers
In SpinalHDL, registers are explicitly specified while in VHDL registers are inferred. Here is an example of SpinalHDL registers:
val counter = Reg(UInt(8 bits)) init(0)
counter := counter + 1 // Count up each cycle
// init(0) means that the register should be initialized to zero when a reset occurs
Process blocks
Process blocks are a simulation feature that is unnecessary to design RTL. It’s why SpinalHDL doesn’t contain any feature analogous to process blocks, and you can assign what you want, where you want.
val cond = Bool()
val myCombinatorial = Bool()
val myRegister = UInt(8 bits)
myCombinatorial := False
when(cond) {
myCombinatorial := True
myRegister = myRegister + 1
}