phy/pcs_1000basex: Simplify/Cleanup PCSRX.

This commit is contained in:
Florent Kermarrec 2024-10-15 11:54:31 +02:00
parent faf426f54a
commit 16998377f6
1 changed files with 60 additions and 67 deletions

View File

@ -25,12 +25,6 @@ SGMII_1000MBPS_SPEED = 0b10
SGMII_100MBPS_SPEED = 0b01 SGMII_100MBPS_SPEED = 0b01
SGMII_10MBPS_SPEED = 0b00 SGMII_10MBPS_SPEED = 0b00
CTYPE_C1 = 0b0
CTYPE_C2 = 0b1
ITYPE_I1 = 0b0
ITYPË_I2 = 0b1
# PCS Gearbox -------------------------------------------------------------------------------------- # PCS Gearbox --------------------------------------------------------------------------------------
class PCSGearbox(LiteXModule): class PCSGearbox(LiteXModule):
@ -117,8 +111,8 @@ class PCSTX(LiteXModule):
fsm.act("CONFIG-D", fsm.act("CONFIG-D",
# Send Configuration Word. # Send Configuration Word.
Case(ctype, { Case(ctype, {
CTYPE_C1 : self.encoder.d[0].eq(D(21, 5)), # C1. 0b0 : self.encoder.d[0].eq(D(21, 5)), # /C1/.
CTYPE_C2 : self.encoder.d[0].eq(D( 2, 2)), # C2. 0b1 : self.encoder.d[0].eq(D( 2, 2)), # /C2/.
}), }),
NextValue(ctype, ~ctype), NextValue(ctype, ~ctype),
NextState("CONFIG-REG") NextState("CONFIG-REG")
@ -133,15 +127,15 @@ class PCSTX(LiteXModule):
If(count == (2 - 1), NextState("START")) If(count == (2 - 1), NextState("START"))
) )
fsm.act("IDLE", fsm.act("IDLE",
# Send Idle characters and handle disparity. # Send Idle words and handle disparity.
Case(self.encoder.disparity[0], { Case(self.encoder.disparity[0], {
ITYPE_I1 : self.encoder.d[0].eq(D(5, 6)), # /I1/ preserves disparity. 0b0 : self.encoder.d[0].eq(D(5, 6)), # /I1/ (Preserves disparity).
ITYPË_I2 : self.encoder.d[0].eq(D(16, 2)), # /I2/ flips disparity. 0b1 : self.encoder.d[0].eq(D(16, 2)), # /I2/ (Flips disparity).
}), }),
NextState("START") NextState("START")
) )
fsm.act("DATA", fsm.act("DATA",
# Send Data frame. # Send Data.
timer_enable.eq(1), timer_enable.eq(1),
sink.ready.eq(timer_done), sink.ready.eq(timer_done),
If(sink.valid, If(sink.valid,
@ -166,8 +160,9 @@ class PCSTX(LiteXModule):
class PCSRX(LiteXModule): class PCSRX(LiteXModule):
def __init__(self, lsb_first=False): def __init__(self, lsb_first=False):
self.rx_en = Signal() self.rx_en = Signal()
self.rx_data = Signal(8) self.rx_data = Signal(8)
self.sample_en = Signal()
self.seen_valid_ci = Signal() self.seen_valid_ci = Signal()
self.seen_config_reg = Signal() self.seen_config_reg = Signal()
@ -177,26 +172,12 @@ class PCSRX(LiteXModule):
# SGMII Speed Adaptation. # SGMII Speed Adaptation.
self.sgmii_speed = Signal(2) self.sgmii_speed = Signal(2)
self.sample_en = Signal()
# # # # # #
config_reg_lsb = Signal(8) # Signals.
load_config_reg_lsb = Signal() # --------
load_config_reg_msb = Signal() count = Signal() # Byte counter for config register.
self.sync += [
self.seen_config_reg.eq(0),
If(load_config_reg_lsb,
config_reg_lsb.eq(self.decoder.d)
),
If(load_config_reg_msb,
self.config_reg.eq(Cat(config_reg_lsb, self.decoder.d)),
self.seen_config_reg.eq(1)
)
]
first_preamble_byte = Signal()
self.comb += self.rx_data.eq(Mux(first_preamble_byte, 0x55, self.decoder.d))
# SGMII Timer. # SGMII Timer.
# ------------ # ------------
@ -218,66 +199,77 @@ class PCSRX(LiteXModule):
# Speed adaptation # Speed adaptation
self.comb += self.sample_en.eq(self.rx_en & timer_done) self.comb += self.sample_en.eq(self.rx_en & timer_done)
# FSM.
# ----
self.fsm = fsm = FSM() self.fsm = fsm = FSM()
fsm.act("START", fsm.act("START",
# Wait for a K-character.
If(self.decoder.k, If(self.decoder.k,
# K-character is Config or Idle K28.5.
If(self.decoder.d == K(28, 5), If(self.decoder.d == K(28, 5),
NextState("K28_5") NextValue(count, 0),
NextState("CONFIG-D-OR-IDLE")
), ),
# K-character is Start-of-packet /S/.
If(self.decoder.d == K(27, 7), If(self.decoder.d == K(27, 7),
self.rx_en.eq(1),
timer_enable.eq(1), timer_enable.eq(1),
first_preamble_byte.eq(1), self.rx_en.eq(1),
self.rx_data.eq(0x55), # First Preamble Byte.
NextState("DATA") NextState("DATA")
) )
) )
) )
fsm.act("K28_5", fsm.act("CONFIG-D-OR-IDLE",
NextState("START"), NextState("ERROR"),
If(~self.decoder.k, If(~self.decoder.k,
If((self.decoder.d == D(21, 5)) | (self.decoder.d == D(2, 2)), # Check for Configuration Word.
If((self.decoder.d == D(21, 5)) | # /C1/.
(self.decoder.d == D( 2, 2)), # /C2/.
self.seen_valid_ci.eq(1), self.seen_valid_ci.eq(1),
NextState("CONFIG_REG_LSB") NextState("CONFIG-REG")
), ),
If((self.decoder.d == D(5, 6)) | (self.decoder.d == D(16, 2)), # Check for Idle Word.
# idle If((self.decoder.d == D( 5, 6)) | # /I1/.
(self.decoder.d == D(16, 2)), # /I2/.
self.seen_valid_ci.eq(1), self.seen_valid_ci.eq(1),
NextState("START") NextState("START")
),
)
)
fsm.act("CONFIG_REG_LSB",
If(self.decoder.k,
If(self.decoder.d == K(27, 7),
self.rx_en.eq(1),
timer_enable.eq(1),
first_preamble_byte.eq(1),
NextState("DATA")
).Else(
NextState("START") # error
) )
).Else(
load_config_reg_lsb.eq(1),
NextState("CONFIG_REG_MSB")
) )
) )
fsm.act("CONFIG_REG_MSB", fsm.act("CONFIG-REG",
NextState("ERROR"),
If(~self.decoder.k, If(~self.decoder.k,
load_config_reg_msb.eq(1) # Receive for Configuration Register.
), NextState("CONFIG-REG"),
NextState("START") NextValue(count, count + 1),
Case(count, {
0b0 : NextValue(self.config_reg[:8], self.decoder.d), # LSB.
0b1 : NextValue(self.config_reg[8:], self.decoder.d), # MSB.
}),
If(count == (2 - 1),
self.seen_config_reg.eq(1),
NextState("START")
)
)
) )
fsm.act("DATA", fsm.act("DATA",
If(self.decoder.k, NextState("START"),
NextState("START") If(~self.decoder.k,
).Else( # Receive Data.
timer_enable.eq(1),
self.rx_en.eq(1), self.rx_en.eq(1),
timer_enable.eq(1) self.rx_data.eq(self.decoder.d),
NextState("DATA")
) )
) )
fsm.act("ERROR",
NextState("START")
)
# PCS ---------------------------------------------------------------------------------------------- # PCS ----------------------------------------------------------------------------------------------
# FIXME: Needs similar cleanup than PCSTX/RX.
class PCS(LiteXModule): class PCS(LiteXModule):
def __init__(self, lsb_first=False, check_period=6e-3, more_ack_time=10e-3): def __init__(self, lsb_first=False, check_period=6e-3, more_ack_time=10e-3):
self.tx = ClockDomainsRenamer("eth_tx")(PCSTX(lsb_first=lsb_first)) self.tx = ClockDomainsRenamer("eth_tx")(PCSTX(lsb_first=lsb_first))
@ -292,14 +284,14 @@ class PCS(LiteXModule):
self.restart = Signal() self.restart = Signal()
self.align = Signal() self.align = Signal()
self.lp_abi = BusSynchronizer(16, "eth_rx", "eth_tx") self.lp_abi = BusSynchronizer(16, "eth_rx", "eth_tx")
# # # # # #
# Endpoint interface. # Sink -> TX.
self.comb += self.sink.connect(self.tx.sink, omit={"last_be", "error"}) self.comb += self.sink.connect(self.tx.sink, omit={"last_be", "error"})
# RX -> Source.
rx_en_d = Signal() rx_en_d = Signal()
self.sync.eth_rx += [ self.sync.eth_rx += [
rx_en_d.eq(self.rx.rx_en), rx_en_d.eq(self.rx.rx_en),
@ -308,11 +300,12 @@ class PCS(LiteXModule):
] ]
self.comb += self.source.last.eq(~self.rx.rx_en & rx_en_d) self.comb += self.source.last.eq(~self.rx.rx_en & rx_en_d)
# Main module. # Seen Valid Synchronizer.
seen_valid_ci = PulseSynchronizer("eth_rx", "eth_tx") seen_valid_ci = PulseSynchronizer("eth_rx", "eth_tx")
self.submodules += seen_valid_ci self.submodules += seen_valid_ci
self.comb += seen_valid_ci.i.eq(self.rx.seen_valid_ci) self.comb += seen_valid_ci.i.eq(self.rx.seen_valid_ci)
# Checker.
checker_max_val = ceil(check_period*125e6) checker_max_val = ceil(check_period*125e6)
checker_counter = Signal(max=checker_max_val+1) checker_counter = Signal(max=checker_max_val+1)
checker_tick = Signal() checker_tick = Signal()