phy/pcs_1000basex: Simplify/Cleanup PCSTX.

This commit is contained in:
Florent Kermarrec 2024-10-15 10:19:53 +02:00
parent 8a3e0a23aa
commit 313e7a985c
1 changed files with 86 additions and 96 deletions

View File

@ -19,128 +19,120 @@ from litex.soc.cores.code_8b10b import K, D, Encoder, Decoder
from liteeth.common import * from liteeth.common import *
# Constants / Helpers ------------------------------------------------------------------------------
SGMII_1000MBPS_SPEED = 0b10
SGMII_100MBPS_SPEED = 0b01
SGMII_10MBPS_SPEED = 0b00
CTYPE_C1 = 0b0
CTYPE_C2 = 0b1
ITYPE_I1 = 0b0
ITYPË_I2 = 0b1
# PCS TX ------------------------------------------------------------------------------------------- # PCS TX -------------------------------------------------------------------------------------------
class PCSTX(LiteXModule): class PCSTX(LiteXModule):
def __init__(self, lsb_first=False): def __init__(self, lsb_first=False):
self.config_valid = Signal() self.config_valid = Signal()
self.config_reg = Signal(16) self.config_reg = Signal(16) # Config register (16-bit).
self.tx_valid = Signal() self.sgmii_speed = Signal(2) # SGMII speed.
self.tx_ready = Signal() self.sink = sink = stream.Endpoint([("data", 8)]) # Data input.
self.tx_data = Signal(8)
self.encoder = Encoder(lsb_first=lsb_first) self.encoder = Encoder(lsb_first=lsb_first) # 8b/10b encoder.
# SGMII Speed Adaptation # Signals.
self.sgmii_speed = Signal(2) # --------
count = Signal() # Byte counter for config register.
parity = Signal() # Parity for /R/ extension.
ctype = Signal() # Toggles config type.
# # # # SGMII timer.
# ------------
parity = Signal() timer = Signal(max=100)
c_type = Signal() timer_done = Signal()
self.sync += parity.eq(~parity) timer_enable = Signal()
self.comb += timer_done.eq(timer == 0)
config_reg_buffer = Signal(16)
load_config_reg_buffer = Signal()
self.sync += If(load_config_reg_buffer, config_reg_buffer.eq(self.config_reg))
# Timer for SGMII data rates.
timer = Signal(max=1000)
timer_en = Signal()
self.sync += [ self.sync += [
If(~timer_en | (timer == 0), timer.eq(timer - 1),
If(~timer_enable | timer_done,
Case(self.sgmii_speed, { Case(self.sgmii_speed, {
0b00: timer.eq(99), SGMII_10MBPS_SPEED : timer.eq(99),
0b01: timer.eq( 9), SGMII_100MBPS_SPEED : timer.eq(9),
0b10: timer.eq( 0), SGMII_1000MBPS_SPEED : timer.eq(0),
}) })
).Elif(timer_en,
timer.eq(timer - 1)
) )
] ]
# FSM.
# ----
self.fsm = fsm = FSM() self.fsm = fsm = FSM()
fsm.act("START", fsm.act("START",
If(self.config_valid, If(self.config_valid,
self.tx_ready.eq(1), # Discard TX data if we are in config_reg phase.
load_config_reg_buffer.eq(1),
self.encoder.k[0].eq(1), self.encoder.k[0].eq(1),
self.encoder.d[0].eq(K(28, 5)), self.encoder.d[0].eq(K(28, 5)),
NextState("CONFIG_D") NextValue(count, 0),
NextState("CONFIG-D")
).Else( ).Else(
If(self.tx_valid, If(sink.valid,
# The first byte sent is replaced by /S/.
self.tx_ready.eq((timer == 0)),
timer_en.eq(1),
self.encoder.k[0].eq(1), self.encoder.k[0].eq(1),
self.encoder.d[0].eq(K(27, 7)), self.encoder.d[0].eq(K(27, 7)), # Start-of-packet /S/.
NextState("DATA") NextState("DATA")
).Else( ).Else(
self.tx_ready.eq(1), # Discard TX data.
self.encoder.k[0].eq(1), self.encoder.k[0].eq(1),
self.encoder.d[0].eq(K(28, 5)), self.encoder.d[0].eq(K(28, 5)),
NextState("IDLE") NextState("IDLE")
) )
) )
) )
fsm.act("CONFIG_D", fsm.act("CONFIG-D",
If(c_type, # Send Configuration Word.
self.encoder.d[0].eq(D(2, 2)) Case(ctype, {
).Else( CTYPE_C1 : self.encoder.d[0].eq(D(21, 5)), # C1.
self.encoder.d[0].eq(D(21, 5)) CTYPE_C2 : self.encoder.d[0].eq(D( 2, 2)), # C2.
), }),
NextValue(c_type, ~c_type), NextValue(ctype, ~ctype),
NextState("CONFIG_REG_LSB") NextState("CONFIG-REG")
), ),
fsm.act("CONFIG_REG_LSB", fsm.act("CONFIG-REG",
self.encoder.d[0].eq(config_reg_buffer[:8]), # Send Configuration Register.
NextState("CONFIG_REG_MSB") NextValue(count, count + 1),
) Case(count, {
fsm.act("CONFIG_REG_MSB", 0 : self.encoder.d[0].eq(self.config_reg[:8]), # LSB.
self.encoder.d[0].eq(config_reg_buffer[8:]), 1 : self.encoder.d[0].eq(self.config_reg[8:]), # MSB.
NextState("START") }),
If(count == (2 - 1), NextState("START"))
) )
fsm.act("IDLE", fsm.act("IDLE",
# Due to latency in the encoder, we read here the disparity # Send Idle characters and handle disparity.
# just before the K28.5 was sent. K28.5 flips the disparity. Case(self.encoder.disparity[0], {
If(self.encoder.disparity[0], ITYPE_I1 : self.encoder.d[0].eq(D(5, 6)), # /I1/ preserves disparity.
# Correcting /I1/ (D5.6 preserves the disparity). ITYPË_I2 : self.encoder.d[0].eq(D(16, 2)), # /I2/ flips disparity.
self.encoder.d[0].eq(D(5, 6)) }),
).Else(
# Preserving /I2/ (D16.2 flips the disparity).
self.encoder.d[0].eq(D(16, 2))
),
NextState("START") NextState("START")
) )
fsm.act("DATA", fsm.act("DATA",
If(self.tx_valid, # Send Data frame.
self.tx_ready.eq((timer == 0)), timer_enable.eq(1),
timer_en.eq(1), sink.ready.eq(timer_done),
self.encoder.d[0].eq(self.tx_data) If(sink.valid,
self.encoder.d[0].eq(sink.data),
).Else( ).Else(
self.tx_ready.eq(1),
# /T/
self.encoder.k[0].eq(1), self.encoder.k[0].eq(1),
self.encoder.d[0].eq(K(29, 7)), self.encoder.d[0].eq(K(29, 7)), # End-of-frame /T/.
NextState("CARRIER_EXTEND_1") NextState("CARRIER-EXTEND")
) )
) )
fsm.act("CARRIER_EXTEND_1", fsm.act("CARRIER-EXTEND",
# /R/ # Extend carrier with /R/ symbols.
self.encoder.k[0].eq(1), self.encoder.k[0].eq(1),
self.encoder.d[0].eq(K(23, 7)), self.encoder.d[0].eq(K(23, 7)), # Carrier Extend /R/.
If(parity, If(parity,
NextState("START") NextState("START")
).Else(
NextState("CARRIER_EXTEND_2")
) )
) )
fsm.act("CARRIER_EXTEND_2", self.sync += parity.eq(~parity) # Toggle parity for /R/ extension.
# /R/
self.encoder.k[0].eq(1),
self.encoder.d[0].eq(K(23, 7)),
NextState("START")
)
# PCS RX ------------------------------------------------------------------------------------------- # PCS RX -------------------------------------------------------------------------------------------
@ -178,23 +170,25 @@ class PCSRX(LiteXModule):
first_preamble_byte = Signal() first_preamble_byte = Signal()
self.comb += self.rx_data.eq(Mux(first_preamble_byte, 0x55, self.decoder.d)) self.comb += self.rx_data.eq(Mux(first_preamble_byte, 0x55, self.decoder.d))
# Timer for SGMII data rates. # SGMII Timer.
timer = Signal(max=1000) # ------------
timer_en = Signal() timer = Signal(max=100)
timer_enable = Signal()
timer_done = Signal()
self.comb += timer_done.eq(timer == 0)
self.sync += [ self.sync += [
If(~timer_en | (timer == 0), timer.eq(timer - 1),
If(~timer_enable | timer_done,
Case(self.sgmii_speed, { Case(self.sgmii_speed, {
0b00: timer.eq(99), SGMII_10MBPS_SPEED : timer.eq(99),
0b01: timer.eq( 9), SGMII_100MBPS_SPEED : timer.eq( 9),
0b10: timer.eq( 0), SGMII_1000MBPS_SPEED : timer.eq( 0),
}) })
).Elif(timer_en,
timer.eq(timer - 1)
) )
] ]
# Speed adaptation # Speed adaptation
self.comb += self.sample_en.eq(self.rx_en & (timer == 0)) self.comb += self.sample_en.eq(self.rx_en & timer_done)
self.fsm = fsm = FSM() self.fsm = fsm = FSM()
fsm.act("START", fsm.act("START",
@ -204,7 +198,7 @@ class PCSRX(LiteXModule):
), ),
If(self.decoder.d == K(27, 7), If(self.decoder.d == K(27, 7),
self.rx_en.eq(1), self.rx_en.eq(1),
timer_en.eq(1), timer_enable.eq(1),
first_preamble_byte.eq(1), first_preamble_byte.eq(1),
NextState("DATA") NextState("DATA")
) )
@ -228,7 +222,7 @@ class PCSRX(LiteXModule):
If(self.decoder.k, If(self.decoder.k,
If(self.decoder.d == K(27, 7), If(self.decoder.d == K(27, 7),
self.rx_en.eq(1), self.rx_en.eq(1),
timer_en.eq(1), timer_enable.eq(1),
first_preamble_byte.eq(1), first_preamble_byte.eq(1),
NextState("DATA") NextState("DATA")
).Else( ).Else(
@ -250,7 +244,7 @@ class PCSRX(LiteXModule):
NextState("START") NextState("START")
).Else( ).Else(
self.rx_en.eq(1), self.rx_en.eq(1),
timer_en.eq(1) timer_enable.eq(1)
) )
) )
@ -305,11 +299,7 @@ class PCS(LiteXModule):
# # # # # #
# Endpoint interface. # Endpoint interface.
self.comb += [ self.comb += self.sink.connect(self.tx.sink, omit={"last_be", "error"})
self.tx.tx_valid.eq(self.sink.valid),
self.sink.ready.eq(self.tx.tx_ready),
self.tx.tx_data.eq(self.sink.data),
]
rx_en_d = Signal() rx_en_d = Signal()
self.sync.eth_rx += [ self.sync.eth_rx += [