0

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!

user3303504
  • 525
  • 3
  • 20

2 Answers2

1

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:

for_loop_test_tb.png

(The value for bits and the number of different input values for foo were restricted to provide a waveform easily interpreted.)

  • Hands down the best answer I've ever received! Thorough, to the point, simple and well explained. Thank you so much for your help! Apologies for the coding errors, I made it in a rush as I was late for a train. – user3303504 Apr 20 '16 at 11:45
0

(There are a number of things wrong with the given process : it should probably be clocked, so that it runs on every rising_edge(clk) then there is no need for foo in the sensitivity list. However....)

One approach is a boolean variable, finished which is set to TRUE before entering the for loop.

Any iteration that has not finished (e.g. enters the waitforHigh state or ANY state other than finish) will clear the finished variable ... (optionally, unless it is transitioning to the finish state).

Then, after end loop the next statement if finished then ... will tell you what you want to know.