交互
简介
事实上,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 }