mirror of
https://github.com/enjoy-digital/usb3_pipe.git
synced 2025-01-04 10:18:41 +08:00
sim/ltssm: rework/simplify polling fsm, going to polling idle in simulation
This commit is contained in:
parent
05e30be3ee
commit
8803c75bbd
5
sim.py
5
sim.py
@ -50,15 +50,20 @@ class USB3PIPESim(SoCMini):
|
||||
host_usb3_serdes = USB3SerDesModel()
|
||||
host_usb3_pipe = USB3PIPE(serdes=host_usb3_serdes, sys_clk_freq=sys_clk_freq)
|
||||
self.submodules += host_usb3_serdes, host_usb3_pipe
|
||||
self.comb += host_usb3_pipe.ltssm.polling_fsm.skip_lfps.eq(1) # FIXME
|
||||
|
||||
# USB3 Device
|
||||
dev_usb3_serdes = USB3SerDesModel()
|
||||
dev_usb3_pipe = USB3PIPE(serdes=dev_usb3_serdes, sys_clk_freq=sys_clk_freq)
|
||||
self.submodules += dev_usb3_serdes, dev_usb3_pipe
|
||||
self.comb += dev_usb3_pipe.ltssm.polling_fsm.skip_lfps.eq(1) # FIXME
|
||||
|
||||
# Connect Host <--> Device
|
||||
self.comb += host_usb3_serdes.connect(dev_usb3_serdes)
|
||||
|
||||
# Simulation End
|
||||
self.sync += If(host_usb3_pipe.ready & dev_usb3_pipe.ready, Finish())
|
||||
|
||||
# Build --------------------------------------------------------------------------------------------
|
||||
|
||||
def main():
|
||||
|
@ -40,4 +40,3 @@ class USB3PIPE(Module):
|
||||
self.comb += ltssm.reset.eq(~self.enable)
|
||||
self.submodules.ltssm = ltssm
|
||||
self.comb += self.ready.eq(ltssm.polling_fsm.idle)
|
||||
|
||||
|
@ -165,90 +165,75 @@ class RXDetectFSM(FSM):
|
||||
@ResetInserter()
|
||||
class PollingFSM(FSM):
|
||||
""" Polling Finite State Machine (section 7.5.4)"""
|
||||
# FIXME: Simplified State Machine for initial tests, implement exits and timeouts.
|
||||
def __init__(self, serdes, lfps_unit, ts_unit):
|
||||
self.exit_to_compliance_mode = Signal()
|
||||
self.exit_to_rx_detect = Signal()
|
||||
self.exit_to_ss_disabled = Signal()
|
||||
self.exit_to_loopback = Signal()
|
||||
self.exit_to_hot_reset = Signal()
|
||||
self.exit_to_u0 = Signal()
|
||||
self.idle = Signal()
|
||||
self.idle = Signal()
|
||||
self.skip_lfps = Signal() # FIXME: for simulation
|
||||
|
||||
# # #
|
||||
|
||||
rx_ts2 = Signal()
|
||||
rx_tseq_seen = Signal()
|
||||
rx_ts1_seen = Signal()
|
||||
rx_ts2_seen = Signal()
|
||||
|
||||
# FSM --------------------------------------------------------------------------------------
|
||||
FSM.__init__(self, reset_state="LFPS")
|
||||
|
||||
# LFPS State -------------------------------------------------------------------------------
|
||||
# Generate/Receive Polling LFPS, jump to RX-EQ when received from partner
|
||||
self.act("LFPS",
|
||||
NextValue(rx_ts2, 0),
|
||||
NextValue(rx_tseq_seen, 0),
|
||||
NextValue(rx_ts1_seen, 0),
|
||||
NextValue(rx_ts2_seen, 0),
|
||||
serdes.rx_align.eq(1),
|
||||
lfps_unit.tx_polling.eq(1),
|
||||
If(lfps_unit.rx_polling,
|
||||
NextState("RX-EQ"), # LFPS handshake.
|
||||
),
|
||||
#self.exit_to_compliance_mode.eq(1), # First LFPS timeout.
|
||||
#self.exit_to_ss_disabled.eq(1), # Subsequent LFPS timeouts (Dev) or directed (DS).
|
||||
#self.exit_to_rx_detect.eq(1), # Subsequent LFPS timeouts (DS).
|
||||
#NextState("END"), # On any exit case.
|
||||
If(lfps_unit.rx_polling | self.skip_lfps,
|
||||
NextState("RX-EQ"),
|
||||
)
|
||||
)
|
||||
|
||||
# RxEQ State -------------------------------------------------------------------------------
|
||||
# Generate/Receive TSEQ, jump to ACTIVE when TSEQ sent and received from partner
|
||||
self.act("RX-EQ",
|
||||
serdes.rx_align.eq(1),
|
||||
lfps_unit.tx_polling.eq(1),
|
||||
ts_unit.rx_enable.eq(1),
|
||||
If(ts_unit.rx_tseq,
|
||||
NextState("ACTIVE"), # TSEQ transmitted.
|
||||
ts_unit.tx_enable.eq(1),
|
||||
ts_unit.tx_tseq.eq(1),
|
||||
NextValue(rx_tseq_seen, rx_tseq_seen | ts_unit.rx_tseq),
|
||||
If(ts_unit.tx_done & rx_tseq_seen,
|
||||
NextState("ACTIVE"),
|
||||
),
|
||||
#self.exit_to_ss_disabled.eq(1), # Directed (DS).
|
||||
#NextState("END"), # On any exit case.
|
||||
)
|
||||
|
||||
# Active State -----------------------------------------------------------------------------
|
||||
# Generate/Receive TS1, jump to CONFIGURATION when TS1 sent and received from partner
|
||||
self.act("ACTIVE",
|
||||
ts_unit.rx_enable.eq(1),
|
||||
If(ts_unit.rx_ts1 | ts_unit.rx_ts2,
|
||||
NextState("CONFIGURATION_0"), # 8 consecutiive TS1 or TS2 received.
|
||||
ts_unit.tx_enable.eq(1),
|
||||
ts_unit.tx_ts1.eq(1),
|
||||
NextValue(rx_ts1_seen, rx_ts1_seen | ts_unit.rx_ts1),
|
||||
If(ts_unit.tx_done & rx_ts1_seen,
|
||||
NextState("CONFIGURATION"),
|
||||
),
|
||||
#self.exit_to_ss_disabled.eq(1), # Timeout (Dev) or directed (DS).
|
||||
#self.exit_to_rx_detect.eq(1), # Timeout (DS).
|
||||
#NextState("END") # On any exit case.
|
||||
)
|
||||
|
||||
# Configuration State ----------------------------------------------------------------------
|
||||
|
||||
self.act("CONFIGURATION_0",
|
||||
# Generate/Receive TS2, jump to IDLE when TS2 sent and reveived from partner
|
||||
self.act("CONFIGURATION",
|
||||
ts_unit.rx_enable.eq(1),
|
||||
ts_unit.tx_enable.eq(1),
|
||||
ts_unit.tx_ts2.eq(1),
|
||||
NextValue(rx_ts2, rx_ts2 | ts_unit.rx_ts2),
|
||||
If(rx_ts2 & ts_unit.ts2_generator.done,
|
||||
ts_unit.tx_enable.eq(0),
|
||||
ts_unit.tx_ts2.eq(0),
|
||||
NextState("IDLE"), # TS2 handshake.
|
||||
),
|
||||
#self.exit_to_ss_disabled.eq(1), # Timeout (Dev) or directed (DS).
|
||||
#self.exit_to_rx_detect.eq(1), # Timeout (DS).
|
||||
#NextState("END"), # On any exit case.
|
||||
NextValue(rx_ts2_seen, rx_ts2_seen | ts_unit.rx_ts2),
|
||||
If(ts_unit.tx_done & rx_ts2_seen,
|
||||
NextState("IDLE"),
|
||||
)
|
||||
)
|
||||
|
||||
# Idle State -------------------------------------------------------------------------------
|
||||
self.act("IDLE",
|
||||
self.idle.eq(1),
|
||||
#self.exit_to_ss_disabled.eq(1), # Timeout (Dev) or directed (DS).
|
||||
#self.exit_to_rx_detect.eq(1), # Timeout (DS).
|
||||
#self.exit_to_loopback.eq(1), # Directed.
|
||||
#self.exit_to_hot_reset.eq(1), # Directed.
|
||||
#self.exit_to_u0.eq(1), # Idle symbol handshake.
|
||||
#NextState("END"), # On any exit case.
|
||||
self.idle.eq(1)
|
||||
)
|
||||
|
||||
# End State --------------------------------------------------------------------------------
|
||||
self.act("END")
|
||||
|
||||
# Link Training and Status State Machine -----------------------------------------------------------
|
||||
|
||||
class LTSSM(Module):
|
||||
|
@ -101,8 +101,8 @@ class TSChecker(Module):
|
||||
|
||||
class TSGenerator(Module):
|
||||
def __init__(self, ordered_set, n_ordered_sets):
|
||||
self.send = Signal() # i
|
||||
self.done = Signal() # i
|
||||
self.start = Signal() # i
|
||||
self.done = Signal() # i
|
||||
self.source = stream.Endpoint([("data", 32), ("ctrl", 4)])
|
||||
|
||||
if ordered_set.name in ["TS1", "TS2"]:
|
||||
@ -112,7 +112,11 @@ class TSGenerator(Module):
|
||||
|
||||
# # #
|
||||
|
||||
run = Signal()
|
||||
start_d = Signal()
|
||||
start_pulse = Signal()
|
||||
run = Signal()
|
||||
self.sync += start_d.eq(self.start)
|
||||
self.comb += start_pulse.eq(self.start & ~start_d)
|
||||
|
||||
# Memory --------------------------------------------------------------------------------
|
||||
mem_depth = len(ordered_set.to_bytes())//4
|
||||
@ -149,7 +153,7 @@ class TSGenerator(Module):
|
||||
else:
|
||||
first_ctrl = 1
|
||||
self.comb += [
|
||||
self.source.valid.eq(self.send | ~self.done),
|
||||
self.source.valid.eq(start_pulse | ~self.done),
|
||||
If(port.adr == 0,
|
||||
self.source.ctrl.eq(first_ctrl),
|
||||
).Else(
|
||||
@ -163,7 +167,7 @@ class TSGenerator(Module):
|
||||
# Count ------------------------------------------------------------------------------------
|
||||
count = Signal(max=mem_depth*n_ordered_sets, reset=mem_depth*n_ordered_sets - 1)
|
||||
self.sync += [
|
||||
If(self.send & self.done,
|
||||
If(start_pulse,
|
||||
run.eq(1),
|
||||
count.eq(0),
|
||||
).Elif(self.done,
|
||||
@ -189,13 +193,14 @@ class TSUnit(Module):
|
||||
self.tx_tseq = Signal() # i
|
||||
self.tx_ts1 = Signal() # i
|
||||
self.tx_ts2 = Signal() # i
|
||||
self.tx_done = Signal() # o
|
||||
|
||||
# # #
|
||||
|
||||
# Ordered Set Checkers ---------------------------------------------------------------------
|
||||
self.submodules.tseq_checker = tseq_checker = TSChecker(ordered_set=TSEQ, n_ordered_sets=8) # FIXME: n?
|
||||
self.submodules.ts1_checker = ts1_checker = TSChecker(ordered_set=TS1, n_ordered_sets=8) # FIXME: n?
|
||||
self.submodules.ts2_checker = ts2_checker = TSChecker(ordered_set=TS2, n_ordered_sets=8) # FIXME: n?
|
||||
self.submodules.tseq_checker = tseq_checker = TSChecker(ordered_set=TSEQ, n_ordered_sets=2048)
|
||||
self.submodules.ts1_checker = ts1_checker = TSChecker(ordered_set=TS1, n_ordered_sets=8)
|
||||
self.submodules.ts2_checker = ts2_checker = TSChecker(ordered_set=TS2, n_ordered_sets=8)
|
||||
self.comb += [
|
||||
serdes.source.connect(tseq_checker.sink, omit={"ready"}),
|
||||
serdes.source.connect(ts1_checker.sink, omit={"ready"}),
|
||||
@ -207,22 +212,23 @@ class TSUnit(Module):
|
||||
]
|
||||
|
||||
# Ordered Set Generators -------------------------------------------------------------------
|
||||
self.submodules.tseq_generator = tseq_generator = TSGenerator(ordered_set=TSEQ, n_ordered_sets=8) # FIXME: n?
|
||||
self.submodules.ts1_generator = ts1_generator = TSGenerator(ordered_set=TS1, n_ordered_sets=8) # FIXME: n?
|
||||
self.submodules.ts2_generator = ts2_generator = TSGenerator(ordered_set=TS2, n_ordered_sets=8) # FIXME: n?
|
||||
self.submodules.tseq_generator = tseq_generator = TSGenerator(ordered_set=TSEQ, n_ordered_sets=65536)
|
||||
self.submodules.ts1_generator = ts1_generator = TSGenerator(ordered_set=TS1, n_ordered_sets=128) # FIXME: n?
|
||||
self.submodules.ts2_generator = ts2_generator = TSGenerator(ordered_set=TS2, n_ordered_sets=128) # FIXME: n?
|
||||
self.comb += [
|
||||
If(self.tx_enable,
|
||||
If(self.tx_tseq,
|
||||
tseq_generator.send.eq(1),
|
||||
tseq_generator.start.eq(1),
|
||||
tseq_generator.source.connect(serdes.sink),
|
||||
),
|
||||
If(self.tx_ts1,
|
||||
ts1_generator.send.eq(1),
|
||||
ts1_generator.start.eq(1),
|
||||
ts1_generator.source.connect(serdes.sink),
|
||||
),
|
||||
If(self.tx_ts2,
|
||||
ts2_generator.send.eq(1),
|
||||
ts2_generator.start.eq(1),
|
||||
ts2_generator.source.connect(serdes.sink),
|
||||
),
|
||||
)
|
||||
),
|
||||
self.tx_done.eq(tseq_generator.done & ts1_generator.done & ts2_generator.done),
|
||||
]
|
||||
|
Loading…
x
Reference in New Issue
Block a user