Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: ilu_intf.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 "ilu_intf.hpp" | |
36 | #include "pcie_common/logger.hpp" | |
37 | ||
38 | namespace pcie { | |
39 | ||
40 | /** | |
41 | * Binary to gray code helper function | |
42 | */ | |
43 | sc_uint<32> bin2gc (sc_uint<32> binval) { | |
44 | sc_uint<32> gcval = 0; | |
45 | sc_uint<1> bit_zero = 0; | |
46 | ||
47 | gcval = binval ^ (bit_zero, binval(32-1, 1)); | |
48 | return gcval; | |
49 | } | |
50 | ||
51 | /** | |
52 | * Gray code to binary helper function | |
53 | */ | |
54 | sc_uint<32> gc2bin (sc_uint<32> gcval) { | |
55 | sc_uint<32> binval = 0; | |
56 | int i; | |
57 | ||
58 | binval[32-1] = gcval[32-1]; | |
59 | for (i = (32 - 2); i >= 0; --i) | |
60 | binval[i] = binval[i+1] ^ gcval[i]; | |
61 | return binval; | |
62 | } | |
63 | ||
64 | /** | |
65 | * Parity calculator | |
66 | */ | |
67 | int parity (sc_uint<32> data) { | |
68 | sc_uint<1> par =0; | |
69 | ||
70 | par = 1; | |
71 | for (int i = 0; i < 32; i++) { | |
72 | par ^= (data & 1); | |
73 | data >>= 1; | |
74 | } | |
75 | return par; | |
76 | } | |
77 | ||
78 | /** | |
79 | * This thread collects outgoing Hdr from the ILU and loads it into the EHB. | |
80 | */ | |
81 | void ilu_intf::ehb_write(void) { | |
82 | bool ehb_we = false; | |
83 | sc_uint<D2P_EHB_ADDR_WDTH> ehb_addr; | |
84 | ||
85 | while (1) { | |
86 | wait(clk.negedge_event()); | |
87 | ehb_we = d2p_ehb_we.read(); | |
88 | ehb_addr = d2p_ehb_addr.read().to_uint(); | |
89 | ||
90 | if (ehb_we) { | |
91 | ehb_buffer[ehb_addr](127,0) = d2p_ehb_data.read(); | |
92 | ehb_buffer[ehb_addr](131,128) = d2p_ehb_dpar.read(); | |
93 | ||
94 | LOG_DEBUG << "EHB Write @ " << ehb_addr | |
95 | << " DATA: " << (string) d2p_ehb_data.read().to_string(); | |
96 | } | |
97 | } | |
98 | } | |
99 | ||
100 | /** | |
101 | * This thread collects outgoing data from the ILU and loads it into the EDB. | |
102 | */ | |
103 | void ilu_intf::edb_write(void) { | |
104 | bool edb_we; | |
105 | sc_uint<D2P_EDB_ADDR_WDTH> edb_addr; | |
106 | ||
107 | while (1) { | |
108 | wait(clk.negedge_event()); | |
109 | edb_we = d2p_edb_we.read(); | |
110 | edb_addr = d2p_edb_addr.read().to_uint(); | |
111 | ||
112 | if (edb_we) { | |
113 | edb_buffer[edb_addr](127,0) = d2p_edb_data.read(); | |
114 | edb_buffer[edb_addr](131,128) = d2p_edb_dpar.read(); | |
115 | LOG_DEBUG << "EDB Write @ " << edb_addr; | |
116 | ||
117 | if (edb_addr < 0x80) | |
118 | ecd_waddr += 1; | |
119 | else | |
120 | erd_waddr += 1; | |
121 | } | |
122 | } | |
123 | } | |
124 | ||
125 | /** | |
126 | * This thread provides IHB content to the ILU. | |
127 | */ | |
128 | void ilu_intf::ihb_read(void) { | |
129 | bool ihb_rd; | |
130 | sc_uint<D2P_IHB_ADDR_WDTH> ihb_addr; | |
131 | ||
132 | while (1) { | |
133 | wait (clk.negedge_event()); | |
134 | ihb_addr = d2p_ihb_addr.read().to_uint(); | |
135 | ihb_rd = d2p_ihb_rd.read(); | |
136 | ||
137 | if (ihb_rd) { | |
138 | wait (clk.posedge_event()); | |
139 | if ( (bin2gc(ihb_addr) != ihb_wptr) && (!ihb_empty) ) { | |
140 | p2d_ihb_dpar.write ( ihb_buffer[ihb_addr] | |
141 | (P2D_IHB_DATA_WDTH+P2D_IHB_DPAR_WDTH-1, | |
142 | P2D_IHB_DATA_WDTH) | |
143 | ); | |
144 | p2d_ihb_data.write(ihb_buffer[ihb_addr](P2D_IHB_DATA_WDTH-1, 0)); | |
145 | LOG_DEBUG << "IHB Read @ " << ihb_addr; | |
146 | } else { | |
147 | ihb_empty = true; | |
148 | LOG_DEBUG << "Reading empty IHB @ " << ihb_addr; | |
149 | } | |
150 | } | |
151 | }// while(1) | |
152 | }//end ihb_read() | |
153 | ||
154 | /** | |
155 | * This thread provides IDB content to the ILU. | |
156 | */ | |
157 | void ilu_intf::idb_read(void) { | |
158 | bool idb_rd; | |
159 | sc_uint<D2P_IDB_ADDR_WDTH> idb_addr; | |
160 | ||
161 | while (1) { | |
162 | wait (clk.negedge_event()); | |
163 | idb_addr = d2p_idb_addr.read().to_uint(); | |
164 | idb_rd = d2p_idb_rd.read(); | |
165 | ||
166 | if (idb_rd) { | |
167 | wait (clk.posedge_event()); | |
168 | p2d_idb_dpar.write ( idb_buffer[idb_addr] | |
169 | (P2D_IDB_DATA_WDTH+P2D_IDB_DPAR_WDTH-1, | |
170 | P2D_IDB_DATA_WDTH) ); | |
171 | p2d_idb_data.write(idb_buffer[idb_addr](P2D_IDB_DATA_WDTH-1, 0)); | |
172 | //LOG_DEBUG << "IDB Read @ " << idb_addr; | |
173 | } | |
174 | }// while(1) | |
175 | } | |
176 | ||
177 | /** | |
178 | * This thread receives ingress TLPs from the lower layers (i.e. ITL), and loads | |
179 | * it into the IHB and IDB. | |
180 | */ | |
181 | void ilu_intf::ingress_packet_handler() { | |
182 | LOG_INFO<<"ILU_INTF: ingress_packet_handler begins..."; | |
183 | RefPciePacket next_pkt; | |
184 | //sc_uint<D2P_IHB_ADDR_WDTH> ihb_wr_addr; | |
185 | //sc_uint<D2P_IHB_ADDR_WDTH+1> nxt_ihb_wr_addr; | |
186 | sc_uint<10> pld_len; | |
187 | sc_uint<10> idb_wr_len; | |
188 | //sc_uint<D2P_IDB_ADDR_WDTH> idb_wr_addr; | |
189 | //sc_uint<D2P_IDB_ADDR_WDTH> nxt_idb_wr_addr; | |
190 | ||
191 | //ihb_wr_addr = 0; | |
192 | //nxt_ihb_wr_addr = 0; | |
193 | try{ | |
194 | while (true) { | |
195 | in_pkt_port.get_packet(next_pkt); | |
196 | LOG_DEBUG << "Received Ingress Packet " << next_pkt->to_string(); | |
197 | //cout<< sc_time_stamp() << " ILU_INTF: Received TLP " << next_pkt->getPacketId() << " from itl." << endl; | |
198 | if(next_pkt->get_control() == DROP_TLP_ILUINTF_RECOVER_CREDITS){//indicates that the packet is to be dropped in here and credits are to be recovered | |
199 | LOG_DEBUG<<"Recvd pkt to be dropped"; | |
200 | if(next_pkt->isCmpl()){ | |
201 | LOG_DEBUG<<"Recovering CHC/CDC..."; | |
202 | recovered_credits.range(CHC) = recovered_credits.range(CHC) + 1; | |
203 | if(next_pkt->hasData()){ | |
204 | sc_uint<12> cred = (GET_TLP_LEN(next_pkt))/4; | |
205 | if((GET_TLP_LEN(next_pkt))%4 != 0) cred++; | |
206 | recovered_credits.range(CDC) = recovered_credits.range(CDC) + cred; | |
207 | } | |
208 | } | |
209 | else if(next_pkt->isPosted()){ | |
210 | LOG_DEBUG<<"Recovering PHC/PDC..."; | |
211 | recovered_credits.range(PHC) = recovered_credits.range(PHC) + 1; | |
212 | if(next_pkt->hasData()){ | |
213 | sc_uint<12> cred = (GET_TLP_LEN(next_pkt))/4; | |
214 | if((GET_TLP_LEN(next_pkt))%4 != 0) cred++; | |
215 | recovered_credits.range(PDC) = recovered_credits.range(PDC) + cred; | |
216 | } | |
217 | } | |
218 | else{ | |
219 | LOG_DEBUG<<"Recovering NHC/NDC..."; | |
220 | recovered_credits.range(NHC) = recovered_credits.range(NHC) + 1; | |
221 | if(next_pkt->hasData()){ | |
222 | sc_uint<12> cred = (GET_TLP_LEN(next_pkt))/4; | |
223 | if((GET_TLP_LEN(next_pkt))%4 != 0) cred++; | |
224 | recovered_credits.range(NDC) = recovered_credits.range(NDC) + cred; | |
225 | } | |
226 | } | |
227 | } | |
228 | else { | |
229 | ihb_empty = false; | |
230 | ihb_wr_addr = nxt_ihb_wr_addr; | |
231 | nxt_ihb_wr_addr += 1; | |
232 | if(!drain_state && !POR_RESET ){ | |
233 | int hdr_size; | |
234 | if (GET_TLP_FMT(next_pkt) & 0x01) { | |
235 | hdr_size = 16; | |
236 | } else { | |
237 | hdr_size = 12; | |
238 | } | |
239 | ||
240 | /// Load the Header into Header buffer | |
241 | for (int byte = 15, pkt_byte=0; pkt_byte < hdr_size; byte--, pkt_byte++) { | |
242 | ihb_buffer[ihb_wr_addr](byte*8+7, byte*8) = | |
243 | next_pkt->get_byte(TLP_HDR_START + pkt_byte); | |
244 | } | |
245 | ||
246 | /// Calculate Header Parity | |
247 | ihb_buffer[ihb_wr_addr][128] = parity(ihb_buffer[ihb_wr_addr](31,0).to_uint()); | |
248 | ihb_buffer[ihb_wr_addr][129] = parity(ihb_buffer[ihb_wr_addr](63,32).to_uint()); | |
249 | ihb_buffer[ihb_wr_addr][130] = parity(ihb_buffer[ihb_wr_addr](95,64).to_uint()); | |
250 | ihb_buffer[ihb_wr_addr][131] = parity(ihb_buffer[ihb_wr_addr](127,96).to_uint()); | |
251 | ||
252 | /// Polulate Data buffers, if data associated with the packet | |
253 | if ((GET_TLP_FMT(next_pkt) >> 1) && | |
254 | ((next_pkt->get_byte(TLP_HDR_START) != tlp_IORd) && | |
255 | (next_pkt->get_byte(TLP_HDR_START) != tlp_IOWr) && | |
256 | (next_pkt->get_byte(TLP_HDR_START) != tlp_MRdLk_32) && | |
257 | (next_pkt->get_byte(TLP_HDR_START) != tlp_MRdLk_64) && | |
258 | (next_pkt->get_byte(TLP_HDR_START) != tlp_CfgRd0) && | |
259 | (next_pkt->get_byte(TLP_HDR_START) != tlp_CfgRd1) && | |
260 | (next_pkt->get_byte(TLP_HDR_START) != tlp_CfgWr0) && | |
261 | (next_pkt->get_byte(TLP_HDR_START) != tlp_CfgWr1) ) | |
262 | ) { // Packet with data | |
263 | pld_len = GET_TLP_LEN(next_pkt); | |
264 | idb_wr_len = pld_len(9,2); | |
265 | LOG_DEBUG << "Payload Length: " << pld_len << " IDB Write Len: " << idb_wr_len; | |
266 | ||
267 | int pkt_byte_ctr = TLP_HDR_START+hdr_size; | |
268 | for (int idb_ctr = 0; idb_ctr < idb_wr_len; idb_ctr++) { | |
269 | idb_wr_addr = nxt_idb_wr_addr; | |
270 | nxt_idb_wr_addr += 1; | |
271 | for (int byte = 15; byte >= 0; byte--) { | |
272 | idb_buffer[idb_wr_addr](byte*8+7, byte*8) = | |
273 | next_pkt->get_byte(pkt_byte_ctr++); | |
274 | idb_buffer[idb_wr_addr][128] = | |
275 | parity(idb_buffer[idb_wr_addr](31,0).to_uint()); | |
276 | idb_buffer[idb_wr_addr][129] = | |
277 | parity(idb_buffer[idb_wr_addr](63,32).to_uint()); | |
278 | idb_buffer[idb_wr_addr][130] = | |
279 | parity(idb_buffer[idb_wr_addr](95,64).to_uint()); | |
280 | idb_buffer[idb_wr_addr][131] = | |
281 | parity(idb_buffer[idb_wr_addr](127,96).to_uint()); | |
282 | } | |
283 | } | |
284 | if (pld_len(1,0).or_reduce()) { | |
285 | idb_wr_addr = nxt_idb_wr_addr; | |
286 | nxt_idb_wr_addr += 1; | |
287 | sc_uint<32> idb_byte_cnt = pld_len(1,0) * 4; | |
288 | ||
289 | for (int byte = 15; byte > 15-(pld_len(1,0)*4); byte--) { | |
290 | idb_buffer[idb_wr_addr](byte*8+7, byte*8) = | |
291 | next_pkt->get_byte(pkt_byte_ctr++); | |
292 | ||
293 | idb_buffer[idb_wr_addr][128] = | |
294 | parity(idb_buffer[idb_wr_addr](31,0).to_uint()); | |
295 | idb_buffer[idb_wr_addr][129] = | |
296 | parity(idb_buffer[idb_wr_addr](63,32).to_uint()); | |
297 | idb_buffer[idb_wr_addr][130] = | |
298 | parity(idb_buffer[idb_wr_addr](95,64).to_uint()); | |
299 | idb_buffer[idb_wr_addr][131] = | |
300 | parity(idb_buffer[idb_wr_addr](127,96).to_uint()); | |
301 | } | |
302 | } | |
303 | } // If Payload | |
304 | WAIT(clk.posedge_event()); | |
305 | p2d_ihb_wptr.write(bin2gc(nxt_ihb_wr_addr)); | |
306 | ihb_wptr = bin2gc(nxt_ihb_wr_addr); | |
307 | }//end if(!drain_state) | |
308 | else WAIT(clk.posedge_event()); | |
309 | } | |
310 | } //end while(1) | |
311 | }//end try | |
312 | catch(sc_exception &e){ | |
313 | LOG_WARNING<<"ILU_INTF: Out of ingress_packet_handler"; | |
314 | } | |
315 | } // ingress_packet_handler() | |
316 | ||
317 | ||
318 | /** | |
319 | * This thread build TLPs out of requests in the EHB and fwds them to the DLL. | |
320 | * Parity errors are also checked for. If detected, Drain State is entered. | |
321 | */ | |
322 | void ilu_intf::egress_packet_handler() { | |
323 | /** EHB Interface Signals | |
324 | d2p_ehb_clk | |
325 | d2p_ehb_we | |
326 | d2p_ehb_addr | |
327 | d2p_ehb_data & dpar | |
328 | ||
329 | d2p_ech_wptr | |
330 | d2p_erh_wptr | |
331 | ||
332 | p2d_ech_rptr | |
333 | p2d_erh_rptr | |
334 | ||
335 | p2d_ecd_rptr | |
336 | p2d_erd_rptr | |
337 | */ | |
338 | LOG_INFO<<"ILU_INTF: egress_packet_handler begins..."; | |
339 | sc_uint<P2D_EHB_ADDR_WDTH> erh_addr; | |
340 | sc_uint<P2D_ERH_RPTR_WDTH> erh_rptr; | |
341 | sc_uint<P2D_ERH_RPTR_WDTH> nxt_erh_rptr; | |
342 | sc_uint<P2D_EHB_ADDR_WDTH> ech_addr; | |
343 | sc_uint<P2D_ECH_RPTR_WDTH> ech_rptr; | |
344 | sc_uint<P2D_ERH_RPTR_WDTH> nxt_ech_rptr; | |
345 | sc_uint<P2D_EHB_ADDR_WDTH> ehb_addr; | |
346 | ||
347 | sc_uint<D2P_EDB_ADDR_WDTH-1> erd_rd_addr; | |
348 | sc_uint<D2P_EDB_ADDR_WDTH-1> ecd_rd_addr; | |
349 | sc_uint<D2P_EDB_ADDR_WDTH> edb_rd_addr; | |
350 | ||
351 | sc_biguint<D2P_EHB_DATA_WDTH> ehb_data; | |
352 | sc_uint<D2P_EHB_DPAR_WDTH> ehb_dpar; | |
353 | sc_biguint<D2P_EDB_DATA_WDTH> edb_data; | |
354 | sc_uint<D2P_EDB_DPAR_WDTH> edb_dpar; | |
355 | ||
356 | bool req_arb = true; | |
357 | RefPciePacket nxt_pkt; | |
358 | bool par_error = false; | |
359 | sc_uint<PCIE_PLD_LEN_WDTH> pld_len; | |
360 | sc_uint<PCIE_PLD_LEN_WDTH-1> edb_rd_len; | |
361 | ||
362 | erh_addr = 0x00; | |
363 | ech_addr = 0x00; | |
364 | erd_rd_addr = 0x00; | |
365 | ecd_rd_addr = 0x00; | |
366 | ihb_wptr = 0x00; | |
367 | ||
368 | pld_len = 0; | |
369 | edb_rd_len = 0; | |
370 | ||
371 | erh_rptr = bin2gc(erh_addr); | |
372 | nxt_erh_rptr = bin2gc(erh_addr); | |
373 | ech_rptr = bin2gc(ech_addr); | |
374 | ||
375 | try{ | |
376 | while (true) { | |
377 | WAIT(clk.negedge_event()); | |
378 | if(!drain_state && !POR_RESET){ | |
379 | if (req_arb) { | |
380 | req_arb = false; | |
381 | nxt_erh_rptr = d2p_erh_wptr.read(); | |
382 | /// Check if the req empty | |
383 | if (erh_rptr != nxt_erh_rptr) { | |
384 | ehb_addr = erh_addr | 0x20; | |
385 | p2d_erh_rptr.write(erh_rptr); | |
386 | LOG_DEBUG << " Processing Egress Request Header \n" | |
387 | << " ERH_ADDR : " << erh_addr | |
388 | << " ERH_RPTR : " << erh_rptr | |
389 | << " EHB_ADDR : " << ehb_addr << "\n" | |
390 | << "Next: ERH Addr: " << erh_addr+1 | |
391 | << " ERH Rptr: " << bin2gc(erh_addr+1); | |
392 | /// Read erh | |
393 | (ehb_dpar, ehb_data) = ehb_buffer[ehb_addr]; | |
394 | ||
395 | /// Verify parity | |
396 | for (int dword = 0; dword < 4; dword++) { | |
397 | sc_uint<32> dw_data = (sc_uint<32>) ehb_data(31+(dword * 32), dword * 32); | |
398 | LOG_DEBUG << "dw_data: " << dw_data << " datapar: " << ehb_dpar[dword] << " calcpar: " <<parity(dw_data); | |
399 | if (ehb_dpar[dword] != parity(dw_data)) { | |
400 | LOG_ERROR << "Parity Error detected on DMU Request Header\n" | |
401 | << "Data: " << (string) dw_data.to_string() | |
402 | << " Parity: " << (int) parity(dw_data); | |
403 | par_error = true; | |
404 | } | |
405 | } | |
406 | if(par_error){ | |
407 | write_error_csr(OE,12,44,"ehp"); | |
408 | drain_req_ev.notify(); | |
409 | } | |
410 | if(!par_error){ | |
411 | /// Build TLP | |
412 | int hdr_size = (ehb_data[125] & 0x1) ? 16 : 12; | |
413 | nxt_pkt = NEW_TLP(hdr_size); | |
414 | nxt_pkt->modify_byte(0, STP); | |
415 | LOG_DEBUG << " TLP Hdr Size " << hdr_size; | |
416 | for (int byte = 15, pkt_byte = 0; | |
417 | pkt_byte < hdr_size; | |
418 | byte--, pkt_byte++) { | |
419 | sc_uint<8> data_byte; | |
420 | data_byte = ehb_data((byte*8)+7, (byte*8)); | |
421 | nxt_pkt->modify_byte( TLP_HDR_START+pkt_byte, | |
422 | data_byte); | |
423 | } | |
424 | ||
425 | /// Check for the Data: | |
426 | if ((GET_TLP_FMT(nxt_pkt) >> 1)) { | |
427 | pld_len = GET_TLP_LEN(nxt_pkt); | |
428 | edb_rd_len = pld_len(9,2); | |
429 | int pkt_byte_ctr = TLP_HDR_START+hdr_size; | |
430 | LOG_DEBUG << "Egress Request : Payload Length: " << pld_len | |
431 | << " EDB Read Len: " << edb_rd_len; | |
432 | ||
433 | nxt_pkt->alloc_bytes(edb_rd_len * 16 + (pld_len(1,0)*4)); | |
434 | /// Read Req Data | |
435 | for (int edb_ctr = 0; edb_ctr < edb_rd_len; edb_ctr++) { | |
436 | while (erd_rd_addr == erd_waddr) { | |
437 | WAIT(clk.negedge_event()); | |
438 | } | |
439 | ||
440 | edb_rd_addr = (1,erd_rd_addr); | |
441 | erd_rd_addr += 1; | |
442 | p2d_erd_rptr.write(bin2gc(edb_rd_addr)); | |
443 | LOG_DEBUG << "TL: EDB Read Addr: " << edb_rd_addr | |
444 | << " ERD Rd Ptr: " << bin2gc(edb_rd_addr); | |
445 | (edb_dpar, edb_data) = edb_buffer[edb_rd_addr]; | |
446 | ||
447 | /// Verify Data Parity | |
448 | for (int dword = 0; dword < 4; dword++) { | |
449 | sc_uint<32> dw_data = (sc_uint<32>) edb_data(31+(dword * 32), dword * 32); | |
450 | LOG_DEBUG << "EBD: dw_data: " << dw_data << " datapar: " << edb_dpar[dword] << " calcpar: " <<parity(dw_data); | |
451 | if (edb_dpar[dword] != parity(dw_data) && GET_TLP_EP(nxt_pkt)!=1) { | |
452 | LOG_ERROR << "Parity Error detected on DMU Request Data\n"; | |
453 | par_error = true; | |
454 | } | |
455 | } | |
456 | if(par_error){ | |
457 | write_error_csr(OE,13,45,"edp"); | |
458 | } | |
459 | /// Load ERD Data to Packet | |
460 | for (int byte = 15; byte >= 0; byte--) { | |
461 | sc_uint<8> data_byte; | |
462 | data_byte = (sc_uint<8>) edb_data((byte*8)+7, (byte*8)); | |
463 | nxt_pkt->modify_byte( pkt_byte_ctr++, data_byte); | |
464 | } | |
465 | } // Read ERD Data | |
466 | if (pld_len(1,0).or_reduce()) { | |
467 | while (erd_rd_addr == erd_waddr) { | |
468 | WAIT(clk.negedge_event()); | |
469 | } | |
470 | edb_rd_addr = (1,erd_rd_addr); | |
471 | erd_rd_addr += 1; | |
472 | p2d_erd_rptr.write(bin2gc(edb_rd_addr)); | |
473 | LOG_DEBUG << "TL: EDB Read Addr: " << edb_rd_addr | |
474 | << " ERD Rd Ptr: " << bin2gc(edb_rd_addr); | |
475 | (edb_dpar, edb_data) = edb_buffer[edb_rd_addr]; | |
476 | ||
477 | /// Verify Data Parity | |
478 | for (int dword = 0; dword < 4; dword++) { | |
479 | sc_uint<32> dw_data = (sc_uint<32>) edb_data(31+(dword * 32), dword * 32); | |
480 | LOG_DEBUG << "EBD: dw_data: " << dw_data << " datapar: " << edb_dpar[dword] << " calcpar: " <<parity(dw_data); | |
481 | if (edb_dpar[dword] != parity(dw_data) && GET_TLP_EP(nxt_pkt)!=1) { | |
482 | LOG_ERROR << "Parity Error detected on DMU Request Data\n"; | |
483 | par_error = true; | |
484 | } | |
485 | } | |
486 | if(par_error){ | |
487 | write_error_csr(OE,13,45,"edp"); | |
488 | } | |
489 | ||
490 | for (int byte = 15; byte >= 15-(pld_len(1,0)*4); byte--) { | |
491 | sc_uint<8> data_byte; | |
492 | data_byte = (sc_uint<8>) edb_data((byte*8)+7, (byte*8)); | |
493 | nxt_pkt->modify_byte( pkt_byte_ctr++, data_byte); | |
494 | } | |
495 | } | |
496 | } // If Packet contains Data | |
497 | if(!par_error){ | |
498 | par_error=false; | |
499 | nxt_pkt->set_control(0x2); | |
500 | LOG_DEBUG << "Sending Request Packet to DLL" << nxt_pkt->to_string(); | |
501 | //cout << sc_time_stamp() << "\t\t\t\t\t| ILU_INTF: Sending Req TLP " << nxt_pkt->getPacketId() << " to ETL." << endl; | |
502 | req_pkt_port.send_packet(nxt_pkt); | |
503 | } | |
504 | else{ | |
505 | nxt_pkt->set_control(0x12); | |
506 | LOG_DEBUG << "Sending Request Packet to DLL" << nxt_pkt->to_string(); | |
507 | //cout << sc_time_stamp() << "\t\t\t\t\t| ILU_INTF: Sending Req TLP " << nxt_pkt->getPacketId() << " to ETL." << endl; | |
508 | req_pkt_port.send_packet(nxt_pkt); | |
509 | drain_req_ev.notify(); | |
510 | } | |
511 | ||
512 | }//end if(!par_error) | |
513 | erh_addr += 1; | |
514 | erh_rptr = bin2gc(erh_addr); | |
515 | } // If Req Hdr not empty | |
516 | } else { // Completion arb | |
517 | req_arb = true; | |
518 | nxt_ech_rptr = d2p_ech_wptr.read(); | |
519 | /// Check if the req empty | |
520 | if (ech_rptr != nxt_ech_rptr) { | |
521 | ehb_addr = ech_addr & 0x1F; | |
522 | p2d_ech_rptr.write(ech_rptr); | |
523 | ||
524 | LOG_DEBUG << " Processing Completion Header " | |
525 | << " ECH_ADDR : " << ech_addr | |
526 | << " ECH_RPTR : " << ech_rptr | |
527 | << " EHB_ADDR : " << ehb_addr << "\n" | |
528 | << "Next: ERH Addr: " << ech_addr+1 | |
529 | << " ERH Rptr: " << bin2gc(ech_addr+1); | |
530 | /// Read erh | |
531 | (ehb_dpar, ehb_data) = ehb_buffer[ehb_addr]; | |
532 | /// Verify parity | |
533 | for (int dword = 0; dword < 4; dword++) { | |
534 | sc_uint<32> dw_data = (sc_uint<32>) ehb_data(31+(dword * 32), dword * 32); | |
535 | if (ehb_dpar[dword] != parity(dw_data)) { | |
536 | LOG_ERROR << "Parity Error detected on DMU Completion Header\n" | |
537 | << "Data: " << (string) dw_data.to_string() | |
538 | << " Parity: " << (int) parity(dw_data); | |
539 | par_error = true; | |
540 | } | |
541 | } | |
542 | if(par_error){ | |
543 | write_error_csr(OE,12,44,"ehp"); | |
544 | drain_req_ev.notify(); | |
545 | } | |
546 | if(!par_error){ | |
547 | /// Build TLP | |
548 | int hdr_size = (ehb_data[125] & 0x1) ? 16 : 12; | |
549 | nxt_pkt = NEW_TLP(hdr_size); | |
550 | nxt_pkt->modify_byte(0, STP); | |
551 | LOG_DEBUG << " TLP Hdr Size " << hdr_size; | |
552 | for (int byte = 15, pkt_byte = 0; | |
553 | pkt_byte < hdr_size; | |
554 | byte--, pkt_byte++) { | |
555 | sc_uint<8> data_byte; | |
556 | data_byte = ehb_data((byte*8)+7, (byte*8)); | |
557 | nxt_pkt->modify_byte( TLP_HDR_START+pkt_byte, data_byte); | |
558 | } | |
559 | ||
560 | /// Check for the Data: | |
561 | if ((GET_TLP_FMT(nxt_pkt) >> 1)) { | |
562 | pld_len = GET_TLP_LEN(nxt_pkt); | |
563 | edb_rd_len = pld_len(9,2); | |
564 | int pkt_byte_ctr = TLP_HDR_START+hdr_size; | |
565 | LOG_DEBUG << "Egress Completion Packet : Payload Length: " << pld_len | |
566 | << "EDB Read Len: " << edb_rd_len; | |
567 | ||
568 | nxt_pkt->alloc_bytes(edb_rd_len * 16 + (pld_len(1,0)*4)); | |
569 | /// Read Req Data | |
570 | for (int edb_ctr = 0; edb_ctr < edb_rd_len; edb_ctr++) { | |
571 | while (ecd_rd_addr == ecd_waddr) { | |
572 | WAIT(clk.negedge_event()); | |
573 | } | |
574 | ||
575 | edb_rd_addr = (0,ecd_rd_addr); | |
576 | ecd_rd_addr += 1; | |
577 | p2d_ecd_rptr.write(bin2gc(edb_rd_addr)); | |
578 | LOG_DEBUG << "TL: EDB Read Addr: " << edb_rd_addr | |
579 | << " ECD Rd Ptr: " << bin2gc(edb_rd_addr); | |
580 | ||
581 | (edb_dpar, edb_data) = edb_buffer[edb_rd_addr]; | |
582 | ||
583 | /// Verify Data Parity | |
584 | for (int dword = 0; dword < 4; dword++) { | |
585 | sc_uint<32> dw_data = (sc_uint<32>) edb_data(31+(dword * 32), dword * 32); | |
586 | if (edb_dpar[dword] != parity(dw_data) && GET_TLP_EP(nxt_pkt)!=1) { | |
587 | LOG_ERROR << "Parity Error detected on DMU Request Data\n"; | |
588 | par_error = true; | |
589 | } | |
590 | } | |
591 | if(par_error){ | |
592 | write_error_csr(OE,13,45,"edp"); | |
593 | } | |
594 | /// Load ECD Data to Packet | |
595 | for (int byte = 15; byte >= 0; byte--) { | |
596 | sc_uint<8> data_byte; | |
597 | data_byte = (sc_uint<8>) edb_data((byte*8)+7, (byte*8)); | |
598 | nxt_pkt->modify_byte( pkt_byte_ctr++, data_byte); | |
599 | ||
600 | } // Load ECD Data | |
601 | } // Read ECD Data | |
602 | if (pld_len(1,0).or_reduce()) { | |
603 | while (ecd_rd_addr == ecd_waddr) { | |
604 | WAIT(clk.negedge_event()); | |
605 | } | |
606 | ||
607 | edb_rd_addr = (0,ecd_rd_addr); | |
608 | ecd_rd_addr += 1; | |
609 | p2d_ecd_rptr.write(bin2gc(edb_rd_addr)); | |
610 | ||
611 | LOG_DEBUG << "TL: EDB Read Addr: " << edb_rd_addr | |
612 | << " ECD Rd Ptr: " << bin2gc(edb_rd_addr); | |
613 | (edb_dpar, edb_data) = edb_buffer[edb_rd_addr]; | |
614 | ||
615 | /// Verify Data Parity | |
616 | for (int dword = 0; dword < 4; dword++) { | |
617 | sc_uint<32> dw_data = (sc_uint<32>) edb_data(31+(dword * 32), dword * 32); | |
618 | if (edb_dpar[dword] != parity(dw_data) && GET_TLP_EP(nxt_pkt)!=1) { | |
619 | LOG_ERROR << "Parity Error detected on DMU Request Data\n"; | |
620 | par_error = true; | |
621 | } | |
622 | } | |
623 | if(par_error){ | |
624 | write_error_csr(OE,13,45,"edp"); | |
625 | } | |
626 | ||
627 | for (int byte = 15; byte >= 15-(pld_len(1,0)*4); byte--) { | |
628 | sc_uint<8> data_byte; | |
629 | data_byte = (sc_uint<8>) edb_data((byte*8)+7, (byte*8)); | |
630 | nxt_pkt->modify_byte( pkt_byte_ctr++, data_byte); | |
631 | } | |
632 | } | |
633 | } // If Packet contains Data | |
634 | if(!par_error){ | |
635 | par_error=false; | |
636 | nxt_pkt->set_control(0x2); | |
637 | LOG_DEBUG << "Sending Completion Packet to DLL" << nxt_pkt->to_string(); | |
638 | //cout<< sc_time_stamp() << "\t\t\t\t\t| ILU_INTF: Sending Cpl TLP " << nxt_pkt->getPacketId() << " to ETL." << endl; | |
639 | cmpl_pkt_port.send_packet(nxt_pkt); | |
640 | } | |
641 | else{ | |
642 | nxt_pkt->set_control(0x12); | |
643 | LOG_DEBUG << "Sending Completion Packet to DLL" << nxt_pkt->to_string(); | |
644 | //cout<< sc_time_stamp() << "\t\t\t\t\t| ILU_INTF: Sending Cpl TLP " << nxt_pkt->getPacketId() << " to ETL." << endl; | |
645 | cmpl_pkt_port.send_packet(nxt_pkt); | |
646 | drain_req_ev.notify(); | |
647 | } | |
648 | }//end if(!parr_error) | |
649 | ech_addr += 1; | |
650 | ech_rptr = bin2gc(ech_addr); | |
651 | } // If Req Hdr not empty | |
652 | } | |
653 | par_error=false; | |
654 | } | |
655 | } // while (true) | |
656 | } | |
657 | catch(sc_exception &e){ | |
658 | LOG_WARNING<<"ILU_INTF: Out of egress_packet_handler"; | |
659 | } | |
660 | } | |
661 | ||
662 | /** Interrupt Generators | |
663 | * When interrupt enabled error bits are set in the OE, CE or UE CSRs, a corresponding interrupt | |
664 | * is generated. | |
665 | */ | |
666 | ||
667 | void ilu_intf::proc_ce_int() { | |
668 | csr_port.set_notify_event(PEU_CSR_A_CE_ERR_RW1C_ALIAS_HW_ADDR, &ce_ev); | |
669 | ||
670 | while (1) { | |
671 | wait (ce_ev); | |
672 | ce_err = csr_port.read_csr(PEU_CSR_A_CE_ERR_RW1C_ALIAS_HW_ADDR); | |
673 | ||
674 | if ( (ce_err & ce_int_en) != 0) { | |
675 | wait (clk.posedge_event()); | |
676 | p2d_ce_int.write(1); | |
677 | } else { | |
678 | wait (clk.posedge_event()); | |
679 | p2d_ce_int.write(0); | |
680 | } | |
681 | } | |
682 | } | |
683 | ||
684 | void ilu_intf::proc_ce_int_en() { | |
685 | csr_port.set_notify_event(PEU_CSR_A_CE_INT_EN_HW_ADDR, &ce_en_ev); | |
686 | while (1) { | |
687 | wait (ce_en_ev); | |
688 | ce_int_en = csr_port.read_csr(PEU_CSR_A_CE_INT_EN_HW_ADDR); | |
689 | } | |
690 | } | |
691 | ||
692 | void ilu_intf::proc_ue_int() { | |
693 | csr_port.set_notify_event(PEU_CSR_A_UE_ERR_RW1C_ALIAS_HW_ADDR, &ue_ev); | |
694 | ||
695 | while (1) { | |
696 | wait (ue_ev); | |
697 | ue_err = csr_port.read_csr(PEU_CSR_A_UE_ERR_RW1C_ALIAS_HW_ADDR); | |
698 | ||
699 | if ( (ue_err & ue_int_en) != 0) { | |
700 | wait (clk.posedge_event()); | |
701 | p2d_ue_int.write(1); | |
702 | } else { | |
703 | wait (clk.posedge_event()); | |
704 | p2d_ue_int.write(0); | |
705 | } | |
706 | } | |
707 | } | |
708 | ||
709 | void ilu_intf::proc_ue_int_en() { | |
710 | csr_port.set_notify_event(PEU_CSR_A_UE_INT_EN_HW_ADDR, &ue_en_ev); | |
711 | while (1) { | |
712 | wait (ue_en_ev); | |
713 | ue_int_en = csr_port.read_csr(PEU_CSR_A_UE_INT_EN_HW_ADDR); | |
714 | } | |
715 | } | |
716 | ||
717 | void ilu_intf::proc_oe_int() { | |
718 | csr_port.set_notify_event(PEU_CSR_A_OE_ERR_RW1C_ALIAS_HW_ADDR, &oe_ev); | |
719 | ||
720 | while (1) { | |
721 | wait (oe_ev); | |
722 | oe_err = csr_port.read_csr(PEU_CSR_A_OE_ERR_RW1C_ALIAS_HW_ADDR); | |
723 | ||
724 | if ( (oe_err & oe_int_en) != 0) { | |
725 | wait (clk.posedge_event()); | |
726 | p2d_oe_int.write(1); | |
727 | } else { | |
728 | wait (clk.posedge_event()); | |
729 | p2d_oe_int.write(0); | |
730 | } | |
731 | } | |
732 | } | |
733 | ||
734 | void ilu_intf::proc_oe_int_en() { | |
735 | csr_port.set_notify_event(PEU_CSR_A_OE_INT_EN_HW_ADDR, &oe_en_ev); | |
736 | while (1) { | |
737 | wait (oe_en_ev); | |
738 | oe_int_en = csr_port.read_csr(PEU_CSR_A_OE_INT_EN_HW_ADDR); | |
739 | } | |
740 | } | |
741 | ||
742 | /** | |
743 | * This thread collects credits from the ILU and updates the Ingress Credits Allocated CSR. | |
744 | */ | |
745 | void ilu_intf::ilu_credit_update_handler(){ | |
746 | sc_uint<D2P_IBC_NHC_WDTH> prev_nhc_cred=0; | |
747 | sc_uint<D2P_IBC_PHC_WDTH> prev_phc_cred=0; | |
748 | sc_uint<D2P_IBC_PDC_WDTH> prev_pdc_cred=0; | |
749 | while(1) { | |
750 | wait(d2p_ibc_req.posedge_event()|p2d_drain.negedge_event()); | |
751 | sc_uint<D2P_IBC_NHC_WDTH> nhc_cred = d2p_ibc_nhc.read(); | |
752 | sc_uint<D2P_IBC_PHC_WDTH> phc_cred = d2p_ibc_phc.read(); | |
753 | sc_uint<D2P_IBC_PDC_WDTH> pdc_cred = d2p_ibc_pdc.read(); | |
754 | //LOG_DEBUG << "ILU_INTF: ilu_credit_update_handler: drain_state: " << drain_state << " nhc:" << nhc_cred << " phc:" << phc_cred << " pdc:" << pdc_cred; | |
755 | //LOG_DEBUG << "ILU_INTF: p_nhc:" << prev_nhc_cred << " p_phc:" << prev_phc_cred << " p_pdc:" << prev_pdc_cred; | |
756 | if(!drain_state && (nhc_cred!=prev_nhc_cred || phc_cred!=prev_phc_cred || pdc_cred!=prev_pdc_cred)) | |
757 | { | |
758 | LOG_DEBUG << "ILU_INTF : IIL has sent IBC credit updates. "; | |
759 | LOG_DEBUG << "NHC: " << nhc_cred << " PHC: " << phc_cred << " PDC: " << pdc_cred; | |
760 | sc_uint<64> ica_reg = csr_port.read_csr(PEU_CSR_A_TLU_ICA_HW_ADDR); | |
761 | sc_uint<64> ici_reg = csr_port.read_csr(PEU_CSR_A_TLU_ICI_HW_ADDR); | |
762 | ica_reg.range(NHC) = (sc_uint<8>)(ici_reg(NHC) + nhc_cred + recovered_credits(NHC)); | |
763 | ica_reg.range(PHC) = (sc_uint<8>)(ici_reg(PHC) + phc_cred + recovered_credits(PHC)); | |
764 | ica_reg.range(PDC) = (sc_uint<12>)(ici_reg(PDC) + pdc_cred + recovered_credits(PDC)); | |
765 | csr_port.write_csr(PEU_CSR_A_TLU_ICA_HW_ADDR,ica_reg); | |
766 | prev_nhc_cred = nhc_cred; | |
767 | prev_phc_cred = phc_cred; | |
768 | prev_pdc_cred = pdc_cred; | |
769 | } | |
770 | p2d_ibc_ack.write(true); | |
771 | try{ | |
772 | WAIT(clk.posedge_event()); | |
773 | WAIT(clk.posedge_event()); | |
774 | WAIT(clk.posedge_event()); | |
775 | WAIT(clk.posedge_event()); | |
776 | WAIT(clk.posedge_event()); | |
777 | WAIT(clk.posedge_event()); | |
778 | } | |
779 | catch(sc_exception &e){ | |
780 | LOG_WARNING<<"ILU_INTF: ilu_credit_update_handler...ending clock wait"; | |
781 | if(RETRAIN_NO_RESET) wait(clk.posedge_event()); | |
782 | } | |
783 | p2d_ibc_ack.write(false); | |
784 | } | |
785 | } | |
786 | ||
787 | /** | |
788 | * This thread forwards CMPL Timeout requests from the RSB to the ILU. | |
789 | */ | |
790 | void ilu_intf::cto_req_handler(){ | |
791 | sc_uint<5> cto_req_tag; | |
792 | while(1){ | |
793 | cto_req_port->get(cto_req_tag); | |
794 | LOG_WARNING << "ILU_INTF: cto_req_handler recvd: " << cto_req_tag ; | |
795 | p2d_cto_req.write(1); | |
796 | p2d_cto_tag.write(cto_req_tag); | |
797 | try{ | |
798 | WAIT(d2p_cto_ack.posedge_event()); | |
799 | p2d_cto_req.write(0); | |
800 | WAIT(d2p_cto_ack.negedge_event()); | |
801 | LOG_INFO << "ILU_INTF: CTO Req handling complete" ; | |
802 | } | |
803 | catch(sc_exception &e){ | |
804 | LOG_WARNING<<"ILUT_INTF: cto req handler resetting..."; | |
805 | p2d_cto_req.write(0); | |
806 | p2d_cto_tag.write(0); | |
807 | } | |
808 | } | |
809 | } | |
810 | ||
811 | /** | |
812 | * This function updates the requested UE, CE and OE error bits. | |
813 | */ | |
814 | void ilu_intf::write_error_csr(uint8 err_type, uint8 primary, uint8 secondary, char field_name[3]){ | |
815 | sc_uint<64> orig_csr_val; | |
816 | sc_uint<64> new_csr_val=0; | |
817 | sc_uint<64> log_enable; | |
818 | ||
819 | LOG_DEBUG << "Setting err bit: " << field_name; | |
820 | ||
821 | switch(err_type){ | |
822 | case OE: orig_csr_val = csr_port.read_csr(PEU_CSR_A_OE_ERR_RW1C_ALIAS_HW_ADDR); | |
823 | LOG_DEBUG << "Updating OE CSR (orig val: " << orig_csr_val << ")"; | |
824 | break; | |
825 | case UE: orig_csr_val = csr_port.read_csr(PEU_CSR_A_UE_ERR_RW1C_ALIAS_HW_ADDR); | |
826 | LOG_DEBUG << "Updating UE CSR (orig val: " << orig_csr_val << ")"; | |
827 | break; | |
828 | case CE: orig_csr_val = csr_port.read_csr(PEU_CSR_A_CE_ERR_RW1C_ALIAS_HW_ADDR); | |
829 | LOG_DEBUG << "Updating CE CSR (orig val: " << orig_csr_val << ")"; | |
830 | break; | |
831 | default: LOG_ERROR << "Warning: undefined error type!"; | |
832 | return; | |
833 | } | |
834 | ||
835 | switch(err_type){ | |
836 | case OE: log_enable = csr_port.read_csr(PEU_CSR_A_OE_LOG_HW_ADDR); | |
837 | LOG_DEBUG << "OE Log enable : " << log_enable << ")"; | |
838 | break; | |
839 | case UE: log_enable = csr_port.read_csr(PEU_CSR_A_UE_LOG_HW_ADDR); | |
840 | LOG_DEBUG << "UE Log Enable : " << log_enable << ")"; | |
841 | break; | |
842 | case CE: log_enable = csr_port.read_csr(PEU_CSR_A_CE_LOG_HW_ADDR); | |
843 | LOG_DEBUG << "CE Log Enable : " << log_enable << ")"; | |
844 | break; | |
845 | } | |
846 | ||
847 | if(log_enable.range(primary,primary)==1) | |
848 | { | |
849 | if(orig_csr_val.range(primary,primary)!=1) | |
850 | new_csr_val.range(primary,primary)=1; | |
851 | else if(orig_csr_val.range(secondary,secondary)!=1) | |
852 | new_csr_val.range(secondary,secondary)=1; | |
853 | else | |
854 | LOG_DEBUG << "Warning: Both PRIMARY and SECONDARY of " << field_name << "are set."; | |
855 | } | |
856 | ||
857 | switch(err_type){ | |
858 | case OE: csr_port.write_csr(PEU_CSR_A_OE_ERR_RW1S_ALIAS_HW_ADDR,new_csr_val); | |
859 | LOG_DEBUG << "Updating OE CSR (new val : " << new_csr_val << ")"; | |
860 | break; | |
861 | case UE: csr_port.write_csr(PEU_CSR_A_UE_ERR_RW1S_ALIAS_HW_ADDR,new_csr_val); | |
862 | LOG_DEBUG << "Updating UE CSR (new val : " << new_csr_val << ")"; | |
863 | break; | |
864 | case CE: csr_port.write_csr(PEU_CSR_A_CE_ERR_RW1S_ALIAS_HW_ADDR,new_csr_val); | |
865 | LOG_DEBUG << "Updating CE CSR (new val : " << new_csr_val << ")"; | |
866 | break; | |
867 | } | |
868 | return; | |
869 | }//end write_csr_error | |
870 | ||
871 | /** | |
872 | * Updates to the Max Payload Size ILU port are reflected into the corresponding CSR. | |
873 | */ | |
874 | void ilu_intf::mps_handler() { | |
875 | sc_uint<64> dev_ctl; | |
876 | sc_uint<3> dev_mps; | |
877 | ||
878 | csr_port.set_notify_event(PEU_CSR_A_DEV_CTL_HW_ADDR, &dev_ctl_ev); | |
879 | while (1) { | |
880 | wait (dev_ctl_ev); | |
881 | dev_ctl = csr_port.read_csr(PEU_CSR_A_DEV_CTL_HW_ADDR); | |
882 | dev_mps = dev_ctl(7,5); | |
883 | LOG_DEBUG << "P2D MPS: " << dev_mps << " Device Ctrl Reg: " << dev_ctl; | |
884 | p2d_mps.write(dev_mps); | |
885 | LOG_DEBUG << "P2D MPS: " << dev_mps << " Device Ctrl Reg: " << dev_ctl << " written"; | |
886 | } | |
887 | } | |
888 | ||
889 | /** | |
890 | * This thread handles entry and exit of the model from 'drain state'. | |
891 | */ | |
892 | void ilu_intf::drain_handler(){ | |
893 | sc_event csr_core_status_ev,csr_tlu_status_ev,csr_lnk_ctl_ev; | |
894 | csr_port.set_notify_event(PEU_CSR_A_CORE_STATUS_HW_ADDR,&csr_core_status_ev); | |
895 | csr_port.set_notify_event(PEU_CSR_A_TLU_STS_HW_ADDR,&csr_tlu_status_ev); | |
896 | csr_port.set_notify_event(PEU_CSR_A_LINK_CTL_HW_ADDR,&csr_lnk_ctl_ev); | |
897 | while(1){ | |
898 | wait(drain_req_ev); | |
899 | if(!drain_state){ | |
900 | LOG_DEBUG<<"++++++++++ ILU_INTF: Signaling DRAIN STATE to ILU ++++++++++"; | |
901 | drain_state=true; | |
902 | if(csr_port.read_csr(ILU_CSR_A_ILU_LOG_ERR_RW1S_ALIAS_HW_ADDR).range(4,4)!=1){ | |
903 | //Setting drain bit in PEU Status CSR | |
904 | csr_port.write_csr_mask(PEU_CSR_A_TLU_STS_HW_ADDR,(0x1 << 8),PEU_CSR_TLU_STS_SET_MASK); | |
905 | p2d_drain.write(1); | |
906 | } | |
907 | *parent_global_event_type = SW_RESET_ENTER; //This state is needed to ensure timers are stopped and to keep updatefcs sent... | |
908 | notify(*parent_global_event); | |
909 | wait(SC_ZERO_TIME); | |
910 | ||
911 | if(csr_port.read_csr(PEU_CSR_A_OE_ERR_RW1C_ALIAS_HW_ADDR).range(9,9)!=1){ | |
912 | //Wait for RESET ASSERT | |
913 | while((csr_port.read_csr(PEU_CSR_A_LINK_CTL_HW_ADDR)).range(0,0)!=0x1) wait(csr_lnk_ctl_ev); | |
914 | LOG_INFO<<"ILU_INTF: Reset-assert bit is set..."; | |
915 | //Setting retrain bit in Link Ctrl CSR | |
916 | sc_uint<64> lnk_ctrl_reg = csr_port.read_csr(PEU_CSR_A_LNK_CTL_HW_ADDR); | |
917 | lnk_ctrl_reg(5,5)=1; | |
918 | csr_port.write_csr(PEU_CSR_A_LNK_CTL_HW_ADDR,lnk_ctrl_reg); | |
919 | ||
920 | while((csr_port.read_csr(PEU_CSR_A_CORE_STATUS_HW_ADDR)).range(48,44)!=0x0D) wait(csr_core_status_ev); | |
921 | LOG_WARNING<<"ILU_INTF: PEU now in Recovery..."; | |
922 | } | |
923 | while(1){ | |
924 | wait(rst_l.negedge_event()|csr_tlu_status_ev); | |
925 | if(rst_l.read()==0){ | |
926 | LOG_WARNING<<"ILU_INTF: PEU now receives RESET_L..."; | |
927 | break; | |
928 | } | |
929 | if(csr_port.read_csr(PEU_CSR_A_TLU_STS_HW_ADDR).range(8,8)==0){ | |
930 | //cout << "=== ILU_INTF: SW has cleared drain-state bit ===" << endl; | |
931 | sc_uint<D2P_IHB_ADDR_WDTH> prev_ihb_wr_addr = ihb_wr_addr; | |
932 | sc_uint<D2P_IHB_ADDR_WDTH+1> prev_nxt_ihb_wr_addr = nxt_ihb_wr_addr; | |
933 | sc_uint<D2P_IDB_ADDR_WDTH> prev_idb_wr_addr = idb_wr_addr; | |
934 | sc_uint<D2P_IDB_ADDR_WDTH+1> prev_nxt_idb_wr_addr = nxt_idb_wr_addr; | |
935 | ||
936 | RETRAIN_NO_RESET = true; | |
937 | ||
938 | *parent_global_event_type = SW_RESET_EXIT; | |
939 | notify(*parent_global_event); | |
940 | wait(SC_ZERO_TIME); | |
941 | ||
942 | p2d_drain.write(0); | |
943 | ||
944 | *parent_global_event_type = WMR_RESET_ENTER; | |
945 | notify(*parent_global_event); | |
946 | wait(SC_ZERO_TIME); | |
947 | ||
948 | *parent_global_event_type = SW_RESET_CHNL_EXIT; | |
949 | notify(*parent_global_event); | |
950 | wait(SC_ZERO_TIME); | |
951 | ||
952 | *parent_global_event_type = WMR_RESET_EXIT; | |
953 | notify(*parent_global_event); | |
954 | wait(SC_ZERO_TIME); | |
955 | ||
956 | ||
957 | ihb_wr_addr = prev_ihb_wr_addr; | |
958 | nxt_ihb_wr_addr = prev_nxt_ihb_wr_addr; | |
959 | p2d_ihb_wptr.write(bin2gc(nxt_ihb_wr_addr)); | |
960 | idb_wr_addr = prev_idb_wr_addr; | |
961 | nxt_idb_wr_addr = prev_nxt_idb_wr_addr; | |
962 | ||
963 | break; | |
964 | } | |
965 | } | |
966 | if(rst_l.read()==0){ | |
967 | *parent_global_event_type = SW_RESET_EXIT; | |
968 | notify(*parent_global_event); | |
969 | wait(SC_ZERO_TIME); | |
970 | p2d_drain.write(0); | |
971 | ||
972 | *parent_global_event_type = WMR_RESET_ENTER; | |
973 | notify(*parent_global_event); | |
974 | wait(SC_ZERO_TIME); | |
975 | sc_uint<D2P_IHB_ADDR_WDTH> ihb_wr_addr=0; | |
976 | p2d_ihb_wptr.write(bin2gc(ihb_wr_addr)); | |
977 | ||
978 | *parent_global_event_type = SW_RESET_CHNL_EXIT; | |
979 | notify(*parent_global_event); | |
980 | wait(rst_l.posedge_event()); | |
981 | ||
982 | *parent_global_event_type = WMR_RESET_EXIT; | |
983 | notify(*parent_global_event); | |
984 | wait(SC_ZERO_TIME); | |
985 | drain_state=false; | |
986 | } | |
987 | } | |
988 | ||
989 | }//end while(1) | |
990 | }//end drain_handler() | |
991 | ||
992 | /** | |
993 | * This thread monitors the 'link down' event. This event puts the model into 'drain state' | |
994 | */ | |
995 | void ilu_intf::pl_drain_catcher(){ | |
996 | sc_event csr_status_ev; | |
997 | csr_port.set_notify_event(PEU_CSR_A_OE_ERR_RW1C_ALIAS_HW_ADDR,&csr_status_ev); | |
998 | while(1){ | |
999 | wait(csr_status_ev); | |
1000 | if(!drain_state && csr_port.read_csr(PEU_CSR_A_OE_ERR_RW1C_ALIAS_HW_ADDR).range(9,9)==1) { | |
1001 | LOG_WARNING<<"ILU_INTF: LINK DOWN...Entering DRAIN state"; | |
1002 | drain_req_ev.notify(); | |
1003 | } | |
1004 | } | |
1005 | } | |
1006 | ||
1007 | /** | |
1008 | * This method initializes module registers and flags. | |
1009 | * It also spawns threads that handle module operation. | |
1010 | */ | |
1011 | void ilu_intf::init(){ | |
1012 | ihb_empty = true; | |
1013 | ecd_waddr = 0x00; | |
1014 | erd_waddr = 0x00; | |
1015 | ihb_wr_addr = 0; | |
1016 | nxt_ihb_wr_addr = 0; | |
1017 | idb_wr_addr = 0; | |
1018 | nxt_idb_wr_addr = 0; | |
1019 | recovered_credits=0x0; | |
1020 | drain_state=false; | |
1021 | SW_RESET=false; | |
1022 | POR_RESET=false; | |
1023 | RETRAIN_NO_RESET=false; | |
1024 | sc_uint<P2D_EHB_ADDR_WDTH> erh_addr; | |
1025 | p2d_erh_rptr.write(bin2gc(erh_addr)); | |
1026 | sc_uint<P2D_EHB_ADDR_WDTH> ech_addr; | |
1027 | p2d_ech_rptr.write(bin2gc(ech_addr)); | |
1028 | p2d_ihb_wptr.write(bin2gc(ihb_wr_addr)); | |
1029 | ihb_wptr = bin2gc(ihb_wr_addr); | |
1030 | ingress_packet_handler_ph = sc_spawn(sc_bind(&ilu_intf::ingress_packet_handler,this)); | |
1031 | egress_packet_handler_ph = sc_spawn(sc_bind(&ilu_intf::egress_packet_handler,this)); | |
1032 | p2d_ce_int.write(0); | |
1033 | p2d_oe_int.write(0); | |
1034 | p2d_ue_int.write(0); | |
1035 | LOG_INFO<<"ILU_INTF: threads spawned..."; | |
1036 | }//end init() | |
1037 | ||
1038 | /** | |
1039 | * This thread handles reset behavior of the module. On the arrival of a reset global event, | |
1040 | * it issues termination requests to threads in this module. Following the reset exit global event | |
1041 | * it invokes init() to re-spawn terminated threads. | |
1042 | */ | |
1043 | void ilu_intf::reset_handler(){ | |
1044 | while(1){ | |
1045 | wait(*parent_global_event); | |
1046 | switch(*parent_global_event_type){ | |
1047 | case WMR_RESET_ENTER: | |
1048 | case POR_RESET_ENTER: | |
1049 | POR_RESET=true; | |
1050 | reset_ev.notify(); | |
1051 | //Wait for all thread to terminate | |
1052 | while(1){ | |
1053 | if(ingress_packet_handler_ph.terminated() && egress_packet_handler_ph.terminated()) break; | |
1054 | wait(ingress_packet_handler_ph.terminated_event()|egress_packet_handler_ph.terminated_event()); | |
1055 | } | |
1056 | LOG_WARNING << "ILU_INTF: WMR/POR Reset threads terminated" ; | |
1057 | LOG_WARNING << "ILU_INTF: WMR/POR Reset dbs cleared" ; | |
1058 | break; | |
1059 | ||
1060 | case WMR_RESET_EXIT: | |
1061 | case POR_RESET_EXIT: | |
1062 | LOG_INFO<<"ILU_INTF: WMR/POR Reset exit"; | |
1063 | init(); | |
1064 | break; | |
1065 | } | |
1066 | }//end while(1) | |
1067 | }//end reset_handler() | |
1068 | ||
1069 | /** | |
1070 | * This thread monitors the 'ihb parity error' event. This event puts the model into 'drain state' | |
1071 | */ | |
1072 | void ilu_intf::ilu_drain_catcher(){ | |
1073 | sc_event ilu_err_rw1s_ev; | |
1074 | csr_port.set_notify_event(ILU_CSR_A_ILU_LOG_ERR_RW1S_ALIAS_HW_ADDR,&ilu_err_rw1s_ev); | |
1075 | while(1){ | |
1076 | wait(ilu_err_rw1s_ev); | |
1077 | if(!drain_state && csr_port.read_csr(ILU_CSR_A_ILU_LOG_ERR_RW1S_ALIAS_HW_ADDR).range(4,4)==1) { | |
1078 | LOG_WARNING<<"ILU_INTF: ILU has detected a parity error...Entering DRAIN state"; | |
1079 | drain_req_ev.notify(); | |
1080 | } | |
1081 | } | |
1082 | } | |
1083 | ||
1084 | ||
1085 | }; // namespace pcie |