c47e7529a6e2d77c6e4dc3b917d1d5ede2109fc4
[litex.git] / litesata / phy / datapath.py
1 from litesata.common import *
2
3 class LiteSATAPHYDatapathRX(Module):
4 def __init__(self):
5 self.sink = Sink(phy_description(16))
6 self.source = Source(phy_description(32))
7
8 ###
9
10 # width convertion (16 to 32) and byte alignment
11 byte_alignment = Signal()
12 last_charisk = Signal(2)
13 last_data = Signal(16)
14 self.sync.sata_rx += \
15 If(self.sink.stb & self.sink.ack,
16 If(self.sink.charisk != 0,
17 byte_alignment.eq(self.sink.charisk[1])
18 ),
19 last_charisk.eq(self.sink.charisk),
20 last_data.eq(self.sink.data)
21 )
22 converter = Converter(phy_description(16), phy_description(32), reverse=False)
23 self.converter = InsertReset(RenameClockDomains(converter, "sata_rx"))
24 self.comb += [
25 self.converter.sink.stb.eq(self.sink.stb),
26 If(byte_alignment,
27 self.converter.sink.charisk.eq(Cat(last_charisk[1], self.sink.charisk[0])),
28 self.converter.sink.data.eq(Cat(last_data[8:], self.sink.data[:8]))
29 ).Else(
30 self.converter.sink.charisk.eq(self.sink.charisk),
31 self.converter.sink.data.eq(self.sink.data)
32 ),
33 self.sink.ack.eq(self.converter.sink.ack),
34 self.converter.reset.eq(self.converter.source.charisk[2:] != 0)
35 ]
36
37 # clock domain crossing
38 # (SATA3) 300MHz sata_rx clk to sys_clk
39 # (SATA2) 150MHz sata_rx clk to sys_clk
40 # (SATA1) 75MHz sata_rx clk to sys_clk
41 # requirements:
42 # due to the convertion ratio of 2, sys_clk need to be > sata_rx/2
43 # source destination is always able to accept data (ack always 1)
44 fifo = AsyncFIFO(phy_description(32), 4)
45 self.fifo = RenameClockDomains(fifo, {"write": "sata_rx", "read": "sys"})
46 self.comb += [
47 Record.connect(self.converter.source, fifo.sink),
48 Record.connect(fifo.source, self.source)
49 ]
50
51 class LiteSATAPHYDatapathTX(Module):
52 def __init__(self):
53 self.sink = Sink(phy_description(32))
54 self.source = Source(phy_description(16))
55
56 ###
57
58 # clock domain crossing
59 # (SATA3) sys_clk to 300MHz sata_tx clk
60 # (SATA2) sys_clk to 150MHz sata_tx clk
61 # (SATA1) sys_clk to 75MHz sata_tx clk
62 # requirements:
63 # source destination is always able to accept data (ack always 1)
64 fifo = AsyncFIFO(phy_description(32), 4)
65 self.fifo = RenameClockDomains(fifo, {"write": "sys", "read": "sata_tx"})
66 self.comb += Record.connect(self.sink, fifo.sink)
67
68 # width convertion (32 to 16)
69 converter = Converter(phy_description(32), phy_description(16), reverse=False)
70 self.converter = RenameClockDomains(converter, "sata_tx")
71 self.comb += [
72 Record.connect(self.fifo.source, self.converter.sink),
73 Record.connect(self.converter.source, self.source)
74 ]
75
76 class LiteSATAPHYAlignInserter(Module):
77 def __init__(self, ctrl):
78 self.sink = sink = Sink(phy_description(32))
79 self.source = source = Source(phy_description(32))
80
81 ###
82
83 # send 2 ALIGN every 256 DWORDs
84 # used for clock compensation between
85 # HOST and device
86 cnt = Signal(8)
87 send = Signal()
88 self.sync += \
89 If(~ctrl.ready,
90 cnt.eq(0)
91 ).Elif(source.stb & source.ack,
92 cnt.eq(cnt+1)
93 )
94 self.comb += [
95 send.eq(cnt < 2),
96 If(send,
97 source.stb.eq(1),
98 source.charisk.eq(0b0001),
99 source.data.eq(primitives["ALIGN"]),
100 sink.ack.eq(0)
101 ).Else(
102 source.stb.eq(sink.stb),
103 source.data.eq(sink.data),
104 source.charisk.eq(sink.charisk),
105 sink.ack.eq(source.ack)
106 )
107 ]
108
109 class LiteSATAPHYAlignRemover(Module):
110 def __init__(self):
111 self.sink = sink = Sink(phy_description(32))
112 self.source = source = Source(phy_description(32))
113
114 ###
115
116 charisk_match = sink.charisk == 0b0001
117 data_match = sink.data == primitives["ALIGN"]
118
119 self.comb += \
120 If(sink.stb & charisk_match & data_match,
121 sink.ack.eq(1),
122 ).Else(
123 Record.connect(sink, source)
124 )
125
126 class LiteSATAPHYDatapath(Module):
127 def __init__(self, trx, ctrl):
128 self.sink = Sink(phy_description(32))
129 self.source = Source(phy_description(32))
130
131 ###
132
133 # TX path
134 self.align_inserter = LiteSATAPHYAlignInserter(ctrl)
135 self.mux = Multiplexer(phy_description(32), 2)
136 self.tx = LiteSATAPHYDatapathTX()
137 self.comb += [
138 self.mux.sel.eq(ctrl.ready),
139 Record.connect(self.sink, self.align_inserter.sink),
140 Record.connect(ctrl.source, self.mux.sink0),
141 Record.connect(self.align_inserter.source, self.mux.sink1),
142 Record.connect(self.mux.source, self.tx.sink),
143 Record.connect(self.tx.source, trx.sink)
144 ]
145
146 # RX path
147 self.rx = LiteSATAPHYDatapathRX()
148 self.demux = Demultiplexer(phy_description(32), 2)
149 self.align_remover = LiteSATAPHYAlignRemover()
150 self.comb += [
151 self.demux.sel.eq(ctrl.ready),
152 Record.connect(trx.source, self.rx.sink),
153 Record.connect(self.rx.source, self.demux.sink),
154 Record.connect(self.demux.source0, ctrl.sink),
155 Record.connect(self.demux.source1, self.align_remover.sink),
156 Record.connect(self.align_remover.source, self.source)
157 ]