-2

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...

Ruka Tsoi
  • 45
  • 2
  • 3
  • 12
  • 1
    Try searching for a **barrel shifter**: http://stackoverflow.com/search?q=[verilog]+barrel+shifter – Greg Jan 18 '14 at 02:17
  • Possible duplicate of [Verilog Barrel Shifter](http://stackoverflow.com/questions/7543592/verilog-barrel-shifter) – bummi Feb 21 '16 at 07:29

4 Answers4

5

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];
Greg
  • 18,111
  • 5
  • 46
  • 68
  • Isn't that backwards? It looks to me like the shift operator binds to the right `A_in` which reduces its length. If `shift` is 0, then shifting the right `A_in` by `regsize - shift` bits will shift regsize bits which leaves a 0 bit long expression which the concat operator fills with an implicitly truncated left `A_in` leaving us `A_in`. If `shift` is 1 to regsize, shifting the right `A_in by `regsize - shift` bits will leave `shift` bits on the right so the left `A_in` only fills `regsize - shift` bits resulting in a overall left rotation by `shift` bits. – James Deng Aug 04 '17 at 08:48
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);
mcleod_ideafix
  • 11,128
  • 2
  • 24
  • 32
  • "<<" or ">>" is for shifting, aren't they? if i am gonna use this, will it duplicate the shift right or shift left function? – Ruka Tsoi Jan 19 '14 at 14:04
  • Yes, they are exactly for that purpose. When you use these operators with a constant on the right side of the expression, they behave the same as the concatenation operator approach (and in fact, they are sinthesized as if concatenation operator would be used). The good thing about these operators is that you can put a variable expression on the right side, and then, the synthesizer will infer a proper (usually barrel) shifter. – mcleod_ideafix Jan 19 '14 at 14:32
  • 9
    This is close, but I don't think the `~` there is the right operator. If you want to rotate left by 1, you need to <<1 and >>15. `~4'b0001 = 4'b1110 (14)`. Should be `>>(16-bits_to_rotate)`? – Tim Jan 19 '14 at 16:18
  • or (~bits_to_rotate +1) – James Deng Aug 04 '17 at 08:53
2

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

 assign A_out[15:0] = {A_in[11:0], A_in[15:12]};
Tim
  • 35,413
  • 11
  • 95
  • 121
  • 1
    actually that is an example. in the lab, the number of bits to be rotated is random and i tried to type something like assign A_out[15:0] = {A_in[15-n:0], A_in[15:15-n+1]}; the compiler said it is out of bound. and i dont know how to solve – Ruka Tsoi Jan 19 '14 at 09:47
  • Yes, variable part select is not legal in that way. – Tim Jan 19 '14 at 16:12
0

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:

PATTERN_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.

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116