from lib.sata.std import *
from lib.sata.link.crc import SATACRCInserter, SATACRCChecker
from lib.sata.link.scrambler import SATAScrambler
-from lib.sata.link.cont import SATACONTInserter
+from lib.sata.link.cont import SATACONTInserter, SATACONTRemover
-# Todo:
-# - RX: manage CONT
+# TODO:
+# - Test D2H
+# - Do more tests
class SATALinkLayer(Module):
def __init__(self, phy):
# TX
# insert CRC
- crc = SATACRCInserter(link_layout(32))
- self.submodules += crc
+ tx_crc = SATACRCInserter(link_layout(32))
+ self.submodules += tx_crc
# scramble
- scrambler = SATAScrambler(link_layout(32))
- self.submodules += scrambler
+ tx_scrambler = SATAScrambler(link_layout(32))
+ self.submodules += tx_scrambler
# graph
self.comb += [
- Record.connect(self.sink, crc.sink),
- Record.connect(crc.source, scrambler.sink)
+ Record.connect(self.sink, tx_crc.sink),
+ Record.connect(tx_crc.source, tx_scrambler.sink)
]
# inserter CONT and scrambled data between
# CONT and next primitive
- cont = SATACONTInserter(phy_layout(32))
- self.submodules += cont
+ tx_cont = SATACONTInserter(phy_layout(32))
+ self.submodules += tx_cont
# datas / primitives mux
tx_insert = Signal(32)
self.comb += [
If(tx_insert != 0,
- cont.sink.stb.eq(1),
- cont.sink.data.eq(tx_insert),
- cont.sink.charisk.eq(0x0001),
+ tx_cont.sink.stb.eq(1),
+ tx_cont.sink.data.eq(tx_insert),
+ tx_cont.sink.charisk.eq(0x0001),
).Elif(fsm.ongoing("H2D_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)
+ 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)
)
]
# graph
- self.comb += Record.connect(cont.source, phy.sink)
+ self.comb += Record.connect(tx_cont.source, phy.sink)
# RX
+
+ # CONT remover
+ rx_cont = SATACONTRemover(phy_layout(32))
+ self.submodules += rx_cont
+
+ # graph
+ self.comb += Record.connect(phy.source, rx_cont.sink)
+
# datas / primitives detection
rx_det = Signal(32)
self.comb += \
- If(phy.source.stb & (phy.source.charisk == 0b0001),
- rx_det.eq(phy.source.data)
+ If(rx_cont.source.stb & (rx_cont.source.charisk == 0b0001),
+ rx_det.eq(rx_cont.source.data)
)
# descrambler
- descrambler = SATAScrambler(link_layout(32))
- self.submodules += descrambler
+ rx_scrambler = SATAScrambler(link_layout(32))
+ self.submodules += rx_scrambler
# check CRC
- crc_checker = SATACRCChecker(link_layout(32))
- self.submodules += crc_checker
+ rx_crc = SATACRCChecker(link_layout(32))
+ self.submodules += rx_crc
# graph
self.comb += [
If(fsm.ongoing("D2H_COPY") & (rx_det == 0),
- descrambler.sink.stb.eq(phy.source.stb & (phy.source.charisk == 0)),
- descrambler.sink.d.eq(phy.source.data),
+ rx_scrambler.sink.stb.eq(rx_cont.source.stb & (rx_cont.source.charisk == 0)),
+ rx_scrambler.sink.d.eq(rx_cont.source.data),
),
- phy.source.ack.eq(1),
- Record.connect(descrambler.source, crc_checker.sink),
- Record.connect(crc_checker.source, self.source)
+ rx_cont.source.ack.eq(1),
+ Record.connect(rx_scrambler.source, rx_crc.sink),
+ Record.connect(rx_crc.source, self.source)
]
# FSM
tx_insert.eq(primitives["SYNC"]),
If(rx_det == primitives["X_RDY"],
NextState("D2H_RDY")
- ).Elif(scrambler.source.stb & scrambler.source.sop,
+ ).Elif(tx_scrambler.source.stb & tx_scrambler.source.sop,
NextState("H2D_RDY")
)
)
fsm.act("H2D_COPY",
If(rx_det == primitives["HOLD"],
tx_insert.eq(primitives["HOLDA"]),
- ).Elif(~scrambler.source.stb,
+ ).Elif(~tx_scrambler.source.stb,
tx_insert.eq(primitives["HOLD"]),
- ).Elif(scrambler.source.stb & scrambler.source.eop & scrambler.source.ack,
+ ).Elif(tx_scrambler.source.stb & tx_scrambler.source.eop & tx_scrambler.source.ack,
NextState("H2D_EOF")
)
)
###
# Detect consecutive primitives
+ # tn insert CONT
cnt = Signal(2)
is_primitive = Signal()
last_was_primitive = Signal()
)
)
- # Repeated primitives scranbler
+ # scranbler (between CONT and next primitive)
scrambler = Scrambler()
self.submodules += scrambler
self.comb += [
)
)
]
+
+class SATACONTRemover(Module):
+ def __init__(self, layout):
+ self.sink = sink = Sink(layout)
+ self.source = source = Source(layout)
+
+ ###
+
+ # Detect CONT
+ is_primitive = Signal()
+ is_cont = Signal()
+ in_cont = Signal()
+ cont_ongoing = Signal()
+
+ self.comb += [
+ is_primitive.eq(sink.charisk != 0),
+ is_cont.eq(is_primitive & sink.data == primitives["CONT"])
+ ]
+ self.sync += \
+ If(is_cont,
+ in_cont.eq(1)
+ ).Elif(is_primitive,
+ in_cont.eq(0)
+ )
+ self.comb += cont_ongoing.eq(is_cont | (in_cont & ~is_primitive))
+
+ # Datapath
+ last_primitive = Signal()
+ self.sync += [
+ If(is_primitive & ~is_cont,
+ last_primitive.eq(sink.data)
+ )
+ ]
+ self.comb += [
+ Record.connect(sink, source),
+ If(cont_ongoing,
+ self.source.charisk.eq(0b0001),
+ self.source.data.eq(last_primitive)
+ )
+ ]