sim/ltssm: rework/simplify polling fsm, going to polling idle in simulation

This commit is contained in:
Florent Kermarrec 2019-10-09 18:38:46 +02:00
parent 05e30be3ee
commit 8803c75bbd
4 changed files with 58 additions and 63 deletions

5
sim.py
View File

@ -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():

View File

@ -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)

View File

@ -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):

View File

@ -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),
]