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?
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))