一个简单的例子

以下是来自 入门 仓库的简单硬件描述。

case class MyTopLevel() extends Component {
  val io = new Bundle {
    val cond0 = in port Bool()
    val cond1 = in port Bool()
    val flag  = out port Bool()
    val state = out port 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
}

它在本节中被分成多个块进行解释。

Component

首先,这里有一个 SpinalHDL Component 的结构。

组件是一段逻辑,可以根据需要多次实例化(粘贴),外部仅可通过输入和输出信号(io)对其访问。

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

  // component logic goes here
}

MyTopLevel 是组件的名称。

在 SpinalHDL 中,组件使用 UpperCamelCase (驼峰命名法)。

备注

请参阅 组件 了解更多信息。

端口

然后,定义端口。

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

方向:

  • cond0cond1 是输入端口

  • flagstate 是输出端口

类型:

  • cond0cond1flag 各为一个比特(3 条单独的线)

  • state 是一个8位无符号整数(用一组8根线来表示一个无符号整数)

备注

此语法仅自 SpinalHDL 1.8 起可用,请参阅 输入/输出定义 了解旧语法和更多信息。

内部逻辑

最后,还有组件的逻辑:

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

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

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

counter 是一个包含 8 位无符号整数的寄存器,初始值为 0。更改寄存器状态的赋值仅可在下一个时钟采样后回读。

备注

由于寄存器的存在,时钟和复位两个隐式信号被添加组件中。有关更多信息,请参阅 寄存器时钟域

然后描述一个条件规则:当输入 cond0 (位于“io”线束中)被置1时,counter 加一,否则 counter 保持其值在最后一条规则中设置的值。但是,您可能会说,如果没有给出前置规则呢?对一个简单的**信号**来说,它将成为一个锁存器,并触发一个错误。但这里的 counter 是一个寄存器,所以它有一个默认值,没有其他规则,它就保持初始值。

这里创建了一个多路复用器: counter 寄存器的输入可以是其输出或其输出加一,这取决于 io.cond0 的值。

然后描述无条件规则(赋值):

  • 输出端口 state 连接到寄存器 counter 的输出。

  • 输出端口 flag 是输入信号 cond1 与另一信号之间的 or 门的输出,该信号在 counter 信号等于0时为真,否则为假。

备注

有关更多信息,请参阅 语义