You're reading an old version of this documentation.
For the latest stable release version, please have a look at master.

A simple example

Below is a simple hardware description from the getting started repository.

case class MyTopLevel() extends Component {
  val io = new Bundle {
    val cond0 = in Bool()
    val cond1 = in Bool()
    val flag  = out Bool()
    val state = out UInt(8 bits)
  }

  val counter = Reg(UInt(8 bits)) init 0

  when(io.cond0) {
    counter := counter + 1
  }

  io.state := counter
  io.flag  := (counter === 0) | io.cond1
}

It is split into chunks and explained in this section.

Component

First, there is the structure of a SpinalHDL Component.

A component is a piece of logic which can be instantiated (pasted) as many times as needed, and where the only accessible signals are its inputs and outputs.

case class MyTopLevel() extends Component {
  val io = new Bundle {
    // port definitions go here
  }

  // component logic goes here
}

MyTopLevel is the name of the component.

In SpinalHDL, components use UpperCamelCase.

Note

See Component and hierarchy for more information.

Ports

Then, the ports are defined.

val cond0 = in port Bool
val cond1 = in port Bool
val flag = out port Bool
val state = out port UInt(8 bits)

Directions:

  • cond0 and cond1 are inputs ports

  • flag and state are outputs ports

Types:

  • cond0, cond1 and flag are three bits (3 individual wires)

  • state is an 8-bit unsigned integer (a set of 8 wires representing an unsigned integer)

Note

This syntax is only available since SpinalHDL 1.8, see Input / output definition for legacy syntax and more information.

Internal logic

Finally, there is the component logic:

val counter = Reg(UInt(8 bits)) init 0

when(io.cond0) {
  counter := counter + 1
}

io.state := counter
io.flag := (counter === 0) | io.cond1

counter is a register containing an 8-bits unsigned integer, with the initial value 0. Assignments to a registers can be read only after the next clock sampling.

Note

Because of the presence of a register, two implicit signals are added to the component for the clock and the reset. See Registers and Clock domains for more information.

Then a conditional rule is described: when the input cond0 (which is in the io bundle) is set, the counter is incremented by one, else counter keeps its value set in the last rule. But, there is no previous rule, you would say. With a simple signal it would be a latch, and trigger an error. But here counter is a register, so it has a default case: it just keeps the same value.

This creates a multiplexer: the input of the counter register can be its output or its output plus one depending on io.cond0.

Then unconditional rules (assignments) are described:

  • The output state is connected to the output of the register counter.

  • The output flag is the output of an or gate between a signal which is true when the output of “counter equals 0”, and the input cond1.

Note

See Semantic for more information.