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:
parent
5f331a403c
commit
924079cabd
1
Makefile
1
Makefile
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue