Rotate left verilog case

2019-04-17 18:34发布

问题:

My task is to write a 16 bit ALU in verilog. I found difficulties when I do the part that needs to rotate the operand and doing the 2's complement addition and subtraction. I know how to work that out by paper and pencil but i cant figure out ways to do it in Verilog. for example: A is denoted as a15 a14 a13 a12 a11 a10 a9 a8 a7 a6 a5 a4 a3 a2 a1 a0 if i am going to rotate 4 bits, the answer would be a11 a10 a9 a8 a7 a6 a5 a4 a3 a2 a1 a0 a15 a14 a13 a12

i tried concatenation but it turns out to be incorrect. need you all help...

回答1:

Why is concatenation incorrect? This should do what you ask.

 assign A_out[15:0] = {A_in[11:0], A_in[15:12]};


回答2:

The following will work using one shifter:

assign A_out = {A_in,A_in} >> (16-shift[3:0]);

When shift is 0 the left A_in is selected. As shift increase the left A_in shifts to the left and the MSBs of the right A_in fills in.

If synthesizing, then you may want to use muxes, as dynamic shift logic tends require more gates. A 16-bit barrel shifter will require 4 levels of 2-to-1 muxes.

wire [15:0] tmp [3:1];
assign tmp[3] = shift[3] ? {  A_in[ 7:0],  A_in[15: 8]} : A_in;
assign tmp[2] = shift[2] ? {tmp[3][11:0],tmp[3][15:12]} : tmp[3];
assign tmp[1] = shift[1] ? {tmp[2][13:0],tmp[2][15:14]} : tmp[2];
assign A_out  = shift[0] ? {tmp[1][14:0],tmp[1][15   ]} : tmp[1];


回答3:

assign A_out = A_in << bits_to_rotate;

Where bits_to_rotate can be a variable value (either a signal or a reg). This will infer a generic shifter using multiplexers, or a barrel shifter, whatever suits better the target hardware. The synthetizer will take care about that.


Oh, well. If you want to rotate instead of shift, the thing is just a bit trickier:

assign A_out = (A_in << bits_to_rotate) | (A_in >> ~bits_to_rotate);


回答4:

The best way I found to do this is finding a pattern. When you want to rotate left an 8 bit signal 1 position (8'b00001111 << 1) the result is 8'b00011110) also when you want to rotate left 9 positions (8'b00001111 << 9) the result is the same, 8'b00011110, and also rotating 17 positions, this reduces your possibilities to next table:

So if you look, the three first bits of all numbers on tale equivalent to rotate 1 position (1,9,17,25...249) are equal to 001 (1).

The three first bits of all numbers on table equivalent to rotate 6 positions (6,14,22,30...254) are equal to 110 (6).

So you can apply a mask (8'b00000111) to determine the correct shifting by making zero all other bits:

reg_out_temp <= reg_in_1 << (reg_in_2 & 8'h07);

reg_out_temp shall be the double of reg_in_1, in this case reg_out_temp shall be 16 bit and reg_in_1 8 bit, so you can get the carried bits to the other byte when you shift the data so you can combine them using an OR expression:

reg_out <= reg_out_temp[15:8] | reg_out_temp[7:0];

So by two clock cycles you have the result. For a 16 bit rotation, your mask shall be 8'b00011111 (8'h1F) because your shifts goes from 0 to 16, and your temporary register shall be of 32 bits.