xmas-snoopy/gateware/rtl/sysmgr_1.v

210 lines
3.9 KiB
Verilog

/*
* sysmgr.v
*
* vim: ts=4 sw=4
*
* System Clock / Reset generation
*
* Copyright (C) 2023 Sylvain Munaut <tnt@246tNt.com>
* 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