组合逻辑时序

时间:2013-11-24 17:44:00

标签: hardware signal-processing vhdl

我目前正在尝试实现一个数据路径,它在一个时钟周期内计算以下内容。

  • 输入A和B并添加它们。
  • 将加法结果向右移一位。 (除以2)
  • 从另一个输入C中减去移位的结果。

该实体的行为架构如下所示。

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个时钟周期后得到结果,而不是我想要的结果。模拟波形如下所示。

Simulation Waveform

我还不熟悉实现时序问题的设计。我想知道,如果有办法在一个时钟周期内实现上述计算。如果有,我该如何实施?

3 个答案:

答案 0 :(得分:2)

为流程内的信号分配新值时,只有在流程完成执行后,此新值才可用。因此,无论何时读取信号的值,您都将使用进程开始执行时的原始值。

另一方面,varibles的赋值会立即发生,如果您愿意,可以在后续语句中使用新值。

因此,要解决您的问题,只需使用变量而不是信号来实现sum_outshift_outdata_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)仍能正常工作。

所以回答这个问题:我如何决定使用unsignedstd_logic_vector

我看到我需要三个输入和一个输出。我可以只是让它们std_logic_vector但我停下来问:它们代表什么?

号。

他们可以消极吗?不是根据我对规范的解读(你的问题)。

所以,无符号数......(注1)

我需要对它们进行非算术运算吗?是的,有一个转变。(注2)

所以,numeric_std.unsignedstd_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;