phy/pcs_1000basex: Simplify/Cleanup PCSTX.
This commit is contained in:
parent
8a3e0a23aa
commit
313e7a985c
|
@ -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 += [
|
||||||
|
|
Loading…
Reference in New Issue