Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / common / pli / socket / c / src / queue.c
CommitLineData
86530b38
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* OpenSPARC T2 Processor File: queue.c
5* Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved
6* 4150 Network Circle, Santa Clara, California 95054, U.S.A.
7*
8* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
9*
10* This program is free software; you can redistribute it and/or modify
11* it under the terms of the GNU General Public License as published by
12* the Free Software Foundation; version 2 of the License.
13*
14* This program is distributed in the hope that it will be useful,
15* but WITHOUT ANY WARRANTY; without even the implied warranty of
16* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17* GNU General Public License for more details.
18*
19* You should have received a copy of the GNU General Public License
20* along with this program; if not, write to the Free Software
21* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22*
23* For the avoidance of doubt, and except that if any non-GPL license
24* choice is available it will apply instead, Sun elects to use only
25* the General Public License version 2 (GPLv2) at this time for any
26* software where a choice of GPL license versions is made
27* available with the language indicating that GPLv2 or any later version
28* may be used, or where a choice of which version of the GPL is applied is
29* otherwise unspecified.
30*
31* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
32* CA 95054 USA or visit www.sun.com if you need additional information or
33* have any questions.
34*
35*
36* ========== Copyright Header End ============================================
37*/
38#define __QUEUE_C_
39#include <unistd.h>
40#include "queue.h"
41#include "monitor.h"
42#include "veriuser.h"
43#include "vcsuser.h"
44#define ULLONG_MAX 18446744073709551615
45////////////////////////////////////////////////////////////////////////
46// Initialize the Array of Lists structure and return pointer
47////////////////////////////////////////////////////////////////////////
48mt_list_ptr init_q (mt_list_ptr q) {
49
50 int i;
51 cDispmon ("queue", MON_NORMAL,"Initializing Queue ..");
52 // Create Array of Lists
53
54 q = (mt_list_ptr)malloc(sizeof(struct mt_list)) ;
55
56 // Initialize each list
57 for (i=0; i<(NUMCORE*NUMTHREAD); i++) {
58 q->t_list[i] = (t_list_head_ptr)malloc(sizeof(struct t_list_head_node));
59 q->t_list[i]->head_ptr = NULL;
60 q->t_list[i]->tail_ptr = NULL;
61 }
62
63 // Return pointer
64
65 if (debug_queue)
66 cDispmon("queue", MON_INFO, "Initialized QID %d",q);
67 return (q);
68}
69
70///////////////////////////////////////////////////////////////////////////////
71// Push a node structure into one of the lists
72///////////////////////////////////////////////////////////////////////////////
73int push_q (mt_list_ptr q, int tid, void *item) {
74 t_list_node_ptr node;
75
76 node = (t_list_node_ptr)malloc(sizeof(struct t_list_node));
77 if (node == NULL) {
78 cDispmon ("queue",MON_ERR,"Malloc Error pushing values to queue (%d)",
79 tid);
80 tf_dofinish();
81 }
82
83
84 node->record = item;
85 node->next = NULL;
86
87
88 // Attach item node to apprpriate list and update head/tail pointers
89
90 if (q->t_list[tid]->head_ptr == NULL) { // Empty Q
91 q->t_list[tid]->head_ptr = node;
92 } else {
93 q->t_list[tid]->tail_ptr->next = node;
94 }
95 q->t_list[tid]->tail_ptr = node;
96
97 return 1;
98}
99
100//////////////////////////////////////////////////////////////////////////////
101// Pop the oldest element form one of the lists
102//////////////////////////////////////////////////////////////////////////////
103void * pop_q (mt_list_ptr q, int tid ) {
104 t_list_node_ptr node;
105 void *record;
106
107 // Copy head item out, and redirect head pointer to item->next
108
109 // Check if Q is already empty.
110 if (q->t_list[tid]->head_ptr == NULL) {
111 return 0;
112 }
113
114 // Get Node from Q
115 node = q->t_list[tid]->head_ptr->next;
116 record = q->t_list[tid]->head_ptr->record;
117
118
119 // Deallocate structure
120 free (q->t_list[tid]->head_ptr);
121
122 // Update head pointer
123 q->t_list[tid]->head_ptr = node;
124
125 // Return the record pointer
126 return record;
127
128}
129
130///////////////////////////////////////////////////////////////////////////////
131// Print the contents of one of the lists
132///////////////////////////////////////////////////////////////////////////////
133int print_q (mt_list_ptr q, int tid) {
134 t_list_node_ptr last;
135 t_check_item_ptr item;
136
137
138 io_printf ("Queue %d ==> \n", tid);
139
140 if (q->t_list[tid]->head_ptr == NULL) {
141 io_printf ("\tNULL\n");
142 return 0;
143 } else {
144 last = q->t_list[tid]->head_ptr;
145 while (last != NULL) {
146 item = (t_check_item_ptr) last->record;
147 printf ("\tTime :%llu\n", item->time);
148 printf ("\tType :%c\n", item->type);
149 printf ("\tReg :%d\n", item->reg_num);
150 printf ("\tValue:0x%llx\n\n", item->value);
151 last = last->next;
152 }
153 }
154return 0;
155}
156
157///////////////////////////////////////////////////////////////////////////////
158// Return the size of one of the lists
159///////////////////////////////////////////////////////////////////////////////
160int size_q (mt_list_ptr q, int tid) {
161 int i;
162 t_list_node_ptr last;
163
164
165 if (q->t_list[tid]->head_ptr == NULL) {
166 return 0;
167 } else {
168 if (debug_queue) {
169 i = 1; last = q->t_list[tid]->head_ptr->next;
170 while (last != NULL) {
171 i++; last = last->next;
172 }
173 return i;
174 } else {
175 return 1;
176 }
177 }
178}
179
180//////////////////////////////////////////////////////////////////////////////
181// Scan the Instruction queues for matching VA and return record.
182// Remove record from queue
183//////////////////////////////////////////////////////////////////////////////
184t_instr_item_ptr scan_instr4va (mt_list_ptr q, int tid, unsigned long long va) {
185
186 t_list_node_ptr node, prev;
187 t_instr_item_ptr item;
188
189 if (q->t_list[tid]->head_ptr == NULL) {
190 return NULL;
191 }
192
193 // Start at head. Scan each item for matching va
194
195 node = q->t_list[tid]->head_ptr;
196 prev = node;
197 item = (t_instr_item_ptr) node->record;
198 while (item->va != va && (node->next != NULL)) {
199 prev = node;
200 node = node->next;
201 item = (t_instr_item_ptr) node->record;
202 }
203 // If match adjust pointer and return item ..
204 if (item->va == va) {
205 if (node == q->t_list[tid]->head_ptr) { // First item ..
206 q->t_list[tid]->head_ptr = node -> next;
207 } else {
208 prev->next = node->next;
209 }
210 if (node == q->t_list[tid]->tail_ptr) // PJ: Last item ..
211 q->t_list[tid]->tail_ptr = prev;
212
213
214 free(node);
215 return item;
216 } else {
217 return NULL;
218 }
219}
220
221//////////////////////////////////////////////////////////////////////////////
222// Get Status of all queues - 64 bit return value
223//////////////////////////////////////////////////////////////////////////////
224unsigned long long status_q (mt_list_ptr q) {
225 unsigned long long status;
226 int i, j;
227 status = 0;
228
229 for (i = NUMCORE*NUMTHREAD-1; i >= 0; i--) {
230 status <<= 1;
231 j = size_q (q, i);
232 if (j) {
233 status |= 1;
234 }
235 }
236 return status ;
237}
238
239//////////////////////////////////////////////////////////////////////////////
240// Find the oldest entry (smallest timestamp) in all thread queues
241//////////////////////////////////////////////////////////////////////////////
242int oldest_t (mt_list_ptr q) {
243 t_check_item_ptr item;
244 unsigned long long oldest=0, tstamp=ULLONG_MAX;
245 int i ;
246
247 for (i = NUMCORE*NUMTHREAD-1; i >= 0; i--) {
248 if (size_q(q, i)) {
249 item = (t_check_item_ptr) q->t_list[i]->head_ptr->record;
250 if (item->time < tstamp) {
251 tstamp = item->time; oldest = i;
252 }
253 }
254 }
255 return oldest ;
256}
257
258//////////////////////////////////////////////////////////////////////////////
259// queue_call () Main PLI call routine
260//
261// Input Params : mt_list_ptr, command, params
262// Command : 0 = Init, 1 = Push, 2 = Pop, 3 = Status
263// Push : tid, time. type, [level/win], num, value, oldest
264// Pop : tid, time, type, level, win, num, value, oldest
265// Instr: tid, va, time, pre_string, post_string
266// Status: mt_list_ptr for Q2
267// Return Values: Init : mt_list_ptr
268// Push : Status (64 bits)
269// Pop : Status (64 bits) , data as params
270// Status : Status (64 bits), oldest for param2
271// Instr : Print Instruction String, Return Status for list
272//
273//////////////////////////////////////////////////////////////////////////////
274
275#ifdef NCV
276int queue_size() { return(64); }
277int queue_call() {
278#else
279unsigned long long queue_call() {
280#endif
281
282 mt_list_ptr q, q2;
283 t_check_item_ptr item;
284 t_instr_item_ptr instr;
285 int command, tid, level=0, win=0, regnum, i, high;
286 unsigned low;
287 unsigned long long value, status, va, time;
288 char type;
289 char *prestring, *postring;
290 static int instr_count = 1;
291#ifndef USE_FPRINTF
292 unsigned char ff = 255; unsigned char fe = 254;
293 unsigned char lev,wn,rn; short td;
294#endif
295
296 // Get queue handle && type of action to be done on queue
297
298 i = 1;
299 q = (mt_list_ptr) tf_getp (i++);
300 command = tf_getp(i++);
301
302 if (debug_queue) cDispmon ("queue", MON_DEBUG, "CMD=%d:", command);
303
304 switch (command) {
305 case INIT_Q :// Initialize queues
306 q = init_q (q);
307 tf_putp (0, (unsigned int) q);
308 return 0;
309 break;
310 case PUSH_Q :// Push parameters into queue for tid
311 // Get params ..
312 tid = tf_getp(i++);
313 low = tf_getlongp (&high, i++);
314 time = high; time <<= 32; time |= low;
315 type = (tf_getcstringp(i++))[0];
316 switch (type) {
317 case 'G' : level = tf_getp(i++); break;
318 case 'W':
319 case 'X': win = tf_getp(i++); break;
320 }
321 regnum = tf_getp(i++);
322 low = tf_getlongp (&high, i++);
323 value = high; value <<= 32; value |= low;
324
325 // Nas trace dump
326 if (nas_trace) {
327 /*printf ("IN=%c: PUSH tid=%d time=%llu type=%c win=%d level=%d num=%d val=%llx\n",
328 indelta[tid], tid, time, type, win, level, regnum, value);
329 */
330#ifndef USE_FPRINTF
331 td = (short)tid; lev = (unsigned char) level;
332 wn = (unsigned char) win; rn = (unsigned char) regnum;
333#endif
334 if(indelta[tid] != '1') {
335 indelta[tid] = '1';
336#ifndef USE_FPRINTF
337 write(nas_fd, &ff, 1);
338 write(nas_fd, &td, 2);
339 write(nas_fd, &type, 1);
340 switch (type) {
341 case 'G' : write(nas_fd, &lev, 1); break;
342 case 'W':
343 case 'X': write(nas_fd, &wn, 1);break;
344 }
345 write(nas_fd, &rn, 1);
346 write(nas_fd, &value, 8);
347#else
348 fprintf(nas_fd, "ff%04d%c", tid, type);
349 switch (type) {
350 case 'G' : fprintf(nas_fd, "%02d", level); break;
351 case 'W':
352 case 'X': fprintf(nas_fd, "%02d", win);break;
353 }
354 fprintf(nas_fd, "%02d%016llx", regnum, value);
355#endif
356 } else if ((indelta[tid] == '1') && (regnum == 999)) {
357 indelta[tid] = '0';
358#ifndef USE_FPRINTF
359 write(nas_fd, &fe, 1);
360 } else {
361 write(nas_fd, &type, 1);
362 switch (type) {
363 case 'G' : write(nas_fd, &lev, 1); break;
364 case 'W':
365 case 'X': write(nas_fd, &wn, 1);break;
366 }
367 write(nas_fd, &rn, 1);
368 write(nas_fd, &value, 8);
369 }
370#else
371 fprintf(nas_fd, "fe");
372 } else {
373 fprintf(nas_fd, "%c", type);
374 switch (type) {
375 case 'G' : fprintf(nas_fd, "%02d", level); break;
376 case 'W':
377 case 'X': fprintf(nas_fd, "%02d", win);break;
378 }
379 fprintf(nas_fd, "%02d%016llx", regnum, value);
380 }
381#endif
382 }
383 // Build item ..
384 //
385 item = (t_check_item_ptr)malloc(sizeof(struct t_check_item));
386 if (item == NULL) {
387 cDispmon ("queue", MON_ERR, "Malloc Error adding to queue (%d)",
388 tid);
389 tf_dofinish();
390 }
391
392 if (debug_queue)
393 cWritemon ("queue", MON_DEBUG, "PUSH tid=%d time=%llu type=%c win=%d level=%d num=%d val=%llx",
394 tid, time, type, win, level, regnum, value);
395
396
397 item->time = time;
398 item->type = type;
399 item->level = level;
400 item->win = win;
401 item->reg_num = regnum;
402 item->value = value;
403
404 // Push into queue
405
406
407 if (! push_q (q, tid, item)) {
408 cDispmon ("queue", MON_ERR, "Error pushing values to queue (%d)\n",
409 tid);
410 tf_dofinish();
411 }
412 q2=q;
413 break;
414 case POP_Q :// Pop oldest record from tid queue and send to bench
415 tid = tf_getp(i++);
416 item = (t_check_item_ptr) pop_q (q, tid);
417 if (item == NULL) {
418 cDispmon("queue", MON_ERR, "Error popping values from queue (%d)\n",
419 tid);
420 tf_dofinish();
421 }
422 tf_putlongp(i++, item->time, item->time >> 32);
423 tf_putp(i++, item->type);
424 tf_putp(i++, item->level);
425 tf_putp(i++, item->win);
426 tf_putp(i++, item->reg_num);
427 tf_putlongp(i++, item->value, item->value >> 32);
428 q2=q;
429 if (debug_queue)
430 cWritemon("queue", MON_DEBUG, "POP tid=%d time=%llu type=%c win=%d level=%d num=%d val=%llx",
431 tid, item->time, item->type, item->win, item->level, item->reg_num,
432 item->value);
433 free(item);
434 break;
435 case STATUS_Q :// Return the Status of the queues
436 if (tf_nump() >= i) {
437 q2 = (mt_list_ptr)tf_getp(i++);
438 }
439 break;
440 case PR_INSTR_Q :// Print the current instruction for tid
441 tid = tf_getp(i++);
442 low = tf_getlongp (&high, i++);
443 va = high; va <<= 32; va |= low;
444 low = tf_getlongp (&high, i++);
445 time = high; time <<= 32; time |= low;
446 // Get the prestring if available
447 if (tf_nump() >= i) {
448 prestring = tf_getcstringp(i++);
449 }
450 // Get the postring if available
451 if (tf_nump() >= i) {
452 postring = tf_getcstringp(i++);
453 }
454 // Check if instruction available in tid queue
455 if ((instr = scan_instr4va(q_instr, tid, va)) == NULL) {
456 //cDispmon("nas", MON_NORMAL, " @%llu #%d T%d %012llx -- Instr Unavailable -- %s",
457 if (! quiet)
458 printf("%s: nas[nas_top]: @%llu #%d T%d %012llx -- Instr Unavailable -- %s\n",
459 tf_strgettime(), time, instr_count, tid, va, postring);
460 } else {
461 if (!show_instr_pa) {
462 //cWritemon("nas", MON_NORMAL, " @%llu #%d T%d %012llx %s %s",
463 if (!quiet)
464 printf("%s: nas[nas_top]: @%llu #%d T%d %012llx %s %s\n",
465 tf_strgettime(), time, instr_count, tid, va,
466 instr->instruction, postring);
467 } else {
468 //cWritemon("nas", MON_NORMAL, " @%llu #%d T%d v:%012llx p:%012llx %s %s",
469 if (!quiet)
470 printf("%s: nas[nas_top]: @%llu #%d T%d v:%012llx p:%012llx %s %s\n",
471 tf_strgettime(), time, instr_count, tid, va, instr->pa,
472 instr->instruction, postring);
473 }
474 //cDispmon("nas", MON_NORMAL,"");
475 free(instr);
476 }
477 instr_count++;
478 break;
479 case FLUSH_TH_Q: // Drain contents of the queue for a single thread
480 tid = tf_getp(i++);
481 if (debug_queue)
482 cWritemon("queue", MON_DEBUG, "Q FLUSH tid=%d", tid);
483
484 q-> t_list[tid]->head_ptr = NULL;
485 q-> t_list[tid]->tail_ptr = NULL;
486 q2 = q;
487 break;
488 default:
489 cDispmon("queue", MON_ERR, "Unexpected command (%d) .. terminating!\n",
490 command );
491 tf_dofinish();
492 break;
493 }
494 if (tf_nump() >=i) {
495 tf_putp(i, oldest_t(q2));
496 if (debug_queue)
497 cWritemon("queue", MON_DEBUG, " oldest=%d ", oldest_t(q2));
498 }
499 status = status_q (q);
500 if (debug_queue)
501 cDispmon("queue", MON_DEBUG, " status=%llx", status);
502 tf_putlongp(0, status, status >> 32);
503 return 0;
504}