*/
-/* The TRACE manifests enable the provision of extra features. If they
- are not defined then a simpler (quicker) simulator is constructed
- without the required run-time checks, etc. */
-#if 1 /* 0 to allow user build selection, 1 to force inclusion */
-#define TRACE (1)
-#endif
-
#include "config.h"
#include "bfd.h"
#include "sim-main.h"
#include "getopt.h"
#include "libiberty.h"
#include "bfd.h"
+#include "elf-bfd.h"
#include "gdb/callback.h" /* GDB simulator callback interface */
#include "gdb/remote-sim.h" /* GDB simulator interface */
trap is required. NOTE: Care must be taken, since this value may be
used in later revisions of the MIPS ISA. */
-#define RSVD_INSTRUCTION (0x00000005)
+#define RSVD_INSTRUCTION (0x00000039)
#define RSVD_INSTRUCTION_MASK (0xFC00003F)
#define RSVD_INSTRUCTION_ARG_SHIFT 6
static SIM_RC sim_firmware_command (SIM_DESC sd, char* arg);
-
#define MEM_SIZE (8 << 20) /* 8 MBytes */
-#if defined(TRACE)
+#if WITH_TRACE_ANY_P
static char *tracefile = "trace.din"; /* default filename for trace log */
FILE *tracefh = NULL;
static void open_trace (SIM_DESC sd);
-#endif /* TRACE */
+#else
+#define open_trace(sd)
+#endif
static const char * get_insn_name (sim_cpu *, int);
switch (opt)
{
case OPTION_DINERO_TRACE: /* ??? */
-#if defined(TRACE)
+#if WITH_TRACE_ANY_P
/* Eventually the simTRACE flag could be treated as a toggle, to
allow external control of the program points being traced
(i.e. only from main onwards, excluding the run-time setup,
}
}
return SIM_RC_OK;
-#else /* !TRACE */
+#else /* !WITH_TRACE_ANY_P */
fprintf(stderr,"\
Simulator constructed without dinero tracing support (for performance).\n\
-Re-compile simulator with \"-DTRACE\" to enable this option.\n");
+Re-compile simulator with \"-DWITH_TRACE_ANY_P\" to enable this option.\n");
return SIM_RC_FAIL;
-#endif /* !TRACE */
+#endif /* !WITH_TRACE_ANY_P */
case OPTION_DINERO_FILE:
-#if defined(TRACE)
+#if WITH_TRACE_ANY_P
if (optarg != NULL) {
char *tmp;
tmp = (char *)malloc(strlen(optarg) + 1);
sim_io_printf(sd,"Placing trace information into file \"%s\"\n",tracefile);
}
}
-#endif /* TRACE */
+#endif /* WITH_TRACE_ANY_P */
return SIM_RC_OK;
case OPTION_FIRMWARE:
PC = pc;
}
+static int mips_reg_fetch (SIM_CPU *, int, unsigned char *, int);
+static int mips_reg_store (SIM_CPU *, int, unsigned char *, int);
+
SIM_DESC
-sim_open (SIM_OPEN_KIND kind, host_callback *cb, struct bfd *abfd, char **argv)
+sim_open (SIM_OPEN_KIND kind, host_callback *cb,
+ struct bfd *abfd, char * const *argv)
{
int i;
SIM_DESC sd = sim_state_alloc (kind, cb);
sim_add_option_table (sd, NULL, mips_options);
- /* getopt will print the error message so we just have to exit if this fails.
- FIXME: Hmmm... in the case of gdb we need getopt to call
- print_filtered. */
+ /* The parser will print an error message for us, so we silently return. */
if (sim_parse_args (sd, argv) != SIM_RC_OK)
{
/* Uninstall the modules to avoid memory leaks,
/* Look for largest memory region defined on command-line at
phys address 0. */
-#ifdef SIM_HAVE_FLATMEM
- mem_size = STATE_MEM_SIZE (sd);
-#endif
for (entry = STATE_MEMOPT (sd); entry != NULL; entry = entry->next)
{
/* If we find an entry at address 0, then we will end up
}
-#if defined(TRACE)
if (STATE & simTRACE)
open_trace(sd);
-#endif /* TRACE */
/*
sim_io_eprintf (sd, "idt@%x pmon@%x lsipmon@%x\n",
{
SIM_CPU *cpu = STATE_CPU (sd, i);
+ CPU_REG_FETCH (cpu) = mips_reg_fetch;
+ CPU_REG_STORE (cpu) = mips_reg_store;
CPU_PC_FETCH (cpu) = mips_pc_get;
CPU_PC_STORE (cpu) = mips_pc_set;
}
return sd;
}
-#if defined(TRACE)
+#if WITH_TRACE_ANY_P
static void
open_trace (SIM_DESC sd)
{
tracefh = stderr;
}
}
-#endif /* TRACE */
+#endif
/* Return name of an insn, used by insn profiling. */
static const char *
}
void
-sim_close (SIM_DESC sd, int quitting)
+mips_sim_close (SIM_DESC sd, int quitting)
{
-#ifdef DEBUG
- printf("DBG: sim_close: entered (quitting = %d)\n",quitting);
-#endif
-
-
- /* "quitting" is non-zero if we cannot hang on errors */
-
- /* shut down modules */
- sim_module_uninstall (sd);
-
- /* Ensure that any resources allocated through the callback
- mechanism are released: */
- sim_io_shutdown (sd);
-
-#if defined(TRACE)
+#if WITH_TRACE_ANY_P
if (tracefh != NULL && tracefh != stderr)
fclose(tracefh);
tracefh = NULL;
-#endif /* TRACE */
-
- /* FIXME - free SD */
-
- return;
-}
-
-
-int
-sim_write (SIM_DESC sd, SIM_ADDR addr, const unsigned char *buffer, int size)
-{
- int index;
- sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
-
- /* Return the number of bytes written, or zero if error. */
-#ifdef DEBUG
- sim_io_printf(sd,"sim_write(0x%s,buffer,%d);\n",pr_addr(addr),size);
#endif
-
- /* We use raw read and write routines, since we do not want to count
- the GDB memory accesses in our statistics gathering. */
-
- for (index = 0; index < size; index++)
- {
- address_word vaddr = (address_word)addr + index;
- address_word paddr;
- int cca;
- if (!address_translation (SD, CPU, NULL_CIA, vaddr, isDATA, isSTORE, &paddr, &cca, isRAW))
- break;
- if (sim_core_write_buffer (SD, CPU, read_map, buffer + index, paddr, 1) != 1)
- break;
- }
-
- return(index);
}
-int
-sim_read (SIM_DESC sd, SIM_ADDR addr, unsigned char *buffer, int size)
+static int
+mips_reg_store (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
{
- int index;
- sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
-
- /* Return the number of bytes read, or zero if error. */
-#ifdef DEBUG
- sim_io_printf(sd,"sim_read(0x%s,buffer,%d);\n",pr_addr(addr),size);
-#endif /* DEBUG */
-
- for (index = 0; (index < size); index++)
- {
- address_word vaddr = (address_word)addr + index;
- address_word paddr;
- int cca;
- if (!address_translation (SD, CPU, NULL_CIA, vaddr, isDATA, isLOAD, &paddr, &cca, isRAW))
- break;
- if (sim_core_read_buffer (SD, CPU, read_map, buffer + index, paddr, 1) != 1)
- break;
- }
-
- return(index);
-}
-
-int
-sim_store_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
-{
- sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
/* NOTE: gdb (the client) stores registers in target byte order
while the simulator uses host byte order */
-#ifdef DEBUG
- sim_io_printf(sd,"sim_store_register(%d,*memory=0x%s);\n",rn,pr_addr(*((SIM_ADDR *)memory)));
-#endif /* DEBUG */
/* Unfortunately this suffers from the same problem as the register
numbering one. We need to know what the width of each logical
if (cpu->register_widths[rn] == 0)
{
- sim_io_eprintf(sd,"Invalid register width for %d (register store ignored)\n",rn);
+ sim_io_eprintf (CPU_STATE (cpu), "Invalid register width for %d (register store ignored)\n", rn);
return 0;
}
-
-
if (rn >= FGR_BASE && rn < FGR_BASE + NR_FGR)
{
cpu->fpr_state[rn - FGR_BASE] = fmt_uninterpreted;
return 0;
}
-int
-sim_fetch_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
+static int
+mips_reg_fetch (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
{
- sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
/* NOTE: gdb (the client) stores registers in target byte order
while the simulator uses host byte order */
-#ifdef DEBUG
-#if 0 /* FIXME: doesn't compile */
- sim_io_printf(sd,"sim_fetch_register(%d=0x%s,mem) : place simulator registers into memory\n",rn,pr_addr(registers[rn]));
-#endif
-#endif /* DEBUG */
if (cpu->register_widths[rn] == 0)
{
- sim_io_eprintf (sd, "Invalid register width for %d (register fetch ignored)\n",rn);
+ sim_io_eprintf (CPU_STATE (cpu), "Invalid register width for %d (register fetch ignored)\n", rn);
return 0;
}
-
-
/* Any floating point register */
if (rn >= FGR_BASE && rn < FGR_BASE + NR_FGR)
{
}
SIM_RC
-sim_create_inferior (SIM_DESC sd, struct bfd *abfd, char **argv, char **env)
+sim_create_inferior (SIM_DESC sd, struct bfd *abfd,
+ char * const *argv, char * const *env)
{
#ifdef DEBUG
for (cpu_nr = 0; cpu_nr < sim_engine_nr_cpus (sd); cpu_nr++)
{
sim_cpu *cpu = STATE_CPU (sd, cpu_nr);
- CPU_PC_SET (cpu, (unsigned64) bfd_get_start_address (abfd));
+ sim_cia pc = bfd_get_start_address (abfd);
+
+ /* We need to undo brain-dead bfd behavior where it sign-extends
+ addresses that are supposed to be unsigned. See the mips bfd
+ sign_extend_vma setting. We have to check the ELF data itself
+ in order to handle o32 & n32 ABIs. */
+ if (abfd->tdata.elf_obj_data->elf_header->e_ident[EI_CLASS] ==
+ ELFCLASS32)
+ pc = (unsigned32) pc;
+
+ CPU_PC_SET (cpu, pc);
}
}
uword64 vaddr,
signed_word val)
{
- address_word paddr;
- int uncached;
+ address_word paddr = vaddr;
if ((vaddr & 3) != 0)
SignalExceptionAddressStore ();
else
{
- if (AddressTranslation (vaddr, isDATA, isSTORE, &paddr, &uncached,
- isTARGET, isREAL))
- {
- const uword64 mask = 7;
- uword64 memval;
- unsigned int byte;
-
- paddr = (paddr & ~mask) | ((paddr & mask) ^ (ReverseEndian << 2));
- byte = (vaddr & mask) ^ (BigEndianCPU << 2);
- memval = ((uword64) val) << (8 * byte);
- StoreMemory (uncached, AccessLength_WORD, memval, 0, paddr, vaddr,
- isREAL);
- }
+ const uword64 mask = 7;
+ uword64 memval;
+ unsigned int byte;
+
+ paddr = (paddr & ~mask) | ((paddr & mask) ^ (ReverseEndian << 2));
+ byte = (vaddr & mask) ^ (BigEndianCPU << 2);
+ memval = ((uword64) val) << (8 * byte);
+ StoreMemory (AccessLength_WORD, memval, 0, paddr, vaddr,
+ isREAL);
}
}
}
else
{
- address_word paddr;
- int uncached;
-
- if (AddressTranslation (vaddr, isDATA, isLOAD, &paddr, &uncached,
- isTARGET, isREAL))
- {
- const uword64 mask = 0x7;
- const unsigned int reverse = ReverseEndian ? 1 : 0;
- const unsigned int bigend = BigEndianCPU ? 1 : 0;
- uword64 memval;
- unsigned int byte;
-
- paddr = (paddr & ~mask) | ((paddr & mask) ^ (reverse << 2));
- LoadMemory (&memval,NULL,uncached, AccessLength_WORD, paddr, vaddr,
- isDATA, isREAL);
- byte = (vaddr & mask) ^ (bigend << 2);
- return EXTEND32 (memval >> (8 * byte));
- }
+ address_word paddr = vaddr;
+ const uword64 mask = 0x7;
+ const unsigned int reverse = ReverseEndian ? 1 : 0;
+ const unsigned int bigend = BigEndianCPU ? 1 : 0;
+ uword64 memval;
+ unsigned int byte;
+
+ paddr = (paddr & ~mask) | ((paddr & mask) ^ (reverse << 2));
+ LoadMemory (&memval, NULL, AccessLength_WORD, paddr, vaddr, isDATA,
+ isREAL);
+ byte = (vaddr & mask) ^ (bigend << 2);
+ return EXTEND32 (memval >> (8 * byte));
}
return 0;
/*-- trace support ----------------------------------------------------------*/
-/* The TRACE support is provided (if required) in the memory accessing
+/* The trace support is provided (if required) in the memory accessing
routines. Since we are also providing the architecture specific
features, the architecture simulation code can also deal with
- notifying the TRACE world of cache flushes, etc. Similarly we do
+ notifying the trace world of cache flushes, etc. Similarly we do
not need to provide profiling support in the simulator engine,
since we can sample in the instruction fetch control loop. By
- defining the TRACE manifest, we add tracing as a run-time
+ defining the trace manifest, we add tracing as a run-time
option. */
-#if defined(TRACE)
+#if WITH_TRACE_ANY_P
/* Tracing by default produces "din" format (as required by
dineroIII). Each line of such a trace file *MUST* have a din label
and address field. The rest of the line is ignored, so comments can
return;
}
-#endif /* TRACE */
+#endif /* WITH_TRACE_ANY_P */
/*---------------------------------------------------------------------------*/
/*-- simulator engine -------------------------------------------------------*/
decode_coproc (SIM_DESC sd,
sim_cpu *cpu,
address_word cia,
- unsigned int instruction)
+ unsigned int instruction,
+ int coprocnum,
+ CP0_operation op,
+ int rt,
+ int rd,
+ int sel)
{
- int coprocnum = ((instruction >> 26) & 3);
-
switch (coprocnum)
{
case 0: /* standard CPU control and cache registers */
{
- int code = ((instruction >> 21) & 0x1F);
- int rt = ((instruction >> 16) & 0x1F);
- int rd = ((instruction >> 11) & 0x1F);
- int tail = instruction & 0x3ff;
/* R4000 Users Manual (second edition) lists the following CP0
instructions:
CODE><-RT><RD-><--TAIL--->
CACHE Cache operation (VR4100 = 101111bbbbbpppppiiiiiiiiiiiiiiii)
ERET Exception return (VR4100 = 01000010000000000000000000011000)
*/
- if (((code == 0x00) || (code == 0x04) /* MFC0 / MTC0 */
- || (code == 0x01) || (code == 0x05)) /* DMFC0 / DMTC0 */
- && tail == 0)
+ if (((op == cp0_mfc0) || (op == cp0_mtc0) /* MFC0 / MTC0 */
+ || (op == cp0_dmfc0) || (op == cp0_dmtc0)) /* DMFC0 / DMTC0 */
+ && sel == 0)
{
- /* Clear double/single coprocessor move bit. */
- code &= ~1;
-
- /* M[TF]C0 (32 bits) | DM[TF]C0 (64 bits) */
-
switch (rd) /* NOTEs: Standard CP0 registers */
{
/* 0 = Index R4000 VR4100 VR4300 */
case 8:
/* 8 = BadVAddr R4000 VR4100 VR4300 */
- if (code == 0x00)
+ if (op == cp0_mfc0 || op == cp0_dmfc0)
GPR[rt] = (signed_word) (signed_address) COP0_BADVADDR;
else
COP0_BADVADDR = GPR[rt];
#endif /* SUBTARGET_R3900 */
case 12:
- if (code == 0x00)
+ if (op == cp0_mfc0 || op == cp0_dmfc0)
GPR[rt] = SR;
else
SR = GPR[rt];
break;
/* 13 = Cause R4000 VR4100 VR4300 */
case 13:
- if (code == 0x00)
+ if (op == cp0_mfc0 || op == cp0_dmfc0)
GPR[rt] = CAUSE;
else
CAUSE = GPR[rt];
break;
/* 14 = EPC R4000 VR4100 VR4300 */
case 14:
- if (code == 0x00)
+ if (op == cp0_mfc0 || op == cp0_dmfc0)
GPR[rt] = (signed_word) (signed_address) EPC;
else
EPC = GPR[rt];
#ifdef SUBTARGET_R3900
/* 16 = Debug */
case 16:
- if (code == 0x00)
+ if (op == cp0_mfc0 || op == cp0_dmfc0)
GPR[rt] = Debug;
else
Debug = GPR[rt];
#else
/* 16 = Config R4000 VR4100 VR4300 */
case 16:
- if (code == 0x00)
+ if (op == cp0_mfc0 || op == cp0_dmfc0)
GPR[rt] = C0_CONFIG;
else
/* only bottom three bits are writable */
#ifdef SUBTARGET_R3900
/* 17 = Debug */
case 17:
- if (code == 0x00)
+ if (op == cp0_mfc0 || op == cp0_dmfc0)
GPR[rt] = DEPC;
else
DEPC = GPR[rt];
GPR[rt] = 0xDEADC0DE; /* CPR[0,rd] */
/* CPR[0,rd] = GPR[rt]; */
default:
- if (code == 0x00)
+ if (op == cp0_mfc0 || op == cp0_dmfc0)
GPR[rt] = (signed_word) (signed32) COP0_GPR[rd];
else
COP0_GPR[rd] = GPR[rt];
#endif
}
}
- else if ((code == 0x00 || code == 0x01)
+ else if ((op == cp0_mfc0 || op == cp0_dmfc0)
&& rd == 16)
{
/* [D]MFC0 RT,C0_CONFIG,SEL */
signed32 cfg = 0;
- switch (tail & 0x07)
+ switch (sel)
{
case 0:
cfg = C0_CONFIG;
}
GPR[rt] = cfg;
}
- else if (code == 0x10 && (tail & 0x3f) == 0x18)
+ else if (op == cp0_eret && sel == 0x18)
{
/* ERET */
if (SR & status_ERL)
SR &= ~status_EXL;
}
}
- else if (code == 0x10 && (tail & 0x3f) == 0x10)
+ else if (op == cp0_rfe && sel == 0x10)
{
/* RFE */
#ifdef SUBTARGET_R3900
/* TODO: CACHE register */
#endif /* SUBTARGET_R3900 */
}
- else if (code == 0x10 && (tail & 0x3f) == 0x1F)
+ else if (op == cp0_deret && sel == 0x1F)
{
/* DERET */
Debug &= ~Debug_DM;