我目前正在尝试实现一个数据路径,它在一个时钟周期内计算以下内容。
该实体的行为架构如下所示。
signal sum_out : std_logic_vector (7 downto 0);
signal shift_out : std_logic_vector (7 downto 0);
process (clock, data_in_a, data_in_b, data_in_c)
begin
if clock'event and clock = '1' then
sum_out <= std_logic_vector(unsigned(data_in_a) + unsigned(data_in_b));
shift_out <= '0' & sum_out(7 downto 1);
data_out <= std_logic_vector(unsigned(data_in_c) - unsigned(shift_out));
end if;
end process;
当我模拟上面的代码时,我确实得到了我期望获得的结果。但是,我在3个时钟周期后得到结果,而不是我想要的结果。模拟波形如下所示。
我还不熟悉实现时序问题的设计。我想知道,如果有办法在一个时钟周期内实现上述计算。如果有,我该如何实施?
答案 0 :(得分:2)
为流程内的信号分配新值时,只有在流程完成执行后,此新值才可用。因此,无论何时读取信号的值,您都将使用进程开始执行时的原始值。
另一方面,varibles的赋值会立即发生,如果您愿意,可以在后续语句中使用新值。
因此,要解决您的问题,只需使用变量而不是信号来实现sum_out
,shift_out
和data_out
。然后只需将data_out
的值复制到实体的输出端口即可。
答案 1 :(得分:2)
不使用变量:
sum <= in_a + in_b;
process (clock)
begin
if rising_edge(clock) then
data_out <= in_c - ('0' & sum(7 downto 1));
end if;
end process;
除了时钟之外的所有声明都是unsigned(7 downto 0);
为什么要使它更复杂?
最初的流水线为3个周期,可能会以更高的时钟速率工作。
编辑以下评论:
我想证明VHDL并非真的必须 详细。
然而,似乎有很多人“教导”VHDL,他们专注于琐碎的元素而完全忽略了大局,所以我会稍微说一下。
VHDL是一种强类型语言,用于防止在类型被误认为彼此时出现的错误,并且(例如)您添加两个大数字并获得否定结果。
它并非如此,您需要在整个地方进行类型转换。 实际上,如果你需要进行大量的类型转换,那么这表明你的设计可能是错误的,现在是时候重新思考,而不是在错误的道路上前进。
代码 - 以任何语言 - 应尽可能简洁明了。
否则很难阅读,并且可能存在漏洞。
类C语言和VHDL之间的最大区别在于:
在C中,使用正确的数据类型,您可以编写sum = in_a + in_b;
它会起作用。使用错误的数据类型,您也可以编写sum = in_a + in_b;
它会编译得很好;它实际上做的是另一回事!这些错误是隐藏的:你需要确定正确的类型,如果你弄错了,你可以做的很少,除了继续测试。
在VHDL中,使用正确的类型,您可以编写sum <= in_a + in_b;
并且使用了错误的类型,编译器会强制你编写类似sum <= std_logic_vector(unsigned(in_a) + unsigned(in_b));
的东西,这些东西很难看,但是(可能:见注1)仍能正常工作。
所以回答这个问题:我如何决定使用unsigned
或std_logic_vector
?
我看到我需要三个输入和一个输出。我可以只是让它们std_logic_vector
但我停下来问:它们代表什么?
号。
他们可以消极吗?不是根据我对规范的解读(你的问题)。
所以,无符号数......(注1)
我需要对它们进行非算术运算吗?是的,有一个转变。(注2)
所以,numeric_std.unsigned
与std_logic_vector
相关,而不是natural
只是一个整数。
现在你无法完全避免类型转换。编码标准可能会施加限制,例如“所有顶级端口必须为std_logic_vector
”,并且您必须实施要求的外部实体规范;用于类型转换的中间信号有时比替代方案更清晰,例如, in_a <= unsigned(data_in_a);
或者,如果您从同一个内存中获取上述指令,字符和数字,您可能会认为内存内容必须为std_logic_vector
,因为不只包含数字。但是选择正确的转换类型的地方,你会发现90%的类型转换消失了。把它作为设计指南。
(注1:但如果C&lt;(A + B)/ 2会发生什么?应该对data_out进行签名?即使按照这些思路思考也可能出现std_logic_vector隐藏的错误......
正确的答案取决于未知数,包括data_out的目的:是否真的应该是无符号的,例如一个内存地址,你可能想标记一个错误,而不是让它签名)
(注2:没有一个不能翻译的合成工具
signal a : natural; ... x <= a/2
进入右移,natural
也会有效,除非有其他理由选择无符号。很多人似乎仍然被教导整数是不可合成的,那只是错误。)
答案 2 :(得分:2)
使用信号执行此操作只需仅注册链中的最后一个元素(data_out)。这个分析,我没有写一个测试台来验证模拟。
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity signal_single_clock is
port (
signal clock: in std_logic;
signal data_in_a: in std_logic_vector(7 downto 0);
signal data_in_b: in std_logic_vector(7 downto 0);
signal data_in_c: in std_logic_vector(7 downto 0);
signal data_out: out std_logic_vector(7 downto 0)
);
end entity;
architecture behave of signal_single_clock is
signal sum_out : std_logic_vector (7 downto 0);
signal shift_out : std_logic_vector (7 downto 0);
begin
sum_out <= std_logic_vector(unsigned(data_in_a) + unsigned(data_in_b));
shift_out <= '0' & sum_out(7 downto 1);
single_reg:
process (clock)
begin
if clock'event and clock = '1' then
data_out <= std_logic_vector(unsigned(data_in_c) - unsigned(shift_out));
end if;
end process;
end architecture;