1 逻辑运算符
如果操作数是多位的,若操作数中每一位都是0值则为逻辑0值;若操作数中有1则为逻辑1值。
assign a = 4’b0111 && 4’b1000;
assign b = 4’b0111 || 4’b1000;
assign c = !4’b0111;
等效于:
assign a = 1’b1 && 1’b1;
assign b = 1’b1 || 1’b1;
assign c = !(1’b1);
缩位运算符
对多bit数据
如果A全1,则&A=1,只要含0,则&A=0
如果A含1,则|A=1
含有奇数个1,则^A=1;含有偶数个1,则=0
算术运算符
取余%
input wire signed [10:0] a,b,
outpout wire signed [10:0] mod_test;
assign mod_test = a % b;
Verilog 里的模运算,先把各自符号位去掉运算,然后余数与第一个运算数(被除数)的符号位一致,即都直接算 10 % 3 = 1,然后如果前面是 10 就是 1,前面是 -10 模值就是 -1。
如果不指定signed类型,负数的运算会被当作无符号数运算,从而得到错误的结果。
2 移位运算符
逻辑移位
a >> n; 右移位运算符
a << n; 左移位运算符
a代表要进行移位的操作数,n代表要移几位。
这两种移位运算都用0来填补移出的空位。
左移,低位补0,位宽增加;右移,高位补0,位宽不变,导致低位被截掉。
从原理上很好理解,如果右移不截掉低位,等于没移。
4'b1001<<1 = 5'10010;
4'b1001>>1 = 4'b0100;
上面是对常数的移位,如果是对位宽固定的变量信号移位。左移可能会出现:先是和上面一样运算,然后由于位宽限制,只能保留4位,最高位被截掉。
input [3:0] DATA_IN;
output reg [3:0] DATA_OUT;
output reg [3:0] DATA_OUT2;
always @ (posedge CLK_50M or negedge RST_N)
begin
if(!RST_N) begin
DATA_OUT1 <= DATA_IN;
DATA_OUT2 <= DATA_IN;
end
else begin
DATA_OUT1 <= (DATA_OUT1<<1);
DATA_OUT2 <= (DATA_OUT2>>1);
end
end
因为二进制数左移n位等于原来的数值乘以2的n次方,所以逻辑左移和逻辑右移主要用来进行无符号数的乘法除法。
ps:这种倍数关系只适用于移位后被舍弃的那位不含1的情况,否则会溢出。
比如111>>1=11,7→3.
reg [2:0] a=111,a<<1=110,7→6
算术移位
算术左移和逻辑左移一样
算术右移s位,左边补s位相应的符号位。
input signed [7:0] m; //m=1000_1011
output signed [7:0] n0,n1;
assign n0 = m<<<2; //n0=00101100
assign n1 = m>>>2; //n1=11100010
注:对无符号数进行逻辑移位和算术移位的结果相同。
算术左移和算术右移主要用来进行有符号数的乘除法。疑问:
1000_1011>>2=1110_0010, -11→-98,结果明显不对啊。
原因:计算机中的运算都是基于补码,-117→-30,正确。
循环移位
循环左移:最左边的那一位经过循环左移一位后会被移到最右边去。
实现方法:拼接运算符{}。实际上,除了用移位做乘除法之外,所有的移位操作都能用{}实现,非常灵活。
reg [7:0] shifter;
always(posedge clk)
begin
shifter<={shifter[6:0],shifter[7]};
end