* ========== Copyright Header Begin ==========================================
* OpenSPARC T2 Processor File: queue.c
* Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved
* 4150 Network Circle, Santa Clara, California 95054, U.S.A.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* For the avoidance of doubt, and except that if any non-GPL license
* choice is available it will apply instead, Sun elects to use only
* the General Public License version 2 (GPLv2) at this time for any
* software where a choice of GPL license versions is made
* available with the language indicating that GPLv2 or any later version
* may be used, or where a choice of which version of the GPL is applied is
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* ========== Copyright Header End ============================================
#define ULLONG_MAX 18446744073709551615
////////////////////////////////////////////////////////////////////////
// Initialize the Array of Lists structure and return pointer
////////////////////////////////////////////////////////////////////////
mt_list_ptr
init_q (mt_list_ptr q
) {
cDispmon ("queue", MON_NORMAL
,"Initializing Queue ..");
q
= (mt_list_ptr
)malloc(sizeof(struct mt_list
)) ;
for (i
=0; i
<(NUMCORE
*NUMTHREAD
); i
++) {
q
->t_list
[i
] = (t_list_head_ptr
)malloc(sizeof(struct t_list_head_node
));
q
->t_list
[i
]->head_ptr
= NULL
;
q
->t_list
[i
]->tail_ptr
= NULL
;
cDispmon("queue", MON_INFO
, "Initialized QID %d",q
);
///////////////////////////////////////////////////////////////////////////////
// Push a node structure into one of the lists
///////////////////////////////////////////////////////////////////////////////
int push_q (mt_list_ptr q
, int tid
, void *item
) {
node
= (t_list_node_ptr
)malloc(sizeof(struct t_list_node
));
cDispmon ("queue",MON_ERR
,"Malloc Error pushing values to queue (%d)",
// Attach item node to apprpriate list and update head/tail pointers
if (q
->t_list
[tid
]->head_ptr
== NULL
) { // Empty Q
q
->t_list
[tid
]->head_ptr
= node
;
q
->t_list
[tid
]->tail_ptr
->next
= node
;
q
->t_list
[tid
]->tail_ptr
= node
;
//////////////////////////////////////////////////////////////////////////////
// Pop the oldest element form one of the lists
//////////////////////////////////////////////////////////////////////////////
void * pop_q (mt_list_ptr q
, int tid
) {
// Copy head item out, and redirect head pointer to item->next
// Check if Q is already empty.
if (q
->t_list
[tid
]->head_ptr
== NULL
) {
node
= q
->t_list
[tid
]->head_ptr
->next
;
record
= q
->t_list
[tid
]->head_ptr
->record
;
free (q
->t_list
[tid
]->head_ptr
);
q
->t_list
[tid
]->head_ptr
= node
;
// Return the record pointer
///////////////////////////////////////////////////////////////////////////////
// Print the contents of one of the lists
///////////////////////////////////////////////////////////////////////////////
int print_q (mt_list_ptr q
, int tid
) {
io_printf ("Queue %d ==> \n", tid
);
if (q
->t_list
[tid
]->head_ptr
== NULL
) {
last
= q
->t_list
[tid
]->head_ptr
;
item
= (t_check_item_ptr
) last
->record
;
printf ("\tTime :%llu\n", item
->time
);
printf ("\tType :%c\n", item
->type
);
printf ("\tReg :%d\n", item
->reg_num
);
printf ("\tValue:0x%llx\n\n", item
->value
);
///////////////////////////////////////////////////////////////////////////////
// Return the size of one of the lists
///////////////////////////////////////////////////////////////////////////////
int size_q (mt_list_ptr q
, int tid
) {
if (q
->t_list
[tid
]->head_ptr
== NULL
) {
i
= 1; last
= q
->t_list
[tid
]->head_ptr
->next
;
//////////////////////////////////////////////////////////////////////////////
// Scan the Instruction queues for matching VA and return record.
// Remove record from queue
//////////////////////////////////////////////////////////////////////////////
t_instr_item_ptr
scan_instr4va (mt_list_ptr q
, int tid
, unsigned long long va
) {
t_list_node_ptr node
, prev
;
if (q
->t_list
[tid
]->head_ptr
== NULL
) {
// Start at head. Scan each item for matching va
node
= q
->t_list
[tid
]->head_ptr
;
item
= (t_instr_item_ptr
) node
->record
;
while (item
->va
!= va
&& (node
->next
!= NULL
)) {
item
= (t_instr_item_ptr
) node
->record
;
// If match adjust pointer and return item ..
if (node
== q
->t_list
[tid
]->head_ptr
) { // First item ..
q
->t_list
[tid
]->head_ptr
= node
-> next
;
if (node
== q
->t_list
[tid
]->tail_ptr
) // PJ: Last item ..
q
->t_list
[tid
]->tail_ptr
= prev
;
//////////////////////////////////////////////////////////////////////////////
// Get Status of all queues - 64 bit return value
//////////////////////////////////////////////////////////////////////////////
unsigned long long status_q (mt_list_ptr q
) {
unsigned long long status
;
for (i
= NUMCORE
*NUMTHREAD
-1; i
>= 0; i
--) {
//////////////////////////////////////////////////////////////////////////////
// Find the oldest entry (smallest timestamp) in all thread queues
//////////////////////////////////////////////////////////////////////////////
int oldest_t (mt_list_ptr q
) {
unsigned long long oldest
=0, tstamp
=ULLONG_MAX
;
for (i
= NUMCORE
*NUMTHREAD
-1; i
>= 0; i
--) {
item
= (t_check_item_ptr
) q
->t_list
[i
]->head_ptr
->record
;
if (item
->time
< tstamp
) {
tstamp
= item
->time
; oldest
= i
;
//////////////////////////////////////////////////////////////////////////////
// queue_call () Main PLI call routine
// Input Params : mt_list_ptr, command, params
// Command : 0 = Init, 1 = Push, 2 = Pop, 3 = Status
// Push : tid, time. type, [level/win], num, value, oldest
// Pop : tid, time, type, level, win, num, value, oldest
// Instr: tid, va, time, pre_string, post_string
// Status: mt_list_ptr for Q2
// Return Values: Init : mt_list_ptr
// Push : Status (64 bits)
// Pop : Status (64 bits) , data as params
// Status : Status (64 bits), oldest for param2
// Instr : Print Instruction String, Return Status for list
//////////////////////////////////////////////////////////////////////////////
int queue_size() { return(64); }
unsigned long long queue_call() {
int command
, tid
, level
=0, win
=0, regnum
, i
, high
;
unsigned long long value
, status
, va
, time
;
char *prestring
, *postring
;
static int instr_count
= 1;
unsigned char ff
= 255; unsigned char fe
= 254;
unsigned char lev
,wn
,rn
; short td
;
// Get queue handle && type of action to be done on queue
q
= (mt_list_ptr
) tf_getp (i
++);
if (debug_queue
) cDispmon ("queue", MON_DEBUG
, "CMD=%d:", command
);
case INIT_Q
:// Initialize queues
tf_putp (0, (unsigned int) q
);
case PUSH_Q
:// Push parameters into queue for tid
low
= tf_getlongp (&high
, i
++);
time
= high
; time
<<= 32; time
|= low
;
type
= (tf_getcstringp(i
++))[0];
case 'G' : level
= tf_getp(i
++); break;
case 'X': win
= tf_getp(i
++); break;
low
= tf_getlongp (&high
, i
++);
value
= high
; value
<<= 32; value
|= low
;
/*printf ("IN=%c: PUSH tid=%d time=%llu type=%c win=%d level=%d num=%d val=%llx\n",
indelta[tid], tid, time, type, win, level, regnum, value);
td
= (short)tid
; lev
= (unsigned char) level
;
wn
= (unsigned char) win
; rn
= (unsigned char) regnum
;
if(indelta
[tid
] != '1') {
case 'G' : write(nas_fd
, &lev
, 1); break;
case 'X': write(nas_fd
, &wn
, 1);break;
write(nas_fd
, &value
, 8);
fprintf(nas_fd
, "ff%04d%c", tid
, type
);
case 'G' : fprintf(nas_fd
, "%02d", level
); break;
case 'X': fprintf(nas_fd
, "%02d", win
);break;
fprintf(nas_fd
, "%02d%016llx", regnum
, value
);
} else if ((indelta
[tid
] == '1') && (regnum
== 999)) {
case 'G' : write(nas_fd
, &lev
, 1); break;
case 'X': write(nas_fd
, &wn
, 1);break;
write(nas_fd
, &value
, 8);
fprintf(nas_fd
, "%c", type
);
case 'G' : fprintf(nas_fd
, "%02d", level
); break;
case 'X': fprintf(nas_fd
, "%02d", win
);break;
fprintf(nas_fd
, "%02d%016llx", regnum
, value
);
item
= (t_check_item_ptr
)malloc(sizeof(struct t_check_item
));
cDispmon ("queue", MON_ERR
, "Malloc Error adding to queue (%d)",
cWritemon ("queue", MON_DEBUG
, "PUSH tid=%d time=%llu type=%c win=%d level=%d num=%d val=%llx",
tid
, time
, type
, win
, level
, regnum
, value
);
if (! push_q (q
, tid
, item
)) {
cDispmon ("queue", MON_ERR
, "Error pushing values to queue (%d)\n",
case POP_Q
:// Pop oldest record from tid queue and send to bench
item
= (t_check_item_ptr
) pop_q (q
, tid
);
cDispmon("queue", MON_ERR
, "Error popping values from queue (%d)\n",
tf_putlongp(i
++, item
->time
, item
->time
>> 32);
tf_putp(i
++, item
->type
);
tf_putp(i
++, item
->level
);
tf_putp(i
++, item
->reg_num
);
tf_putlongp(i
++, item
->value
, item
->value
>> 32);
cWritemon("queue", MON_DEBUG
, "POP tid=%d time=%llu type=%c win=%d level=%d num=%d val=%llx",
tid
, item
->time
, item
->type
, item
->win
, item
->level
, item
->reg_num
,
case STATUS_Q
:// Return the Status of the queues
q2
= (mt_list_ptr
)tf_getp(i
++);
case PR_INSTR_Q
:// Print the current instruction for tid
low
= tf_getlongp (&high
, i
++);
va
= high
; va
<<= 32; va
|= low
;
low
= tf_getlongp (&high
, i
++);
time
= high
; time
<<= 32; time
|= low
;
// Get the prestring if available
prestring
= tf_getcstringp(i
++);
// Get the postring if available
postring
= tf_getcstringp(i
++);
// Check if instruction available in tid queue
if ((instr
= scan_instr4va(q_instr
, tid
, va
)) == NULL
) {
//cDispmon("nas", MON_NORMAL, " @%llu #%d T%d %012llx -- Instr Unavailable -- %s",
printf("%s: nas[nas_top]: @%llu #%d T%d %012llx -- Instr Unavailable -- %s\n",
tf_strgettime(), time
, instr_count
, tid
, va
, postring
);
//cWritemon("nas", MON_NORMAL, " @%llu #%d T%d %012llx %s %s",
printf("%s: nas[nas_top]: @%llu #%d T%d %012llx %s %s\n",
tf_strgettime(), time
, instr_count
, tid
, va
,
instr
->instruction
, postring
);
//cWritemon("nas", MON_NORMAL, " @%llu #%d T%d v:%012llx p:%012llx %s %s",
printf("%s: nas[nas_top]: @%llu #%d T%d v:%012llx p:%012llx %s %s\n",
tf_strgettime(), time
, instr_count
, tid
, va
, instr
->pa
,
instr
->instruction
, postring
);
//cDispmon("nas", MON_NORMAL,"");
case FLUSH_TH_Q
: // Drain contents of the queue for a single thread
cWritemon("queue", MON_DEBUG
, "Q FLUSH tid=%d", tid
);
q
-> t_list
[tid
]->head_ptr
= NULL
;
q
-> t_list
[tid
]->tail_ptr
= NULL
;
cDispmon("queue", MON_ERR
, "Unexpected command (%d) .. terminating!\n",
tf_putp(i
, oldest_t(q2
));
cWritemon("queue", MON_DEBUG
, " oldest=%d ", oldest_t(q2
));
cDispmon("queue", MON_DEBUG
, " status=%llx", status
);
tf_putlongp(0, status
, status
>> 32);