2014-11-04 11:35:46 -05:00
|
|
|
from migen.fhdl.std import *
|
2014-11-11 12:47:34 -05:00
|
|
|
from migen.genlib.fsm import FSM, NextState
|
2014-11-04 11:35:46 -05:00
|
|
|
|
|
|
|
from lib.sata.std import *
|
2014-11-11 12:47:34 -05:00
|
|
|
from lib.sata.link.crc import SATACRCInserter, SATACRCChecker
|
|
|
|
from lib.sata.link.scrambler import SATAScrambler
|
2014-12-03 05:50:31 -05:00
|
|
|
from lib.sata.link.cont import SATACONTInserter, SATACONTRemover
|
2014-11-04 11:35:46 -05:00
|
|
|
|
2014-12-03 05:50:31 -05:00
|
|
|
# TODO:
|
|
|
|
# - Test D2H
|
|
|
|
# - Do more tests
|
2014-11-11 06:26:32 -05:00
|
|
|
|
|
|
|
class SATALinkLayer(Module):
|
2014-11-11 12:47:34 -05:00
|
|
|
def __init__(self, phy):
|
|
|
|
self.sink = Sink(link_layout(32))
|
|
|
|
self.source = Source(link_layout(32))
|
2014-11-04 11:35:46 -05:00
|
|
|
|
2014-11-11 06:26:32 -05:00
|
|
|
fsm = FSM(reset_state="IDLE")
|
|
|
|
self.submodules += fsm
|
2014-11-04 11:35:46 -05:00
|
|
|
|
2014-11-11 06:26:32 -05:00
|
|
|
# TX
|
|
|
|
# insert CRC
|
2014-12-03 05:50:31 -05:00
|
|
|
tx_crc = SATACRCInserter(link_layout(32))
|
|
|
|
self.submodules += tx_crc
|
2014-11-04 11:35:46 -05:00
|
|
|
|
2014-11-11 06:26:32 -05:00
|
|
|
# scramble
|
2014-12-03 05:50:31 -05:00
|
|
|
tx_scrambler = SATAScrambler(link_layout(32))
|
|
|
|
self.submodules += tx_scrambler
|
2014-11-04 11:35:46 -05:00
|
|
|
|
2014-11-11 06:26:32 -05:00
|
|
|
# graph
|
|
|
|
self.comb += [
|
2014-12-03 05:50:31 -05:00
|
|
|
Record.connect(self.sink, tx_crc.sink),
|
|
|
|
Record.connect(tx_crc.source, tx_scrambler.sink)
|
2014-11-11 06:26:32 -05:00
|
|
|
]
|
2014-11-04 11:35:46 -05:00
|
|
|
|
2014-12-03 05:12:26 -05:00
|
|
|
# inserter CONT and scrambled data between
|
|
|
|
# CONT and next primitive
|
2014-12-03 05:50:31 -05:00
|
|
|
tx_cont = SATACONTInserter(phy_layout(32))
|
|
|
|
self.submodules += tx_cont
|
2014-12-03 05:12:26 -05:00
|
|
|
|
2014-11-11 06:26:32 -05:00
|
|
|
# datas / primitives mux
|
|
|
|
tx_insert = Signal(32)
|
|
|
|
self.comb += [
|
|
|
|
If(tx_insert != 0,
|
2014-12-03 05:50:31 -05:00
|
|
|
tx_cont.sink.stb.eq(1),
|
|
|
|
tx_cont.sink.data.eq(tx_insert),
|
|
|
|
tx_cont.sink.charisk.eq(0x0001),
|
2014-11-11 12:47:34 -05:00
|
|
|
).Elif(fsm.ongoing("H2D_COPY"),
|
2014-12-03 05:50:31 -05:00
|
|
|
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)
|
2014-11-11 06:26:32 -05:00
|
|
|
)
|
|
|
|
]
|
2014-11-04 11:35:46 -05:00
|
|
|
|
2014-12-03 05:12:26 -05:00
|
|
|
# graph
|
2014-12-03 05:50:31 -05:00
|
|
|
self.comb += Record.connect(tx_cont.source, phy.sink)
|
2014-12-03 05:12:26 -05:00
|
|
|
|
2014-11-11 06:26:32 -05:00
|
|
|
# RX
|
2014-12-03 05:50:31 -05:00
|
|
|
|
|
|
|
# CONT remover
|
|
|
|
rx_cont = SATACONTRemover(phy_layout(32))
|
|
|
|
self.submodules += rx_cont
|
|
|
|
|
|
|
|
# graph
|
|
|
|
self.comb += Record.connect(phy.source, rx_cont.sink)
|
|
|
|
|
2014-11-11 06:26:32 -05:00
|
|
|
# datas / primitives detection
|
|
|
|
rx_det = Signal(32)
|
|
|
|
self.comb += \
|
2014-12-03 05:50:31 -05:00
|
|
|
If(rx_cont.source.stb & (rx_cont.source.charisk == 0b0001),
|
|
|
|
rx_det.eq(rx_cont.source.data)
|
2014-11-11 06:26:32 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
# descrambler
|
2014-12-03 05:50:31 -05:00
|
|
|
rx_scrambler = SATAScrambler(link_layout(32))
|
|
|
|
self.submodules += rx_scrambler
|
2014-11-04 11:35:46 -05:00
|
|
|
|
2014-11-11 06:26:32 -05:00
|
|
|
# check CRC
|
2014-12-03 05:50:31 -05:00
|
|
|
rx_crc = SATACRCChecker(link_layout(32))
|
|
|
|
self.submodules += rx_crc
|
2014-11-04 11:35:46 -05:00
|
|
|
|
2014-11-11 06:26:32 -05:00
|
|
|
# graph
|
|
|
|
self.comb += [
|
2014-12-02 15:34:16 -05:00
|
|
|
If(fsm.ongoing("D2H_COPY") & (rx_det == 0),
|
2014-12-03 05:50:31 -05:00
|
|
|
rx_scrambler.sink.stb.eq(rx_cont.source.stb & (rx_cont.source.charisk == 0)),
|
|
|
|
rx_scrambler.sink.d.eq(rx_cont.source.data),
|
2014-11-11 10:15:28 -05:00
|
|
|
),
|
2014-12-03 05:50:31 -05:00
|
|
|
rx_cont.source.ack.eq(1),
|
|
|
|
Record.connect(rx_scrambler.source, rx_crc.sink),
|
|
|
|
Record.connect(rx_crc.source, self.source)
|
2014-11-11 06:26:32 -05:00
|
|
|
]
|
2014-11-04 11:35:46 -05:00
|
|
|
|
2014-11-11 06:26:32 -05:00
|
|
|
# FSM
|
2014-11-04 11:35:46 -05:00
|
|
|
fsm.act("IDLE",
|
2014-11-11 06:26:32 -05:00
|
|
|
tx_insert.eq(primitives["SYNC"]),
|
2014-11-11 12:47:34 -05:00
|
|
|
If(rx_det == primitives["X_RDY"],
|
2014-11-11 06:26:32 -05:00
|
|
|
NextState("D2H_RDY")
|
2014-12-03 05:50:31 -05:00
|
|
|
).Elif(tx_scrambler.source.stb & tx_scrambler.source.sop,
|
2014-11-11 06:26:32 -05:00
|
|
|
NextState("H2D_RDY")
|
|
|
|
)
|
2014-11-04 11:35:46 -05:00
|
|
|
)
|
2014-11-11 06:26:32 -05:00
|
|
|
|
|
|
|
# Host to Device
|
|
|
|
fsm.act("H2D_RDY",
|
|
|
|
tx_insert.eq(primitives["X_RDY"]),
|
2014-11-11 12:47:34 -05:00
|
|
|
If(rx_det == primitives["R_RDY"],
|
2014-11-11 06:26:32 -05:00
|
|
|
NextState("H2D_SOF")
|
2014-11-11 12:47:34 -05:00
|
|
|
)
|
2014-11-04 11:35:46 -05:00
|
|
|
)
|
2014-11-11 06:26:32 -05:00
|
|
|
fsm.act("H2D_SOF",
|
|
|
|
tx_insert.eq(primitives["SOF"]),
|
|
|
|
If(phy.sink.ack,
|
|
|
|
NextState("H2D_COPY")
|
|
|
|
)
|
2014-11-04 11:35:46 -05:00
|
|
|
)
|
2014-11-11 06:26:32 -05:00
|
|
|
fsm.act("H2D_COPY",
|
2014-12-02 15:34:16 -05:00
|
|
|
If(rx_det == primitives["HOLD"],
|
|
|
|
tx_insert.eq(primitives["HOLDA"]),
|
2014-12-03 05:50:31 -05:00
|
|
|
).Elif(~tx_scrambler.source.stb,
|
2014-12-02 15:34:16 -05:00
|
|
|
tx_insert.eq(primitives["HOLD"]),
|
2014-12-03 05:50:31 -05:00
|
|
|
).Elif(tx_scrambler.source.stb & tx_scrambler.source.eop & tx_scrambler.source.ack,
|
2014-11-11 06:26:32 -05:00
|
|
|
NextState("H2D_EOF")
|
|
|
|
)
|
2014-11-04 11:35:46 -05:00
|
|
|
)
|
2014-11-11 06:26:32 -05:00
|
|
|
fsm.act("H2D_EOF",
|
|
|
|
tx_insert.eq(primitives["EOF"]),
|
|
|
|
If(phy.sink.ack,
|
|
|
|
NextState("H2D_WTRM")
|
|
|
|
)
|
2014-11-04 11:35:46 -05:00
|
|
|
)
|
2014-11-11 06:26:32 -05:00
|
|
|
fsm.act("H2D_WTRM",
|
|
|
|
tx_insert.eq(primitives["WTRM"]),
|
2014-11-11 10:15:28 -05:00
|
|
|
If(rx_det == primitives["R_OK"],
|
2014-11-11 06:26:32 -05:00
|
|
|
NextState("IDLE")
|
|
|
|
).Elif(rx_det == primitives["R_ERR"],
|
2014-11-04 11:35:46 -05:00
|
|
|
NextState("IDLE")
|
2014-11-11 06:26:32 -05:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
# 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",
|
2014-12-02 15:34:16 -05:00
|
|
|
If(rx_det == primitives["HOLD"],
|
|
|
|
tx_insert.eq(primitives["HOLDA"])
|
|
|
|
).Elif(rx_det == primitives["EOF"],
|
2014-11-11 06:26:32 -05:00
|
|
|
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"]),
|
2014-11-11 10:15:28 -05:00
|
|
|
If(rx_det == primitives["SYNC"],
|
2014-11-04 11:35:46 -05:00
|
|
|
NextState("IDLE")
|
|
|
|
)
|
|
|
|
)
|