1
\$\begingroup\$

I'd like to make a MUXer who switches between 2 signals let's say A and B. Signal A and B also generate both interrupts. The MUXer counts the interrupts and for example after n-interrupts of A, the output will become this of B. If B generates m-interrupts, the output toggles back to A.

In underlying code I wait for 3 pulses of the A interrupt, during this the mux output is A. After that I wait for 5 pulses of the B interrupt while the mux out becomes B. The whole cycle is then repeated.

I'm implementing this with a 3 process FSM as explained here: http://www.csit-sun.pub.ro/courses/Masterat/Xilinx%20Synthesis%20Technology/toolbox.xilinx.com/docsan/xilinx4/data/docs/xst/hdlcode15.html

Can someone explain why it doesn't work properly? The vhdl code:

entity FSM_MUX is
 Port ( CLK : in STD_LOGIC;
 RST : in STD_LOGIC;
 A: in STD_LOGIC;
 A_INT : in STD_LOGIC;
 B: in STD_LOGIC;
 B_INT : in STD_LOGIC;
 START : in STD_LOGIC;
 MUX_OUT : out STD_LOGIC);
end FSM_MUX;
architecture Behavioral of FSM_MUX is
type state is (iddle,state_A,state_B) ;
signal old_state : state ;
signal new_state : state ;
begin
process(CLK)
 begin 
 if (CLK' event and CLK = '1') then
 if RST = '0' or START = '0' then
 old_state <= iddle ;
 else
 old_state <= new_state;
 end if;
 end if;
end process;
process (old_state,A_INT,B_INT)
 variable counter : integer range 0 to ((2**16)-1):=0;
 begin
 case old_state is
 when iddle => if A_INT = '1' then
 new_state <= state_A;
 else
 new_state <= iddle;
 end if;
 when state_A => if A_INT = '1' then
 if counter < 3 then 
 counter := counter + 1;
 new_state <= state_A;
 else
 counter := 0;
 new_state <= state_B;
 end if;
 end if;
 when state_B => if B_INT = '1' then
 if counter < 5 then 
 counter := counter + 1;
 new_state <= state_B;
 else
 counter := 0;
 new_state <= state_A;
 end if;
 end if;
 end case;
end process;
process(old_state) 
begin
 case old_state is
 when iddle => MUX <='0';
 when state_A => MUX <= A;
 when state_B => MUX <= B; 
 end case;
end process;
end Behavioral;

Thanks in advance!

asked Feb 20, 2016 at 12:08
\$\endgroup\$
2
  • 1
    \$\begingroup\$ It's most likely subject to some of the usual defects of a 2-process SM. Check it for sensitivity list errors, latches or counters in the async process, etc. Or simply rewrite it in the simpler, smaller, more reliable single process form. \$\endgroup\$ Commented Feb 20, 2016 at 12:39
  • \$\begingroup\$ I actually answered it because the code "error" was obvious to me. But, next time please give a testbench which shows the faulty behaviour. And then describe in the question the expected behaviour. \$\endgroup\$ Commented Feb 20, 2016 at 18:15

1 Answer 1

2
\$\begingroup\$

The variable counter is actually a register, so you must describe it in the first process which is clocked. You cannot describe it in the second process, because you have less control on how often this process is resumed during the same clock cycle. The process is resumed whenever one of the signals in the process sensitivity list changes. I also prefer signals instead of variables because in most simulators you can add only signals to the waveform for debugging.

To control a counter register in the first (clocked) process from the second process, you need two control signals: counter_rst when the counter should be reseted, and counter_inc when the counter should be incremented. The counter in the first process can then be described with:

 if (CLK' event and CLK = '1') then
 if counter_rst = '1' then -- you may add RST and/or START here
 counter <= 0;
 elsif counter_inc = '1' then
 counter <= counter + 1;
 end if;
 end if;

You may add RSTor START on the first condition to fit your needs.

For example, the counter is now incremented when you assign counter_inc <= '1'; in the second process. This replaces the assignment of counter := counter + 1; in your current code. If no increment is needed, then you must assign counter_inc <= '0'. This is accomplished by making a default assignment at the start of the process. The control signal counter_rst is handled in a similar way. The counter must be added to the sensitivity list of the second process, because you want combinational logic here.

You also have to fix the counter checks. If you want to count 3 pulses, then you must count from 0 to 2.

Your code also needs a default assignment for new_state, because you didn't assigned a new value in each branch in the second process. In the last process it must read MUX_OUT instead of MUX, also A and B must be added to the process sensitivity list. Otherwise you get a latch.

This is the whole fixed code:

library ieee;
use ieee.std_logic_1164.all;
entity FSM_MUX is
 Port ( CLK : in STD_LOGIC;
 RST : in STD_LOGIC;
 A: in STD_LOGIC;
 A_INT : in STD_LOGIC;
 B: in STD_LOGIC;
 B_INT : in STD_LOGIC;
 START : in STD_LOGIC;
 MUX_OUT : out STD_LOGIC);
end FSM_MUX;
architecture Behavioral of FSM_MUX is
 type state is (iddle,state_A,state_B) ;
 signal old_state : state ;
 signal new_state : state ;
 signal counter : integer range 0 to ((2**16)-1) := 0;
 signal counter_inc : std_logic; -- increment counter
 signal counter_rst : std_logic; -- reset counter
begin
 process(CLK)
 begin 
 if (CLK' event and CLK = '1') then
 if RST = '0' or START = '0' then
 old_state <= iddle;
 else
 old_state <= new_state;
 end if;
 -- counter register
 if counter_rst = '1' then -- you may add RST and/or START here
 counter <= 0;
 elsif counter_inc = '1' then
 counter <= counter + 1;
 end if;
 end if;
 end process;
 process (old_state, A_INT, B_INT, counter) -- added counter
 begin
 counter_inc <= '0'; -- default assignment ...
 counter_rst <= '0'; -- ... may be overwritten below
 new_state <= old_state;
 case old_state is
 when iddle =>
 if A_INT = '1' then
 new_state <= state_A;
 else
 new_state <= iddle;
 end if;
 when state_A =>
 if A_INT = '1' then
 if counter < 2 then -- count from 0 to 2 for 3 pulses
 counter_inc <= '1'; -- increment counter
 new_state <= state_A;
 else
 counter_rst <= '1'; -- reset counter
 new_state <= state_B;
 end if;
 end if;
 when state_B =>
 if B_INT = '1' then
 if counter < 4 then -- count from 0 to 4 for 5 pulses
 counter_inc <= '1'; -- increment counter
 new_state <= state_B;
 else
 counter_rst <= '1'; -- reset counter
 new_state <= state_A;
 end if;
 end if;
 end case;
 end process;
 process(old_state, A, B) -- added A and B 
 begin
 case old_state is
 when iddle => MUX_OUT <= '0'; -- MUX_OUT instead of MUX !
 when state_A => MUX_OUT <= A;
 when state_B => MUX_OUT <= B;
 end case;
 end process;
end Behavioral;

This was my testbench:

library ieee;
use ieee.std_logic_1164.all;
entity FSM_MUX_tb is
end FSM_MUX_tb;
architecture sim of FSM_MUX_tb is
 signal CLK : STD_LOGIC := '1';
 signal RST : STD_LOGIC;
 signal A : STD_LOGIC;
 signal A_INT : STD_LOGIC;
 signal B : STD_LOGIC;
 signal B_INT : STD_LOGIC;
 signal START : STD_LOGIC;
 signal MUX_OUT : STD_LOGIC;
begin -- sim
 DUT: entity work.FSM_MUX
 port map (
 CLK => CLK,
 RST => RST,
 A => A,
 A_INT => A_INT,
 B => B,
 B_INT => B_INT,
 START => START,
 MUX_OUT => MUX_OUT);
 -- clock generation
 CLK <= not CLK after 10 ns;
 -- waveform generation
 WaveGen_Proc: process
 begin
 RST <= '1'; -- low-active, optional
 START <= '1';
 A <= '0';
 B <= '1';
 A_INT <= '0';
 B_INT <= '0';
 -- leave IDDLE state
 wait until rising_edge(CLK);
 A_INT <= '1';
 wait until rising_edge(CLK);
 A_INT <= '0';
 -- just some waiting
 wait until rising_edge(CLK);
 wait until rising_edge(CLK);
 -- 3 A_INT pulses to leave STATE_A
 for i in 1 to 3 loop
 wait until rising_edge(CLK);
 A_INT <= '1';
 wait until rising_edge(CLK);
 A_INT <= '0';
 end loop; -- i
 -- 5 B_INT pulses to leave STATE_B
 for i in 1 to 5 loop
 wait until rising_edge(CLK);
 B_INT <= '1';
 wait until rising_edge(CLK);
 B_INT <= '0';
 end loop; -- i
 wait;
 end process WaveGen_Proc;
end sim;

And this is the simulation output:

simulation output

answered Feb 20, 2016 at 18:11
\$\endgroup\$
1
  • \$\begingroup\$ Many thanks for the help! Not only for your efforts to provide the correct solution but also to explain neatly the why and how. I've tried everything with the sensivity list, though I forgot the default assignement of new_state. The fact that the counter was a register and such, I didn't know. I'll try to find some direct "translations" of vhdl into hardware on the www, it seems my knowledge needs some polishing. Thanks again! \$\endgroup\$ Commented Feb 21, 2016 at 10:55

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.