Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: cpxorder.vr | |
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 <vera_defines.vrh> | |
36 | #include <VeraListProgram.vrh> | |
37 | #include <ListMacros.vrh> | |
38 | // #include<defines.vri> | |
39 | #include<ccx.vri> | |
40 | #include<defines.vri> | |
41 | #include<cpxorder_ports_binds.vrh> | |
42 | //#include<iop_rtl.h> | |
43 | // #include<ccm_top.if.vrh> | |
44 | #include<std_display_class.vrh> | |
45 | #include<std_display_defines.vri> | |
46 | #include "globals.vri" | |
47 | ||
48 | ||
49 | class ccmCpxPkt { | |
50 | ||
51 | integer index; | |
52 | bit [CPX_WIDTH-1:0] packet; | |
53 | } | |
54 | ||
55 | // declare list of ccmCpxPkt objects | |
56 | MakeVeraList(ccmCpxPkt) | |
57 | ||
58 | // This class is an ordered list. All packets should be removed from this list | |
59 | // in the same order as they were added to this list. | |
60 | class ccmCpxPktFIFO { | |
61 | ||
62 | integer core, indexCounter; | |
63 | VeraList_ccmCpxPkt List; | |
64 | VeraListIterator_ccmCpxPkt I; | |
65 | ccmCpxPkt p; | |
66 | ||
67 | ||
68 | task new(integer core) { | |
69 | this.core = core; | |
70 | indexCounter = 0; | |
71 | List = new(); | |
72 | } | |
73 | ||
74 | task Add(ccmCpxPkt packet) { | |
75 | ||
76 | // assign an identifying number to the packet | |
77 | packet.index = indexCounter++; | |
78 | ||
79 | // add packet to back of list. | |
80 | List.push_back(packet); | |
81 | ||
82 | return; | |
83 | } | |
84 | ||
85 | task Remove(bit [CPX_WIDTH-1:0] packet) { | |
86 | // packets issued in PerformEndChecks() are not added to OqOrder and therefore | |
87 | // cannot be removed | |
88 | if(List.empty()) | |
89 | return; | |
90 | ||
91 | // packet to be removed must be the p on the list | |
92 | p = List.front(); | |
93 | ||
94 | if(p.packet =?= packet) | |
95 | List.pop_front(); | |
96 | else { | |
97 | //error("%0d: CPXORDER ERROR: Packet received (%x) is not the first (%x) on Core %0d's list\n", get_time(LO), packet, p.packet, core); | |
98 | PR_ERROR("CPXORDER", MON_ERR, psprintf ("%0d: CPXORDER ERROR: Packet received (%x) is not the first (%x) on Core %0d's list\n", get_time(LO), packet, p.packet, core)); | |
99 | } | |
100 | return; | |
101 | } | |
102 | ||
103 | function integer LastIndex() { | |
104 | ||
105 | p = List.back(); | |
106 | LastIndex = p.index; | |
107 | ||
108 | return; | |
109 | } | |
110 | ||
111 | task Replace(integer index, bit [CPX_WIDTH-1:0] packet) { | |
112 | ||
113 | if(!List.empty()) { | |
114 | I = List.start(); | |
115 | p = I.data(); | |
116 | ||
117 | while(p.index != index) { | |
118 | I.next(); | |
119 | p = I.data(); | |
120 | } | |
121 | ||
122 | p.packet = packet; | |
123 | } | |
124 | } | |
125 | ||
126 | task Reset() { | |
127 | indexCounter = 0; | |
128 | List.clear(); | |
129 | } | |
130 | } | |
131 | ||
132 | ||
133 | ///////////////////////////////////////////////////////////////////////////////// | |
134 | ||
135 | task MonitorCPX() { | |
136 | // local StandardDisplay dbg; | |
137 | string myname; | |
138 | shadow integer i, j, k; | |
139 | integer reqcount[72]; | |
140 | bit [7:0] sctag_cpx_req_cq; | |
141 | bit [7:0] sctag_cpx_ifill2_cq[9]; | |
142 | ||
143 | // a single pulse of bit j of request[i] represents 1 packet being sent from Bank i to Core j. | |
144 | bit [7:0] request[9]; | |
145 | bit [7:0] request_d1[9]; | |
146 | bit [8:0] atom = 0, atom_d1 = 0; | |
147 | // a single pulse of bit j of ifill2[i] represents 1 IFILL_RET2 being sent from Bank i to Core j. | |
148 | bit [7:0] ifill2[9]; | |
149 | bit [7:0] ifill2_d1[9]; | |
150 | bit [145:0] io_cpx_data_ca; | |
151 | shadow bit [7:0] scratch; | |
152 | ||
153 | l2port lp[9]; | |
154 | cpxport cp[8]; | |
155 | ccmCpxPktFIFO Core[8]; | |
156 | ccmCpxPkt packet; | |
157 | ||
158 | ||
159 | // bind ports | |
160 | cp[0] = cpxbind_0; | |
161 | cp[1] = cpxbind_1; | |
162 | cp[2] = cpxbind_2; | |
163 | cp[3] = cpxbind_3; | |
164 | cp[4] = cpxbind_4; | |
165 | cp[5] = cpxbind_5; | |
166 | cp[6] = cpxbind_6; | |
167 | cp[7] = cpxbind_7; | |
168 | lp[0] = l2bind_0; | |
169 | lp[1] = l2bind_1; | |
170 | lp[2] = l2bind_2; | |
171 | lp[3] = l2bind_3; | |
172 | lp[4] = l2bind_4; | |
173 | lp[5] = l2bind_5; | |
174 | lp[6] = l2bind_6; | |
175 | lp[7] = l2bind_7; | |
176 | lp[8] = iobind; | |
177 | ||
178 | //dbg = new; | |
179 | ||
180 | // initialize variables | |
181 | for(i=0; i<9; i++) { | |
182 | sctag_cpx_ifill2_cq[i] = 8'b0; | |
183 | request_d1[i] = 8'b0; | |
184 | request[i] = 8'b0; | |
185 | ifill2_d1[i] = 8'b0; | |
186 | ifill2[i] = 8'b0; | |
187 | ||
188 | for(j=0; j<8; j++) | |
189 | reqcount[i*8 + j] = 0; | |
190 | } | |
191 | ||
192 | for(j=0; j<8; j++) | |
193 | Core[j] = new(j); | |
194 | ||
195 | myname = "CPXORDER"; | |
196 | ||
197 | PR_NORMAL(myname, MON_NORMAL, psprintf("%0d: CPX Ordering Monitor started\n", get_time(LO))); | |
198 | //printf("%0d: CPX Ordering Monitor started\n", get_time(LO)); | |
199 | ||
200 | ||
201 | fork | |
202 | { | |
203 | while(1) { | |
204 | // if reset is active, drop all requests | |
205 | if(cpxorder.ccx_gdbginit_l == 1'b0) { | |
206 | for(i=0; i<9; i++) { | |
207 | sctag_cpx_ifill2_cq[i] = 8'b0; | |
208 | request_d1[i] = 8'b0; | |
209 | request[i] = 8'b0; | |
210 | ifill2_d1[i] = 8'b0; | |
211 | ifill2[i] = 8'b0; | |
212 | ||
213 | for(j=0; j<8; j++) | |
214 | reqcount[i*8 + j] = 0; | |
215 | } | |
216 | ||
217 | for(j=0; j<8; j++) | |
218 | Core[j].Reset(); | |
219 | ||
220 | @(posedge cpxorder.ccx_gdbginit_l); | |
221 | } | |
222 | ||
223 | /// Determine if a packet is being passed to the CPX by each bank in this cycle | |
224 | // 8 banks + io | |
225 | for(i=0; i<9; i++) { | |
226 | sctag_cpx_req_cq = lp[i].$sctag_cpx_req_cq; | |
227 | ||
228 | // add to reqcount[dest_core] for each request if reqcount[dest_core] is less than 3 | |
229 | if(sctag_cpx_req_cq != 8'b0) { | |
230 | for(j=0; j<8; j++) { | |
231 | if(sctag_cpx_req_cq[j] && reqcount[i*8+j] < 3) { | |
232 | reqcount[i*8+j]++; | |
233 | } | |
234 | } | |
235 | } | |
236 | ||
237 | // subtract from reqcount[dest_core] if grant for dest_core is given | |
238 | if(lp[i].$cpx_sctag_grant_cx != 0) { | |
239 | for(j=0; j<8; j++) { | |
240 | if(lp[i].$cpx_sctag_grant_cx[j]) | |
241 | reqcount[i*8+j]--; | |
242 | } | |
243 | } | |
244 | ||
245 | if(sctag_cpx_req_cq != 8'b0 || sctag_cpx_ifill2_cq[i] != 8'b0) { | |
246 | if(reqcount[i*8] < 3 && reqcount[i*8+1] < 3 && reqcount[i*8+2] < 3 && reqcount[i*8+3] < 3 && | |
247 | reqcount[i*8+4] < 3 && reqcount[i*8+5] < 3 && reqcount[i*8+6] < 3 && reqcount[i*8+7] < 3) { | |
248 | // signifies that this packet(s) is/are to be passed to the CPX | |
249 | request[i] = sctag_cpx_req_cq; | |
250 | ||
251 | // IFILL_RET1 | |
252 | if(lp[i].$sctag_cpx_atom_cq) { | |
253 | // signifies that the next packet to be passed to the CPX is an IFILL_RET1 | |
254 | atom[i] = 1'b1; | |
255 | ||
256 | // remember that next request from the same bank to the same core is an IFILL_RET2 request | |
257 | // (since sctag_cpx_req_cq is not asserted for IFILL_RET2 packets) | |
258 | sctag_cpx_ifill2_cq[i] = sctag_cpx_req_cq; | |
259 | ||
260 | // increment reqcount[dest_core] for IFILL_RET2 after IFILL_RET1 is dequeued | |
261 | for(j=0; j<8; j++) { | |
262 | if(sctag_cpx_req_cq[j]) | |
263 | reqcount[i*8+j]++; | |
264 | } | |
265 | } | |
266 | // all other packets | |
267 | else { | |
268 | ifill2[i] = sctag_cpx_ifill2_cq[i]; | |
269 | sctag_cpx_ifill2_cq[i] = 8'b0; | |
270 | } | |
271 | } // if(reqcount[i*8] < 3 && ... && reqcount[i*8+7] < 3) | |
272 | } // if(sctag_cpx_req_cq[i] != 8'b0 || sctag_cpx_ifill2_cq[i] != 8'b0) | |
273 | } // for(i=0; i<9; i++) | |
274 | ||
275 | ||
276 | /// Arrange CPX packets in the order that each Core is supposed to receive them | |
277 | if(request[0] != 8'b0 || request[1] != 8'b0 || request[2] != 8'b0 || request[3] != 8'b0 || | |
278 | request[4] != 8'b0 || request[5] != 8'b0 || request[6] != 8'b0 || request[7] != 8'b0 | request[8] != 8'b0) { | |
279 | fork | |
280 | { | |
281 | // direction of priority is determined 1 cycle after the request is asserted | |
282 | if(i==8) | |
283 | io_cpx_data_ca = lp[8].$sctag_cpx_data_ca; | |
284 | @(posedge cpxorder.ccx_rclk); | |
285 | ||
286 | for(j=0; j<8; j++) { | |
287 | // ascending priority (bank0 > bank2 ... bank7 > NCU) | |
288 | if(cp[j].$dir_a) { | |
289 | for(i=0; i<9; i++) { | |
290 | scratch = request_d1[i]; | |
291 | ||
292 | if(scratch[j]) { | |
293 | packet = new(); | |
294 | if(i==8) | |
295 | //packet.packet = lp[i].$sctag_cpx_data_ca ^ 146'b1; | |
296 | packet.packet = io_cpx_data_ca; | |
297 | else | |
298 | packet.packet = lp[i].$sctag_cpx_data_ca; | |
299 | ||
300 | Core[j].Add(packet); | |
301 | PR_INFO(myname, MON_INFO, psprintf("CPXORDER: Added %x from Bank%0d to Core%0d\n", packet.packet, i, j)); | |
302 | //printf("CPXORDER: Added %x from Bank%0d to Core%0d\n", packet.packet, i, j); | |
303 | ||
304 | if(atom_d1[i]) { | |
305 | packet = new(); | |
306 | Core[j].Add(packet); // add empty packet to list | |
307 | k = Core[j].LastIndex(); | |
308 | ||
309 | fork | |
310 | { | |
311 | @(posedge cpxorder.ccx_rclk); | |
312 | while(1) { | |
313 | scratch = ifill2_d1[i]; | |
314 | if(scratch[j]) | |
315 | break; | |
316 | @(posedge cpxorder.ccx_rclk); | |
317 | } | |
318 | Core[j].Replace(k, lp[i].$sctag_cpx_data_ca); | |
319 | ||
320 | PR_INFO(myname, MON_INFO, psprintf("CPXORDER: Replaced %x from Bank%0d to Core%0d\n", lp[i].$sctag_cpx_data_ca, i, j)); | |
321 | //printf("CPXORDER: Replaced %x from Bank%0d to Core%0d\n", lp[i].$sctag_cpx_data_ca, i, j); | |
322 | } | |
323 | join none | |
324 | } | |
325 | } | |
326 | } | |
327 | } | |
328 | // descending priority ( NCU > bank7 > ... bank2 > bank1 > bank0) | |
329 | else { | |
330 | for(i=8; i>=0; i--) { | |
331 | scratch = request_d1[i]; | |
332 | ||
333 | if(scratch[j]) { | |
334 | packet = new(); | |
335 | if(i==8) | |
336 | //packet.packet = lp[i].$sctag_cpx_data_ca ^ 145'b1; | |
337 | packet.packet = io_cpx_data_ca; | |
338 | else | |
339 | packet.packet = lp[i].$sctag_cpx_data_ca; | |
340 | Core[j].Add(packet); | |
341 | PR_INFO(myname, MON_INFO, psprintf("CPXORDER: Added %x from Bank%0d to Core%0d\n", packet.packet, i, j)); | |
342 | //printf("CPXORDER: Added %x from Bank%0d to Core%0d\n", packet.packet, i, j); | |
343 | ||
344 | if(atom_d1[i]) { | |
345 | packet = new(); | |
346 | Core[j].Add(packet); // add empty packet to list | |
347 | k = Core[j].LastIndex(); | |
348 | ||
349 | fork | |
350 | { | |
351 | @(posedge cpxorder.ccx_rclk); | |
352 | while(1) { | |
353 | scratch = ifill2_d1[i]; | |
354 | if(scratch[j]) | |
355 | break; | |
356 | @(posedge cpxorder.ccx_rclk); | |
357 | } | |
358 | Core[j].Replace(k, lp[i].$sctag_cpx_data_ca); | |
359 | PR_INFO(myname, MON_INFO, psprintf("CPXORDER: Replaced %x from Bank%0d to Core%0d\n", lp[i].$sctag_cpx_data_ca, i, j)); | |
360 | //printf("CPXORDER: Replaced %x from Bank%0d to Core%0d\n", lp[i].$sctag_cpx_data_ca, i, j); | |
361 | } | |
362 | join none | |
363 | } | |
364 | } | |
365 | } | |
366 | } | |
367 | } // for(j=0; j<8; j++) | |
368 | } | |
369 | join none | |
370 | } | |
371 | ||
372 | ||
373 | /// Check that CPX packets arrive at the Cores in the correct order | |
374 | // (packets from the NCU are excluded) | |
375 | for(j=0; j<8; j++) { | |
376 | if(cp[j].$cpx_spc_data_cx2[CPX_VALID]) { | |
377 | Core[j].Remove(cp[j].$cpx_spc_data_cx2); | |
378 | PR_INFO(myname, MON_INFO, psprintf("CPXORDER: Removed %x from Core%0d\n", cp[j].$cpx_spc_data_cx2, j)); | |
379 | //printf("CPXORDER: Removed %x from Core%0d\n", cp[j].$cpx_spc_data_cx2, j); | |
380 | } | |
381 | } | |
382 | ||
383 | ||
384 | /// Stage request signals to the next cycle (on negedge cpxorder.ccx_rclk to prevent possible | |
385 | /// race between forked threads) | |
386 | @(negedge cpxorder.ccx_rclk); | |
387 | ||
388 | for(i=0; i<9; i++) { | |
389 | request_d1[i] = request[i]; | |
390 | request[i] = 8'b0; | |
391 | ifill2_d1[i] = ifill2[i]; | |
392 | ifill2[i] = 8'b0; | |
393 | } | |
394 | atom_d1 = atom; | |
395 | atom = 9'b0; | |
396 | ||
397 | ||
398 | @(posedge cpxorder.ccx_rclk); | |
399 | } // while(1) | |
400 | } | |
401 | join none | |
402 | } |