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