Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

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

Status
Not open for further replies.

metamisers

Junior Member level 2
Junior Member level 2
Joined
May 11, 2022
Messages
24
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
229
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.


Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
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 (s0, s1, s2, s3);
 
signal current_state : state_type; 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;
 
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 <= s0;
                y <= (others => '1');
                y <= (others => '0');
                y <= "0000000" & led;
        else
                current_state <= next_state;
                y <= y_cld;
        end if;
    end if;
end process;
 
    state_control : process(current_state, ibtn) begin
    next_state <= current_state;
        case (current_state) is
                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;
 
-- The components are written here!
 
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
 
entity led_flasher is
    Port ( clk : IN std_logic;
           dout : OUT std_logic);
end entity led_flasher;
 
architecture rtl of led_flasher is
 
    signal cntr : std_logic_vector (7 downto 0) := (others => '0');
 
begin
 
    dout <= cntr(7);
 
    counter : process(clk) begin
        if rising_edge(clk) then
            cntr <= std_logic_vector(unsigned(cntr) + 1);
        end if;
    end process counter;
 
end rtl;
 
 
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
 
entity 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 entity addition;
 
architecture rtl of addition is
 
begin
 
    add_out <= std_logic_vector(resize(unsigned(x1),8) + resize(unsigned(x2),8));
 
end rtl;
 
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
 
entity 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 entity multiplication;
 
architecture rtl of multiplication is
 
begin
 
    mult_out <= "00" & std_logic_vector(unsigned(x1) * unsigned(x2));
 
end rtl;
 
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
 
entity gray_cntr is
    Port ( clk   : IN std_logic;
           srst  : IN std_logic;
           gcntr : OUT std_logic_vector (7 downto 0));
end entity gray_cntr;
 
architecture rtl of gray_cntr is
 
signal cntr : std_logic_vector (7 downto 0) := (others => '0');
 
begin
 
    process(clk) begin
        if rising_edge(clk) then
            if srst = '1' then
                cntr <= (others => '0');
            else
                cntr <= std_logic_vector(unsigned(cntr) + 1);
            end if;
        end if;
    end process;
 
    gcntr(7) <= cntr(7);
    gcntr(6) <= cntr(7) xor cntr(6);
    gcntr(5) <= cntr(6) xor cntr(5);
    gcntr(4) <= cntr(5) xor cntr(4);
    gcntr(3) <= cntr(4) xor cntr(3);
    gcntr(2) <= cntr(3) xor cntr(2);
    gcntr(1) <= cntr(2) xor cntr(1);
    gcntr(0) <= cntr(1) xor cntr(0);
 
end rtl;
 
-- And the testbench is described here.
 
library IEEE;
    use IEEE.std_logic_1164.all;
    use IEEE.numeric_std.all;
 
    entity fsm_tb is
    --Port ();
    end entity fsm_tb;
 
    architecture rtl_tb of fsm_tb is
 
    component 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 component fsm;
 
    signal clk  : std_logic;
    signal srst : std_logic;
    signal x1   : std_logic_vector (2 downto 0);
    signal x2   : std_logic_vector (2 downto 0);
    signal btn  : std_logic;
    signal y    : std_logic_vector (7 downto 0);
 
    signal period : time := 1 ns;
 
    begin
 
    clk_gen : process begin
    clk <= '0';
    loop
        clk <= '1';
        wait for period/2;
        clk <= '0';
        wait for period/2;
    end loop;
    end process clk_gen;
 
    x1_gen : process begin
    x1 <= "000";
    wait for period;
    loop
        x1 <= std_logic_vector(unsigned(x1) + 1);
        wait for period;
    end loop;
    end process x1_gen;
 
    x2_gen : process begin
    x2 <= "000";
    wait for period;
    loop
        x2 <= std_logic_vector(unsigned(x2) + 1);
        wait for period;
    end loop;
    end process x2_gen;
 
    reset_proc : process begin
    srst <= '1';
    wait for period;
    srst <= '0';
    wait;
    end process reset_proc;
 
    btn_proc : process begin
    btn <= '0',
           '1' after 20 ns,
           '0' after 21 ns,
           '1' after 40 ns,
           '0' after 41 ns,
           '1' after 60 ns,
           '0' after 61 ns,
           '1' after 80 ns,
           '0' after 81 ns,
           '1' after 100 ns,
           '0' after 101 ns,
           '1' after 120 ns,
           '0' after 121 ns;
           wait;
    end process btn_proc;
 
 
    ---------------------------------------------------------------------
    -- Instantiate the DUT
    ---------------------------------------------------------------------
 
    dut : fsm port map  ( clk => clk,
                          srst => srst,
                          x1 => x1,
                          x2 => x2,
                          btn => btn,
                          y => y);
 
    end rtl_tb;


Here's the screenshot of the simulation on Modelsim.

screenshot.png



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 ...
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.
main_process : process(clk) begin if rising_edge(clk) then if srst = '1' then current_state <= s0; y <= (others => '1'); y <= (others => '0'); y <= "0000000" & led; else current_state <= next_state; y <= y_cld; end if; end if; end process;
It is meaningless to write like that Only the last assignment takes effect when srst = '1'.

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

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top