0

I'm having trouble with a counter update in my FSM. I have a counter being incremented inside a state: the state must change when the counter hits a constant value N. I try to slim down the code to a minimum example.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity int32_ctrlFSM_debug is 
 port (
  clk      : in std_logic;
  reset    : in std_logic;
  trigger  : in std_logic
 );
end int32_ctrlFSM_debug;

architecture arch of int32_ctrlFSM_debug is
type state_type is (state_1, state_2);
constant N           : integer := 4;
signal counter_reg   : std_logic_vector(N - 1 downto 0);
signal counter_next  : std_logic_vector(N - 1 downto 0);
signal state_reg     : state_type;
signal state_next    : state_type;


begin
-- FSMD state & data registers
process(clk, reset)
begin
  if reset = '1' then
   state_reg    <= state_1;
   counter_reg  <= (others => '0');


 elsif (clk'event and clk = '1') then
   state_reg   <= state_next;
   counter_reg <= counter_next;

 end if;
end process;
-- next-state logic & data path
process (state_reg, trigger)
begin
-- default values
state_next    <= state_reg;
counter_next  <= counter_reg;

case state_reg is

  when state_1 =>
    if trigger = '1' then
      counter_next <= std_logic_vector(unsigned(counter_reg) + 1);
      if unsigned(counter_next) = N-1 then
        counter_next <= (others => '0');
        state_next   <= state_2;
      end if;
    end if;

  when state_2 =>
    if trigger = '1' then
      counter_next <= std_logic_vector(unsigned(counter_reg) + 1);
      if unsigned(counter_next) = N-1 then
        counter_next <= (others => '0');
        state_next   <= state_1;
      end if;
    end if;

end case;
end process;

end arch;

Here a testbench

library ieee;
use ieee.std_logic_1164.all;

entity int32_ctrlFSM_debug_tb is
end int32_ctrlFSM_debug_tb;

architecture tb of int32_ctrlFSM_debug_tb is

component int32_ctrlFSM_debug
    port (
      clk           : in std_logic;
      reset         : in std_logic;
      trigger : in std_logic
          );
end component;

signal clk           : std_logic;
signal reset         : std_logic;
signal trigger : std_logic;

constant TbPeriod : time := 100 ns; -- EDIT Put right period here
signal TbClock : std_logic := '0';
signal TbSimEnded : std_logic := '0';

begin

dut : int32_ctrlFSM_debug
port map (clk           => clk,
          reset         => reset,
          trigger => trigger);

-- Clock generation
TbClock <= not TbClock after TbPeriod/2 when TbSimEnded /= '1' else '0';

-- EDIT: Check that clk is really your main clock signal
clk <= TbClock;

stimuli : process
begin
    -- EDIT Adapt initialization as needed
    trigger <= '0';

    -- Reset generation
    -- EDIT: Check that reset is really your reset signal
    reset <= '1';
    wait for 4 * TbPeriod;
    wait for 1 * TbPeriod/2;
    reset <= '0';
    wait for 10 * TbPeriod;


    -- Stimuli
    wait for 10 * TbPeriod;

    -- send 4 rx_done pulses
    for i in 1 to 8 loop
      trigger <= '1';
      wait for 1 * TbPeriod;
      trigger <= '0';

      wait for 10 * TbPeriod;
    end loop;




    -- Stop the clock and hence terminate the simulation
    TbSimEnded <= '1';
    wait;
end process;

 end tb;`

The problem is that my counter never starts. Here's a scrrenshot from Xsim (vivado 2018.3).

enter image description here

I am doing all of this (counter_reg and counter_next) in order to avoid latches. Any help would be appreciated.

Andrea

a_bet
  • 327
  • 4
  • 15
  • This is the same problem as in your last question: You use a two-process coding style without understanding how it is supposed to be used. As such your sensitivity lists are consistently wrong. – DonFusili Apr 18 '19 at 14:04

1 Answers1

1

Your sensitivity lists are wrong, you should add every independent variable to the sensitivity list of the second process.

You could also switch to a single-process style, which doesn't have all these problems:

onlyprocess : process(clk, reset)
  type state_type is (state1, state2);
  variable r_state : state_type;
  constant N : integer := 4;
  variable r_counter : integer range 0 to N-1;
begin

  if reset = '1' then
    r_state   := state1;
    r_counter := 0;
  elsif rising_edge(clk) then
    if trigger = '1' then
      r_counter := r_counter +1;
      if r_counter = N-1 then
        case r_state is
          when state1 =>
            r_state := state2;
          when state2 =>
            r_state := state1
        end case;
        r_counter := 0;
      end if;
    end if;
  end if;

end process;
DonFusili
  • 1,069
  • 7
  • 10
  • Ok, thank you very much for the answer. I tried also my 2-segments adding counter_reg to the sensitivity list and it works. I still don't understand why I need the process to trigger on counter_reg (i.e. counter_reg is in the sensitivity list). I use 2-segments because it helps me separating regs and next state logic, as described in Pong P Chu books. Would you suggest to switch to 1-segment coding? – a_bet Apr 18 '19 at 14:53
  • @a_bet I will always suggest writing VHDL using one process per clock domain per submodule unless impossible, but there are lively discussions about what works best. The two-process style works because it forces you to think about combinatorial clouds between clocked registers, but this isn't the 90s anymore: we have decent tooling, so that kind of reasoning is only marginally useful. – DonFusili Apr 18 '19 at 14:57
  • Even though two process style adds modularity, maintainability to the program, it is less convenient when it comes to debuging – Mitu Raj Apr 18 '19 at 15:50
  • @MituRaj It also doesn't add modularity or maintainability, of course, and it detracts from readability because you have to keep signal assignments in mind all the time. It's basically refusing to think about algorithms and forcing yourself to think about gates, which is untenable for any decent size project. – DonFusili Apr 18 '19 at 15:55
  • Pong Chu book presents 3 styles in his book as explain why he uses it at different situations. For eg: If you want output to be non-registered, and if doing a mealy machine, we can't do it in a single process – Mitu Raj Apr 18 '19 at 15:59
  • However not a big fan of multi-process as long as meeting the logic is the prime objective of the designer. Instead of thinking too much about how combinational logic looks like n all – Mitu Raj Apr 18 '19 at 16:03
  • @MituRaj Your output is always registered in a one-process style, but assuming you meant "If you want output to be non-registered", you just described my reasoning back to me: "Always use one process, unless impossible". – DonFusili Apr 18 '19 at 16:04
  • Ya it was a typo – Mitu Raj Apr 18 '19 at 16:04
  • I see. I am also having timing loop issues, possibly related to my misunderstanding of the 2-segments style I think. – a_bet Apr 18 '19 at 16:12