[SOLVED] Delaying the output by 2 clock cycles in FSM in VHDL

Status
Not open for further replies.

metamisers

Junior Member level 2
Joined
May 11, 2022
Messages
24
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
230
Hello eveyone,

I am trying to design a FSM in VHDL. The FSM has 4 states.

s0 => Led flasher i.e. on/off with specific period and duty cycle
s1 => addition of two numbers
s2 => multiplication of 2 numbers
s3 => gray counter output

The states run independently at every clock cycle. When a button is pressed, s0 ->s1 and so on. The FSM works fine. Problem is that I want the FSM to start delayed i.e. after 2 clock cycles. Hence i first assign output y to all 1's, then y to all 0's and then to state s0. But it is not working as intended. Here's the VHDL code below.


Here's the screenshot of the simulation on Modelsim.




As we can see, as the clk sees the reset, after the next rising edge of clk, the output y is assigned to state s0, There should be a 1, a 0 first before the values of state s0 appear at output y. How can I solve this issue?

Thanks.
 
Last edited by a moderator:

Solution
You can edit your code like this. Here the main_process ensures the init state stays active for the first two clock cycles, setting the y output to all 1's and then to all 0's before transitioning to s0.

Code:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity fsm is    
    Port (
        clk  : IN std_logic;
        srst : IN std_logic;
        x1   : IN std_logic_vector (2 downto 0);
        x2   : IN std_logic_vector (2 downto 0);
        btn  : IN std_logic;
        y    : OUT std_logic_vector (7 downto 0)
    );
end entity fsm;

architecture rtl of fsm is

    type state_type is (init, s0, s1, s2, s3);

    signal current_state : state_type := init;
    signal next_state : state_type;

    signal y_cld ...

You need to make those assignments on the subsequent rising edges of the clock for them to take effect as you desire.

There are many ways where the code could be made better.
1. Sum, Mult, xi, x2, etc needs to start working only after the clock sees the srst as LOW (see how you are using gcntr).
2. Use "one process" SM style coding as opposed to two. It heavily enhances code clarity.
 
@dpaul


Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
f rising_edge(clk) then
        if srst = '1' then
                current_state <= s0;
                y <= "0000000" & led;
        else
                current_state <= (others => '1');
                current_state <= (others => '0');
                current_state <= next_state;
                y <= y_cld;
        end if;
    end if;


This will cause the current state to put 1's, then 0's and then go to the next state. How can I make those assignments on the subsequent rising edges? Can you elaborate a bit more please?

Thanks.
 
Last edited by a moderator:

You can edit your code like this. Here the main_process ensures the init state stays active for the first two clock cycles, setting the y output to all 1's and then to all 0's before transitioning to s0.

Code:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity fsm is    
    Port (
        clk  : IN std_logic;
        srst : IN std_logic;
        x1   : IN std_logic_vector (2 downto 0);
        x2   : IN std_logic_vector (2 downto 0);
        btn  : IN std_logic;
        y    : OUT std_logic_vector (7 downto 0)
    );
end entity fsm;

architecture rtl of fsm is

    type state_type is (init, s0, s1, s2, s3);

    signal current_state : state_type := init;
    signal next_state : state_type;

    signal y_cld : std_logic_vector (7 downto 0);

    signal sum   : std_logic_vector (7 downto 0);
    signal mult  : std_logic_vector (7 downto 0);
    signal gcntr : std_logic_vector (7 downto 0);
    signal led   : std_logic;

    signal ibtn : std_logic;
    signal delay_counter : integer range 0 to 2 := 0;

component led_flasher is
    Port ( clk  : IN std_logic;
           dout : OUT std_logic);
end component led_flasher;

component addition is
    Port ( x1      : IN std_logic_vector (2 downto 0);
           x2      : IN std_logic_vector (2 downto 0);
           add_out : OUT std_logic_vector (7 downto 0));
end component addition;

component multiplication is
    Port ( x1       : IN std_logic_vector (2 downto 0);
           x2       : IN std_logic_vector (2 downto 0);
           mult_out : OUT std_logic_vector (7 downto 0));
end component multiplication;

component gray_cntr is
    Port (  clk   : IN std_logic;
            srst  : IN std_logic;
            gcntr : OUT std_logic_vector (7 downto 0));
end component gray_cntr;

begin

    ibtn <= btn;

    main_process : process(clk) begin
        if rising_edge(clk) then
            if srst = '1' then
                current_state <= init;
                delay_counter <= 0;
            else
                if current_state = init then
                    if delay_counter = 0 then
                        y <= (others => '1');
                    elsif delay_counter = 1 then
                        y <= (others => '0');
                    elsif delay_counter = 2 then
                        current_state <= next_state;
                    end if;
                    delay_counter <= delay_counter + 1;
                else
                    current_state <= next_state;
                    y <= y_cld;
                end if;
            end if;
        end if;
    end process;

    state_control : process(current_state, ibtn) begin
        next_state <= current_state;
        case (current_state) is
            when init =>
                next_state <= s0;
            when s0 =>
                if ibtn = '1' then
                    next_state <= s1;
                end if;
            when s1 =>
                if ibtn = '1' then
                    next_state <= s2;
                end if;
            when s2 =>
                if ibtn = '1' then
                    next_state <= s3;
                end if;
            when s3 =>
                if ibtn = '1' then
                    next_state <= s0;
                end if;
            when others =>
                next_state <= s0;
        end case;
    end process state_control;

    output_control : process(current_state, led, mult, sum, gcntr) begin
        case(current_state) is
            when s0 =>
                y_cld <= "0000000" & led;
            when s1 =>
                y_cld <= sum;
            when s2 =>
                y_cld <= mult;
            when s3 =>
                y_cld <= gcntr;
            when others =>
                y_cld <= (others => '0');
        end case;
    end process output_control;

    -------------------------------------------------------------
    -- Instantiate the DUT
    -------------------------------------------------------------

    state0 : led_flasher port map ( clk => clk, dout => led );

    state1 : addition port map ( x1 => x1, x2 => x2, add_out => sum );

    state2 : multiplication port map ( x1 => x1, x2 => x2, mult_out => mult );

    state3 : gray_cntr port map ( clk => clk, srst => srst, gcntr => gcntr );

end rtl;
 
Last edited by a moderator:
Solution
Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…