diff --git a/ibex_demo_system.core b/ibex_demo_system.core index 2e6c6e4d..094ace24 100644 --- a/ibex_demo_system.core +++ b/ibex_demo_system.core @@ -40,6 +40,7 @@ filesets: files: - rtl/fpga/top_sonata.sv - rtl/fpga/clkgen_sonata.sv + - rtl/fpga/rst_ctrl.sv file_type: systemVerilogSource files_verilator: diff --git a/rtl/fpga/clkgen_sonata.sv b/rtl/fpga/clkgen_sonata.sv index d216f67f..1b3a885f 100644 --- a/rtl/fpga/clkgen_sonata.sv +++ b/rtl/fpga/clkgen_sonata.sv @@ -5,11 +5,9 @@ module clkgen_sonata ( input IO_CLK, output IO_CLK_BUF, - input IO_RST_N, output clk_sys, - output rst_sys_n + output locked ); - logic locked_pll; logic io_clk_buf; logic clk_50_buf; logic clk_50_unbuf; @@ -56,7 +54,7 @@ module clkgen_sonata ( .DRDY (), .DWE (1'b0), // Other control and status signals - .LOCKED (locked_pll), + .LOCKED (locked), .PWRDWN (1'b0), // Do not reset PLL on external reset, otherwise ILA disconnects at a reset .RST (1'b0)); @@ -77,7 +75,4 @@ module clkgen_sonata ( // outputs // clock assign clk_sys = clk_50_buf; - - // reset - assign rst_sys_n = locked_pll & IO_RST_N; endmodule diff --git a/rtl/fpga/rst_ctrl.sv b/rtl/fpga/rst_ctrl.sv new file mode 100644 index 00000000..8532bb48 --- /dev/null +++ b/rtl/fpga/rst_ctrl.sv @@ -0,0 +1,98 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Produces an active-low power-on-reset (PoR) on output `rst_no`. A reset will only happen once +// `pll_locked_i` is set to indicate the systems PLL(s) have locked and clock(s) are stable. Further +// resets can be triggered by the 'rst_btn_i' input (active high). This input is debounced so it can +// be easily connected to a physical button. +// +// The PoR has three phases: +// * phase 0 - Reset is left deasserted +// * phase 1 - Reset is asserted and held asserted (giving a negative edge on rst_no from phase 0 to +// phase 1) +// * phase 2 - Reset is deasserted (giving a positive edge on rst_no from phase 1 to phase 2) +// +// The 'ResetPhase0Count' and 'ResetPhase1Count' specify the length of time for phase 0 and phase +// 1 in clock cycles (phase 2 is an unbounded length) +// +// When 'rst_btn_i' is asserted (set to 1) the controller is held at the beginning of phase 1 (reset +// is asserted, and a negative edge seen on `rst_no` when the debounced `rst_btn_i` is first +// asserted). It proceds to phase 2 as normal when the debounced `rst_btn_i` is deasserted. +// +// Debouncing of `rst_btn_i` occurs internally to the module. The `rst_btn_i` input must be in +// a single state for more than `DebounceCount` cycles for that state to take effect. +// +// If the `pll_locked_i` input goes low a new reset will be produced when it goes high again. +// +// The provided `clk_i` is assumed to always be stable and must be independent of the output reset +// `rst_no` and of the PLL providing the `pll_locked_i` input. +// +// The `rst_no` signal is produced directly from a flop to prevent glitches. This flop is clocked +// from `clk_i`. +// +// This module is designed for FPGA implementation as it relies on an 'initial' statement to set the +// power-on contents of registers. + +module rst_ctrl #( + parameter int unsigned ResetPhase0Count = 5, + parameter int unsigned ResetPhase1Count = 200, + parameter int unsigned DebounceCount = 500 +) ( + input clk_i, + input pll_locked_i, + input rst_btn_i, + + output rst_no +); + localparam CounterWidth = $clog2(ResetPhase1Count + 1); + + logic [CounterWidth-1:0] reset_counter_d, reset_counter_q; + logic rst_btn_debounce; + logic rst_n_d, debounce_rst_n_d, rst_n_q, debounce_rst_n_q; + + initial begin + reset_counter_q = '0; + rst_n_q = 1'b1; + debounce_rst_n_q = 1'b1; + end + + always_comb begin + reset_counter_d = reset_counter_q; + + if (rst_btn_debounce && (reset_counter_q >= ResetPhase0Count)) begin + reset_counter_d = ResetPhase0Count; + end else begin + if (pll_locked_i) begin + if (reset_counter_q < ResetPhase1Count) begin + reset_counter_d <= reset_counter_d + 1; + end + end else begin + reset_counter_d = '0; + end + end + end + + always_ff @(posedge clk_i) begin + reset_counter_q <= reset_counter_d; + rst_n_q <= rst_n_d; + debounce_rst_n_q <= debounce_rst_n_d; + end + + debounce #(.ClkCount(DebounceCount)) u_rst_btn_debounce ( + .clk_i, + .rst_ni(debounce_rst_n_q), + + .btn_i(rst_btn_i), + .btn_o(rst_btn_debounce) + ); + + assign rst_n_d = reset_counter_q < ResetPhase0Count ? 1'b1 : + reset_counter_q < ResetPhase1Count ? 1'b0 : + 1'b1; + + assign debounce_rst_n_d = reset_counter_q <= ResetPhase0Count ? 1'b1 : + reset_counter_q < ResetPhase1Count ? 1'b0 : + 1'b1; + assign rst_no = rst_n_q; +endmodule diff --git a/rtl/fpga/top_sonata.sv b/rtl/fpga/top_sonata.sv index 24f68d7d..0c1fb1b5 100644 --- a/rtl/fpga/top_sonata.sv +++ b/rtl/fpga/top_sonata.sv @@ -42,21 +42,11 @@ module top_sonata ( logic [4:0] nav_sw_n; logic [7:0] user_sw_n; - initial begin - reset_counter = 0; - end + logic pll_locked; + logic rst_btn; - always_ff @(posedge mainclk_buf) begin - if (reset_counter != 8'hff) begin - reset_counter <= reset_counter + 8'd1; - end - end - assign top_rst_n = reset_counter < 8'd5 ? 1'b1 : - reset_counter < 8'd200 ? 1'b0 : - nrst_btn; - - assign led_bootok = 1'b1; + assign led_bootok = top_rst_n; // Switch inputs have pull-ups and switches pull to ground when on. Invert here so CPU sees 1 for // on and 0 for off. @@ -70,7 +60,7 @@ module top_sonata ( .SRAMInitFile(SRAMInitFile) ) u_ibex_demo_system ( .clk_sys_i(clk_sys), - .rst_sys_ni(rst_sys_n), + .rst_sys_ni(top_rst_n), .gp_i({user_sw_n, nav_sw_n}), .gp_o({led_user, lcd_backlight, lcd_dc, lcd_rst, lcd_cs}), @@ -84,7 +74,7 @@ module top_sonata ( .spi_tx_o(lcd_copi), .spi_sck_o(lcd_clk), - .trst_ni(rst_sys_n), + .trst_ni(top_rst_n), .tms_i, .tck_i, .td_i, @@ -95,9 +85,16 @@ module top_sonata ( clkgen_sonata clkgen( .IO_CLK(main_clk), .IO_CLK_BUF(mainclk_buf), - .IO_RST_N(top_rst_n), .clk_sys, - .rst_sys_n + .locked(pll_locked) ); + assign rst_btn = ~nrst_btn; + + rst_ctrl u_rst_ctrl ( + .clk_i (mainclk_buf), + .pll_locked_i(pll_locked), + .rst_btn_i (rst_btn), + .rst_no (top_rst_n) + ); endmodule