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)
- # CONT remover
- rx_cont = SATACONTRemover(phy_layout(32))
- self.submodules += rx_cont
+ ###
- # graph
- self.comb += Record.connect(phy.source, rx_cont.sink)
+ fsm = FSM(reset_state="IDLE")
+ self.submodules += fsm
+
+ # CONT remover
+ 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