173 lines
4.1 KiB
Python
173 lines
4.1 KiB
Python
from lib.sata.common import *
|
|
|
|
from migen.genlib.misc import chooser
|
|
|
|
class SATAPHYDatapathRX(Module):
|
|
def __init__(self):
|
|
self.sink = Sink(phy_description(16))
|
|
self.source = Source(phy_description(32))
|
|
|
|
###
|
|
|
|
# bytes alignment
|
|
|
|
# shift register
|
|
data_sr = Signal(32+8)
|
|
charisk_sr = Signal(4+1)
|
|
data_sr_d = Signal(32+8)
|
|
charisk_sr_d = Signal(4+1)
|
|
self.comb += [
|
|
data_sr.eq(Cat(data_sr_d[16:], self.sink.data)),
|
|
charisk_sr.eq(Cat(charisk_sr_d[2:], self.sink.charisk))
|
|
]
|
|
self.sync.sata_rx += [
|
|
data_sr_d.eq(data_sr),
|
|
charisk_sr_d.eq(charisk_sr)
|
|
]
|
|
|
|
# alignment
|
|
alignment = Signal()
|
|
valid = Signal()
|
|
self.sync.sata_rx += [
|
|
If(self.sink.charisk !=0,
|
|
alignment.eq(self.sink.charisk[1]),
|
|
valid.eq(0)
|
|
).Else(
|
|
valid.eq(~valid)
|
|
)
|
|
]
|
|
|
|
# 16 to 32
|
|
data = Signal(32)
|
|
charisk = Signal(4)
|
|
self.comb += [
|
|
If(alignment,
|
|
data.eq(data_sr[0:32]),
|
|
charisk.eq(charisk_sr[0:4])
|
|
).Else(
|
|
data.eq(data_sr[8:40]),
|
|
charisk.eq(charisk_sr[1:5])
|
|
)
|
|
]
|
|
|
|
# clock domain crossing
|
|
# (SATA3) 300MHz sata_rx clk to sys_clk
|
|
# (SATA2) 150MHz sata_rx clk to sys_clk
|
|
# (SATA1) 75MHz sata_rx clk to sys_clk
|
|
# requirements:
|
|
# due to the convertion ratio of 2, sys_clk need to be > sata_rx/2
|
|
# source destination is always able to accept data (ack always 1)
|
|
fifo = AsyncFIFO(phy_description(32), 4)
|
|
self.fifo = RenameClockDomains(fifo, {"write": "sata_rx", "read": "sys"})
|
|
self.comb += [
|
|
fifo.sink.stb.eq(valid),
|
|
fifo.sink.data.eq(data),
|
|
fifo.sink.charisk.eq(charisk),
|
|
]
|
|
self.comb += Record.connect(fifo.source, self.source)
|
|
|
|
class SATAPHYDatapathTX(Module):
|
|
def __init__(self):
|
|
self.sink = Sink(phy_description(32))
|
|
self.source = Source(phy_description(16))
|
|
|
|
###
|
|
|
|
# clock domain crossing
|
|
# (SATA3) sys_clk to 300MHz sata_tx clk
|
|
# (SATA2) sys_clk to 150MHz sata_tx clk
|
|
# (SATA1) sys_clk to 75MHz sata_tx clk
|
|
# requirements:
|
|
# source destination is always able to accept data (ack always 1)
|
|
fifo = AsyncFIFO(phy_description(32), 4)
|
|
self.fifo = RenameClockDomains(fifo, {"write": "sys", "read": "sata_tx"})
|
|
self.comb += Record.connect(self.sink, fifo.sink)
|
|
|
|
# 32 to 16
|
|
mux = Signal()
|
|
last = Signal()
|
|
self.comb += [
|
|
last.eq(mux == 1),
|
|
self.source.stb.eq(fifo.source.stb),
|
|
fifo.source.ack.eq(last),
|
|
]
|
|
self.sync.sata_tx += [
|
|
If(self.source.stb,
|
|
If(last,
|
|
mux.eq(0)
|
|
).Else(
|
|
mux.eq(mux + 1)
|
|
)
|
|
)
|
|
]
|
|
self.comb += [
|
|
chooser(fifo.source.data, mux, self.source.data),
|
|
chooser(fifo.source.charisk, mux, self.source.charisk)
|
|
]
|
|
|
|
class SATAPHYDatapath(Module):
|
|
def __init__(self, trx, ctrl):
|
|
self.sink = Sink(phy_description(32))
|
|
self.source = Source(phy_description(32))
|
|
|
|
###
|
|
|
|
# change data width & cross domain crossing
|
|
rx = SATAPHYDatapathRX()
|
|
tx = SATAPHYDatapathTX()
|
|
self.submodules += rx, tx
|
|
self.comb += [
|
|
trx.source.connect(rx.sink),
|
|
tx.source.connect(trx.sink)
|
|
]
|
|
|
|
# Align cnt (send 2 Align DWORDs every 256 DWORDs)
|
|
align_cnt = Signal(8)
|
|
self.sync += \
|
|
If(~ctrl.ready,
|
|
align_cnt.eq(0)
|
|
).Elif(tx.sink.stb & tx.sink.ack,
|
|
align_cnt.eq(align_cnt+1)
|
|
)
|
|
send_align = (align_cnt < 2)
|
|
|
|
receive_align = Signal()
|
|
self.comb += receive_align.eq(rx.source.stb &
|
|
(rx.source.charisk == 0b0001) &
|
|
(rx.source.data == primitives["ALIGN"]))
|
|
|
|
# user / ctrl mux
|
|
self.comb += [
|
|
# user
|
|
If(ctrl.ready,
|
|
If(send_align,
|
|
tx.sink.stb.eq(1),
|
|
tx.sink.data.eq(primitives["ALIGN"]),
|
|
tx.sink.charisk.eq(0b0001),
|
|
self.sink.ack.eq(0)
|
|
).Else(
|
|
tx.sink.stb.eq(self.sink.stb),
|
|
tx.sink.data.eq(self.sink.data),
|
|
tx.sink.charisk.eq(self.sink.charisk),
|
|
self.sink.ack.eq(tx.sink.ack)
|
|
),
|
|
If(receive_align,
|
|
rx.source.ack.eq(1)
|
|
).Else(
|
|
self.source.stb.eq(rx.source.stb),
|
|
self.source.data.eq(rx.source.data),
|
|
self.source.charisk.eq(rx.source.charisk),
|
|
rx.source.ack.eq(1)
|
|
)
|
|
# ctrl
|
|
).Else(
|
|
tx.sink.stb.eq(ctrl.source.stb),
|
|
tx.sink.data.eq(ctrl.source.data),
|
|
tx.sink.charisk.eq(ctrl.source.charisk),
|
|
|
|
ctrl.sink.stb.eq(rx.source.stb),
|
|
ctrl.sink.data.eq(rx.source.data),
|
|
rx.source.ack.eq(1),
|
|
)
|
|
]
|