十二 · 2021年11月09日

以变量为索引,取指定之位宽

聊一聊如何动态选取变量中指定宽度的数据。

+:与-:

在Verilog/SystemVerilog中,当我们从一个数据中根据另一个变量动态选取指定位宽时用到的表达式为“+:”和“-:”。+:和 -:适用于那些 [MSB : LSB]都想使用变量的情况。

[BASE +: WIDTH] 代表 [BASE+WIDTH : BASE],BASE是变量,WIDTH是常量。

[BASE  -: WIDTH] 代表 [BASE :  BASE-WIDTH]。

data[0 +: 8]  <--等价于--> data[7:0]
data[15 +: 2] <--等价于--> data[16:15]
data[7 -: 8]  <--等价于--> data[7:0]
data[15 -: 2] <--等价于--> data[15:14]

这也算是一个常用的功能。条条大路通罗马,在SpinalHDL里,有两种写法可实现相同的功能。

x(offset, width)

无论是对于UInt/SInt还是Bits,其都提供了一个x(offset, width)方法,该方法用于从变量中指定偏移处选取指定位宽。offset为UInt类型,用于指定偏移,width为BitCount类型(SpinalHDL-Doc中有误,width类型不可为Int):

case class example6() extends Component{
  val io=new Bundle{
    val dataIn=in UInt(512 bits)
    val sel=in UInt(9 bits)
    val dataOut=out UInt(8 bits)
  }
  io.dataOut:=io.dataIn(io.sel,8 bits)
}

其对应的RTL代码为:

module example6 (
  input      [511:0]  io_dataIn,
  input      [9:0]    io_sel,
  output     [7:0]    io_dataOut
);
  assign io_dataOut = io_dataIn[io_sel +: 8];
endmodule

可以看出,x(offset, width)方法对应的实现是+:,而对于-:则并没有支持,若想实现只能这么来写:

io.dataOut:=io.dataIn(io.sel,8 bits)

subdivideIn

相较于x(offset, width),subdivideIn则方法则是将变量按指定方式进行切割形成一个Vec数组,其语法为:

//Subdivide x into y slices, y: Int
x.subdivideIn(y slices)
//Subdivide x into multiple slices of y bits, y: IntSubdivide x into multiple slices of y bits, y: Int
x.subdivideIn(y bits)

而在《起承转合,Vec数组的使用》中提到,Vec中有提供read方法,能够让我们读取指定的范围,因而可以这么来写:

io.dataOut:=io.dataIn.subdivideIn(8 bits).read(io.sel)

其生成的Verilog代码中会是一个case语句。

one more thing

无论是Verilog/SystemVerilog,还是SpinalHDL,向量的选取均只能取固定位宽的数据,这也是为什么x(offset, width)中width必须是一个固定值。我们描述的仍旧是电路,所以电路对象在进行电路描述时便是固定下来的。

无他,我们甚至可以认为SpinalHDL是一个用来写Verilog的工具脚本而已~

END

作者:玉骐
原文链接:https://mp.weixin.qq.com/s/O6RNZ1G5Oy5UTwG5WEBjEw
微信公众号:
 title=

推荐阅读

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