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_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():
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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):
|
||||||
|
@ -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),
|
||||||
]
|
]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user