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:

std_logic Bool
std_logic_vector Bits
unsigned UInt
signed SInt

While for defining an 8 bit unsigned in VHDL you have to give the range of bits unsigned(7 downto 0),
in SpinalHDL you simply supply the number of bits UInt(8 bits).

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).


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


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))

  counter := 0
}.elsewhen(counter === 76){
  counter := 79
  counter(7) := ! counter(7)

    counter := 65
    counter := counter + 1


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


In SpinalHDL, registers are explicitly specified while in VHDL it’s 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 analog 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
  myCombinatorial := True
  myRegister = myRegister + 1