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