Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: pl_top.cpp | |
4 | // Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved | |
5 | // 4150 Network Circle, Santa Clara, California 95054, U.S.A. | |
6 | // | |
7 | // * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
8 | // | |
9 | // This program is free software; you can redistribute it and/or modify | |
10 | // it under the terms of the GNU General Public License as published by | |
11 | // the Free Software Foundation; version 2 of the License. | |
12 | // | |
13 | // This program is distributed in the hope that it will be useful, | |
14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | // GNU General Public License for more details. | |
17 | // | |
18 | // You should have received a copy of the GNU General Public License | |
19 | // along with this program; if not, write to the Free Software | |
20 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 | // | |
22 | // For the avoidance of doubt, and except that if any non-GPL license | |
23 | // choice is available it will apply instead, Sun elects to use only | |
24 | // the General Public License version 2 (GPLv2) at this time for any | |
25 | // software where a choice of GPL license versions is made | |
26 | // available with the language indicating that GPLv2 or any later version | |
27 | // may be used, or where a choice of which version of the GPL is applied is | |
28 | // otherwise unspecified. | |
29 | // | |
30 | // Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
31 | // CA 95054 USA or visit www.sun.com if you need additional information or | |
32 | // have any questions. | |
33 | // | |
34 | // ========== Copyright Header End ============================================ | |
35 | #include <systemc.h> | |
36 | #include <math.h> | |
37 | #include "pl/pl_top.h" | |
38 | #include <map> | |
39 | ||
40 | USING_NAMESPACE(pcie) | |
41 | USING_NAMESPACE(Logger) | |
42 | ||
43 | /// This is the main transmit block. | |
44 | /// It gets the packet from the TLM FIFO | |
45 | /// forms the PL frame and then sends out according to the LINK_WIDTH | |
46 | /// It first scrambles, then encodes and then finally forms frames | |
47 | /// It is also responsible for forming intermediate SKP Ordered sets and IDLE sets | |
48 | void pl_top::process_packet() | |
49 | { | |
50 | int i,j; | |
51 | int lane; | |
52 | int pkt_cnt = 0; | |
53 | int pkt_id = 0; | |
54 | int skp_counter = 0; | |
55 | int dll_pkt_cnt = 0; | |
56 | double size; | |
57 | unsigned short scramble_lfsr; | |
58 | unsigned long word_val; | |
59 | map<int,int>::iterator iter; | |
60 | RefPciePacket pkt; | |
61 | RefPciePacket receive_packet; | |
62 | RefPciePacket idle_packet; | |
63 | RefPciePacket skp_packet; | |
64 | bool waitingforFirstData = true; | |
65 | bool packet_ready_dll,packet_ready_tl,round_robin_dll_tl = false; | |
66 | bool skp_ordered_set = false; | |
67 | bool put_end_symbol = false; | |
68 | sc_lv<5> control; /// control signal from the DLL | |
69 | ||
70 | while(1){ | |
71 | if ( dll_pkt_cnt >= 5) | |
72 | packet_ready_tl = dll_pl_tlp_in.is_packet_ready(); | |
73 | ||
74 | packet_ready_dll = dll_pl_dllp_in.is_packet_ready(); | |
75 | ||
76 | ||
77 | #ifdef SEND_SKP | |
78 | if((packet_ready_tl || packet_ready_dll) && init_done.read() && !last_idle_frame.read() && !interleave_idle && ((skp_counter < 1450) || skp_counter == 0)) /// Link Init complete and DLLP has put a packet into the FIFO | |
79 | #else | |
80 | if((packet_ready_tl || packet_ready_dll) && init_done.read() && !last_idle_frame.read() && !interleave_idle) /// Link Init complete and DLLP has put a packet into the FIFO | |
81 | #endif | |
82 | { | |
83 | if(packet_ready_dll && !round_robin_dll_tl) | |
84 | { | |
85 | dll_pl_dllp_in.get_packet(receive_packet); | |
86 | //cout<< sc_time_stamp() <<"\t\t\t\t\t| PL: Recvd DLLP " << receive_packet->getPacketId() << " from DLL." <<endl; | |
87 | dll_pkt_cnt++; | |
88 | if(dll_pkt_cnt >= 5) /// Make sure FC_INIT packets go before any TLP | |
89 | round_robin_dll_tl = true; | |
90 | } | |
91 | else if(packet_ready_tl && round_robin_dll_tl) | |
92 | { | |
93 | dll_pl_tlp_in.get_packet(receive_packet); | |
94 | //cout<< sc_time_stamp() <<"\t\t\t\t\t| PL: Recvd TLP " << receive_packet->getPacketId() << " from DLL." <<endl; | |
95 | round_robin_dll_tl = false; | |
96 | } | |
97 | else if(packet_ready_dll && !packet_ready_tl && round_robin_dll_tl) /// Still keep next priority for TL. But dequeue DLL Q for now | |
98 | { | |
99 | dll_pl_dllp_in.get_packet(receive_packet); | |
100 | //cout<< sc_time_stamp() <<"\t\t\t\t\t| PL: Recvd DLLP " << receive_packet->getPacketId() << " from DLL." <<endl; | |
101 | dll_pkt_cnt++; | |
102 | } | |
103 | else if( packet_ready_tl && !packet_ready_dll && !round_robin_dll_tl) /// Still Keep next priority for DLL. But dequeue TL for now | |
104 | { | |
105 | dll_pl_tlp_in.get_packet(receive_packet); | |
106 | //cout<< sc_time_stamp() <<"\t\t\t\t\t| PL: Recvd TLP " << receive_packet->getPacketId() << " from DLL." <<endl; | |
107 | } | |
108 | ||
109 | pkt_id = receive_packet->getPacketId(); | |
110 | ||
111 | global_packet = receive_packet; | |
112 | q_not_empty.write(true); | |
113 | waitingforFirstData = false; | |
114 | size = global_packet->get_size(); | |
115 | interleave_idle = true; | |
116 | control = global_packet->get_control(); | |
117 | } | |
118 | #ifdef SEND_SKP | |
119 | else if((skp_counter < 1450) || skp_counter == 0)/// Produce IDLE packets | |
120 | #else | |
121 | else | |
122 | #endif | |
123 | { | |
124 | idle_packet = new pciePacket(LINK_WIDTH); | |
125 | for(i=0;i<LINK_WIDTH;i++) | |
126 | idle_packet->modify_byte(i,0x00); | |
127 | global_packet = idle_packet; | |
128 | if(packet_ready_dll || packet_ready_tl) | |
129 | { | |
130 | q_not_empty.write(true); /// data is available, but the last IDLE frame has not been transmitted | |
131 | } | |
132 | else if(!packet_ready_dll && !packet_ready_tl && waitingforFirstData) | |
133 | q_not_empty.write(false); | |
134 | ||
135 | size = global_packet->get_size(); | |
136 | interleave_idle = false; /// Interleave every DLLP/TLP with an IDLE frame | |
137 | control = 0x000; /// No Control Chars in the IDLE frame | |
138 | } | |
139 | #ifdef SEND_SKP | |
140 | else if((skp_counter >= 1450)) | |
141 | { | |
142 | skp_packet = new pciePacket(4*LINK_WIDTH); /// SKP is sent across 4 frames | |
143 | for(i=0;i<LINK_WIDTH;i++) | |
144 | skp_packet->modify_byte(i,COM); | |
145 | for(i=LINK_WIDTH;i<2*LINK_WIDTH;i++) | |
146 | skp_packet->modify_byte(i,SKP); | |
147 | for(i=2*LINK_WIDTH;i<3*LINK_WIDTH;i++) | |
148 | skp_packet->modify_byte(i,SKP); | |
149 | for(i=3*LINK_WIDTH;i<4*LINK_WIDTH;i++) | |
150 | skp_packet->modify_byte(i,SKP); | |
151 | ||
152 | global_packet = skp_packet; | |
153 | size = global_packet->get_size(); | |
154 | control = 0x001; | |
155 | skp_counter = 0; | |
156 | } | |
157 | #endif | |
158 | pkt = global_packet; | |
159 | ||
160 | put_end_symbol = false; | |
161 | control = pkt->get_control(); | |
162 | if(control[1] == 0x1) /// Only for STP, ignore the 0th byte | |
163 | size--; | |
164 | /// Check if LINK_WIDTH > size + 2 | |
165 | if(size <= LINK_WIDTH) /// For FC_Init and IDLE frames | |
166 | { | |
167 | control = pkt->get_control(); /// Control signal from the DLLP | |
168 | /// [0] = D/K# | |
169 | /// [1] = STP | |
170 | /// [2] = SDP | |
171 | /// [3] = END | |
172 | /// [4] = EDB | |
173 | if((control[1] != 0x1) && (control[2] != 0x1)) /// IDLE packet | |
174 | { | |
175 | for(i = 0; i < size; i++) /// The actual data without STP/SDP | |
176 | { | |
177 | xtracted_data[i] = pkt->get_byte(i); | |
178 | xtracted_data_c[i] = false; | |
179 | } | |
180 | for(i = size ; i < LINK_WIDTH ; i++) /// PAD or END character | |
181 | { | |
182 | xtracted_data[i] = PAD; | |
183 | } | |
184 | size = LINK_WIDTH; | |
185 | } | |
186 | else /// FC_Init | |
187 | { | |
188 | if(control[1] == 0x1) | |
189 | { | |
190 | xtracted_data[0] = STP; | |
191 | xtracted_data_c[0] = true; | |
192 | } | |
193 | else if(control[2] == 0x1) | |
194 | { | |
195 | xtracted_data[0] = SDP; | |
196 | xtracted_data_c[0] = true; | |
197 | } | |
198 | for(i = 1,j=0; i <= size,j< size; i++,j++) /// The actual data with CRC | |
199 | { | |
200 | xtracted_data[i] = pkt->get_byte(j); | |
201 | xtracted_data_c[i] = false; | |
202 | } | |
203 | for(i = size+1 ; i < LINK_WIDTH ; i++) /// PAD or END character | |
204 | { | |
205 | if(((i+1) % 4) == 0 && (control[3] == 0x1) && !put_end_symbol) /// END | |
206 | { | |
207 | xtracted_data[i] = END; | |
208 | xtracted_data_c[i] = true; | |
209 | put_end_symbol = true; | |
210 | } | |
211 | else if(((i+1) %4) == 0 && (control[4] == 0x1) && !put_end_symbol) /// EDB | |
212 | { | |
213 | xtracted_data[i] = EDB; | |
214 | xtracted_data_c[i] = true; | |
215 | put_end_symbol = true; | |
216 | } | |
217 | else | |
218 | { | |
219 | xtracted_data[i] = PAD; | |
220 | xtracted_data_c[i] = true; | |
221 | } | |
222 | } | |
223 | size = LINK_WIDTH; | |
224 | } | |
225 | } | |
226 | else/// Transaction Layer packets or SKP Ordered Set or DLLP with size > LINK_WIDTH | |
227 | { | |
228 | control = pkt->get_control(); | |
229 | if(control[0] == 0) /// TLP | |
230 | { | |
231 | if(control[1] == 0x1) | |
232 | { | |
233 | xtracted_data[0] = STP; | |
234 | xtracted_data_c[0] = true; | |
235 | } | |
236 | else if(control[2] == 0x1) | |
237 | { | |
238 | xtracted_data[0] = SDP; | |
239 | xtracted_data_c[0] = true; | |
240 | } | |
241 | for(i=1,j=0; i<= size,j<size ; i++,j++) /// The actual data with CRC for TLP | |
242 | { | |
243 | if(xtracted_data[0] == SDP) /// get data from byte 0 | |
244 | xtracted_data[i] = pkt->get_byte(j); | |
245 | else | |
246 | xtracted_data[i] = pkt->get_byte(i); | |
247 | xtracted_data_c[i] = false; | |
248 | } | |
249 | for(i = size+1 ; i < LINK_WIDTH*ceil(double((size+2)/LINK_WIDTH)); i++) | |
250 | { | |
251 | if(((i+1) % 4) == 0 && (control[3] == 0x1) && !put_end_symbol) /// END | |
252 | { | |
253 | xtracted_data[i] = END; | |
254 | xtracted_data_c[i] = true; | |
255 | put_end_symbol = true; | |
256 | } | |
257 | else if(((i+1) % 4) == 0 && (control[4] == 0x1) && !put_end_symbol) /// EDB | |
258 | { | |
259 | xtracted_data[i] = EDB; | |
260 | xtracted_data_c[i] = true; | |
261 | put_end_symbol = true; | |
262 | } | |
263 | else | |
264 | { | |
265 | xtracted_data[i] = PAD; | |
266 | xtracted_data_c[i] = true; | |
267 | } | |
268 | } | |
269 | size = LINK_WIDTH*ceil(double((size+2)/LINK_WIDTH)); | |
270 | } | |
271 | else | |
272 | { | |
273 | /// SKP Ordered Set | |
274 | for(i=0; i< size; i++) | |
275 | { | |
276 | xtracted_data[i] = pkt->get_byte(i); | |
277 | xtracted_data_c[i] = true; | |
278 | } | |
279 | size = 4*LINK_WIDTH; | |
280 | } | |
281 | } | |
282 | ||
283 | /// Now scramble the data | |
284 | if(init_done.read() && reset_l.read() && reset_por_l.read()) | |
285 | { | |
286 | initialization_done = true; | |
287 | for(int lane_scram=0; lane_scram<LINK_WIDTH; lane_scram++) | |
288 | scrambler_i->start_scramble_reg[lane_scram] = true; | |
289 | scramble_lfsr = scrambler_i->get_lfsr(0); | |
290 | for(i = 0 ; i< size ; i++) /// Whether to scramble or descramble the data. The Start, end and PAD symbols will not be scrambled anyway | |
291 | { | |
292 | if(((i % LINK_WIDTH) == 0 && (i > 0)) || (LINK_WIDTH == 1 && xtracted_data[i] == SKP)) | |
293 | { | |
294 | if(xtracted_data_c[i]) /// Should go into this block when LINK_1 and control character | |
295 | { | |
296 | if(xtracted_data[i] == SKP) | |
297 | { | |
298 | skp_ordered_set = true; | |
299 | scrambler_i->scramble_descramble_all(SKP,0,1); | |
300 | } | |
301 | } | |
302 | else | |
303 | { | |
304 | scrambler_i->scramble_descramble_all(0x00,1,0); /// Forward the LFSR for the next scramble | |
305 | scramble_lfsr = scrambler_i->get_lfsr(0); | |
306 | } | |
307 | } | |
308 | ||
309 | if(control[0] == 0x1) /// This is a control packet. Dont scramble it at all | |
310 | { | |
311 | xtracted_data_c[i] = true; | |
312 | continue; | |
313 | } | |
314 | ||
315 | if(xtracted_data_c[i]) /// Dont scramble K characters | |
316 | { | |
317 | /// First check if its a COM...Reset lfsr | |
318 | word_val = xtracted_data[i].get_word(0); | |
319 | if(xtracted_data[i] == COM) | |
320 | scrambler_i->scramble_descramble_all(word_val,1,1); | |
321 | continue; | |
322 | } | |
323 | ||
324 | word_val = xtracted_data[i].get_word(0); | |
325 | xtracted_data[i] = scrambler_i->scramble_descramble_all(word_val,1,0); | |
326 | if(scrambler_i->get_lfsr(0) != 0xffff) { | |
327 | for(int lane_scram=0; lane_scram<LINK_WIDTH; lane_scram++) | |
328 | scrambler_i->set_lfsr(scramble_lfsr,lane_scram); | |
329 | } | |
330 | wait(SC_ZERO_TIME); | |
331 | ||
332 | } | |
333 | if(!skp_ordered_set) | |
334 | { | |
335 | scrambler_i->scramble_descramble_all(0x00,1,0); /// Size of packet is only 8 bytes | |
336 | for(int lane_scram=0; lane_scram<LINK_WIDTH; lane_scram++) | |
337 | scrambler_i->start_scramble_reg[lane_scram] = false; | |
338 | } | |
339 | else | |
340 | { | |
341 | skp_ordered_set = false; | |
342 | } | |
343 | ||
344 | skp_ordered_set = false; | |
345 | /// Now encode the data | |
346 | for(i = 0; i< size ; i++) | |
347 | { | |
348 | wait(SC_ZERO_TIME); | |
349 | lane = i%LINK_WIDTH; | |
350 | if(curr_running_disp->get_CRD(lane) == 0) | |
351 | { | |
352 | word_val = xtracted_data[i].get_word(0); | |
353 | iter = map_table->neg_spec_symbol_map.find(word_val); | |
354 | if((iter == map_table->neg_spec_symbol_map.end()) || !xtracted_data_c[i]) /// This is not a control packet and not STP/SDP/END/EDB when not scrambled | |
355 | iter = map_table->neg_data_encode_map.find(word_val); | |
356 | xtracted_data[i] = iter->second; | |
357 | } | |
358 | else if(curr_running_disp->get_CRD(lane) == 1) | |
359 | { | |
360 | word_val = xtracted_data[i].get_word(0); | |
361 | iter = map_table->spec_symbol_map.find(word_val); | |
362 | if((iter == map_table->spec_symbol_map.end()) || !xtracted_data_c[i]) /// This is not a control packet and not STP/SDP/END/EDB when not scrambled | |
363 | iter = map_table->data_encode_map.find(word_val); | |
364 | xtracted_data[i] = iter->second; | |
365 | } | |
366 | if(curr_running_disp->calculate_disparity(xtracted_data[i].get_word(0),0) == 0) | |
367 | { | |
368 | curr_running_disp->set_CRD(lane,sc_logic(0)); | |
369 | } | |
370 | else if(curr_running_disp->calculate_disparity(xtracted_data[i].get_word(0),0) == 1) | |
371 | { | |
372 | curr_running_disp->set_CRD(lane,sc_logic(1)); | |
373 | } | |
374 | wait(SC_ZERO_TIME); | |
375 | } | |
376 | /// data has now been encoded...needs to be serialized | |
377 | /// Have the packet, now packetize it properly | |
378 | /// If we now have to just send the data onto the bus this data, xtracted_data can be forwarded | |
379 | } | |
380 | else if(!init_done.read()) | |
381 | { | |
382 | initialization_done = false; | |
383 | interleave_idle = true; | |
384 | skp_counter = 0; | |
385 | } | |
386 | ||
387 | finished_sending_pkt = false; | |
388 | while(pkt_cnt < size) | |
389 | { | |
390 | finished_sending_pkt = false; | |
391 | for(j=0;j<10;j++) | |
392 | { | |
393 | for(i=pkt_cnt;i< (pkt_cnt+LINK_WIDTH) ;i++) | |
394 | { | |
395 | if(LINK_WIDTH == 1) | |
396 | lane_data[j] = (xtracted_data[i].range(9-j,9-j)); | |
397 | else | |
398 | lane_data[j] = (xtracted_data[i].range(9-j,9-j),lane_data[j].range(LINK_WIDTH-1,1)); | |
399 | } | |
400 | } | |
401 | pkt_cnt += LINK_WIDTH; | |
402 | sym_boundary = 1; | |
403 | wait(frame_boundary_ltssm_tx.posedge_event()); /// init_done will not be detected first time | |
404 | /// So send IDLE frames first time only in this section | |
405 | /// Else send the correct frames | |
406 | /// At the end of this cycle, the data format is as we would like it to be (packetized properly) | |
407 | for(i=0;i<10;i++) | |
408 | { | |
409 | encoded_data = 0; | |
410 | encoded_data = lane_data[i]; /// This should be just fine | |
411 | wait(link_clk.negedge_event()); | |
412 | skp_counter++; | |
413 | switch(i) | |
414 | { | |
415 | case 0 : encoded_data0 = encoded_data; | |
416 | case 1 : encoded_data1 = encoded_data; | |
417 | case 2 : encoded_data2 = encoded_data; | |
418 | case 3 : encoded_data3 = encoded_data; | |
419 | case 4 : encoded_data4 = encoded_data; | |
420 | case 5 : encoded_data5 = encoded_data; | |
421 | case 6 : encoded_data6 = encoded_data; | |
422 | case 7 : encoded_data7 = encoded_data; | |
423 | case 8 : encoded_data8 = encoded_data; | |
424 | case 9 : encoded_data9 = encoded_data; | |
425 | } | |
426 | } | |
427 | sym_boundary = 0; | |
428 | /// The data into the serializer input is ready and available | |
429 | /// The serializer gives out data at every posedge link_clk. | |
430 | /// Look at the data at the negedge to take care of race conditions | |
431 | /// Thus, get the serialized at every negedge link_clk for the entire packet | |
432 | /// Data is in serialized_data_out. This is a logic value | |
433 | } | |
434 | finished_sending_pkt = true; | |
435 | pkt_cnt = 0; | |
436 | } | |
437 | } | |
438 | ||
439 | //// Signal for retraining | |
440 | void pl_top::check_reinit() | |
441 | { | |
442 | while(true) | |
443 | { | |
444 | wait(frame_boundary_ltssm_tx.posedge_event()); | |
445 | if(!init_done.read() && finished_sending_pkt) | |
446 | start_reinit.write(true); | |
447 | else if(!init_done.read() && !initialization_done) | |
448 | start_reinit.write(true); | |
449 | else | |
450 | start_reinit.write(false); | |
451 | } | |
452 | } | |
453 | ||
454 | /// Singal for staging the retraining | |
455 | void pl_top::check_stage_reinit() | |
456 | { | |
457 | while(true) | |
458 | { | |
459 | wait(frame_boundary_ltssm_tx.negedge_event()); | |
460 | if(start_reinit.read()) | |
461 | stage_reinit.write(true); | |
462 | else | |
463 | stage_reinit.write(false); | |
464 | } | |
465 | } | |
466 | ||
467 | /// This block is responsible for processing the incoming | |
468 | /// data on the ingress port/receiver side. | |
469 | /// It does the reverse of the transmit side. | |
470 | /// First decodes, then descrambles and then reframes | |
471 | /// Forms the appropriate packet and then puts into into the TLM FIFO | |
472 | /// for the DLL to consume the packet | |
473 | void pl_top::ingress_process_packet() /// Receiver/Ingress port | |
474 | { | |
475 | int i,j; | |
476 | int ingr_cnt = 0; | |
477 | int pkt_cnt = 0; | |
478 | int idl_count = 0,num_pad = 0; | |
479 | int lane_with_start = 0,lane_with_end = 0; | |
480 | int reset_lfsr_counter = 0; | |
481 | unsigned short descramble_lfsr[LINK_WIDTH]; | |
482 | unsigned long word_val; | |
483 | RefPciePacket ingress_packet,send_packet; | |
484 | bool end_detected = false; | |
485 | bool stp_sdp_ended = true; | |
486 | bool start_ingr_packet[LINK_WIDTH],end_ingr_packet[LINK_WIDTH],start_ingr_pkt = false; | |
487 | bool first_time_after_L0 = true; | |
488 | bool reset_lfsr; | |
489 | bool com_detected = false; | |
490 | bool skp_ordered_set = false; | |
491 | bool last_frame_idle = false; | |
492 | bool back2back_pkt = false; | |
493 | bool this_frame_start_detected = false,this_frame_end_detected = false; | |
494 | map<int,int>::iterator iter1,iter2,iter3,iter4; | |
495 | ||
496 | //Receive Error types | |
497 | enum {RE_NONE, RE_PRD, RE_NRD, RE_FRA, RE_8b10b}; | |
498 | int rcv_error = RE_NONE; | |
499 | ||
500 | while(true) | |
501 | { | |
502 | while(!end_detected) /// Read in the entire packet | |
503 | { | |
504 | /// Now its the turn of the deserializer to play its part | |
505 | /// Make sure the deserializer can see the internal PL layer frame_boundary/ref_clk properly | |
506 | wait(frm_boundary_deser.posedge_event()); | |
507 | wait(link_clk.posedge_event()); | |
508 | ||
509 | ingr_xtracted_data[ingr_cnt++] = deser_data0; /// First chunk and so on | |
510 | ingr_xtracted_data[ingr_cnt++] = deser_data1; | |
511 | ingr_xtracted_data[ingr_cnt++] = deser_data2; | |
512 | ingr_xtracted_data[ingr_cnt++] = deser_data3; | |
513 | ingr_xtracted_data[ingr_cnt++] = deser_data4; | |
514 | ingr_xtracted_data[ingr_cnt++] = deser_data5; | |
515 | ingr_xtracted_data[ingr_cnt++] = deser_data6; | |
516 | ingr_xtracted_data[ingr_cnt++] = deser_data7; | |
517 | ingr_xtracted_data[ingr_cnt++] = deser_data8; | |
518 | ingr_xtracted_data[ingr_cnt++] = deser_data9; | |
519 | /// Received LINK_WIDTH number of characters | |
520 | if((init_done_rx.read() && reset_l.read() && reset_por_l.read())) /// Wait until a packet is sent before handling over control to the LTSSM | |
521 | { | |
522 | for(j=0;j<LINK_WIDTH;j++) | |
523 | { | |
524 | for(i=0;i<10;i++) | |
525 | { | |
526 | ingr_lane_data[j] = (ingr_xtracted_data[ingr_cnt+i-10].range(j,j),ingr_lane_data[j].range(9,1)); | |
527 | } | |
528 | start_ingr_packet[j] = false; | |
529 | end_ingr_packet[j] = false; | |
530 | descrambler_i->start_scramble_reg[j] = true; | |
531 | descramble_lfsr[j] = descrambler_i->get_lfsr(j); /// Descramble all the packets with this lfsr | |
532 | } | |
533 | for(i=0;i<LINK_WIDTH;i++) /// Form the packets | |
534 | { | |
535 | ingr_decoded_data[pkt_cnt] = ingr_lane_data[i].range(0,9); | |
536 | pkt_cnt++; | |
537 | if(i % 4 == 0) | |
538 | { | |
539 | if(ingr_decoded_data[pkt_cnt-1] == 0x097 || ingr_decoded_data[pkt_cnt-1] == 0x368 || ingr_decoded_data[pkt_cnt-1] == 0x30a || ingr_decoded_data[pkt_cnt-1] == 0x0f5) /// STP/SDP | |
540 | { | |
541 | start_ingr_packet[i] = true; | |
542 | start_ingr_pkt = true; | |
543 | this_frame_start_detected = true; | |
544 | } | |
545 | } | |
546 | if((i+1) % 4 == 0) | |
547 | { | |
548 | if(ingr_decoded_data[pkt_cnt-1] == 0x117 || ingr_decoded_data[pkt_cnt-1] == 0x2e8 || ingr_decoded_data[pkt_cnt-1] == 0x217 || ingr_decoded_data[pkt_cnt-1] == 0x1e8) /// END/EDB | |
549 | { | |
550 | end_ingr_packet[i] = true; | |
551 | this_pkt_size = pkt_cnt; | |
552 | end_detected = true; | |
553 | this_frame_end_detected = true; | |
554 | } | |
555 | } | |
556 | /// Decode the characters in this frame | |
557 | /// ingr_decoded_data[pkt_cnt-1].concat_get_data(val,0); | |
558 | word_val = ingr_decoded_data[pkt_cnt-1].get_word(0); | |
559 | iter3 = map_table->spec_symbol_decode_map.find(word_val); | |
560 | iter1 = map_table->data_decode_map.find(word_val); | |
561 | iter4 = map_table->neg_spec_symbol_decode_map.find(word_val); | |
562 | iter2 = map_table->neg_data_decode_map.find(word_val); | |
563 | if(iter3 != map_table->spec_symbol_decode_map.end()) | |
564 | { | |
565 | ingr_xtracted_byte[pkt_cnt-1] = iter3->second; | |
566 | if(!curr_running_disp->get_rx_CRD(i).to_bool() && init_done_rx.read()) | |
567 | { | |
568 | LOG_WARNING << "WARNING : _PL_INGR_ : Positive running Disparity Error in lane " << i; | |
569 | rcv_error = RE_PRD; | |
570 | } | |
571 | else if(init_done_rx.read()) | |
572 | { | |
573 | if(curr_running_disp->calculate_disparity(ingr_decoded_data[pkt_cnt-1],0) == 1) | |
574 | curr_running_disp->set_rx_CRD(i,sc_logic(1)); | |
575 | else if(curr_running_disp->calculate_disparity(ingr_decoded_data[pkt_cnt-1],0) == 0) | |
576 | curr_running_disp->set_rx_CRD(i,sc_logic(0)); | |
577 | } | |
578 | /// Check for STP/SDP framing error | |
579 | if(iter3->second == STP || iter3->second == SDP) | |
580 | { | |
581 | if((i % 4 != 0) && init_done_rx.read()) | |
582 | { | |
583 | LOG_WARNING << "WARNING : _PL_INGR_ : Framing Error (Lane= " << i << "). STP/SDP should come on modulo 4 lanes"; | |
584 | rcv_error = RE_FRA; | |
585 | } | |
586 | if(last_frame_idle && i != 0 && init_done_rx.read()) | |
587 | { | |
588 | LOG_WARNING << "WARNING : _PL_INGR_ : Framing Error (Lane= " << i << "). STP/SDP must be in lane 0 after Logical Idle"; | |
589 | rcv_error = RE_FRA; | |
590 | } | |
591 | if(!stp_sdp_ended && init_done_rx.read()) | |
592 | { | |
593 | LOG_WARNING << "WARNING : _PL_INGR : Framing Error (Lane= " << i << "). STP/SDP without previous END/EDB"; | |
594 | rcv_error = RE_FRA; | |
595 | } | |
596 | stp_sdp_ended = false; | |
597 | } | |
598 | else if(iter3->second == SKP) | |
599 | { | |
600 | LOG_DEBUG << "DEBUG : _PL_INGR_ : SKP Character received (Lane= " << i << ")"; | |
601 | } | |
602 | ||
603 | /// Check for END/EDB framing error | |
604 | else if(iter3->second == END || iter3->second == EDB) | |
605 | { | |
606 | if(((i+1) % 4) != 0 && init_done_rx.read()) | |
607 | { | |
608 | LOG_WARNING << "WARNING : _PL_INGR_ : Framing Error (Lane= " << i << "). END/EDB should come in modulo 4 - 1 lanes"; | |
609 | rcv_error = RE_FRA; | |
610 | } | |
611 | ||
612 | if(i != LINK_WIDTH - 1) /// Make sure the next packet is a PAD/STP/SDP | |
613 | { | |
614 | if(ingr_lane_data[i+1].range(0,9) != 0x97 && ingr_lane_data[i+1].range(0,9) != 0x368 && ingr_lane_data[i+1].range(0,9) != 0x30a && ingr_lane_data[i+1].range(0,9) != 0xf5 && ingr_lane_data[i+1].range(0,9) != 0x3a8 && ingr_lane_data[i+1].range(0,9) != 0x57 && init_done_rx.read()) | |
615 | { | |
616 | LOG_WARNING << "WARNING : _PL_INGR_ : Framing Error (Lane= " << i << "). END/EDB must be followed by PAD/STP/SDP"; | |
617 | rcv_error = RE_FRA; | |
618 | } | |
619 | } | |
620 | if(stp_sdp_ended && init_done_rx.read()) | |
621 | { | |
622 | LOG_WARNING << "WARNING : _PL_INGR_ : Framing Error (Lane= " << i << "). END/EDB without previous STP/SDP"; | |
623 | rcv_error = RE_FRA; | |
624 | } | |
625 | stp_sdp_ended = true; | |
626 | } | |
627 | else if(iter3->second == COM && !stp_sdp_ended && init_done_rx.read()) | |
628 | { | |
629 | LOG_WARNING << "WARNING : _PL_INGR_ : Framing Error (Lane= " << i << "). Unexpected COM Character. Unterminated STP/SDP"; | |
630 | rcv_error = RE_FRA; | |
631 | } | |
632 | ||
633 | ingr_xtracted_byte_c[pkt_cnt-1] = true; | |
634 | } | |
635 | else if(iter4 != map_table->neg_spec_symbol_decode_map.end()) | |
636 | { | |
637 | ingr_xtracted_byte[pkt_cnt-1] = iter4->second; | |
638 | if(curr_running_disp->get_rx_CRD(i).to_bool() && init_done_rx.read()) | |
639 | { | |
640 | LOG_WARNING << "WARNING : _PL_INGR_ : Negative running Disparity Error in lane " << i; | |
641 | rcv_error = RE_NRD; | |
642 | } | |
643 | else if(init_done_rx.read()) | |
644 | { | |
645 | if(curr_running_disp->calculate_disparity(ingr_decoded_data[pkt_cnt-1],0) == 1) | |
646 | curr_running_disp->set_rx_CRD(i,sc_logic(1)); | |
647 | else if(curr_running_disp->calculate_disparity(ingr_decoded_data[pkt_cnt-1],0) == 0) | |
648 | curr_running_disp->set_rx_CRD(i,sc_logic(0)); | |
649 | } | |
650 | if(iter4->second == STP || iter4->second == SDP) | |
651 | { | |
652 | if(i % 4 != 0 && init_done_rx.read()) | |
653 | { | |
654 | LOG_WARNING << "WARNING : _PL_INGR_ : Framing Error (Lane= " << i << "). STP/SDP should come on modulo 4 lanes"; | |
655 | rcv_error = RE_FRA; | |
656 | } | |
657 | if(last_frame_idle && i != 0 && init_done_rx.read()) | |
658 | { | |
659 | LOG_WARNING << "WARNING : _PL_INGR_ : Framing Error (Lane= " << i << "). STP/SDP must be in lane 0 after Logical Idle"; | |
660 | rcv_error = RE_FRA; | |
661 | } | |
662 | if(!stp_sdp_ended && init_done_rx.read()) | |
663 | { | |
664 | LOG_WARNING << "WARNING : _PL_INGR : Framing Error (Lane= " << i << "). STP/SDP without previous END/EDB"; | |
665 | rcv_error = RE_FRA; | |
666 | } | |
667 | stp_sdp_ended = false; | |
668 | } | |
669 | else if(iter4->second == SKP) | |
670 | { | |
671 | LOG_DEBUG << "DEBUG : _PL_INGR_ : SKP Character received (Lane= " << i << ")"; | |
672 | } | |
673 | /// Check for END/EDB framing error | |
674 | else if(iter4->second == END || iter4->second == EDB) | |
675 | { | |
676 | if(((i+1) % 4) != 0 && init_done_rx.read()) | |
677 | { | |
678 | LOG_WARNING << "WARNING : _PL_INGR_ : Framing Error (Lane= " << i << "). END/EDB should come in modulo 4 - 1 lanes"; | |
679 | rcv_error = RE_FRA; | |
680 | } | |
681 | ||
682 | if(i != LINK_WIDTH - 1) /// Make sure the next packet is a PAD/STP/SDP | |
683 | { | |
684 | if(ingr_lane_data[i+1].range(0,9) != 0x97 && ingr_lane_data[i+1].range(0,9) != 0x368 && ingr_lane_data[i+1].range(0,9) != 0x30a && ingr_lane_data[i+1].range(0,9) != 0xf5 && ingr_lane_data[i+1].range(0,9) != 0x3a8 && ingr_lane_data[i+1].range(0,9) != 0x57 && init_done_rx.read()) | |
685 | { | |
686 | LOG_WARNING << "WARNING : _PL_INGR_ : Framing Error (Lane= " << i << "). END/EDB must be followed by PAD/STP/SDP"; | |
687 | rcv_error = RE_FRA; | |
688 | } | |
689 | } | |
690 | if(stp_sdp_ended && init_done_rx.read()) | |
691 | { | |
692 | LOG_WARNING << "WARNING : _PL_INGR_ : Framing Error (Lane= " << i << "). END/EDB without previous STP/SDP"; | |
693 | rcv_error = RE_FRA; | |
694 | } | |
695 | stp_sdp_ended = true; | |
696 | } | |
697 | else if(iter4->second == COM && !stp_sdp_ended && init_done_rx.read()) | |
698 | { | |
699 | LOG_WARNING << "WARNING : _PL_INGR_ : Framing Error (Lane= " << i << "). Unexpected COM. Unterminated STP/SDP"; | |
700 | rcv_error = RE_FRA; | |
701 | } | |
702 | ingr_xtracted_byte_c[pkt_cnt-1] = true; | |
703 | } | |
704 | else if(iter1 != map_table->data_decode_map.end()) | |
705 | { | |
706 | ingr_xtracted_byte[pkt_cnt-1] = iter1->second; | |
707 | ingr_xtracted_byte_c[pkt_cnt-1] = false; | |
708 | if(!curr_running_disp->get_rx_CRD(i).to_bool() && curr_running_disp->calculate_disparity(ingr_decoded_data[pkt_cnt-1],0) != 2 && init_done_rx.read()) | |
709 | { | |
710 | LOG_WARNING << "WARNING : _PL_INGR_ : Positive running Disparity Error in lane " << i; | |
711 | rcv_error = RE_PRD; | |
712 | } | |
713 | else if(init_done_rx.read()) | |
714 | { | |
715 | if(curr_running_disp->calculate_disparity(ingr_decoded_data[pkt_cnt-1],0) == 1) | |
716 | curr_running_disp->set_rx_CRD(i,sc_logic(1)); | |
717 | else if(curr_running_disp->calculate_disparity(ingr_decoded_data[pkt_cnt-1],0) == 0) | |
718 | curr_running_disp->set_rx_CRD(i,sc_logic(0)); | |
719 | } | |
720 | } | |
721 | else if(iter2 != map_table->neg_data_decode_map.end()) | |
722 | { | |
723 | ingr_xtracted_byte[pkt_cnt-1] = iter2->second; | |
724 | ingr_xtracted_byte_c[pkt_cnt-1] = false; | |
725 | if(curr_running_disp->get_rx_CRD(i).to_bool() && curr_running_disp->calculate_disparity(ingr_decoded_data[pkt_cnt-1],0) != 2 && init_done_rx.read()) | |
726 | { | |
727 | LOG_WARNING << "WARNING : _PL_INGR_ : Negative running Disparity Error in lane " << i; | |
728 | rcv_error = RE_NRD; | |
729 | } | |
730 | else if(init_done_rx.read()) | |
731 | { | |
732 | if(curr_running_disp->calculate_disparity(ingr_decoded_data[pkt_cnt-1],0) == 1) | |
733 | curr_running_disp->set_rx_CRD(i,sc_logic(1)); | |
734 | else if(curr_running_disp->calculate_disparity(ingr_decoded_data[pkt_cnt-1],0) == 0) | |
735 | curr_running_disp->set_rx_CRD(i,sc_logic(0)); | |
736 | } | |
737 | } | |
738 | else if(!first_time_after_L0 && init_done_rx.read()) | |
739 | { | |
740 | ingr_xtracted_byte[pkt_cnt-1] = "xxxxxxxx"; | |
741 | ingr_xtracted_byte_c[pkt_cnt-1] = false; | |
742 | LOG_WARNING << "WARNING : _PL_INGR_ : 8b/10b Decode Error (Lane= " << i << ")"; | |
743 | rcv_error = RE_8b10b; | |
744 | } | |
745 | ||
746 | if(ingr_xtracted_byte_c[pkt_cnt - 1] && ingr_xtracted_byte[pkt_cnt - 1] == K28_5) /// COM Reset | |
747 | { | |
748 | reset_lfsr_counter++; | |
749 | } | |
750 | if(ingr_xtracted_byte_c[pkt_cnt-1] && (ingr_xtracted_byte[pkt_cnt - 1] == SKP) && com_detected) /// This is a SKP ordered set | |
751 | { | |
752 | skp_ordered_set = true; | |
753 | LOG_DEBUG << "DEBUG : _PL_INGR_ : SKP Ordered Set Received (Lane= " << i << ")"; | |
754 | } | |
755 | else | |
756 | { | |
757 | skp_ordered_set = false; | |
758 | } | |
759 | /// Dont forward the LFSR | |
760 | /// Also the LFSR should not be forwarded for the entire SKP ordered set | |
761 | if(ingr_xtracted_byte_c[pkt_cnt-1] && (ingr_xtracted_byte[pkt_cnt-1] == PAD) && (end_detected == 1)) /// Dont send PAD after END/EDB to DLL | |
762 | { | |
763 | num_pad++; | |
764 | } | |
765 | if(!ingr_xtracted_byte_c[pkt_cnt-1]) | |
766 | { | |
767 | word_val = ingr_xtracted_byte[pkt_cnt-1].get_word(0); | |
768 | ingr_xtracted_byte[pkt_cnt-1] = descrambler_i->scramble_descramble(word_val,0,0,i); | |
769 | if(ingr_xtracted_byte[pkt_cnt-1] == 0x00) | |
770 | idl_count++; | |
771 | descrambler_i->set_lfsr(descramble_lfsr[i],i); | |
772 | } | |
773 | } | |
774 | if(reset_lfsr_counter == LINK_WIDTH) | |
775 | reset_lfsr = true; | |
776 | else | |
777 | reset_lfsr = false; | |
778 | reset_lfsr_counter = 0; | |
779 | ||
780 | if(idl_count == 8) /// An IDLE Frame | |
781 | { | |
782 | last_frame_idle = 1; | |
783 | idl_count = 0; | |
784 | } | |
785 | else | |
786 | { | |
787 | last_frame_idle = 0; | |
788 | } | |
789 | if(reset_lfsr) | |
790 | { | |
791 | descrambler_i->scramble_descramble_all(K28_5,0,1); | |
792 | reset_lfsr = false; | |
793 | com_detected = true; /// Could be the start of an ordered set | |
794 | } | |
795 | else if(skp_ordered_set) | |
796 | descrambler_i->scramble_descramble_all(SKP,0,1); | |
797 | else if(!first_time_after_L0) /// Dont forward the LFSR immediatly after coming out of the LTSSM control | |
798 | { | |
799 | com_detected = false; | |
800 | for(int lane_num = 0; lane_num < LINK_WIDTH; lane_num++){ | |
801 | word_val = ingr_xtracted_byte[(pkt_cnt-1)-(LINK_WIDTH-1-lane_num)].get_word(0); | |
802 | if(ingr_xtracted_byte_c[(pkt_cnt-1)-(LINK_WIDTH-1-lane_num)]) | |
803 | descrambler_i->scramble_descramble(word_val,0,1,lane_num); | |
804 | else | |
805 | descrambler_i->scramble_descramble(word_val,0,0,lane_num); | |
806 | } | |
807 | } | |
808 | ||
809 | if(first_time_after_L0) first_time_after_L0 = false; | |
810 | ||
811 | for(int lane_scram = 0; lane_scram < LINK_WIDTH; lane_scram++) | |
812 | descrambler_i->start_scramble_reg[lane_scram] = false; | |
813 | /// pkt_cnt is always a multiple of LINK_WIDTH | |
814 | /// the END might be encountered at a boundary of LINK_WIDTH or somewhere in between | |
815 | /// Lets check for that | |
816 | } | |
817 | else | |
818 | { | |
819 | ingr_cnt = 0; | |
820 | pkt_cnt = 0; | |
821 | num_pad = 0; | |
822 | first_time_after_L0 = true; | |
823 | rcv_error = RE_NONE; | |
824 | stp_sdp_ended = true; | |
825 | } | |
826 | /// Checks for LINK_WIDTH byte DLLP or IDL interleaved TLP or back to back TLP | |
827 | for(i=0;i<LINK_WIDTH;i++) | |
828 | { | |
829 | if(start_ingr_packet[i]) | |
830 | { | |
831 | /// This lane has STP/SDP | |
832 | lane_with_start = i; | |
833 | } | |
834 | if(end_ingr_packet[i]) | |
835 | { | |
836 | lane_with_end = i; | |
837 | } | |
838 | } | |
839 | if(this_frame_start_detected && this_frame_end_detected) /// Test for Back to Back packets without interleaving | |
840 | { | |
841 | if(lane_with_start > lane_with_end) | |
842 | back2back_pkt = true; | |
843 | else | |
844 | back2back_pkt = false; | |
845 | ||
846 | lane_with_start = 0; | |
847 | lane_with_end = 0; | |
848 | } | |
849 | if(!start_ingr_pkt && rcv_error==RE_NONE) | |
850 | { | |
851 | pkt_cnt = 0; | |
852 | this_pkt_size = 0; | |
853 | ingr_cnt = 0; | |
854 | num_pad = 0; | |
855 | } | |
856 | ||
857 | this_frame_start_detected = false; | |
858 | this_frame_end_detected = false; | |
859 | } | |
860 | /// If it comes out of this loop, it means it received an END/EDB symbol | |
861 | /// Its fair to assume that a start must have come | |
862 | ||
863 | /// Now just form the packets | |
864 | ingress_packet = new pciePacket(this_pkt_size); | |
865 | ||
866 | for(i=0;i<this_pkt_size;i++) | |
867 | { | |
868 | ingress_packet->modify_byte(i,ingr_xtracted_byte[i]); | |
869 | } | |
870 | global_ingress_packet = ingress_packet; | |
871 | /// Notify the producer that the packet has been produced | |
872 | /// Before I reset everything to 0 I need to check for back2back | |
873 | if(back2back_pkt) | |
874 | { | |
875 | for(i=this_pkt_size,j=0;i<pkt_cnt;i++,j++) | |
876 | { | |
877 | ingr_xtracted_byte[j] = ingr_xtracted_byte[i]; /// Prepare for the next packet | |
878 | ingr_xtracted_byte_c[j] = ingr_xtracted_byte_c[i]; | |
879 | } | |
880 | start_ingr_pkt = true; | |
881 | pkt_cnt = j; | |
882 | end_detected = 0; | |
883 | num_pad = 0; | |
884 | ingr_cnt = 0; | |
885 | } | |
886 | else | |
887 | { | |
888 | pkt_cnt = 0; | |
889 | end_detected = 0; | |
890 | start_ingr_pkt = false; | |
891 | num_pad = 0; | |
892 | ingr_cnt = 0; | |
893 | } | |
894 | back2back_pkt = false; | |
895 | ||
896 | /// The Producer code now begins | |
897 | send_packet = global_ingress_packet; | |
898 | ||
899 | if(send_packet->get_size() != 0) | |
900 | { | |
901 | switch(rcv_error){ | |
902 | case RE_NONE: | |
903 | send_packet->set_control(DLLP_ACK); | |
904 | break; | |
905 | case RE_FRA: | |
906 | send_packet->set_control(DLLP_NAK_FRAMING); | |
907 | break; | |
908 | case RE_8b10b: | |
909 | case RE_PRD: | |
910 | case RE_NRD: | |
911 | send_packet->set_control(DLLP_NAK); | |
912 | break; | |
913 | ||
914 | } | |
915 | pl_dll_out.send_packet(send_packet); | |
916 | } | |
917 | LOG_DEBUG << "PL_TOP: Resetting rcv_error to RE_NONE"; | |
918 | rcv_error=RE_NONE; | |
919 | } | |
920 | } |