写在前面
本文主要介绍了spinal HDL语言的基本数据类型,主要对Bool、Bits、UInt、SInt、Enum进行介绍。
数据类型简介
该语言提供了 5 种基本类型和 2 种可以使用的复合类型。
- 基本类型:Bool,Bits,UInt用于无符号整数,SInt用于有符号整数和Enum。
- 复合类型:Bundle和Vec。
除了基本类型之外,Spinal 还支持开发:
- 定点数(部分支持)
- 浮点数(实验支持)
最后,有一种特殊类型可用于检查 BitVector 和包含空洞(无关值)的位常量之间的相等性。一个例子如下所示:
val myBits = Bits(8 bits)
val itMatch = myBits === M"00--10--" // - don't care value
Bool
Bool
类型对应于一个布尔值(TRUE或FALSE)。
声明
声明布尔值的语法如下:([] 之间的所有内容都是可选的)
Syntax | Description | Return |
Bool[()] | 创建一个布尔值 | Bool |
True | 创建一个布尔值 | Bool |
False | 创建一个布尔值 | Bool |
Bool(value: Boolean) | 创建一个分配有 Scala Boolean(true, false) 的 Bool | Bool |
val myBool_1 = Bool() // Create a Bool
myBool_1 := False // := is the assignment operator
val myBool_2 = False // Equivalent to the code above
val myBool_3 = Bool(5 > 12) // Use a Scala Boolean to create a Bool
运算
以下运算符可用于 Bool 类型:
Operator | Description | Return type |
!x | 逻辑非 | Bool |
x && yx & y | 逻辑与 | Bool |
x || y x | y | 逻辑或 | Bool |
x ^ y | 逻辑异或 | Bool |
x.set[()] | 将 x 设置为 True | |
x.clear[()] | 将 x 设置为 False | |
x.setWhen(cond) | 当 cond 为 True 时设置 x | Bool |
x.clearWhen(cond) | 当 cond 为 True 时清除 x | Bool |
x.riseWhen(cond) | 当 x 为 False 且 cond 为 True 时设置 x | Bool |
x.fallWhen(cond) | 当 x 为 True 且 cond 为 True 时清除 x | Bool |
val a, b, c = Bool()
val res = (!a & b) ^ c // ((NOT a) AND b) XOR c
val d = False
when(cond) {
d.set() // equivalent to d := True
}
val e = False
e.setWhen(cond) // equivalent to when(cond) { d := True }
val f = RegInit(False) fallWhen(ack) setWhen(req)
/** equivalent to
* when(f && ack) { f := False }
* when(req) { f := True }
* or
* f := req || (f && !ack)
*/
// 注意操作顺序
val g = RegInit(False) setWhen(req) fallWhen(ack)
// equivalent to g := ((!g) && req) || (g && !ack)
边缘检测
Operator | Description | Return type |
x.edge[()] | 当 x 改变状态时返回 True | Bool |
x.edge(initAt: Bool) | 与 x.edge 相同,但具有重置值 | Bool |
x.rise[()] | 当 x 在上一个周期为低且现在为高时返回 True | Bool |
x.rise(initAt: Bool) | 与 x.rise 相同,但具有重置值 | Bool |
x.fall[()] | 当 x 在上一个周期为高且现在为低时返回 True | Bool |
x.fall(initAt: Bool) | 与 x.fall相同,但具有重置值 | Bool |
x.edges[()] | Return a bundle (rise, fall, toggle) 返回一个包(上升、下降、切换) | BoolEdges |
x.edges(initAt: Bool) | 与 x.edges 相同,但具有重置值 | BoolEdges |
when(myBool_1.rise(False)) {
// do something when a rising edge is detected
}
val edgeBundle = myBool_2.edges(False)
when(edgeBundle.rise) {
// do something when a rising edge is detected
}
when(edgeBundle.fall) {
// do something when a falling edge is detected
}
when(edgeBundle.toggle) {
// do something at each edge
}
比较
Operator | Description | Return type |
x === | 相等 | Bool |
x =/= y | 不相等 | Bool |
when(myBool) { // Equivalent to when(myBool === True)
// do something when myBool is True
}
when(!myBool) { // Equivalent to when(myBool === False)
// do something when myBool is False
}
类型转换
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.asUInt(bitCount) | 二进制转换为 UInt 并调整大小 | UInt(bitCount bits) |
x.asBits(bitCount) | 二进制转换为 Bits 并调整大小 | Bits(bitCount bits) |
// Add the carry to an SInt value
val carry = Bool()
val res = mySInt + carry.asSInt
其他
Operator | Description | Return |
x ## y | 连接类似位拼接, x->high, y->low | Bits(w(x) + w(y) bits) |
val a, b, c = Bool
// Concatenation of three Bool into a Bits
val myBits =
Bits
Bits
类型对应于不传达任何算术含义的位向量。
声明
声明位向量的语法如下:([] 之间的所有内容都是可选的)
Syntax | Description | Return |
Bits [()] | 创建一个 BitVector,推断比特数 | Bits |
Bits(x bits) | 创建一个具有 x 位的 BitVector | Bits |
B(value: Int[, x bits])B(value: BigInt[, x bits]) | 创建一个 BitVector,其中 x 位分配有“值” | Bits |
B”[[size’]base]value” | 创建一个分配有“值”的 BitVector(基数:“h”、“d”、“o”、“b”) | Bits |
B([x bits,] element, …) | 创建一个分配有元素指定值的 BitVector | Bits |
// Declaration
val myBits = Bits() // the size is inferred
val myBits1 = Bits(32 bits)
val myBits2 = B(25, 8 bits)
val myBits3 = B"8'xFF" // Base could be x,h (base 16)
// d (base 10)
// o (base 8)
// b (base 2)
val myBits4 = B"1001_0011" // _ can be used for readability
// Element
val myBits5 = B(8 bits, default -> True) // "11111111"
val myBits6 = B(8 bits, (7 downto 5) -> B"101", 4 -> true, 3 -> True, default -> false) // "10111000"
val myBits7 = Bits(8 bits)
myBits7 := (7 -> true, default -> false) // "10000000" (For assignment purposes, you can omit the B)
运算
逻辑运算
Operator | Description | Return type |
~x | 按位非 | Bits(w(x) bits) |
x & y | 按位与 | Bits(w(xy) bits) |
x | y | 按位或 | Bits(w(xy) bits) |
x ^ y | 按位异或 | Bits(w(xy) bits) |
x.xorR | x 的所有位异或 | Bool |
x.orR | 或 x 的所有位 | Bool |
x.andR | 与 x 的所有位 | Bool |
x >> y | 逻辑右移,y:Int | Bits(w(x) - y bits) |
x >> y | 逻辑右移,y:UInt | Bits(w(x) bits) |
x << y | 逻辑左移,y:Int | Bits(w(x) + y bits) |
x << y | 逻辑左移,y:UInt | Bits(w(x) + max(y) bits) |
x |>> y | 逻辑右移,y:Int/UInt | Bits(w(x) bits) |
x |<< y | 逻辑左移,y:Int/UInt | Bits(w(x) bits) |
x.rotateLeft(y) | 逻辑左旋,y:UInt/Int | Bits(w(x) bits) |
x.rotateRight(y) | 逻辑右旋,y:UInt/Int | Bits(w(x) bits) |
x.clearAll[()] | 清除所有位 | |
x.setAll[()] | 设置所有位 | |
x.setAllTo(value: Boolean) | 将所有位设置为给定的布尔值 | |
x.setAllTo(value: Bool) | 将所有位设置为给定的 Bool 值 |
// Bitwise operator
val a, b, c = Bits(32 bits)
c := ~(a & b) // Inverse(a AND b)
val all_1 = a.andR // Check that all bits are equal to 1
// Logical shift
val bits_10bits = bits_8bits << 2 // shift left (results in 10 bits)
val shift_8bits = bits_8bits |<< 2 // shift left (results in 8 bits)
// Logical rotation
val myBits = bits_8bits.rotateLeft(3) // left bit rotation
// Set/clear
val a = B"8'x42"
when(cond) {
a.setAll() // set all bits to True when cond is True
}
比较运算
Operator | Description | Return type |
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 | 映射到布尔数组 | Vec(Bool, w(x)) |
B(x: T) | 将数据转换为Bits | Bits(w(x) bits) |
// cast a Bits to SInt
val mySInt = myBits.asSInt
// create a Vector of bool
val myVec = myBits.asBools
// Cast a SInt to Bits
val myBits = B(mySInt)
位提取
Operator | Description | Return |
x(y) | 读取指定比特, y: Int/UInt | Bool |
x(offset,width bits) | 读取位域,偏移量 offset:UInt,宽度width:Int | Bits(width bits) |
x(range) | 读取范围位。例如:myBits(4 downto 2) | Bits(range bits) |
x(y) := z | 赋值位,y:Int/UInt | Bool |
x(offset, width bits) := z | 赋值位域,偏移量:UInt,宽度:Int | Bits(width bits) |
x(range) := z | 赋值位范围。例如:myBits(4 downto 2) := B”010” | Bits(range bits) |
// get the element at the index 4
val myBool = myBits(4)
// assign
myBits(1) := True
// Range
val myBits_8bits = myBits_16bits(7 downto 0)
val myBits_7bits = myBits_16bits(0 to 6)
val myBits_6bits = myBits_16Bits(0 until 6)
myBits_8bits(3 downto 0) :=
其他操作
Operator | Description | Return |
x.getWidth | 返回位数 | Int |
x.range | 返回范围(x.high 到 0) | Range |
x.high | 返回类型 x 的上界 | Int |
x.msb | 返回最高位 | Bool |
x.lsb | 返回最低位 | Bool |
x ## y | 连接,x->高,y->低 | Bits(w(x) + w(y) bits) |
x.subdivideIn(y slices) | 将x细分为y个切片,y:Int | Vec(Bits, y) |
x.subdivideIn(y bits) | 将x细分为多个y位切片,y:Int | Vec(Bits, w(x)/y) |
x.resize(y) | 返回 x 的调整大小副本,如果放大,则填充零,y: Int | Bits(y bits) |
x.resized | 返回X为一个允许自动调整大小副本。 | Bits(w(x) bits) |
x.resizeLeft(x) | 通过将 MSB 保持在同一位置来调整大小,x:Int | Bits(x bits) |
示例
println(myBits_32bits.getWidth) // 32
myBool := myBits.lsb // Equivalent to myBits(0)
// Concatenation
myBits_24bits := bits_8bits_1 ## bits_8bits_2 ## bits_8bits_3
// Subdivide
val sel = UInt(2 bits)
val myBitsWord = myBits_128bits.subdivideIn(32 bits)(sel)
// sel = 0 => myBitsWord = myBits_128bits(127 downto 96)
// sel = 1 => myBitsWord = myBits_128bits( 95 downto 64)
// sel = 2 => myBitsWord = myBits_128bits( 63 downto 32)
// sel = 3 => myBitsWord = myBits_128bits( 31 downto 0)
// If you want to access in reverse order you can do:
val myVector = myBits_128bits.subdivideIn(32 bits).reverse
val myBitsWord = myVector(sel)
// Resize
myBits_32bits := B"32'x112233344"
myBits_8bits := myBits_32bits.resized // automatic resize (myBits_8bits = 0x44)
myBits_8bits := myBits_32bits.resize(8) // resize to 8 bits (myBits_8bits = 0x44)
myBits_8bits := myBits_32bits.resizeLeft(8) // resize to 8 bits (myBits_8bits = 0x11)
UInt/SInt
UInt
/SInt
类型对应于比特的矢量可被用于符号/无符号整数运算。
声明
Syntax | Description | Return |
UInt[()]SInt[()] | 创建一个无符号/有符号整数,推断位数 | UIntSInt |
UInt(x bits)SInt(x bits) | 创建一个 x 位的无符号/有符号整数 | UIntSInt |
U(value: Int[,x bits]) U(value: BigInt[,x bits]) S(value: Int[,x bits]) S(value: BigInt[,x bits]) | 创建一个分配有“值”的无符号/有符号整数 | UIntSInt |
U”[[size’]base]value ”S”[[size’]base]value” | 创建一个分配有“值”的无符号/有符号整数(基数:“h”、“d”、“o”、“b”) | UIntSInt |
U([x bits,] element, …)S([x bits,] element, …) | 创建一个由元素指定的值分配的无符号整数 | UIntSInt |
示例
val myUInt = UInt(8 bits)
myUInt := U(2,8 bits)
myUInt := U(2)
myUInt := U"0000_0101" // Base per default is binary => 5
myUInt := U"h1A" // Base could be x (base 16)
// h (base 16)
// d (base 10)
// o (base 8)
// b (base 2)
myUInt := U"8'h1A"
myUInt := 2 // You can use a Scala Int as a literal value
val myBool := myUInt === U(7 -> true,(6 downto 0) -> false)
val myBool := myUInt === U(myUInt.range -> true)
// For assignment purposes, you can omit the U/S, which also allows the use of the [default -> ???] feature
myUInt := (default -> true) // Assign myUInt with "11111111"
myUInt := (myUInt.range -> true) // Assign myUInt with "11111111"
myUInt := (7 -> true, default -> false) // Assign myUInt with "10000000"
myUInt := ((4 downto 1) -> true, default -> false) // Assign myUInt with "00011110"
运算操作
逻辑运算
同Bits逻辑运算操作,但是返回值有所不同,和Bits相比增加了 逻辑异或(x^y),返回值为布尔值。
Operator | Description | Return type |
x ^ y | Logical XOR | Bool |
~x | Bitwise NOT | T(w(x) bits) |
x & y | Bitwise AND | T(max(w(xy) bits) |
x | y | Bitwise OR | T(max(w(xy) bits) |
x ^ y | Bitwise XOR | T(max(w(xy) bits) |
x.xorR | XOR all bits of x | Bool |
x.orR | OR all bits of x | Bool |
x.andR | AND all bits of x | Bool |
x >> y | Arithmetic shift right, y : Int | T(w(x) - y bits) |
x >> y | Arithmetic shift right, y : UInt | T(w(x) bits) |
x << y | Arithmetic shift left, y : Int | T(w(x) + y bits) |
x << y | Arithmetic shift left, y : UInt | T(w(x) + max(y) bits) |
x |>> y | Logical shift right, y : Int/UInt | T(w(x) bits) |
x |<< y | Logical shift left, y : Int/UInt | T(w(x) bits) |
x.rotateLeft(y) | Logical left rotation, y : UInt/Int | T(w(x) bits) |
x.rotateRight(y) | Logical right rotation, y : UInt/Int | T(w(x) bits) |
x.clearAll[()] | Clear all bits | |
x.setAll[()] | Set all bits | |
x.setAllTo(value : Boolean) | Set all bits to the given Boolean value | |
x.setAllTo(value : Bool) | Set all bits to the given Bool value |
// Bitwise operator
val a, b, c = SInt(32 bits)
c := ~(a & b) // Inverse(a AND b)
val all_1 = a.andR // Check that all bits are equal to 1
// Logical shift
val uint_10bits = uint_8bits << 2 // shift left (resulting in 10 bits)
val shift_8bits = uint_8bits |<< 2 // shift left (resulting in 8 bits)
// Logical rotation
val myBits = uint_8bits.rotateLeft(3) // left bit rotation
// Set/clear
val a = B"8'x42"
when(cond) {
a.setAll() // set all bits to True when cond is True
}
算术运算
Operator | Description | Return |
x + y | 加法 | T(max(w(x), w(y)), bits) |
x +^ y | 带进位加法 | T(max(w(x), w(y) + 1), bits) |
x +| y | 设置进位加法 | T(max(w(x), w(y)), bits) |
x - y | 减法 | T(max(w(x), w(y)), bits) |
x -^ y | 带借位减法 | T(max(w(x), w(y) + 1), bits) |
x -| y | 带设置借位减法 | T(max(w(x), w(y)), bits) |
x * y | 乘法 | T(w(x) + w(y)), bits) |
x / y | 除法 | T(w(x), bits) |
x % y | 取模 | T(w(x), bits) |
比较运算
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, w(x)) |
S(x: T) | 将数据转换为 SInt | SInt(w(x), bits) |
U(x: T) | 将数据转换为 UInt | UInt(w(x), bits) |
x.intoSInt | 转换为 SInt 扩展符号位 | SInt(w(x) + 1, bits) |
示例
// Cast an SInt to Bits
val myBits = mySInt.asBits
// Create a Vector of Bool
val myVec = myUInt.asBools
// Cast a Bits to SInt
val mySInt = S(myBits)
位提取
Operator | Description | Return |
x(y) | 读取指定比特, y: Int/UInt | Bool |
x(offset,width bits) | 读取位域,偏移量 offset:UInt,宽度width:Int | T(width bits) |
x(range) | 读取范围位。例如:myBits(4 downto 2) | T(range bits) |
x(y) := z | 赋值位,y:Int/UInt | Bool |
x(offset, width bits) := z | 赋值位域,偏移量:UInt,宽度:Int | T(width bits) |
x(range) := z | 赋值位范围。例如:myBits(4 downto 2) := B”010” | T(range bits) |
// get the bit at index 4
val myBool = myUInt(4)
// assign bit 1 to True
mySInt(1) := True
// Range
val myUInt_8bits = myUInt_16bits(7 downto 0)
val myUInt_7bits = myUInt_16bits(0 to 6)
val myUInt_6bits = myUInt_16Bits(0 until 6)
mySInt_8bits(3 downto 0) :=
其他操作
Operator | Description | Return |
x.getWidth | 返回位数 | Int |
x.msb | 返回最高位 | Bool |
x.lsb | 返回最低位 | Bool |
x.range | 返回范围(x.high 到 0) | Range |
x.high | 返回类型 x 的上界 | Int |
x ## y | 连接,x->高,y->低 | Bits(w(x) + w(y) bits) |
x @@ y | 连接 x:T 和 y:Bool/SInt/UInt | T(w(x) + w(y) bits) |
x.subdivideIn(y slices) | 将x细分为y个切片,y:Int | Vec(T, y) |
x.subdivideIn(y bits) | 将x细分为y位的多个切片,y:Int | Vec(T, w(x)/y) |
x.resize(y) | 返回 x 的调整大小的副本,如果放大,则 UInt 用零填充或 SInt 用符号填充,y: Int | T(y bits) |
x.resized | 返回允许自动生成的 x 副本 在需要的地方调整大小 | T(w(x) bits) |
myUInt.twoComplement(en: Bool) | 使用二进制补码将 UInt 转换为 SInt | SInt(w(myUInt) + 1, bits) |
mySInt.abs | 返回 UInt 值的绝对值 | UInt(w(mySInt), bits) |
mySInt.abs(en: Bool) | en为True时返回UInt值的绝对值 | UInt(w(mySInt), bits) |
mySInt.sign | 返回最高位 | Bool |
x.expand | 返回 用 1 位扩展的x | T(w(x)+1 bit) |
mySInt.absWithSym | 返回对称的 UInt 值的绝对值,缩小 1 位。 | UInt(w(mySInt) - 1, bits) |
myBool := mySInt.lsb // equivalent to mySInt(0)
// Concatenation
val mySInt = mySInt_1 @@ mySInt_1 @@ myBool
val myBits = mySInt_1 ## mySInt_1 ## myBool
// Subdivide
val sel = UInt(2 bits)
val mySIntWord = mySInt_128bits.subdivideIn(32 bits)(sel)
// sel = 0 => mySIntWord = mySInt_128bits(127 downto 96)
// sel = 1 => mySIntWord = mySInt_128bits( 95 downto 64)
// sel = 2 => mySIntWord = mySInt_128bits( 63 downto 32)
// sel = 3 => mySIntWord = mySInt_128bits( 31 downto 0)
// If you want to access in reverse order you can do:
val myVector = mySInt_128bits.subdivideIn(32 bits).reverse
val mySIntWord = myVector(sel)
// Resize
myUInt_32bits := U"32'x112233344"
myUInt_8bits := myUInt_32bits.resized // automatic resize (myUInt_8bits = 0x44)
myUInt_8bits := myUInt_32bits.resize(8) // resize to 8 bits (myUInt_8bits = 0x44)
// Two's complement
mySInt := myUInt.twoComplement(myBool)
// Absolute value
mySInt_abs := mySInt.abs
定点操作
对于定点,可以将其分为两部分:
- 低位运算(舍入方法)
- 高位运算(饱和运算)
Lower bit operations
SpinalHDL-Name | Wikipedia-Name | API | Mathematic Algorithm | return(align=false) | Supported |
FLOOR | RoundDown | floor | floor(x) | w(x)-n bits | Yes |
FLOORTOZERO | RoundToZero | floorToZero | sign*floor(abs(x)) | w(x)-n bits | Yes |
CEIL | RoundUp | ceil | ceil(x) | w(x)-n+1 bits | Yes |
CEILTOINF | RoundToInf | ceilToInf | sign*ceil(abs(x)) | w(x)-n+1 bits | Yes |
ROUNDUP | RoundHalfUp | roundUp | floor(x+0.5) | w(x)-n+1 bits | Yes |
ROUNDDOWN | RoundHalfDown | roundDown | ceil(x-0.5) | w(x)-n+1 bits | Yes |
ROUNDTOZERO | RoundHalfToZero | roundToZero | sign*ceil(abs(x)-0.5) | w(x)-n+1 bits | Yes |
ROUNDTOINF | RoundHalfToInf | roundToInf | sign*floor(abs(x)+0.5) | w(x)-n+1 bits | Yes |
ROUNDTOEVEN | RoundHalfToEven | roundToEven | No | ||
ROUNDTOODD | RoundHalfToOdd | roundToOdd | No |
RoundToEven 和 RoundToOdd 模式非常特殊,用于一些精度要求较高的大数据统计领域,SpinalHDL 尚不支持。
在 SpinalHDL ROUNDTOINF 中是默认的 RoundType (round = roundToInf)
val A = SInt(16 bit)
val B = A.roundToInf(6 bits) // default 'align = false' with carry, got 11 bit
val B = A.roundToInf(6 bits, align = true) // sat 1 carry bit, got 10 bit
val B = A.floor(6 bits) // return 10 bit
val B = A.floorToZero(6 bits) // return 10 bit
val B = A.ceil(6 bits) // ceil with carry so return 11 bit
val B = A.ceil(6 bits, align = true) // ceil with carry then sat 1 bit return 10 bit
val B = A.ceilToInf(6 bits)
val B = A.roundUp(6 bits)
val B = A.roundDown(6 bits)
val B = A.roundToInf(6 bits)
val B = A.roundToZero(6 bits)
val B = A.round(6 bits) // SpinalHDL uses roundToInf as the default rounding mode
val B0 = A.roundToInf(6 bits, align = true) // ---+
// |--> equal
val B1 = A.roundToInf(6 bits, align = false).sat(1) // ---+
只有 floor 和 floorToZero 在没有 align 选项的情况下工作; 他们不需要进位。 其他舍入操作默认使用进位位。
API | UInt/SInt | description | Return(align=false) | Return(align=true) |
floor | Both | w(x)-n bits | w(x)-n bits | |
floorToZero | SInt | equal to floor in UInt | w(x)-n bits | w(x)-n bits |
ceil | Both | w(x)-n+1 bits | w(x)-n bits | |
ceilToInf | SInt | equal to ceil in UInt | w(x)-n+1 bits | w(x)-n bits |
roundUp | Both | simple for HW | w(x)-n+1 bits | w(x)-n bits |
roundDown | Both | w(x)-n+1 bits | w(x)-n bits | |
roundToInf | SInt | most Common | w(x)-n+1 bits | w(x)-n bits |
roundToZero | SInt | equal to roundDown in UInt | w(x)-n+1 bits | w(x)-n bits |
round | Both | SpinalHDL chose roundToInf | w(x)-n+1 bits | w(x)-n bits |
虽然roundToInf很常见,但是roundUp成本最低,时序好,几乎没有性能损失。 因此,强烈建议使用roundUp 。
High bit operations
function | Operation | Positive-Op | Negative-Op |
sat | Saturation | when(Top[w-1, w-n].orR) set maxValue | When(Top[w-1, w-n].andR) set minValue |
trim | Discard | N/A | N/A |
symmetry | Symmetric | N/A | minValue = -maxValue |
对称(Symmetric )仅对 SInt 有效。
val A = SInt(8 bit)
val B = A.sat(3 bits) // return 5 bits with saturated highest 3 bits
val B = A.sat(3) // equal to sat(3 bits)
val B = A.trim(3 bits) // return 5 bits with the highest 3 bits discarded
val B = A.trim(3 bits) // return 5 bits with the highest 3 bits discarded
val C = A.symmetry // return 8 bits and symmetry as (-128~127 to -127~127)
val C = A.sat(3).symmetry // return 5 bits and symmetry as (-16~15 to -15~15)
fixTo function
UInt/SInt 提供了两种方法来做固定点:
在你的 RTL 工作中强烈推荐 fixTo,你不需要像上图中的 Way1 那样手动处理进位对齐和位宽计算。
Factory Fix 函数可以自动进行截位设置:
Function | Description | Return |
fixTo(section, roundType, symmetric) | section.size bits |
val A = SInt(16 bit)
val B = A.fixTo(10 downto 3) // default RoundType.ROUNDTOINF, sym = false
val B = A.fixTo( 8 downto 0, RoundType.ROUNDUP)
val B = A.fixTo( 9 downto 3, RoundType.CEIL, sym = false)
val B = A.fixTo(16 downto 1, RoundType.ROUNDTOINF, sym = true )
val B = A.fixTo(10 downto 3, RoundType.FLOOR) // floor 3 bit, sat 5 bit @ highest
val B = A.fixTo(20 downto 3, RoundType.FLOOR) // floor 3 bit, expand 2 bit @ highest
SpinalEnum
该Enumeration
类型对应于命名值列表。
声明
枚举数据类型的声明如下:
object Enumeration extends SpinalEnum {
val element0, element1, ..., elementN = newElement()
}
对于上面的示例,使用了默认编码。本机枚举类型用于 VHDL,二进制编码用于 Verilog。也可以通过如下定义枚举来强制枚举编码:
object Enumeration extends SpinalEnum(defaultEncoding=encodingOfYourChoice) {
val element0, element1, ..., elementN = newElement()
}
如果要定义一个枚举作为输入/输出给定组件,你必须做如下:in(MyEnum())
或out(MyEnum())
编码
支持以下枚举编码:
Encoding | Bit width | Description |
native | 使用VHDL枚举系统,这是默认编码 | |
binarySequential | log2Up(stateCount) | 使用 Bits 按声明顺序存储状态(值从 0 到 n-1) |
binaryOneHot | stateCount(状态计数) | 使用 Bits 来存储状态。每一位对应一个状态 |
自定义编码可以通过两种不同的方式执行:静态或动态。
/*
* Static encoding
*/
object MyEnumStatic extends SpinalEnum {
val e0, e1, e2, e3 = newElement()
defaultEncoding = SpinalEnumEncoding("staticEncoding")(
e0 -> 0,
e1 -> 2,
e2 -> 3,
e3 -> 7)
}
/*
* Dynamic encoding with the function : _ * 2 + 1
* e.g. : e0 => 0 * 2 + 1 = 1
* e1 => 1 * 2 + 1 = 3
* e2 => 2 * 2 + 1 = 5
* e3 => 3 * 2 + 1 = 7
*/
val encoding = SpinalEnumEncoding("dynamicEncoding", _ * 2 + 1)
object MyEnumDynamic extends SpinalEnum(encoding) {
val e0, e1, e2, e3 = newElement()
}
例子
实例化一个枚举信号并为其赋值:
object UartCtrlTxState extends SpinalEnum {
val sIdle, sStart, sData, sParity, sStop = newElement()
}
val stateNext = UartCtrlTxState()
stateNext := UartCtrlTxState.sIdle
// You can also import the enumeration to have visibility of its elements
import UartCtrlTxState._
stateNext :=
运算操作
以下运算符可用于该Enumeration
类型:
比较
操作员 | 描述 | 返回类型 |
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) |
Reference
- spinal HDL 官方文档。