拼位操作{}不是黑拼
在进行数据传输时经常会需要对数据进行拼位操作以对数据格式进行期望的改变.但是往往因为使用不当,导致得到的数据与期望的不一致.本文将示例拼位操作的用法和注意事项.
1 格式
{expr1,expr2,expr3,…exprN};【示例】
…… logic [7:0] Dbus; initial begin Dbus = 8‘b0001_0010; Dbus[7:4] = {Dbus[0],Dbus[1],Dbus[2],Dbus[3]}; // reverse Dbus[3:0] // Dbus = 8‘b0100_0010; end ……
下面将通过几个示例展示其中一些使用注意事项.
【示例】
{Dbus,5}示例中的“5”并没有明确指定位宽,这样的拼位操作是不允许的.因为拼位操作需要计算拼位后的位宽,所以没有明确指定拼位操作数位宽的方式,在拼位操作中是不允许的.
【示例】
【示例】
…… wire Abus; wire [3:0] Bbus; wire Cbus; wire [7:0] Dbus,Ebus; …… assign Dbus = {Abus,Bbus,Cbus,2’b01}; assign Ebus = {Abus,Bbus[3],Bbus[2],Bbus[1],Bbus[0],Cbus,1’b0,1’b1}; ……
示例中的Dbus和Ebus实际上是一致的,即具有确定位宽的矢量可以在拼位操作中可以展开按位单独列出进行拼接,也可以仅使用矢量名就可以了.
这里有个问题,需要重复多次拼接同一个数时,如果还是单独一个一个的列出l来工作量将是巨大的同时出错的可能性也增加了,为了避免这种情况出现,可以使用拼接操作过程中重复运算,其格式如下:
{repetition_number{expr1,expr2,expr3,…exprN}}
{3{1’b1}}; // 相当于3’b111 {2’b11,{3{1’b0}}}; // 相当于5’b11000
注意,这里的repetition_number不能是负数、x和z,这里与纯粹的使用{}拼接稍有不同的地方是,repetition_number重复拼接后,其外还有一对{},用以对重复的表达式进行拼接合并.
【示例】
{2’b11,4{abc}}; // illegal {2’b11,{4{abc}}}; // ok
这里需要注意,repetition_number如果为0时,那么这个重复将会被忽略.
【示例】
{1’b1,{0{1’b1}}}; // 结果是1’b1
在具体应用时,有时会看到如下这样的示例.
【示例】
`timescale 1 ns / 1 ps `define ONE ‘d1 `define TWO ‘d2 `define THREE ‘d3 module top_tb; reg [8:0] data_out; initial begin data_out = {`ONE + `TWO{2’b01}}; $display(“1st : data_out is %b”,data_out); data_out = {`ONE ? `TWO : `THREE{2’b01}}; $display(“2nd : data_out is %b”,data_out); end endmodule【仿真结果】
1st : data_out is 000010101 2nd : data_out is 000000101从仿真结果可以看到,拼位操作符的优先级是最低的,可参考下表.
除了上述的各种使用注意事项,在使用拼位操作符进行数据处理时还需要注意以下几点:
-
拼位操作后的结果是无符号数;
-
被重复的表达式结果不能是实数(real);
-
`{}和{}是两个不同的运算符,示例如下:
【示例】
logic [7:0] data; // 8bit data = {4’hf,4’h3}; // data是8’hf3 …… int data[4]; // data是个含有4个元素的数组 data = `{1,2,3,4}; // data中每个元素的值分别为1、2、3和4