Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / legion / src / procs / sunsparc / debug / trace.c
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: trace.c
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
*
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
*
* The above named 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 work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ========== Copyright Header End ============================================
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "@(#)trace.c 1.8 07/01/09 SMI"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <assert.h>
#include <string.h>
#include "ss_common.h"
#include "niagara.h"
#if 1
#define DBGP(s) do { s } while (0)
#endif
void dbg_trace(simcpu_t *sp, uint32_t rawi);
void dbg_trace_parse(void);
void dbg_trace_dump(void);
static void dump_intregs(uint64_t *data);
/*
* Trace modes
* ALL = trace all instns for all values of %pc
* PC = start trace when "start" %pc is encountered
* stop when 'end' %pc is encountered.
* INSTN = only trace when instn count is within start-end range
*/
enum trace_modes { ALL, PC, INSTN };
/* start/end for pc,instn tracing */
uint32_t trace_mode;
char trace_mode_str[64];
uint64_t start_trace = 0x0;
uint64_t end_trace = 0x0;
bool_t dump_regs = false;
/*
* This will be called while parsing the conf file
* to allow this hook to parse specific options from
* the conf file.
*
* Format of trace directive is:
* debug_hook [trace] [mode] [regs] [start] [end];
*
* [trace] - we've already parsed this. That's how we got here.
* [mode] - is one of [all, pc, instn]
* all : traces all instns (no start, end values)
* pc : just trace when %pc is withing start-end range
* instn : just trace when instn count is within start-end
* [regs] - if defined, we dump the %g,%o,%l,%i regs with each sample.
* [start]
* [end] - only trace when %pc or inst_cnt is within [start]-[end]
* range
*
* examples:
* trace all;
* trace all regs;
* trace pc 0x123 0x456;
* trace pc regs 0x123 0x456;
* trace instn 0x123 0x456;
* trace instn regs 0x123 0x456;
*/
void
dbg_trace_parse(void)
{
lexer_tok_t tok;
DBGP(printf("\nInside dbg_trace_parse()"););
tok = lex_get_token(); /* trace mode */
strcpy(trace_mode_str, lex.strp);
if (streq(lex.strp, "all"))
trace_mode = ALL;
else if (streq(lex.strp, "pc"))
trace_mode = PC;
else if (streq(lex.strp, "instn"))
trace_mode = INSTN;
else
lex_fatal("unknown trace_mode [%s] parsing config", lex.strp);
/* parse optional regs token */
tok = lex_get_token();
if (streq(lex.strp, "regs")) {
dump_regs = true;
} else {
lex_unget(); /* no regs option, continue */
}
/*
* continue parsing conf file
*/
switch (trace_mode) {
case ALL:
break; /* no more parsing for 'all' mode */
case PC:
case INSTN:
lex_get(T_Number); /* start pc/instn */
start_trace = lex.val;
lex_get(T_Number); /* end pc/instn */
end_trace = lex.val;
break;
}
DBGP(printf("\ndbg_trace_parse: mode=%s, start=0x%llx, end=0x%llx",
trace_mode_str, start_trace, end_trace););
/*
* return to parse_debug_hook() which will take care
* of parsing the last semi colon.
*/
}
/*
* This function will get called before each instruction
* gets executed. For performance reasons, we may want to
* store the data in a buffer and post-process it later.
*/
void
dbg_trace(simcpu_t *sp, uint32_t rawi)
{
sparcv9_cpu_t *v9p;
char trace_buf[64];
static bool_t first_time = true;
/*
* If a trace range is given, we only trace within that
* range
*/
switch (trace_mode) {
case ALL:
break; /* trace everything */
case PC:
if ((sp->pc < start_trace) || (sp->pc > end_trace)) {
return; /* only trace when %pc is in range */
}
break;
case INSTN:
if ((sp->cycle < start_trace) ||
(sp->cycle > end_trace)) {
return; /* only trace when instn count is in range */
}
break;
}
v9p = (sparcv9_cpu_t *)sp->specificp;
sparcv9_idis(trace_buf, sizeof (trace_buf),
FE_INSTN(rawi), sp->pc);
if (first_time) {
printf("\n[cpu] Instn_# tl:tt/gl state %%pc [raw_instn]"
"\tinstn\n");
first_time = false;
}
/*
* When printing registers, we print them in their state prior to
* executing the instruction in question.
*/
if (dump_regs)
dump_intregs(sp->intreg);
printf("\n[0x%llx] 0x%llx %x:%x/%x 0x%x 0x%llx [0x%08x]\t%s",
sp->gid, sp->cycle,
v9p->tl,
(v9p->tl == 0) ? 0 : N_TT(v9p, v9p->tl),
v9p->gl,
v9p->state,
sp->pc,
FE_INSTN(rawi),
trace_buf);
}
static void
dump_intregs(uint64_t *intreg)
{
int i;
for (i = 0; i < 8; i++) {
printf("\ng%d=0x%016llx o%d=0x%016llx l%d=0x%016llx i%d=0x%016llx",
i, intreg[i],
i, intreg[i+8],
i, intreg[i+16],
i, intreg[i+24]);
}
}
void
dbg_trace_dump(void)
{
printf("\ndbg_trace_dump: caled with mode=%s, start=0x%llx, "\
"end=0x%llx\n", trace_mode_str, start_trace, end_trace);
}