I'm struggling with a VHDL conundrum. Here's some code which should explain what I'm trying to do:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use work.all;
entity forLoopTest is
-- Number of bits known only at compilation
generic(
bits : integer range 1 to 1024; := 256;
);
port(
clk: in std_logic := '0';
-- Single bit inputs from foo
foo: in std_logic_vector(bits-1 downto 0) := (others => '0');
-- Output should be high when all inputs have gone to '1' at some point
bar: out std_logic
);
end forLoopTest;
------------------------------------------------------------------------------------------------------------
architecture implementation of forLoopTest is
-- Create states for finite state machine, where finish implies a '1' has been received
type FSM_states_single is (waitForHigh, finish);
-- Make an array of the states, one for each input bit
type FSM_states_multi is array (bits-1 downto 0) of FSM_states_single;
-- Create signal of states initialised to the waiting condition
signal state : FSM_states_multi := (others => waitForHigh);
begin
process(clk, foo)
-- For each input bit:
for bitNumber in 0 to bits-1 loop
case state(bitNumber) is
-- Whilst waiting, poll the input bit
when waitForHigh =>
-- If it goes high, then switch states
if (foo(bitNumber) = '1') then
state(bitNumber) <= finish;
end if;
-- If input bit has gone high:
when finish =>
-- What is simplest method of setting "bar"?
-- "bar" should be high if and only if all bits have equalled '1' at some point
-- Otherwise it should be '0'
-- Though of dominant setting '0', and submissive setting 'H', but multiple things setting output fails
-- Either explicitly, or only one of them is used, others ignored
end case;
end loop;
end process;
end implementation;
Basically, I am trying to find an optimal method of deducing when all "threads" of the for loop have completed. The above is a hypothetical example to illustrate the point. One method using the above code would be to simply "AND" all of the states. However, I'm not sure how to and an unknown number of variables (pre-compilation). Also I am curious to know what other methods of solving this problem are.
Thanks in advance!
Added the clock and a reset to your process. The reset allows you to clear state.
No bar flip flop, it'd be easy to do, move an if statement.
The case statement was removed because of how bar is derived, evaluating both states isn't necessary:
library ieee;
use ieee.std_logic_1164.all;
-- use ieee.std_logic_arith.all; -- not used
use work.all;
entity forlooptest is
generic (
bits : integer range 1 to 1024 := 256 -- removed ';' 2 places
);
port (
clk: in std_logic;
reset: in std_logic; -- added
foo: in std_logic_vector(bits-1 downto 0) := (others => '0');
bar: out std_logic
);
end entity forlooptest;
architecture foo of forlooptest is
type FSM_states_single is (waitForHigh, finish);
type FSM_states_multi is array (bits-1 downto 0) of FSM_states_single;
signal state : FSM_states_multi := (others => waitForHigh);
begin
FOO_BAR:
process (clk, reset)
variable state_v: FSM_states_multi; -- added
begin -- original missing begin
state_v := state; -- variable can be evaluated after assignment
if reset = '1' then
state_v := (others => WaitForHigh);
elsif rising_edge(clk) then
for bitNumber in 0 to bits-1 loop
if state_v(bitNumber) = waitForHigh and
foo(BitNumber) = '1' then
state_v(bitNumber) := finish;
end if;
end loop;
state <= state_v;
end if;
if state_v = (state_v'range => finish) then
bar <= '1'; -- bar not a FlipFlop move if statement above
else -- preceding end if and add to reset condition for FF
bar <= '0'; -- no latch
end if;
end process;
end architecture;
Making bar a flip flop can be done by moving it's if statement above the preceding end if, removing the else and assignment to '0', and adding bar <= '0' to the reset.
There's also a variable copy of state so any updated bits are available immediately for evaluation. (A signal assignment doesn't take effect immediately while a variable assignment does).
Note the heart of the matter, how to evaluate state (state_v) using an aggregate value with every position set to finish. You can't use an others
here. The number of elements and their type has to be discernable from the aggregate expression as an input to the equality operator.
Adding a small testbench with a limited range of bits:
library ieee;
use ieee.std_logic_1164.all;
entity for_loop_test_tb is
end entity;
architecture fum of for_loop_test_tb is
constant bits: integer range 1 to 1024 := 16;
signal clk: std_logic := '0';
signal reset: std_logic; -- added
signal foo: std_logic_vector(bits-1 downto 0) := (others => '0');
signal bar: std_logic;
begin
DUT:
entity work.forlooptest
generic map (bits => bits)
port map (
clk => clk,
reset => reset,
foo => foo,
bar => bar
);
CLOCK:
process
begin
wait for 5 ns;
clk <= not clk;
if now > 150 ns then
wait;
end if;
end process;
STIMULI:
process
begin
wait for 10 ns;
reset <= '1';
wait for 10 ns;
reset <= '0';
wait for 10 ns;
foo <= x"0FF0";
wait for 10 ns;
foo <= x"0001";
wait for 10 ns;
foo <= x"F002";
wait for 10 ns;
foo <= x"0F00";
wait for 10 ns;
foo <= x"FF00";
wait for 10 ns;
foo <= x"0001";
wait for 10 ns;
foo <= x"00F0";
wait for 10 ns;
foo <= x"F0F0";
wait for 10 ns;
foo <= x"0004";
wait for 10 ns;
foo <= x"CCCC";
wait;
end process;
end architecture;
And that gives:
(The value for bits and the number of different input values for foo were restricted to provide a waveform easily interpreted.)