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_serdes = USB3SerDesModel()
host_usb3_pipe = USB3PIPE(serdes=host_usb3_serdes, sys_clk_freq=sys_clk_freq) host_usb3_pipe = USB3PIPE(serdes=host_usb3_serdes, sys_clk_freq=sys_clk_freq)
self.submodules += host_usb3_serdes, host_usb3_pipe self.submodules += host_usb3_serdes, host_usb3_pipe
self.comb += host_usb3_pipe.ltssm.polling_fsm.skip_lfps.eq(1) # FIXME
# USB3 Device # USB3 Device
dev_usb3_serdes = USB3SerDesModel() dev_usb3_serdes = USB3SerDesModel()
dev_usb3_pipe = USB3PIPE(serdes=dev_usb3_serdes, sys_clk_freq=sys_clk_freq) dev_usb3_pipe = USB3PIPE(serdes=dev_usb3_serdes, sys_clk_freq=sys_clk_freq)
self.submodules += dev_usb3_serdes, dev_usb3_pipe self.submodules += dev_usb3_serdes, dev_usb3_pipe
self.comb += dev_usb3_pipe.ltssm.polling_fsm.skip_lfps.eq(1) # FIXME
# Connect Host <--> Device # Connect Host <--> Device
self.comb += host_usb3_serdes.connect(dev_usb3_serdes) self.comb += host_usb3_serdes.connect(dev_usb3_serdes)
# Simulation End
self.sync += If(host_usb3_pipe.ready & dev_usb3_pipe.ready, Finish())
# Build -------------------------------------------------------------------------------------------- # Build --------------------------------------------------------------------------------------------
def main(): def main():

View File

@ -40,4 +40,3 @@ class USB3PIPE(Module):
self.comb += ltssm.reset.eq(~self.enable) self.comb += ltssm.reset.eq(~self.enable)
self.submodules.ltssm = ltssm self.submodules.ltssm = ltssm
self.comb += self.ready.eq(ltssm.polling_fsm.idle) self.comb += self.ready.eq(ltssm.polling_fsm.idle)

View File

@ -165,90 +165,75 @@ class RXDetectFSM(FSM):
@ResetInserter() @ResetInserter()
class PollingFSM(FSM): class PollingFSM(FSM):
""" Polling Finite State Machine (section 7.5.4)""" """ 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): def __init__(self, serdes, lfps_unit, ts_unit):
self.exit_to_compliance_mode = Signal() self.idle = Signal()
self.exit_to_rx_detect = Signal() self.skip_lfps = Signal() # FIXME: for simulation
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()
# # # # # #
rx_ts2 = Signal() rx_tseq_seen = Signal()
rx_ts1_seen = Signal()
rx_ts2_seen = Signal()
# FSM -------------------------------------------------------------------------------------- # FSM --------------------------------------------------------------------------------------
FSM.__init__(self, reset_state="LFPS") FSM.__init__(self, reset_state="LFPS")
# LFPS State ------------------------------------------------------------------------------- # LFPS State -------------------------------------------------------------------------------
# Generate/Receive Polling LFPS, jump to RX-EQ when received from partner
self.act("LFPS", 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), serdes.rx_align.eq(1),
lfps_unit.tx_polling.eq(1), lfps_unit.tx_polling.eq(1),
If(lfps_unit.rx_polling, If(lfps_unit.rx_polling | self.skip_lfps,
NextState("RX-EQ"), # LFPS handshake. NextState("RX-EQ"),
), )
#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.
) )
# RxEQ State ------------------------------------------------------------------------------- # RxEQ State -------------------------------------------------------------------------------
# Generate/Receive TSEQ, jump to ACTIVE when TSEQ sent and received from partner
self.act("RX-EQ", self.act("RX-EQ",
serdes.rx_align.eq(1), serdes.rx_align.eq(1),
lfps_unit.tx_polling.eq(1),
ts_unit.rx_enable.eq(1), ts_unit.rx_enable.eq(1),
If(ts_unit.rx_tseq, ts_unit.tx_enable.eq(1),
NextState("ACTIVE"), # TSEQ transmitted. 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 ----------------------------------------------------------------------------- # Active State -----------------------------------------------------------------------------
# Generate/Receive TS1, jump to CONFIGURATION when TS1 sent and received from partner
self.act("ACTIVE", self.act("ACTIVE",
ts_unit.rx_enable.eq(1), ts_unit.rx_enable.eq(1),
If(ts_unit.rx_ts1 | ts_unit.rx_ts2, ts_unit.tx_enable.eq(1),
NextState("CONFIGURATION_0"), # 8 consecutiive TS1 or TS2 received. 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 ---------------------------------------------------------------------- # Configuration State ----------------------------------------------------------------------
# Generate/Receive TS2, jump to IDLE when TS2 sent and reveived from partner
self.act("CONFIGURATION_0", self.act("CONFIGURATION",
ts_unit.rx_enable.eq(1), ts_unit.rx_enable.eq(1),
ts_unit.tx_enable.eq(1), ts_unit.tx_enable.eq(1),
ts_unit.tx_ts2.eq(1), ts_unit.tx_ts2.eq(1),
NextValue(rx_ts2, rx_ts2 | ts_unit.rx_ts2), NextValue(rx_ts2_seen, rx_ts2_seen | ts_unit.rx_ts2),
If(rx_ts2 & ts_unit.ts2_generator.done, If(ts_unit.tx_done & rx_ts2_seen,
ts_unit.tx_enable.eq(0), NextState("IDLE"),
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.
) )
# Idle State ------------------------------------------------------------------------------- # Idle State -------------------------------------------------------------------------------
self.act("IDLE", self.act("IDLE",
self.idle.eq(1), 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.
) )
# End State --------------------------------------------------------------------------------
self.act("END")
# Link Training and Status State Machine ----------------------------------------------------------- # Link Training and Status State Machine -----------------------------------------------------------
class LTSSM(Module): class LTSSM(Module):

View File

@ -101,8 +101,8 @@ class TSChecker(Module):
class TSGenerator(Module): class TSGenerator(Module):
def __init__(self, ordered_set, n_ordered_sets): def __init__(self, ordered_set, n_ordered_sets):
self.send = Signal() # i self.start = Signal() # i
self.done = Signal() # i self.done = Signal() # i
self.source = stream.Endpoint([("data", 32), ("ctrl", 4)]) self.source = stream.Endpoint([("data", 32), ("ctrl", 4)])
if ordered_set.name in ["TS1", "TS2"]: 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 -------------------------------------------------------------------------------- # Memory --------------------------------------------------------------------------------
mem_depth = len(ordered_set.to_bytes())//4 mem_depth = len(ordered_set.to_bytes())//4
@ -149,7 +153,7 @@ class TSGenerator(Module):
else: else:
first_ctrl = 1 first_ctrl = 1
self.comb += [ self.comb += [
self.source.valid.eq(self.send | ~self.done), self.source.valid.eq(start_pulse | ~self.done),
If(port.adr == 0, If(port.adr == 0,
self.source.ctrl.eq(first_ctrl), self.source.ctrl.eq(first_ctrl),
).Else( ).Else(
@ -163,7 +167,7 @@ class TSGenerator(Module):
# Count ------------------------------------------------------------------------------------ # Count ------------------------------------------------------------------------------------
count = Signal(max=mem_depth*n_ordered_sets, reset=mem_depth*n_ordered_sets - 1) count = Signal(max=mem_depth*n_ordered_sets, reset=mem_depth*n_ordered_sets - 1)
self.sync += [ self.sync += [
If(self.send & self.done, If(start_pulse,
run.eq(1), run.eq(1),
count.eq(0), count.eq(0),
).Elif(self.done, ).Elif(self.done,
@ -189,13 +193,14 @@ class TSUnit(Module):
self.tx_tseq = Signal() # i self.tx_tseq = Signal() # i
self.tx_ts1 = Signal() # i self.tx_ts1 = Signal() # i
self.tx_ts2 = Signal() # i self.tx_ts2 = Signal() # i
self.tx_done = Signal() # o
# # # # # #
# Ordered Set Checkers --------------------------------------------------------------------- # Ordered Set Checkers ---------------------------------------------------------------------
self.submodules.tseq_checker = tseq_checker = TSChecker(ordered_set=TSEQ, 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) # FIXME: n? 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) # FIXME: n? self.submodules.ts2_checker = ts2_checker = TSChecker(ordered_set=TS2, n_ordered_sets=8)
self.comb += [ self.comb += [
serdes.source.connect(tseq_checker.sink, omit={"ready"}), serdes.source.connect(tseq_checker.sink, omit={"ready"}),
serdes.source.connect(ts1_checker.sink, omit={"ready"}), serdes.source.connect(ts1_checker.sink, omit={"ready"}),
@ -207,22 +212,23 @@ class TSUnit(Module):
] ]
# Ordered Set Generators ------------------------------------------------------------------- # Ordered Set Generators -------------------------------------------------------------------
self.submodules.tseq_generator = tseq_generator = TSGenerator(ordered_set=TSEQ, 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=8) # FIXME: n? 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=8) # FIXME: n? self.submodules.ts2_generator = ts2_generator = TSGenerator(ordered_set=TS2, n_ordered_sets=128) # FIXME: n?
self.comb += [ self.comb += [
If(self.tx_enable, If(self.tx_enable,
If(self.tx_tseq, If(self.tx_tseq,
tseq_generator.send.eq(1), tseq_generator.start.eq(1),
tseq_generator.source.connect(serdes.sink), tseq_generator.source.connect(serdes.sink),
), ),
If(self.tx_ts1, If(self.tx_ts1,
ts1_generator.send.eq(1), ts1_generator.start.eq(1),
ts1_generator.source.connect(serdes.sink), ts1_generator.source.connect(serdes.sink),
), ),
If(self.tx_ts2, If(self.tx_ts2,
ts2_generator.send.eq(1), ts2_generator.start.eq(1),
ts2_generator.source.connect(serdes.sink), ts2_generator.source.connect(serdes.sink),
), ),
) ),
self.tx_done.eq(tseq_generator.done & ts1_generator.done & ts2_generator.done),
] ]