VHDL 忽略进程外的语句

VHDL ignores statement outside a process

我希望这是在正确的地方,但因为我认为这是语法问题而不是实际系统设计问题,所以可能是。

出于某种原因,当我将它留在进程之外时,我有一个语句被忽略了。我可以 copy/paste 将相同的语句放入一个进程中,然后它突然起作用了。但随后它必须等待时钟信号,这就把整个事情搞砸了。

architecture CU of CONTROL_UNIT is
    type OPCODE_ARRAY is array(3 downto 0) of std_logic_vector(3 downto 0);
    signal OPCODES : OPCODE_ARRAY;
begin
    OPCODES(3) <= OPCODE_IN; --problem statement!
    process(CLK)
    begin
        if rising_edge(CLK) then
            for I in 0 to 2 loop
                OPCODES(I) <= OPCODES(I + 1);
            end loop;
        end if;
    end process;
    --more code
end CU;

如果我这样模拟,我会得到这种我不明白的情况:

注意 OPCODE_IN 是 D 但 OPCODES(3) 仍然是 U。

如果我在进程中移动语句,它会将 OPCODE_IN 的值转移到 OPCODES(3) 中,但当然它需要另一个时钟周期,这会打乱所有的时间:

architecture CU of CONTROL_UNIT is
    type OPCODE_ARRAY is array(3 downto 0) of std_logic_vector(3 downto 0);
    signal OPCODES : OPCODE_ARRAY;
begin
    process(CLK)
    begin
        if rising_edge(CLK) then
            for I in 0 to 2 loop
                OPCODES(I) <= OPCODES(I + 1);
            end loop;
            OPCODES(3) <= OPCODE_IN; --problem statement!
        end if;
    end process;
    --more code
end CU;

有人知道为什么会这样吗?

在评论中总结答案:

第一个示例中的过程将为来自最长静态前缀 OPCODES(I) 的所有信号创建驱动程序,即 OPCODES。所以 OPCODES(0) 也会有驱动程序。但是在您的过程中没有为 OPCODES(0) 赋值,因此它是 'U'.

当你把OPCODES(3) <= OPCODE_IN;放在进程中时,你进行赋值,问题就解决了。

展开循环时,分配的最长静态前缀变为 OPCODES(1)OPCODES(2)OPCODES(3),而不是 OPCODES。所以你没有OPCODES(0)的驱动了,问题又解决了。

这是 VHDL 变得非常 counter-intuitive 的怪癖之一。它特别令人困惑,因为其他并行处理语言没有它。

另一个解决方案是使用 generate-statement.

architecture CU of CONTROL_UNIT is
    type OPCODE_ARRAY is array(3 downto 0) of std_logic_vector(3 downto 0);
    signal OPCODES : OPCODE_ARRAY;
begin
    OPCODES(3) <= OPCODE_IN; --problem statement!
    some_label: for I in 0 to 2 generate
        OPCODES(I) <= OPCODES(I + 1) when rising_edge(clk);
    end generate;
    --more code
end architecture;

有趣的是,在这种情况下 OPCODES(I) 突然又是一个静态表达式。非常一致,嗯? ;)

您可以直接表示移位,同时消除for...loop和最长静态前缀问题。

process(CLK)
begin
    if rising_edge(CLK) then
        OPCODES <= OPCODE_IN & OPCODES(3 downto 1);
    end if;
end process;

或者,如果您喜欢循环...

architecture CU of CONTROL_UNIT is
    type OPCODE_ARRAY is array(3 downto 0) of std_logic_vector(3 downto 0);
    signal OPCODES : OPCODE_ARRAY;
begin
    process(CLK, OPCODE_IN)
    begin
        OPCODES(3) <= OPCODE_IN;
        if rising_edge(CLK) then
            for I in 0 to 2 loop
                OPCODES(I) <= OPCODES(I + 1);
            end loop;
        end if;
    end process;
    --more code
end CU;

...虽然我觉得不是很满意。对 OPCODES(3) 的赋值不必在进程的时钟部分内。

它有一个丑陋之处,因为它需要敏感列表中的额外信号,并且没有提供任何明显的理由将其作为静态前缀问题的解决方案。