std_logic_vector 中的 VHDL 签名数据到未签名数据
VHDL signed data in std_logic_vector to unsigned data
我在 FPGA 板上有一个 ADC (LTC1407A-1),它用 2 的补码符号数据填充 14 位寄存器。我想将此数据转换为无符号的:
- 源数据范围:
-8192 to 8191
- 目标数据范围:
0 to 16383
然而,无论我怎样尝试,我似乎都得不到想要的结果。我目前VHDL寄存器模块的工作代码部分如下:
library IEEE;
use ieee.std_logic_arith.all;
use ieee.std_logic_1164.all;
entity reg10 is
Port ( clk : in STD_LOGIC; --50MHz clock
reset : in STD_LOGIC; --asynchronous reset
i_load : in STD_LOGIC; --load signal
i_data : in STD_LOGIC_VECTOR (13 downto 0); --data signal
o_data : out STD_LOGIC_VECTOR (15 downto 0) --output data
);
end reg10;
architecture Behavioral of reg10 is
signal s_data : STD_LOGIC_VECTOR(9 downto 0);
signal f_data : STD_LOGIC_VECTOR(13 downto 0);
signal t_sign : signed (13 downto 0);
begin
process(clk, reset)
begin
if reset = '1' then
s_data <= "0000000000";
elsif clk'event and clk = '1' then
t_sign <= SIGNED(i_data);
f_data <= STD_LOGIC_VECTOR(t_sign);
s_data <= "00" & f_data(13 downto 6);
end if;
end process;
o_data <= "000010" & s_data(9 downto 0);
end Behavioral;
我进行了大量搜索并找到了很多可以完成转换的示例,但是,我不明白应该采取的正确方法。我曾尝试将 i_data
分配为 signed
、在内部变量之间转换以及许多其他推荐的解决方案,但都无济于事。
signal t_sign : signed (13 downto 0);
f_data <= conv_std_logic_vector(i_data, 14);
代码缓冲不断变化的输入向量,并将数据格式化为输出向量以供 VGA 控制器显示。
感谢帮助。谢谢。
第一个错误是:
use ieee.std_logic_arith.all;
不要那样做。这样做:
use ieee.numeric_std.all;
另一个库已经将 std_logic 视为已签名或未签名。你不应该那样。
然后从 signed to std_logic_vector 转换为 unsigned。例如:
[signal] foo <= unsigned(std_logic_vector(signed(bar)));
然而,在你的情况下,输入已经是 std_logic,所以只需转换为无符号。它应该可以工作,除非您的输入表示是 non-standard。 (即有一个偏移量)。如果它有偏移量,请执行以下操作:
[signal] foo <= unsigned(std_logic_vector(signed(bar)+offset));
N.B。 <=
[信号] 分配在下一个增量 (https://en.wikipedia.org/wiki/Delta_delay) 分配。因此,在一个增量内评估的流程中(即没有等待语句),直到流程结束后才会应用它们。因此,在您的示例中,即使 f_data
由 t_sign
中的数据赋值,但 after t_sign
行被赋值,t_sign
将在进程结束之前不会改变,所以它的改变不会直接影响f_data
。相反,该过程将在下一个 clk
上触发,并且 clk'event and clk = '1'
将分配 f_data
新的处理值 t_sign
。实际上,每个 <=
都会在您的示例中插入一个寄存器。
编辑:
我自己可能会使用强制转换为整数。
foo <= to_unsigned(to_integer(bar)+offset, foo'length);
您的 i_data 的范围是 13 到 0。正如 Brian 提到的,可以通过添加 8192 来完成转换。
8192 是“1_0000_0000_0000”作为 bit_string 表示长度匹配 i_data.
的二进制
这意味着通过加法转换,您只需翻转 MSB 加法,结果就是最长操作数的长度。因为您也在 s_data 作业中进行了截断,所以您只需要 8 个触发器。
对于:
signal s_data: std_logic_vector (7 downto 0);
我们可以将 s_data 分配为:
s_data <= (i_data(13) xor '1') & i_data(12 downto 6);
o_data 赋值变为:
o_data <= "00001000" & s_data;
在不考虑进位的情况下,加法简化为单个 XOR 门以翻转符号,将二进制补码转换为二进制幅度表达式。
f_data 和 t_data 不需要,因为 J.H。 Bonarius 表示除非需要两个额外的流水线阶段。
你也可以问,只引入一个gate delay,到底要不要注册
如果寄存器被淘汰:
o_data <= "00001000" & (i_data(13) xor '1') & i_data(12 downto 6);
您还可以注意到,在任何时候都不会使用 'bits' i_data(5 到 0)。
并且因为在一个输入上具有常量“1”的 XOR 是反转:
o_data <= "00001000" & not i_data(13) & i_data(12 downto 6);
那个运算可以不合逻辑
请注意,不需要算术包,也不需要类型转换(转换在 VHDL 中不准确,类型转换只允许在密切相关的类型之间进行,请参阅 IEEE Std 1076-2008 9.3.6 类型转换)。
如果消除明显不必要的流水线寄存器,您还可以预期综合会优化将 8192 添加到基本相同的结果。在修改原始模型以添加 8192 时,这也意味着其中一些流水线寄存器 'bits' 被优化掉了。
您的设计模型也没有使用 i_load。
我在 FPGA 板上有一个 ADC (LTC1407A-1),它用 2 的补码符号数据填充 14 位寄存器。我想将此数据转换为无符号的:
- 源数据范围:
-8192 to 8191
- 目标数据范围:
0 to 16383
然而,无论我怎样尝试,我似乎都得不到想要的结果。我目前VHDL寄存器模块的工作代码部分如下:
library IEEE;
use ieee.std_logic_arith.all;
use ieee.std_logic_1164.all;
entity reg10 is
Port ( clk : in STD_LOGIC; --50MHz clock
reset : in STD_LOGIC; --asynchronous reset
i_load : in STD_LOGIC; --load signal
i_data : in STD_LOGIC_VECTOR (13 downto 0); --data signal
o_data : out STD_LOGIC_VECTOR (15 downto 0) --output data
);
end reg10;
architecture Behavioral of reg10 is
signal s_data : STD_LOGIC_VECTOR(9 downto 0);
signal f_data : STD_LOGIC_VECTOR(13 downto 0);
signal t_sign : signed (13 downto 0);
begin
process(clk, reset)
begin
if reset = '1' then
s_data <= "0000000000";
elsif clk'event and clk = '1' then
t_sign <= SIGNED(i_data);
f_data <= STD_LOGIC_VECTOR(t_sign);
s_data <= "00" & f_data(13 downto 6);
end if;
end process;
o_data <= "000010" & s_data(9 downto 0);
end Behavioral;
我进行了大量搜索并找到了很多可以完成转换的示例,但是,我不明白应该采取的正确方法。我曾尝试将 i_data
分配为 signed
、在内部变量之间转换以及许多其他推荐的解决方案,但都无济于事。
signal t_sign : signed (13 downto 0);
f_data <= conv_std_logic_vector(i_data, 14);
代码缓冲不断变化的输入向量,并将数据格式化为输出向量以供 VGA 控制器显示。
感谢帮助。谢谢。
第一个错误是:
use ieee.std_logic_arith.all;
不要那样做。这样做:
use ieee.numeric_std.all;
另一个库已经将 std_logic 视为已签名或未签名。你不应该那样。 然后从 signed to std_logic_vector 转换为 unsigned。例如:
[signal] foo <= unsigned(std_logic_vector(signed(bar)));
然而,在你的情况下,输入已经是 std_logic,所以只需转换为无符号。它应该可以工作,除非您的输入表示是 non-standard。 (即有一个偏移量)。如果它有偏移量,请执行以下操作:
[signal] foo <= unsigned(std_logic_vector(signed(bar)+offset));
N.B。 <=
[信号] 分配在下一个增量 (https://en.wikipedia.org/wiki/Delta_delay) 分配。因此,在一个增量内评估的流程中(即没有等待语句),直到流程结束后才会应用它们。因此,在您的示例中,即使 f_data
由 t_sign
中的数据赋值,但 after t_sign
行被赋值,t_sign
将在进程结束之前不会改变,所以它的改变不会直接影响f_data
。相反,该过程将在下一个 clk
上触发,并且 clk'event and clk = '1'
将分配 f_data
新的处理值 t_sign
。实际上,每个 <=
都会在您的示例中插入一个寄存器。
编辑: 我自己可能会使用强制转换为整数。
foo <= to_unsigned(to_integer(bar)+offset, foo'length);
您的 i_data 的范围是 13 到 0。正如 Brian 提到的,可以通过添加 8192 来完成转换。
8192 是“1_0000_0000_0000”作为 bit_string 表示长度匹配 i_data.
的二进制这意味着通过加法转换,您只需翻转 MSB 加法,结果就是最长操作数的长度。因为您也在 s_data 作业中进行了截断,所以您只需要 8 个触发器。
对于:
signal s_data: std_logic_vector (7 downto 0);
我们可以将 s_data 分配为:
s_data <= (i_data(13) xor '1') & i_data(12 downto 6);
o_data 赋值变为:
o_data <= "00001000" & s_data;
在不考虑进位的情况下,加法简化为单个 XOR 门以翻转符号,将二进制补码转换为二进制幅度表达式。
f_data 和 t_data 不需要,因为 J.H。 Bonarius 表示除非需要两个额外的流水线阶段。
你也可以问,只引入一个gate delay,到底要不要注册
如果寄存器被淘汰:
o_data <= "00001000" & (i_data(13) xor '1') & i_data(12 downto 6);
您还可以注意到,在任何时候都不会使用 'bits' i_data(5 到 0)。
并且因为在一个输入上具有常量“1”的 XOR 是反转:
o_data <= "00001000" & not i_data(13) & i_data(12 downto 6);
那个运算可以不合逻辑
请注意,不需要算术包,也不需要类型转换(转换在 VHDL 中不准确,类型转换只允许在密切相关的类型之间进行,请参阅 IEEE Std 1076-2008 9.3.6 类型转换)。
如果消除明显不必要的流水线寄存器,您还可以预期综合会优化将 8192 添加到基本相同的结果。在修改原始模型以添加 8192 时,这也意味着其中一些流水线寄存器 'bits' 被优化掉了。
您的设计模型也没有使用 i_load。