十二 · 2021年10月26日

SpinalHDL—数据类型:Bits

书接上文,SpinalHDL在Bool的基础上,定义了Bits数据类型,本篇就Bits的初始化及使用方式结合SpinalHDL Doc做一个总结。

Bits:初始化

Bits意味这一组有Bool类型组成的向量,类似与我们在Verilog中的多比特位宽变量。在SpinalHDL中,声明一个Bits变量可采用如下形式(“[]”中为可选项):

b7f0100be448869ea61f6150ed7ec797.png

相较于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提供了一系列的操作运算符,如下表所示:

fde182c59208af1e59ae406a9328ce9a.png

这里值得注意的是:&、|、^操作符中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变量相同:

8d69f0fe8b6662998e238f2a990891ad.png

when(myBits === 3) {
}

when(myBits_32 =/= B"32'x44332211") {
} 

类型转换

Bits类型可以与其他类型之间进行相互转换,SpinalHDL提供的方法如下:
2a4910822a1497e75eb3ee2f12f95941.png

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也支持部分读取/赋值操作:

8114020452c71e26ab49280cdcc02383.png

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也提供了一些其他方法:

3ce0195fea6c1c6c660605ff336b31e4.png

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
微信公众号:
 title=

推荐阅读

更多SpinalHDL技术干货请关注Spinal FPGA专栏。
推荐阅读
关注数
1578
内容数
130
用SpinalHDL提升生产力
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息