交互

简介

事实上,SpinalHDL 不是一种语言:它是一个常规的 Scala 库。乍一看这似乎很奇怪,但这是一个非常强大的组合。

您可以使用整个 Scala 世界的工具,通过 SpinalHDL 库来帮助您描述硬件,但要正确地做到这一点,了解 SpinalHDL 如何与 Scala 交互非常重要。

SpinalHDL 在 API 隐藏后的工作原理

当您执行 SpinalHDL 硬件描述时,每次使用 SpinalHDL 函数、运算符或类时,它都会构建一个内存中图来表示您设计的网表。

然后,当实例细化完成后(顶层 Component 类的实例化),SpinalHDL 将对构建的图进行一些处理,如果一切正常,它将把该图生成为 VHDL 或 Verilog文件。

一切都是引用

例如,如果您定义一个 Scala 函数,它接受类型为 Bits 的参数,那么当您调用它时,它将作为引用传递。因此,如果您在函数内部赋值(通过“:=”)该参数,它对底层 Bits 对象具有相同的效果,就像您在函数外部给它赋值一样。

硬件类型

SpinalHDL 中的硬件数据类型是两个概念的组合:

  • 给定 Scala 类型的实例

  • 该实例的配置信息

例如,Bits(8 bits) 是 Scala 类型 Bits 及其 8 bits 这一配置信息(作为构造参数)的组合。

RGB 示例

我们以 Rgb 线束类为例:

case class Rgb(rWidth: Int, gWidth: Int, bWidth: Int) extends Bundle {
  val r = UInt(rWidth bits)
  val g = UInt(gWidth bits)
  val b = UInt(bWidth bits)
}

这里的硬件数据类型是 Scala Rgb 类及其 rWidth, gWidth, 和 bWidth 参数的组合。

这是一个用法示例:

// Define an Rgb signal
val myRgbSignal = Rgb(5, 6, 5)

// Define another Rgb signal of the same data type as the preceding one
val myRgbCloned = cloneOf(myRgbSignal)

您还可以使用函数来定义各种类型工厂(typedef):

// Define a type factory function
def myRgbTypeDef = Rgb(5, 6, 5)

// Use that type factory to create an Rgb signal
val myRgbFromTypeDef = myRgbTypeDef

生成的 RTL 中的信号名称

为了命名生成的 RTL 中的信号,SpinalHDL 使用 Java 反射遍历整个组件层次结构,收集存储在类属性内的所有引用,并使用属性名称命名它们。

这就是函数内定义的每个信号的名称都会丢失的原因:

def myFunction(arg: UInt) {
  val temp = arg + 1  // You will not retrieve the `temp` signal in the generated RTL
  return temp
}

val value = myFunction(U"000001") + 42

如果您想在生成的 RTL 中保留内部变量的名称,一种解决方案是使用逻辑区( Area):

def myFunction(arg: UInt) new Area {
  val temp = arg + 1  // You will not retrieve the temp signal in the generated RTL
}

val myFunctionCall = myFunction(U"000001")  // Will generate `temp` with `myFunctionCall_temp` as the name
val value = myFunctionCall.temp  + 42

Scala 用于实例细化,SpinalHDL 用于硬件描述

例如,如果您编写 Scala for 循环来生成某些硬件,它将生成展开的 VHDL/Verilog 代码。

另外,如果你想要一个常量,你不应该使用 SpinalHDL 硬件代码,而应该使用 Scala 代码。例如:

// This is wrong, because you can't use a hardware Bool as construction parameter. (It will cause hierarchy violations.)
class SubComponent(activeHigh: Bool) extends Component {
  // ...
}

// This is right, you can use all the Scala world to parameterize your hardware.
class SubComponent(activeHigh: Boolean) extends Component {
  // ...
}

Scala 实例细化能力(if、for、函数式编程)

在Scala中,所有的语法都可以用来细化硬件设计。例如,Scala的 if 语句可以用于启用或禁用部分硬件的生成。

val counter = Reg(UInt(8 bits))
counter := counter + 1
if(generateAClearWhenHit42) {  // Elaboration test, like an if generate in vhdl
  when(counter === 42) {       // Hardware test
    counter := 0
  }
}

Scala 的 for 循环也是如此:

val value = Reg(Bits(8 bits))
when(something) {
  // Set all bits of value by using a Scala for loop (evaluated during hardware elaboration)
  for(idx <- 0 to 7) {
    value(idx) := True
  }
}

此外,函数式编程技术可用于许多 SpinalHDL 类型:

val values = Vec(Bits(8 bits), 4)

val valuesAre42    = values.map(_ === 42)
val valuesAreAll42 = valuesAre42.reduce(_ && _)

val valuesAreEqualToTheirIndex = values.zipWithIndex.map{ case (value, i) => value === i }