Add reset synchronizer

Add a reset synchronizer to ensure synchronous reset release. There is
also a glitch filter to reject spurious resets. It will reject pulses
shorter than 5 ns (or around 1.25 ns per LUT).

Signed-off-by: Sean Anderson <seanga2@gmail.com>
This commit is contained in:
Sean Anderson 2023-03-05 16:42:16 -05:00
parent 5f331a403c
commit 924079cabd
4 changed files with 102 additions and 0 deletions

View File

@ -146,6 +146,7 @@ MODULES += pcs_tx
MODULES += phy_core MODULES += phy_core
MODULES += pmd_dp83223 MODULES += pmd_dp83223
MODULES += pmd_dp83223_rx MODULES += pmd_dp83223_rx
MODULES += reset_sync
MODULES += scramble MODULES += scramble
MODULES += uart_tx MODULES += uart_tx
MODULES += uart_rx MODULES += uart_rx

View File

@ -204,6 +204,12 @@ entire rest of the data path up to the PCS (when we can finally align the data)
must handle these edge cases. However, it avoids the internal, must handle these edge cases. However, it avoids the internal,
nebulously-specified, and limited-in-number iCE40 PLLs. nebulously-specified, and limited-in-number iCE40 PLLs.
=== `reset_sync`
This module synchronizes external reset signals (asynchronous assert and
release) into the local clock domain (asynchronous assert, desynchronous
release). A glitch filter suppresses spurious resets.
=== `scramble` === `scramble`
This module implements a scrambler as described in ANSI X3.264-1995 section This module implements a scrambler as described in ANSI X3.264-1995 section

50
rtl/reset_sync.v Normal file
View File

@ -0,0 +1,50 @@
// SPDX-License-Identifier: AGPL-3.0-Only
/*
* Copyright (C) 2023 Sean Anderson <seanga2@gmail.com>
*/
`include "common.vh"
module reset_sync (
input clk,
input rst_in,
output reg rst_out
);
wire rst;
reg rst_last;
initial rst_last = 1;
initial rst_out = 1;
`ifdef SYNTHESIS
/* Filter out glitches */
wire [3:0] rst_delay;
assign rst_delay[0] = rst_in;
assign rst = &rst_delay;
genvar i;
generate for (i = 0; i < 3; i = i + 1) begin
(* keep *)
SB_LUT4 #(
.LUT_INIT(16'hff00)
) filter (
.I3(rst_delay[i]),
.O(rst_delay[i + 1])
);
end endgenerate
`else
assign rst = rst_in;
`endif
always @(posedge clk, posedge rst) begin
if (rst) begin
rst_last <= 1;
rst_out <= 1;
end else begin
rst_last <= rst;
rst_out <= rst_last;
end
end
endmodule

45
tb/reset_sync.py Normal file
View File

@ -0,0 +1,45 @@
# SPDX-License-Identifier: AGPL-3.0-Only
# Copyright (C) 2023 Sean Anderson <seanga2@gmail.com>
import cocotb
from cocotb.binary import BinaryValue
from cocotb.clock import Clock
from cocotb.triggers import ReadOnly, RisingEdge, Timer
@cocotb.test(timeout_time=100, timeout_unit='us')
async def test_bridge(sync):
sync.clk.value = BinaryValue('Z')
sync.rst_in.value = 0
await Timer(1)
assert sync.rst_out.value
await cocotb.start(Clock(sync.clk, 8, units='ns').start())
await RisingEdge(sync.clk)
assert sync.rst_out.value
await RisingEdge(sync.clk)
assert sync.rst_out.value
await RisingEdge(sync.clk)
assert not sync.rst_out.value
await Timer(1)
assert not sync.rst_out.value
sync.rst_in.value = 1
await ReadOnly()
assert sync.rst_out.value
await Timer(1)
sync.rst_in.value = 0
assert sync.rst_out.value
await RisingEdge(sync.clk)
assert sync.rst_out.value
await RisingEdge(sync.clk)
assert sync.rst_out.value
await RisingEdge(sync.clk)
assert not sync.rst_out.value