change submodules/specials/clock_domains syntax
[litex.git] / litesata / core / link / __init__.py
1 from litesata.common import *
2 from litesata.core.link.crc import LiteSATACRCInserter, LiteSATACRCChecker
3 from litesata.core.link.scrambler import LiteSATAScrambler
4 from litesata.core.link.cont import LiteSATACONTInserter, LiteSATACONTRemover
5
6 from_rx = [
7 ("idle", 1),
8 ("insert", 32),
9 ("det", 32)
10 ]
11
12 class LiteSATALinkTX(Module):
13 def __init__(self, phy):
14 self.sink = Sink(link_description(32))
15 self.from_rx = Sink(from_rx)
16
17 ###
18
19 self.fsm = fsm = FSM(reset_state="IDLE")
20 self.submodules += fsm
21
22 # insert CRC
23 crc = LiteSATACRCInserter(link_description(32))
24 self.submodules += crc
25
26 # scramble
27 scrambler = LiteSATAScrambler(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 = BufferizeEndpoints(LiteSATACONTInserter(phy_description(32)), "source")
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 If(self.from_rx.det == primitives["SYNC"],
69 NextState("RDY")
70 )
71 )
72 )
73 )
74 fsm.act("RDY",
75 insert.eq(primitives["X_RDY"]),
76 If(~self.from_rx.idle,
77 NextState("IDLE")
78 ).Elif(self.from_rx.det == primitives["R_RDY"],
79 NextState("SOF")
80 )
81 )
82 fsm.act("SOF",
83 insert.eq(primitives["SOF"]),
84 If(phy.sink.ack,
85 NextState("COPY")
86 )
87 )
88 fsm.act("COPY",
89 If(self.from_rx.det == primitives["HOLD"],
90 insert.eq(primitives["HOLDA"]),
91 ).Elif(~scrambler.source.stb,
92 insert.eq(primitives["HOLD"]),
93 ).Elif(scrambler.source.stb & scrambler.source.eop & scrambler.source.ack,
94 NextState("EOF")
95 )
96 )
97 fsm.act("EOF",
98 insert.eq(primitives["EOF"]),
99 If(phy.sink.ack,
100 NextState("WTRM")
101 )
102 )
103 fsm.act("WTRM",
104 insert.eq(primitives["WTRM"]),
105 If(self.from_rx.det == primitives["R_OK"],
106 NextState("IDLE")
107 ).Elif(self.from_rx.det == primitives["R_ERR"],
108 NextState("IDLE")
109 )
110 )
111
112 class LiteSATALinkRX(Module):
113 def __init__(self, phy):
114 self.source = Source(link_description(32))
115 self.hold = Signal()
116 self.to_tx = Source(from_rx)
117
118 ###
119
120 self.fsm = fsm = FSM(reset_state="IDLE")
121 self.submodules += fsm
122
123 # CONT remover
124 cont = BufferizeEndpoints(LiteSATACONTRemover(phy_description(32)), "source")
125 self.submodules += cont
126 self.comb += Record.connect(phy.source, cont.sink)
127
128 # datas / primitives detection
129 insert = Signal(32)
130 det = Signal(32)
131 self.comb += \
132 If(cont.source.stb & (cont.source.charisk == 0b0001),
133 det.eq(cont.source.data)
134 )
135
136 # descrambler
137 scrambler = LiteSATAScrambler(link_description(32))
138 self.submodules += scrambler
139
140 # check CRC
141 crc = LiteSATACRCChecker(link_description(32))
142 self.submodules += crc
143
144 sop = Signal()
145 eop = Signal()
146 self.sync += \
147 If(fsm.ongoing("IDLE"),
148 sop.eq(1),
149 ).Elif(fsm.ongoing("COPY"),
150 If(scrambler.sink.stb & scrambler.sink.ack,
151 sop.eq(0)
152 )
153 )
154 self.comb += eop.eq(det == primitives["EOF"])
155
156 crc_error = Signal()
157 self.sync += \
158 If(crc.source.stb & crc.source.eop & crc.source.ack,
159 crc_error.eq(crc.source.error)
160 )
161
162 # graph
163 self.comb += [
164 cont.source.ack.eq(1),
165 Record.connect(scrambler.source, crc.sink),
166 Record.connect(crc.source, self.source),
167 ]
168 cont_source_data_d = Signal(32)
169 self.sync += \
170 If(cont.source.stb & (det == 0),
171 scrambler.sink.d.eq(cont.source.data)
172 )
173
174 # FSM
175 fsm.act("IDLE",
176 scrambler.reset.eq(1),
177 If(det == primitives["X_RDY"],
178 NextState("RDY")
179 )
180 )
181 fsm.act("RDY",
182 insert.eq(primitives["R_RDY"]),
183 If(det == primitives["SOF"],
184 NextState("WAIT_FIRST")
185 )
186 )
187 fsm.act("WAIT_FIRST",
188 insert.eq(primitives["R_IP"]),
189 If(cont.source.stb & (det == 0),
190 NextState("COPY")
191 )
192 )
193 self.comb += [
194 scrambler.sink.sop.eq(sop),
195 scrambler.sink.eop.eq(eop)
196 ]
197 fsm.act("COPY",
198 scrambler.sink.stb.eq(cont.source.stb & ((det == 0) | eop)),
199 insert.eq(primitives["R_IP"]),
200 If(det == primitives["HOLD"],
201 insert.eq(primitives["HOLDA"])
202 ).Elif(det == primitives["EOF"],
203 NextState("WTRM")
204 ).Elif(self.hold,
205 insert.eq(primitives["HOLD"])
206 )
207 )
208 fsm.act("EOF",
209 insert.eq(primitives["R_IP"]),
210 If(det == primitives["WTRM"],
211 NextState("WTRM")
212 )
213 )
214 fsm.act("WTRM",
215 insert.eq(primitives["R_IP"]),
216 If(~crc_error,
217 NextState("R_OK")
218 ).Else(
219 NextState("R_ERR")
220 )
221 )
222 fsm.act("R_OK",
223 insert.eq(primitives["R_OK"]),
224 If(det == primitives["SYNC"],
225 NextState("IDLE")
226 )
227 )
228 fsm.act("R_ERR",
229 insert.eq(primitives["R_ERR"]),
230 If(det == primitives["SYNC"],
231 NextState("IDLE")
232 )
233 )
234
235 # to TX
236 self.comb += [
237 self.to_tx.idle.eq(fsm.ongoing("IDLE")),
238 self.to_tx.insert.eq(insert),
239 self.to_tx.det.eq(det)
240 ]
241
242 class LiteSATALink(Module):
243 def __init__(self, phy, buffer_depth):
244 self.submodules.tx_buffer = PacketBuffer(link_description(32), buffer_depth)
245 self.submodules.tx = LiteSATALinkTX(phy)
246 self.submodules.rx = LiteSATALinkRX(phy)
247 self.submodules.rx_buffer = PacketBuffer(link_description(32), buffer_depth, almost_full=3*buffer_depth//4)
248 self.comb += [
249 Record.connect(self.tx_buffer.source, self.tx.sink),
250 Record.connect(self.rx.to_tx, self.tx.from_rx),
251 Record.connect(self.rx.source, self.rx_buffer.sink),
252 self.rx.hold.eq(self.rx_buffer.almost_full)
253 ]
254 self.sink, self.source = self.tx_buffer.sink, self.rx_buffer.source