mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-27 04:52:05 +08:00
7b01c1cc1d
In commit:
commit 60a3da00bd
Date: Sat Jan 22 11:38:18 2022 +0000
objdump/opcodes: add syntax highlighting to disassembler output
I broke several sim/ targets by forgetting to update their uses of the
libopcodes disassembler to take account of the new styled printing.
These should all be fixed by this commit.
I've not tried to add actual styled output to the simulator traces,
instead, the styled print routines just ignore the style and print the
output unstyled.
1361 lines
35 KiB
C
1361 lines
35 KiB
C
/* Simulator tracing/debugging support.
|
||
Copyright (C) 1997-2022 Free Software Foundation, Inc.
|
||
Contributed by Cygnus Support.
|
||
|
||
This file is part of GDB, the GNU debugger.
|
||
|
||
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; either version 3 of the License, or
|
||
(at your option) any later version.
|
||
|
||
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, see <http://www.gnu.org/licenses/>. */
|
||
|
||
/* This must come before any other includes. */
|
||
#include "defs.h"
|
||
|
||
#include <stdarg.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
#include "ansidecl.h"
|
||
#include "bfd.h"
|
||
#include "dis-asm.h"
|
||
#include "libiberty.h"
|
||
|
||
#include "sim-main.h"
|
||
#include "sim-assert.h"
|
||
#include "sim-io.h"
|
||
#include "sim-options.h"
|
||
#include "sim-fpu.h"
|
||
#include "sim/callback.h"
|
||
|
||
#ifndef SIZE_PHASE
|
||
#define SIZE_PHASE 8
|
||
#endif
|
||
|
||
#ifndef SIZE_LOCATION
|
||
#define SIZE_LOCATION 20
|
||
#endif
|
||
|
||
#ifndef SIZE_PC
|
||
#define SIZE_PC 6
|
||
#endif
|
||
|
||
#ifndef SIZE_LINE_NUMBER
|
||
#define SIZE_LINE_NUMBER 4
|
||
#endif
|
||
|
||
static MODULE_INIT_FN trace_init;
|
||
static MODULE_UNINSTALL_FN trace_uninstall;
|
||
|
||
static DECLARE_OPTION_HANDLER (trace_option_handler);
|
||
|
||
enum {
|
||
OPTION_TRACE_INSN = OPTION_START,
|
||
OPTION_TRACE_DISASM,
|
||
OPTION_TRACE_DECODE,
|
||
OPTION_TRACE_EXTRACT,
|
||
OPTION_TRACE_LINENUM,
|
||
OPTION_TRACE_MEMORY,
|
||
OPTION_TRACE_MODEL,
|
||
OPTION_TRACE_ALU,
|
||
OPTION_TRACE_CORE,
|
||
OPTION_TRACE_EVENTS,
|
||
OPTION_TRACE_FPU,
|
||
OPTION_TRACE_BRANCH,
|
||
OPTION_TRACE_SEMANTICS,
|
||
OPTION_TRACE_RANGE,
|
||
OPTION_TRACE_FUNCTION,
|
||
OPTION_TRACE_DEBUG,
|
||
OPTION_TRACE_FILE,
|
||
OPTION_TRACE_VPU,
|
||
OPTION_TRACE_SYSCALL,
|
||
OPTION_TRACE_REGISTER
|
||
};
|
||
|
||
static const OPTION trace_options[] =
|
||
{
|
||
/* This table is organized to group related instructions together. */
|
||
{ {"trace", optional_argument, NULL, 't'},
|
||
't', "on|off", "Trace useful things",
|
||
trace_option_handler, NULL },
|
||
{ {"trace-insn", optional_argument, NULL, OPTION_TRACE_INSN},
|
||
'\0', "on|off", "Perform instruction tracing",
|
||
trace_option_handler, NULL },
|
||
{ {"trace-disasm", optional_argument, NULL, OPTION_TRACE_DISASM},
|
||
'\0', "on|off", "Disassemble instructions (slower, but more accurate)",
|
||
trace_option_handler, NULL },
|
||
{ {"trace-decode", optional_argument, NULL, OPTION_TRACE_DECODE},
|
||
'\0', "on|off", "Trace instruction decoding",
|
||
trace_option_handler, NULL },
|
||
{ {"trace-extract", optional_argument, NULL, OPTION_TRACE_EXTRACT},
|
||
'\0', "on|off", "Trace instruction extraction",
|
||
trace_option_handler, NULL },
|
||
{ {"trace-linenum", optional_argument, NULL, OPTION_TRACE_LINENUM},
|
||
'\0', "on|off", "Perform line number tracing (implies --trace-insn)",
|
||
trace_option_handler, NULL },
|
||
{ {"trace-memory", optional_argument, NULL, OPTION_TRACE_MEMORY},
|
||
'\0', "on|off", "Trace memory operations",
|
||
trace_option_handler, NULL },
|
||
{ {"trace-alu", optional_argument, NULL, OPTION_TRACE_ALU},
|
||
'\0', "on|off", "Trace ALU (Arithmetic Logic Unit) operations",
|
||
trace_option_handler, NULL },
|
||
{ {"trace-fpu", optional_argument, NULL, OPTION_TRACE_FPU},
|
||
'\0', "on|off", "Trace FPU (Floating Point Unit) operations",
|
||
trace_option_handler, NULL },
|
||
{ {"trace-vpu", optional_argument, NULL, OPTION_TRACE_VPU},
|
||
'\0', "on|off", "Trace VPU (Vector Processing Unit) operations",
|
||
trace_option_handler, NULL },
|
||
{ {"trace-branch", optional_argument, NULL, OPTION_TRACE_BRANCH},
|
||
'\0', "on|off", "Trace branching",
|
||
trace_option_handler, NULL },
|
||
{ {"trace-semantics", optional_argument, NULL, OPTION_TRACE_SEMANTICS},
|
||
'\0', "on|off", "Perform ALU, FPU, VPU, MEMORY, and BRANCH tracing",
|
||
trace_option_handler, NULL },
|
||
{ {"trace-model", optional_argument, NULL, OPTION_TRACE_MODEL},
|
||
'\0', "on|off", "Include model performance data",
|
||
trace_option_handler, NULL },
|
||
{ {"trace-core", optional_argument, NULL, OPTION_TRACE_CORE},
|
||
'\0', "on|off", "Trace core operations",
|
||
trace_option_handler, NULL },
|
||
{ {"trace-events", optional_argument, NULL, OPTION_TRACE_EVENTS},
|
||
'\0', "on|off", "Trace events",
|
||
trace_option_handler, NULL },
|
||
{ {"trace-syscall", optional_argument, NULL, OPTION_TRACE_SYSCALL},
|
||
'\0', "on|off", "Trace system calls",
|
||
trace_option_handler, NULL },
|
||
{ {"trace-register", optional_argument, NULL, OPTION_TRACE_REGISTER},
|
||
'\0', "on|off", "Trace cpu register accesses",
|
||
trace_option_handler, NULL },
|
||
#ifdef SIM_HAVE_ADDR_RANGE
|
||
{ {"trace-range", required_argument, NULL, OPTION_TRACE_RANGE},
|
||
'\0', "START,END", "Specify range of addresses for instruction tracing",
|
||
trace_option_handler, NULL },
|
||
#if 0 /*wip*/
|
||
{ {"trace-function", required_argument, NULL, OPTION_TRACE_FUNCTION},
|
||
'\0', "FUNCTION", "Specify function to trace",
|
||
trace_option_handler, NULL },
|
||
#endif
|
||
#endif
|
||
{ {"trace-debug", optional_argument, NULL, OPTION_TRACE_DEBUG},
|
||
'\0', "on|off", "Add information useful for debugging the simulator to the tracing output",
|
||
trace_option_handler, NULL },
|
||
{ {"trace-file", required_argument, NULL, OPTION_TRACE_FILE},
|
||
'\0', "FILE NAME", "Specify tracing output file",
|
||
trace_option_handler, NULL },
|
||
{ {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL }
|
||
};
|
||
|
||
/* Set/reset the trace options indicated in MASK. */
|
||
|
||
static SIM_RC
|
||
set_trace_option_mask (SIM_DESC sd, const char *name, int mask, const char *arg)
|
||
{
|
||
int trace_nr;
|
||
int cpu_nr;
|
||
int trace_val = 1;
|
||
|
||
if (arg != NULL)
|
||
{
|
||
if (strcmp (arg, "yes") == 0
|
||
|| strcmp (arg, "on") == 0
|
||
|| strcmp (arg, "1") == 0)
|
||
trace_val = 1;
|
||
else if (strcmp (arg, "no") == 0
|
||
|| strcmp (arg, "off") == 0
|
||
|| strcmp (arg, "0") == 0)
|
||
trace_val = 0;
|
||
else
|
||
{
|
||
sim_io_eprintf (sd, "Argument `%s' for `--trace%s' invalid, one of `on', `off', `yes', `no' expected\n", arg, name);
|
||
return SIM_RC_FAIL;
|
||
}
|
||
}
|
||
|
||
/* Update applicable trace bits. */
|
||
for (trace_nr = 0; trace_nr < MAX_TRACE_VALUES; ++trace_nr)
|
||
{
|
||
if ((mask & (1 << trace_nr)) == 0)
|
||
continue;
|
||
|
||
/* Set non-cpu specific values. */
|
||
STATE_TRACE_FLAGS (sd)[trace_nr] = trace_val;
|
||
|
||
/* Set cpu values. */
|
||
for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++)
|
||
{
|
||
CPU_TRACE_FLAGS (STATE_CPU (sd, cpu_nr))[trace_nr] = trace_val;
|
||
}
|
||
}
|
||
|
||
/* Re-compute the cpu trace summary. */
|
||
if (trace_val)
|
||
{
|
||
for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++)
|
||
CPU_TRACE_DATA (STATE_CPU (sd, cpu_nr))->trace_any_p = 1;
|
||
}
|
||
else
|
||
{
|
||
for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++)
|
||
{
|
||
CPU_TRACE_DATA (STATE_CPU (sd, cpu_nr))->trace_any_p = 0;
|
||
for (trace_nr = 0; trace_nr < MAX_TRACE_VALUES; ++trace_nr)
|
||
{
|
||
if (CPU_TRACE_FLAGS (STATE_CPU (sd, cpu_nr))[trace_nr])
|
||
{
|
||
CPU_TRACE_DATA (STATE_CPU (sd, cpu_nr))->trace_any_p = 1;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return SIM_RC_OK;
|
||
}
|
||
|
||
/* Set one trace option based on its IDX value. */
|
||
|
||
static SIM_RC
|
||
set_trace_option (SIM_DESC sd, const char *name, int idx, const char *arg)
|
||
{
|
||
return set_trace_option_mask (sd, name, 1 << idx, arg);
|
||
}
|
||
|
||
|
||
static SIM_RC
|
||
trace_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
|
||
char *arg, int is_command)
|
||
{
|
||
int n;
|
||
|
||
switch (opt)
|
||
{
|
||
case 't' :
|
||
if (!WITH_TRACE_ANY_P)
|
||
sim_io_eprintf (sd, "Tracing not compiled in, `-t' ignored\n");
|
||
else
|
||
return set_trace_option_mask (sd, "trace", TRACE_USEFUL_MASK, arg);
|
||
break;
|
||
|
||
case OPTION_TRACE_INSN :
|
||
if (WITH_TRACE_INSN_P)
|
||
return set_trace_option (sd, "-insn", TRACE_INSN_IDX, arg);
|
||
else
|
||
sim_io_eprintf (sd, "Instruction tracing not compiled in, `--trace-insn' ignored\n");
|
||
break;
|
||
|
||
case OPTION_TRACE_DISASM :
|
||
if (WITH_TRACE_DISASM_P)
|
||
return set_trace_option (sd, "-disasm", TRACE_DISASM_IDX, arg);
|
||
else
|
||
sim_io_eprintf (sd, "Instruction tracing not compiled in, `--trace-disasm' ignored\n");
|
||
break;
|
||
|
||
case OPTION_TRACE_DECODE :
|
||
if (WITH_TRACE_DECODE_P)
|
||
return set_trace_option (sd, "-decode", TRACE_DECODE_IDX, arg);
|
||
else
|
||
sim_io_eprintf (sd, "Decode tracing not compiled in, `--trace-decode' ignored\n");
|
||
break;
|
||
|
||
case OPTION_TRACE_EXTRACT :
|
||
if (WITH_TRACE_EXTRACT_P)
|
||
return set_trace_option (sd, "-extract", TRACE_EXTRACT_IDX, arg);
|
||
else
|
||
sim_io_eprintf (sd, "Extract tracing not compiled in, `--trace-extract' ignored\n");
|
||
break;
|
||
|
||
case OPTION_TRACE_LINENUM :
|
||
if (WITH_TRACE_LINENUM_P && WITH_TRACE_INSN_P)
|
||
{
|
||
if (set_trace_option (sd, "-linenum", TRACE_LINENUM_IDX, arg) != SIM_RC_OK
|
||
|| set_trace_option (sd, "-linenum", TRACE_INSN_IDX, arg) != SIM_RC_OK)
|
||
return SIM_RC_FAIL;
|
||
}
|
||
else
|
||
sim_io_eprintf (sd, "Line number or instruction tracing not compiled in, `--trace-linenum' ignored\n");
|
||
break;
|
||
|
||
case OPTION_TRACE_MEMORY :
|
||
if (WITH_TRACE_MEMORY_P)
|
||
return set_trace_option (sd, "-memory", TRACE_MEMORY_IDX, arg);
|
||
else
|
||
sim_io_eprintf (sd, "Memory tracing not compiled in, `--trace-memory' ignored\n");
|
||
break;
|
||
|
||
case OPTION_TRACE_MODEL :
|
||
if (WITH_TRACE_MODEL_P)
|
||
return set_trace_option (sd, "-model", TRACE_MODEL_IDX, arg);
|
||
else
|
||
sim_io_eprintf (sd, "Model tracing not compiled in, `--trace-model' ignored\n");
|
||
break;
|
||
|
||
case OPTION_TRACE_ALU :
|
||
if (WITH_TRACE_ALU_P)
|
||
return set_trace_option (sd, "-alu", TRACE_ALU_IDX, arg);
|
||
else
|
||
sim_io_eprintf (sd, "ALU tracing not compiled in, `--trace-alu' ignored\n");
|
||
break;
|
||
|
||
case OPTION_TRACE_CORE :
|
||
if (WITH_TRACE_CORE_P)
|
||
return set_trace_option (sd, "-core", TRACE_CORE_IDX, arg);
|
||
else
|
||
sim_io_eprintf (sd, "CORE tracing not compiled in, `--trace-core' ignored\n");
|
||
break;
|
||
|
||
case OPTION_TRACE_EVENTS :
|
||
if (WITH_TRACE_EVENTS_P)
|
||
return set_trace_option (sd, "-events", TRACE_EVENTS_IDX, arg);
|
||
else
|
||
sim_io_eprintf (sd, "EVENTS tracing not compiled in, `--trace-events' ignored\n");
|
||
break;
|
||
|
||
case OPTION_TRACE_FPU :
|
||
if (WITH_TRACE_FPU_P)
|
||
return set_trace_option (sd, "-fpu", TRACE_FPU_IDX, arg);
|
||
else
|
||
sim_io_eprintf (sd, "FPU tracing not compiled in, `--trace-fpu' ignored\n");
|
||
break;
|
||
|
||
case OPTION_TRACE_VPU :
|
||
if (WITH_TRACE_VPU_P)
|
||
return set_trace_option (sd, "-vpu", TRACE_VPU_IDX, arg);
|
||
else
|
||
sim_io_eprintf (sd, "VPU tracing not compiled in, `--trace-vpu' ignored\n");
|
||
break;
|
||
|
||
case OPTION_TRACE_BRANCH :
|
||
if (WITH_TRACE_BRANCH_P)
|
||
return set_trace_option (sd, "-branch", TRACE_BRANCH_IDX, arg);
|
||
else
|
||
sim_io_eprintf (sd, "Branch tracing not compiled in, `--trace-branch' ignored\n");
|
||
break;
|
||
|
||
case OPTION_TRACE_SYSCALL :
|
||
if (WITH_TRACE_SYSCALL_P)
|
||
return set_trace_option (sd, "-syscall", TRACE_SYSCALL_IDX, arg);
|
||
else
|
||
sim_io_eprintf (sd, "System call tracing not compiled in, `--trace-syscall' ignored\n");
|
||
break;
|
||
|
||
case OPTION_TRACE_REGISTER :
|
||
if (WITH_TRACE_REGISTER_P)
|
||
return set_trace_option (sd, "-register", TRACE_REGISTER_IDX, arg);
|
||
else
|
||
sim_io_eprintf (sd, "Register tracing not compiled in, `--trace-register' ignored\n");
|
||
break;
|
||
|
||
case OPTION_TRACE_SEMANTICS :
|
||
if (WITH_TRACE_ALU_P
|
||
&& WITH_TRACE_FPU_P
|
||
&& WITH_TRACE_MEMORY_P
|
||
&& WITH_TRACE_BRANCH_P)
|
||
{
|
||
if (set_trace_option (sd, "-semantics", TRACE_ALU_IDX, arg) != SIM_RC_OK
|
||
|| set_trace_option (sd, "-semantics", TRACE_FPU_IDX, arg) != SIM_RC_OK
|
||
|| set_trace_option (sd, "-semantics", TRACE_VPU_IDX, arg) != SIM_RC_OK
|
||
|| set_trace_option (sd, "-semantics", TRACE_MEMORY_IDX, arg) != SIM_RC_OK
|
||
|| set_trace_option (sd, "-semantics", TRACE_BRANCH_IDX, arg) != SIM_RC_OK)
|
||
return SIM_RC_FAIL;
|
||
}
|
||
else
|
||
sim_io_eprintf (sd, "Alu, fpu, memory, and/or branch tracing not compiled in, `--trace-semantics' ignored\n");
|
||
break;
|
||
|
||
#ifdef SIM_HAVE_ADDR_RANGE
|
||
case OPTION_TRACE_RANGE :
|
||
if (WITH_TRACE_ANY_P)
|
||
{
|
||
int cpu_nr;
|
||
char *chp = arg;
|
||
unsigned long start,end;
|
||
start = strtoul (chp, &chp, 0);
|
||
if (*chp != ',')
|
||
{
|
||
sim_io_eprintf (sd, "--trace-range missing END argument\n");
|
||
return SIM_RC_FAIL;
|
||
}
|
||
end = strtoul (chp + 1, NULL, 0);
|
||
/* FIXME: Argument validation. */
|
||
if (cpu != NULL)
|
||
sim_addr_range_add (TRACE_RANGE (CPU_PROFILE_DATA (cpu)),
|
||
start, end);
|
||
else
|
||
for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr)
|
||
sim_addr_range_add (TRACE_RANGE (CPU_TRACE_DATA (STATE_CPU (sd, cpu_nr))),
|
||
start, end);
|
||
}
|
||
else
|
||
sim_io_eprintf (sd, "Tracing not compiled in, `--trace-range' ignored\n");
|
||
break;
|
||
|
||
case OPTION_TRACE_FUNCTION :
|
||
if (WITH_TRACE_ANY_P)
|
||
{
|
||
/*wip: need to compute function range given name*/
|
||
}
|
||
else
|
||
sim_io_eprintf (sd, "Tracing not compiled in, `--trace-function' ignored\n");
|
||
break;
|
||
#endif /* SIM_HAVE_ADDR_RANGE */
|
||
|
||
case OPTION_TRACE_DEBUG :
|
||
if (WITH_TRACE_DEBUG_P)
|
||
return set_trace_option (sd, "-debug", TRACE_DEBUG_IDX, arg);
|
||
else
|
||
sim_io_eprintf (sd, "Tracing debug support not compiled in, `--trace-debug' ignored\n");
|
||
break;
|
||
|
||
case OPTION_TRACE_FILE :
|
||
if (!WITH_TRACE_ANY_P)
|
||
sim_io_eprintf (sd, "Tracing not compiled in, `--trace-file' ignored\n");
|
||
else
|
||
{
|
||
FILE *f = fopen (arg, "w");
|
||
|
||
if (f == NULL)
|
||
{
|
||
sim_io_eprintf (sd, "Unable to open trace output file `%s'\n", arg);
|
||
return SIM_RC_FAIL;
|
||
}
|
||
for (n = 0; n < MAX_NR_PROCESSORS; ++n)
|
||
TRACE_FILE (CPU_TRACE_DATA (STATE_CPU (sd, n))) = f;
|
||
TRACE_FILE (STATE_TRACE_DATA (sd)) = f;
|
||
}
|
||
break;
|
||
}
|
||
|
||
return SIM_RC_OK;
|
||
}
|
||
|
||
/* Provide a prototype to silence -Wmissing-prototypes. */
|
||
SIM_RC sim_install_trace (SIM_DESC sd);
|
||
|
||
/* Install tracing support. */
|
||
SIM_RC
|
||
sim_install_trace (SIM_DESC sd)
|
||
{
|
||
int i;
|
||
|
||
SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
|
||
|
||
sim_add_option_table (sd, NULL, trace_options);
|
||
memset (STATE_TRACE_DATA (sd), 0, sizeof (* STATE_TRACE_DATA (sd)));
|
||
for (i = 0; i < MAX_NR_PROCESSORS; ++i)
|
||
memset (CPU_TRACE_DATA (STATE_CPU (sd, i)), 0,
|
||
sizeof (* CPU_TRACE_DATA (STATE_CPU (sd, i))));
|
||
sim_module_add_init_fn (sd, trace_init);
|
||
sim_module_add_uninstall_fn (sd, trace_uninstall);
|
||
return SIM_RC_OK;
|
||
}
|
||
|
||
static SIM_RC
|
||
trace_init (SIM_DESC sd)
|
||
{
|
||
#ifdef SIM_HAVE_ADDR_RANGE
|
||
/* Check if a range has been specified without specifying what to
|
||
collect. */
|
||
{
|
||
int i;
|
||
|
||
for (i = 0; i < MAX_NR_PROCESSORS; ++i)
|
||
{
|
||
sim_cpu *cpu = STATE_CPU (sd, i);
|
||
|
||
if (ADDR_RANGE_RANGES (TRACE_RANGE (CPU_TRACE_DATA (cpu)))
|
||
&& ! TRACE_INSN_P (cpu))
|
||
{
|
||
sim_io_eprintf_cpu (cpu, "Tracing address range specified without --trace-insn.\n");
|
||
sim_io_eprintf_cpu (cpu, "Address range ignored.\n");
|
||
sim_addr_range_delete (TRACE_RANGE (CPU_TRACE_DATA (cpu)),
|
||
0, ~ (address_word) 0);
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
|
||
return SIM_RC_OK;
|
||
}
|
||
|
||
static void
|
||
trace_uninstall (SIM_DESC sd)
|
||
{
|
||
int i,j;
|
||
FILE *sfile = TRACE_FILE (STATE_TRACE_DATA (sd));
|
||
|
||
if (sfile != NULL)
|
||
fclose (sfile);
|
||
|
||
for (i = 0; i < MAX_NR_PROCESSORS; ++i)
|
||
{
|
||
FILE *cfile = TRACE_FILE (CPU_TRACE_DATA (STATE_CPU (sd, i)));
|
||
if (cfile != NULL && cfile != sfile)
|
||
{
|
||
/* If output from different cpus is going to the same file,
|
||
avoid closing the file twice. */
|
||
for (j = 0; j < i; ++j)
|
||
if (TRACE_FILE (CPU_TRACE_DATA (STATE_CPU (sd, j))) == cfile)
|
||
break;
|
||
if (i == j)
|
||
fclose (cfile);
|
||
}
|
||
}
|
||
|
||
if (STATE_PROG_SYMS (sd))
|
||
free (STATE_PROG_SYMS (sd));
|
||
}
|
||
|
||
/* compute the nr of trace data units consumed by data */
|
||
static int
|
||
save_data_size (TRACE_DATA *data,
|
||
long size)
|
||
{
|
||
return ((size + sizeof (TRACE_INPUT_DATA (data) [0]) - 1)
|
||
/ sizeof (TRACE_INPUT_DATA (data) [0]));
|
||
}
|
||
|
||
|
||
/* Archive DATA into the trace buffer */
|
||
void
|
||
save_data (SIM_DESC sd,
|
||
TRACE_DATA *data,
|
||
data_fmt fmt,
|
||
long size,
|
||
const void *buf)
|
||
{
|
||
int i = TRACE_INPUT_IDX (data);
|
||
if (i == sizeof (TRACE_INPUT_FMT (data)))
|
||
sim_io_error (sd, "trace buffer overflow");
|
||
TRACE_INPUT_FMT (data) [i] = fmt;
|
||
TRACE_INPUT_SIZE (data) [i] = size;
|
||
memcpy (&TRACE_INPUT_DATA (data) [i], buf, size);
|
||
i += save_data_size (data, size);
|
||
TRACE_INPUT_IDX (data) = i;
|
||
}
|
||
|
||
static void
|
||
print_data (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
data_fmt fmt,
|
||
long size,
|
||
void *data)
|
||
{
|
||
switch (fmt)
|
||
{
|
||
case trace_fmt_instruction_incomplete:
|
||
trace_printf (sd, cpu, " (instruction incomplete)");
|
||
break;
|
||
case trace_fmt_word:
|
||
case trace_fmt_addr:
|
||
{
|
||
switch (size)
|
||
{
|
||
case sizeof (uint32_t):
|
||
trace_printf (sd, cpu, " 0x%08lx", (long) * (uint32_t*) data);
|
||
break;
|
||
case sizeof (uint64_t):
|
||
trace_printf (sd, cpu, " 0x%08lx%08lx",
|
||
(long) ((* (uint64_t*) data) >> 32),
|
||
(long) * (uint64_t*) data);
|
||
break;
|
||
default:
|
||
abort ();
|
||
}
|
||
break;
|
||
}
|
||
case trace_fmt_bool:
|
||
{
|
||
SIM_ASSERT (size == sizeof (int));
|
||
trace_printf (sd, cpu, " %-8s",
|
||
(* (int*) data) ? "true" : "false");
|
||
break;
|
||
}
|
||
case trace_fmt_fp:
|
||
{
|
||
sim_fpu fp;
|
||
switch (size)
|
||
{
|
||
/* FIXME: Assumes sizeof float == 4; sizeof double == 8 */
|
||
case 4:
|
||
sim_fpu_32to (&fp, *(uint32_t*)data);
|
||
break;
|
||
case 8:
|
||
sim_fpu_64to (&fp, *(uint64_t*)data);
|
||
break;
|
||
default:
|
||
abort ();
|
||
}
|
||
trace_printf (sd, cpu, " %8g", sim_fpu_2d (&fp));
|
||
switch (size)
|
||
{
|
||
case 4:
|
||
trace_printf (sd, cpu, " (0x%08lx)",
|
||
(long) *(uint32_t*)data);
|
||
break;
|
||
case 8:
|
||
trace_printf (sd, cpu, " (0x%08lx%08lx)",
|
||
(long) (*(uint64_t*)data >> 32),
|
||
(long) (*(uint64_t*)data));
|
||
break;
|
||
default:
|
||
abort ();
|
||
}
|
||
break;
|
||
}
|
||
case trace_fmt_fpu:
|
||
/* FIXME: At present sim_fpu data is stored as a double */
|
||
trace_printf (sd, cpu, " %8g", * (double*) data);
|
||
break;
|
||
case trace_fmt_string:
|
||
trace_printf (sd, cpu, " %-8s", (char*) data);
|
||
break;
|
||
default:
|
||
abort ();
|
||
}
|
||
}
|
||
|
||
static const char *
|
||
trace_idx_to_str (int trace_idx)
|
||
{
|
||
static char num[8];
|
||
switch (trace_idx)
|
||
{
|
||
case TRACE_ALU_IDX: return "alu: ";
|
||
case TRACE_INSN_IDX: return "insn: ";
|
||
case TRACE_DISASM_IDX: return "disasm: ";
|
||
case TRACE_DECODE_IDX: return "decode: ";
|
||
case TRACE_EXTRACT_IDX: return "extract: ";
|
||
case TRACE_MEMORY_IDX: return "memory: ";
|
||
case TRACE_CORE_IDX: return "core: ";
|
||
case TRACE_EVENTS_IDX: return "events: ";
|
||
case TRACE_FPU_IDX: return "fpu: ";
|
||
case TRACE_BRANCH_IDX: return "branch: ";
|
||
case TRACE_SYSCALL_IDX: return "syscall: ";
|
||
case TRACE_REGISTER_IDX: return "reg: ";
|
||
case TRACE_VPU_IDX: return "vpu: ";
|
||
default:
|
||
sprintf (num, "?%d?", trace_idx);
|
||
return num;
|
||
}
|
||
}
|
||
|
||
static void
|
||
trace_results (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
int last_input)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
int nr_out;
|
||
int i;
|
||
|
||
/* cross check trace_idx against TRACE_IDX (data)? */
|
||
|
||
/* prefix */
|
||
trace_printf (sd, cpu, "%s %s",
|
||
trace_idx_to_str (TRACE_IDX (data)),
|
||
TRACE_PREFIX (data));
|
||
TRACE_IDX (data) = 0;
|
||
|
||
for (i = 0, nr_out = 0;
|
||
i < TRACE_INPUT_IDX (data);
|
||
i += save_data_size (data, TRACE_INPUT_SIZE (data) [i]), nr_out++)
|
||
{
|
||
if (i == last_input)
|
||
{
|
||
int pad = (strlen (" 0x") + sizeof (unsigned_word) * 2);
|
||
int padding = pad * (3 - nr_out);
|
||
if (padding < 0)
|
||
padding = 0;
|
||
padding += strlen (" ::");
|
||
trace_printf (sd, cpu, "%*s", padding, " ::");
|
||
}
|
||
print_data (sd, cpu,
|
||
TRACE_INPUT_FMT (data) [i],
|
||
TRACE_INPUT_SIZE (data) [i],
|
||
&TRACE_INPUT_DATA (data) [i]);
|
||
}
|
||
trace_printf (sd, cpu, "\n");
|
||
}
|
||
|
||
int
|
||
trace_load_symbols (SIM_DESC sd)
|
||
{
|
||
bfd *abfd;
|
||
asymbol **asymbols;
|
||
long symsize;
|
||
long symbol_count;
|
||
|
||
/* Already loaded, so nothing to do. */
|
||
if (STATE_PROG_SYMS (sd))
|
||
return 1;
|
||
|
||
abfd = STATE_PROG_BFD (sd);
|
||
if (abfd == NULL)
|
||
return 0;
|
||
|
||
symsize = bfd_get_symtab_upper_bound (abfd);
|
||
if (symsize < 0)
|
||
return 0;
|
||
|
||
asymbols = xmalloc (symsize);
|
||
symbol_count = bfd_canonicalize_symtab (abfd, asymbols);
|
||
if (symbol_count < 0)
|
||
{
|
||
free (asymbols);
|
||
return 0;
|
||
}
|
||
|
||
STATE_PROG_SYMS (sd) = asymbols;
|
||
STATE_PROG_SYMS_COUNT (sd) = symbol_count;
|
||
return 1;
|
||
}
|
||
|
||
bfd_vma
|
||
trace_sym_value (SIM_DESC sd, const char *name)
|
||
{
|
||
asymbol **asymbols;
|
||
long i;
|
||
|
||
if (!trace_load_symbols (sd))
|
||
return -1;
|
||
|
||
asymbols = STATE_PROG_SYMS (sd);
|
||
|
||
for (i = 0; i < STATE_PROG_SYMS_COUNT (sd); ++i)
|
||
if (strcmp (asymbols[i]->name, name) == 0)
|
||
return bfd_asymbol_value (asymbols[i]);
|
||
|
||
return -1;
|
||
}
|
||
|
||
void
|
||
trace_prefix (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
sim_cia cia,
|
||
address_word pc,
|
||
int line_p,
|
||
const char *filename,
|
||
int linenum,
|
||
const char *fmt,
|
||
...)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
va_list ap;
|
||
char *prefix = TRACE_PREFIX (data);
|
||
char *chp;
|
||
/* FIXME: The TRACE_PREFIX_WIDTH should be determined at build time using
|
||
known information about the disassembled instructions. */
|
||
#ifndef TRACE_PREFIX_WIDTH
|
||
#define TRACE_PREFIX_WIDTH 48
|
||
#endif
|
||
int width = TRACE_PREFIX_WIDTH;
|
||
|
||
/* if the previous trace data wasn't flushed, flush it now with a
|
||
note indicating that the trace was incomplete. */
|
||
if (TRACE_IDX (data) != 0)
|
||
{
|
||
int last_input = TRACE_INPUT_IDX (data);
|
||
save_data (sd, data, trace_fmt_instruction_incomplete, 1, "");
|
||
trace_results (sd, cpu, TRACE_IDX (data), last_input);
|
||
}
|
||
TRACE_IDX (data) = 0;
|
||
TRACE_INPUT_IDX (data) = 0;
|
||
|
||
/* Create the text prefix for this new instruction: */
|
||
if (!line_p)
|
||
{
|
||
if (filename)
|
||
{
|
||
sprintf (prefix, "%s:%-*d 0x%.*lx ",
|
||
filename,
|
||
SIZE_LINE_NUMBER, linenum,
|
||
SIZE_PC, (long) pc);
|
||
}
|
||
else
|
||
{
|
||
sprintf (prefix, "0x%.*lx ",
|
||
SIZE_PC, (long) pc);
|
||
/* Shrink the width by the amount that we didn't print. */
|
||
width -= SIZE_LINE_NUMBER + SIZE_PC + 8;
|
||
}
|
||
chp = strchr (prefix, '\0');
|
||
va_start (ap, fmt);
|
||
vsprintf (chp, fmt, ap);
|
||
va_end (ap);
|
||
}
|
||
else
|
||
{
|
||
char buf[256];
|
||
buf[0] = 0;
|
||
if (STATE_TEXT_SECTION (sd)
|
||
&& pc >= STATE_TEXT_START (sd)
|
||
&& pc < STATE_TEXT_END (sd))
|
||
{
|
||
const char *pc_filename = (const char *)0;
|
||
const char *pc_function = (const char *)0;
|
||
unsigned int pc_linenum = 0;
|
||
bfd *abfd;
|
||
asymbol **asymbols;
|
||
|
||
if (!trace_load_symbols (sd))
|
||
sim_engine_abort (sd, cpu, cia, "could not load symbols");
|
||
|
||
abfd = STATE_PROG_BFD (sd);
|
||
asymbols = STATE_PROG_SYMS (sd);
|
||
|
||
if (bfd_find_nearest_line (abfd, STATE_TEXT_SECTION (sd), asymbols,
|
||
pc - STATE_TEXT_START (sd),
|
||
&pc_filename, &pc_function, &pc_linenum))
|
||
{
|
||
char *p = buf;
|
||
if (pc_linenum)
|
||
{
|
||
sprintf (p, "#%-*d ", SIZE_LINE_NUMBER, pc_linenum);
|
||
p += strlen (p);
|
||
}
|
||
else
|
||
{
|
||
sprintf (p, "%-*s ", SIZE_LINE_NUMBER+1, "---");
|
||
p += SIZE_LINE_NUMBER+2;
|
||
}
|
||
|
||
if (pc_function)
|
||
{
|
||
sprintf (p, "%s ", pc_function);
|
||
p += strlen (p);
|
||
}
|
||
else if (pc_filename)
|
||
{
|
||
char *q = (char *) strrchr (pc_filename, '/');
|
||
sprintf (p, "%s ", (q) ? q+1 : pc_filename);
|
||
p += strlen (p);
|
||
}
|
||
|
||
if (*p == ' ')
|
||
*p = '\0';
|
||
}
|
||
}
|
||
|
||
sprintf (prefix, "0x%.*x %-*.*s ",
|
||
SIZE_PC, (unsigned) pc,
|
||
SIZE_LOCATION, SIZE_LOCATION, buf);
|
||
chp = strchr (prefix, '\0');
|
||
va_start (ap, fmt);
|
||
vsprintf (chp, fmt, ap);
|
||
va_end (ap);
|
||
}
|
||
|
||
/* Pad it out to TRACE_PREFIX_WIDTH. */
|
||
chp = strchr (prefix, '\0');
|
||
if (chp - prefix < width)
|
||
{
|
||
memset (chp, ' ', width - (chp - prefix));
|
||
chp = &prefix [width];
|
||
*chp = '\0';
|
||
}
|
||
strcpy (chp, " -");
|
||
|
||
/* check that we've not over flowed the prefix buffer */
|
||
if (strlen (prefix) >= sizeof (TRACE_PREFIX (data)))
|
||
abort ();
|
||
}
|
||
|
||
void
|
||
trace_generic (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
const char *fmt,
|
||
...)
|
||
{
|
||
va_list ap;
|
||
trace_printf (sd, cpu, "%s %s",
|
||
trace_idx_to_str (trace_idx),
|
||
TRACE_PREFIX (CPU_TRACE_DATA (cpu)));
|
||
va_start (ap, fmt);
|
||
trace_vprintf (sd, cpu, fmt, ap);
|
||
va_end (ap);
|
||
trace_printf (sd, cpu, "\n");
|
||
}
|
||
|
||
static int
|
||
dis_read (bfd_vma memaddr, bfd_byte *myaddr, unsigned int length,
|
||
struct disassemble_info *dinfo)
|
||
{
|
||
SIM_CPU *cpu = dinfo->application_data;
|
||
sim_core_read_buffer (CPU_STATE (cpu), cpu, NULL_CIA, myaddr, memaddr, length);
|
||
return 0;
|
||
}
|
||
|
||
static int ATTRIBUTE_PRINTF (2, 3)
|
||
dis_printf (SIM_CPU *cpu, const char *fmt, ...)
|
||
{
|
||
SIM_DESC sd = CPU_STATE (cpu);
|
||
va_list ap;
|
||
va_start (ap, fmt);
|
||
trace_vprintf (sd, cpu, fmt, ap);
|
||
va_end (ap);
|
||
return 0;
|
||
}
|
||
|
||
static int ATTRIBUTE_PRINTF (3, 4)
|
||
dis_styled_printf (SIM_CPU *cpu, enum disassembler_style style,
|
||
const char *fmt, ...)
|
||
{
|
||
SIM_DESC sd = CPU_STATE (cpu);
|
||
va_list ap;
|
||
va_start (ap, fmt);
|
||
trace_vprintf (sd, cpu, fmt, ap);
|
||
va_end (ap);
|
||
return 0;
|
||
}
|
||
|
||
void
|
||
trace_disasm (SIM_DESC sd, sim_cpu *cpu, address_word addr)
|
||
{
|
||
struct bfd *bfd = STATE_PROG_BFD (sd);
|
||
TRACE_DATA *trace_data = CPU_TRACE_DATA (cpu);
|
||
disassemble_info *info = &trace_data->dis_info;
|
||
|
||
/* See if we need to set up the disassembly func. */
|
||
if (trace_data->dis_bfd != bfd)
|
||
{
|
||
trace_data->dis_bfd = bfd;
|
||
trace_data->disassembler
|
||
= disassembler (bfd_get_arch (trace_data->dis_bfd),
|
||
bfd_big_endian (trace_data->dis_bfd),
|
||
bfd_get_mach (trace_data->dis_bfd),
|
||
trace_data->dis_bfd);
|
||
INIT_DISASSEMBLE_INFO (*info, cpu, dis_printf, dis_styled_printf);
|
||
info->read_memory_func = dis_read;
|
||
info->arch = bfd_get_arch (bfd);
|
||
info->mach = bfd_get_mach (bfd);
|
||
disassemble_init_for_target (info);
|
||
}
|
||
|
||
info->application_data = cpu;
|
||
|
||
trace_printf (sd, cpu, "%s %s",
|
||
trace_idx_to_str (TRACE_DISASM_IDX),
|
||
TRACE_PREFIX (trace_data));
|
||
trace_data->disassembler (addr, info);
|
||
trace_printf (sd, cpu, "\n");
|
||
}
|
||
|
||
void
|
||
trace_input0 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
TRACE_IDX (data) = trace_idx;
|
||
}
|
||
|
||
void
|
||
trace_input_word1 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
unsigned_word d0)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
TRACE_IDX (data) = trace_idx;
|
||
save_data (sd, data, trace_fmt_word, sizeof (unsigned_word), &d0);
|
||
}
|
||
|
||
void
|
||
trace_input_word2 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
unsigned_word d0,
|
||
unsigned_word d1)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
TRACE_IDX (data) = trace_idx;
|
||
save_data (sd, data, trace_fmt_word, sizeof (unsigned_word), &d0);
|
||
save_data (sd, data, trace_fmt_word, sizeof (unsigned_word), &d1);
|
||
}
|
||
|
||
void
|
||
trace_input_word3 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
unsigned_word d0,
|
||
unsigned_word d1,
|
||
unsigned_word d2)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
TRACE_IDX (data) = trace_idx;
|
||
save_data (sd, data, trace_fmt_word, sizeof (unsigned_word), &d0);
|
||
save_data (sd, data, trace_fmt_word, sizeof (unsigned_word), &d1);
|
||
save_data (sd, data, trace_fmt_word, sizeof (unsigned_word), &d2);
|
||
}
|
||
|
||
void
|
||
trace_input_word4 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
unsigned_word d0,
|
||
unsigned_word d1,
|
||
unsigned_word d2,
|
||
unsigned_word d3)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
TRACE_IDX (data) = trace_idx;
|
||
save_data (sd, data, trace_fmt_word, sizeof (d0), &d0);
|
||
save_data (sd, data, trace_fmt_word, sizeof (d1), &d1);
|
||
save_data (sd, data, trace_fmt_word, sizeof (d2), &d2);
|
||
save_data (sd, data, trace_fmt_word, sizeof (d3), &d3);
|
||
}
|
||
|
||
void
|
||
trace_input_bool1 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
int d0)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
TRACE_IDX (data) = trace_idx;
|
||
save_data (sd, data, trace_fmt_bool, sizeof (d0), &d0);
|
||
}
|
||
|
||
void
|
||
trace_input_addr1 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
address_word d0)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
TRACE_IDX (data) = trace_idx;
|
||
save_data (sd, data, trace_fmt_addr, sizeof (d0), &d0);
|
||
}
|
||
|
||
void
|
||
trace_input_fp1 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
fp_word f0)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
TRACE_IDX (data) = trace_idx;
|
||
save_data (sd, data, trace_fmt_fp, sizeof (fp_word), &f0);
|
||
}
|
||
|
||
void
|
||
trace_input_fp2 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
fp_word f0,
|
||
fp_word f1)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
TRACE_IDX (data) = trace_idx;
|
||
save_data (sd, data, trace_fmt_fp, sizeof (fp_word), &f0);
|
||
save_data (sd, data, trace_fmt_fp, sizeof (fp_word), &f1);
|
||
}
|
||
|
||
void
|
||
trace_input_fp3 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
fp_word f0,
|
||
fp_word f1,
|
||
fp_word f2)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
TRACE_IDX (data) = trace_idx;
|
||
save_data (sd, data, trace_fmt_fp, sizeof (fp_word), &f0);
|
||
save_data (sd, data, trace_fmt_fp, sizeof (fp_word), &f1);
|
||
save_data (sd, data, trace_fmt_fp, sizeof (fp_word), &f2);
|
||
}
|
||
|
||
void
|
||
trace_input_fpu1 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
sim_fpu *f0)
|
||
{
|
||
double d;
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
TRACE_IDX (data) = trace_idx;
|
||
d = sim_fpu_2d (f0);
|
||
save_data (sd, data, trace_fmt_fp, sizeof (double), &d);
|
||
}
|
||
|
||
void
|
||
trace_input_fpu2 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
sim_fpu *f0,
|
||
sim_fpu *f1)
|
||
{
|
||
double d;
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
TRACE_IDX (data) = trace_idx;
|
||
d = sim_fpu_2d (f0);
|
||
save_data (sd, data, trace_fmt_fp, sizeof (double), &d);
|
||
d = sim_fpu_2d (f1);
|
||
save_data (sd, data, trace_fmt_fp, sizeof (double), &d);
|
||
}
|
||
|
||
void
|
||
trace_input_fpu3 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
sim_fpu *f0,
|
||
sim_fpu *f1,
|
||
sim_fpu *f2)
|
||
{
|
||
double d;
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
TRACE_IDX (data) = trace_idx;
|
||
d = sim_fpu_2d (f0);
|
||
save_data (sd, data, trace_fmt_fp, sizeof (double), &d);
|
||
d = sim_fpu_2d (f1);
|
||
save_data (sd, data, trace_fmt_fp, sizeof (double), &d);
|
||
d = sim_fpu_2d (f2);
|
||
save_data (sd, data, trace_fmt_fp, sizeof (double), &d);
|
||
}
|
||
|
||
void
|
||
trace_result_word1 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
unsigned_word r0)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
int last_input;
|
||
|
||
/* Append any results to the end of the inputs */
|
||
last_input = TRACE_INPUT_IDX (data);
|
||
save_data (sd, data, trace_fmt_word, sizeof (unsigned_word), &r0);
|
||
|
||
trace_results (sd, cpu, trace_idx, last_input);
|
||
}
|
||
|
||
void
|
||
trace_result0 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
int last_input;
|
||
|
||
/* Append any results to the end of the inputs */
|
||
last_input = TRACE_INPUT_IDX (data);
|
||
|
||
trace_results (sd, cpu, trace_idx, last_input);
|
||
}
|
||
|
||
void
|
||
trace_result_word2 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
unsigned_word r0,
|
||
unsigned_word r1)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
int last_input;
|
||
|
||
/* Append any results to the end of the inputs */
|
||
last_input = TRACE_INPUT_IDX (data);
|
||
save_data (sd, data, trace_fmt_word, sizeof (r0), &r0);
|
||
save_data (sd, data, trace_fmt_word, sizeof (r1), &r1);
|
||
|
||
trace_results (sd, cpu, trace_idx, last_input);
|
||
}
|
||
|
||
void
|
||
trace_result_word4 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
unsigned_word r0,
|
||
unsigned_word r1,
|
||
unsigned_word r2,
|
||
unsigned_word r3)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
int last_input;
|
||
|
||
/* Append any results to the end of the inputs */
|
||
last_input = TRACE_INPUT_IDX (data);
|
||
save_data (sd, data, trace_fmt_word, sizeof (r0), &r0);
|
||
save_data (sd, data, trace_fmt_word, sizeof (r1), &r1);
|
||
save_data (sd, data, trace_fmt_word, sizeof (r2), &r2);
|
||
save_data (sd, data, trace_fmt_word, sizeof (r3), &r3);
|
||
|
||
trace_results (sd, cpu, trace_idx, last_input);
|
||
}
|
||
|
||
void
|
||
trace_result_bool1 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
int r0)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
int last_input;
|
||
|
||
/* Append any results to the end of the inputs */
|
||
last_input = TRACE_INPUT_IDX (data);
|
||
save_data (sd, data, trace_fmt_bool, sizeof (r0), &r0);
|
||
|
||
trace_results (sd, cpu, trace_idx, last_input);
|
||
}
|
||
|
||
void
|
||
trace_result_addr1 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
address_word r0)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
int last_input;
|
||
|
||
/* Append any results to the end of the inputs */
|
||
last_input = TRACE_INPUT_IDX (data);
|
||
save_data (sd, data, trace_fmt_addr, sizeof (r0), &r0);
|
||
|
||
trace_results (sd, cpu, trace_idx, last_input);
|
||
}
|
||
|
||
void
|
||
trace_result_fp1 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
fp_word f0)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
int last_input;
|
||
|
||
/* Append any results to the end of the inputs */
|
||
last_input = TRACE_INPUT_IDX (data);
|
||
save_data (sd, data, trace_fmt_fp, sizeof (fp_word), &f0);
|
||
|
||
trace_results (sd, cpu, trace_idx, last_input);
|
||
}
|
||
|
||
void
|
||
trace_result_fp2 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
fp_word f0,
|
||
fp_word f1)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
int last_input;
|
||
|
||
/* Append any results to the end of the inputs */
|
||
last_input = TRACE_INPUT_IDX (data);
|
||
save_data (sd, data, trace_fmt_fp, sizeof (f0), &f0);
|
||
save_data (sd, data, trace_fmt_fp, sizeof (f1), &f1);
|
||
|
||
trace_results (sd, cpu, trace_idx, last_input);
|
||
}
|
||
|
||
void
|
||
trace_result_fpu1 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
sim_fpu *f0)
|
||
{
|
||
double d;
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
int last_input;
|
||
|
||
/* Append any results to the end of the inputs */
|
||
last_input = TRACE_INPUT_IDX (data);
|
||
d = sim_fpu_2d (f0);
|
||
save_data (sd, data, trace_fmt_fp, sizeof (double), &d);
|
||
|
||
trace_results (sd, cpu, trace_idx, last_input);
|
||
}
|
||
|
||
void
|
||
trace_result_string1 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
char *s0)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
int last_input;
|
||
|
||
/* Append any results to the end of the inputs */
|
||
last_input = TRACE_INPUT_IDX (data);
|
||
save_data (sd, data, trace_fmt_string, strlen (s0) + 1, s0);
|
||
|
||
trace_results (sd, cpu, trace_idx, last_input);
|
||
}
|
||
|
||
void
|
||
trace_result_word1_string1 (SIM_DESC sd,
|
||
sim_cpu *cpu,
|
||
int trace_idx,
|
||
unsigned_word r0,
|
||
char *s0)
|
||
{
|
||
TRACE_DATA *data = CPU_TRACE_DATA (cpu);
|
||
int last_input;
|
||
|
||
/* Append any results to the end of the inputs */
|
||
last_input = TRACE_INPUT_IDX (data);
|
||
save_data (sd, data, trace_fmt_word, sizeof (unsigned_word), &r0);
|
||
save_data (sd, data, trace_fmt_string, strlen (s0) + 1, s0);
|
||
|
||
trace_results (sd, cpu, trace_idx, last_input);
|
||
}
|
||
|
||
void
|
||
trace_vprintf (SIM_DESC sd, sim_cpu *cpu, const char *fmt, va_list ap)
|
||
{
|
||
if (cpu != NULL)
|
||
{
|
||
if (TRACE_FILE (CPU_TRACE_DATA (cpu)) != NULL)
|
||
vfprintf (TRACE_FILE (CPU_TRACE_DATA (cpu)), fmt, ap);
|
||
else
|
||
sim_io_evprintf (sd, fmt, ap);
|
||
}
|
||
else
|
||
{
|
||
if (TRACE_FILE (STATE_TRACE_DATA (sd)) != NULL)
|
||
vfprintf (TRACE_FILE (STATE_TRACE_DATA (sd)), fmt, ap);
|
||
else
|
||
sim_io_evprintf (sd, fmt, ap);
|
||
}
|
||
}
|
||
|
||
void
|
||
trace_printf (SIM_DESC sd, sim_cpu *cpu, const char *fmt, ...)
|
||
{
|
||
va_list ap;
|
||
|
||
va_start (ap, fmt);
|
||
|
||
trace_vprintf (sd, cpu, fmt, ap);
|
||
|
||
va_end (ap);
|
||
}
|
||
|
||
void
|
||
sim_debug_printf (sim_cpu *cpu, const char *fmt, ...)
|
||
{
|
||
va_list ap;
|
||
|
||
va_start (ap, fmt);
|
||
|
||
if (CPU_DEBUG_FILE (cpu) == NULL)
|
||
(* STATE_CALLBACK (CPU_STATE (cpu))->evprintf_filtered)
|
||
(STATE_CALLBACK (CPU_STATE (cpu)), fmt, ap);
|
||
else
|
||
vfprintf (CPU_DEBUG_FILE (cpu), fmt, ap);
|
||
|
||
va_end (ap);
|
||
}
|