Verilog 提供了移位运算符方便移位操作,移位操作符有四种分别是逻辑左移<<,逻辑右移>> ,算术左移<<<,算术右移>>>。移位操作符是双目操作数运算符。
1. 逻辑左移<<
将左操作数按照右操作数(RHS) 指定的位数左移,左操作数移出的位数丢弃,右边补零;
例:
wire [7:0] a,b;
assign a = 7;
assign b = a << 3;
由于a的2进制数是8’b0000_0111, 左移三位后的数值是8’b0011_1000; 因此b的值为8’b0011_1000。
在有效位移出之前相当于乘以23 。
2. 逻辑右移>>
将左操作数按照右操作数(RHS) 指定的位数右移,左操作数移出的位数丢弃,左边补零;
例:
wire [7:0] a,b;
assign a = 31;
assign b = a >> 3;
由于a的2进制数是8’b0001_1111, 右移三位后的数值是8’b0000_0011; 因此b的值为8’b0000_0011,十进制3。
相当于除以23 取整。
例:
设计文件 logic_shift.v
module logic_shift
(
input [7:0] a,b,
output [15:0] c,d
);
assign c = a << b;
assign d = a >> b;
endmodule
仿真文件tb.v
`timescale 1ns/1ps
module tb
(
);
reg [7:0] a, b;
wire [15:0] c;
wire [15:0] d;
initial
begin
a = 'b0;
b = 'b0;
#10
a = 'd15;
b = 'd3;
#10
a = 'd31;
b = 'd4;
end
logic_shift logic_shift_dut
(
.a (a),
.b (b),
.c (c),
.d (d)
);
endmodule
Modelsim 仿真波形

从上图可以看出当a==8’b0001_1111,且左移4位时,主要c的位宽足够宽,左移时并没有将溢出的位数丢弃。可见在左移前,右边的变量会根据赋值语句左边的变量自动调整宽度。
3. 算术左移 <<<
算术左移将被移位的操作数左移指定的位数,左边移出的位数丢弃(注意赋值语句位宽调整),右边补零。除了被移位的操作数按有符号数,其它与<<几乎没有差别。
4. 算术右移 >>>
算术右移将被移位的操作数右移指定的位数,右边移出的位数丢弃(注意赋值语句位宽调整),左边补符号位。一般有符号数的最高位(2进制)为符号位,因此右移时,符号位在左边不断复制并右移。
例:
wire signed [7:0] a;
wire signed [7:0] c;
assign c = a >>> 3;
则c 的值实际为 {a[7],a[7],a[7],a[7:3]};
要实现算术右移的结果,被移位的操作数必须定义为有符号数,如:
wire signed [7:0] a; 否则其结果与>>一致。
例:
设计文件 arith_shift.v:
module arith_shift
(
input signed [7:0] a,b,
output signed [3:0] test,
output signed [15:0] c,d
);
assign test = a <<< b;
assign c = a <<< b;
assign d = a >>> b;
endmodule
仿真文件 tb.v
`timescale 1ns/1ps
module tb
(
);
reg [7:0] a, b;
wire [3:0] test;
wire [15:0] c;
wire [15:0] d;
initial
begin
a = 'b0;
b = 'b0;
#10
a = 'd15;
b = 'd3;
#10
a = 'd31;
b = 'd4;
#10
a = -'d3;
b = 'd4;
#10
b = 'd6;
#10
b = 'd8;
#10
b = 'd10;
#10
b = 'd11;
#10
b = 'd12;
#10
b = 'd13;
#10
b = 'd14;
#10
b = 'd15;
#10
b = 'd16;
end
arith_shift arith_shift_dut
(
.a (a),
.b (b),
.test (test),
.c (c),
.d (d)
);
endmodule
Modelsim 仿真波形


从上图可以看出,除了复制符号位扩展,算术左移与逻辑左移几乎没有区别,右移自动填充符号位。
对应视频:
学习本篇文章后有几点收获,1、逻辑左移<>,代表除以2的幂次方;3、在左移前,右边的变量会根据赋值语句左边的变量自动调整宽度;4、算术右移 >>>,右边移出的位数丢弃(注意赋值语句位宽调整),左边补符号位;5、赋值语句,当算数移位中的位宽调整时,当左边操作数位宽右边操作数位宽时,右边操作数先扩展符号位,与左边操作数位宽对齐,然后再进行移位。
纠正:1、逻辑左移,代表乘以2的幂次方;2、逻辑右移,代表除以2的幂次方;3、算数右移,左边补充符号位(注意赋值语句位宽调整);4、赋值语句,当左边操作数位宽大于右边操作数位宽时,右边操作数先扩展符号位,与左边操作数位宽对齐,然后再进行移位;当左边操作数位宽小于右边操作数位宽时,右边操作数先进行移位,最后截取左边操作数位宽长度;