在 VHDL 中正确地从有符号转换为无符号
Convert from signed to unsigned in VHDL properly
我有一个带符号的累加器,用作 BROM LUT 的索引。无论如何,我在我的代码中进行了错误检查以检测 overflow/underflow 事件。这些绝对至关重要,因为应用是模拟 RF 前端的 AGC,因此下溢可能会导致蓬勃发展的信号获得最大增益,从而炸毁我们的前端部件。因此,我需要找到一种方法来正确地从有符号转换为无符号。例如,这是我目前拥有的:
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));
我遇到的问题是信号 index
的有符号到无符号转换。因为这是带符号的 2 的补码,所以位没有变化。因此,当我将 accumToLut 值设置为 max/min 有符号值时,当我执行 index <= unsigned(accumToLutScaled)
.
时,这不会转换为相应的 max/min 无符号值
举个例子,假设preSumV
、mult.result
、accumToLut
都是12位。当发生溢出事件时,accumToLut 被设置为有效的 0x7FF
或 0b0111111111111
。但是,当我转换为无符号时,我希望它是 FFF
,对应于 LUT 中的最大条目。最好只为 index
赋值添加一个偏移量,还是有更简洁的方法?
听起来您正在寻找绝对价值,对吗?你想知道什么时候结果的量级太大,但你不关心符号。使用内置的 abs
函数来执行此操作。我相信 abs 的结果是一个无符号值,但您可能必须转换为无符号。
index <= unsigned(abs(accumToLutScaled));
来自@Tricky,根据我table的大小添加固定偏移量,我已经解决了这个问题:
index <= unsigned(accumToLutScaled + 2**(accumToLutScaled'length - 1))
我有一个带符号的累加器,用作 BROM LUT 的索引。无论如何,我在我的代码中进行了错误检查以检测 overflow/underflow 事件。这些绝对至关重要,因为应用是模拟 RF 前端的 AGC,因此下溢可能会导致蓬勃发展的信号获得最大增益,从而炸毁我们的前端部件。因此,我需要找到一种方法来正确地从有符号转换为无符号。例如,这是我目前拥有的:
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));
我遇到的问题是信号 index
的有符号到无符号转换。因为这是带符号的 2 的补码,所以位没有变化。因此,当我将 accumToLut 值设置为 max/min 有符号值时,当我执行 index <= unsigned(accumToLutScaled)
.
举个例子,假设preSumV
、mult.result
、accumToLut
都是12位。当发生溢出事件时,accumToLut 被设置为有效的 0x7FF
或 0b0111111111111
。但是,当我转换为无符号时,我希望它是 FFF
,对应于 LUT 中的最大条目。最好只为 index
赋值添加一个偏移量,还是有更简洁的方法?
听起来您正在寻找绝对价值,对吗?你想知道什么时候结果的量级太大,但你不关心符号。使用内置的 abs
函数来执行此操作。我相信 abs 的结果是一个无符号值,但您可能必须转换为无符号。
index <= unsigned(abs(accumToLutScaled));
来自@Tricky,根据我table的大小添加固定偏移量,我已经解决了这个问题:
index <= unsigned(accumToLutScaled + 2**(accumToLutScaled'length - 1))