简体   繁体   中英

VHDL Code MAC Unit - How to avoid overflow by summing up two signed signals without adding additional bits

I want to do an code, which accumulates an input signal. This means the input signal is added to the previous value. This is then the output

library IEEE;
use IEEE.NUMERIC_STD.ALL;
use ieee.std_logic_1164.all

entity adder is
    port(clock : in std_logic;
         ADD_value : in signed(k-1 downto 0));
         Result: out signed(k-1 downto 0));
end adder;

architecture behavioral of adder is


begin
variable acc_value : signed(k-1 downto 0);
    process(clock)
    begin
        if rising_edge(clock) then
            acc_value := acc_value + Add_value;
            Result<=acc_value ;
        end if;
    end process;
end behavioral;

The problem is that both variables are signed. If an overflow occurs, the overflow goes from the k-1 position to the k-1 position, means the sign is destroyed. Per example if i have 01111 with the first "0" as sign, and i add "10" it goes to "10001", which is bitwise right, but as a signed wrong, because it is a negative value

I tried things like acc_value:= resize(acc_value + Result_var,k); or acc_value:= to_signed(acc_value + Result_var,k); but I had the same problem

I want as a result, to keep the data length k in case of an overflow, too. If an overflow occurs, the Result should be set to the maximum possible value in respect to the sign. This means I dont care if there is an overflow, I then only want then a maximum/minimum value

The maximum (minimum in case of negative value) as a kind of saturation. It is possible to come away from the maximum again, since negative values are allowed too.

It makes no sense to accumulate forever. There must a barrier exist, which you could check (and perhaps signal an overflow, if the barrier is exceeded). Your signal acc_value must have the width maximum_bit_width, which represents this barrier (be aware that the signal sum_temp has 1 bit more, see below). Result_var may have still the width k. Then you can code (I changed acc_value from "out" to "buffer" to be able to read it, perhaps you should introduce an intermediate signal and leave acc_value as "out" or use VHDL2008 as suggested):

         acc_value : buffer signed(maximum_bit_width-1 downto 0);
…
    process(clock)
        variable sum_temp : signed(maximum_bit_width downto 0);
    begin
        if rising_edge(clock) then
            sum_temp := acc_value(maximum_bit_width-1)&acc_value + Result_var;
            if sum_temp(maximum_bit_width)=sum_temp(maximum_bit_width-1) then
                acc_value <= sum_temp(maximum_bit_width-1 downto 0);
            else
                if sum_temp(maximum_bit_width)=‘0‘ then
                    acc_value <= (‘0‘, others => ‘1‘);
                else
                    acc_value <= (‘1‘, others => ‘0‘);
                end if;
            end if;
        end if;
    end process;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM