/* * sysmgr.v * * vim: ts=4 sw=4 * * System Clock / Reset generation * * Copyright (C) 2023 Sylvain Munaut * SPDX-License-Identifier: CERN-OHL-P-2.0 */ `default_nettype none module sysmgr ( // Control input wire sys_start, input wire sys_stop, input wire usb_ena, // LED clock ( 6 MHz ) output wire clk_led, output wire rst_led, // System clock ( 24 MHz ) output wire clk_sys, output wire rst_sys, // USB ( 48 MHz ) output wire clk_usb, output wire rst_usb ); // Signals // ------- wire clk_osc; wire clk_base; wire pll_lock; reg [3:0] clk_div; reg clk_usb_i; reg clk_sys_i; wire clk_led_i; reg [3:0] rst_cnt; wire rst_i; wire rst_gbuf; reg [2:0] sys_start_s; reg [2:0] sys_stop_s; wire usb_rst_trig; reg [3:0] usb_rst_cnt; wire usb_rst_i; reg [3:0] usb_off_dly; reg sys_off; wire usb_off; // SB_HFOSC // ------- // Generates 12 MHz (* ROUTE_THROUGH_FABRIC = 1 *) SB_HFOSC #( .CLKHF_DIV("0b10") ) osc_I ( .CLKHFPU(1'b1), .CLKHFEN(1'b1), .CLKHF(clk_osc) ); // PLL // --- SB_PLL40_CORE #( .DIVR (4'b0000), .DIVF (7'b0111111), .DIVQ (3'b011), .FILTER_RANGE (3'b001), .FEEDBACK_PATH ("SIMPLE"), .DELAY_ADJUSTMENT_MODE_FEEDBACK ("FIXED"), .FDA_FEEDBACK (4'b0000), .SHIFTREG_DIV_MODE (2'b00), .PLLOUT_SELECT ("GENCLK"), .ENABLE_ICEGATE (1'b0) ) pll_I ( .REFERENCECLK (clk_osc), .PLLOUTCORE (clk_base), .PLLOUTGLOBAL (), .EXTFEEDBACK (1'b0), .DYNAMICDELAY (8'h00), .RESETB (1'b1), .BYPASS (1'b0), .LATCHINPUTVALUE (1'b0), .LOCK (pll_lock), .SDI (1'b0), .SDO (), .SCLK (1'b0) ); // Dividers // -------- // Counter always @(posedge clk_base) clk_div <= clk_div + 1; // USB is div-by-2 + gated always @(posedge clk_base) clk_usb_i <= clk_div[0] & ~usb_off; // SYS is div-by-4 + gated always @(posedge clk_base) clk_sys_i <= clk_div[1] & ~sys_off; // LED is div-by-16 assign clk_led_i = clk_div[3]; // Global buffers SB_GB clk_usb_gbuf_I ( .USER_SIGNAL_TO_GLOBAL_BUFFER(clk_usb_i), .GLOBAL_BUFFER_OUTPUT(clk_usb) ); SB_GB clk_sys_gbuf_I ( .USER_SIGNAL_TO_GLOBAL_BUFFER(clk_sys_i), .GLOBAL_BUFFER_OUTPUT(clk_sys) ); SB_GB clk_led_gbuf_I ( .USER_SIGNAL_TO_GLOBAL_BUFFER(clk_led_i), .GLOBAL_BUFFER_OUTPUT(clk_led) ); // USB Enable // ---------- // Delay falling latch signal always @(posedge clk_base) usb_off_dly <= usb_ena ? 4'b0000 : { usb_off_dly[2:0], 1'b1 }; assign usb_off = usb_off_dly[3]; // USB Reset // --------- // Reset trigger assign usb_rst_trig = ~usb_ena | ~pll_lock; // Reset counter always @(posedge clk_usb or posedge usb_rst_trig) if (usb_rst_trig) usb_rst_cnt <= 4'h8; else usb_rst_cnt <= usb_rst_cnt + usb_rst_i; assign usb_rst_i = usb_rst_cnt[3]; // Global buffer SB_GB rst_usb_gbuf_I ( .USER_SIGNAL_TO_GLOBAL_BUFFER(usb_rst_i), .GLOBAL_BUFFER_OUTPUT(rst_usb) ); // SYS Enable // ---------- // Synch triggers always @(posedge clk_base) begin sys_start_s <= { ~sys_start_s[1] & sys_start_s[0], sys_start_s[0], sys_start }; sys_stop_s <= { ~sys_stop_s[1] & sys_stop_s[0], sys_stop_s[0], sys_stop }; end always @(posedge clk_base) sys_off <= (sys_off & ~rst_i & ~sys_start_s[2]) | sys_stop_s[2]; // Reset LED / SYS // --------------- // Counter always @(posedge clk_led or negedge pll_lock) if (~pll_lock) rst_cnt <= 4'h8; else rst_cnt <= rst_cnt + rst_i; assign rst_i = rst_cnt[3]; // Global buffer SB_GB rst_gbuf_I ( .USER_SIGNAL_TO_GLOBAL_BUFFER(rst_i), .GLOBAL_BUFFER_OUTPUT(rst_gbuf) ); // Distribution assign rst_led = rst_gbuf; assign rst_sys = rst_gbuf; endmodule // sysmgr