Rework SOC reset
authorAnton Blanchard <anton@linux.ibm.com>
Sat, 7 Sep 2019 11:28:21 +0000 (21:28 +1000)
committerAnton Blanchard <anton@ozlabs.org>
Sat, 7 Sep 2019 21:40:19 +0000 (07:40 +1000)
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>
Makefile
fpga/clk_gen_bypass.vhd
fpga/clk_gen_plle2.vhd
fpga/pp_soc_reset.vhd [deleted file]
fpga/soc_reset.vhdl [new file with mode: 0644]
fpga/soc_reset_tb.vhdl [new file with mode: 0644]
fpga/toplevel.vhd
microwatt.core

index b4ec01e6cb4d76dcacd156030b0fb1d9548c76e5..3d82a6a24c4fcab2af975786a7e13fcca1743d83 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ GHDL=ghdl
 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
 
@@ -41,6 +41,11 @@ wishbone_arbiter.o: wishbone_types.o
 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 $@
 
index 2cc022605d9ee7523ba97b713aaf811d0d248713..b204329e392125104e403bc54eea3c255f26d056 100644 (file)
@@ -3,10 +3,10 @@ use ieee.std_logic_1164.all;
 
 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;
 
@@ -14,7 +14,7 @@ architecture bypass of clock_generator is
 
 begin
 
-  locked <= not resetn;
-  system_clk <= clk;
+  pll_locked_out <= pll_rst_in;
+  pll_clk_out <= ext_clk;
 
 end architecture bypass;
index 57e4fe911694d4151f27fa56e38907856de23111..e2c761ca876d23b2e7d89badabdf4ffe6cc87f7f 100644 (file)
@@ -8,10 +8,10 @@ entity clock_generator is
   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
@@ -55,17 +55,17 @@ begin
       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;
diff --git a/fpga/pp_soc_reset.vhd b/fpga/pp_soc_reset.vhd
deleted file mode 100644 (file)
index c53d85a..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
--- 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;
diff --git a/fpga/soc_reset.vhdl b/fpga/soc_reset.vhdl
new file mode 100644 (file)
index 0000000..2685dab
--- /dev/null
@@ -0,0 +1,59 @@
+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;
diff --git a/fpga/soc_reset_tb.vhdl b/fpga/soc_reset_tb.vhdl
new file mode 100644 (file)
index 0000000..ee8fc17
--- /dev/null
@@ -0,0 +1,106 @@
+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;
index 940882351fa602f11afad7a03d5d2697537b8f39..24e2fe2a08289efb4ba69423f9690a45c4a18949 100644 (file)
@@ -12,9 +12,11 @@ use work.wishbone_types.all;
 -- 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;
@@ -28,12 +30,12 @@ end entity toplevel;
 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;
@@ -137,21 +139,25 @@ begin
                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
index 1838667d3dfb93763e28a41c52a544140c8e3b44..b82b0d02125289f1fd92726500d004ed90c7a3b7 100644 (file)
@@ -33,7 +33,7 @@ filesets:
     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