The old reset code was overly complicated and never worked properly.
Replace it with a simpler sequence that uses a couple of shift registers
to assert resets:
- Wait a number of external clock cycles before removing reset from
the PLL.
- After the PLL locks and the external reset button isn't pressed,
wait a number of PLL clock cycles before removing reset from the SOC.
Signed-off-by: Anton Blanchard <anton@linux.ibm.com>
GHDLFLAGS=--std=08
CFLAGS=-O2 -Wall
-all = core_tb simple_ram_behavioural_tb
+all = core_tb simple_ram_behavioural_tb soc_reset_tb
# XXX
# loadstore_tb fetch_tb
wishbone_types.o:
writeback.o: common.o
+fpga/soc_reset_tb.o: fpga/soc_reset.o
+
+soc_reset_tb: fpga/soc_reset_tb.o fpga/soc_reset.o
+ $(GHDL) -e $(GHDLFLAGS) soc_reset_tb
+
core_tb: core_tb.o simple_ram_behavioural_helpers_c.o sim_console_c.o
$(GHDL) -e $(GHDLFLAGS) -Wl,simple_ram_behavioural_helpers_c.o -Wl,sim_console_c.o $@
entity clock_generator is
port (
- clk : in std_logic;
- resetn : in std_logic;
- system_clk : out std_logic;
- locked : out std_logic);
+ ext_clk : in std_logic;
+ pll_rst_in : in std_logic;
+ pll_clk_out : out std_logic;
+ pll_locked_out : out std_logic);
end entity clock_generator;
begin
- locked <= not resetn;
- system_clk <= clk;
+ pll_locked_out <= pll_rst_in;
+ pll_clk_out <= ext_clk;
end architecture bypass;
generic (
clk_period_hz : positive := 100000000);
port (
- clk : in std_logic;
- resetn : in std_logic;
- system_clk : out std_logic;
- locked : out std_logic);
+ ext_clk : in std_logic;
+ pll_rst_in : in std_logic;
+ pll_clk_out : out std_logic;
+ pll_locked_out : out std_logic);
end entity clock_generator;
architecture rtl of clock_generator is
DIVCLK_DIVIDE => pll_settings.divclk_divide,
STARTUP_WAIT => "FALSE")
port map (
- CLKOUT0 => system_clk,
+ CLKOUT0 => pll_clk_out,
CLKOUT1 => open,
CLKOUT2 => open,
CLKOUT3 => open,
CLKOUT4 => open,
CLKOUT5 => open,
CLKFBOUT => clkfb,
- LOCKED => locked,
- CLKIN1 => clk,
+ LOCKED => pll_locked_out,
+ CLKIN1 => ext_clk,
PWRDWN => '0',
- RST => not resetn,
+ RST => pll_rst_in,
CLKFBIN => clkfb);
end architecture rtl;
+++ /dev/null
--- The Potato Processor - A simple processor for FPGAs
--- (c) Kristian Klomsten Skordal 2018 <kristian.skordal@wafflemail.net>
-
-library ieee;
-use ieee.std_logic_1164.all;
-use work.pp_utilities.all;
-
---! @brief System reset unit.
---! Because most resets in the processor core are synchronous, at least one
---! clock pulse has to be given to the processor while the reset signal is
---! asserted. However, if the clock generator is being reset at the same time,
---! the system clock might not run during reset, preventing the processor from
---! properly resetting.
-entity pp_soc_reset is
- generic(
- RESET_CYCLE_COUNT : natural := 20000000
- );
- port(
- clk : in std_logic;
-
- reset_n : in std_logic;
- reset_out : out std_logic;
-
- system_clk : in std_logic;
- system_clk_locked : in std_logic
- );
-end entity pp_soc_reset;
-
-architecture behaviour of pp_soc_reset is
-
- subtype counter_type is natural range 0 to RESET_CYCLE_COUNT;
- signal counter : counter_type;
-
- signal fast_reset : std_logic := '0';
- signal slow_reset : std_logic := '1';
-begin
-
- reset_out <= slow_reset;
-
--- process(clk)
--- begin
--- if rising_edge(clk) then
--- if reset_n = '0' then
--- fast_reset <= '1';
--- elsif system_clk_locked = '1' then
--- if fast_reset = '1' and slow_reset = '1' then
--- fast_reset <= '0';
--- end if;
--- end if;
--- end if;
--- end process;
-
- process(system_clk)
- begin
- if rising_edge(system_clk) then
- if reset_n = '0' then
- slow_reset <= '1';
- counter <= RESET_CYCLE_COUNT;
- else
- if counter = 0 then
- slow_reset <= '0';
- else
- counter <= counter - 1;
- end if;
- end if;
- end if;
- end process;
-
-end architecture behaviour;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+
+entity soc_reset is
+ generic (
+ PLL_RESET_CLOCKS : integer := 32;
+ SOC_RESET_CLOCKS : integer := 32;
+ RESET_LOW : boolean := true
+ );
+ port (
+ ext_clk : in std_ulogic;
+ pll_clk : in std_ulogic;
+
+ pll_locked_in : in std_ulogic;
+ ext_rst_in : in std_ulogic;
+
+ pll_rst_out : out std_ulogic;
+ rst_out : out std_ulogic
+ );
+end soc_reset;
+
+architecture rtl of soc_reset is
+ signal ext_rst_n : std_ulogic;
+ signal rst_n : std_ulogic;
+ signal pll_rst_reg : std_ulogic_vector(PLL_RESET_CLOCKS downto 0) := (others => '1');
+ signal soc_rst_reg : std_ulogic_vector(SOC_RESET_CLOCKS downto 0) := (others => '1');
+begin
+ ext_rst_n <= ext_rst_in when RESET_LOW else not ext_rst_in;
+ rst_n <= ext_rst_n and pll_locked_in;
+
+ -- PLL reset is active high
+ pll_rst_out <= pll_rst_reg(0);
+ -- Pass active high reset around
+ rst_out <= soc_rst_reg(0);
+
+ -- Wait for external clock to become stable before starting the PLL
+ -- By the time the FPGA has been loaded the clock should be well and
+ -- truly stable, but lets give it a few cycles to be sure.
+ pll_reset_0 : process(ext_clk)
+ begin
+ if (rising_edge(ext_clk)) then
+ pll_rst_reg <= '0' & pll_rst_reg(pll_rst_reg'length-1 downto 1);
+ end if;
+ end process;
+
+ -- Once our clock is stable and the external reset button isn't being
+ -- pressed, assert the SOC reset for long enough for the CPU pipeline
+ -- to clear completely.
+ soc_reset_0 : process(pll_clk)
+ begin
+ if (rising_edge(pll_clk)) then
+ if (rst_n = '0') then
+ soc_rst_reg <= (others => '1');
+ else
+ soc_rst_reg <= '0' & soc_rst_reg(soc_rst_reg'length-1 downto 1);
+ end if;
+ end if;
+ end process;
+end rtl;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+
+entity soc_reset_tb is
+end soc_reset_tb;
+
+architecture behave of soc_reset_tb is
+ signal ext_clk : std_ulogic;
+ signal pll_clk : std_ulogic;
+
+ signal pll_locked_in : std_ulogic;
+ signal ext_rst_in : std_ulogic;
+
+ signal pll_rst_out : std_ulogic;
+ signal pll_rst_out_expected : std_ulogic;
+ signal rst_out : std_ulogic;
+ signal rst_out_expected : std_ulogic;
+
+ constant clk_period : time := 10 ns;
+
+ type test_vector is record
+ pll_locked_in : std_ulogic;
+ ext_rst_in : std_ulogic;
+ pll_rst_out : std_ulogic;
+ rst_out : std_ulogic;
+ end record;
+
+ type test_vector_array is array (natural range <>) of test_vector;
+ constant test_vectors : test_vector_array := (
+ -- PLL not locked, reset button not pressed
+ ('0', '1', '1', '1'),
+ ('0', '1', '1', '1'),
+ ('0', '1', '1', '1'),
+ ('0', '1', '1', '1'),
+ -- Reset is removed from the PLL
+ ('0', '1', '0', '1'),
+ ('0', '1', '0', '1'),
+ ('0', '1', '0', '1'),
+ -- At some point PLL comes out of reset
+ ('1', '1', '0', '1'),
+ ('1', '1', '0', '1'),
+ ('1', '1', '0', '1'),
+ ('1', '1', '0', '1'),
+ -- Finally SOC comes out of reset
+ ('1', '1', '0', '0'),
+ ('1', '1', '0', '0'),
+
+ -- PLL locked, reset button pressed
+ ('1', '0', '0', '1'),
+ ('1', '0', '0', '1'),
+ ('1', '0', '0', '1'),
+ -- PLL locked, reset button released
+ ('1', '1', '0', '1'),
+ ('1', '1', '0', '1'),
+ ('1', '1', '0', '1'),
+ -- Finally SOC comes out of reset
+ ('1', '1', '0', '0')
+ );
+begin
+ soc_reset_0: entity work.soc_reset
+ generic map (
+ PLL_RESET_CLOCKS => 4,
+ SOC_RESET_CLOCKS => 4,
+ RESET_LOW => true
+ )
+ port map (
+ ext_clk => ext_clk,
+ pll_clk => pll_clk,
+ pll_locked_in => pll_locked_in,
+ ext_rst_in => ext_rst_in,
+ pll_rst_out => pll_rst_out,
+ rst_out => rst_out
+ );
+
+ clock: process
+ begin
+ ext_clk <= '0';
+ pll_clk <= '0';
+ wait for clk_period/2;
+ ext_clk <= '1';
+ pll_clk <= '1';
+ wait for clk_period/2;
+ end process clock;
+
+ stim: process
+ begin
+ for i in test_vectors'range loop
+ (pll_locked_in, ext_rst_in, pll_rst_out_expected, rst_out_expected) <= test_vectors(i);
+
+ --report "pll_locked_in " & std_ulogic'image(pll_locked_in);
+ --report "ext_rst_in " & std_ulogic'image(ext_rst_in);
+ --report "pll_rst_out " & std_ulogic'image(pll_rst_out);
+ --report "rst_out" & std_ulogic'image(rst_out);
+
+ assert pll_rst_out_expected = pll_rst_out report "pll_rst_out bad";
+ assert rst_out_expected = rst_out report "rst_out bad";
+
+ wait for clk_period;
+ end loop;
+
+ wait for clk_period;
+
+ assert false report "end of test" severity failure;
+ wait;
+ end process;
+end behave;
-- 0x00000000: Main memory (1 MB)
-- 0xc0002000: UART0 (for host communication)
entity toplevel is
- generic (
- MEMORY_SIZE : positive := 524288;
- RAM_INIT_FILE : string := "firmware.hex");
+ generic (
+ MEMORY_SIZE : positive := 524288;
+ RAM_INIT_FILE : string := "firmware.hex";
+ RESET_LOW : boolean := true
+ );
port(
ext_clk : in std_logic;
ext_rst : in std_logic;
architecture behaviour of toplevel is
-- Reset signals:
- signal rst : std_logic;
+ signal rst : std_ulogic;
+ signal pll_rst_n : std_ulogic;
-- Internal clock signals:
- signal system_clk : std_logic;
- signal timer_clk : std_logic;
- signal system_clk_locked : std_logic;
+ signal system_clk : std_ulogic;
+ signal system_clk_locked : std_ulogic;
-- wishbone signals:
signal wishbone_proc_out: wishbone_master_out;
end case;
end process processor_intercon;
- reset_controller: entity work.pp_soc_reset
+ reset_controller: entity work.soc_reset
+ generic map(
+ RESET_LOW => RESET_LOW
+ )
port map(
- clk => system_clk,
- reset_n => ext_rst,
- reset_out => rst,
- system_clk => system_clk,
- system_clk_locked => system_clk_locked
+ ext_clk => ext_clk,
+ pll_clk => system_clk,
+ pll_locked_in => system_clk_locked,
+ ext_rst_in => ext_rst,
+ pll_rst_out => pll_rst_n,
+ rst_out => rst
);
clkgen: entity work.clock_generator
port map(
- clk => ext_clk,
- resetn => ext_rst,
- system_clk => system_clk,
- locked => system_clk_locked
+ ext_clk => ext_clk,
+ pll_rst_in => pll_rst_n,
+ pll_clk_out => system_clk,
+ pll_locked_out => system_clk_locked
);
processor: entity work.core
files:
- fpga/pp_fifo.vhd
- fpga/pp_soc_memory.vhd
- - fpga/pp_soc_reset.vhd
+ - fpga/soc_reset.vhdl
- fpga/pp_soc_uart.vhd
- fpga/pp_utilities.vhd
- fpga/toplevel.vhd