书接上文,SpinalHDL在Bool的基础上,定义了Bits数据类型,本篇就Bits的初始化及使用方式结合SpinalHDL Doc做一个总结。
Bits:初始化
Bits意味这一组有Bool类型组成的向量,类似与我们在Verilog中的多比特位宽变量。在SpinalHDL中,声明一个Bits变量可采用如下形式(“[]”中为可选项):
相较于Veriog,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)
操作符
针对Bits变量,SpinalHDL提供了一系列的操作运算符,如下表所示:
这里值得注意的是:&、|、^操作符中x,y的宽度必须保持一致,否则在生成RTL代码时将提示不能正常编译(可使用resized方法自动扩展剪裁位宽),相当于把RTL中的位宽不匹配警报消除在设计阶段。
对于逻辑右移操作,同时x>>y,y变量类型的不同所产生的结果也不同,看下述代码:
class BitsInst extends Component {
val data_in1=in Bits(16 bits)
val data_out1=out Bits()
val data_out2=out Bits()
data_out1:=data_in1>>3
data_out2:=data_in1>>U(3)
}
其生成的RTL代码为:
module BitsInst (
input [15:0] data_in1,
output [12:0] data_out1,
output [15:0] data_out2
);
assign data_out1 = (data_in1 >>> 3);
assign data_out2 = (data_in1 >>> 2'b11);
endmodule
可以看到 ,data_out1位宽为13个bit,而data_out2位宽为16个比特。结合定义,对比可以看出:若y为Int类型(scala原生类型),所谓的移位操作更像是截断处理,而若y为UInt类型,则和Verilog中的移位操作含义基本相同。此外,虽然生成的RTL代码里采用的是>>>,但由于是无符号数,故而与逻辑右移相同。
由于SpinalHDL会检测":="左右两侧位宽是否相同,所以若在编写时使用错误在生成rtl时即可发现,不会等到仿真时摸不着头脑。
比较操作符
比较操作符Bits变量和Bool变量相同:
when(myBits === 3) {
}
when(myBits_32 =/= B"32'x44332211") {
}
类型转换
Bits类型可以与其他类型之间进行相互转换,SpinalHDL提供的方法如下:
val mySInt = myBits.asSInt
// create a Vector of bool
val myVec = myBits.asBools
// Cast a SInt to Bits
val myBits = B(mySInt)
部分赋值/提取操作符
与Verilog/Systemverilog相同,Bits也支持部分读取/赋值操作:
val myBool = myBits(4)
val myBits2= Bits(2 bits)
// assign
myBits(1) := True
myBits2:=myBits(2,2 bits)
myBits2:=myBits(U(2),2 bits)
// 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) := myBits_4bits
对于x(offset,width bits),其意味着从offset比特位开始,向上截取width比特位宽,上述示例第5行等效于myBits2:=myBits(3 downto 2)。
其他方法
为方便代码设计,SpinalHDL针对Bits也提供了一些其他方法:
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
END
作者:玉骐
原文链接:https://mp.weixin.qq.com/s/tFPIUS\_K21d9wXtXZnrOSw
微信公众号:
推荐阅读
更多SpinalHDL技术干货请关注Spinal FPGA专栏。