2
votes

I have a signed accumulator that is used as the index to a BROM LUT. Anyways, I have error checking in my code to detect overflow/underflow events. These are absolutely critical as the application is the AGC of an analog RF front end, so underflowing might cause a booming signal to get maximum gain, blowing up our front end parts. Thus, I need to find a way to properly convert from signed to unsigned. For example, here is what I have so far:

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

process (clk)
    variable preSumV   : signed(accumToLut'left downto 0) := (others => '0');
    variable satCheckV : std_logic_vector(2 downto 0) := (others => '0');
begin
    if rising_edge(clk) then
        if reset = '1' then
            preSumV         := (others => '0');
            satCheckV       := (others => '0');
            overflow        <= '0';
            underflow       <= '0';
            accumToLut      <= (others => '0');
            accumToLutValid <= '0';
        else
            accumToLutValid <= mult.resultValid;

            -- accumulate
            if mult.resultValid = '1' then
                -- perform accum
                preSumV   := preSumV + mult.result(mult.result'left downto mult.result'left-accumToLut'length+1);
                satCheckV := accumToLut(accumToLut'left) & mult.result(mult.result'left) & preSumV(preSumV'left);

                -- check for signed OVF/saturation
                -- A,B is pos, sum neg = overflow so set max pos
                if satCheckV = "001" then
                    overflow <= '1';
                    accumToLut(accumToLut'left) <= '0';
                    accumToLut(accumToLut'left-1 downto 0) <= (others => '1');

                -- A,B is neg, sum pos = underflow so set max neg
                elsif satCheckV = "110" then
                    underflow <= '1';
                    accumToLut(accumToLut'left) <= '1';
                    accumToLut(accumToLut'left-1 downto 0) <= (others => '0');

                -- -- no overflow
                else
                    overflow   <= '0';
                    underflow  <= '0';
                    accumToLut <= preSumV;
                    --accumToLut <= preSumV(preSumV'left-1 downto 0);
                end if;
            end if;
        end if;
    end if;
end process;

accumToLutScaled <= accumToLut(accumToLut'left downto accumToLut'left-GainWordLookup'length+1);
index            <= unsigned(accumToLutScaled);
GainWordLookup   <= c_LinToDbLut(to_integer(accumToLutScaled));

The issue I am experiencing is the signed to unsigned conversion with the signal index. Because this is signed 2's complement, there is no change in the bits. Thus, when I set the accumToLut value to either the max/min signed value, this is not translating to the corresponding max/min unsigned value when I perform index <= unsigned(accumToLutScaled).

To provide an example, assume that preSumV, mult.result, and accumToLut are all 12 bits. When there is an overflow event, accumToLut gets set to 0x7FF or 0b0111111111111 which is valid. However, when I convert to unsigned, I would like this to be FFF, corresponding to the maximum entry in the LUT. Is it best to just add an offset to the index assignment, or is there a cleaner way of doing this?

2
Your code is simply a type conversion, not a numerical conversion. There is no proper conversion for what you want - you'll either have to write a custom conversion for it or just use unsigned in the first place. It looks like what you really want as the index is (accumToLutScaled + 2**12) - Tricky
I see, so to get the desired behavior, I should be performing 2's comp on the result? - nichollsg

2 Answers

0
votes

It sounds like you're looking for absolute value right? You want to know when the magnitude of the result is too large, but you don't care about sign. Use the built-in abs function to do this. I believe the result of abs is an unsigned value, but you might have to cast to unsigned.

index <= unsigned(abs(accumToLutScaled));
0
votes

From @Tricky, adding a fixed offset based on the size of my table, I have fixed this issue:

index <= unsigned(accumToLutScaled + 2**(accumToLutScaled'length - 1))