make ctrl/datapath in phy vendor agnostics and simplify imports
[litex.git] / lib / sata / link / __init__.py
1 from lib.sata.common import *
2 from lib.sata.link.crc import SATACRCInserter, SATACRCChecker
3 from lib.sata.link.scrambler import SATAScrambler
4 from lib.sata.link.cont import SATACONTInserter, SATACONTRemover
5
6 from_rx = [
7 ("idle", 1),
8 ("insert", 32),
9 ("det", 32)
10 ]
11
12 class SATALinkTX(Module):
13 def __init__(self, phy):
14 self.sink = Sink(link_description(32))
15 self.from_rx = Sink(from_rx)
16
17 ###
18
19 fsm = FSM(reset_state="IDLE")
20 self.submodules += fsm
21
22 # insert CRC
23 crc = SATACRCInserter(link_description(32))
24 self.submodules += crc
25
26 # scramble
27 scrambler = SATAScrambler(link_description(32))
28 self.submodules += scrambler
29
30 # connect CRC / scrambler
31 self.comb += [
32 Record.connect(self.sink, crc.sink),
33 Record.connect(crc.source, scrambler.sink)
34 ]
35
36 # inserter CONT and scrambled data between
37 # CONT and next primitive
38 cont = SATACONTInserter(phy_description(32))
39 self.submodules += cont
40
41 # datas / primitives mux
42 insert = Signal(32)
43 self.comb += [
44 If(self.from_rx.insert,
45 cont.sink.stb.eq(1),
46 cont.sink.data.eq(self.from_rx.insert),
47 cont.sink.charisk.eq(0x0001),
48 ).
49 Elif(insert,
50 cont.sink.stb.eq(1),
51 cont.sink.data.eq(insert),
52 cont.sink.charisk.eq(0x0001),
53 ).Elif(fsm.ongoing("COPY"),
54 cont.sink.stb.eq(scrambler.source.stb),
55 cont.sink.data.eq(scrambler.source.d),
56 scrambler.source.ack.eq(cont.sink.ack),
57 cont.sink.charisk.eq(0)
58 )
59 ]
60 self.comb += Record.connect(cont.source, phy.sink)
61
62 # FSM
63 fsm.act("IDLE",
64 scrambler.reset.eq(1),
65 If(self.from_rx.idle,
66 insert.eq(primitives["SYNC"]),
67 If(scrambler.source.stb & scrambler.source.sop,
68 NextState("RDY"),
69 )
70 )
71 )
72 fsm.act("RDY",
73 insert.eq(primitives["X_RDY"]),
74 If(~self.from_rx.idle,
75 NextState("IDLE")
76 ).Elif(self.from_rx.det == primitives["R_RDY"],
77 NextState("SOF")
78 )
79 )
80 fsm.act("SOF",
81 insert.eq(primitives["SOF"]),
82 If(phy.sink.ack,
83 NextState("COPY")
84 )
85 )
86 fsm.act("COPY",
87 If(self.from_rx.det == primitives["HOLD"],
88 insert.eq(primitives["HOLDA"]),
89 ).Elif(~scrambler.source.stb,
90 insert.eq(primitives["HOLD"]),
91 ).Elif(scrambler.source.stb & scrambler.source.eop & scrambler.source.ack,
92 NextState("EOF")
93 )
94 )
95 fsm.act("EOF",
96 insert.eq(primitives["EOF"]),
97 If(phy.sink.ack,
98 NextState("WTRM")
99 )
100 )
101 fsm.act("WTRM",
102 insert.eq(primitives["WTRM"]),
103 If(self.from_rx.det == primitives["R_OK"],
104 NextState("IDLE")
105 ).Elif(self.from_rx.det == primitives["R_ERR"],
106 NextState("IDLE")
107 )
108 )
109
110 class SATALinkRX(Module):
111 def __init__(self, phy):
112 self.source = Source(link_description(32))
113 self.to_tx = Source(from_rx)
114
115 ###
116
117 fsm = FSM(reset_state="IDLE")
118 self.submodules += fsm
119
120 # CONT remover
121 cont = SATACONTRemover(phy_description(32))
122 self.submodules += cont
123 self.comb += Record.connect(phy.source, cont.sink)
124
125 # datas / primitives detection
126 insert = Signal(32)
127 det = Signal(32)
128 self.comb += \
129 If(cont.source.stb & (cont.source.charisk == 0b0001),
130 det.eq(cont.source.data)
131 )
132
133 # descrambler
134 scrambler = SATAScrambler(link_description(32))
135 self.submodules += scrambler
136
137 # check CRC
138 crc = SATACRCChecker(link_description(32))
139 self.submodules += crc
140
141 sop = Signal()
142 self.sync += \
143 If(fsm.ongoing("RDY"),
144 sop.eq(1)
145 ).Elif(scrambler.sink.stb & scrambler.sink.ack,
146 sop.eq(0)
147 )
148
149 # small fifo to manage HOLD
150 self.submodules.fifo = SyncFIFO(link_description(32), 32)
151
152 # graph
153 self.sync += \
154 If(fsm.ongoing("COPY") & (det == 0),
155 scrambler.sink.stb.eq(cont.source.stb & (cont.source.charisk == 0)),
156 scrambler.sink.d.eq(cont.source.data),
157 ).Else(
158 scrambler.sink.stb.eq(0)
159 )
160 self.comb += [
161 scrambler.sink.sop.eq(sop),
162 scrambler.sink.eop.eq(det == primitives["EOF"]),
163 cont.source.ack.eq(1),
164 Record.connect(scrambler.source, crc.sink),
165 Record.connect(crc.source, self.fifo.sink),
166 Record.connect(self.fifo.source, self.source)
167 ]
168
169 # FSM
170 fsm.act("IDLE",
171 scrambler.reset.eq(1),
172 If(det == primitives["X_RDY"],
173 NextState("RDY")
174 )
175 )
176 fsm.act("RDY",
177 insert.eq(primitives["R_RDY"]),
178 If(det == primitives["SOF"],
179 NextState("COPY")
180 )
181 )
182 fsm.act("COPY",
183 insert.eq(primitives["R_IP"]),
184 If(det == primitives["HOLD"],
185 insert.eq(primitives["HOLDA"])
186 ).Elif(det == primitives["EOF"],
187 NextState("WTRM")
188 ).Elif(self.fifo.fifo.level > 8,
189 insert.eq(primitives["HOLD"])
190 )
191 )
192 fsm.act("EOF",
193 If(det == primitives["WTRM"],
194 NextState("WTRM")
195 )
196 )
197 fsm.act("WTRM",
198 insert.eq(primitives["R_OK"]),
199 If(det == primitives["SYNC"],
200 NextState("IDLE")
201 )
202 )
203
204 # to TX
205 self.comb += [
206 self.to_tx.idle.eq(fsm.ongoing("IDLE")),
207 self.to_tx.insert.eq(insert),
208 self.to_tx.det.eq(det)
209 ]
210
211 class SATALink(Module):
212 def __init__(self, phy):
213 self.submodules.tx = SATALinkTX(phy)
214 self.submodules.rx = SATALinkRX(phy)
215 self.comb += Record.connect(self.rx.to_tx, self.tx.from_rx)
216 self.sink, self.source = self.tx.sink, self.rx.source