参数化

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

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

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

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

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

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

实例细化时参数

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

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

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

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

  • Hardwired code and constants (not strictly parameter management at all but serves to highlight the most basic mechanism, a code change, not a parameter data change)

  • 由伴随对象提供的常量值在 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。

This may be used in cases to help parameterize the SpinalHDL hardware description using an elaboration-time conditional expression. Causing HDL constructs to be emitted or not-emitted in the resulting HDL. The generate method can be seen as SpinalHDL syntactic sugar reducing language clutter.

Project SpinalHDL code referencing mySignal would need to ensure it handles the possibility of null gracefully. This is usually not a problem as those parts of the design can also be omitted dependant on the flag value. Thus the feature of parameterizing this component is demonstrated.

您也可以在线束(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…)来构建一些数据模型,然后以程序方式将它们转换为硬件(例如,迭代这些列表中的元素)。