我在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控制器显示。
帮助表示感谢。感谢。
答案 0 :(得分:1)
你的i_data的范围是13 downto 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门,将符号转换为二进制补码为二进制幅度表达式。
J.H.不需要f_data和t_data。除非需要两个额外的管道阶段,否则Bonarius表示。当你只引入一个门延迟时,你也可以询问是否需要注册。
如果寄存器被删除:
o_data <= "00001000" & (i_data(13) xor '1') & i_data(12 downto 6);
你还可以注意到,在任何时候都没有使用'bit'i_data(5 downto 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时,这也意味着某些流水线寄存器“位”会被优化掉。
您的设计模型也不使用i_load。
答案 1 :(得分:0)
第一个错误是:
use ieee.std_logic_arith.all;
不要这样做。这样做:
use ieee.numeric_std.all;
另一个库已将std_logic视为已签名或未签名。你不应该那样想。 然后从signed转换为std_logic_vector到unsigned。 e.g:
[signal] foo <= unsigned(std_logic_vector(signed(bar)));
但是,在你的情况下,输入已经是std_logic,所以只需转换为unsigned。它应该工作,除非您的输入表示是非标准的。 (即有偏差)。如果它有偏移量,请执行以下操作:
[signal] foo <= unsigned(std_logic_vector(signed(bar)+offset));
<强> N.B。 <=
[signal]分配在下一个delta(https://en.wikipedia.org/wiki/Delta_delay)处分配。因此,在一个delta内评估的进程(即没有等待语句)中,直到进程结束后才会应用它们。因此,在您的示例中,即使f_data
中的数据分配了t_sign
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);