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 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")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue