Single Step

From Hamsterworks Wiki!

Jump to: navigation, search

This FPGA project was completed in December 2015.

Jeff Milstead asked me "I'm using a small CPU on a Nexys-2 (Spartan 3E), and I'd like to add free-run/hold/single-step buttons to it so I can step the processor... is there a 'correct/preferred' way of doing this?"

Yes there is! Using the BUFGMUX primitive you can cleanly switch between two clock sources (even if one of the sources is a push button)

In this project, when the run_switch is '0' the LEDs count at 32MHz, but if you change the run_switch to high, then the count will increase by one every time you push the "single_step" button.

Here's the logical structure

Clk switch.png


Contents

Source

The source is pretty self-evident... the 'trick' is in buffering the clock correctly before sending it into the BUFGMUX

single_step.vhd

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

library UNISIM;
use UNISIM.VComponents.all;

entity clock_step is
    Port ( clk         : in  STD_LOGIC;
           run_switch  : in  STD_LOGIC;
           single_step : in  STD_LOGIC;
           LED         : out  STD_LOGIC_VECTOR (7 downto 0));
end clock_step;

architecture Behavioral of clock_step is

	COMPONENT debounce
	PORT(
		clk : IN std_logic;
		i : IN std_logic;          
		o : OUT std_logic
		);
	END COMPONENT;

   signal run_switch_debounced        : std_logic := '0';
   signal single_step_debounced           : std_logic := '0';

   signal counter : unsigned(7 downto 0);
   
   signal switched_clk : std_logic;
   signal switched_clk_unbuffered : std_logic;
   signal clk_buffered : std_logic;
begin

i_BUFG: BUFG port map (
      I => clk,
      O => clk_buffered
   );

Inst_debounce1: debounce PORT MAP(
		clk => clk_buffered,
		i => run_switch,
		o => run_switch_debounced 
	);

Inst_debounce2: debounce PORT MAP(
		clk => clk_buffered,
		i => single_step,
		o => single_step_debounced
	);

BUFGMUX_inst : BUFGMUX port map (
      O  => switched_clk,           -- Clock MUX output
      I0 => clk_buffered,           -- Clock0 input
      I1 => single_step_debounced,  -- Clock1 input
      S  => run_switch_debounced    -- Clock select input
   );

process(switched_clk)
   begin
      if rising_edge(switched_clk) then
         counter <= counter + 1;        
      end if;
   end process;

   LED <= std_logic_vector(counter);

end Behavioral;

debounce.vhd

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity debounce is
    Port ( clk : in  STD_LOGIC;
           i : in  STD_LOGIC;
           o : out  STD_LOGIC);
end debounce;

architecture Behavioral of debounce is
   signal debounce_counter : unsigned (20 downto 0) := (others => '0');
   signal synced           : std_logic := '0';
   signal debounced        : std_logic := '0';

begin
process(clk)
   begin
      if rising_edge(clk) then
         if synced = '1' then
            if debounce_counter(debounce_counter'high) = '1' then
               debounce_counter <= (others => '1');
               o <= '1';
            else
               debounce_counter <= debounce_counter + 1;
            end if;
         else
            if debounce_counter(debounce_counter'high) = '0' then
               debounce_counter <= (others => '0');
               o <= '0';
            else
               debounce_counter <= debounce_counter - 1;
            end if;
         end if;
         synced <= i;
      end if;
   end process;

end Behavioral;

PapilioPro.ucf

Constraints for the Papilio Pro + LogicStart MegaWing.

NET CLK            LOC="P94"  | IOSTANDARD=LVTTL | PERIOD=31.25ns;               # CLK

NET LED(0)         LOC="P123" | IOSTANDARD=LVTTL;                                # C8
NET LED(1)         LOC="P124" | IOSTANDARD=LVTTL;                                # C9
NET LED(2)         LOC="P126" | IOSTANDARD=LVTTL;                                # C10
NET LED(3)         LOC="P127" | IOSTANDARD=LVTTL;                                # C11
NET LED(4)         LOC="P131" | IOSTANDARD=LVTTL;                                # C12
NET LED(5)         LOC="P132" | IOSTANDARD=LVTTL;                                # C13
NET LED(6)         LOC="P133" | IOSTANDARD=LVTTL;                                # C14
NET LED(7)         LOC="P134" | IOSTANDARD=LVTTL;                                # C15

NET RUN_SWITCH     LOC="P114" | IOSTANDARD=LVTTL;                                # C0
NET SINGLE_STEP    LOC="P47"  | IOSTANDARD=LVTTL;                                # B15

Personal tools