什么是 `+:` 和 `-:`?

28

+:-:是Verilog/SystemVerilog运算符?何时以及如何使用它们?例如:

logic [15:0] down_vect;
logic [0:15] up_vect;

down_vect[lsb_base_expr +: width_expr]
up_vect  [msb_base_expr +: width_expr]
down_vect[msb_base_expr -: width_expr]
up_vect  [lsb_base_expr -: width_expr]
3个回答

44

那个特定的语法被称为索引部分选择。 当你需要从多位寄存器的变量偏移中选择固定数量的比特时,它非常有用。

这是一个语法示例:

reg [31:0] dword;
reg [7:0] byte0;
reg [7:0] byte1;
reg [7:0] byte2;
reg [7:0] byte3;

assign byte0 = dword[0 +: 8];    // Same as dword[7:0]
assign byte1 = dword[8 +: 8];    // Same as dword[15:8]
assign byte2 = dword[16 +: 8];   // Same as dword[23:16]
assign byte3 = dword[24 +: 8];   // Same as dword[31:24]

这种语法的最大优势在于您可以使用变量作为索引。在Verilog中,普通的选择需要常数。因此,尝试使用类似 dword[i+7:i] 这样的表达式是不允许的。

因此,如果您想使用可变选择来选择特定的字节,则可以使用索引部分选择。

以下是使用变量的示例:

reg [31:0] dword;
reg [7:0] byte; 
reg [1:0] i;

// This is illegal due to the variable i, even though the width is always 8 bits
assign byte = dword[(i*8)+7 : i*8];  // ** Not allowed!

// Use the indexed part select 
assign byte = dword[i*8 +: 8];

4

该操作符的目的是在需要访问总线的一部分时,MSB位和LSB位位置都是变量,但片段的宽度是一个常量值,如下例所示:

bit[7:0] bus_in = 8'hAA;
int lsb = 3;
int msb = lsb+3;  // Setting msb=6, for out bus of 4 bits

bit[3:0] bus_out_bad = bus_in[msb:lsb]; // ILLEGAL - both boundaries are variables
bit[3:0] bus_out_ok  = bus_in[lsb+:3]; // Good - only one variable

只是挑刺一下,那个“好”的例子应该是bus_in[lsb+:4],以便与“坏”的例子相匹配并提取一个4位的子段。 - undefined

3

5.2.1 向量位选择和部分选择寻址

位选择从向量网、向量寄存器、整数或时间变量或参数中提取特定位。位可以使用表达式寻址。如果位选择超出地址范围或位选择为 x 或 z,则引用返回的值应为 x。对于标量、实型或实时变量或参数的位选择或部分选择是非法的。

向量网、向量寄存器、整数或时间变量或参数中的多个连续位组成了部分选择,有两种类型的部分选择:常量部分选择和索引部分选择。向量寄存器或网的常量部分选择采用以下语法:

vect[msb_expr:lsb_expr]

msb_expr和lsb_expr都必须是常量整数表达式。第一个表达式必须比第二个表达式指向更重要的位。

对于向量网络、向量寄存器、整数或时间变量或参数的索引部分选择,使用以下语法:

reg [15:0] big_vect;
reg [0:15] little_vect;
big_vect[lsb_base_expr +: width_expr]
little_vect[msb_base_expr +: width_expr]
big_vect[msb_base_expr -: width_expr]
little_vect[lsb_base_expr -: width_expr]

msb_base_expr和lsb_base_expr应为整数表达式,width_expr应为正常数整数表达式。lsb_base_expr和msb_base_expr可以在运行时变化。前两个例子选择从基数开始并升序的位范围。所选位数等于宽度表达式。后两个例子选择从基数开始并降序的位范围。

任何类型的部分选择都要寻址一系列完全超出网络、寄存器、整数、时间变量或参数的地址范围,或者是“x”或“z”的部分选择,读取时返回" x "值,写入时对存储的数据没有影响。部分超出范围的部分选择在读取时应该返回超出范围的位数的"x"值,并且在写入时只会影响到在范围内的位数。

例如:

reg [31: 0] big_vect;
reg [0 :31] little_vect;
reg [63: 0] dword;
integer sel;

big_vect[ 0 +: 8] // == big_vect[ 7 : 0]
big_vect[15 -: 8] // == big_vect[15 : 8]

little_vect[ 0 +: 8] // == little_vect[0 : 7]
little_vect[15 -: 8] // == little_vect[8 :15]

dword[8sel +: 8] // variable part-select with fixed width*

示例1——以下示例指定由操作数索引寻址的acc向量的单个位:

acc[index]

通过acc的声明部分来确定地址访问的实际位。例如,下一个示例中显示的每个acc声明都会导致索引的特定值访问不同的位:

reg [15:0] acc;
reg [2:17] acc

示例2-下一个示例及其后面的条目说明了位寻址的原则。 代码声明了一个名为vect的8位寄存器,并将其初始化为4。 列表描述了如何寻址该向量的单独位。

reg [7:0] vect;
vect = 4; // fills vect with the pattern 00000100
// msb is bit 7, lsb is bit 0

— If the value of addr is 2, then vect[addr] returns 1.
— If the value of addr is out of bounds, then vect[addr] returns x.
— If addr is 0, 1, or 3 through 7, vect[addr] returns 0.
— vect[3:0] returns the bits 0100.
— vect[5:1] returns the bits 00010.
— vect[ expression that returns x ] returns x.
— vect[ expression that returns z ] returns x.
— If any bit of addr is x or z , then the value of addr is x.

注意1:评估为x或z的部分选择索引可能会被标记为编译时错误。 注意2:超出声明范围的位选择或部分选择索引可能会被标记为编译时错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接