shizuka
shizuka

Reputation: 1

VHDL: issues with adding and subtracting

What issues could I run into with this code? I was thinking that there could be an issue if the result from the addition is bigger than what 15 bits can represent (32767), or if I get a negative number in the subtraction.

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
use ieee.numeric_std.all;

entity test is
    port(   input:  in std_logic_vector(14 downto 0);
            sel : out boolean;
            output: out std_logic_vector(14 downto 0));
end test;


architecture test of test is

constant first : integer := 1050;
constant second : integer := 33611;

begin

 output <= input - first;
 output <= input + second;
 sel <= input < first;

end test;

Upvotes: 0

Views: 10294

Answers (2)

user1818839
user1818839

Reputation:

The primary issue you have is that the design intent is not communicated so it is impossible to distinguish correct from incorrect results - in that sense, whatever it does must be right!

I differ from David's opinion in one respect : where he says "std_logic_vector is an unsigned representation" I suggest that std_logic_vector is neither signed nor unsigned; it is just a bag of bits. If it happens to follow unsigned rules, that's an accident of the set of libraries you have included.

Instead, I would delete the non-standard libraries:

use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;

and use exclusively the standard libraries:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

Then - if the input and output ports are meant to represent unsigned numbers, the best thing to do is say so...

port(   input  : in unsigned(14 downto 0);
        sel    : out boolean;
        output : out unsigned(14 downto 0));

(If you are not allowed to change the port types, you can use unsigned signals internally, and type convert between them and the ports.)

Now as regards the expressions, they may overflow (and in the case of "second" obviously will!).

In simulation, these overflows OUGHT to be reported as arithmetic errors. (Note : at least one simulator runs with overflow checks off as the default setting! Just dumb...)

As the designer, you decide what the correct semantics for overflows are:

  • They represent bugs. Simulate with overflow checks enabled, detect and fix the bugs.
  • They are permitted, and e.g. negative numbers represent large positive numbers. Express this in the code, e.g. as output <= (input - first) mod 2**output'length; Now anyone reading the code understands that overflow is allowed, and simply wraps.
  • Overflow should saturate to the positive or negative limit. Signal this by writing output <= saturate(input - first); I'll leave writing the Saturate function as an exercise...

Upvotes: 2

user1155120
user1155120

Reputation:

The adding operators "+" and "-" are performed bit wise - std_logic_vector is an array type with a base element type of std_ulogic which represents 'bits' as a multi level value system that includes meta values. Their result is bounded by the longer of the two operands. (They don't overflow).

See the source for package std_logic_unsigned:

function "+"(L: STD_LOGIC_VECTOR; R: STD_LOGIC_VECTOR) return STD_LOGIC_VECTOR is
        -- pragma label_applies_to plus
        constant length: INTEGER := maximum(L'length, R'length);
        variable result  : STD_LOGIC_VECTOR (length-1 downto 0);
    begin
        result  := UNSIGNED(L) + UNSIGNED(R);-- pragma label plus
        return   std_logic_vector(result);
    end;

Which uses the unsigned add from std_logic_arith:

  function "+"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED is
    -- pragma label_applies_to plus
    -- synopsys subpgm_id 236
    constant length: INTEGER := max(L'length, R'length);
    begin
    return unsigned_plus(CONV_UNSIGNED(L, length),
                 CONV_UNSIGNED(R, length)); -- pragma label plus
    end;

An this uses unsigned_plus also found in std_logic_arith:

function unsigned_plus(A, B: UNSIGNED) return UNSIGNED is
variable carry: STD_ULOGIC;
variable BV, sum: UNSIGNED (A'left downto 0);

-- pragma map_to_operator ADD_UNS_OP
-- pragma type_function LEFT_UNSIGNED_ARG
    -- pragma return_port_name Z

begin
if (A(A'left) = 'X' or B(B'left) = 'X') then
        sum := (others => 'X');
        return(sum);
end if;
carry := '0';
BV := B;

for i in 0 to A'left loop
    sum(i) := A(i) xor BV(i) xor carry;
    carry := (A(i) and BV(i)) or
        (A(i) and carry) or
        (carry and BV(i));
end loop;
return sum;
end;

std_logic_vector is an unsigned representation, there is no concept of negative numbers, it's a bag of bits. If you want to signify signed operations you should be using package numeric_std, and either type convert or use operands for your relational and adding operators that are type signed.

That being said you'll get the same answers using std_logic_vector with Synopsys's std_logic_unsigned package or unsigned with the IEEE numeric_std package.

(And your last two use clauses aren't needed by the code you show).

And the reason you don't need a use clause making packages numeric_std or std_logic_arith visible is because you aren't using signed or unsigned types and package std_logic_unsigned has it's own use clause for std_logic_arith and otherwise has declarations for everything you're using in your design specification ("+", "-" and "<").

Upvotes: 0

Related Questions