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