目录
参考《Verilog 编程艺术》魏家明著
表达式
表达式是用操作符(operator)把操作数(operand)组合起来,并按照操作符的语义计算出结果。
操作符
操作符优先级
单目操作符优先级最高;
表格中行间的操作符优先级按降序排列
表格中行内的操作符具有相同的优先级
可以用括号调整操作符的顺序。
整数
整数可以在表达式中使用:
An unsized, unbased integer (12)
An unsized, based integer ('d12, 'sd12)
A sized, based integer (16'd12, 16'sd12)
在表达式中,对于用不同方式表达的整数有不同的解释
1。An unsized, unbased integer 被当作符号数
2。An unsized, based integer 被当作符号数
3。A sized,signed,based integer 被当作符号数
4。An unsized,unsigned,based integer 被当作无符号数
5。A sized,unsigned,based,integer 被当作无符号数
例如:有两种方式执行“minus 12 divided by 3”注意-12和-'d12具有同样的2的补码位。但是-'d12在表达式中失去了作为符号负数的特性。
integer intA;
intA = -12 / 3; // result is -4
intA = -'d12 / 3; // result is 1431655761
intA = -'sd12 / 3; // result is -4
intA = -4'sd12 / 3; // result is 1;-4'sd12 is the negative of the 4-bit quantity 1100,
// which is -4, -(-4) = 4。
// 属于上边第3种情况,属于符号数,1100第一位被当作负号解释,故其值表示(-4)
算数操作符
+,-,*,/,%,**
1.“/”是除法运算,在做整数除时向零方向舍去小数部分
2.“**”是指数运算
3.“%”取模运算,只可用于整数运算,而其他操作符既可用于整数也可用于实数
例如:在生成时钟的时候,必须选择合适的timescale和precision。当时用 PERIOD/2 计算延时时,必须保证小数不会被舍弃,实际上应该使用 PERIOD/2.0
prameter PERIOD = 15;
initial begin clk <= 0; forever #(PERIOD/2) clk = ~clk; end // Not correct
initial begin clk <= 0; forever #(PERIOD/2.0) clk = ~clk; end // Correct
算数表达式中的regs和integers
1.赋给reg变量或net线网的值被当作unsigned,除非reg变量或net线网被清晰声明成signed。
2.赋给integer,real或realtime变量的值被当作signed。
3.赋给time变量的值被当作unsigned
4.除了赋给real和realtime变量的值,符号数signed都用2的补码形式表示
5.赋给real和realtime变量的值用浮点数表示
6.signed和unsigned之间的转换保持同样的位bit表示。
比较操作符
<,<=,>,>=,===,!==,==,!=
比较操作符的规则如下:
1.它们的比较结果是0(true)或1(false),但是如果操作数中有x或z,而且比较操作不是===和!==,那么结果就是x。
2.==和!=被称为logical equality and logical inequality operators,操作数中的x或z会导致结果为x。
3.===和!==被称为case equality and case inequality operators,操作数中的x或z也会参与比较,所以结果只能为0或1。
4.如果两个操作数中有一个或两个无符号数,那么比较就按照无符号数比较;如果操作数的位长不一样,那么位长小的操作数就需要做零扩展。
5.只有两个操作数都是符号数时,比较才按照符号数比较;如果操作数的位长不一样,那么位长小的操作数就需要先做符号扩展。
6.如果两个操作数中只有一个操作数是实数,那么另一个操作数要先转换成实数,然后再比较。
7.比较操作符比算数操作符的优先级低。
逻辑操作符
&& || !
1.它们的运算结果为0或1,但是当操作数中有x或z时,结果为x
2.优先级次为:!最高,&&次之,||最低
例如:a<size-1 && b!=c && index!=lastone
等价于:(a<size-1) && (b!=c) && (index!=lastone)
位运算操作符
&,|,^,~^,~
归约操作符
归约操作对操作数进行操作然后产生1-bit的结果,包括:&,|,^,~&,~|,~^
移位操作符
逻辑移位:<< 和 >>
算数移位:<<< 和 >>>
移位操作规则:
1/左移操作<< 和 <<<左移相应的位数,空位填0
2/右移操作>> 和 >>>右移相应的位数,但是对于空出的位处理不一样:对于逻辑右移,空出的位填0;对于算数右移,且操作数为unsigned,空出的位填0;对于signed,空出的位填符号位。
3/如果右操作数含有x或z,那么结果为x
4/如果使用 >>> 那么结果的正负是由左操作数决定的。
5/右操作数始终被当作无符号数,而且对结果的正负没有影响
条件操作符
(?:)
需要三个操作数
conditional_expression = expr1 ? expr2 : expr3;
规则:
1/如果expr1为真,那么结果时expr2;
2/如果expr1为假,那么结果时expr3;
3/如果expr1为x或z,那么结果时x;
连接操作符
把一个或多个操作数的位连接起来。没有size的常数不能再连接操作中使用,因为连接操作需要每个操作数的size
例子:{a, b[3:0], w, 3'b101};
等价于:{a, b[3], b[2], b[1], b[0], w, 1'b1, 1'b0, 1'b1};
连接操作还支持复制,复制数应该大于等于0;
{4{w}}; // {w, w, w, w};
{b, 3{a, b}}; // {b, a, b, a, b, a, b};
操作数
表达式中的操作数有不同的形式
1.如果直接以瓦纳征的方式使用net,variable或parameter,就是直接使用它们的名字,那么它们中的所有位都将被当作操作数。
2.如果使用vector net,vector reg,integer,time variable或parameter的1-bit数据,那么就用bit-select操作数。
3.如果使用vector net,vector reg,integer,time variable或parameter的multi-bit数据,那么就用part-select操作数。
4.数组元素的bit-select或part-select可以当作操作数使用。
5.连接操作生成的数据(包括嵌套的连接操作)可以当作操作数使用。
6.函数调用可以当作操作数使用
向量的抽取
向量的抽取(bit-select and part-select)
bit-select规则:
1/bit-select从vector net,vector reg,integer,time variable后parameter中抽取1bit指定的数据。
2/位索引可以是一个表达式。
3/如果位索引超出范围,或者位索引是x或z,那么结果是x
4/对scalar,real variable和realtime variable使用bit-select是非法的。
part-select规则:
1/part-select从vector net,vector reg,integer,time variable后parameter中抽取multi-bit指定的数据。
2/对scalar,real variable和realtime variable使用multi-select是非法的。
3/如果part-select完全超出范围,对于read来说,结果为x;对于write来说,没有意义
4/如果part-select部分超出范围,对于read来说,没有超出的位正常返回,超出的位结果为x;对于write来说,没有超出的位受到影响。
5/part-select有两种类型:constant part-select和indexed part-select
constant part-select使用如下的语法:
vect[msb_expr : lsb_expr]; msb_expr 和 lsb_expr必须是常数
indexed part-select使用如下的语法:
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];
使用part-select:
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]; // == bit_vect[15 : 8]
little_vect[0 +: 8]; // == little_vect[0 : 7]
little_vect[15 -: 8];// == little_vect[8 : 15]
dword[8*sel +: 8];
数组的访问
reg [7 : 0] twod_array[0 : 255][0 : 255]; // 一个二维数组,每个元素是8位宽的
wire threed_array[0:255][0:255][0:7]; // 三维数组,每个元素是1位宽的
towd_array[15][2]; // access one word
towd_array[15][3][3:0]; // accsee lower 4bits of word
towd_array[15][4][0+:4]; // accsee lower 4bits of word
towd_array[2][4][6]; // access bit 6 of word
threed_array[15][2][0]; // legal
threed_array[15][2][3:0];// illegal
字符串
字符串就是一个由8-bit ASCII 构成的序列,它看起来就像一个单一的数值(single numericvalue)。当字符串变量的长度大于它所容纳实际字符串长的时,在赋值时这个变量的左侧就用0填充,这个赋值操作与其他非字符串的赋值类似。
例子:
module string_test;
reg [8*14 : 1] stringvar; // 可以容纳14个字符
initial begin
stringvar = "Hello world";
$dispaly("%s is stored as %h", stringvar, stringvar);
stringvar = {stringvar, "!!!"};
$dispaly("%s is stored as %h", stringvar, stringvar);
end
endmodule
字符串操作:
支持复制,连接和比较。复制通过赋值语句实现,连接通过连接操作符实现,比较通过比较操作符实现。
当在reg vector中操作字符串时,为了保存8-bitASCII序列,reg至少应该有8*n bits,这里n是字符的个数
表达式位长
如果想要在计算表达式时获得一致和谐的结果,那么控制表达式中的位长就很重要。例如,如果两个16-bit的reg变量上做位与操作,那么计算结果就是16-bit。加法操作中,选择16-bit还是17-bit与模型的操作类型有关,也与操作是否要处理进位溢出有关。
reg [15:0] a, b;
reg [15:0] sumA;
reg [16:0] sumB;
sumA = a + b;
sumB = a + b;
表达式位长规则:
1.表达式的位长由表达式中的操作数和表达式所处的上下文决定。
2.自决定表达式就是表达式的位长完全由表达式自己决定,例如用于表示延迟的表达式
3.上下文决定表达式就是表达式的位长既由表达式本身的位长决定,也由这样的事实决定(表达式本身是另一个表达式的一部分)。
4.如果不想让乘法丢失溢出的位,那么就要把结果赋值给一个位长足够大的变量,这样才能够保存运算的最大结果。
符号表达式
系统函数$signed() $unsigned()用于处理表达式的类型转换
例子:
reg [7:0] regA,regB;
reg signed [7:0] regS;
regA = $unsigned(-4); // 8'b11111100
regB = $unsigned(-4'sd4); // 8'b00001100
regS = $signed(4'd1100); // -4
赋值和截断
赋值时,如果RHS的位长大于LHS的位长,那么直接把多出的位丢弃,以匹配LHS的位长。
对于signed 表达式截断可能会改变结果的符号。
例子:
reg [5:0] a;
reg signed [4:0] b;
initial begin
a = 8'hff; // a = 6'h3f
b = 8'hff; // b = 5'h1f
end
reg [0:5] a;
reg signed [0:4] b, c;
initial begin
a = 8'sh8f; // a = 6'h0f;
b = 8'sh8f; // b = 5'h0f;
c = -113; // c = 15;
// 1000_1111 = -113,截断 = 'h0f = 15
end
与x/z比较
综合工具总是把对x或z的比较当作false,这种行为不同于仿真器行为,可能会导致仿真和综合的不一致。所以为了防止这样的不一致,在比较时不要使用这些不关心的值(x/z)
例子:case语句就会导致仿真和综合的不一致,因为仿真器会让 2'b1x 匹配 A=2'b11 或 A = 2'b10.但是综合工具把 2'b1x 当作false,对于2'b0x也同样处理。
case (A)
2'b1x:…
2'b0x:…
default:…
endcase
例子:综合工具总是把B赋值给1,同时发出警告,因为 if(A == 1'bx)总是被当作false
module tset(
input A,
output reg B
);
always @(*) begin
if (A == 1'bx) B = 0;
eslse B = 1;
end
endmodule
标签:操作数,编程,select,操作符,Verilog,bit,reg,表达式
From: https://blog.csdn.net/qq_53922164/article/details/137141270