mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
link: split SATALinkLayer in SATALinkLayerTX and SATALinkLayerRX
This commit is contained in:
parent
d3974882e4
commit
ddd4b65f44
2 changed files with 136 additions and 103 deletions
|
@ -7,159 +7,192 @@ from lib.sata.link.scrambler import SATAScrambler
|
|||
from lib.sata.link.cont import SATACONTInserter, SATACONTRemover
|
||||
|
||||
# TODO:
|
||||
# - Test D2H
|
||||
# - Do more tests
|
||||
|
||||
class SATALinkLayer(Module):
|
||||
from_rx = [
|
||||
("idle", 1),
|
||||
("insert", 32),
|
||||
("det", 32)
|
||||
]
|
||||
|
||||
class SATALinkLayerTX(Module):
|
||||
def __init__(self, phy):
|
||||
self.sink = Sink(link_layout(32))
|
||||
self.source = Source(link_layout(32))
|
||||
self.from_rx = Sink(from_rx)
|
||||
|
||||
###
|
||||
|
||||
fsm = FSM(reset_state="IDLE")
|
||||
self.submodules += fsm
|
||||
|
||||
# TX
|
||||
# insert CRC
|
||||
tx_crc = SATACRCInserter(link_layout(32))
|
||||
self.submodules += tx_crc
|
||||
crc = SATACRCInserter(link_layout(32))
|
||||
self.submodules += crc
|
||||
|
||||
# scramble
|
||||
tx_scrambler = SATAScrambler(link_layout(32))
|
||||
self.submodules += tx_scrambler
|
||||
scrambler = SATAScrambler(link_layout(32))
|
||||
self.submodules += scrambler
|
||||
|
||||
# graph
|
||||
# connect CRC / scrambler
|
||||
self.comb += [
|
||||
Record.connect(self.sink, tx_crc.sink),
|
||||
Record.connect(tx_crc.source, tx_scrambler.sink)
|
||||
Record.connect(self.sink, crc.sink),
|
||||
Record.connect(crc.source, scrambler.sink)
|
||||
]
|
||||
|
||||
# inserter CONT and scrambled data between
|
||||
# CONT and next primitive
|
||||
tx_cont = SATACONTInserter(phy_layout(32))
|
||||
self.submodules += tx_cont
|
||||
cont = SATACONTInserter(phy_layout(32))
|
||||
self.submodules += cont
|
||||
|
||||
# datas / primitives mux
|
||||
tx_insert = Signal(32)
|
||||
insert = Signal(32)
|
||||
self.comb += [
|
||||
If(tx_insert != 0,
|
||||
tx_cont.sink.stb.eq(1),
|
||||
tx_cont.sink.data.eq(tx_insert),
|
||||
tx_cont.sink.charisk.eq(0x0001),
|
||||
).Elif(fsm.ongoing("H2D_COPY"),
|
||||
tx_cont.sink.stb.eq(tx_scrambler.source.stb),
|
||||
tx_cont.sink.data.eq(tx_scrambler.source.d),
|
||||
tx_scrambler.source.ack.eq(tx_cont.sink.ack),
|
||||
tx_cont.sink.charisk.eq(0)
|
||||
If(self.from_rx.insert,
|
||||
cont.sink.stb.eq(1),
|
||||
cont.sink.data.eq(self.from_rx.insert),
|
||||
cont.sink.charisk.eq(0x0001),
|
||||
).
|
||||
Elif(insert,
|
||||
cont.sink.stb.eq(1),
|
||||
cont.sink.data.eq(insert),
|
||||
cont.sink.charisk.eq(0x0001),
|
||||
).Elif(fsm.ongoing("COPY"),
|
||||
cont.sink.stb.eq(scrambler.source.stb),
|
||||
cont.sink.data.eq(scrambler.source.d),
|
||||
scrambler.source.ack.eq(cont.sink.ack),
|
||||
cont.sink.charisk.eq(0)
|
||||
)
|
||||
]
|
||||
self.comb += Record.connect(cont.source, phy.sink)
|
||||
|
||||
# graph
|
||||
self.comb += Record.connect(tx_cont.source, phy.sink)
|
||||
# FSM
|
||||
fsm.act("IDLE",
|
||||
insert.eq(primitives["SYNC"]),
|
||||
If(scrambler.source.stb & scrambler.source.sop,
|
||||
If(self.from_rx.idle,
|
||||
NextState("RDY")
|
||||
)
|
||||
)
|
||||
)
|
||||
fsm.act("RDY",
|
||||
insert.eq(primitives["X_RDY"]),
|
||||
If(self.from_rx.det == primitives["R_RDY"],
|
||||
NextState("SOF")
|
||||
)
|
||||
)
|
||||
fsm.act("SOF",
|
||||
insert.eq(primitives["SOF"]),
|
||||
If(phy.sink.ack,
|
||||
NextState("COPY")
|
||||
)
|
||||
)
|
||||
fsm.act("COPY",
|
||||
If(self.from_rx.det == primitives["HOLD"],
|
||||
insert.eq(primitives["HOLDA"]),
|
||||
).Elif(~scrambler.source.stb,
|
||||
insert.eq(primitives["HOLD"]),
|
||||
).Elif(scrambler.source.stb & scrambler.source.eop & scrambler.source.ack,
|
||||
NextState("EOF")
|
||||
)
|
||||
)
|
||||
fsm.act("EOF",
|
||||
insert.eq(primitives["EOF"]),
|
||||
If(phy.sink.ack,
|
||||
NextState("WTRM")
|
||||
)
|
||||
)
|
||||
fsm.act("WTRM",
|
||||
insert.eq(primitives["WTRM"]),
|
||||
If(self.from_rx.det == primitives["R_OK"],
|
||||
NextState("IDLE")
|
||||
).Elif(self.from_rx.det == primitives["R_ERR"],
|
||||
NextState("IDLE")
|
||||
)
|
||||
)
|
||||
|
||||
# RX
|
||||
class SATALinkLayerRX(Module):
|
||||
def __init__(self, phy):
|
||||
self.source = Source(link_layout(32))
|
||||
self.to_tx = Source(from_rx)
|
||||
|
||||
###
|
||||
|
||||
fsm = FSM(reset_state="IDLE")
|
||||
self.submodules += fsm
|
||||
|
||||
# CONT remover
|
||||
rx_cont = SATACONTRemover(phy_layout(32))
|
||||
self.submodules += rx_cont
|
||||
|
||||
# graph
|
||||
self.comb += Record.connect(phy.source, rx_cont.sink)
|
||||
cont = SATACONTRemover(phy_layout(32))
|
||||
self.submodules += cont
|
||||
self.comb += Record.connect(phy.source, cont.sink)
|
||||
|
||||
# datas / primitives detection
|
||||
rx_det = Signal(32)
|
||||
insert = Signal(32)
|
||||
det = Signal(32)
|
||||
self.comb += \
|
||||
If(rx_cont.source.stb & (rx_cont.source.charisk == 0b0001),
|
||||
rx_det.eq(rx_cont.source.data)
|
||||
If(cont.source.stb & (cont.source.charisk == 0b0001),
|
||||
det.eq(cont.source.data)
|
||||
)
|
||||
|
||||
# descrambler
|
||||
rx_scrambler = SATAScrambler(link_layout(32))
|
||||
self.submodules += rx_scrambler
|
||||
scrambler = SATAScrambler(link_layout(32))
|
||||
self.submodules += scrambler
|
||||
|
||||
# check CRC
|
||||
rx_crc = SATACRCChecker(link_layout(32))
|
||||
self.submodules += rx_crc
|
||||
crc = SATACRCChecker(link_layout(32))
|
||||
self.submodules += crc
|
||||
|
||||
# graph
|
||||
self.comb += [
|
||||
If(fsm.ongoing("D2H_COPY") & (rx_det == 0),
|
||||
rx_scrambler.sink.stb.eq(rx_cont.source.stb & (rx_cont.source.charisk == 0)),
|
||||
rx_scrambler.sink.d.eq(rx_cont.source.data),
|
||||
If(fsm.ongoing("COPY") & (det == 0),
|
||||
scrambler.sink.stb.eq(cont.source.stb & (cont.source.charisk == 0)),
|
||||
scrambler.sink.d.eq(cont.source.data),
|
||||
),
|
||||
rx_cont.source.ack.eq(1),
|
||||
Record.connect(rx_scrambler.source, rx_crc.sink),
|
||||
Record.connect(rx_crc.source, self.source)
|
||||
cont.source.ack.eq(1),
|
||||
Record.connect(scrambler.source, crc.sink),
|
||||
Record.connect(crc.source, self.source)
|
||||
]
|
||||
|
||||
# FSM
|
||||
# FSM
|
||||
fsm.act("IDLE",
|
||||
tx_insert.eq(primitives["SYNC"]),
|
||||
If(rx_det == primitives["X_RDY"],
|
||||
NextState("D2H_RDY")
|
||||
).Elif(tx_scrambler.source.stb & tx_scrambler.source.sop,
|
||||
NextState("H2D_RDY")
|
||||
If(det == primitives["X_RDY"],
|
||||
NextState("RDY")
|
||||
)
|
||||
)
|
||||
|
||||
# Host to Device
|
||||
fsm.act("H2D_RDY",
|
||||
tx_insert.eq(primitives["X_RDY"]),
|
||||
If(rx_det == primitives["R_RDY"],
|
||||
NextState("H2D_SOF")
|
||||
fsm.act("RDY",
|
||||
insert.eq(primitives["R_RDY"]),
|
||||
If(det == primitives["SOF"],
|
||||
NextState("COPY")
|
||||
)
|
||||
)
|
||||
fsm.act("H2D_SOF",
|
||||
tx_insert.eq(primitives["SOF"]),
|
||||
If(phy.sink.ack,
|
||||
NextState("H2D_COPY")
|
||||
fsm.act("COPY",
|
||||
If(det == primitives["HOLD"],
|
||||
insert.eq(primitives["HOLDA"])
|
||||
).Elif(det == primitives["EOF"],
|
||||
NextState("WTRM")
|
||||
)
|
||||
)
|
||||
fsm.act("H2D_COPY",
|
||||
If(rx_det == primitives["HOLD"],
|
||||
tx_insert.eq(primitives["HOLDA"]),
|
||||
).Elif(~tx_scrambler.source.stb,
|
||||
tx_insert.eq(primitives["HOLD"]),
|
||||
).Elif(tx_scrambler.source.stb & tx_scrambler.source.eop & tx_scrambler.source.ack,
|
||||
NextState("H2D_EOF")
|
||||
fsm.act("EOF",
|
||||
If(det == primitives["WTRM"],
|
||||
NextState("WTRM")
|
||||
)
|
||||
)
|
||||
fsm.act("H2D_EOF",
|
||||
tx_insert.eq(primitives["EOF"]),
|
||||
If(phy.sink.ack,
|
||||
NextState("H2D_WTRM")
|
||||
)
|
||||
)
|
||||
fsm.act("H2D_WTRM",
|
||||
tx_insert.eq(primitives["WTRM"]),
|
||||
If(rx_det == primitives["R_OK"],
|
||||
NextState("IDLE")
|
||||
).Elif(rx_det == primitives["R_ERR"],
|
||||
fsm.act("WTRM",
|
||||
insert.eq(primitives["R_OK"]),
|
||||
If(det == primitives["SYNC"],
|
||||
NextState("IDLE")
|
||||
)
|
||||
)
|
||||
|
||||
# Device to Host
|
||||
fsm.act("D2H_RDY",
|
||||
tx_insert.eq(primitives["R_RDY"]),
|
||||
If(rx_det == primitives["SOF"],
|
||||
NextState("D2H_COPY")
|
||||
)
|
||||
)
|
||||
fsm.act("D2H_COPY",
|
||||
If(rx_det == primitives["HOLD"],
|
||||
tx_insert.eq(primitives["HOLDA"])
|
||||
).Elif(rx_det == primitives["EOF"],
|
||||
NextState("D2H_WTRM")
|
||||
)
|
||||
)
|
||||
fsm.act("D2H_EOF",
|
||||
If(rx_det == primitives["WTRM"],
|
||||
NextState("D2H_WTRM")
|
||||
)
|
||||
)
|
||||
fsm.act("D2H_WTRM",
|
||||
tx_insert.eq(primitives["R_OK"]),
|
||||
If(rx_det == primitives["SYNC"],
|
||||
NextState("IDLE")
|
||||
)
|
||||
)
|
||||
# to TX
|
||||
self.comb += [
|
||||
self.to_tx.idle.eq(fsm.ongoing("IDLE")),
|
||||
self.to_tx.insert.eq(insert),
|
||||
self.to_tx.det.eq(det)
|
||||
]
|
||||
|
||||
class SATALinkLayer(Module):
|
||||
def __init__(self, phy):
|
||||
self.submodules.tx = SATALinkLayerTX(phy)
|
||||
self.submodules.rx = SATALinkLayerRX(phy)
|
||||
self.comb += Record.connect(self.rx.to_tx, self.tx.from_rx)
|
||||
self.sink, self.source = self.tx.sink, self.rx.source
|
||||
|
|
Loading…
Reference in a new issue