Devsman
Devsman

Reputation: 498

VHDL ignores statement outside a process

I hope this is in the right place, but since I think it's an issue with syntax instead of actual system design maybe it is.

For some reason I have a statement that is ignored when I leave it outside a process. I can copy/paste the same statement into a process and suddenly it works. But then it has to wait on the clock signal, which messes up the whole thing.

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;

If I simulate it like this, I get this situation that I don't understand:

Notice OPCODE_IN is D but OPCODE(3) is still U

Notice OPCODE_IN is D but OPCODES(3) is still U.

If I move the statement inside the process, it will shift the value of OPCODE_IN into OPCODES(3) but of course it takes another clock cycle which messes up the timing of everything:

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;

Does anybody have any ideas why this is behaving this way?

Upvotes: 2

Views: 2117

Answers (3)

FPGA-guy
FPGA-guy

Reputation: 55

You can express the shift directly and eliminate both the for...loop and the longest static prefix issue.

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

Or, if you have a preference for the loop ...

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;

...though I do not find it very satisfying. The assignment to OPCODES(3) does not have to be inside the clocked portion of the process.

It has an ugliness to it as it requires the extra signal in the sensitivity list and it does not offer any obvious reason for its inclusion as a solution to the static prefix problem.

Upvotes: 2

JHBonarius
JHBonarius

Reputation: 11271

This is one of the quirks where VHDL becomes very counter-intuitive. It is especially confusing since other parallel processing languages don't have it.

Another solution would be to use 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;

Funny enough, in this case OPCODES(I) suddenly is a static expression again. Very consistent, eh? ;)

Upvotes: 1

Staszek
Staszek

Reputation: 951

To sum up answers in the comments:

Process from your first example will create drivers for all signals from the longest static prefix of OPCODES(I), which is OPCODES. So OPCODES(0) will have driver too. But in your process there is no assignment for OPCODES(0), hence it is 'U'.

When you put OPCODES(3) <= OPCODE_IN; in the process, you make assignment, and problem is solved.

When you unroll your loop, the longest static prefix for your assignments, becomes OPCODES(1), OPCODES(2), and OPCODES(3), instead of OPCODES. So you don't have driver for OPCODES(0) any more, and problem is solved again.

Upvotes: 1

Related Questions