forked from M-Labs/artiq
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:
parent
73ab71f443
commit
b52f253dbd
|
@ -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"}),
|
||||
|
||||
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"}),
|
||||
# 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
|
||||
|
||||
# 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),
|
||||
),
|
||||
If(idle_low | idle_high,
|
||||
idle.eq(1),
|
||||
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**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,
|
||||
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")
|
||||
|
||||
|
|
Loading…
Reference in New Issue