位
Bits 类型表示多位向量,不传达任何算术含义。
声明
声明位向量的语法如下([]之间的所有内容都是可选的):
| 语法 | 描述 | 
|---|---|
| Bits [()] | 创建Bits,其位数是从构造后最宽的赋值语句推断出来的 | 
| Bits(x bits) | 创建具有 x 位的Bits | 
| B(value: Int[, x bits]) B(value: BigInt[, x bits]) | 创建 x 位Bits,且赋值为’value’ | 
| B”[[size’]base]value” | 创建Bits并赋值为’value’(基数:“h”、“d”、“o”、“b”) | 
| B([x bits,] elements: Element*) | 创建并赋值由 elements 指定值的Bits | 
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
// Bits with all ones ("11111111")
val myBits5 = B(8 bits, default -> True)
// initialize with "10111000" through a few elements
val myBits6 = B(8 bits, (7 downto 5) -> B"101", 4 -> true, 3 -> True, default -> false)
// "10000000" (For assignment purposes, you can omit the B)
val myBits7 = Bits(8 bits)
myBits7 := (7 -> true, default -> false)
当推断 Bits 的宽度时,赋予值的宽度仍然必须与信号的最终宽度相匹配:
// Declaration
val myBits = Bits()     // the size is inferred from the widest assignment
// ....
// .resized needed to prevent WIDTH MISMATCH error as the constants
// width does not match size that is inferred from assignment below
myBits := B("1010").resized  // auto-widen Bits(4 bits) to Bits(6 bits)
when(condxMaybe) {
  // Bits(6 bits) is inferred for myBits, this is the widest assignment
  myBits := B("110000")
}
运算符
以下运算符可用于 Bits 类型:
逻辑运算
| 运算符 | 描述 | 返回类型 | 
|---|---|---|
| ~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 | 
| y = 1 // 整数 x >> y | 逻辑右移,y: Int 结果的宽度可能会变少 | Bits(w(x) - y bits) | 
| y = U(1) // UInt x >> y | 逻辑右移,y: UInt 结果宽度相同 | Bits(w(x) bits) | 
| y = 1 // 整数 x << y | 逻辑左移,y: Int 结果的宽度可能会增加 | Bits(w(x) + y bits) | 
| y = U(1) // UInt 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 | 
| x.setAll[()] | 将所有的位设置为1 | 修改x | 
| x.setAllTo(value: Boolean) | 将所有位设置为给定的布尔值(Scala Boolean) | 修改x | 
| x.setAllTo(value: Bool) | 将所有位设置为给定的布尔值(Spinal Bool) | 修改x | 
// 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
}
比较运算
| 运算符 | 描述 | 返回类型 | 
|---|---|---|
| x === y | 等价性判断 | Bool | 
| x =/= y | 不等价判断运算 | Bool | 
when(myBits === 3) {
  // ...
}
val notMySpecialValue = myBits_32 =/= B"32'x44332211"
类型转换
| 运算符 | 描述 | 返回类型 | 
|---|---|---|
| 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)) | 
| x.asBool | 提取  | Bool(x.lsb) | 
| B(x: T) | 将数据转换为  | Bits(w(x) bits) | 
要将 Bool 、 UInt 或 SInt 转换为 Bits,您可以使用 B(something) 或 B(something[, 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)
// Cast the same SInt to Bits but resize to 3 bits
//  (will expand/truncate as necessary, retaining LSB)
val myBits = B(mySInt, 3 bits)
位提取
所有位提取操作均可用于读取一个位/一组位。与其他 HDL 一样,提取运算符也可用于为 Bits 的一部分赋值。
所有位提取操作均可用于读取一个位/一组位。与其他 HDL 一样,它们也可用于选择要写入位的范围。
| 运算符 | 描述 | 返回类型 | 
|---|---|---|
| x(y: Int) | 静态访问第 y 位 | Bool | 
| x(y: UInt) | 访问第 y 位,这里y为可变的信号 | Bool | 
| x(offset: Int, width bits) | 固定地选择偏移量和宽度, | Bits(width bits) | 
| x(offset: UInt, width bits) | 选择偏移量可变和宽度固定的信号, | Bits(width bits) | 
| x(range: Range) | 访问Bits的 范围 。例如:myBits(4 downto 2) | Bits(range.size bits) | 
| x.subdivideIn(y slices, [strict: Boolean]) | 将x分割为y片,y: Int | Vec(Bits(…), y) | 
| x.subdivideIn(y bits, [strict: Boolean]) | 将 x 分割为 y 位的多个切片,y: Int | Vec(Bits(y bit), …) | 
| x.msb | 访问 x 的最高有效位(最高索引) | Bool | 
| x.lsb | 访问 x 的最低有效位(索引 0) | Bool | 
一些基本示例:
// get the element at the index 4
val myBool = myBits(4)
// assign element 1
myBits(1) := True
// index dynamically
val index = UInt(2 bit)
val indexed = myBits(index, 2 bit)
// range index
val myBits_8bit = myBits_16bit(7 downto 0)
val myBits_7bit = myBits_16bit(0 to 6)
val myBits_6bit = myBits_16bit(0 until 6)
// assign to myBits_16bit(3 downto 0)
myBits_8bit(3 downto 0) := myBits_4bit
// equivalent slices, no reversing occurs
val a = myBits_16bit(8 downto 4)
val b = myBits_16bit(4 to 8)
// read / assign the msb / leftmost bit / x.high bit
val isNegative = myBits_16bit.msb
myBits_16bit.msb := False
分割细节
两个 subdivideIn 函数的所有参数都有一个可选参数 strict 参数(即 subdivideIn(slices: SlicesCount, strict: Boolean = true) )。如果 strict 为 true,则如果输入无法等分,将引发错误。如果设置为 false,最后一个元素可能比其他(大小相等)元素小。
// Subdivide
val sel = UInt(2 bits)
val myBitsWord = myBits_128bits.subdivideIn(32 bits)(sel)
    // sel = 3 => myBitsWord = myBits_128bits(127 downto 96)
    // sel = 2 => myBitsWord = myBits_128bits( 95 downto 64)
    // sel = 1 => myBitsWord = myBits_128bits( 63 downto 32)
    // sel = 0 => 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 myRevBitsWord = myVector(sel)
 // We can also assign through subdivides
 val output8 = Bits(8 bit)
 val pieces = output8.subdivideIn(2 slices)
 // assign to output8
 pieces(0) := 0xf
 pieces(1) := 0x5
杂项
与上面列出的位提取操作相反,上述函数不能使用其返回值给原始信号赋值。
| 运算符 | 描述 | 返回类型 | 
|---|---|---|
| x.getWidth | 返回位数 | Int | 
| x.bitsRange | 返回范围(0 到 x.high) | 范围 | 
| x.valueRange | 返回最小到最大 x 值的范围,理解为无符号整数(0 到 2 ** width - 1)。 | 范围 | 
| x.high | 返回 MSB(最高有效位) 的索引(x的最高索引,该索引从0开始计数) | Int | 
| x.reversed | 返回 x 的副本,其位顺序相反,MSB<>LSB 是镜像的。 | Bits(w(x) bits) | 
| x ## y | 连接Bits,x->高位,y->低位 | Bits(w(x) + w(y) bits) | 
| x #* n | n次重复x并合并 | Bits(w(x) * n bits) | 
| x.resize(y) | 返回一个新的信号与 x 信号直接连接但位宽变成了y位。如果位宽变大了,则根据需要在 MSB 处用零填充进行扩展,y: Int | Bits(y bits) | 
| x.resized | 返回一个允许自动调整位宽的 x 的副本信号。调整位宽操作被推迟到稍后的赋值操作。调整位宽可能会加宽或截断原信号,但保留 LSB。 | Bits(w(x) bits) | 
| x.resizeLeft(x) | 调整位宽时保持 MSB 位置不变,x:Int 调整位宽可能会加宽或截断信号,同时保留 MSB。 | Bits(x bits) | 
| x.getZero | 返回新的 Bits 的实例,该实例被分配了与 x 宽度相同的0值(常量)。 | Bits(0, w(x) bits) | 
| x.getAllTrue | 返回 Bits 的新实例,该实例被赋予了与 x 宽度相同的1值(常量)。 | Bits(w(x) bits).setAll() | 
备注
validRange 只能用于最小值和最大值能够保存在32 位有符号整数的情况下。 (这是由于 Scala scala.collection.immutable.Range 类型使用 Int 作为范围描述)
println(myBits_32bits.getWidth) // 32
// Concatenation
myBits_24bits := bits_8bits_1 ## bits_8bits_2 ## bits_8bits_3
// or
myBits_24bits := Cat(bits_8bits_1, bits_8bits_2, bits_8bits_3)
// 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)
掩码字面量
MaskedLiteral 值带有”不关心”值的位向量,其中”不关心”值用 - 表示。它们可用于直接比较或用于 switch 和 mux 等语句。
val myBits = B"1101"
val test1 = myBits === M"1-01" // True
val test2 = myBits === M"0---" // False
val test3 = myBits === M"1--1" // True