Verilog: how to take the absolute value
Asked Answered
C

3

2

In verilog I have an array of binary values. How do I take the absolute value of the subtracted values ?

Verilog code:

module aaa(clk);
  input clk;

  reg [7:0] a [1:9];  
  reg [7:0] s [1:9];

  always@(posedge clk)  
  begin
    s[1] = a[1] - a[2];
    s[2] = a[2] - a[3];
    s[3] = a[1] + a[3];
  end
endmodule

I want my s[1] and s[2] values to be always positive. How can I do it in synthesisable verilog?

I have tried using signed reg, but it shows an error.

Comanchean answered 17/10, 2013 at 10:8 Comment(1)
Que is not very clear to me. Can you please provide desired input, output and your error msg with what you tried?Misinform
E
7

Regardless of whether the number is signed or not twos complement is still used which correctly performs addition and subtraction at the bit level.

If a number is to be interpreted as signed the MSB can be used to tell if it is positive (0) or negative (1)

To absolute the number just invert based on the MSB:

reg [31:0] ans    ; // Something else drives this value
reg [31:0] abs_ans; // Absolute version of ans
// invert (absolute value)
always @* begin
  if (ans[31] == 1'b1) begin
    abs_ans = -ans;
  end
  else begin
    abs_ans = ans;
  end
end

NB: using = because it is a combinatorial block, if using a flip-flop (edge trigger) use <= as @TzachiNoy has mentioned.

Evangelia answered 22/10, 2013 at 7:20 Comment(1)
This works with the input and output being the same number of bits, if the sign of the input is signed or unsigned, however the downstream (output) context must be considered unsigned. Maybe this is natural/oblivious because the absolute value is always > 0. Take care that the output of this is not connected to a signed context variable/module. If the output needs to be connected to a signed context, make the output one bit bigger to correctly interpret the result as a signed value.Shoop
A
1

This should do the work:

s[1] <= (a[1]>a[2])?(a[1]-a[2]):(a[2]-a[1]);

Note: you should always use '<=' in clocked always blocks.

Amphicoelous answered 18/10, 2013 at 8:32 Comment(2)
i think he means |a[1]| and |a[2]| and didn't asked for |a[1]-a[2]|Mahmoud
s[1] and s[2] values to be always positive is mathematically incorrect if the answer is not what he meant. |a[1]| - |a[2]| could be negative (and hence s[1]). But it is the same idea either way.Extensible
A
1

Just following the answer from @Morgan, and because I already had a module in my system that performed this operation, here is my contribution:

module Mod(
  input  signed [11:0] i,
  output signed [11:0] o
  );

  assign o = i[11] ? -i : i; // This does all the magic
endmodule

And here is a testbench:

module tb;
  reg signed [11:0] i;
  wire signed [11:0] o;

  Mod M(i,o);

  integer t;

  initial begin
    for (t = -10; t < 10; t = t + 1) begin
      #1
      i <= t;
      $display("i = %d, o = %d", i, o);
    end
  end
endmodule

The output is:

i =     x, o =     x
i =   -10, o =    10
i =    -9, o =     9
i =    -8, o =     8
i =    -7, o =     7
i =    -6, o =     6
i =    -5, o =     5
i =    -4, o =     4
i =    -3, o =     3
i =    -2, o =     2
i =    -1, o =     1
i =     0, o =     0
i =     1, o =     1
i =     2, o =     2
i =     3, o =     3
i =     4, o =     4
i =     5, o =     5
i =     6, o =     6
i =     7, o =     7
i =     8, o =     8
Arriaga answered 31/3, 2016 at 23:8 Comment(3)
A 12-bit number ranges from 2047 to -2048. Won't your verilog code return -2048 for 0x800 since the two compliment of 0x800 is 0x800?Movie
@Movie You answered it yourself. There is no 12 bit positive number corresponding to -2048. Therefore, you need to either make the `o' wire with 13 bits or not set in as unsigned. Either way, bitwise, the result won't change. In verilog, for adition and sign inversion, the signed keyword doesn't change any values, it only affects the display. An aditional wire o2: wire signed [11:0] o2 = o; Will have the same bit values, and will show 2048 as positive, like you want.Arriaga
You can implement a saturating absolute. So -2048 is +2047. Otherwise, you need an extra bit, no matter which answer you choose.Extensible

© 2022 - 2024 — McMap. All rights reserved.