0

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

  • What "pattern detection" and which process? I see four processes and can't tell which one you're talking about. –  Nov 11 '15 at 12:52
  • @BrianDrummond Sorry, added that information on the original post. The pattern detection is the detection of number 1010 in the counter component. The process is the process inside the counter component – Filipe Correia Nov 11 '15 at 15:10
  • Why are you synthesizing logic with assignments to 'X'? It implies latches with enables that are combinatorial values of states. Use default assignments before the case statement and don't count on latches. It'll likely improve timing and allow you to use combinatorial 'detector's. Not a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) - the relationship between `ol` and `olIn` and `olOut` isn't shown, nor is the clock speed target, `control` doesn't analyze without a context clause. Don't mix std_logic_arith/unsigned and numeric_std. –  Nov 11 '15 at 16:42
  • @user1155120 ol can be both olIn or olOut, this means that, I connect ol from counterIn to olIn and ol from counterOut to olOut. I didn't put it everything here because it would be too big. I used the 'X' assignments so xilinx uses karnaugh maps to simplify logic the most (instructions given by my teacher). I can put everything needed to make that circuit work here, but I was mostly asking for the best procedure to design a good circuit, not a solution to the problem per se. When I synthesize, it doesn't give me any latches. – Filipe Correia Nov 11 '15 at 21:15

1 Answers1

1

The counter process is steering into dangerous waters; it is part synchronous process and part combinational, and there is virtually no chance of a synthesis result matching the simulation behaviour. This is probably why you report problems with post-route sims.

As a synchronous process, its sensitivity list should be process (clk, rst) and nothing else, and the pattern test should be within the if rising_edge(clk) clause.

HOWEVER it must be written with an understanding of how signal and variable assignments are scheduled. Specifically, if you didn't understand this, you may find things happening a cycle later than expected. Two approaches may help :

  1. If counter2 is a variable, then the comparisons happen on the updated value, and set ol when counter2 = 10.
  2. OR you could simply advance the comparisons a cycle, e.g. if ( counter2 = "1001" ) then so that the flag is set in the same cycle that counter2 becomes 10. This will actually generate faster hardware, since the comparison and increment happen in parallel, operating on registered inputs, rather than performing a comparison on a combinational adder's output.

For an alternative approach, you can eliminate not just the counter process but also the four control signals interconnecting them. I strongly recommend this single-process approach, for smaller, simpler, more reliable code, though it seems to be unpopular in some academic circles.

Community
  • 1
  • 1
  • Ok, I will further analyse your answer and thanks a lot for the input! – Filipe Correia Nov 11 '15 at 21:16
  • @Brian why is it unpopular in some circles? I have used it extensively in my academic projects, and also a couple of professional projects. – wahab Nov 12 '15 at 12:18
  • @wahab : I keep asking that question myself! But there are new VHDL books still being published that seemingly don't "get it" and even regard its advantages as drawbacks. Perhaps they are still arguing the hoary old "Mealy/Moore" controversy? –  Nov 12 '15 at 12:27