Control logic implementation
In this post, we want to implement a simple exercise in order to show how to implement a programmable time-out counter that uses three different input coding. It is an exercise in control logic that you can use in your FPGA/ASIC design.
The control logic is explained in Figure1:
we need to count three different type of events and the counting values can be programmable up to three different ways. For instance, starting with count 3 pulses from input 1 then 5 pulses from input 2 and then 7 pulses from input three. After that, the control logic shall generate a pulse.
You can use this example as a template if you need to implement a similar control logic in your design. It can be viewed as a step programmable timeout controller.
VHDL code for time out counter
In the VHDL code implementation of the programmable timeout counter, we are using a different approach for describing the Finite State Machine w.r.t to the canonical one pointed out in this post.
In this case, the definition of the state of the control logic is implemented using a constant instead of enumeration type provided by VHDL.
Here you can find an example that uses the VHDL enumeration type facility to implement an FSM.
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity programmable_time_out is port ( i_clk : in std_logic; i_rstb : in std_logic; i_sync_reset : in std_logic; i_count_module_1 : in std_logic_vector(7 downto 0); i_count_module_2 : in std_logic_vector(7 downto 0); i_count_module_3 : in std_logic_vector(7 downto 0); i_input_1 : in std_logic; i_input_2 : in std_logic; i_input_3 : in std_logic; o_pulse : out std_logic; o_status_counter : out std_logic_vector(7 downto 0); o_status_fsm : out std_logic_vector(3 downto 0)); end programmable_time_out; architecture rtl of programmable_time_out is constant C_NBIT_STATE : integer := 4; constant ST_WAIT_UNTIL_COUNT1 : std_logic_vector(C_NBIT_STATE-1 downto 0) := X"1"; constant ST_WAIT_UNTIL_COUNT2 : std_logic_vector(C_NBIT_STATE-1 downto 0) := X"2"; constant ST_WAIT_UNTIL_COUNT3 : std_logic_vector(C_NBIT_STATE-1 downto 0) := X"3"; constant ST_RESET : std_logic_vector(C_NBIT_STATE-1 downto 0) := X"F"; signal r_st_present : std_logic_vector(C_NBIT_STATE-1 downto 0); signal w_st_next : std_logic_vector(C_NBIT_STATE-1 downto 0); signal r_counter : unsigned(7 downto 0); signal r_counter_module : unsigned(7 downto 0); signal r_counter_tc : std_logic; signal r_counter_ena : std_logic; begin r_counter_tc <= '1' when (r_counter >= r_counter_module) else '0'; p_state : process(i_clk,i_rstb) begin if(i_rstb='0') then r_st_present <= ST_RESET; elsif(rising_edge(i_clk)) then if(i_sync_reset='1') then r_st_present <= ST_RESET; else r_st_present <= w_st_next; end if; end if; end process p_state; p_comb : process( r_st_present , r_counter_tc , i_input_2 , i_input_3 ) begin case r_st_present is when ST_WAIT_UNTIL_COUNT1 => if (r_counter_tc='1') then w_st_next <= ST_WAIT_UNTIL_COUNT2; else w_st_next <= ST_WAIT_UNTIL_COUNT1; end if; when ST_WAIT_UNTIL_COUNT2 => if (r_counter_tc='1') then w_st_next <= ST_WAIT_UNTIL_COUNT3; else w_st_next <= ST_WAIT_UNTIL_COUNT2; end if; when ST_WAIT_UNTIL_COUNT3 => if (r_counter_tc='1') then w_st_next <= ST_RESET; else w_st_next <= ST_WAIT_UNTIL_COUNT3; end if; when others => -- ST_RESET => w_st_next <= ST_WAIT_UNTIL_COUNT1; end case; end process p_comb; p_state_out : process(i_clk,i_rstb) begin if(i_rstb='0') then o_pulse <= '0'; o_status_counter <= (others=>'0'); o_status_fsm <= ST_RESET; r_counter_module <= (others=>'0'); r_counter_ena <= '0'; r_counter <= (others=>'0'); elsif(rising_edge(i_clk)) then o_status_counter <= std_logic_vector(r_counter); o_status_fsm <= r_st_present; case r_st_present is when ST_WAIT_UNTIL_COUNT1 => o_pulse <= '0'; r_counter_module <= unsigned(i_count_module_1); r_counter_ena <= i_input_1; if(r_counter_tc='1') then r_counter <= (others=>'0'); elsif(r_counter_ena='1') then r_counter <= r_counter + 1; end if; when ST_WAIT_UNTIL_COUNT2 => o_pulse <= '0'; r_counter_module <= unsigned(i_count_module_2); r_counter_ena <= i_input_2; if(r_counter_tc='1') then r_counter <= (others=>'0'); elsif(r_counter_ena='1') then r_counter <= r_counter + 1; end if; when ST_WAIT_UNTIL_COUNT3 => o_pulse <= '0'; r_counter_module <= unsigned(i_count_module_3); r_counter_ena <= i_input_3; if(r_counter_tc='1') then r_counter <= (others=>'0'); elsif(r_counter_ena='1') then r_counter <= r_counter + 1; end if; when others=> -- ST_RESET => o_pulse <= '1'; r_counter_module <= unsigned(i_count_module_1); r_counter_ena <= '0'; r_counter <= (others=>'0'); end case; end if; end process p_state_out; end rtl;
What is the differences from the use of enumeration types?
For what concern the logic behavior there are no main differences.
The enumeration type approach is more readable when you are running the VHDL code simulation.
For what concern the digital design implementation in FPGA/ASIC this approach allows you to have a better control on the coding of the status of the control logic. In this case, you can code the FSM state as
- one-hot
- binary
- gray code
directly during the definition phase without specifying the encoding type to the synthesis tool. In this case, you can implement a deeper control on FSM implementation.
In the VHDL code of the programmable timeout design, we have reported as the status signal the internal FSM status and internal counter as you can see on Figure2.
You can use this info as debug information as will be clear watching the video of the demo on DE0 board.
[video_player type=”youtube” youtube_remove_logo=”Y” width=”560″ height=”315″ align=”center” margin_top=”0″ margin_bottom=”20″]aHR0cHM6Ly95b3V0dS5iZS9CcHZUV2h4ZHNmYw==[/video_player]
VHDL code simulation
In the simulation, the test bench is set to have
- input_1 = 4
- input_2 = 3
- input_3 = 5
In actual fact, from the wave windows, it is clear that after 4 input-1 pulses the control logic goes to state 2 and other pulses on input-1 are ignored.
After 3 input-2 pulses, the control logic g0es to the state 3 and only input 3 is evaluated.
After 5 input-3 pulses, the control logic passes from reset state and toggle the output
If you appreciated this post, please help us to share it with your friend.
[social_sharing style=”style-7″ fb_like_url=”https://surf-vhdl.com/how-to-implement-a-programmable-timeout-counter” fb_color=”light” fb_lang=”en_US” fb_text=”like” fb_button_text=”Share” tw_lang=”en” tw_url=”https://surf-vhdl.com/how-to-implement-a-programmable-timeout-counter” tw_button_text=”Share” g_url=”https://surf-vhdl.com/how-to-implement-a-programmable-timeout-counter” g_lang=”en-GB” g_button_text=”Share” linkedin_url=”https://surf-vhdl.com/how-to-implement-a-programmable-timeout-counter” linkedin_lang=”en_US” alignment=”center”]
If you need to contact us, please write to: surf.vhdl@gmail.com
We appreciate any of your comment, please post below: