写在前面
本文主要介绍了spinal HDL语言的复合数据类型,主要对Bundle、Vec进行介绍,同时对UFix/SFix进行了介绍。
Bundle
Bundle是复合类型,根据单个名称定义了一组命名的信号的(任何SpinalHDL基本类型)。Bundle可用于对数据结构、总线和接口进行建模。
声明
声明包的语法如下:
case class myBundle extends Bundle {
val bundleItem0 = AnyType
val bundleItem1 = AnyType
val bundleItemN = AnyType
}
例如,一个包含颜色的包可以定义为:
case class Color(channelWidth: Int) extends Bundle {
val r, g, b = UInt(channelWidth bits)
}
运算操作
以下运算符可用于该Bundle类型:
Operator  | Description  | Return type  | 
x === y  | 相等  | Bool  | 
x =/= y  | 不相等  | Bool  | 
类型转换
Operator  | Description  | Return  | 
x.asBits  | 二进制转换为Bits  | Bits(w(x) bits)  | 
val color1 = Color(8)
val myBits := color1.asBits
将 Bits 转换回 Bundle
该.assignFromBits操作可以被看作是.asBits相反的操作。
Operator  | Description  | Return  | 
x.assignFromBits(y)  | 转换Bits (y) 为 Bundle(x)  | Unit  | 
x.assignFromBits(y, hi, lo)  | 转换 Bits (y) 为 Bundle(x)具有高/低边界  | Unit  | 
以下示例将名为 CommonDataBus 的 Bundle 保存到循环缓冲区(第 3 方内存)中,稍后读取位并将它们转换回 CommonDataBus 格式。

case class TestBundle () extends Component {
val io = new Bundle {
val we = in Bool()
val addrWr = in UInt (7 bits)
val dataIn = slave (CommonDataBus())
val addrRd = in UInt (7 bits)
val dataOut = master (CommonDataBus())
}
val mm = Ram3rdParty_1w_1rs (G_DATA_WIDTH = io.dataIn.getBitsWidth,
G_ADDR_WIDTH = io.addrWr.getBitsWidth,
G_VENDOR = "Intel_Arria10_M20K")
mm.io.clk_in := clockDomain.readClockWire
mm.io.clk_out := clockDomain.readClockWire
mm.io.we := io.we
mm.io.addr_wr := io.addrWr.asBits
mm.io.d := io.dataIn.asBits
mm.io.addr_rd := io.addrRd.asBits
io.dataOut.assignFromBits(mm.io.q)
}
IO方向
在组件的 IO 定义中定义 Bundle 时,需要指定其方向。
如果 bundle 的所有元素都在同一个方向,你可以使用 in(MyBundle()) 或 out(MyBundle())。
val io = new Bundle {
val input = in (Color(8))
val output = out(Color(8))
}
master/slave
如果您的接口遵循主/从拓扑,则可以使用 IMasterSlave 特性。 然后你必须实现函数 def asMaster(): Unit 来从 master 的角度设置每个元素的方向。 然后你可以在 IO 定义中使用 master(MyBundle()) 和 slave(MyBundle()) 语法。
case class HandShake(payloadWidth: Int) extends Bundle with IMasterSlave {
val valid = Bool()
val ready = Bool()
val payload = Bits(payloadWidth bits)
// You have to implement this asMaster function.
// This function should set the direction of each signals from an master point of view
override def asMaster(): Unit = {
out(valid, payload)
in(ready)
}
}
val io = new Bundle {
val input = slave(HandShake(8))
val output = master(HandShake(8))
}
Vec
Vec 是一种复合类型,它在单个名称下定义一组索引信号(任何 SpinalHDL 基本类型)。
声明
Declaration  | Description  | 
Vec(type: Data, size: Int)  | 创建一个能够容纳“数据”类型的“大小”元素的向量  | 
Vec(x, y, …)  | 创建一个向量,其中索引指向提供的元素。此构造函数支持混合元素宽度。  | 
示例
// Create a vector of 2 signed integers
val myVecOfSInt = Vec(SInt(8 bits), 2)
myVecOfSInt(0) := 2
myVecOfSInt(1) := myVecOfSInt(0) + 3
// Create a vector of 3 different type elements
val myVecOfMixedUInt = Vec(UInt(3 bits), UInt(5 bits), UInt(8 bits))
val x, y, z = UInt(8 bits)
val myVecOf_xyz_ref = Vec(x, y, z)
// Iterate on a vector
for(element <- myVecOf_xyz_ref) {
element := 0 // Assign x, y, z with the value 0
}
// Map on vector
myVecOfMixedUInt.map(_ := 0) // Assign all elements with value 0
// Assign 3 to the first element of the vector
myVecOf_xyz_ref(1) := 3
运算操作
以下运算符可用于该Vec类型:
比较操作
Operator  | Description  | Return type  | 
x === y  | 相等  | Bool  | 
x =/= y  | 不相等  | Bool  | 
示例
// Create a vector of 2 signed integers
val vec2 = Vec(SInt(8 bits), 2)
val vec1 = Vec(SInt(8 bits), 2)
myBool := vec2 === vec1 // Compare all elements
类型转换
Operator  | Description  | Return  | 
x.asBits  | 二进制转化为Bits  | Bits(w(x) bits)  | 
示例
// Create a vector of 2 signed integers
val vec1 = Vec(SInt(8 bits), 2)
myBits_16bits := vec1.asBits
其他
Operator  | Description  | Return  | 
x.getBitsWidth  | 返回 Vec 的完整大小  | Int  | 
示例
// Create a vector of 2 signed integers
val vec1 = Vec(SInt(8 bits), 2)
println(vec1.getBitsWidth) // 16
UFix/SFix
UFix 和 SFix 类型对应于可用于定点算术的位向量。
声明
声明定点数的语法如下:
Unsigned Fixed-Point
Syntax  | bit width  | resolution  | max  | min  | 
UFix(peak: ExpNumber, resolution: ExpNumber)  | 峰值分辨率  | 2^分辨率  | 2peak-2resolution  | 0  | 
UFix(peak: ExpNumber, width: BitCount)  | 宽度  | 2^(峰宽)  | 2peak-2(peak-width)  | 0  | 
Signed Fixed-Point
Syntax  | bit width  | resolution  | max  | min  | 
SFix(peak: ExpNumber, resolution: ExpNumber)  | 峰值分辨率+1  | 2^分辨率  | 2peak-2分辨率  | -(2^peak)  | 
SFix(peak: ExpNumber, width: BitCount)  | 宽度  | 2^(峰宽-1)  | 2peak-2(peak-width-1)  | -(2^peak)  | 
格式
所选格式遵循使用 Q 表示法定义定点数格式的常用方法。例如 Q8.2 将表示 8+2 位的定点数,其中 8 位用于自然部分,2 位用于小数部分。如果定点数是有符号的,则多使用一位作为符号。分辨率定义为可以用这个数字表示的 2 的最小幂。
为了使表示 2 的幂的数字更不容易出错,在spinal.corecalled 中有一个数字类型,ExpNumber用于定点类型构造函数。这种类型的便利包装器以exp函数的形式存在(在本页的代码示例中使用)。
示例
// Unsigned Fixed-Point
val UQ_8_2 = UFix(peak = 8 exp, resolution = -2 exp) // bit width = 8 - (-2) = 10 bits
val UQ_8_2 = UFix(8 exp, -2 exp)
val UQ_8_2 = UFix(peak = 8 exp, width = 10 bits)
val UQ_8_2 = UFix(8 exp, 10 bits)
// Signed Fixed-Point
val Q_8_2 = SFix(peak = 8 exp, resolution = -2 exp) // bit width = 8 - (-2) + 1 = 11 bits
val Q_8_2 = SFix(8 exp, -2 exp)
val Q_8_2 = SFix(peak = 8 exp, width = 11 bits)
val Q_8_2 = SFix(8 exp, 11 bits)
赋值操作
当没有比特丢失时,对定点值的赋值是有效的。任何位丢失都会导致错误。如果源定点值太大,该.truncated函数将允许您调整源数字的大小以匹配目标大小。
示例
val i16_m2 = SFix(16 exp, -2 exp)
val i16_0 = SFix(16 exp, 0 exp)
val i8_m2 = SFix( 8 exp, -2 exp)
val o16_m2 = SFix(16 exp, -2 exp)
val o16_m0 = SFix(16 exp, 0 exp)
val o14_m2 = SFix(14 exp, -2 exp)
o16_m2 := i16_m2 // OK
o16_m0 := i16_m2 // Not OK, Bit loss
o14_m2 := i16_m2 // Not OK, Bit loss
o16_m0 := i16_m2.truncated // OK, as it is resized
o14_m2 := i16_m2.truncated // OK, as it is resized
Scala常量
在分配给 UFix 或 SFix 信号时,Scala BigInt 或 Double 类型可用作常量。
val i4_m2 = SFix(4 exp, -2 exp)
i4_m2 := 1.25 // Will load 5 in i4_m2.raw
i4_m2 := 4 // Will load 16 in i4_m2.raw
原始值
可以使用该raw属性读取或写入定点数的整数表示。
val UQ_8_2 = UFix(8 exp, 10 bits)
UQ_8_2.raw := 4 // Assign the value corresponding to 1.0
UQ_8_2.raw := U(17) // Assign the value corresponding to 4.25
运算操作
以下运算符可用于该UFix类型:
算术运算
Operator  | Description  | Returned resolution  | Returned amplitude  | 
x + y  | 加  | Min(x.resolution, y.resolution)  | Max(x.amplitude, y.amplitude)  | 
x - y  | 减  | Min(x.resolution, y.resolution)  | Max(x.amplitude, y.amplitude)  | 
x * y  | 乘  | x.resolution * y.resolution)  | x.amplitude * y.amplitude  | 
x >> y  | 算术右移, y : Int  | x.amplitude >> y  | x.resolution >> y  | 
x << y  | 算术左移, y : Int  | x.amplitude << y  | x.resolution << y  | 
x >>| y  | 算术右移, y : Int  | x.amplitude >> y  | x.resolution  | 
x <<| y  | 算术左移, y : Int  | x.amplitude << y  | x.resolution  | 
Comparison
Operator  | Description  | Return type  | 
x === y  | 相等  | Bool  | 
x =/= y  | 不相等  | Bool  | 
x > y  | 大于  | Bool  | 
x >= y  | 大于等于  | Bool  | 
x > y  | 小于  | Bool  | 
x >= y  | 小于等于  | Bool  | 
类型转换
Operator  | Description  | Return  | 
x.asBits  | 二进制转换为 Bits  | Bits(w(x) bits)  | 
x.asUInt  | 二进制转换为 UInt  | UInt(w(x) bits)  | 
x.asSInt  | 二进制转换为 SInt  | SInt(w(x) bits)  | 
x.asBools  | 转换成 Bool 数组  | Vec(Bool,width(x))  | 
x.toUInt  | 返回对应的 UInt(带截断)  | UInt  | 
x.toSInt  | 返回对应的 SInt(带截断)  | SInt  | 
x.toUFix  | 返回对应的 UFix  | UFix  | 
x.toSFix  | 返回对应的SFix  | SFix  | 
其他
Name  | Return  | Description  | 
x.maxValue  | 返回可存储的最大值  | Double  | 
x.minValue  | 返回可存储的最小值  | Double  | 
x.resolution  | x.amplitude * y.amplitude  | Double  | 
Reference
- spinal HDL官方文档
 
                










