change submodules/specials/clock_domains syntax
[litex.git] / litesata / core / transport / __init__.py
1 from litesata.common import *
2
3 def _get_item(obj, name, width):
4 if "_lsb" in name:
5 item = getattr(obj, name.replace("_lsb", ""))[:width]
6 elif "_msb" in name:
7 item = getattr(obj, name.replace("_msb", ""))[width:2*width]
8 else:
9 item = getattr(obj, name)
10 return item
11
12 def _encode_cmd(obj, description, signal):
13 r = []
14 for k, v in sorted(description.items()):
15 start = v.dword*32 + v.offset
16 end = start + v.width
17 item = _get_item(obj, k, v.width)
18 r.append(signal[start:end].eq(item))
19 return r
20
21 def test_type(name, signal):
22 return signal == fis_types[name]
23
24 class LiteSATATransportTX(Module):
25 def __init__(self, link):
26 self.sink = sink = Sink(transport_tx_description(32))
27
28 ###
29
30 cmd_ndwords = max(fis_reg_h2d_cmd_len, fis_data_cmd_len)
31 encoded_cmd = Signal(cmd_ndwords*32)
32
33 counter = Counter(max=cmd_ndwords+1)
34 self.submodules += counter
35
36 cmd_len = Signal(counter.width)
37 cmd_with_data = Signal()
38
39 cmd_send = Signal()
40 data_send = Signal()
41 cmd_done = Signal()
42
43 fis_type = Signal(8)
44 update_fis_type = Signal()
45
46 def test_type_tx(name):
47 return test_type(name, sink.type)
48
49 self.fsm = fsm = FSM(reset_state="IDLE")
50 self.submodules += fsm
51 fsm.act("IDLE",
52 sink.ack.eq(0),
53 counter.reset.eq(1),
54 update_fis_type.eq(1),
55 If(sink.stb & sink.sop,
56 If(test_type_tx("REG_H2D"),
57 NextState("SEND_CTRL_CMD")
58 ).Elif(test_type_tx("DATA"),
59 NextState("SEND_DATA_CMD")
60 ).Else(
61 sink.ack.eq(1)
62 )
63 ).Else(
64 sink.ack.eq(1)
65 )
66 )
67 self.sync += \
68 If(update_fis_type, fis_type.eq(link.source.d[:8]))
69
70 fsm.act("SEND_CTRL_CMD",
71 _encode_cmd(sink, fis_reg_h2d_layout, encoded_cmd),
72 cmd_len.eq(fis_reg_h2d_cmd_len-1),
73 cmd_send.eq(1),
74 If(cmd_done,
75 sink.ack.eq(1),
76 NextState("IDLE")
77 )
78 )
79 fsm.act("SEND_DATA_CMD",
80 sink.ack.eq(0),
81 _encode_cmd(sink, fis_data_layout, encoded_cmd),
82 cmd_len.eq(fis_data_cmd_len-1),
83 cmd_with_data.eq(1),
84 cmd_send.eq(1),
85 If(cmd_done,
86 NextState("SEND_DATA")
87 )
88 )
89 fsm.act("SEND_DATA",
90 data_send.eq(1),
91 sink.ack.eq(link.sink.ack),
92 If(sink.stb & sink.eop & sink.ack,
93 NextState("IDLE")
94 )
95 )
96
97 cmd_cases = {}
98 for i in range(cmd_ndwords):
99 cmd_cases[i] = [link.sink.d.eq(encoded_cmd[32*i:32*(i+1)])]
100
101 self.comb += [
102 counter.ce.eq(sink.stb & link.sink.ack),
103 cmd_done.eq((counter.value == cmd_len) & link.sink.stb & link.sink.ack),
104 If(cmd_send,
105 link.sink.stb.eq(sink.stb),
106 link.sink.sop.eq(counter.value == 0),
107 link.sink.eop.eq((counter.value == cmd_len) & ~cmd_with_data),
108 Case(counter.value, cmd_cases)
109 ).Elif(data_send,
110 link.sink.stb.eq(sink.stb),
111 link.sink.sop.eq(0),
112 link.sink.eop.eq(sink.eop),
113 link.sink.d.eq(sink.data)
114 )
115 ]
116
117 def _decode_cmd(signal, description, obj):
118 r = []
119 for k, v in sorted(description.items()):
120 start = v.dword*32+v.offset
121 end = start+v.width
122 item = _get_item(obj, k, v.width)
123 r.append(item.eq(signal[start:end]))
124 return r
125
126 class LiteSATATransportRX(Module):
127 def __init__(self, link):
128 self.source = source = Source(transport_rx_description(32))
129
130 ###
131
132 cmd_ndwords = max(fis_reg_d2h_cmd_len, fis_dma_activate_d2h_cmd_len,
133 fis_pio_setup_d2h_cmd_len, fis_data_cmd_len)
134 encoded_cmd = Signal(cmd_ndwords*32)
135
136 counter = Counter(max=cmd_ndwords+1)
137 self.submodules += counter
138
139 cmd_len = Signal(counter.width)
140
141 cmd_receive = Signal()
142 data_receive = Signal()
143 cmd_done = Signal()
144 data_done = Signal()
145
146 def test_type_rx(name):
147 return test_type(name, link.source.d[:8])
148
149 self.fsm = fsm = FSM(reset_state="IDLE")
150 self.submodules += fsm
151
152 data_sop = Signal()
153 fis_type = Signal(8)
154 update_fis_type = Signal()
155
156 fsm.act("IDLE",
157 link.source.ack.eq(0),
158 counter.reset.eq(1),
159 update_fis_type.eq(1),
160 If(link.source.stb & link.source.sop,
161 If(test_type_rx("REG_D2H"),
162 NextState("RECEIVE_CTRL_CMD")
163 ).Elif(test_type_rx("DMA_ACTIVATE_D2H"),
164 NextState("RECEIVE_CTRL_CMD")
165 ).Elif(test_type_rx("PIO_SETUP_D2H"),
166 NextState("RECEIVE_CTRL_CMD")
167 ).Elif(test_type_rx("DATA"),
168 NextState("RECEIVE_DATA_CMD"),
169 ).Else(
170 link.source.ack.eq(1)
171 )
172 ).Else(
173 link.source.ack.eq(1)
174 )
175 )
176 self.sync += \
177 If(update_fis_type, fis_type.eq(link.source.d[:8]))
178
179 fsm.act("RECEIVE_CTRL_CMD",
180 If(test_type("REG_D2H", fis_type),
181 cmd_len.eq(fis_reg_d2h_cmd_len-1)
182 ).Elif(test_type("DMA_ACTIVATE_D2H", fis_type),
183 cmd_len.eq(fis_dma_activate_d2h_cmd_len-1)
184 ).Else(
185 cmd_len.eq(fis_pio_setup_d2h_cmd_len-1)
186 ),
187 cmd_receive.eq(1),
188 link.source.ack.eq(1),
189 If(cmd_done,
190 NextState("PRESENT_CTRL_CMD")
191 )
192 )
193 fsm.act("PRESENT_CTRL_CMD",
194 source.stb.eq(1),
195 source.sop.eq(1),
196 source.eop.eq(1),
197 If(test_type("REG_D2H", fis_type),
198 _decode_cmd(encoded_cmd, fis_reg_d2h_layout, source),
199 ).Elif(test_type("DMA_ACTIVATE_D2H", fis_type),
200 _decode_cmd(encoded_cmd, fis_dma_activate_d2h_layout, source),
201 ).Else(
202 _decode_cmd(encoded_cmd, fis_pio_setup_d2h_layout, source),
203 ),
204 If(source.stb & source.ack,
205 NextState("IDLE")
206 )
207 )
208 fsm.act("RECEIVE_DATA_CMD",
209 cmd_len.eq(fis_data_cmd_len-1),
210 cmd_receive.eq(1),
211 link.source.ack.eq(1),
212 If(cmd_done,
213 NextState("PRESENT_DATA")
214 )
215 )
216 fsm.act("PRESENT_DATA",
217 data_receive.eq(1),
218 source.stb.eq(link.source.stb),
219 _decode_cmd(encoded_cmd, fis_data_layout, source),
220 source.sop.eq(data_sop),
221 source.eop.eq(link.source.eop),
222 source.error.eq(link.source.error),
223 source.data.eq(link.source.d),
224 link.source.ack.eq(source.ack),
225 If(source.stb & source.eop & source.ack,
226 NextState("IDLE")
227 )
228 )
229
230 self.sync += \
231 If(fsm.ongoing("RECEIVE_DATA_CMD"),
232 data_sop.eq(1)
233 ).Elif(fsm.ongoing("PRESENT_DATA"),
234 If(source.stb & source.ack,
235 data_sop.eq(0)
236 )
237 )
238
239 cmd_cases = {}
240 for i in range(cmd_ndwords):
241 cmd_cases[i] = [encoded_cmd[32*i:32*(i+1)].eq(link.source.d)]
242
243 self.comb += \
244 If(cmd_receive & link.source.stb,
245 counter.ce.eq(1)
246 )
247 self.sync += \
248 If(cmd_receive,
249 Case(counter.value, cmd_cases),
250 )
251 self.comb += cmd_done.eq((counter.value == cmd_len) & link.source.ack)
252
253 class LiteSATATransport(Module):
254 def __init__(self, link):
255 self.submodules.tx = LiteSATATransportTX(link)
256 self.submodules.rx = LiteSATATransportRX(link)
257 self.sink, self.source = self.tx.sink, self.rx.source