Simplify OOB reset by clock division (#2217)

* oob: simply logic by dividing into clk100

* replace clk100 clk ctrl with clk200 async reset

* fix comment (singular/plural)

* oob reset: invoke platform commands locally

* cleanup

* oob reset: add async reset import

* fix duplicated comment
pull/2221/head
occheung 2023-09-25 17:02:49 -07:00 committed by GitHub
parent 73ab71f443
commit b52f253dbd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 65 additions and 39 deletions

View File

@ -1,4 +1,5 @@
from migen import *
from migen.genlib.resetsync import AsyncResetSynchronizer
from misoc.interconnect.csr import *
from misoc.cores.code_8b10b import SingleEncoder, Decoder
from artiq.gateware.drtio.core import TransceiverInterface, ChannelInterface
@ -396,53 +397,78 @@ class SerdesSingle(Module):
class OOBReset(Module):
def __init__(self, iserdes_o):
ce_counter = Signal(13)
activity_ce = Signal()
transition_ce = Signal()
def __init__(self, platform, iserdes_o):
self.clock_domains.cd_clk100 = ClockDomain()
self.specials += [
Instance("BUFR",
i_I=ClockSignal("clk200"),
o_O=ClockSignal("clk100"),
p_BUFR_DIVIDE="2"),
AsyncResetSynchronizer(self.cd_clk100, ResetSignal("clk200")),
]
self.sync.clk200 += Cat(ce_counter, activity_ce).eq(ce_counter + 1)
self.comb += transition_ce.eq(ce_counter[0])
idle_low_meta = Signal()
idle_high_meta = Signal()
idle_low = Signal()
idle_high = Signal()
idle = Signal()
self.rst = Signal(reset=1)
# Detect the lack of transitions (idle) within 2 clk200 cycles
self.specials += [
Instance("FDCE", p_INIT=1, i_D=1, i_CLR=iserdes_o,
i_CE=transition_ce, i_C=ClockSignal("clk200"), o_Q=idle_low_meta,
attr={"async_reg", "ars_ff1"}),
Instance("FDCE", p_INIT=1, i_D=idle_low_meta, i_CLR=0,
i_CE=transition_ce, i_C=ClockSignal("clk200"), o_Q=idle_low,
attr={"async_reg", "ars_ff2"}),
# Detect the lack of transitions (idle) within a clk100 cycle
for idle, source in [
(idle_low, iserdes_o), (idle_high, ~iserdes_o)]:
idle_meta = Signal()
ff_pair = [ff1, ff2] = [
Instance("FDCE", p_INIT=1, i_D=1, i_CLR=source,
i_CE=1, i_C=ClockSignal("clk100"), o_Q=idle_meta,
attr={"async_reg"}),
Instance("FDCE", p_INIT=1, i_D=idle_meta, i_CLR=0,
i_CE=1, i_C=ClockSignal("clk100"), o_Q=idle,
attr={"async_reg"}),
]
self.specials += ff_pair
Instance("FDCE", p_INIT=1, i_D=1, i_CLR=~iserdes_o,
i_CE=transition_ce, i_C=ClockSignal("clk200"), o_Q=idle_high_meta,
attr={"async_reg", "ars_ff1"}),
Instance("FDCE", p_INIT=1, i_D=idle_high_meta, i_CLR=0,
i_CE=transition_ce, i_C=ClockSignal("clk200"), o_Q=idle_high,
attr={"async_reg", "ars_ff2"}),
]
platform.add_platform_command(
"set_false_path -quiet -to {ff1}/CLR", ff1=ff1)
# Capture transition detected by FF1/Q in FF2/D
platform.add_platform_command(
"set_max_delay 2 -quiet "
"-from {ff1}/Q -to {ff2}/D", ff1=ff1, ff2=ff2)
# Detect activity for the last 2**13 clk200 cycles
# The 2**13 cycles are fully partitioned into 2**12 time segments of 2
# cycles in duration. If there exists 2-cycle time segment without
# signal level transition, rst is asserted.
self.sync.clk200 += [
If(activity_ce,
idle.eq(0),
self.rst.eq(idle),
),
# Detect activity for the last 2**15 clk100 cycles
self.submodules.fsm = fsm = ClockDomainsRenamer("clk100")(
FSM(reset_state="WAIT_TRANSITION"))
counter = Signal(15, reset=0x7FFF)
# Keep sysclk reset asserted until transition is detected for a
# continuous 2**15 clk100 cycles
fsm.act("WAIT_TRANSITION",
self.rst.eq(1),
If(idle_low | idle_high,
idle.eq(1),
self.rst.eq(1),
),
]
NextValue(counter, 0x7FFF),
).Else(
If(counter == 0,
NextState("WAIT_NO_TRANSITION"),
NextValue(counter, 0x7FFF),
).Else(
NextValue(counter, counter - 1),
)
)
)
# Reassert sysclk reset if there are no transition for the last 2**15
# clk100 cycles.
fsm.act("WAIT_NO_TRANSITION",
self.rst.eq(0),
If(idle_low | idle_high,
If(counter == 0,
NextState("WAIT_TRANSITION"),
NextValue(counter, 0x7FFF),
).Else(
NextValue(counter, counter - 1),
)
).Else(
NextValue(counter, 0x7FFF),
)
)
class EEMSerdes(Module, TransceiverInterface, AutoCSR):
@ -526,7 +552,7 @@ class EEMSerdes(Module, TransceiverInterface, AutoCSR):
self.submodules += serdes_list
self.submodules.oob_reset = OOBReset(serdes_list[0].rx_serdes.o[0])
self.submodules.oob_reset = OOBReset(platform, serdes_list[0].rx_serdes.o[0])
self.rst = self.oob_reset.rst
self.rst.attr.add("no_retiming")