参数化

参数化有多个方面的含义:

  • 在设计实例细化(elaboration)过程中向 SpinalHDL 提供细化过程的参数并对其进行管理

  • 通过使用参数,设计人员可以实现任何类型硬件的构造、配置和互连任务。例如硬件设计中的可选组件生成。

与 HDL 泛化功能(例如 Verilog 模块参数和 VHDL 泛型)的目标类似。 SpinalHDL 通过 Scala 类型安全和内置 HDL 设计规则检查带来额外保护,提供了更丰富、更强大的功能集。

用于组件参数化的 SpinalHDL 机制不是构建在任何 HDL 机制之上,因此,不会受到 HDL 语言级别/版本支持或手写 HDL 带来限制的影响。

对于希望使用 SpinalHDL 与参数化 Verilog 或通用 VHDL 进行互操作的读者,请参阅 BlackBox IP 中有关您的项目所需场景的部分。

实例细化时参数

您可以使用所有 Scala 语法来提供实例细化时参数。

所有的语法意味着您可以使用 Scala 语言的全部功能,以按照您选择的复杂程度解决项目的参数化要求。

SpinalHDL 不会对如何实现参数化目标施加任何特殊限制。因此,有许多 Scala 设计模式和一些 SpinalHDL 帮助程序可用于管理参数,以适合不同场景。

以下是一些示例和可能的想法:

  • 硬连线代码和常量(突出最基本的机制,而不是严格的参数管理,代码上的变更,而不是数据上的变更)

  • 由伴随对象提供的常量值在 Scala 中是静态常量。

  • 提供给 Scala 类构造函数的值,通常一个 case class 会导致 Scala 将这些构造函数的参数值捕获为常量。

  • 常规 Scala 流程控制语法,包括但不限于条件、循环、lambda/monad 等。

  • 配置类的模式(示例存在于库中,包括 UartCtrlConfig, SpiMasterCtrlConfig 等)

  • 项目定义的“插件”模式(在 VexRiscV 项目中有示例,用于配置生成的 CPU IP 核所使用的功能集)

  • 使用标准 Scala/JVM 库和 API 从文件或网络源中加载值和信息。

  • “任何你可以创建的机制”

所有机制都会导致实力细化生成的 HDL 输出发生变化。

这可以仅仅使用 Scala 编程就完成设计,支持单个常数值到整个 SoC 的所有总线和互连架构描述的参数化。

这是一个类参数的示例

case class MyBus(width : Int) extends Bundle {
  val mySignal = UInt(width bits)
}
case class MyComponent(width : Int) extends Component {
  val bus = MyBus(width)
}

您还可以使用 Scala 对象(伴随对象模式)中定义的全局变量。

ScopeProperty 也可用于配置。

可选硬件

所以这里还有更多的可能性。

对于可选信号:

case class MyComponent(flag : Boolean) extends Component {
  val mySignal = flag generate (Bool())
  // equivalent to "val mySignal = if (flag) Bool() else null"
}

generate 函数是一种实现具有可选值的表达式机制。如果谓词为 true,generate 将计算给定表达式并返回结果,否则返回 null。

使用实例细化时条件表达式有助于参数化 SpinalHDL 硬件描述。导致 HDL 结构在生成的 HDL 中存在或不存在。generate函数可以看作是 SpinalHDL 语法糖,减少语言混乱。

SpinalHDL 代码中引用 mySignal 信号将需要确保它优雅地处理 null 的可能性。这通常不是问题,因为实际设计中的这些部分也会根据 flag 值省略。从而达到了该组件参数化的目的。

您也可以在线束(Bundle)中做相同的事。

请注意,您还可以使用 scala 选项类(Option)。

如果你想禁用某个硬件块的生成:

case class MyComponent(flag : Boolean) extends Component {
  val myHardware = flag generate new Area {
    //optional hardware here
  }
}

您还可以使用 scala 中的 for 循环:

case class MyComponent(amount : Int) extends Component {
  val myHardware = for(i <- 0 until amount) yield new Area {
    // hardware here
  }
}

因此,您可以在实例细化时根据需要扩展这些 scala 用法,包括使用整个 scala 集合(List、Set、Map…)来构建一些数据模型,然后以程序方式将它们转换为硬件(例如,迭代这些列表中的元素)。