Reputation: 498
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 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
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
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
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