Verilog signed vs unsigned samples and first

titus.andronicus picture titus.andronicus · Jun 11, 2014 · Viewed 41.7k times · Source

Assuming I have a register reg [15:0] my_reg, which contains a 16-bit signed sample:

How do I convert the sample from signed to unsigned? I have read this Wikipedia article, and am aware of the 2-bit complement for signed numbers, but how do I perform this conversion in Verilog efficiently? (I don't know if my_reg is positive or negatve, and it changes in every clock cycle = I receive a new sample on every positive clock edge).

The ultimate goal (to add a little bit of context) is to implement a digital FPGA built-in automatic gain control (AGC).

EDIT: as suggested I have split the two questions in two different posts. See the other one here

Answer

Morgan picture Morgan · Jun 11, 2014

In Verilog a reg contains binary data, signed unsigned are just a matter of interpretation. The bit values stay the same, subtraction and addition are always performed using two's complement.

For example, we can look at a 4 bit value and see how the numbers can be interpreted:

  Binary Unsigned  signed  
  1000          8      -8
  1110         14      -2
  1111         15      -1    
  0001          1       1
  0010          2       2
  0111          7       7

I think you want to calibrate these numbers on to a positive scale, -8 becomes 0, 0 becomes 8, 7 becomes 15. This would be done by adding 1 in to the MSB position. In our 4 bit example:

  Binary   Signed  Addition Unsigned result
  1000         -8  +1000    0000   0
  1110         -2  +1000    0110   6
  1111         -1  +1000    0111   7
  0001          1  +1000    1001   9
  0010          2  +1000    1010   10  
  0111          7  +1000    1111   15

There are some closely related questions:
1. Verilog: how to take the absolute value.
2. Verilog Construction of Two's Complement Comparator.

If your register really does contain signed information then semantically you should define it as :

reg signed [15:0] my_reg;

To absolute the value:

reg signed [15:0] my_reg;
reg        [15:0] my_reg_unsigned;

always @* begin
  if (my_reg < 16'd0) begin
    my_reg_unsigned = -my_reg ;
  end
  else begin
    my_reg_unsigned = my_reg ;
  end
end

If you do not need to absolute it but just want to use that number to drive some thing it is valid to just connect signed to an unsigned, ie:

always @* begin
  my_reg_unsigned = my_reg ;
end

This will copy the bit values, my_reg_unsigned can be interpreted as signed using $signed(my_reg_unsigned)