from lib.sata.link import crc
from lib.sata.link import scrambler
-class SATALinkLayerTX(Module):
- def __init__(self, dw):
+# Todo:
+# - TX: (optional) insert COND and scramble between COND and primitives
+# - RX: manage COND, HOLD from device
+
+class SATALinkLayer(Module):
+ def __init__(self, phy, dw=32):
self.sink = Sink(link_layout(dw))
- self.source = Source(phy_layout(dw))
+ self.source = Source(link_layout(dw))
- ###
+ fsm = FSM(reset_state="IDLE")
+ self.submodules += fsm
- # insert CRC
+ # TX
+ # insert CRC
crc_inserter = crc.SATACRCInserter(link_layout(dw))
self.submodules += crc_inserter
- # scramble
+ # scramble
scrambler = scrambler.SATAScrambler(link_layout(dw))
self.submodules += scrambler
-class SATALinkLayerRX(Module):
- def __init__(self, dw):
- self.sink = Sink(link_layout(dw))
- self.source = Source(phy_layout(dw))
+ # graph
+ self.comb += [
+ Record.connect(self.sink, crc_inserter.sink),
+ Record.connect(crc_inserter, scrambler)
+ ]
- ###
+ # datas / primitives mux
+ tx_insert = Signal(32)
+ self.comb += [
+ If(tx_insert != 0,
+ phy.sink.stb.eq(1),
+ phy.sink.data.eq(tx_insert),
+ phy.sink.charisk.eq(0x0001),
+ ).Elsif(fsm.ongoing("H2D_COPY"),
+ phy.sink.stb.eq(scrambler.source.stb),
+ phy.sink.data.eq(scrambler.source.data),
+ scrambler.source.ack.eq(phy.source.ack),
+ phy.sink.charisk.eq(0)
+ )
+ ]
- # descramble
+ # RX
+ # datas / primitives detection
+ rx_det = Signal(32)
+ self.comb += \
+ If(phy.source.stb & (phy.source.charisk == 0b0001),
+ rx_det.eq(phy.source.data)
+ )
+
+ # descrambler
descrambler = descrambler.SATAScrambler(link_layout(dw))
self.submodules += descrambler
- # check CRC
+ # check CRC
crc_checker = crc.SATACRCChecker(link_layout(dw))
self.submodules += crc_checker
-class SATALinkLayer(Module):
- def __init__(self, phy, dw=32):
- self.submodules.tx = SATALinkLayerTX(dw)
- self.submodules.rx = SATALinkLayerRX(dw)
+ # graph
+ self.comb += [
+ If(fsm.ongoing("H2D_COPY" & (rx_det == 0),
+ descrambler.sink.stb.eq(phy.source.stb & (phy.charisk == 0)),
+ descrambler.sink.d.eq(phy.source.d),
+ )
+ Record.connect(descrambler.source, crc_checker.sink),
+ Record.connect(crc_checker.source, self.source)
+ ]
- fsm = FSM(reset_state="IDLE")
- self.submodules += fsm
+ # FSM
fsm.act("IDLE",
- phy.sink.stb.eq(1),
- phy.sink.d.eq(SYNC_VAL),
- NextState("RDY")
- )
- fsm.act("RDY",
- phy.sink.stb.eq(1),
- phy.sink.d.eq(X_RDY_VAL)
- If(phy.source.stb & (phy.source.d == X_RDY_VAL),
- NextState("SOF")
+ tx_insert.eq(primitives["SYNC"]),
+ If(rx_primitive == "X_RDY",
+ NextState("D2H_RDY")
+ ).Elif(scrambler.stb & scrambler.sop,
+ NextState("H2D_RDY")
+ )
)
- fsm.act("SOF",
- phy.sink.stb.eq(1),
- phy.sink.d.eq(SOF_VAL),
- NextState("COPY")
+
+ # Host to Device
+ fsm.act("H2D_RDY",
+ tx_insert.eq(primitives["X_RDY"]),
+ If(rx_primitive == primitives["R_RDY"]),
+ NextState("H2D_SOF")
)
- fsm.act("COPY",
- phy.sink.stb.eq(1),
- phy.sink.d.eq(),
- NextState("EOF")
+ fsm.act("H2D_SOF",
+ tx_insert.eq(primitives["SOF"]),
+ If(phy.sink.ack,
+ NextState("H2D_COPY")
+ )
)
- fsm.act("EOF",
- phy.sink.stb.eq(1),
- phy.sink.d.eq(EOF_VAL),
- NextState("")
+ fsm.act("H2D_COPY",
+ If(scrambler.stb & scrambler.ack & scramvbler.eop,
+ NextState("H2D_EOF")
+ )
)
- fsm.act("EOF",
- phy.sink.stb.eq(1),
- phy.sink.d.eq(EOF_VAL),
- NextState("")
+ fsm.act("H2D_EOF",
+ tx_insert.eq(primitives["EOF"]),
+ If(phy.sink.ack,
+ NextState("H2D_WTRM")
+ )
)
- fsm.act("WTRM",
- phy.sink.stb.eq(1),
- phy.sink.d.eq(WTRM_VAL),
- If(phy.source.stb & (phy.source.d == R_OK_VAL),
+ fsm.act("H2D_WTRM",
+ tx_insert.eq(primitives["WTRM"]),
+ If(rx_det == primitives["R_OK"]),
+ NextState("IDLE")
+ ).Elif(rx_det == primitives["R_ERR"],
NextState("IDLE")
- ).Elif(phy.source.stb & (phy.source.d == R_ERR_VAL),
+ )
+ )
+
+ # 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["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")
)
)