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 += pmd_dp83223
MODULES += pmd_dp83223_rx
MODULES += reset_sync
MODULES += scramble
MODULES += uart_tx
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,
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`
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