1.无符号移位
1.1.基本设计
我们在进行Verilog代码设计时经常会用到移位运算,对于无符号运算,我们只需要使用移位运算符("<<“和”>>")就能够实现移位的功能,这个很容易理解。
如无符号左移时,接收寄存器要比源寄存器多出对应移位位宽。
reg [3:0] reg1;
reg [5:0] reg2;
always@(posedge clk)
reg2 <= reg1 << 2;//左移两位,reg2比reg1多出两位。
同理对于无符号右移时,只需要减少对应位宽就行。
reg [3:0] reg1;
reg [2:0] reg2;
always@(posedge clk)
reg2 <= reg1 >> 1;//右移1位,reg2比reg1减少1位。
1.1.易错
有的时候移位的位数可能是从别的电路传过来的。比如下面的:
wire [1:0] a,b;
assign a = 2'd1;
assign b = 2'd1;
reg [3:0] reg1;
reg [9:0] reg2;
always@(posedge clk)
reg2 <= reg1 << (a+b+3'd4);
这样写,一般是没有问题的,但是在一些大型电路中,就可能会存在移位位数发生错误的问题,导致移位的位数不能按照我们所预期的结果去移位。
建议代码这样写:
wire [1:0] a,b;
assign a = 2'd1;
assign b = 2'd1;
wire [4:0] shift;
assign shift = a+b+3'd4;
reg [3:0] reg1;
reg [9:0] reg2;
always@(posedge clk)
reg2 <= reg1 << shift ;
或者把移位内部的表达式中的数据表示成integer,即32位位宽的形式。(3’d4直接改为4)
always@(posedge clk)
reg2 <= reg1 << (a+b+4);
不过最好写成上面第一种建议,以免造成不必要的资源浪费。
2.有符号算术移位
2.1.基本设计
既然是使用了算术移位了,那么肯定是涉及到有符号数的运算了,那就不要再把寄存器定义成无符号数了。把上面的代码改为有符号数,移位符号改为算术移位,抄下来就行了。
左移:
reg signed [3:0] reg1;
reg signed [5:0] reg2;
always@(posedge clk)
reg2 <= reg1 <<< 2;//左移两位,reg2比reg1多出两位。
右移:
reg signed [3:0] reg1;
reg signed [2:0] reg2;
always@(posedge clk)
reg2 <= reg1 >>> 1;//右移1位,reg2比reg1减少1位。
说明:在进行设计的时候,有符号运算就写成服务于有符号运算的运算符和数据类型定义,无符号就写成服务于无符号运算的运算符和数据类型定义。如果乱写,会很麻烦,建议不要乱搞,否则会浪费很多时间。