So, in my last school project, I had to implement, in VHDL, an algorithm that calculated the complex average of various sets of values.
We had to use FSMs with external counters to manage the memories' addresses and to manage state changes. So, when I finished a set, I wanted to move from state 3 to state 4, state 4 to state 5 and state 5 to init. This is done using a signal called OlIn (for the memIn counter) and OlOut (for the memOut counter)
entity control is
Port ( clk : in STD_LOGIC;
rst : in STD_LOGIC;
finish: out STD_LOGIC;
op1, op2 : out STD_LOGIC;
muxes : out STD_LOGIC_VECTOR (3 downto 0);
enables : out STD_LOGIC_VECTOR (2 downto 0);
cenO, cenI : out STD_LOGIC;
olIn, olOut : in STD_LOGIC;
we: out STD_LOGIC);
end control;
architecture Behavioral of control is
type fsm_states is (s_init, load, cycle1, cycle2, cycle3, cycle4, cycle5, done);
signal next_state, state: fsm_states;
signal sfinish: STD_LOGIC;
begin
state_reg : process(clk,rst)
begin
if (clk'event and clk='1') then
if(rst = '1') then
state <= s_init;
else
state <= next_state;
end if;
end if;
end process;
state_comb: process(state,sfinish, olIn, olOut)
begin
next_state <= state;
case state is
when s_init =>
next_state <= load;
when load =>
next_state <= cycle1;
when cycle1 =>
next_state <= cycle2;
when cycle2 =>
next_state <= cycle3;
when cycle3 =>
next_state <= cycle4;
when cycle4 =>
if(olIn='1') then
next_state <= cycle5;
else
next_state <= cycle1;
end if;
when cycle5 =>
if(olOut='1') then
next_state <= done;
else
next_state <= s_init;
end if;
when done =>
next_state <= done;
end case;
end process;
process (state,olIn)
begin
case state is
when s_init =>
cenI <= '1';
cenO <= '0';
muxes <= "XXXX";
enables <= "X11";
op1 <= 'X';
op2 <= 'X';
sfinish <= '0';
we <= '0';
when load =>
cenI <= '0';
cenO <= '0';
muxes <= "XXX0";
enables <= "110";
op1 <= 'X';
op2 <= 'X';
sfinish <= '0';
we <= '0';
when cycle1 =>
cenI <= '0';
cenO <= '0';
muxes <= "0001";
enables <= "110";
op1 <= '0';
op2 <= '0';
sfinish <= '0';
we <= '0';
when cycle2 =>
cenI <= '0';
cenO <= '0';
muxes <= "1011";
enables <= "110";
op1 <= '0';
op2 <= '0';
sfinish <= '0';
we <= '0';
when cycle3 =>
cenI <= '1';
cenO <= '0';
muxes <= "X101";
enables <= "010";
op1 <= '1';
op2 <= '0';
sfinish <= '0';
we <= '0';
when cycle4 =>
cenI <= '0';
cenO <= '0';
muxes <= "XXXX";
enables <= "100";
op1 <= 'X';
op2 <= 'X';
sfinish <= '0';
we <= '0';
if(olIn = '1') then
we <= '1';
cenO <= '1';
end if;
when cycle5 =>
cenI <= '0';
cenO <= '1';
muxes <= "XXXX";
enables <= "110";
op1 <= 'X';
op2 <= 'X';
sfinish <= '0';
we <= '0';
if (olIn = '1') then
we <= '1';
cenO<= '1';
cenI <= '1';
end if;
when done =>
cenI <= '0';
cenO <= '0';
muxes <= "XXXX";
enables <= "000";
op1 <= 'X';
op2 <= 'X';
sfinish <= '1';
we <= '0';
end case;
end process;
finish <= sfinish;
end Behavioral;
The way I implemented the memIn counter was like this:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use ieee.numeric_std.all;
entity counter is
generic (N : integer := 4; -- numero de bits do contador global
Ni : integer := 3; -- numero de bits do contador local
I : integer := 0 -- valor inicial dos contadores
);
Port (
clk : in STD_LOGIC;
rst: in STD_LOGIC;
cen : in STD_LOGIC;
ol : out STD_LOGIC;
counter : out STD_LOGIC_VECTOR (N-1 downto 0));
end counter;
architecture Behavioral of counter is
signal counter2: std_logic_vector (Ni-1 downto 0);
signal tmp, i_aux: std_logic_vector (N-1 downto 0);
begin
i_aux<=std_logic_vector(to_unsigned(I, i_aux'length));
process (clk, rst, cen, i_aux, counter2)
begin
if (rst ='1') then
tmp <= i_aux;
counter2 <= i_aux(Ni-1 downto 0);
elsif (clk'event and clk = '1') and (cen = '1') then
ol <= '0';
tmp <= tmp + 1;
counter2 <= counter2 + 1;
end if;
if ( counter2 = "1010" ) then
ol <= '1';
end if;
if ( counter2 = "1011" ) then
ol <= '0';
counter2 <= ( 0 => '1', others => '0');
end if;
end process;
counter <= tmp;
end Behavioral;
but, because the pattern detection occurs outside the process, post-routing simulation fails. If I put the pattern detection inside the process, it always was one cycle early or last too long and I didn't manage to correct it.
The pattern to detect is the number nine in binary (1010), then, the counter sends an Ol signal to control that signals the end of the processing of all the data in a set.
The process in which this detection should occur is in the process that's inside the counter, but the only way I could make it work was outside of that process.
Bit 0 of counter : out doesn't go into the memory (I have to stay in the same memory address for two cycles), so counter should count to Eight (4 memory addresses (1 up to 4) Memory address zero is for preparing data.
How could I have done this better? Should I just put the detection inside the process and tried harder to get a match detector that worked?
Thanks