THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- $Revision$
- $Author$
- $Date$
-
NOTEs:
-We only need to take account of the target endianness when moving data
-between the simulator and the host. We do not need to worry about the
-endianness of the host, since this sim code and GDB are executing in
-the same process.
-
The IDT monitor (found on the VR4300 board), seems to lie about
register contents. It seems to treat the registers as sign-extended
32-bit values. This cause *REAL* problems when single-stepping 64-bit
*/
-/* The TRACE and PROFILE 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. */
+/* 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)
-#define PROFILE (1)
#endif
#include "bfd.h"
#include "sim-utils.h"
#include "sim-options.h"
#include "sim-assert.h"
+#include "sim-hw.h"
+
+#include "itable.h"
+
#include "config.h"
#include <stdio.h>
#include <stdarg.h>
#include <ansidecl.h>
-#include <signal.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
#include "getopt.h"
#include "libiberty.h"
#include "bfd.h"
-#include "callback.h" /* GDB simulator callback interface */
-#include "remote-sim.h" /* GDB simulator interface */
-
-#include "support.h" /* internal support manifests */
+#include "gdb/callback.h" /* GDB simulator callback interface */
+#include "gdb/remote-sim.h" /* GDB simulator interface */
#include "sysdep.h"
char* pr_addr PARAMS ((SIM_ADDR addr));
char* pr_uword64 PARAMS ((uword64 addr));
-#ifndef SIGBUS
-#define SIGBUS SIGSEGV
-#endif
-/* Get the simulator engine description, without including the code: */
-#define SIM_MANIFESTS
-#include "engine.c"
-#undef SIM_MANIFESTS
+/* Within interp.c we refer to the sim_state and sim_cpu directly. */
+#define CPU cpu
+#define SD sd
-struct sim_state simulator;
/* The following reserved instruction value is used when a simulator
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_MASK (0xFC00003F)
#define RSVD_INSTRUCTION_ARG_MASK 0xFFFFF
-/* NOTE: These numbers depend on the processor architecture being
- simulated: */
-#define Interrupt (0)
-#define TLBModification (1)
-#define TLBLoad (2)
-#define TLBStore (3)
-#define AddressLoad (4)
-#define AddressStore (5)
-#define InstructionFetch (6)
-#define DataReference (7)
-#define SystemCall (8)
-#define BreakPoint (9)
-#define ReservedInstruction (10)
-#define CoProcessorUnusable (11)
-#define IntegerOverflow (12) /* Arithmetic overflow (IDT monitor raises SIGFPE) */
-#define Trap (13)
-#define FPE (15)
-#define Watch (23)
-
-/* The following exception code is actually private to the simulator
- world. It is *NOT* a processor feature, and is used to signal
- run-time errors in the simulator. */
-#define SimulatorFault (0xFFFFFFFF)
-
-/* The following are generic to all versions of the MIPS architecture
- to date: */
-/* Memory Access Types (for CCA): */
-#define Uncached (0)
-#define CachedNoncoherent (1)
-#define CachedCoherent (2)
-#define Cached (3)
-
-#define isINSTRUCTION (1 == 0) /* FALSE */
-#define isDATA (1 == 1) /* TRUE */
-
-#define isLOAD (1 == 0) /* FALSE */
-#define isSTORE (1 == 1) /* TRUE */
-
-#define isREAL (1 == 0) /* FALSE */
-#define isRAW (1 == 1) /* TRUE */
-
-#define isTARGET (1 == 0) /* FALSE */
-#define isHOST (1 == 1) /* TRUE */
-
-/* The "AccessLength" specifications for Loads and Stores. NOTE: This
- is the number of bytes minus 1. */
-#define AccessLength_BYTE (0)
-#define AccessLength_HALFWORD (1)
-#define AccessLength_TRIPLEBYTE (2)
-#define AccessLength_WORD (3)
-#define AccessLength_QUINTIBYTE (4)
-#define AccessLength_SEXTIBYTE (5)
-#define AccessLength_SEPTIBYTE (6)
-#define AccessLength_DOUBLEWORD (7)
-#define AccessLength_QUADWORD (15)
-
-#if defined(HASFPU)
-/* FPU registers must be one of the following types. All other values
- are reserved (and undefined). */
-typedef enum {
- fmt_single = 0,
- fmt_double = 1,
- fmt_word = 4,
- fmt_long = 5,
- /* The following are well outside the normal acceptable format
- range, and are used in the register status vector. */
- fmt_unknown = 0x10000000,
- fmt_uninterpreted = 0x20000000,
-} FP_formats;
-#endif /* HASFPU */
-
-/* NOTE: We cannot avoid globals, since the GDB "sim_" interface does
- not allow a private variable to be passed around. This means that
- simulators under GDB can only be single-threaded. However, it would
- be possible for the simulators to be multi-threaded if GDB allowed
- for a private pointer to be maintained. i.e. a general "void **ptr"
- variable that GDB passed around in the argument list to all of
- sim_xxx() routines. It could be initialised to NULL by GDB, and
- then updated by sim_open() and used by the other sim_xxx() support
- functions. This would allow new features in the simulator world,
- like storing a context - continuing execution to gather a result,
- and then going back to the point where the context was saved and
- changing some state before continuing. i.e. the ability to perform
- UNDOs on simulations. It would also allow the simulation of
- shared-memory multi-processor systems.
-
- [NOTE: This is now partially implemented] */
-
-static host_callback *callback = NULL; /* handle onto the current callback structure */
-
-/* This is nasty, since we have to rely on matching the register
- numbers used by GDB. Unfortunately, depending on the MIPS target
- GDB uses different register numbers. We cannot just include the
- relevant "gdb/tm.h" link, since GDB may not be configured before
- the sim world, and also the GDB header file requires too much other
- state. */
-/* TODO: Sort out a scheme for *KNOWING* the mapping between real
- registers, and the numbers that GDB uses. At the moment due to the
- order that the tools are built, we cannot rely on a configured GDB
- world whilst constructing the simulator. This means we have to
- assume the GDB register number mapping. */
-#ifndef TM_MIPS_H
-#define LAST_EMBED_REGNUM (89)
-#endif
-
-/* To keep this default simulator simple, and fast, we use a direct
- vector of registers. The internal simulator engine then uses
- manifests to access the correct slot. */
-static ut_reg registers[LAST_EMBED_REGNUM + 1];
-static int register_widths[LAST_EMBED_REGNUM + 1];
-
-#define GPR (®isters[0])
-#if defined(HASFPU)
-#define FGRIDX (38)
-#define FGR (®isters[FGRIDX])
-#endif /* HASFPU */
-#define LO (registers[33])
-#define HI (registers[34])
-#define PC (registers[37])
-#define CAUSE (registers[36])
-#define SRIDX (32)
-#define SR (registers[SRIDX]) /* CPU status register */
-#define FCR0IDX (71)
-#define FCR0 (registers[FCR0IDX]) /* really a 32bit register */
-#define FCR31IDX (70)
-#define FCR31 (registers[FCR31IDX]) /* really a 32bit register */
-#define FCSR (FCR31)
-#define COCIDX (LAST_EMBED_REGNUM + 2) /* special case : outside the normal range */
-
-/* The following are pseudonyms for standard registers */
-#define ZERO (registers[0])
-#define V0 (registers[2])
-#define A0 (registers[4])
-#define A1 (registers[5])
-#define A2 (registers[6])
-#define A3 (registers[7])
-#define SP (registers[29])
-#define RA (registers[31])
-
-
-/* start-sanitize-r5900 */
-/*
-The R5900 has 128 bit registers, but the hi 64 bits are only touched by
-multimedia (MMI) instructions. The normal mips instructions just use the
-lower 64 bits. To avoid changing the older parts of the simulator to
-handle this weirdness, the high 64 bits of each register are kept in
-a separate array (registers1). The high 64 bits of any register are by
-convention refered by adding a '1' to the end of the normal register's
-name. So LO still refers to the low 64 bits of the LO register, LO1
-refers to the high 64 bits of that same register.
-*/
-
-/* The high part of each register */
-static ut_reg registers1[LAST_EMBED_REGNUM + 1];
-
-#define GPR1 (®isters1[0])
-
-#define LO1 (registers1[33])
-#define HI1 (registers1[34])
-
-#define BYTES_IN_MMI_REGS (sizeof(registers[0])+sizeof(registers1[0]))
-#define HALFWORDS_IN_MMI_REGS (BYTES_IN_MMI_REGS/2)
-#define WORDS_IN_MMI_REGS (BYTES_IN_MMI_REGS/4)
-#define DOUBLEWORDS_IN_MMI_REGS (BYTES_IN_MMI_REGS/8)
-
-#define BYTES_IN_MIPS_REGS (sizeof(registers[0]))
-#define HALFWORDS_IN_MIPS_REGS (BYTES_IN_MIPS_REGS/2)
-#define WORDS_IN_MIPS_REGS (BYTES_IN_MIPS_REGS/4)
-#define DOUBLEWORDS_IN_MIPS_REGS (BYTES_IN_MIPS_REGS/8)
-
-
-/*
-SUB_REG_FETCH - return as lvalue some sub-part of a "register"
- T - type of the sub part
- TC - # of T's in the mips part of the "register"
- I - index (from 0) of desired sub part
- A - low part of "register"
- A1 - high part of register
-*/
-#define SUB_REG_FETCH(T,TC,A,A1,I) (*(((T*)(((I) < (TC)) ? (A) : (A1))) + ((I) % (TC))))
-
-/*
-GPR_<type>(R,I) - return, as lvalue, the I'th <type> of general register R
- where <type> has two letters:
- 1 is S=signed or U=unsigned
- 2 is B=byte H=halfword W=word D=doubleword
-*/
-
-#define SUB_REG_SB(A,A1,I) SUB_REG_FETCH(signed char, BYTES_IN_MIPS_REGS, A, A1, I)
-#define SUB_REG_SH(A,A1,I) SUB_REG_FETCH(signed short, HALFWORDS_IN_MIPS_REGS, A, A1, I)
-#define SUB_REG_SW(A,A1,I) SUB_REG_FETCH(signed int, WORDS_IN_MIPS_REGS, A, A1, I)
-#define SUB_REG_SD(A,A1,I) SUB_REG_FETCH(signed long long, DOUBLEWORDS_IN_MIPS_REGS, A, A1, I)
-
-#define SUB_REG_UB(A,A1,I) SUB_REG_FETCH(unsigned char, BYTES_IN_MIPS_REGS, A, A1, I)
-#define SUB_REG_UH(A,A1,I) SUB_REG_FETCH(unsigned short, HALFWORDS_IN_MIPS_REGS, A, A1, I)
-#define SUB_REG_UW(A,A1,I) SUB_REG_FETCH(unsigned int, WORDS_IN_MIPS_REGS, A, A1, I)
-#define SUB_REG_UD(A,A1,I) SUB_REG_FETCH(unsigned long long,DOUBLEWORDS_IN_MIPS_REGS, A, A1, I)
-
-
-
-#define GPR_SB(R,I) SUB_REG_SB(®isters[R], ®isters1[R], I)
-#define GPR_SH(R,I) SUB_REG_SH(®isters[R], ®isters1[R], I)
-#define GPR_SW(R,I) SUB_REG_SW(®isters[R], ®isters1[R], I)
-#define GPR_SD(R,I) SUB_REG_SD(®isters[R], ®isters1[R], I)
-
-#define GPR_UB(R,I) SUB_REG_UB(®isters[R], ®isters1[R], I)
-#define GPR_UH(R,I) SUB_REG_UH(®isters[R], ®isters1[R], I)
-#define GPR_UW(R,I) SUB_REG_UW(®isters[R], ®isters1[R], I)
-#define GPR_UD(R,I) SUB_REG_UD(®isters[R], ®isters1[R], I)
-
-
-#define RS_SB(I) SUB_REG_SB(&rs_reg, &rs_reg1, I)
-#define RS_SH(I) SUB_REG_SH(&rs_reg, &rs_reg1, I)
-#define RS_SW(I) SUB_REG_SW(&rs_reg, &rs_reg1, I)
-#define RS_SD(I) SUB_REG_SD(&rs_reg, &rs_reg1, I)
-
-#define RS_UB(I) SUB_REG_UB(&rs_reg, &rs_reg1, I)
-#define RS_UH(I) SUB_REG_UH(&rs_reg, &rs_reg1, I)
-#define RS_UW(I) SUB_REG_UW(&rs_reg, &rs_reg1, I)
-#define RS_UD(I) SUB_REG_UD(&rs_reg, &rs_reg1, I)
-
-#define RT_SB(I) SUB_REG_SB(&rt_reg, &rt_reg1, I)
-#define RT_SH(I) SUB_REG_SH(&rt_reg, &rt_reg1, I)
-#define RT_SW(I) SUB_REG_SW(&rt_reg, &rt_reg1, I)
-#define RT_SD(I) SUB_REG_SD(&rt_reg, &rt_reg1, I)
-
-#define RT_UB(I) SUB_REG_UB(&rt_reg, &rt_reg1, I)
-#define RT_UH(I) SUB_REG_UH(&rt_reg, &rt_reg1, I)
-#define RT_UW(I) SUB_REG_UW(&rt_reg, &rt_reg1, I)
-#define RT_UD(I) SUB_REG_UD(&rt_reg, &rt_reg1, I)
-
-
-
-#define LO_SB(I) SUB_REG_SB(&LO, &LO1, I)
-#define LO_SH(I) SUB_REG_SH(&LO, &LO1, I)
-#define LO_SW(I) SUB_REG_SW(&LO, &LO1, I)
-#define LO_SD(I) SUB_REG_SD(&LO, &LO1, I)
-
-#define LO_UB(I) SUB_REG_UB(&LO, &LO1, I)
-#define LO_UH(I) SUB_REG_UH(&LO, &LO1, I)
-#define LO_UW(I) SUB_REG_UW(&LO, &LO1, I)
-#define LO_UD(I) SUB_REG_UD(&LO, &LO1, I)
-
-#define HI_SB(I) SUB_REG_SB(&HI, &HI1, I)
-#define HI_SH(I) SUB_REG_SH(&HI, &HI1, I)
-#define HI_SW(I) SUB_REG_SW(&HI, &HI1, I)
-#define HI_SD(I) SUB_REG_SD(&HI, &HI1, I)
-
-#define HI_UB(I) SUB_REG_UB(&HI, &HI1, I)
-#define HI_UH(I) SUB_REG_UH(&HI, &HI1, I)
-#define HI_UW(I) SUB_REG_UW(&HI, &HI1, I)
-#define HI_UD(I) SUB_REG_UD(&HI, &HI1, I)
-/* end-sanitize-r5900 */
-
-
-/* start-sanitize-r5900 */
-static ut_reg SA; /* the shift amount register */
-/* end-sanitize-r5900 */
-
-static ut_reg EPC = 0; /* Exception PC */
-
-#if defined(HASFPU)
-/* Keep the current format state for each register: */
-static FP_formats fpr_state[32];
-#endif /* HASFPU */
-
-/* The following are internal simulator state variables: */
-static ut_reg IPC = 0; /* internal Instruction PC */
-static ut_reg DSPC = 0; /* delay-slot PC */
-
-
-/* TODO : these should be the bitmasks for these bits within the
- status register. At the moment the following are VR4300
- bit-positions: */
-#define status_KSU_mask (0x3) /* mask for KSU bits */
-#define status_KSU_shift (3) /* shift for field */
-#define ksu_kernel (0x0)
-#define ksu_supervisor (0x1)
-#define ksu_user (0x2)
-#define ksu_unknown (0x3)
-
-#define status_IE (1 << 0) /* Interrupt enable */
-#define status_EXL (1 << 1) /* Exception level */
-#define status_RE (1 << 25) /* Reverse Endian in user mode */
-#define status_FR (1 << 26) /* enables MIPS III additional FP registers */
-#define status_SR (1 << 20) /* soft reset or NMI */
-#define status_BEV (1 << 22) /* Location of general exception vectors */
-#define status_TS (1 << 21) /* TLB shutdown has occurred */
-#define status_ERL (1 << 2) /* Error level */
-#define status_RP (1 << 27) /* Reduced Power mode */
-
-#define cause_BD ((unsigned)1 << 31) /* Exception in branch delay slot */
-
-#if defined(HASFPU)
-/* Macro to update FPSR condition-code field. This is complicated by
- the fact that there is a hole in the index range of the bits within
- the FCSR register. Also, the number of bits visible depends on the
- MIPS ISA version being supported. */
-#define SETFCC(cc,v) {\
- int bit = ((cc == 0) ? 23 : (24 + (cc)));\
- FCSR = ((FCSR & ~(1 << bit)) | ((v) << bit));\
- }
-#define GETFCC(cc) (((((cc) == 0) ? (FCSR & (1 << 23)) : (FCSR & (1 << (24 + (cc))))) != 0) ? 1 : 0)
-
-/* This should be the COC1 value at the start of the preceding
- instruction: */
-#define PREVCOC1() ((state & simPCOC1) ? 1 : 0)
-#endif /* HASFPU */
-
-/* Standard FCRS bits: */
-#define IR (0) /* Inexact Result */
-#define UF (1) /* UnderFlow */
-#define OF (2) /* OverFlow */
-#define DZ (3) /* Division by Zero */
-#define IO (4) /* Invalid Operation */
-#define UO (5) /* Unimplemented Operation */
-
-/* Get masks for individual flags: */
-#if 1 /* SAFE version */
-#define FP_FLAGS(b) (((unsigned)(b) < 5) ? (1 << ((b) + 2)) : 0)
-#define FP_ENABLE(b) (((unsigned)(b) < 5) ? (1 << ((b) + 7)) : 0)
-#define FP_CAUSE(b) (((unsigned)(b) < 6) ? (1 << ((b) + 12)) : 0)
-#else
-#define FP_FLAGS(b) (1 << ((b) + 2))
-#define FP_ENABLE(b) (1 << ((b) + 7))
-#define FP_CAUSE(b) (1 << ((b) + 12))
-#endif
-
-#define FP_FS (1 << 24) /* MIPS III onwards : Flush to Zero */
-
-#define FP_MASK_RM (0x3)
-#define FP_SH_RM (0)
-#define FP_RM_NEAREST (0) /* Round to nearest (Round) */
-#define FP_RM_TOZERO (1) /* Round to zero (Trunc) */
-#define FP_RM_TOPINF (2) /* Round to Plus infinity (Ceil) */
-#define FP_RM_TOMINF (3) /* Round to Minus infinity (Floor) */
-#define GETRM() (int)((FCSR >> FP_SH_RM) & FP_MASK_RM)
-
-/* Slots for delayed register updates. For the moment we just have a
- fixed number of slots (rather than a more generic, dynamic
- system). This keeps the simulator fast. However, we only allow for
- the register update to be delayed for a single instruction
- cycle. */
-#define PSLOTS (5) /* Maximum number of instruction cycles */
-static int pending_in;
-static int pending_out;
-static int pending_total;
-static int pending_slot_count[PSLOTS];
-static int pending_slot_reg[PSLOTS];
-static ut_reg pending_slot_value[PSLOTS];
+/* Bits in the Debug register */
+#define Debug_DBD 0x80000000 /* Debug Branch Delay */
+#define Debug_DM 0x40000000 /* Debug Mode */
+#define Debug_DBp 0x00000002 /* Debug Breakpoint indicator */
/*---------------------------------------------------------------------------*/
/*-- GDB simulator interface ------------------------------------------------*/
/*---------------------------------------------------------------------------*/
-static void dotrace PARAMS((FILE *tracefh,int type,SIM_ADDR address,int width,char *comment,...));
-static void sim_warning PARAMS((char *fmt,...));
-extern void sim_error PARAMS((char *fmt,...));
-static void ColdReset PARAMS((void));
-static int AddressTranslation PARAMS((uword64 vAddr,int IorD,int LorS,uword64 *pAddr,int *CCA,int host,int raw));
-static void StoreMemory PARAMS((int CCA,int AccessLength,uword64 MemElem,uword64 MemElem1,uword64 pAddr,uword64 vAddr,int raw));
-static void LoadMemory PARAMS((uword64*memvalp,uword64*memval1p,int CCA,int AccessLength,uword64 pAddr,uword64 vAddr,int IorD,int raw));
-static void SignalException PARAMS((int exception,...));
-static long getnum PARAMS((char *value));
-extern void sim_set_profile PARAMS((int frequency));
-static unsigned int power2 PARAMS((unsigned int value));
+static void ColdReset PARAMS((SIM_DESC sd));
/*---------------------------------------------------------------------------*/
-/* The following are not used for MIPS IV onwards: */
-#define PENDING_FILL(r,v) {\
-/* printf("DBG: FILL BEFORE pending_in = %d, pending_out = %d, pending_total = %d\n",pending_in,pending_out,pending_total); */\
- if (pending_slot_reg[pending_in] != (LAST_EMBED_REGNUM + 1))\
- sim_warning("Attempt to over-write pending value");\
- pending_slot_count[pending_in] = 2;\
- pending_slot_reg[pending_in] = (r);\
- pending_slot_value[pending_in] = (uword64)(v);\
-/*printf("DBG: FILL reg %d value = 0x%s\n",(r),pr_addr(v));*/\
- pending_total++;\
- pending_in++;\
- if (pending_in == PSLOTS)\
- pending_in = 0;\
-/*printf("DBG: FILL AFTER pending_in = %d, pending_out = %d, pending_total = %d\n",pending_in,pending_out,pending_total);*/\
- }
-
-static int LLBIT = 0;
-/* LLBIT = Load-Linked bit. A bit of "virtual" state used by atomic
- read-write instructions. It is set when a linked load occurs. It is
- tested and cleared by the conditional store. It is cleared (during
- other CPU operations) when a store to the location would no longer
- be atomic. In particular, it is cleared by exception return
- instructions. */
-
-static int HIACCESS = 0;
-static int LOACCESS = 0;
-static int HI1ACCESS = 0;
-static int LO1ACCESS = 0;
-
-/* ??? The 4300 and a few other processors have interlocks on hi/lo register
- reads, and hence do not have this problem. To avoid spurious warnings,
- we just disable this always. */
-#if 1
-#define CHECKHILO(s)
-#else
-/* The HIACCESS and LOACCESS counts are used to ensure that
- corruptions caused by using the HI or LO register to close to a
- following operation are spotted. */
-static ut_reg HLPC = 0;
-/* If either of the preceding two instructions have accessed the HI or
- LO registers, then the values they see should be
- undefined. However, to keep the simulator world simple, we just let
- them use the value read and raise a warning to notify the user: */
-#define CHECKHILO(s) {\
- if ((HIACCESS != 0) || (LOACCESS != 0) || (HI1ACCESS != 0) || (LO1ACCESS != 0))\
- sim_warning("%s over-writing HI and LO registers values (PC = 0x%s HLPC = 0x%s)\n",(s),pr_addr(PC),pr_addr(HLPC));\
- }
-#endif
-
-/* NOTE: We keep the following status flags as bit values (1 for true,
- 0 for false). This allows them to be used in binary boolean
- operations without worrying about what exactly the non-zero true
- value is. */
-
-/* UserMode */
-#define UserMode ((((SR & status_KSU_mask) >> status_KSU_shift) == ksu_user) ? 1 : 0)
-
-/* BigEndianMem */
-/* Hardware configuration. Affects endianness of LoadMemory and
- StoreMemory and the endianness of Kernel and Supervisor mode
- execution. The value is 0 for little-endian; 1 for big-endian. */
-#define BigEndianMem (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN)
-/*(state & simBE) ? 1 : 0)*/
-
-/* ByteSwapMem */
-/* This is true if the host and target have different endianness. */
-#define ByteSwapMem (CURRENT_TARGET_BYTE_ORDER != CURRENT_HOST_BYTE_ORDER)
-
-/* ReverseEndian */
-/* This mode is selected if in User mode with the RE bit being set in
- SR (Status Register). It reverses the endianness of load and store
- instructions. */
-#define ReverseEndian (((SR & status_RE) && UserMode) ? 1 : 0)
-
-/* BigEndianCPU */
-/* The endianness for load and store instructions (0=little;1=big). In
- User mode this endianness may be switched by setting the state_RE
- bit in the SR register. Thus, BigEndianCPU may be computed as
- (BigEndianMem EOR ReverseEndian). */
-#define BigEndianCPU (BigEndianMem ^ ReverseEndian) /* Already bits */
-
-#if !defined(FASTSIM) || defined(PROFILE)
-/* At the moment these values will be the same, since we do not have
- access to the pipeline cycle count information from the simulator
- engine. */
-static unsigned int instruction_fetches = 0;
-static unsigned int instruction_fetch_overflow = 0;
-#endif
-
-/* Flags in the "state" variable: */
-#define simHALTEX (1 << 2) /* 0 = run; 1 = halt on exception */
-#define simHALTIN (1 << 3) /* 0 = run; 1 = halt on interrupt */
-#define simTRACE (1 << 8) /* 0 = do nothing; 1 = trace address activity */
-#define simPROFILE (1 << 9) /* 0 = do nothing; 1 = gather profiling samples */
-#define simPCOC0 (1 << 17) /* COC[1] from current */
-#define simPCOC1 (1 << 18) /* COC[1] from previous */
-#define simDELAYSLOT (1 << 24) /* 0 = do nothing; 1 = delay slot entry exists */
-#define simSKIPNEXT (1 << 25) /* 0 = do nothing; 1 = skip instruction */
-#define simSIGINT (1 << 28) /* 0 = do nothing; 1 = SIGINT has occured */
-#define simJALDELAYSLOT (1 << 29) /* 1 = in jal delay slot */
-static unsigned int state = 0;
#define DELAYSLOT() {\
- if (state & simDELAYSLOT)\
- sim_warning("Delay slot already activated (branch in delay slot?)");\
- state |= simDELAYSLOT;\
+ if (STATE & simDELAYSLOT)\
+ sim_io_eprintf(sd,"Delay slot already activated (branch in delay slot?)\n");\
+ STATE |= simDELAYSLOT;\
}
#define JALDELAYSLOT() {\
DELAYSLOT ();\
- state |= simJALDELAYSLOT;\
+ STATE |= simJALDELAYSLOT;\
}
#define NULLIFY() {\
- state &= ~simDELAYSLOT;\
- state |= simSKIPNEXT;\
+ STATE &= ~simDELAYSLOT;\
+ STATE |= simSKIPNEXT;\
}
-#define INDELAYSLOT() ((state & simDELAYSLOT) != 0)
-#define INJALDELAYSLOT() ((state & simJALDELAYSLOT) != 0)
+#define CANCELDELAYSLOT() {\
+ DSSTATE = 0;\
+ STATE &= ~(simDELAYSLOT | simJALDELAYSLOT);\
+ }
+
+#define INDELAYSLOT() ((STATE & simDELAYSLOT) != 0)
+#define INJALDELAYSLOT() ((STATE & simJALDELAYSLOT) != 0)
+/* Note that the monitor code essentially assumes this layout of memory.
+ If you change these, change the monitor code, too. */
+/* FIXME Currently addresses are truncated to 32-bits, see
+ mips/sim-main.c:address_translation(). If that changes, then these
+ values will need to be extended, and tested for more carefully. */
#define K0BASE (0x80000000)
#define K0SIZE (0x20000000)
#define K1BASE (0xA0000000)
#define K1SIZE (0x20000000)
-/* Simple run-time monitor support */
-static unsigned char *monitor = NULL;
-static ut_reg monitor_base = 0xBFC00000;
-static unsigned monitor_size = (1 << 11); /* power-of-2 */
+/* Simple run-time monitor support.
+
+ We emulate the monitor by placing magic reserved instructions at
+ the monitor's entry points; when we hit these instructions, instead
+ of raising an exception (as we would normally), we look at the
+ instruction and perform the appropriate monitory operation.
+
+ `*_monitor_base' are the physical addresses at which the corresponding
+ monitor vectors are located. `0' means none. By default,
+ install all three.
+ The RSVD_INSTRUCTION... macros specify the magic instructions we
+ use at the monitor entry points. */
+static int firmware_option_p = 0;
+static SIM_ADDR idt_monitor_base = 0xBFC00000;
+static SIM_ADDR pmon_monitor_base = 0xBFC00500;
+static SIM_ADDR lsipmon_monitor_base = 0xBFC00200;
+
+static SIM_RC sim_firmware_command (SIM_DESC sd, char* arg);
+
+
+#define MEM_SIZE (8 << 20) /* 8 MBytes */
-static char *logfile = NULL; /* logging disabled by default */
-static FILE *logfh = NULL;
#if defined(TRACE)
static char *tracefile = "trace.din"; /* default filename for trace log */
-static FILE *tracefh = NULL;
-static void open_trace PARAMS((void));
+FILE *tracefh = NULL;
+static void open_trace PARAMS((SIM_DESC sd));
#endif /* TRACE */
-#if defined(PROFILE)
-static unsigned profile_frequency = 256;
-static unsigned profile_nsamples = (128 << 10);
-static unsigned short *profile_hist = NULL;
-static ut_reg profile_minpc;
-static ut_reg profile_maxpc;
-static int profile_shift = 0; /* address shift amount */
-#endif /* PROFILE */
+static const char * get_insn_name (sim_cpu *, int);
+
+/* simulation target board. NULL=canonical */
+static char* board = NULL;
+
+
+static DECLARE_OPTION_HANDLER (mips_option_handler);
+
+enum {
+ OPTION_DINERO_TRACE = OPTION_START,
+ OPTION_DINERO_FILE,
+ OPTION_FIRMWARE,
+ OPTION_BOARD
+};
static SIM_RC
-mips_option_handler (sd, opt, arg)
+mips_option_handler (sd, cpu, opt, arg, is_command)
SIM_DESC sd;
+ sim_cpu *cpu;
int opt;
char *arg;
+ int is_command;
{
+ int cpu_nr;
switch (opt)
{
- case 'l':
- if (arg != NULL) {
- char *tmp;
- tmp = (char *)malloc(strlen(arg) + 1);
- if (tmp == NULL)
- callback->printf_filtered(callback,"Failed to allocate buffer for logfile name \"%s\"\n",optarg);
- else {
- strcpy(tmp,optarg);
- logfile = tmp;
- }
- }
- return SIM_RC_OK;
-
- case 'n': /* OK */
- callback->printf_filtered(callback,"Explicit model selection not yet available (Ignoring \"%s\")\n",optarg);
- return SIM_RC_FAIL;
-
- case 't': /* ??? */
+ case OPTION_DINERO_TRACE: /* ??? */
#if defined(TRACE)
/* 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,
etc.). */
- if (arg == NULL)
- state |= simTRACE;
- else if (strcmp (arg, "yes") == 0)
- state |= simTRACE;
- else if (strcmp (arg, "no") == 0)
- state &= ~simTRACE;
- else
+ for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++)
{
- fprintf (stderr, "Unreconized trace option `%s'\n", arg);
- return SIM_RC_FAIL;
+ sim_cpu *cpu = STATE_CPU (sd, cpu_nr);
+ if (arg == NULL)
+ STATE |= simTRACE;
+ else if (strcmp (arg, "yes") == 0)
+ STATE |= simTRACE;
+ else if (strcmp (arg, "no") == 0)
+ STATE &= ~simTRACE;
+ else if (strcmp (arg, "on") == 0)
+ STATE |= simTRACE;
+ else if (strcmp (arg, "off") == 0)
+ STATE &= ~simTRACE;
+ else
+ {
+ fprintf (stderr, "Unrecognized dinero-trace option `%s'\n", arg);
+ return SIM_RC_FAIL;
+ }
}
return SIM_RC_OK;
#else /* !TRACE */
fprintf(stderr,"\
-Simulator constructed without tracing support (for performance).\n\
+Simulator constructed without dinero tracing support (for performance).\n\
Re-compile simulator with \"-DTRACE\" to enable this option.\n");
return SIM_RC_FAIL;
#endif /* !TRACE */
- case 'z':
+ case OPTION_DINERO_FILE:
#if defined(TRACE)
if (optarg != NULL) {
char *tmp;
tmp = (char *)malloc(strlen(optarg) + 1);
if (tmp == NULL)
{
- callback->printf_filtered(callback,"Failed to allocate buffer for tracefile name \"%s\"\n",optarg);
+ sim_io_printf(sd,"Failed to allocate buffer for tracefile name \"%s\"\n",optarg);
return SIM_RC_FAIL;
}
else {
strcpy(tmp,optarg);
tracefile = tmp;
- callback->printf_filtered(callback,"Placing trace information into file \"%s\"\n",tracefile);
+ sim_io_printf(sd,"Placing trace information into file \"%s\"\n",tracefile);
}
}
#endif /* TRACE */
return SIM_RC_OK;
- case 'p':
-#if defined(PROFILE)
- state |= simPROFILE;
- return SIM_RC_OK;
-#else /* !PROFILE */
- fprintf(stderr,"\
-Simulator constructed without profiling support (for performance).\n\
-Re-compile simulator with \"-DPROFILE\" to enable this option.\n");
- return SIM_RC_FAIL;
-#endif /* !PROFILE */
-
- case 'x':
-#if defined(PROFILE)
- profile_nsamples = (unsigned)getnum(optarg);
-#endif /* PROFILE */
- return SIM_RC_OK;
-
- case 'y':
-#if defined(PROFILE)
- sim_set_profile((int)getnum(optarg));
-#endif /* PROFILE */
- return SIM_RC_OK;
+ case OPTION_FIRMWARE:
+ return sim_firmware_command (sd, arg);
+ case OPTION_BOARD:
+ {
+ if (arg)
+ {
+ board = zalloc(strlen(arg) + 1);
+ strcpy(board, arg);
+ }
+ return SIM_RC_OK;
+ }
}
-
+
return SIM_RC_OK;
}
+
static const OPTION mips_options[] =
{
- { {"log", required_argument, NULL,'l'},
- 'l', "FILE", "Log file",
- mips_option_handler },
- { {"name", required_argument, NULL,'n'},
- 'n', "MODEL", "Select arch model",
- mips_option_handler },
- { {"profile", optional_argument, NULL,'p'},
- 'p', "on|off", "Enable profiling",
+ { {"dinero-trace", optional_argument, NULL, OPTION_DINERO_TRACE},
+ '\0', "on|off", "Enable dinero tracing",
mips_option_handler },
- { {"trace", optional_argument, NULL,'t'},
- 't', "on|off", "Enable tracing",
- mips_option_handler },
- { {"tracefile",required_argument, NULL,'z'},
- 'z', "FILE", "Write trace to file",
- mips_option_handler },
- { {"frequency",required_argument, NULL,'y'},
- 'y', "FREQ", "Profile frequency",
- mips_option_handler },
- { {"samples", required_argument, NULL,'x'},
- 'y', "SIZE", "Profile sample size",
+ { {"dinero-file", required_argument, NULL, OPTION_DINERO_FILE},
+ '\0', "FILE", "Write dinero trace to FILE",
mips_option_handler },
+ { {"firmware", required_argument, NULL, OPTION_FIRMWARE},
+ '\0', "[idt|pmon|lsipmon|none][@ADDRESS]", "Emulate ROM monitor",
+ mips_option_handler },
+ { {"board", required_argument, NULL, OPTION_BOARD},
+ '\0', "none" /* rely on compile-time string concatenation for other options */
+
+#define BOARD_JMR3904 "jmr3904"
+ "|" BOARD_JMR3904
+#define BOARD_JMR3904_PAL "jmr3904pal"
+ "|" BOARD_JMR3904_PAL
+#define BOARD_JMR3904_DEBUG "jmr3904debug"
+ "|" BOARD_JMR3904_DEBUG
+#define BOARD_BSP "bsp"
+ "|" BOARD_BSP
+
+ , "Customize simulation for a particular board.", mips_option_handler },
+
{ {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
};
int interrupt_pending;
-static void
+void
interrupt_event (SIM_DESC sd, void *data)
{
+ sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
+ address_word cia = CIA_GET (cpu);
if (SR & status_IE)
{
interrupt_pending = 0;
- SignalException (Interrupt);
+ SignalExceptionInterrupt (1); /* interrupt "1" */
}
else if (!interrupt_pending)
sim_events_schedule (sd, 1, interrupt_event, data);
}
+/*---------------------------------------------------------------------------*/
+/*-- Device registration hook -----------------------------------------------*/
+/*---------------------------------------------------------------------------*/
+static void device_init(SIM_DESC sd) {
+#ifdef DEVICE_INIT
+ extern void register_devices(SIM_DESC);
+ register_devices(sd);
+#endif
+}
/*---------------------------------------------------------------------------*/
/*-- GDB simulator interface ------------------------------------------------*/
/*---------------------------------------------------------------------------*/
SIM_DESC
-sim_open (kind,cb,argv)
+sim_open (kind, cb, abfd, argv)
SIM_OPEN_KIND kind;
host_callback *cb;
+ struct bfd *abfd;
char **argv;
{
- SIM_DESC sd = &simulator;
+ SIM_DESC sd = sim_state_alloc (kind, cb);
+ sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
- STATE_OPEN_KIND (sd) = kind;
- STATE_MAGIC (sd) = SIM_MAGIC_NUMBER;
- STATE_CALLBACK (sd) = cb;
- callback = cb;
- CPU_STATE (STATE_CPU (sd, 0)) = sd;
+ SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
/* FIXME: watchpoints code shouldn't need this */
STATE_WATCHPOINTS (sd)->pc = &(PC);
STATE_WATCHPOINTS (sd)->sizeof_pc = sizeof (PC);
STATE_WATCHPOINTS (sd)->interrupt_handler = interrupt_event;
- /* memory defaults (unless sim_size was here first) */
- if (STATE_MEM_SIZE (sd) == 0)
- STATE_MEM_SIZE (sd) = (2 << 20);
- STATE_MEM_BASE (sd) = K1BASE;
-
- if (callback == NULL) {
- fprintf(stderr,"SIM Error: sim_open() called without callbacks attached\n");
- return 0;
- }
+ /* Initialize the mechanism for doing insn profiling. */
+ CPU_INSN_NAME (cpu) = get_insn_name;
+ CPU_MAX_INSNS (cpu) = nr_itable_entries;
- state = 0;
+ STATE = 0;
if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
return 0;
- sim_add_option_table (sd, mips_options);
+ 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
return 0;
}
+ /* handle board-specific memory maps */
+ if (board == NULL)
+ {
+ /* Allocate core managed memory */
+ sim_memopt *entry, *match = NULL;
+ address_word mem_size = 0;
+ int mapped = 0;
+
+ /* For compatibility with the old code - under this (at level one)
+ are the kernel spaces K0 & K1. Both of these map to a single
+ smaller sub region */
+ sim_do_command(sd," memory region 0x7fff8000,0x8000") ; /* MTZ- 32 k stack */
+
+ /* 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
+ allocating a new buffer in the "memory alias" command
+ below. The region at address 0 will be deleted. */
+ address_word size = (entry->modulo != 0
+ ? entry->modulo : entry->nr_bytes);
+ if (entry->addr == 0
+ && (!match || entry->level < match->level))
+ match = entry;
+ else if (entry->addr == K0BASE || entry->addr == K1BASE)
+ mapped = 1;
+ else
+ {
+ sim_memopt *alias;
+ for (alias = entry->alias; alias != NULL; alias = alias->next)
+ {
+ if (alias->addr == 0
+ && (!match || entry->level < match->level))
+ match = entry;
+ else if (alias->addr == K0BASE || alias->addr == K1BASE)
+ mapped = 1;
+ }
+ }
+ }
+
+ if (!mapped)
+ {
+ if (match)
+ {
+ /* Get existing memory region size. */
+ mem_size = (match->modulo != 0
+ ? match->modulo : match->nr_bytes);
+ /* Delete old region. */
+ sim_do_commandf (sd, "memory delete %d:0x%lx@%d",
+ match->space, match->addr, match->level);
+ }
+ else if (mem_size == 0)
+ mem_size = MEM_SIZE;
+ /* Limit to KSEG1 size (512MB) */
+ if (mem_size > K1SIZE)
+ mem_size = K1SIZE;
+ /* memory alias K1BASE@1,K1SIZE%MEMSIZE,K0BASE */
+ sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx%%0x%lx,0x%0x",
+ K1BASE, K1SIZE, (long)mem_size, K0BASE);
+ }
+
+ device_init(sd);
+ }
+ else if (board != NULL
+ && (strcmp(board, BOARD_BSP) == 0))
+ {
+ int i;
+
+ STATE_ENVIRONMENT (sd) = OPERATING_ENVIRONMENT;
+
+ /* ROM: 0x9FC0_0000 - 0x9FFF_FFFF and 0xBFC0_0000 - 0xBFFF_FFFF */
+ sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx,0x%0x",
+ 0x9FC00000,
+ 4 * 1024 * 1024, /* 4 MB */
+ 0xBFC00000);
+
+ /* SRAM: 0x8000_0000 - 0x803F_FFFF and 0xA000_0000 - 0xA03F_FFFF */
+ sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx,0x%0x",
+ 0x80000000,
+ 4 * 1024 * 1024, /* 4 MB */
+ 0xA0000000);
+
+ /* DRAM: 0x8800_0000 - 0x89FF_FFFF and 0xA800_0000 - 0xA9FF_FFFF */
+ for (i=0; i<8; i++) /* 32 MB total */
+ {
+ unsigned size = 4 * 1024 * 1024; /* 4 MB */
+ sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx,0x%0x",
+ 0x88000000 + (i * size),
+ size,
+ 0xA8000000 + (i * size));
+ }
+ }
+#if (WITH_HW)
+ else if (board != NULL
+ && (strcmp(board, BOARD_JMR3904) == 0 ||
+ strcmp(board, BOARD_JMR3904_PAL) == 0 ||
+ strcmp(board, BOARD_JMR3904_DEBUG) == 0))
+ {
+ /* match VIRTUAL memory layout of JMR-TX3904 board */
+ int i;
+
+ /* --- disable monitor unless forced on by user --- */
+
+ if (! firmware_option_p)
+ {
+ idt_monitor_base = 0;
+ pmon_monitor_base = 0;
+ lsipmon_monitor_base = 0;
+ }
+
+ /* --- environment --- */
+
+ STATE_ENVIRONMENT (sd) = OPERATING_ENVIRONMENT;
+
+ /* --- memory --- */
+
+ /* ROM: 0x9FC0_0000 - 0x9FFF_FFFF and 0xBFC0_0000 - 0xBFFF_FFFF */
+ sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx,0x%0x",
+ 0x9FC00000,
+ 4 * 1024 * 1024, /* 4 MB */
+ 0xBFC00000);
+
+ /* SRAM: 0x8000_0000 - 0x803F_FFFF and 0xA000_0000 - 0xA03F_FFFF */
+ sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx,0x%0x",
+ 0x80000000,
+ 4 * 1024 * 1024, /* 4 MB */
+ 0xA0000000);
+
+ /* DRAM: 0x8800_0000 - 0x89FF_FFFF and 0xA800_0000 - 0xA9FF_FFFF */
+ for (i=0; i<8; i++) /* 32 MB total */
+ {
+ unsigned size = 4 * 1024 * 1024; /* 4 MB */
+ sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx,0x%0x",
+ 0x88000000 + (i * size),
+ size,
+ 0xA8000000 + (i * size));
+ }
+
+ /* Dummy memory regions for unsimulated devices - sorted by address */
+
+ sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx", 0xB1000000, 0x400); /* ISA I/O */
+ sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx", 0xB2100000, 0x004); /* ISA ctl */
+ sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx", 0xB2500000, 0x004); /* LED/switch */
+ sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx", 0xB2700000, 0x004); /* RTC */
+ sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx", 0xB3C00000, 0x004); /* RTC */
+ sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx", 0xFFFF8000, 0x900); /* DRAMC */
+ sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx", 0xFFFF9000, 0x200); /* EBIF */
+ sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx", 0xFFFFE000, 0x01c); /* EBIF */
+ sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx", 0xFFFFF500, 0x300); /* PIO */
+
+
+ /* --- simulated devices --- */
+ sim_hw_parse (sd, "/tx3904irc@0xffffc000/reg 0xffffc000 0x20");
+ sim_hw_parse (sd, "/tx3904cpu");
+ sim_hw_parse (sd, "/tx3904tmr@0xfffff000/reg 0xfffff000 0x100");
+ sim_hw_parse (sd, "/tx3904tmr@0xfffff100/reg 0xfffff100 0x100");
+ sim_hw_parse (sd, "/tx3904tmr@0xfffff200/reg 0xfffff200 0x100");
+ sim_hw_parse (sd, "/tx3904sio@0xfffff300/reg 0xfffff300 0x100");
+ {
+ /* FIXME: poking at dv-sockser internals, use tcp backend if
+ --sockser_addr option was given.*/
+ extern char* sockser_addr;
+ if(sockser_addr == NULL)
+ sim_hw_parse (sd, "/tx3904sio@0xfffff300/backend stdio");
+ else
+ sim_hw_parse (sd, "/tx3904sio@0xfffff300/backend tcp");
+ }
+ sim_hw_parse (sd, "/tx3904sio@0xfffff400/reg 0xfffff400 0x100");
+ sim_hw_parse (sd, "/tx3904sio@0xfffff400/backend stdio");
+
+ /* -- device connections --- */
+ sim_hw_parse (sd, "/tx3904irc > ip level /tx3904cpu");
+ sim_hw_parse (sd, "/tx3904tmr@0xfffff000 > int tmr0 /tx3904irc");
+ sim_hw_parse (sd, "/tx3904tmr@0xfffff100 > int tmr1 /tx3904irc");
+ sim_hw_parse (sd, "/tx3904tmr@0xfffff200 > int tmr2 /tx3904irc");
+ sim_hw_parse (sd, "/tx3904sio@0xfffff300 > int sio0 /tx3904irc");
+ sim_hw_parse (sd, "/tx3904sio@0xfffff400 > int sio1 /tx3904irc");
+
+ /* add PAL timer & I/O module */
+ if(! strcmp(board, BOARD_JMR3904_PAL))
+ {
+ /* the device */
+ sim_hw_parse (sd, "/pal@0xffff0000");
+ sim_hw_parse (sd, "/pal@0xffff0000/reg 0xffff0000 64");
+
+ /* wire up interrupt ports to irc */
+ sim_hw_parse (sd, "/pal@0x31000000 > countdown tmr0 /tx3904irc");
+ sim_hw_parse (sd, "/pal@0x31000000 > timer tmr1 /tx3904irc");
+ sim_hw_parse (sd, "/pal@0x31000000 > int int0 /tx3904irc");
+ }
+
+ if(! strcmp(board, BOARD_JMR3904_DEBUG))
+ {
+ /* -- DEBUG: glue interrupt generators --- */
+ sim_hw_parse (sd, "/glue@0xffff0000/reg 0xffff0000 0x50");
+ sim_hw_parse (sd, "/glue@0xffff0000 > int0 int0 /tx3904irc");
+ sim_hw_parse (sd, "/glue@0xffff0000 > int1 int1 /tx3904irc");
+ sim_hw_parse (sd, "/glue@0xffff0000 > int2 int2 /tx3904irc");
+ sim_hw_parse (sd, "/glue@0xffff0000 > int3 int3 /tx3904irc");
+ sim_hw_parse (sd, "/glue@0xffff0000 > int4 int4 /tx3904irc");
+ sim_hw_parse (sd, "/glue@0xffff0000 > int5 int5 /tx3904irc");
+ sim_hw_parse (sd, "/glue@0xffff0000 > int6 int6 /tx3904irc");
+ sim_hw_parse (sd, "/glue@0xffff0000 > int7 int7 /tx3904irc");
+ sim_hw_parse (sd, "/glue@0xffff0000 > int8 dmac0 /tx3904irc");
+ sim_hw_parse (sd, "/glue@0xffff0000 > int9 dmac1 /tx3904irc");
+ sim_hw_parse (sd, "/glue@0xffff0000 > int10 dmac2 /tx3904irc");
+ sim_hw_parse (sd, "/glue@0xffff0000 > int11 dmac3 /tx3904irc");
+ sim_hw_parse (sd, "/glue@0xffff0000 > int12 sio0 /tx3904irc");
+ sim_hw_parse (sd, "/glue@0xffff0000 > int13 sio1 /tx3904irc");
+ sim_hw_parse (sd, "/glue@0xffff0000 > int14 tmr0 /tx3904irc");
+ sim_hw_parse (sd, "/glue@0xffff0000 > int15 tmr1 /tx3904irc");
+ sim_hw_parse (sd, "/glue@0xffff0000 > int16 tmr2 /tx3904irc");
+ sim_hw_parse (sd, "/glue@0xffff0000 > int17 nmi /tx3904cpu");
+ }
+
+ device_init(sd);
+ }
+#endif
+
+
+ /* check for/establish the a reference program image */
+ if (sim_analyze_program (sd,
+ (STATE_PROG_ARGV (sd) != NULL
+ ? *STATE_PROG_ARGV (sd)
+ : NULL),
+ abfd) != SIM_RC_OK)
+ {
+ sim_module_uninstall (sd);
+ return 0;
+ }
+
+ /* Configure/verify the target byte order and other runtime
+ configuration options */
+ if (sim_config (sd) != SIM_RC_OK)
+ {
+ sim_module_uninstall (sd);
+ return 0;
+ }
+
if (sim_post_argv_init (sd) != SIM_RC_OK)
{
/* Uninstall the modules to avoid memory leaks,
/* verify assumptions the simulator made about the host type system.
This macro does not return if there is a problem */
- CHECKSIM();
-
-#if defined(HASFPU)
- /* Check that the host FPU conforms to IEEE 754-1985 for the SINGLE
- and DOUBLE binary formats. This is a bit nasty, requiring that we
- trust the explicit manifests held in the source: */
- /* TODO: We need to cope with the simulated target and the host not
- having the same endianness. This will require the high and low
- words of a (double) to be swapped when converting between the
- host and the simulated target. */
- {
- union {
- unsigned int i[2];
- double d;
- float f[2];
- } s;
-
- s.d = (double)523.2939453125;
-
- if ((s.i[0] == 0 && (s.f[1] != (float)4.01102924346923828125
- || s.i[1] != 0x40805A5A))
- || (s.i[1] == 0 && (s.f[0] != (float)4.01102924346923828125
- || s.i[0] != 0x40805A5A)))
- {
- fprintf(stderr,"The host executing the simulator does not seem to have IEEE 754-1985 std FP\n");
- return 0;
- }
- }
-#endif /* HASFPU */
+ SIM_ASSERT (sizeof(int) == (4 * sizeof(char)));
+ SIM_ASSERT (sizeof(word64) == (8 * sizeof(char)));
/* This is NASTY, in that we are assuming the size of specific
registers: */
{
int rn;
- for (rn = 0; (rn < (LAST_EMBED_REGNUM + 1)); rn++) {
- if (rn < 32)
- register_widths[rn] = GPRLEN;
- else if ((rn >= FGRIDX) && (rn < (FGRIDX + 32)))
- register_widths[rn] = GPRLEN;
- else if ((rn >= 33) && (rn <= 37))
- register_widths[rn] = GPRLEN;
- else if ((rn == SRIDX) || (rn == FCR0IDX) || (rn == FCR31IDX) || ((rn >= 72) && (rn <= 89)))
- register_widths[rn] = 32;
- else
- register_widths[rn] = 0;
- }
+ for (rn = 0; (rn < (LAST_EMBED_REGNUM + 1)); rn++)
+ {
+ if (rn < 32)
+ cpu->register_widths[rn] = WITH_TARGET_WORD_BITSIZE;
+ else if ((rn >= FGR_BASE) && (rn < (FGR_BASE + NR_FGR)))
+ cpu->register_widths[rn] = WITH_TARGET_FLOATING_POINT_BITSIZE;
+ else if ((rn >= 33) && (rn <= 37))
+ cpu->register_widths[rn] = WITH_TARGET_WORD_BITSIZE;
+ else if ((rn == SRIDX)
+ || (rn == FCR0IDX)
+ || (rn == FCR31IDX)
+ || ((rn >= 72) && (rn <= 89)))
+ cpu->register_widths[rn] = 32;
+ else
+ cpu->register_widths[rn] = 0;
+ }
+
+
}
+#if defined(TRACE)
+ if (STATE & simTRACE)
+ open_trace(sd);
+#endif /* TRACE */
- if (logfile != NULL) {
- if (strcmp(logfile,"-") == 0)
- logfh = stdout;
- else {
- logfh = fopen(logfile,"wb+");
- if (logfh == NULL) {
- callback->printf_filtered(callback,"Failed to create file \"%s\", writing log information to stderr.\n",tracefile);
- logfh = stderr;
- }
+ /*
+ sim_io_eprintf (sd, "idt@%x pmon@%x lsipmon@%x\n",
+ idt_monitor_base,
+ pmon_monitor_base,
+ lsipmon_monitor_base);
+ */
+
+ /* Write the monitor trap address handlers into the monitor (eeprom)
+ address space. This can only be done once the target endianness
+ has been determined. */
+ if (idt_monitor_base != 0)
+ {
+ unsigned loop;
+ unsigned idt_monitor_size = 1 << 11;
+
+ /* the default monitor region */
+ sim_do_commandf (sd, "memory region 0x%x,0x%x",
+ idt_monitor_base, idt_monitor_size);
+
+ /* Entry into the IDT monitor is via fixed address vectors, and
+ not using machine instructions. To avoid clashing with use of
+ the MIPS TRAP system, we place our own (simulator specific)
+ "undefined" instructions into the relevant vector slots. */
+ for (loop = 0; (loop < idt_monitor_size); loop += 4)
+ {
+ address_word vaddr = (idt_monitor_base + loop);
+ unsigned32 insn = (RSVD_INSTRUCTION |
+ (((loop >> 2) & RSVD_INSTRUCTION_ARG_MASK)
+ << RSVD_INSTRUCTION_ARG_SHIFT));
+ H2T (insn);
+ sim_write (sd, vaddr, (char *)&insn, sizeof (insn));
+ }
}
- }
- /* FIXME: In the future both of these malloc's can be replaced by
- calls to sim-core. */
+ if ((pmon_monitor_base != 0) || (lsipmon_monitor_base != 0))
+ {
+ /* The PMON monitor uses the same address space, but rather than
+ branching into it the address of a routine is loaded. We can
+ cheat for the moment, and direct the PMON routine to IDT style
+ instructions within the monitor space. This relies on the IDT
+ monitor not using the locations from 0xBFC00500 onwards as its
+ entry points.*/
+ unsigned loop;
+ for (loop = 0; (loop < 24); loop++)
+ {
+ unsigned32 value = ((0x500 - 8) / 8); /* default UNDEFINED reason code */
+ switch (loop)
+ {
+ case 0: /* read */
+ value = 7;
+ break;
+ case 1: /* write */
+ value = 8;
+ break;
+ case 2: /* open */
+ value = 6;
+ break;
+ case 3: /* close */
+ value = 10;
+ break;
+ case 5: /* printf */
+ value = ((0x500 - 16) / 8); /* not an IDT reason code */
+ break;
+ case 8: /* cliexit */
+ value = 17;
+ break;
+ case 11: /* flush_cache */
+ value = 28;
+ break;
+ }
+
+ SIM_ASSERT (idt_monitor_base != 0);
+ value = ((unsigned int) idt_monitor_base + (value * 8));
+ H2T (value);
- /* If the host has "mmap" available we could use it to provide a
- very large virtual address space for the simulator, since memory
- would only be allocated within the "mmap" space as it is
- accessed. This can also be linked to the architecture specific
- support, required to simulate the MMU. */
- sim_size(STATE_MEM_SIZE (sd));
- /* NOTE: The above will also have enabled any profiling state! */
+ if (pmon_monitor_base != 0)
+ {
+ address_word vaddr = (pmon_monitor_base + (loop * 4));
+ sim_write (sd, vaddr, (char *)&value, sizeof (value));
+ }
+
+ if (lsipmon_monitor_base != 0)
+ {
+ address_word vaddr = (lsipmon_monitor_base + (loop * 4));
+ sim_write (sd, vaddr, (char *)&value, sizeof (value));
+ }
+ }
+
+ /* Write an abort sequence into the TRAP (common) exception vector
+ addresses. This is to catch code executing a TRAP (et.al.)
+ instruction without installing a trap handler. */
+ if ((idt_monitor_base != 0) ||
+ (pmon_monitor_base != 0) ||
+ (lsipmon_monitor_base != 0))
+ {
+ unsigned32 halt[2] = { 0x2404002f /* addiu r4, r0, 47 */,
+ HALT_INSTRUCTION /* BREAK */ };
+ H2T (halt[0]);
+ H2T (halt[1]);
+ sim_write (sd, 0x80000000, (char *) halt, sizeof (halt));
+ sim_write (sd, 0x80000180, (char *) halt, sizeof (halt));
+ sim_write (sd, 0x80000200, (char *) halt, sizeof (halt));
+ /* XXX: Write here unconditionally? */
+ sim_write (sd, 0xBFC00200, (char *) halt, sizeof (halt));
+ sim_write (sd, 0xBFC00380, (char *) halt, sizeof (halt));
+ sim_write (sd, 0xBFC00400, (char *) halt, sizeof (halt));
+ }
+ }
- /* Create the monitor address space as well */
- monitor = (unsigned char *)calloc(1,monitor_size);
- if (!monitor)
- fprintf(stderr,"Not enough VM for monitor simulation (%d bytes)\n",
- monitor_size);
-#if defined(TRACE)
- if (state & simTRACE)
- open_trace();
-#endif /* TRACE */
return sd;
}
#if defined(TRACE)
static void
-open_trace()
+open_trace(sd)
+ SIM_DESC sd;
{
tracefh = fopen(tracefile,"wb+");
if (tracefh == NULL)
{
- sim_warning("Failed to create file \"%s\", writing trace information to stderr.",tracefile);
+ sim_io_eprintf(sd,"Failed to create file \"%s\", writing trace information to stderr.\n",tracefile);
tracefh = stderr;
}
}
#endif /* TRACE */
-/* For the profile writing, we write the data in the host
- endianness. This unfortunately means we are assuming that the
- profile file we create is processed on the same host executing the
- simulator. The gmon.out file format should either have an explicit
- endianness, or a method of encoding the endianness in the file
- header. */
-static int
-writeout32(fh,val)
- FILE *fh;
- unsigned int val;
-{
- char buff[4];
- int res = 1;
-
- if (CURRENT_HOST_BYTE_ORDER == BIG_ENDIAN) {
- buff[3] = ((val >> 0) & 0xFF);
- buff[2] = ((val >> 8) & 0xFF);
- buff[1] = ((val >> 16) & 0xFF);
- buff[0] = ((val >> 24) & 0xFF);
- } else {
- buff[0] = ((val >> 0) & 0xFF);
- buff[1] = ((val >> 8) & 0xFF);
- buff[2] = ((val >> 16) & 0xFF);
- buff[3] = ((val >> 24) & 0xFF);
- }
- if (fwrite(buff,4,1,fh) != 1) {
- sim_warning("Failed to write 4bytes to the profile file");
- res = 0;
- }
- return(res);
-}
-
-static int
-writeout16(fh,val)
- FILE *fh;
- unsigned short val;
+/* Return name of an insn, used by insn profiling. */
+static const char *
+get_insn_name (sim_cpu *cpu, int i)
{
- char buff[2];
- int res = 1;
- if (CURRENT_HOST_BYTE_ORDER == BIG_ENDIAN) {
- buff[1] = ((val >> 0) & 0xFF);
- buff[0] = ((val >> 8) & 0xFF);
- } else {
- buff[0] = ((val >> 0) & 0xFF);
- buff[1] = ((val >> 8) & 0xFF);
- }
- if (fwrite(buff,2,1,fh) != 1) {
- sim_warning("Failed to write 2bytes to the profile file");
- res = 0;
- }
- return(res);
+ return itable[i].name;
}
void
printf("DBG: sim_close: entered (quitting = %d)\n",quitting);
#endif
- /* Cannot assume sim_kill() has been called */
+
/* "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: */
- callback->shutdown(callback);
-
-#if defined(PROFILE)
- if ((state & simPROFILE) && (profile_hist != NULL)) {
- FILE *pf = fopen("gmon.out","wb");
- unsigned loop;
-
- if (pf == NULL)
- sim_warning("Failed to open \"gmon.out\" profile file");
- else {
- int ok;
-#ifdef DEBUG
- printf("DBG: minpc = 0x%s\n",pr_addr(profile_minpc));
- printf("DBG: maxpc = 0x%s\n",pr_addr(profile_maxpc));
-#endif /* DEBUG */
- ok = writeout32(pf,(unsigned int)profile_minpc);
- if (ok)
- ok = writeout32(pf,(unsigned int)profile_maxpc);
- if (ok)
- ok = writeout32(pf,(profile_nsamples * 2) + 12); /* size of sample buffer (+ header) */
-#ifdef DEBUG
- printf("DBG: nsamples = %d (size = 0x%08X)\n",profile_nsamples,((profile_nsamples * 2) + 12));
-#endif /* DEBUG */
- for (loop = 0; (ok && (loop < profile_nsamples)); loop++) {
- ok = writeout16(pf,profile_hist[loop]);
- if (!ok)
- break;
- }
-
- fclose(pf);
- }
-
- free(profile_hist);
- profile_hist = NULL;
- state &= ~simPROFILE;
- }
-#endif /* PROFILE */
+ sim_io_shutdown (sd);
#if defined(TRACE)
if (tracefh != NULL && tracefh != stderr)
fclose(tracefh);
tracefh = NULL;
- state &= ~simTRACE;
#endif /* TRACE */
- if (logfh != NULL && logfh != stdout && logfh != stderr)
- fclose(logfh);
- logfh = NULL;
-
- if (STATE_MEMORY (sd) != NULL)
- free(STATE_MEMORY (sd)); /* cfree not available on all hosts */
- STATE_MEMORY (sd) = NULL;
+ /* FIXME - free SD */
return;
}
unsigned char *buffer;
int size;
{
- int index = size;
- uword64 vaddr = (uword64)addr;
+ int index;
+ sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
/* Return the number of bytes written, or zero if error. */
#ifdef DEBUG
- callback->printf_filtered(callback,"sim_write(0x%s,buffer,%d);\n",pr_addr(addr),size);
+ sim_io_printf(sd,"sim_write(0x%s,buffer,%d);\n",pr_addr(addr),size);
#endif
- /* We provide raw read and write routines, since we do not want to
- count the GDB memory accesses in our statistics gathering. */
-
- /* There is a lot of code duplication in the individual blocks
- below, but the variables are declared locally to a block to give
- the optimiser the best chance of improving the code. We have to
- perform slow byte reads from the host memory, to ensure that we
- get the data into the correct endianness for the (simulated)
- target memory world. */
-
- /* Mask count to get odd byte, odd halfword, and odd word out of the
- way. We can then perform doubleword transfers to and from the
- simulator memory for optimum performance. */
- if (index && (index & 1)) {
- uword64 paddr;
- int cca;
- if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isRAW)) {
- uword64 value = ((uword64)(*buffer++));
- StoreMemory(cca,AccessLength_BYTE,value,0,paddr,vaddr,isRAW);
- }
- vaddr++;
- index &= ~1; /* logical operations usually quicker than arithmetic on RISC systems */
- }
- if (index && (index & 2)) {
- uword64 paddr;
- int cca;
- if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isRAW)) {
- uword64 value;
- /* We need to perform the following magic to ensure that that
- bytes are written into same byte positions in the target memory
- world, regardless of the endianness of the host. */
- if (BigEndianMem) {
- value = ((uword64)(*buffer++) << 8);
- value |= ((uword64)(*buffer++) << 0);
- } else {
- value = ((uword64)(*buffer++) << 0);
- value |= ((uword64)(*buffer++) << 8);
- }
- StoreMemory(cca,AccessLength_HALFWORD,value,0,paddr,vaddr,isRAW);
- }
- vaddr += 2;
- index &= ~2;
- }
- if (index && (index & 4)) {
- uword64 paddr;
- int cca;
- if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isRAW)) {
- uword64 value;
- if (BigEndianMem) {
- value = ((uword64)(*buffer++) << 24);
- value |= ((uword64)(*buffer++) << 16);
- value |= ((uword64)(*buffer++) << 8);
- value |= ((uword64)(*buffer++) << 0);
- } else {
- value = ((uword64)(*buffer++) << 0);
- value |= ((uword64)(*buffer++) << 8);
- value |= ((uword64)(*buffer++) << 16);
- value |= ((uword64)(*buffer++) << 24);
- }
- StoreMemory(cca,AccessLength_WORD,value,0,paddr,vaddr,isRAW);
- }
- vaddr += 4;
- index &= ~4;
- }
- for (;index; index -= 8) {
- uword64 paddr;
- int cca;
- if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isRAW)) {
- uword64 value;
- if (BigEndianMem) {
- value = ((uword64)(*buffer++) << 56);
- value |= ((uword64)(*buffer++) << 48);
- value |= ((uword64)(*buffer++) << 40);
- value |= ((uword64)(*buffer++) << 32);
- value |= ((uword64)(*buffer++) << 24);
- value |= ((uword64)(*buffer++) << 16);
- value |= ((uword64)(*buffer++) << 8);
- value |= ((uword64)(*buffer++) << 0);
- } else {
- value = ((uword64)(*buffer++) << 0);
- value |= ((uword64)(*buffer++) << 8);
- value |= ((uword64)(*buffer++) << 16);
- value |= ((uword64)(*buffer++) << 24);
- value |= ((uword64)(*buffer++) << 32);
- value |= ((uword64)(*buffer++) << 40);
- value |= ((uword64)(*buffer++) << 48);
- value |= ((uword64)(*buffer++) << 56);
- }
- StoreMemory(cca,AccessLength_DOUBLEWORD,value,0,paddr,vaddr,isRAW);
+ /* 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;
}
- vaddr += 8;
- }
- return(size);
+ return(index);
}
int
int size;
{
int index;
+ sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
/* Return the number of bytes read, or zero if error. */
#ifdef DEBUG
- callback->printf_filtered(callback,"sim_read(0x%s,buffer,%d);\n",pr_addr(addr),size);
+ sim_io_printf(sd,"sim_read(0x%s,buffer,%d);\n",pr_addr(addr),size);
#endif /* DEBUG */
- /* TODO: Perform same optimisation as the sim_write() code
- above. NOTE: This will require a bit more work since we will need
- to ensure that the source physical address is doubleword aligned
- before, and then deal with trailing bytes. */
- for (index = 0; (index < size); index++) {
- uword64 vaddr,paddr,value;
- int cca;
- vaddr = (uword64)addr + index;
- if (AddressTranslation(vaddr,isDATA,isLOAD,&paddr,&cca,isTARGET,isRAW)) {
- LoadMemory(&value,NULL,cca,AccessLength_BYTE,paddr,vaddr,isDATA,isRAW);
- buffer[index] = (unsigned char)(value&0xFF);
- } else
- break;
- }
+ 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);
}
-void
-sim_store_register (sd,rn,memory)
+int
+sim_store_register (sd,rn,memory,length)
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
- callback->printf_filtered(callback,"sim_store_register(%d,*memory=0x%s);\n",rn,pr_addr(*((SIM_ADDR *)memory)));
+ 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
register number is for the architecture being simulated. */
- if (register_widths[rn] == 0)
- sim_warning("Invalid register width for %d (register store ignored)",rn);
- else
+ if (cpu->register_widths[rn] == 0)
{
- if (register_widths[rn] == 32)
- registers[rn] = T2H_4 (*(unsigned int*)memory);
- else
- registers[rn] = T2H_8 (*(uword64*)memory);
+ sim_io_eprintf(sd,"Invalid register width for %d (register store ignored)\n",rn);
+ return 0;
}
- return;
+
+
+ if (rn >= FGR_BASE && rn < FGR_BASE + NR_FGR)
+ {
+ cpu->fpr_state[rn - FGR_BASE] = fmt_uninterpreted;
+ if (cpu->register_widths[rn] == 32)
+ {
+ if (length == 8)
+ {
+ cpu->fgr[rn - FGR_BASE] =
+ (unsigned32) T2H_8 (*(unsigned64*)memory);
+ return 8;
+ }
+ else
+ {
+ cpu->fgr[rn - FGR_BASE] = T2H_4 (*(unsigned32*)memory);
+ return 4;
+ }
+ }
+ else
+ {
+ if (length == 8)
+ {
+ cpu->fgr[rn - FGR_BASE] = T2H_8 (*(unsigned64*)memory);
+ return 8;
+ }
+ else
+ {
+ cpu->fgr[rn - FGR_BASE] = T2H_4 (*(unsigned32*)memory);
+ return 4;
+ }
+ }
+ }
+
+ if (cpu->register_widths[rn] == 32)
+ {
+ if (length == 8)
+ {
+ cpu->registers[rn] =
+ (unsigned32) T2H_8 (*(unsigned64*)memory);
+ return 8;
+ }
+ else
+ {
+ cpu->registers[rn] = T2H_4 (*(unsigned32*)memory);
+ return 4;
+ }
+ }
+ else
+ {
+ if (length == 8)
+ {
+ cpu->registers[rn] = T2H_8 (*(unsigned64*)memory);
+ return 8;
+ }
+ else
+ {
+ cpu->registers[rn] = (signed32) T2H_4(*(unsigned32*)memory);
+ return 4;
+ }
+ }
+
+ return 0;
}
-void
-sim_fetch_register (sd,rn,memory)
+int
+sim_fetch_register (sd,rn,memory,length)
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
- callback->printf_filtered(callback,"sim_fetch_register(%d=0x%s,mem) : place simulator registers into memory\n",rn,pr_addr(registers[rn]));
+#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 (register_widths[rn] == 0)
- sim_warning("Invalid register width for %d (register fetch ignored)",rn);
- else
+ if (cpu->register_widths[rn] == 0)
{
- if (register_widths[rn] == 32)
- *((unsigned int *)memory) = H2T_4 ((unsigned int)(registers[rn] & 0xFFFFFFFF));
- else /* 64bit register */
- *((uword64 *)memory) = H2T_8 (registers[rn]);
+ sim_io_eprintf (sd, "Invalid register width for %d (register fetch ignored)\n",rn);
+ return 0;
}
- return;
-}
-void
-sim_info (sd,verbose)
- SIM_DESC sd;
- int verbose;
-{
-
- return;
- /* Accessed from the GDB "info files" command: */
- if (STATE_VERBOSE_P (sd) || verbose)
+ /* Any floating point register */
+ if (rn >= FGR_BASE && rn < FGR_BASE + NR_FGR)
{
-
- sim_io_printf (sd, "MIPS %d-bit %s endian simulator\n",
- (PROCESSOR_64BIT ? 64 : 32),
- (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN ? "Big" : "Little"));
-
- sim_io_printf (sd, "0x%08X bytes of memory at 0x%s\n",
- STATE_MEM_SIZE (sd),
- pr_addr (STATE_MEM_BASE (sd)));
-
-#if !defined(FASTSIM)
-#if 0
- /* at present this simulator executes one instruction per
- simulator cycle. Consequently this data never changes */
- if (instruction_fetch_overflow != 0)
- sim_io_printf (sd, "Instruction fetches = 0x%08X%08X\n",
- instruction_fetch_overflow, instruction_fetches);
+ if (cpu->register_widths[rn] == 32)
+ {
+ if (length == 8)
+ {
+ *(unsigned64*)memory =
+ H2T_8 ((unsigned32) (cpu->fgr[rn - FGR_BASE]));
+ return 8;
+ }
+ else
+ {
+ *(unsigned32*)memory = H2T_4 (cpu->fgr[rn - FGR_BASE]);
+ return 4;
+ }
+ }
else
- sim_io_printf (sd, "Instruction fetches = %d\n", instruction_fetches);
-#endif
- /* It would be a useful feature, if when performing multi-cycle
- simulations (rather than single-stepping) we keep the start and
- end times of the execution, so that we can give a performance
- figure for the simulator. */
-#endif /* !FASTSIM */
- sim_io_printf (sd, "Number of execution cycles = %ld\n",
- (long) sim_events_time (sd));
-
- /* print information pertaining to MIPS ISA and architecture being simulated */
- /* things that may be interesting */
- /* instructions executed - if available */
- /* cycles executed - if available */
- /* pipeline stalls - if available */
- /* virtual time taken */
- /* profiling size */
- /* profiling frequency */
- /* profile minpc */
- /* profile maxpc */
+ {
+ if (length == 8)
+ {
+ *(unsigned64*)memory = H2T_8 (cpu->fgr[rn - FGR_BASE]);
+ return 8;
+ }
+ else
+ {
+ *(unsigned32*)memory = H2T_4 ((unsigned32)(cpu->fgr[rn - FGR_BASE]));
+ return 4;
+ }
+ }
}
-}
-
-SIM_RC
-sim_load (sd,prog,abfd,from_tty)
- SIM_DESC sd;
- char *prog;
- bfd *abfd;
- int from_tty;
-{
- bfd *prog_bfd;
-
- prog_bfd = sim_load_file (sd,
- STATE_MY_NAME (sd),
- callback,
- prog,
- /* pass NULL for abfd, we always open our own */
- NULL,
- STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG);
- if (prog_bfd == NULL)
- return SIM_RC_FAIL;
- sim_analyze_program (sd, prog_bfd);
- /* Configure/verify the target byte order and other runtime
- configuration options */
- sim_config (sd, PREFERED_TARGET_BYTE_ORDER(prog_bfd));
-
- /* (re) Write the monitor trap address handlers into the monitor
- (eeprom) address space. This can only be done once the target
- endianness has been determined. */
- {
- unsigned loop;
- /* Entry into the IDT monitor is via fixed address vectors, and
- not using machine instructions. To avoid clashing with use of
- the MIPS TRAP system, we place our own (simulator specific)
- "undefined" instructions into the relevant vector slots. */
- for (loop = 0; (loop < monitor_size); loop += 4) {
- uword64 vaddr = (monitor_base + loop);
- uword64 paddr;
- int cca;
- if (AddressTranslation(vaddr, isDATA, isSTORE, &paddr, &cca, isTARGET, isRAW))
- StoreMemory(cca, AccessLength_WORD,
- (RSVD_INSTRUCTION | (((loop >> 2) & RSVD_INSTRUCTION_ARG_MASK) << RSVD_INSTRUCTION_ARG_SHIFT)),
- 0, paddr, vaddr, isRAW);
+ if (cpu->register_widths[rn] == 32)
+ {
+ if (length == 8)
+ {
+ *(unsigned64*)memory =
+ H2T_8 ((unsigned32) (cpu->registers[rn]));
+ return 8;
+ }
+ else
+ {
+ *(unsigned32*)memory = H2T_4 ((unsigned32)(cpu->registers[rn]));
+ return 4;
+ }
+ }
+ else
+ {
+ if (length == 8)
+ {
+ *(unsigned64*)memory =
+ H2T_8 ((unsigned64) (cpu->registers[rn]));
+ return 8;
+ }
+ else
+ {
+ *(unsigned32*)memory = H2T_4 ((unsigned32)(cpu->registers[rn]));
+ return 4;
+ }
}
- /* The PMON monitor uses the same address space, but rather than
- branching into it the address of a routine is loaded. We can
- cheat for the moment, and direct the PMON routine to IDT style
- instructions within the monitor space. This relies on the IDT
- monitor not using the locations from 0xBFC00500 onwards as its
- entry points.*/
- for (loop = 0; (loop < 24); loop++)
- {
- uword64 vaddr = (monitor_base + 0x500 + (loop * 4));
- uword64 paddr;
- int cca;
- unsigned int value = ((0x500 - 8) / 8); /* default UNDEFINED reason code */
- switch (loop)
- {
- case 0: /* read */
- value = 7;
- break;
-
- case 1: /* write */
- value = 8;
- break;
-
- case 2: /* open */
- value = 6;
- break;
-
- case 3: /* close */
- value = 10;
- break;
-
- case 5: /* printf */
- value = ((0x500 - 16) / 8); /* not an IDT reason code */
- break;
-
- case 8: /* cliexit */
- value = 17;
- break;
-
- case 11: /* flush_cache */
- value = 28;
- break;
- }
- /* FIXME - should monitor_base be SIM_ADDR?? */
- value = ((unsigned int)monitor_base + (value * 8));
- if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isRAW))
- StoreMemory(cca,AccessLength_WORD,value,0,paddr,vaddr,isRAW);
- else
- sim_error("Failed to write to monitor space 0x%s",pr_addr(vaddr));
-
- /* The LSI MiniRISC PMON has its vectors at 0x200, not 0x500. */
- vaddr -= 0x300;
- if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isRAW))
- StoreMemory(cca,AccessLength_WORD,value,0,paddr,vaddr,isRAW);
- else
- sim_error("Failed to write to monitor space 0x%s",pr_addr(vaddr));
- }
- }
- return SIM_RC_OK;
+ return 0;
}
+
SIM_RC
-sim_create_inferior (sd, argv,env)
+sim_create_inferior (sd, abfd, argv,env)
SIM_DESC sd;
+ struct bfd *abfd;
char **argv;
char **env;
{
#ifdef DEBUG
+#if 0 /* FIXME: doesn't compile */
printf("DBG: sim_create_inferior entered: start_address = 0x%s\n",
pr_addr(PC));
+#endif
#endif /* DEBUG */
- ColdReset();
- /* If we were providing a more complete I/O, co-processor or memory
- simulation, we should perform any "device" initialisation at this
- point. This can include pre-loading memory areas with particular
- patterns (e.g. simulating ROM monitors). */
+ ColdReset(sd);
-#if 1
- PC = (uword64) STATE_START_ADDR(sd);
-#else
- /* TODO: Sort this properly. SIM_ADDR may already be a 64bit value: */
- PC = SIGNEXTEND(bfd_get_start_address(prog_bfd),32);
-#endif
-
- /* Prepare to execute the program to be simulated */
- /* argv and env are NULL terminated lists of pointers */
+ if (abfd != NULL)
+ {
+ /* override PC value set by ColdReset () */
+ int cpu_nr;
+ for (cpu_nr = 0; cpu_nr < sim_engine_nr_cpus (sd); cpu_nr++)
+ {
+ sim_cpu *cpu = STATE_CPU (sd, cpu_nr);
+ CIA_SET (cpu, (unsigned64) bfd_get_start_address (abfd));
+ }
+ }
- if (argv || env) {
#if 0 /* def DEBUG */
- callback->printf_filtered(callback,"sim_create_inferior() : passed arguments ignored\n");
+ if (argv || env)
{
- char **cptr;
- for (cptr = argv; (cptr && *cptr); cptr++)
- printf("DBG: arg \"%s\"\n",*cptr);
+ /* We should really place the argv slot values into the argument
+ registers, and onto the stack as required. However, this
+ assumes that we have a stack defined, which is not
+ necessarily true at the moment. */
+ char **cptr;
+ sim_io_printf(sd,"sim_create_inferior() : passed arguments ignored\n");
+ for (cptr = argv; (cptr && *cptr); cptr++)
+ printf("DBG: arg \"%s\"\n",*cptr);
}
#endif /* DEBUG */
- /* We should really place the argv slot values into the argument
- registers, and onto the stack as required. However, this
- assumes that we have a stack defined, which is not necessarily
- true at the moment. */
- }
return SIM_RC_OK;
}
void
-sim_kill (sd)
+sim_do_command (sd,cmd)
SIM_DESC sd;
+ char *cmd;
{
-#if 1
- /* This routine should be for terminating any existing simulation
- thread. Since we are single-threaded only at the moment, this is
- not an issue. It should *NOT* be used to terminate the
- simulator. */
-#else /* do *NOT* call sim_close */
- sim_close(sd, 1); /* Do not hang on errors */
- /* This would also be the point where any memory mapped areas used
- by the simulator should be released. */
-#endif
- return;
+ if (sim_args_command (sd, cmd) != SIM_RC_OK)
+ sim_io_printf (sd, "Error: \"%s\" is not a valid MIPS simulator command.\n",
+ cmd);
}
-typedef enum {e_terminate,e_help,e_setmemsize,e_reset} e_cmds;
-
-static struct t_sim_command {
- e_cmds id;
- const char *name;
- const char *help;
-} sim_commands[] = {
- {e_help, "help", ": Show MIPS simulator private commands"},
- {e_setmemsize,"set-memory-size","<n> : Specify amount of memory simulated"},
- {e_reset, "reset-system", ": Reset the simulated processor"},
- {e_terminate, NULL}
-};
+/*---------------------------------------------------------------------------*/
+/*-- Private simulator support interface ------------------------------------*/
+/*---------------------------------------------------------------------------*/
-void
-sim_do_command (sd,cmd)
- SIM_DESC sd;
- char *cmd;
-{
- struct t_sim_command *cptr;
+/* Read a null terminated string from memory, return in a buffer */
+static char *
+fetch_str (SIM_DESC sd,
+ address_word addr)
+{
+ char *buf;
+ int nr = 0;
+ char null;
+ while (sim_read (sd, addr + nr, &null, 1) == 1 && null != 0)
+ nr++;
+ buf = NZALLOC (char, nr + 1);
+ sim_read (sd, addr, buf, nr);
+ return buf;
+}
- if (callback == NULL) {
- fprintf(stderr,"Simulator not enabled: \"target sim\" should be used to activate\n");
- return;
- }
- if (!(cmd && *cmd != '\0'))
- cmd = "help";
+/* Implements the "sim firmware" command:
+ sim firmware NAME[@ADDRESS] --- emulate ROM monitor named NAME.
+ NAME can be idt, pmon, or lsipmon. If omitted, ADDRESS
+ defaults to the normal address for that monitor.
+ sim firmware none --- don't emulate any ROM monitor. Useful
+ if you need a clean address space. */
+static SIM_RC
+sim_firmware_command (SIM_DESC sd, char *arg)
+{
+ int address_present = 0;
+ SIM_ADDR address;
+
+ /* Signal occurrence of this option. */
+ firmware_option_p = 1;
- /* NOTE: Accessed from the GDB "sim" commmand: */
- for (cptr = sim_commands; cptr && cptr->name; cptr++)
- if (strncmp (cmd, cptr->name, strlen(cptr->name)) == 0)
+ /* Parse out the address, if present. */
+ {
+ char *p = strchr (arg, '@');
+ if (p)
{
- cmd += strlen(cptr->name);
- switch (cptr->id) {
- case e_help: /* no arguments */
- { /* no arguments */
- struct t_sim_command *lptr;
- callback->printf_filtered(callback,"List of MIPS simulator commands:\n");
- for (lptr = sim_commands; lptr->name; lptr++)
- callback->printf_filtered(callback,"%s %s\n",lptr->name,lptr->help);
- sim_args_command (sd, "help");
- }
- break;
+ char *q;
+ address_present = 1;
+ p ++; /* skip over @ */
- case e_setmemsize: /* memory size argument */
+ address = strtoul (p, &q, 0);
+ if (*q != '\0')
{
- unsigned int newsize = (unsigned int)getnum(cmd);
- sim_size(newsize);
+ sim_io_printf (sd, "Invalid address given to the"
+ "`sim firmware NAME@ADDRESS' command: %s\n",
+ p);
+ return SIM_RC_FAIL;
}
- break;
-
- case e_reset: /* no arguments */
- ColdReset();
- /* NOTE: See the comments in sim_open() relating to device
- initialisation. */
- break;
-
- default:
- callback->printf_filtered(callback,"FATAL: Matched \"%s\", but failed to match command id %d.\n",cmd,cptr->id);
- break;
- }
- break;
}
+ else
+ {
+ address_present = 0;
+ address = -1; /* Dummy value. */
+ }
+ }
- if (!(cptr->name))
+ if (! strncmp (arg, "idt", 3))
{
- /* try for a common command when the sim specific lookup fails */
- if (sim_args_command (sd, cmd) != SIM_RC_OK)
- callback->printf_filtered(callback,"Error: \"%s\" is not a valid MIPS simulator command.\n",cmd);
+ idt_monitor_base = address_present ? address : 0xBFC00000;
+ pmon_monitor_base = 0;
+ lsipmon_monitor_base = 0;
}
-
- return;
-}
-
-/*---------------------------------------------------------------------------*/
-/* NOTE: The following routines do not seem to be used by GDB at the
- moment. However, they may be useful to the standalone simulator
- world. */
-
-
-/* The profiling format is described in the "gmon_out.h" header file */
-void
-sim_set_profile (n)
- int n;
-{
-#if defined(PROFILE)
- profile_frequency = n;
- state |= simPROFILE;
-#endif /* PROFILE */
- return;
-}
-
-void
-sim_set_profile_size (n)
- int n;
-{
- SIM_DESC sd = &simulator;
-#if defined(PROFILE)
- if (state & simPROFILE) {
- int bsize;
-
- /* Since we KNOW that the memory banks are a power-of-2 in size: */
- profile_nsamples = power2(n);
- profile_minpc = STATE_MEM_BASE (sd);
- profile_maxpc = (STATE_MEM_BASE (sd) + STATE_MEM_SIZE (sd));
-
- /* Just in-case we are sampling every address: NOTE: The shift
- right of 2 is because we only have word-aligned PC addresses. */
- if (profile_nsamples > (STATE_MEM_SIZE (sd) >> 2))
- profile_nsamples = (STATE_MEM_SIZE (sd) >> 2);
-
- /* Since we are dealing with power-of-2 values: */
- profile_shift = (((STATE_MEM_SIZE (sd) >> 2) / profile_nsamples) - 1);
-
- bsize = (profile_nsamples * sizeof(unsigned short));
- if (profile_hist == NULL)
- profile_hist = (unsigned short *)calloc(64,(bsize / 64));
- else
- profile_hist = (unsigned short *)realloc(profile_hist,bsize);
- if (profile_hist == NULL) {
- sim_warning("Failed to allocate VM for profiling buffer (0x%08X bytes)",bsize);
- state &= ~simPROFILE;
+ else if (! strncmp (arg, "pmon", 4))
+ {
+ /* pmon uses indirect calls. Hook into implied idt. */
+ pmon_monitor_base = address_present ? address : 0xBFC00500;
+ idt_monitor_base = pmon_monitor_base - 0x500;
+ lsipmon_monitor_base = 0;
+ }
+ else if (! strncmp (arg, "lsipmon", 7))
+ {
+ /* lsipmon uses indirect calls. Hook into implied idt. */
+ pmon_monitor_base = 0;
+ lsipmon_monitor_base = address_present ? address : 0xBFC00200;
+ idt_monitor_base = lsipmon_monitor_base - 0x200;
+ }
+ else if (! strncmp (arg, "none", 4))
+ {
+ if (address_present)
+ {
+ sim_io_printf (sd,
+ "The `sim firmware none' command does "
+ "not take an `ADDRESS' argument.\n");
+ return SIM_RC_FAIL;
+ }
+ idt_monitor_base = 0;
+ pmon_monitor_base = 0;
+ lsipmon_monitor_base = 0;
}
- }
-#endif /* PROFILE */
-
- return;
-}
-
-void
-sim_size(newsize)
- int newsize;
-{
- SIM_DESC sd = &simulator;
- char *new;
- /* Used by "run", and internally, to set the simulated memory size */
- if (newsize == 0) {
- callback->printf_filtered(callback,"Zero not valid: Memory size still 0x%08X bytes\n",STATE_MEM_SIZE (sd));
- return;
- }
- newsize = power2(newsize);
- if (STATE_MEMORY (sd) == NULL)
- new = (char *)calloc(64,(STATE_MEM_SIZE (sd) / 64));
else
- new = (char *)realloc(STATE_MEMORY (sd),newsize);
- if (new == NULL) {
- if (STATE_MEMORY (sd) == NULL)
- sim_error("Not enough VM for simulation memory of 0x%08X bytes",STATE_MEM_SIZE (sd));
- else
- sim_warning("Failed to resize memory (still 0x%08X bytes)",STATE_MEM_SIZE (sd));
- } else {
- STATE_MEM_SIZE (sd) = (unsigned)newsize;
- STATE_MEMORY (sd) = new;
-#if defined(PROFILE)
- /* Ensure that we sample across the new memory range */
- sim_set_profile_size(profile_nsamples);
-#endif /* PROFILE */
- }
-
- return;
-}
-
-int
-sim_trace(sd)
- SIM_DESC sd;
-{
- sim_io_eprintf (sd, "Sim trace not supported");
-#if 0
- /* This routine is called by the "run" program, when detailed
- execution information is required. Rather than executing a single
- instruction, and looping around externally... we just start
- simulating, returning TRUE when the simulator stops (for whatever
- reason). */
-
-#if defined(TRACE)
- /* Ensure tracing is enabled, if available */
- if (tracefh == NULL)
{
- open_trace();
- state |= simTRACE;
+ sim_io_printf (sd, "\
+Unrecognized name given to the `sim firmware NAME' command: %s\n\
+Recognized firmware names are: `idt', `pmon', `lsipmon', and `none'.\n",
+ arg);
+ return SIM_RC_FAIL;
}
-#endif /* TRACE */
-
-#if 0
- state &= ~(simSTOP | simSTEP); /* execute until event */
-#endif
- state |= (simHALTEX | simHALTIN); /* treat interrupt event as exception */
- /* Start executing instructions from the current state (set
- explicitly by register updates, or by sim_create_inferior): */
- simulate();
-
-#endif
- return(1);
+
+ return SIM_RC_OK;
}
-/*---------------------------------------------------------------------------*/
-/*-- Private simulator support interface ------------------------------------*/
-/*---------------------------------------------------------------------------*/
+
/* Simple monitor interface (currently setup for the IDT and PMON monitors) */
-static void
-sim_monitor(reason)
- unsigned int reason;
+int
+sim_monitor (SIM_DESC sd,
+ sim_cpu *cpu,
+ address_word cia,
+ unsigned int reason)
{
- SIM_DESC sd = &simulator;
#ifdef DEBUG
printf("DBG: sim_monitor: entered (reason = %d)\n",reason);
#endif /* DEBUG */
/* The following callback functions are available, however the
monitor we are simulating does not make use of them: get_errno,
isatty, lseek, rename, system, time and unlink */
- switch (reason) {
+ switch (reason)
+ {
+
case 6: /* int open(char *path,int flags) */
{
- uword64 paddr;
- int cca;
- if (AddressTranslation(A0,isDATA,isLOAD,&paddr,&cca,isHOST,isREAL))
- V0 = callback->open(callback,(char *)((int)paddr),(int)A1);
- else
- sim_error("Attempt to pass pointer that does not reference simulated memory");
+ char *path = fetch_str (sd, A0);
+ V0 = sim_io_open (sd, path, (int)A1);
+ zfree (path);
+ break;
}
- break;
case 7: /* int read(int file,char *ptr,int len) */
{
- uword64 paddr;
- int cca;
- if (AddressTranslation(A1,isDATA,isLOAD,&paddr,&cca,isHOST,isREAL))
- V0 = callback->read(callback,(int)A0,(char *)((int)paddr),(int)A2);
- else
- sim_error("Attempt to pass pointer that does not reference simulated memory");
+ int fd = A0;
+ int nr = A2;
+ char *buf = zalloc (nr);
+ V0 = sim_io_read (sd, fd, buf, nr);
+ sim_write (sd, A1, buf, nr);
+ zfree (buf);
}
break;
case 8: /* int write(int file,char *ptr,int len) */
{
- uword64 paddr;
- int cca;
- if (AddressTranslation(A1,isDATA,isLOAD,&paddr,&cca,isHOST,isREAL))
- V0 = callback->write(callback,(int)A0,(const char *)((int)paddr),(int)A2);
- else
- sim_error("Attempt to pass pointer that does not reference simulated memory");
+ int fd = A0;
+ int nr = A2;
+ char *buf = zalloc (nr);
+ sim_read (sd, A1, buf, nr);
+ V0 = sim_io_write (sd, fd, buf, nr);
+ if (fd == 1)
+ sim_io_flush_stdout (sd);
+ else if (fd == 2)
+ sim_io_flush_stderr (sd);
+ zfree (buf);
+ break;
}
- break;
case 10: /* int close(int file) */
- V0 = callback->close(callback,(int)A0);
- break;
+ {
+ V0 = sim_io_close (sd, (int)A0);
+ break;
+ }
+
+ case 2: /* Densan monitor: char inbyte(int waitflag) */
+ {
+ if (A0 == 0) /* waitflag == NOWAIT */
+ V0 = (unsigned_word)-1;
+ }
+ /* Drop through to case 11 */
case 11: /* char inbyte(void) */
{
char tmp;
- if (callback->read_stdin(callback,&tmp,sizeof(char)) != sizeof(char)) {
- sim_error("Invalid return from character read");
- V0 = (ut_reg)-1;
- }
+ /* ensure that all output has gone... */
+ sim_io_flush_stdout (sd);
+ if (sim_io_read_stdin (sd, &tmp, sizeof(char)) != sizeof(char))
+ {
+ sim_io_error(sd,"Invalid return from character read");
+ V0 = (unsigned_word)-1;
+ }
else
- V0 = (ut_reg)tmp;
+ V0 = (unsigned_word)tmp;
+ break;
}
- break;
+ case 3: /* Densan monitor: void co(char chr) */
case 12: /* void outbyte(char chr) : write a byte to "stdout" */
{
char tmp = (char)(A0 & 0xFF);
- callback->write_stdout(callback,&tmp,sizeof(char));
+ sim_io_write_stdout (sd, &tmp, sizeof(char));
+ break;
}
- break;
case 17: /* void _exit() */
- sim_warning("sim_monitor(17): _exit(int reason) to be coded");
- sim_engine_halt (sd, STATE_CPU (sd, 0), NULL, NULL_CIA, sim_exited,
- (unsigned int)(A0 & 0xFFFFFFFF));
- break;
+ {
+ sim_io_eprintf (sd, "sim_monitor(17): _exit(int reason) to be coded\n");
+ sim_engine_halt (SD, CPU, NULL, NULL_CIA, sim_exited,
+ (unsigned int)(A0 & 0xFFFFFFFF));
+ break;
+ }
- case 28 : /* PMON flush_cache */
+ case 28: /* PMON flush_cache */
break;
case 55: /* void get_mem_info(unsigned int *ptr) */
/* [A0 + 4] = instruction cache size */
/* [A0 + 8] = data cache size */
{
- uword64 vaddr = A0;
- uword64 paddr, value;
- int cca;
- int failed = 0;
-
- /* NOTE: We use RAW memory writes here, but since we are not
- gathering statistics for the monitor calls we are simulating,
- it is not an issue. */
-
- /* Memory size */
- if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isREAL)) {
- value = (uword64)STATE_MEM_SIZE (sd);
- StoreMemory(cca,AccessLength_WORD,value,0,paddr,vaddr,isRAW);
- /* We re-do the address translations, in-case the block
- overlaps a memory boundary: */
- value = 0;
- vaddr += (AccessLength_WORD + 1);
- if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isREAL)) {
- StoreMemory(cca,AccessLength_WORD,0,value,paddr,vaddr,isRAW);
- vaddr += (AccessLength_WORD + 1);
- if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isREAL))
- StoreMemory(cca,AccessLength_WORD,value,0,paddr,vaddr,isRAW);
- else
- failed = -1;
- } else
- failed = -1;
- } else
- failed = -1;
-
- if (failed)
- sim_error("Invalid pointer passed into monitor call");
- }
- break;
+ unsigned_4 value;
+ unsigned_4 zero = 0;
+ address_word mem_size;
+ sim_memopt *entry, *match = NULL;
+
+ /* Search for memory region mapped to KSEG0 or KSEG1. */
+ for (entry = STATE_MEMOPT (sd);
+ entry != NULL;
+ entry = entry->next)
+ {
+ if ((entry->addr == K0BASE || entry->addr == K1BASE)
+ && (!match || entry->level < match->level))
+ match = entry;
+ else
+ {
+ sim_memopt *alias;
+ for (alias = entry->alias;
+ alias != NULL;
+ alias = alias->next)
+ if ((alias->addr == K0BASE || alias->addr == K1BASE)
+ && (!match || entry->level < match->level))
+ match = entry;
+ }
+ }
- case 158 : /* PMON printf */
+ /* Get region size, limit to KSEG1 size (512MB). */
+ SIM_ASSERT (match != NULL);
+ mem_size = (match->modulo != 0
+ ? match->modulo : match->nr_bytes);
+ if (mem_size > K1SIZE)
+ mem_size = K1SIZE;
+
+ value = mem_size;
+ H2T (value);
+ sim_write (sd, A0 + 0, (char *)&value, 4);
+ sim_write (sd, A0 + 4, (char *)&zero, 4);
+ sim_write (sd, A0 + 8, (char *)&zero, 4);
+ /* sim_io_eprintf (sd, "sim: get_mem_info() deprecated\n"); */
+ break;
+ }
+
+ case 158: /* PMON printf */
/* in: A0 = pointer to format string */
/* A1 = optional argument 1 */
/* A2 = optional argument 2 */
/* out: void */
/* The following is based on the PMON printf source */
{
- uword64 paddr;
- int cca;
+ address_word s = A0;
+ char c;
+ signed_word *ap = &A1; /* 1st argument */
/* This isn't the quickest way, since we call the host print
routine for every character almost. But it does avoid
having to allocate and manage a temporary string buffer. */
- if (AddressTranslation(A0,isDATA,isLOAD,&paddr,&cca,isHOST,isREAL)) {
- char *s = (char *)((int)paddr);
- ut_reg *ap = &A1; /* 1st argument */
- /* TODO: Include check that we only use three arguments (A1, A2 and A3) */
- for (; *s;) {
- if (*s == '%') {
- char tmp[40];
- enum {FMT_RJUST, FMT_LJUST, FMT_RJUST0, FMT_CENTER} fmt = FMT_RJUST;
- int width = 0, trunc = 0, haddot = 0, longlong = 0;
- s++;
- for (; *s; s++) {
- if (strchr ("dobxXulscefg%", *s))
- break;
- else if (*s == '-')
- fmt = FMT_LJUST;
- else if (*s == '0')
- fmt = FMT_RJUST0;
- else if (*s == '~')
- fmt = FMT_CENTER;
- else if (*s == '*') {
- if (haddot)
- trunc = (int)*ap++;
- else
- width = (int)*ap++;
- } else if (*s >= '1' && *s <= '9') {
- char *t;
- unsigned int n;
- for (t = s; isdigit (*s); s++);
- strncpy (tmp, t, s - t);
- tmp[s - t] = '\0';
- n = (unsigned int)strtol(tmp,NULL,10);
- if (haddot)
- trunc = n;
- else
- width = n;
- s--;
- } else if (*s == '.')
- haddot = 1;
- }
- if (*s == '%') {
- callback->printf_filtered(callback,"%%");
- } else if (*s == 's') {
- if ((int)*ap != 0) {
- if (AddressTranslation(*ap++,isDATA,isLOAD,&paddr,&cca,isHOST,isREAL)) {
- char *p = (char *)((int)paddr);;
- callback->printf_filtered(callback,p);
- } else {
- ap++;
- sim_error("Attempt to pass pointer that does not reference simulated memory");
- }
- }
- else
- callback->printf_filtered(callback,"(null)");
- } else if (*s == 'c') {
- int n = (int)*ap++;
- callback->printf_filtered(callback,"%c",n);
- } else {
- if (*s == 'l') {
- if (*++s == 'l') {
- longlong = 1;
- ++s;
- }
- }
- if (strchr ("dobxXu", *s)) {
- word64 lv = (word64) *ap++;
- if (*s == 'b')
- callback->printf_filtered(callback,"<binary not supported>");
- else {
- sprintf(tmp,"%%%s%c",longlong ? "ll" : "",*s);
- if (longlong)
- callback->printf_filtered(callback,tmp,lv);
- else
- callback->printf_filtered(callback,tmp,(int)lv);
- }
- } else if (strchr ("eEfgG", *s)) {
-#ifdef _MSC_VER /* MSVC version 2.x can't convert from uword64 directly */
- double dbl = (double)((word64)*ap++);
-#else
- double dbl = (double)*ap++;
-#endif
- sprintf(tmp,"%%%d.%d%c",width,trunc,*s);
- callback->printf_filtered(callback,tmp,dbl);
- trunc = 0;
- }
- }
- s++;
- } else
- callback->printf_filtered(callback,"%c",*s++);
- }
- } else
- sim_error("Attempt to pass pointer that does not reference simulated memory");
+ /* TODO: Include check that we only use three arguments (A1,
+ A2 and A3) */
+ while (sim_read (sd, s++, &c, 1) && c != '\0')
+ {
+ if (c == '%')
+ {
+ char tmp[40];
+ enum {FMT_RJUST, FMT_LJUST, FMT_RJUST0, FMT_CENTER} fmt = FMT_RJUST;
+ int width = 0, trunc = 0, haddot = 0, longlong = 0;
+ while (sim_read (sd, s++, &c, 1) && c != '\0')
+ {
+ if (strchr ("dobxXulscefg%", c))
+ break;
+ else if (c == '-')
+ fmt = FMT_LJUST;
+ else if (c == '0')
+ fmt = FMT_RJUST0;
+ else if (c == '~')
+ fmt = FMT_CENTER;
+ else if (c == '*')
+ {
+ if (haddot)
+ trunc = (int)*ap++;
+ else
+ width = (int)*ap++;
+ }
+ else if (c >= '1' && c <= '9')
+ {
+ address_word t = s;
+ unsigned int n;
+ while (sim_read (sd, s++, &c, 1) == 1 && isdigit (c))
+ tmp[s - t] = c;
+ tmp[s - t] = '\0';
+ n = (unsigned int)strtol(tmp,NULL,10);
+ if (haddot)
+ trunc = n;
+ else
+ width = n;
+ s--;
+ }
+ else if (c == '.')
+ haddot = 1;
+ }
+ switch (c)
+ {
+ case '%':
+ sim_io_printf (sd, "%%");
+ break;
+ case 's':
+ if ((int)*ap != 0)
+ {
+ address_word p = *ap++;
+ char ch;
+ while (sim_read (sd, p++, &ch, 1) == 1 && ch != '\0')
+ sim_io_printf(sd, "%c", ch);
+ }
+ else
+ sim_io_printf(sd,"(null)");
+ break;
+ case 'c':
+ sim_io_printf (sd, "%c", (int)*ap++);
+ break;
+ default:
+ if (c == 'l')
+ {
+ sim_read (sd, s++, &c, 1);
+ if (c == 'l')
+ {
+ longlong = 1;
+ sim_read (sd, s++, &c, 1);
+ }
+ }
+ if (strchr ("dobxXu", c))
+ {
+ word64 lv = (word64) *ap++;
+ if (c == 'b')
+ sim_io_printf(sd,"<binary not supported>");
+ else
+ {
+ sprintf (tmp, "%%%s%c", longlong ? "ll" : "", c);
+ if (longlong)
+ sim_io_printf(sd, tmp, lv);
+ else
+ sim_io_printf(sd, tmp, (int)lv);
+ }
+ }
+ else if (strchr ("eEfgG", c))
+ {
+ double dbl = *(double*)(ap++);
+ sprintf (tmp, "%%%d.%d%c", width, trunc, c);
+ sim_io_printf (sd, tmp, dbl);
+ trunc = 0;
+ }
+ }
+ }
+ else
+ sim_io_printf(sd, "%c", c);
+ }
+ break;
}
- break;
default:
- sim_warning("TODO: sim_monitor(%d) : PC = 0x%s",reason,pr_addr(IPC));
- sim_warning("(Arguments : A0 = 0x%s : A1 = 0x%s : A2 = 0x%s : A3 = 0x%s)",pr_addr(A0),pr_addr(A1),pr_addr(A2),pr_addr(A3));
- break;
+ /* Unknown reason. */
+ return 0;
}
- return;
+ return 1;
}
/* Store a word into memory. */
static void
-store_word (vaddr, val)
- uword64 vaddr;
- t_reg val;
+store_word (SIM_DESC sd,
+ sim_cpu *cpu,
+ address_word cia,
+ uword64 vaddr,
+ signed_word val)
{
- uword64 paddr;
+ address_word paddr;
int uncached;
if ((vaddr & 3) != 0)
- SignalException (AddressStore);
+ SignalExceptionAddressStore ();
else
{
if (AddressTranslation (vaddr, isDATA, isSTORE, &paddr, &uncached,
/* Load a word from memory. */
-static t_reg
-load_word (vaddr)
- uword64 vaddr;
+static signed_word
+load_word (SIM_DESC sd,
+ sim_cpu *cpu,
+ address_word cia,
+ uword64 vaddr)
{
if ((vaddr & 3) != 0)
- SignalException (AddressLoad);
+ {
+ SIM_CORE_SIGNAL (SD, cpu, cia, read_map, AccessLength_WORD+1, vaddr, read_transfer, sim_core_unaligned_signal);
+ }
else
{
- uword64 paddr;
+ address_word paddr;
int uncached;
if (AddressTranslation (vaddr, isDATA, isLOAD, &paddr, &uncached,
LoadMemory (&memval,NULL,uncached, AccessLength_WORD, paddr, vaddr,
isDATA, isREAL);
byte = (vaddr & mask) ^ (bigend << 2);
- return SIGNEXTEND (((memval >> (8 * byte)) & 0xffffffff), 32);
+ return EXTEND32 (memval >> (8 * byte));
}
}
code, but for ease of simulation we just handle them directly. */
static void
-mips16_entry (insn)
- unsigned int insn;
+mips16_entry (SIM_DESC sd,
+ sim_cpu *cpu,
+ address_word cia,
+ unsigned int insn)
{
int aregs, sregs, rreg;
if (aregs < 5)
{
int i;
- t_reg tsp;
+ signed_word tsp;
/* This is the entry pseudo-instruction. */
for (i = 0; i < aregs; i++)
- store_word ((uword64) (SP + 4 * i), registers[i + 4]);
+ store_word (SD, CPU, cia, (uword64) (SP + 4 * i), GPR[i + 4]);
tsp = SP;
SP -= 32;
if (rreg)
{
tsp -= 4;
- store_word ((uword64) tsp, RA);
+ store_word (SD, CPU, cia, (uword64) tsp, RA);
}
for (i = 0; i < sregs; i++)
{
tsp -= 4;
- store_word ((uword64) tsp, registers[16 + i]);
+ store_word (SD, CPU, cia, (uword64) tsp, GPR[16 + i]);
}
}
else
{
int i;
- t_reg tsp;
+ signed_word tsp;
/* This is the exit pseudo-instruction. */
if (rreg)
{
tsp -= 4;
- RA = load_word ((uword64) tsp);
+ RA = load_word (SD, CPU, cia, (uword64) tsp);
}
for (i = 0; i < sregs; i++)
{
tsp -= 4;
- registers[i + 16] = load_word ((uword64) tsp);
+ GPR[i + 16] = load_word (SD, CPU, cia, (uword64) tsp);
}
SP += 32;
- if (aregs == 5)
- {
- FGR[0] = WORD64LO (GPR[4]);
- fpr_state[0] = fmt_uninterpreted;
- }
- else if (aregs == 6)
+ if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT)
{
- FGR[0] = WORD64LO (GPR[5]);
- FGR[1] = WORD64LO (GPR[4]);
- fpr_state[0] = fmt_uninterpreted;
- fpr_state[1] = fmt_uninterpreted;
- }
+ if (aregs == 5)
+ {
+ FGR[0] = WORD64LO (GPR[4]);
+ FPR_STATE[0] = fmt_uninterpreted;
+ }
+ else if (aregs == 6)
+ {
+ FGR[0] = WORD64LO (GPR[5]);
+ FGR[1] = WORD64LO (GPR[4]);
+ FPR_STATE[0] = fmt_uninterpreted;
+ FPR_STATE[1] = fmt_uninterpreted;
+ }
+ }
PC = RA;
}
-}
-
-void
-sim_warning(char *fmt,...)
-{
- char buf[256];
- va_list ap;
-
- va_start (ap,fmt);
- vsprintf (buf, fmt, ap);
- va_end (ap);
- if (logfh != NULL) {
- fprintf(logfh,"SIM Warning: %s\n", buf);
- } else {
- callback->printf_filtered(callback,"SIM Warning: %s\n", buf);
- }
- /* This used to call SignalException with a SimulatorFault, but that causes
- the simulator to exit, and that is inappropriate for a warning. */
- return;
-}
-
-void
-sim_error(char *fmt,...)
-{
- char buf[256];
- va_list ap;
-
- va_start (ap,fmt);
- vsprintf (buf, fmt, ap);
- va_end (ap);
-
- callback->printf_filtered(callback,"SIM Error: %s", buf);
- SignalException (SimulatorFault, buf);
- return;
-}
-
-static unsigned int
-power2(value)
- unsigned int value;
-{
- int loop,tmp;
-
- /* Round *UP* to the nearest power-of-2 if not already one */
- if (value != (value & ~(value - 1))) {
- for (tmp = value, loop = 0; (tmp != 0); loop++)
- tmp >>= 1;
- value = (1 << loop);
- }
-
- return(value);
-}
-
-static long
-getnum(value)
- char *value;
-{
- long num;
- char *end;
-
- num = strtol(value,&end,10);
- if (end == value)
- callback->printf_filtered(callback,"Warning: Invalid number \"%s\" ignored, using zero\n",value);
- else {
- if (*end && ((tolower(*end) == 'k') || (tolower(*end) == 'm'))) {
- if (tolower(*end) == 'k')
- num *= (1 << 10);
- else
- num *= (1 << 20);
- end++;
- }
- if (*end)
- callback->printf_filtered(callback,"Warning: Spurious characters \"%s\" at end of number ignored\n",end);
- }
-
- return(num);
}
/*-- trace support ----------------------------------------------------------*/
currently have an ARM version of their tool called ChARM. */
-static
-void dotrace(FILE *tracefh,int type,SIM_ADDR address,int width,char *comment,...)
-{
- if (state & simTRACE) {
+void
+dotrace (SIM_DESC sd,
+ sim_cpu *cpu,
+ FILE *tracefh,
+ int type,
+ SIM_ADDR address,
+ int width,
+ char *comment,...)
+{
+ if (STATE & simTRACE) {
va_list ap;
fprintf(tracefh,"%d %s ; width %d ; ",
type,
/*---------------------------------------------------------------------------*/
static void
-ColdReset()
-{
- /* RESET: Fixed PC address: */
- PC = (((uword64)0xFFFFFFFF<<32) | 0xBFC00000);
- /* The reset vector address is in the unmapped, uncached memory space. */
-
- SR &= ~(status_SR | status_TS | status_RP);
- SR |= (status_ERL | status_BEV);
-
-#if defined(HASFPU) && (GPRLEN == (64))
- /* Cheat and allow access to the complete register set immediately: */
- SR |= status_FR; /* 64bit registers */
-#endif /* HASFPU and 64bit FP registers */
-
- /* Ensure that any instructions with pending register updates are
- cleared: */
- {
- int loop;
- for (loop = 0; (loop < PSLOTS); loop++)
- pending_slot_reg[loop] = (LAST_EMBED_REGNUM + 1);
- pending_in = pending_out = pending_total = 0;
- }
-
-#if defined(HASFPU)
- /* Initialise the FPU registers to the unknown state */
- {
- int rn;
- for (rn = 0; (rn < 32); rn++)
- fpr_state[rn] = fmt_uninterpreted;
- }
-#endif /* HASFPU */
-
- return;
-}
-
-/* Description from page A-22 of the "MIPS IV Instruction Set" manual (revision 3.1) */
-/* Translate a virtual address to a physical address and cache
- coherence algorithm describing the mechanism used to resolve the
- memory reference. Given the virtual address vAddr, and whether the
- reference is to Instructions ot Data (IorD), find the corresponding
- physical address (pAddr) and the cache coherence algorithm (CCA)
- used to resolve the reference. If the virtual address is in one of
- the unmapped address spaces the physical address and the CCA are
- determined directly by the virtual address. If the virtual address
- is in one of the mapped address spaces then the TLB is used to
- determine the physical address and access type; if the required
- translation is not present in the TLB or the desired access is not
- permitted the function fails and an exception is taken.
-
- NOTE: This function is extended to return an exception state. This,
- along with the exception generation is used to notify whether a
- valid address translation occured */
-
-static int
-AddressTranslation(vAddr,IorD,LorS,pAddr,CCA,host,raw)
- uword64 vAddr;
- int IorD;
- int LorS;
- uword64 *pAddr;
- int *CCA;
- int host;
- int raw;
-{
- SIM_DESC sd = &simulator;
- int res = -1; /* TRUE : Assume good return */
-
-#ifdef DEBUG
- callback->printf_filtered(callback,"AddressTranslation(0x%s,%s,%s,...);\n",pr_addr(vAddr),(IorD ? "isDATA" : "isINSTRUCTION"),(LorS ? "iSTORE" : "isLOAD"));
-#endif
-
- /* Check that the address is valid for this memory model */
-
- /* For a simple (flat) memory model, we simply pass virtual
- addressess through (mostly) unchanged. */
- vAddr &= 0xFFFFFFFF;
-
- /* Treat the kernel memory spaces identically for the moment: */
- if ((STATE_MEM_BASE (sd) == K1BASE) && (vAddr >= K0BASE) && (vAddr < (K0BASE + K0SIZE)))
- vAddr += (K1BASE - K0BASE);
-
- /* Also assume that the K1BASE memory wraps. This is required to
- allow the PMON run-time __sizemem() routine to function (without
- having to provide exception simulation). NOTE: A kludge to work
- around the fact that the monitor memory is currently held in the
- K1BASE space. */
- if (((vAddr < monitor_base) || (vAddr >= (monitor_base + monitor_size))) && (vAddr >= K1BASE && vAddr < (K1BASE + K1SIZE)))
- vAddr = (K1BASE | (vAddr & (STATE_MEM_SIZE (sd) - 1)));
-
- *pAddr = vAddr; /* default for isTARGET */
- *CCA = Uncached; /* not used for isHOST */
-
- /* NOTE: This is a duplicate of the code that appears in the
- LoadMemory and StoreMemory functions. They should be merged into
- a single function (that can be in-lined if required). */
- if ((vAddr >= STATE_MEM_BASE (sd)) && (vAddr < (STATE_MEM_BASE (sd) + STATE_MEM_SIZE (sd)))) {
- if (host)
- *pAddr = (int)&STATE_MEMORY (sd)[((unsigned int)(vAddr - STATE_MEM_BASE (sd)) & (STATE_MEM_SIZE (sd) - 1))];
- } else if ((vAddr >= monitor_base) && (vAddr < (monitor_base + monitor_size))) {
- if (host)
- *pAddr = (int)&monitor[((unsigned int)(vAddr - monitor_base) & (monitor_size - 1))];
- } else {
-#ifdef DEBUG
- sim_warning("Failed: AddressTranslation(0x%s,%s,%s,...) IPC = 0x%s",pr_addr(vAddr),(IorD ? "isDATA" : "isINSTRUCTION"),(LorS ? "isSTORE" : "isLOAD"),pr_addr(IPC));
-#endif /* DEBUG */
- res = 0; /* AddressTranslation has failed */
- *pAddr = (SIM_ADDR)-1;
- if (!raw) /* only generate exceptions on real memory transfers */
- SignalException((LorS == isSTORE) ? AddressStore : AddressLoad);
-#ifdef DEBUG
- else
- /* This is a normal occurance during gdb operation, for instance trying
- to print parameters at function start before they have been setup,
- and hence we should not print a warning except when debugging the
- simulator. */
- sim_warning("AddressTranslation for %s %s from 0x%s failed",(IorD ? "data" : "instruction"),(LorS ? "store" : "load"),pr_addr(vAddr));
-#endif
- }
-
- return(res);
-}
-
-/* Description from page A-23 of the "MIPS IV Instruction Set" manual (revision 3.1) */
-/* Prefetch data from memory. Prefetch is an advisory instruction for
- which an implementation specific action is taken. The action taken
- may increase performance, but must not change the meaning of the
- program, or alter architecturally-visible state. */
-
-static void UNUSED
-Prefetch(CCA,pAddr,vAddr,DATA,hint)
- int CCA;
- uword64 pAddr;
- uword64 vAddr;
- int DATA;
- int hint;
-{
-#ifdef DEBUG
- callback->printf_filtered(callback,"Prefetch(%d,0x%s,0x%s,%d,%d);\n",CCA,pr_addr(pAddr),pr_addr(vAddr),DATA,hint);
-#endif /* DEBUG */
-
- /* For our simple memory model we do nothing */
- return;
-}
-
-/* Description from page A-22 of the "MIPS IV Instruction Set" manual (revision 3.1) */
-/* Load a value from memory. Use the cache and main memory as
- specified in the Cache Coherence Algorithm (CCA) and the sort of
- access (IorD) to find the contents of AccessLength memory bytes
- starting at physical location pAddr. The data is returned in the
- fixed width naturally-aligned memory element (MemElem). The
- low-order two (or three) bits of the address and the AccessLength
- indicate which of the bytes within MemElem needs to be given to the
- processor. If the memory access type of the reference is uncached
- then only the referenced bytes are read from memory and valid
- within the memory element. If the access type is cached, and the
- data is not present in cache, an implementation specific size and
- alignment block of memory is read and loaded into the cache to
- satisfy a load reference. At a minimum, the block is the entire
- memory element. */
-static void
-LoadMemory(memvalp,memval1p,CCA,AccessLength,pAddr,vAddr,IorD,raw)
- uword64* memvalp;
- uword64* memval1p;
- int CCA;
- int AccessLength;
- uword64 pAddr;
- uword64 vAddr;
- int IorD;
- int raw;
+ColdReset (SIM_DESC sd)
{
- SIM_DESC sd = &simulator;
- uword64 value = 0;
- uword64 value1 = 0;
-
-#ifdef DEBUG
- if (STATE_MEMORY (sd) == NULL)
- callback->printf_filtered(callback,"DBG: LoadMemory(%p,%p,%d,%d,0x%s,0x%s,%s,%s)\n",memvalp,memval1p,CCA,AccessLength,pr_addr(pAddr),pr_addr(vAddr),(IorD ? "isDATA" : "isINSTRUCTION"),(raw ? "isRAW" : "isREAL"));
-#endif /* DEBUG */
-
-#if defined(WARN_MEM)
- if (CCA != uncached)
- sim_warning("LoadMemory CCA (%d) is not uncached (currently all accesses treated as cached)",CCA);
-
- if (((pAddr & LOADDRMASK) + AccessLength) > LOADDRMASK) {
- /* In reality this should be a Bus Error */
- sim_error("AccessLength of %d would extend over %dbit aligned boundary for physical address 0x%s\n",AccessLength,(LOADDRMASK + 1)<<2,pr_addr(pAddr));
- }
-#endif /* WARN_MEM */
-
- /* Decide which physical memory locations are being dealt with. At
- this point we should be able to split the pAddr bits into the
- relevant address map being simulated. If the "raw" variable is
- set, the memory read being performed should *NOT* update any I/O
- state or affect the CPU state. This also includes avoiding
- affecting statistics gathering. */
-
- /* If instruction fetch then we need to check that the two lo-order
- bits are zero, otherwise raise a InstructionFetch exception: */
- if ((IorD == isINSTRUCTION)
- && ((pAddr & 0x3) != 0)
- && (((pAddr & 0x1) != 0) || ((vAddr & 0x1) == 0)))
- SignalException(InstructionFetch);
- else {
- unsigned int index = 0;
- unsigned char *mem = NULL;
-
-#if defined(TRACE)
- if (!raw)
- dotrace(tracefh,((IorD == isDATA) ? 0 : 2),(unsigned int)(pAddr&0xFFFFFFFF),(AccessLength + 1),"load%s",((IorD == isDATA) ? "" : " instruction"));
-#endif /* TRACE */
-
- /* NOTE: Quicker methods of decoding the address space can be used
- when a real memory map is being simulated (i.e. using hi-order
- address bits to select device). */
- if ((pAddr >= STATE_MEM_BASE (sd)) && (pAddr < (STATE_MEM_BASE (sd) + STATE_MEM_SIZE (sd)))) {
- index = ((unsigned int)(pAddr - STATE_MEM_BASE (sd)) & (STATE_MEM_SIZE (sd) - 1));
- mem = STATE_MEMORY (sd);
- } else if ((pAddr >= monitor_base) && (pAddr < (monitor_base + monitor_size))) {
- index = ((unsigned int)(pAddr - monitor_base) & (monitor_size - 1));
- mem = monitor;
- }
- if (mem == NULL)
- sim_error("Simulator memory not found for physical address 0x%s\n",pr_addr(pAddr));
- else {
- /* If we obtained the endianness of the host, and it is the same
- as the target memory system we can optimise the memory
- accesses. However, without that information we must perform
- slow transfer, and hope that the compiler optimisation will
- merge successive loads. */
-
- /* In reality we should always be loading a doubleword value (or
- word value in 32bit memory worlds). The external code then
- extracts the required bytes. However, to keep performance
- high we only load the required bytes into the relevant
- slots. */
+ int cpu_nr;
+ for (cpu_nr = 0; cpu_nr < sim_engine_nr_cpus (sd); cpu_nr++)
+ {
+ sim_cpu *cpu = STATE_CPU (sd, cpu_nr);
+ /* RESET: Fixed PC address: */
+ PC = (unsigned_word) UNSIGNED64 (0xFFFFFFFFBFC00000);
+ /* The reset vector address is in the unmapped, uncached memory space. */
+
+ SR &= ~(status_SR | status_TS | status_RP);
+ SR |= (status_ERL | status_BEV);
+
+ /* Cheat and allow access to the complete register set immediately */
+ if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT
+ && WITH_TARGET_WORD_BITSIZE == 64)
+ SR |= status_FR; /* 64bit registers */
+
+ /* Ensure that any instructions with pending register updates are
+ cleared: */
+ PENDING_INVALIDATE();
+
+ /* Initialise the FPU registers to the unknown state */
+ if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT)
+ {
+ int rn;
+ for (rn = 0; (rn < 32); rn++)
+ FPR_STATE[rn] = fmt_uninterpreted;
+ }
+
+ /* Initialise the Config0 register. */
+ C0_CONFIG = 0x80000000 /* Config1 present */
+ | 2; /* KSEG0 uncached */
+ if (WITH_TARGET_WORD_BITSIZE == 64)
+ {
+ /* FIXME Currently mips/sim-main.c:address_translation()
+ truncates all addresses to 32-bits. */
+ if (0 && WITH_TARGET_ADDRESS_BITSIZE == 64)
+ C0_CONFIG |= (2 << 13); /* MIPS64, 64-bit addresses */
+ else
+ C0_CONFIG |= (1 << 13); /* MIPS64, 32-bit addresses */
+ }
if (BigEndianMem)
- switch (AccessLength) { /* big-endian memory */
- case AccessLength_QUADWORD :
- value1 |= ((uword64)mem[index++] << 56);
- case 14: /* AccessLength is one less than datalen */
- value1 |= ((uword64)mem[index++] << 48);
- case 13:
- value1 |= ((uword64)mem[index++] << 40);
- case 12:
- value1 |= ((uword64)mem[index++] << 32);
- case 11:
- value1 |= ((unsigned int)mem[index++] << 24);
- case 10:
- value1 |= ((unsigned int)mem[index++] << 16);
- case 9:
- value1 |= ((unsigned int)mem[index++] << 8);
- case 8:
- value1 |= mem[index];
-
- case AccessLength_DOUBLEWORD :
- value |= ((uword64)mem[index++] << 56);
- case AccessLength_SEPTIBYTE :
- value |= ((uword64)mem[index++] << 48);
- case AccessLength_SEXTIBYTE :
- value |= ((uword64)mem[index++] << 40);
- case AccessLength_QUINTIBYTE :
- value |= ((uword64)mem[index++] << 32);
- case AccessLength_WORD :
- value |= ((unsigned int)mem[index++] << 24);
- case AccessLength_TRIPLEBYTE :
- value |= ((unsigned int)mem[index++] << 16);
- case AccessLength_HALFWORD :
- value |= ((unsigned int)mem[index++] << 8);
- case AccessLength_BYTE :
- value |= mem[index];
- break;
- }
- else {
- index += (AccessLength + 1);
- switch (AccessLength) { /* little-endian memory */
- case AccessLength_QUADWORD :
- value1 |= ((uword64)mem[--index] << 56);
- case 14: /* AccessLength is one less than datalen */
- value1 |= ((uword64)mem[--index] << 48);
- case 13:
- value1 |= ((uword64)mem[--index] << 40);
- case 12:
- value1 |= ((uword64)mem[--index] << 32);
- case 11:
- value1 |= ((uword64)mem[--index] << 24);
- case 10:
- value1 |= ((uword64)mem[--index] << 16);
- case 9:
- value1 |= ((uword64)mem[--index] << 8);
- case 8:
- value1 |= ((uword64)mem[--index] << 0);
-
- case AccessLength_DOUBLEWORD :
- value |= ((uword64)mem[--index] << 56);
- case AccessLength_SEPTIBYTE :
- value |= ((uword64)mem[--index] << 48);
- case AccessLength_SEXTIBYTE :
- value |= ((uword64)mem[--index] << 40);
- case AccessLength_QUINTIBYTE :
- value |= ((uword64)mem[--index] << 32);
- case AccessLength_WORD :
- value |= ((uword64)mem[--index] << 24);
- case AccessLength_TRIPLEBYTE :
- value |= ((uword64)mem[--index] << 16);
- case AccessLength_HALFWORD :
- value |= ((uword64)mem[--index] << 8);
- case AccessLength_BYTE :
- value |= ((uword64)mem[--index] << 0);
- break;
- }
- }
-
-#ifdef DEBUG
- printf("DBG: LoadMemory() : (offset %d) : value = 0x%s%s\n",
- (int)(pAddr & LOADDRMASK),pr_uword64(value1),pr_uword64(value));
-#endif /* DEBUG */
-
- /* TODO: We could try and avoid the shifts when dealing with raw
- memory accesses. This would mean updating the LoadMemory and
- StoreMemory routines to avoid shifting the data before
- returning or using it. */
- if (AccessLength <= AccessLength_DOUBLEWORD) {
- if (!raw) { /* do nothing for raw accessess */
- if (BigEndianMem)
- value <<= (((7 - (pAddr & LOADDRMASK)) - AccessLength) * 8);
- else /* little-endian only needs to be shifted up to the correct byte offset */
- value <<= ((pAddr & LOADDRMASK) * 8);
- }
- }
-
-#ifdef DEBUG
- printf("DBG: LoadMemory() : shifted value = 0x%s%s\n",
- pr_uword64(value1),pr_uword64(value));
-#endif /* DEBUG */
+ C0_CONFIG |= 0x00008000; /* Big Endian */
}
- }
-
-*memvalp = value;
-if (memval1p) *memval1p = value1;
}
-/* Description from page A-23 of the "MIPS IV Instruction Set" manual
- (revision 3.1) */
-/* Store a value to memory. The specified data is stored into the
- physical location pAddr using the memory hierarchy (data caches and
- main memory) as specified by the Cache Coherence Algorithm
- (CCA). The MemElem contains the data for an aligned, fixed-width
- memory element (word for 32-bit processors, doubleword for 64-bit
- processors), though only the bytes that will actually be stored to
- memory need to be valid. The low-order two (or three) bits of pAddr
- and the AccessLength field indicates which of the bytes within the
- MemElem data should actually be stored; only these bytes in memory
- will be changed. */
-
-static void
-StoreMemory(CCA,AccessLength,MemElem,MemElem1,pAddr,vAddr,raw)
- int CCA;
- int AccessLength;
- uword64 MemElem;
- uword64 MemElem1; /* High order 64 bits */
- uword64 pAddr;
- uword64 vAddr;
- int raw;
-{
- SIM_DESC sd = &simulator;
-#ifdef DEBUG
- callback->printf_filtered(callback,"DBG: StoreMemory(%d,%d,0x%s,0x%s,0x%s,0x%s,%s)\n",CCA,AccessLength,pr_uword64(MemElem),pr_uword64(MemElem1),pr_addr(pAddr),pr_addr(vAddr),(raw ? "isRAW" : "isREAL"));
-#endif /* DEBUG */
-
-#if defined(WARN_MEM)
- if (CCA != uncached)
- sim_warning("StoreMemory CCA (%d) is not uncached (currently all accesses treated as cached)",CCA);
-
- if (((pAddr & LOADDRMASK) + AccessLength) > LOADDRMASK)
- sim_error("AccessLength of %d would extend over %dbit aligned boundary for physical address 0x%s\n",AccessLength,(LOADDRMASK + 1)<<2,pr_addr(pAddr));
-#endif /* WARN_MEM */
-
-#if defined(TRACE)
- if (!raw)
- dotrace(tracefh,1,(unsigned int)(pAddr&0xFFFFFFFF),(AccessLength + 1),"store");
-#endif /* TRACE */
-
- /* See the comments in the LoadMemory routine about optimising
- memory accesses. Also if we wanted to make the simulator smaller,
- we could merge a lot of this code with the LoadMemory
- routine. However, this would slow the simulator down with
- run-time conditionals. */
- {
- unsigned int index = 0;
- unsigned char *mem = NULL;
-
- if ((pAddr >= STATE_MEM_BASE (sd)) && (pAddr < (STATE_MEM_BASE (sd) + STATE_MEM_SIZE (sd)))) {
- index = ((unsigned int)(pAddr - STATE_MEM_BASE (sd)) & (STATE_MEM_SIZE (sd) - 1));
- mem = STATE_MEMORY (sd);
- } else if ((pAddr >= monitor_base) && (pAddr < (monitor_base + monitor_size))) {
- index = ((unsigned int)(pAddr - monitor_base) & (monitor_size - 1));
- mem = monitor;
- }
-
- if (mem == NULL)
- sim_error("Simulator memory not found for physical address 0x%s\n",pr_addr(pAddr));
- else {
- int shift = 0;
-
-#ifdef DEBUG
- printf("DBG: StoreMemory: offset = %d MemElem = 0x%s%s\n",(unsigned int)(pAddr & LOADDRMASK),pr_uword64(MemElem1),pr_uword64(MemElem));
-#endif /* DEBUG */
-
- if (AccessLength <= AccessLength_DOUBLEWORD) {
- if (BigEndianMem) {
- if (raw)
- shift = ((7 - AccessLength) * 8);
- else /* real memory access */
- shift = ((pAddr & LOADDRMASK) * 8);
- MemElem <<= shift;
- } else {
- /* no need to shift raw little-endian data */
- if (!raw)
- MemElem >>= ((pAddr & LOADDRMASK) * 8);
- }
- }
-
-#ifdef DEBUG
- printf("DBG: StoreMemory: shift = %d MemElem = 0x%s%s\n",shift,pr_uword64(MemElem1),pr_uword64(MemElem));
-#endif /* DEBUG */
-
- if (BigEndianMem) {
- switch (AccessLength) { /* big-endian memory */
- case AccessLength_QUADWORD :
- mem[index++] = (unsigned char)(MemElem1 >> 56);
- MemElem1 <<= 8;
- case 14 :
- mem[index++] = (unsigned char)(MemElem1 >> 56);
- MemElem1 <<= 8;
- case 13 :
- mem[index++] = (unsigned char)(MemElem1 >> 56);
- MemElem1 <<= 8;
- case 12 :
- mem[index++] = (unsigned char)(MemElem1 >> 56);
- MemElem1 <<= 8;
- case 11 :
- mem[index++] = (unsigned char)(MemElem1 >> 56);
- MemElem1 <<= 8;
- case 10 :
- mem[index++] = (unsigned char)(MemElem1 >> 56);
- MemElem1 <<= 8;
- case 9 :
- mem[index++] = (unsigned char)(MemElem1 >> 56);
- MemElem1 <<= 8;
- case 8 :
- mem[index++] = (unsigned char)(MemElem1 >> 56);
-
- case AccessLength_DOUBLEWORD :
- mem[index++] = (unsigned char)(MemElem >> 56);
- MemElem <<= 8;
- case AccessLength_SEPTIBYTE :
- mem[index++] = (unsigned char)(MemElem >> 56);
- MemElem <<= 8;
- case AccessLength_SEXTIBYTE :
- mem[index++] = (unsigned char)(MemElem >> 56);
- MemElem <<= 8;
- case AccessLength_QUINTIBYTE :
- mem[index++] = (unsigned char)(MemElem >> 56);
- MemElem <<= 8;
- case AccessLength_WORD :
- mem[index++] = (unsigned char)(MemElem >> 56);
- MemElem <<= 8;
- case AccessLength_TRIPLEBYTE :
- mem[index++] = (unsigned char)(MemElem >> 56);
- MemElem <<= 8;
- case AccessLength_HALFWORD :
- mem[index++] = (unsigned char)(MemElem >> 56);
- MemElem <<= 8;
- case AccessLength_BYTE :
- mem[index++] = (unsigned char)(MemElem >> 56);
- break;
- }
- } else {
- index += (AccessLength + 1);
- switch (AccessLength) { /* little-endian memory */
- case AccessLength_QUADWORD :
- mem[--index] = (unsigned char)(MemElem1 >> 56);
- case 14 :
- mem[--index] = (unsigned char)(MemElem1 >> 48);
- case 13 :
- mem[--index] = (unsigned char)(MemElem1 >> 40);
- case 12 :
- mem[--index] = (unsigned char)(MemElem1 >> 32);
- case 11 :
- mem[--index] = (unsigned char)(MemElem1 >> 24);
- case 10 :
- mem[--index] = (unsigned char)(MemElem1 >> 16);
- case 9 :
- mem[--index] = (unsigned char)(MemElem1 >> 8);
- case 8 :
- mem[--index] = (unsigned char)(MemElem1 >> 0);
-
- case AccessLength_DOUBLEWORD :
- mem[--index] = (unsigned char)(MemElem >> 56);
- case AccessLength_SEPTIBYTE :
- mem[--index] = (unsigned char)(MemElem >> 48);
- case AccessLength_SEXTIBYTE :
- mem[--index] = (unsigned char)(MemElem >> 40);
- case AccessLength_QUINTIBYTE :
- mem[--index] = (unsigned char)(MemElem >> 32);
- case AccessLength_WORD :
- mem[--index] = (unsigned char)(MemElem >> 24);
- case AccessLength_TRIPLEBYTE :
- mem[--index] = (unsigned char)(MemElem >> 16);
- case AccessLength_HALFWORD :
- mem[--index] = (unsigned char)(MemElem >> 8);
- case AccessLength_BYTE :
- mem[--index] = (unsigned char)(MemElem >> 0);
- break;
- }
- }
- }
- }
-
- return;
-}
-
-/* Description from page A-26 of the "MIPS IV Instruction Set" manual (revision 3.1) */
-/* Order loads and stores to synchronise shared memory. Perform the
- action necessary to make the effects of groups of synchronizable
- loads and stores indicated by stype occur in the same order for all
- processors. */
-static void
-SyncOperation(stype)
- int stype;
-{
-#ifdef DEBUG
- callback->printf_filtered(callback,"SyncOperation(%d) : TODO\n",stype);
-#endif /* DEBUG */
- return;
-}
/* Description from page A-26 of the "MIPS IV Instruction Set" manual (revision 3.1) */
/* Signal an exception condition. This will result in an exception
that aborts the instruction. The instruction operation pseudocode
will never see a return from this function call. */
-static void
-SignalException (int exception,...)
+void
+signal_exception (SIM_DESC sd,
+ sim_cpu *cpu,
+ address_word cia,
+ int exception,...)
{
- int vector;
- SIM_DESC sd = &simulator;
+ /* int vector; */
+
+#ifdef DEBUG
+ sim_io_printf(sd,"DBG: SignalException(%d) PC = 0x%s\n",exception,pr_addr(cia));
+#endif /* DEBUG */
+
/* Ensure that any active atomic read/modify/write operation will fail: */
LLBIT = 0;
+ /* Save registers before interrupt dispatching */
+#ifdef SIM_CPU_EXCEPTION_TRIGGER
+ SIM_CPU_EXCEPTION_TRIGGER(sd, cpu, cia);
+#endif
+
switch (exception) {
- /* TODO: For testing purposes I have been ignoring TRAPs. In
- reality we should either simulate them, or allow the user to
- ignore them at run-time. */
- case Trap :
- sim_warning("Ignoring instruction TRAP (PC 0x%s)",pr_addr(IPC));
- break;
- case ReservedInstruction :
+ case DebugBreakPoint:
+ if (! (Debug & Debug_DM))
+ {
+ if (INDELAYSLOT())
+ {
+ CANCELDELAYSLOT();
+
+ Debug |= Debug_DBD; /* signaled from within in delay slot */
+ DEPC = cia - 4; /* reference the branch instruction */
+ }
+ else
+ {
+ Debug &= ~Debug_DBD; /* not signaled from within a delay slot */
+ DEPC = cia;
+ }
+
+ Debug |= Debug_DM; /* in debugging mode */
+ Debug |= Debug_DBp; /* raising a DBp exception */
+ PC = 0xBFC00200;
+ sim_engine_restart (SD, CPU, NULL, NULL_CIA);
+ }
+ break;
+
+ case ReservedInstruction:
{
va_list ap;
unsigned int instruction;
space with suitable instruction values. For systems were
actual trap instructions are used, we would not need to
perform this magic. */
- if ((instruction & RSVD_INSTRUCTION_MASK) == RSVD_INSTRUCTION) {
- sim_monitor( ((instruction >> RSVD_INSTRUCTION_ARG_SHIFT) & RSVD_INSTRUCTION_ARG_MASK) );
- PC = RA; /* simulate the return from the vector entry */
- /* NOTE: This assumes that a branch-and-link style
- instruction was used to enter the vector (which is the
- case with the current IDT monitor). */
- sim_engine_restart (sd, STATE_CPU (sd, 0), NULL, NULL_CIA);
- }
+ if ((instruction & RSVD_INSTRUCTION_MASK) == RSVD_INSTRUCTION)
+ {
+ int reason = (instruction >> RSVD_INSTRUCTION_ARG_SHIFT) & RSVD_INSTRUCTION_ARG_MASK;
+ if (!sim_monitor (SD, CPU, cia, reason))
+ sim_io_error (sd, "sim_monitor: unhandled reason = %d, pc = 0x%s\n", reason, pr_addr (cia));
+
+ /* NOTE: This assumes that a branch-and-link style
+ instruction was used to enter the vector (which is the
+ case with the current IDT monitor). */
+ sim_engine_restart (SD, CPU, NULL, RA);
+ }
/* Look for the mips16 entry and exit instructions, and
simulate a handler for them. */
- else if ((IPC & 1) != 0
+ else if ((cia & 1) != 0
&& (instruction & 0xf81f) == 0xe809
- && (instruction & 0x0c0) != 0x0c0) {
- mips16_entry (instruction);
- sim_engine_restart (sd, STATE_CPU (sd, 0), NULL, NULL_CIA);
- } /* else fall through to normal exception processing */
- sim_warning("ReservedInstruction 0x%08X at IPC = 0x%s",instruction,pr_addr(IPC));
+ && (instruction & 0x0c0) != 0x0c0)
+ {
+ mips16_entry (SD, CPU, cia, instruction);
+ sim_engine_restart (sd, NULL, NULL, NULL_CIA);
+ }
+ /* else fall through to normal exception processing */
+ sim_io_eprintf(sd,"ReservedInstruction at PC = 0x%s\n", pr_addr (cia));
}
- case BreakPoint:
-#ifdef DEBUG
- callback->printf_filtered(callback,"DBG: SignalException(%d) IPC = 0x%s\n",exception,pr_addr(IPC));
-#endif /* DEBUG */
- /* Keep a copy of the current A0 in-case this is the program exit
- breakpoint: */
- {
- va_list ap;
- unsigned int instruction;
- va_start(ap,exception);
- instruction = va_arg(ap,unsigned int);
- va_end(ap);
- /* Check for our special terminating BREAK: */
- if ((instruction & 0x03FFFFC0) == 0x03ff0000) {
- sim_engine_halt (sd, STATE_CPU (sd, 0), NULL, NULL_CIA,
- sim_exited, (unsigned int)(A0 & 0xFFFFFFFF));
- }
- }
- if (state & simDELAYSLOT)
- PC = IPC - 4; /* reference the branch instruction */
- else
- PC = IPC;
- sim_engine_halt (sd, STATE_CPU (sd, 0), NULL, NULL_CIA,
- sim_stopped, SIGTRAP);
-
default:
/* Store exception code into current exception id variable (used
by exit code): */
/* TODO: If not simulating exceptions then stop the simulator
execution. At the moment we always stop the simulation. */
+#ifdef SUBTARGET_R3900
+ /* update interrupt-related registers */
+
+ /* insert exception code in bits 6:2 */
+ CAUSE = LSMASKED32(CAUSE, 31, 7) | LSINSERTED32(exception, 6, 2);
+ /* shift IE/KU history bits left */
+ SR = LSMASKED32(SR, 31, 4) | LSINSERTED32(LSEXTRACTED32(SR, 3, 0), 5, 2);
+
+ if (STATE & simDELAYSLOT)
+ {
+ STATE &= ~simDELAYSLOT;
+ CAUSE |= cause_BD;
+ EPC = (cia - 4); /* reference the branch instruction */
+ }
+ else
+ EPC = cia;
+
+ if (SR & status_BEV)
+ PC = (signed)0xBFC00000 + 0x180;
+ else
+ PC = (signed)0x80000000 + 0x080;
+#else
/* See figure 5-17 for an outline of the code below */
if (! (SR & status_EXL))
{
CAUSE = (exception << 2);
- if (state & simDELAYSLOT)
+ if (STATE & simDELAYSLOT)
{
- state &= ~simDELAYSLOT;
+ STATE &= ~simDELAYSLOT;
CAUSE |= cause_BD;
- EPC = (IPC - 4); /* reference the branch instruction */
+ EPC = (cia - 4); /* reference the branch instruction */
}
else
- EPC = IPC;
+ EPC = cia;
/* FIXME: TLB et.al. */
- vector = 0x180;
+ /* vector = 0x180; */
}
else
{
CAUSE = (exception << 2);
- vector = 0x180;
+ /* vector = 0x180; */
}
SR |= status_EXL;
/* Store exception code into current exception id variable (used
by exit code): */
+
if (SR & status_BEV)
PC = (signed)0xBFC00200 + 0x180;
else
PC = (signed)0x80000000 + 0x180;
+#endif
switch ((CAUSE >> 2) & 0x1F)
{
/* Interrupts arrive during event processing, no need to
restart */
return;
-
+
+ case NMIReset:
+ /* Ditto */
+#ifdef SUBTARGET_3900
+ /* Exception vector: BEV=0 BFC00000 / BEF=1 BFC00000 */
+ PC = (signed)0xBFC00000;
+#endif /* SUBTARGET_3900 */
+ return;
+
case TLBModification:
case TLBLoad:
case TLBStore:
case InstructionFetch:
case DataReference:
/* The following is so that the simulator will continue from the
- exception address on breakpoint operations. */
- PC = EPC;
- sim_engine_halt (sd, STATE_CPU (sd, 0), NULL, NULL_CIA,
- sim_stopped, SIGBUS);
+ exception handler address. */
+ sim_engine_halt (SD, CPU, NULL, PC,
+ sim_stopped, SIM_SIGBUS);
case ReservedInstruction:
case CoProcessorUnusable:
PC = EPC;
- sim_engine_halt (sd, STATE_CPU (sd, 0), NULL, NULL_CIA,
- sim_stopped, SIGILL);
+ sim_engine_halt (SD, CPU, NULL, PC,
+ sim_stopped, SIM_SIGILL);
case IntegerOverflow:
case FPE:
- sim_engine_halt (sd, STATE_CPU (sd, 0), NULL, NULL_CIA,
- sim_stopped, SIGFPE);
+ sim_engine_halt (SD, CPU, NULL, PC,
+ sim_stopped, SIM_SIGFPE);
+
+ case BreakPoint:
+ sim_engine_halt (SD, CPU, NULL, PC, sim_stopped, SIM_SIGTRAP);
+ break;
- case Trap:
- case Watch:
case SystemCall:
- PC = EPC;
- sim_engine_halt (sd, STATE_CPU (sd, 0), NULL, NULL_CIA,
- sim_stopped, SIGTRAP);
+ case Trap:
+ sim_engine_restart (SD, CPU, NULL, PC);
+ break;
- case BreakPoint:
+ case Watch:
PC = EPC;
- sim_engine_abort (sd, STATE_CPU (sd, 0), NULL_CIA,
- "FATAL: Should not encounter a breakpoint\n");
+ sim_engine_halt (SD, CPU, NULL, PC,
+ sim_stopped, SIM_SIGTRAP);
- default : /* Unknown internal exception */
+ default: /* Unknown internal exception */
PC = EPC;
- sim_engine_halt (sd, STATE_CPU (sd, 0), NULL, NULL_CIA,
- sim_stopped, SIGQUIT);
+ sim_engine_halt (SD, CPU, NULL, PC,
+ sim_stopped, SIM_SIGABRT);
}
- case SimulatorFault:
- {
- va_list ap;
- char *msg;
- va_start(ap,exception);
- msg = va_arg(ap,char *);
- va_end(ap);
- sim_engine_abort (sd, STATE_CPU (sd, 0), NULL_CIA,
- "FATAL: Simulator error \"%s\"\n",msg);
- }
- }
-
- return;
-}
-
-#if defined(WARN_RESULT)
-/* Description from page A-26 of the "MIPS IV Instruction Set" manual (revision 3.1) */
-/* This function indicates that the result of the operation is
- undefined. However, this should not affect the instruction
- stream. All that is meant to happen is that the destination
- register is set to an undefined result. To keep the simulator
- simple, we just don't bother updating the destination register, so
- the overall result will be undefined. If desired we can stop the
- simulator by raising a pseudo-exception. */
-static void
-UndefinedResult()
-{
- sim_warning("UndefinedResult: IPC = 0x%s",pr_addr(IPC));
-#if 0 /* Disabled for the moment, since it actually happens a lot at the moment. */
- state |= simSTOP;
-#endif
- return;
-}
-#endif /* WARN_RESULT */
-
-static void UNUSED
-CacheOp(op,pAddr,vAddr,instruction)
- int op;
- uword64 pAddr;
- uword64 vAddr;
- unsigned int instruction;
-{
-#if 1 /* stop warning message being displayed (we should really just remove the code) */
- static int icache_warning = 1;
- static int dcache_warning = 1;
-#else
- static int icache_warning = 0;
- static int dcache_warning = 0;
-#endif
-
- /* If CP0 is not useable (User or Supervisor mode) and the CP0
- enable bit in the Status Register is clear - a coprocessor
- unusable exception is taken. */
-#if 0
- callback->printf_filtered(callback,"TODO: Cache availability checking (PC = 0x%s)\n",pr_addr(IPC));
-#endif
-
- switch (op & 0x3) {
- case 0: /* instruction cache */
- switch (op >> 2) {
- case 0: /* Index Invalidate */
- case 1: /* Index Load Tag */
- case 2: /* Index Store Tag */
- case 4: /* Hit Invalidate */
- case 5: /* Fill */
- case 6: /* Hit Writeback */
- if (!icache_warning)
- {
- sim_warning("Instruction CACHE operation %d to be coded",(op >> 2));
- icache_warning = 1;
- }
- break;
-
- default:
- SignalException(ReservedInstruction,instruction);
- break;
- }
- break;
-
- case 1: /* data cache */
- switch (op >> 2) {
- case 0: /* Index Writeback Invalidate */
- case 1: /* Index Load Tag */
- case 2: /* Index Store Tag */
- case 3: /* Create Dirty */
- case 4: /* Hit Invalidate */
- case 5: /* Hit Writeback Invalidate */
- case 6: /* Hit Writeback */
- if (!dcache_warning)
- {
- sim_warning("Data CACHE operation %d to be coded",(op >> 2));
- dcache_warning = 1;
- }
- break;
-
- default:
- SignalException(ReservedInstruction,instruction);
- break;
- }
- break;
-
- default: /* unrecognised cache ID */
- SignalException(ReservedInstruction,instruction);
- break;
- }
-
- return;
-}
-
-/*-- FPU support routines ---------------------------------------------------*/
-
-#if defined(HASFPU) /* Only needed when building FPU aware simulators */
-
-#if 1
-#define SizeFGR() (GPRLEN)
-#else
-/* They depend on the CPU being simulated */
-#define SizeFGR() ((PROCESSOR_64BIT && ((SR & status_FR) == 1)) ? 64 : 32)
-#endif
-
-/* Numbers are held in normalized form. The SINGLE and DOUBLE binary
- formats conform to ANSI/IEEE Std 754-1985. */
-/* SINGLE precision floating:
- * seeeeeeeefffffffffffffffffffffff
- * s = 1bit = sign
- * e = 8bits = exponent
- * f = 23bits = fraction
- */
-/* SINGLE precision fixed:
- * siiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
- * s = 1bit = sign
- * i = 31bits = integer
- */
-/* DOUBLE precision floating:
- * seeeeeeeeeeeffffffffffffffffffffffffffffffffffffffffffffffffffff
- * s = 1bit = sign
- * e = 11bits = exponent
- * f = 52bits = fraction
- */
-/* DOUBLE precision fixed:
- * siiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
- * s = 1bit = sign
- * i = 63bits = integer
- */
-
-/* Extract sign-bit: */
-#define FP_S_s(v) (((v) & ((unsigned)1 << 31)) ? 1 : 0)
-#define FP_D_s(v) (((v) & ((uword64)1 << 63)) ? 1 : 0)
-/* Extract biased exponent: */
-#define FP_S_be(v) (((v) >> 23) & 0xFF)
-#define FP_D_be(v) (((v) >> 52) & 0x7FF)
-/* Extract unbiased Exponent: */
-#define FP_S_e(v) (FP_S_be(v) - 0x7F)
-#define FP_D_e(v) (FP_D_be(v) - 0x3FF)
-/* Extract complete fraction field: */
-#define FP_S_f(v) ((v) & ~((unsigned)0x1FF << 23))
-#define FP_D_f(v) ((v) & ~((uword64)0xFFF << 52))
-/* Extract numbered fraction bit: */
-#define FP_S_fb(b,v) (((v) & (1 << (23 - (b)))) ? 1 : 0)
-#define FP_D_fb(b,v) (((v) & (1 << (52 - (b)))) ? 1 : 0)
-
-/* Explicit QNaN values used when value required: */
-#define FPQNaN_SINGLE (0x7FBFFFFF)
-#define FPQNaN_WORD (0x7FFFFFFF)
-#define FPQNaN_DOUBLE (((uword64)0x7FF7FFFF << 32) | 0xFFFFFFFF)
-#define FPQNaN_LONG (((uword64)0x7FFFFFFF << 32) | 0xFFFFFFFF)
-
-/* Explicit Infinity values used when required: */
-#define FPINF_SINGLE (0x7F800000)
-#define FPINF_DOUBLE (((uword64)0x7FF00000 << 32) | 0x00000000)
-
-#if 1 /* def DEBUG */
-#define RMMODE(v) (((v) == FP_RM_NEAREST) ? "Round" : (((v) == FP_RM_TOZERO) ? "Trunc" : (((v) == FP_RM_TOPINF) ? "Ceil" : "Floor")))
-#define DOFMT(v) (((v) == fmt_single) ? "single" : (((v) == fmt_double) ? "double" : (((v) == fmt_word) ? "word" : (((v) == fmt_long) ? "long" : (((v) == fmt_unknown) ? "<unknown>" : (((v) == fmt_uninterpreted) ? "<uninterpreted>" : "<format error>"))))))
-#endif /* DEBUG */
-
-static uword64
-ValueFPR(fpr,fmt)
- int fpr;
- FP_formats fmt;
-{
- uword64 value = 0;
- int err = 0;
-
- /* Treat unused register values, as fixed-point 64bit values: */
- if ((fmt == fmt_uninterpreted) || (fmt == fmt_unknown))
-#if 1
- /* If request to read data as "uninterpreted", then use the current
- encoding: */
- fmt = fpr_state[fpr];
-#else
- fmt = fmt_long;
-#endif
-
- /* For values not yet accessed, set to the desired format: */
- if (fpr_state[fpr] == fmt_uninterpreted) {
- fpr_state[fpr] = fmt;
-#ifdef DEBUG
- printf("DBG: Register %d was fmt_uninterpreted. Now %s\n",fpr,DOFMT(fmt));
-#endif /* DEBUG */
- }
- if (fmt != fpr_state[fpr]) {
- sim_warning("FPR %d (format %s) being accessed with format %s - setting to unknown (PC = 0x%s)",fpr,DOFMT(fpr_state[fpr]),DOFMT(fmt),pr_addr(IPC));
- fpr_state[fpr] = fmt_unknown;
- }
-
- if (fpr_state[fpr] == fmt_unknown) {
- /* Set QNaN value: */
- switch (fmt) {
- case fmt_single:
- value = FPQNaN_SINGLE;
- break;
-
- case fmt_double:
- value = FPQNaN_DOUBLE;
- break;
-
- case fmt_word:
- value = FPQNaN_WORD;
- break;
-
- case fmt_long:
- value = FPQNaN_LONG;
- break;
-
- default:
- err = -1;
- break;
- }
- } else if (SizeFGR() == 64) {
- switch (fmt) {
- case fmt_single:
- case fmt_word:
- value = (FGR[fpr] & 0xFFFFFFFF);
- break;
-
- case fmt_uninterpreted:
- case fmt_double:
- case fmt_long:
- value = FGR[fpr];
- break;
-
- default :
- err = -1;
- break;
- }
- } else {
- switch (fmt) {
- case fmt_single:
- case fmt_word:
- value = (FGR[fpr] & 0xFFFFFFFF);
- break;
-
- case fmt_uninterpreted:
- case fmt_double:
- case fmt_long:
- if ((fpr & 1) == 0) { /* even registers only */
- value = ((((uword64)FGR[fpr+1]) << 32) | (FGR[fpr] & 0xFFFFFFFF));
- } else {
- SignalException (ReservedInstruction, 0);
- }
- break;
-
- default :
- err = -1;
- break;
- }
- }
-
- if (err)
- SignalException(SimulatorFault,"Unrecognised FP format in ValueFPR()");
-
-#ifdef DEBUG
- printf("DBG: ValueFPR: fpr = %d, fmt = %s, value = 0x%s : PC = 0x%s : SizeFGR() = %d\n",fpr,DOFMT(fmt),pr_addr(value),pr_addr(IPC),SizeFGR());
-#endif /* DEBUG */
-
- return(value);
-}
-
-static void
-StoreFPR(fpr,fmt,value)
- int fpr;
- FP_formats fmt;
- uword64 value;
-{
- int err = 0;
-
-#ifdef DEBUG
- printf("DBG: StoreFPR: fpr = %d, fmt = %s, value = 0x%s : PC = 0x%s : SizeFGR() = %d\n",fpr,DOFMT(fmt),pr_addr(value),pr_addr(IPC),SizeFGR());
-#endif /* DEBUG */
-
- if (SizeFGR() == 64) {
- switch (fmt) {
- case fmt_single :
- case fmt_word :
- FGR[fpr] = (((uword64)0xDEADC0DE << 32) | (value & 0xFFFFFFFF));
- fpr_state[fpr] = fmt;
- break;
-
- case fmt_uninterpreted:
- case fmt_double :
- case fmt_long :
- FGR[fpr] = value;
- fpr_state[fpr] = fmt;
- break;
-
- default :
- fpr_state[fpr] = fmt_unknown;
- err = -1;
- break;
- }
- } else {
- switch (fmt) {
- case fmt_single :
- case fmt_word :
- FGR[fpr] = (value & 0xFFFFFFFF);
- fpr_state[fpr] = fmt;
- break;
-
- case fmt_uninterpreted:
- case fmt_double :
- case fmt_long :
- if ((fpr & 1) == 0) { /* even register number only */
- FGR[fpr+1] = (value >> 32);
- FGR[fpr] = (value & 0xFFFFFFFF);
- fpr_state[fpr + 1] = fmt;
- fpr_state[fpr] = fmt;
- } else {
- fpr_state[fpr] = fmt_unknown;
- fpr_state[fpr + 1] = fmt_unknown;
- SignalException (ReservedInstruction, 0);
- }
- break;
-
- default :
- fpr_state[fpr] = fmt_unknown;
- err = -1;
- break;
- }
- }
-#if defined(WARN_RESULT)
- else
- UndefinedResult();
-#endif /* WARN_RESULT */
-
- if (err)
- SignalException(SimulatorFault,"Unrecognised FP format in StoreFPR()");
-
-#ifdef DEBUG
- printf("DBG: StoreFPR: fpr[%d] = 0x%s (format %s)\n",fpr,pr_addr(FGR[fpr]),DOFMT(fmt));
-#endif /* DEBUG */
-
- return;
-}
-
-static int
-NaN(op,fmt)
- uword64 op;
- FP_formats fmt;
-{
- int boolean = 0;
-
- /* Check if (((E - bias) == (E_max + 1)) && (fraction != 0)). We
- know that the exponent field is biased... we we cheat and avoid
- removing the bias value. */
- switch (fmt) {
- case fmt_single:
- boolean = ((FP_S_be(op) == 0xFF) && (FP_S_f(op) != 0));
- /* We could use "FP_S_fb(1,op)" to ascertain whether we are
- dealing with a SNaN or QNaN */
- break;
- case fmt_double:
- boolean = ((FP_D_be(op) == 0x7FF) && (FP_D_f(op) != 0));
- /* We could use "FP_S_fb(1,op)" to ascertain whether we are
- dealing with a SNaN or QNaN */
- break;
- case fmt_word:
- boolean = (op == FPQNaN_WORD);
- break;
- case fmt_long:
- boolean = (op == FPQNaN_LONG);
- break;
- default:
- fprintf (stderr, "Bad switch\n");
- abort ();
- }
-
-#ifdef DEBUG
-printf("DBG: NaN: returning %d for 0x%s (format = %s)\n",boolean,pr_addr(op),DOFMT(fmt));
-#endif /* DEBUG */
-
- return(boolean);
-}
-
-static int
-Infinity(op,fmt)
- uword64 op;
- FP_formats fmt;
-{
- int boolean = 0;
-
-#ifdef DEBUG
- printf("DBG: Infinity: format %s 0x%s (PC = 0x%s)\n",DOFMT(fmt),pr_addr(op),pr_addr(IPC));
-#endif /* DEBUG */
-
- /* Check if (((E - bias) == (E_max + 1)) && (fraction == 0)). We
- know that the exponent field is biased... we we cheat and avoid
- removing the bias value. */
- switch (fmt) {
- case fmt_single:
- boolean = ((FP_S_be(op) == 0xFF) && (FP_S_f(op) == 0));
- break;
- case fmt_double:
- boolean = ((FP_D_be(op) == 0x7FF) && (FP_D_f(op) == 0));
- break;
- default:
- printf("DBG: TODO: unrecognised format (%s) for Infinity check\n",DOFMT(fmt));
- break;
- }
-
-#ifdef DEBUG
- printf("DBG: Infinity: returning %d for 0x%s (format = %s)\n",boolean,pr_addr(op),DOFMT(fmt));
-#endif /* DEBUG */
-
- return(boolean);
-}
-
-static int
-Less(op1,op2,fmt)
- uword64 op1;
- uword64 op2;
- FP_formats fmt;
-{
- int boolean = 0;
-
- /* Argument checking already performed by the FPCOMPARE code */
-
-#ifdef DEBUG
- printf("DBG: Less: %s: op1 = 0x%s : op2 = 0x%s\n",DOFMT(fmt),pr_addr(op1),pr_addr(op2));
-#endif /* DEBUG */
-
- /* The format type should already have been checked: */
- switch (fmt) {
- case fmt_single:
- {
- unsigned int wop1 = (unsigned int)op1;
- unsigned int wop2 = (unsigned int)op2;
- boolean = (*(float *)&wop1 < *(float *)&wop2);
- }
- break;
- case fmt_double:
- boolean = (*(double *)&op1 < *(double *)&op2);
- break;
- default:
- fprintf (stderr, "Bad switch\n");
- abort ();
- }
-
-#ifdef DEBUG
- printf("DBG: Less: returning %d (format = %s)\n",boolean,DOFMT(fmt));
-#endif /* DEBUG */
-
- return(boolean);
-}
-
-static int
-Equal(op1,op2,fmt)
- uword64 op1;
- uword64 op2;
- FP_formats fmt;
-{
- int boolean = 0;
-
- /* Argument checking already performed by the FPCOMPARE code */
-
-#ifdef DEBUG
- printf("DBG: Equal: %s: op1 = 0x%s : op2 = 0x%s\n",DOFMT(fmt),pr_addr(op1),pr_addr(op2));
-#endif /* DEBUG */
-
- /* The format type should already have been checked: */
- switch (fmt) {
- case fmt_single:
- boolean = ((op1 & 0xFFFFFFFF) == (op2 & 0xFFFFFFFF));
- break;
- case fmt_double:
- boolean = (op1 == op2);
- break;
- default:
- fprintf (stderr, "Bad switch\n");
- abort ();
- }
-
-#ifdef DEBUG
- printf("DBG: Equal: returning %d (format = %s)\n",boolean,DOFMT(fmt));
-#endif /* DEBUG */
-
- return(boolean);
-}
-
-static uword64
-AbsoluteValue(op,fmt)
- uword64 op;
- FP_formats fmt;
-{
- uword64 result = 0;
-
-#ifdef DEBUG
- printf("DBG: AbsoluteValue: %s: op = 0x%s\n",DOFMT(fmt),pr_addr(op));
-#endif /* DEBUG */
-
- /* The format type should already have been checked: */
- switch (fmt) {
- case fmt_single:
- {
- unsigned int wop = (unsigned int)op;
- float tmp = ((float)fabs((double)*(float *)&wop));
- result = (uword64)*(unsigned int *)&tmp;
- }
- break;
- case fmt_double:
- {
- double tmp = (fabs(*(double *)&op));
- result = *(uword64 *)&tmp;
- }
- default:
- fprintf (stderr, "Bad switch\n");
- abort ();
- }
-
- return(result);
-}
-
-static uword64
-Negate(op,fmt)
- uword64 op;
- FP_formats fmt;
-{
- uword64 result = 0;
-
-#ifdef DEBUG
- printf("DBG: Negate: %s: op = 0x%s\n",DOFMT(fmt),pr_addr(op));
-#endif /* DEBUG */
-
- /* The format type should already have been checked: */
- switch (fmt) {
- case fmt_single:
- {
- unsigned int wop = (unsigned int)op;
- float tmp = ((float)0.0 - *(float *)&wop);
- result = (uword64)*(unsigned int *)&tmp;
- }
- break;
- case fmt_double:
- {
- double tmp = ((double)0.0 - *(double *)&op);
- result = *(uword64 *)&tmp;
- }
- break;
- default:
- fprintf (stderr, "Bad switch\n");
- abort ();
- }
-
- return(result);
-}
-
-static uword64
-Add(op1,op2,fmt)
- uword64 op1;
- uword64 op2;
- FP_formats fmt;
-{
- uword64 result = 0;
-
-#ifdef DEBUG
- printf("DBG: Add: %s: op1 = 0x%s : op2 = 0x%s\n",DOFMT(fmt),pr_addr(op1),pr_addr(op2));
-#endif /* DEBUG */
-
- /* The registers must specify FPRs valid for operands of type
- "fmt". If they are not valid, the result is undefined. */
-
- /* The format type should already have been checked: */
- switch (fmt) {
- case fmt_single:
- {
- unsigned int wop1 = (unsigned int)op1;
- unsigned int wop2 = (unsigned int)op2;
- float tmp = (*(float *)&wop1 + *(float *)&wop2);
- result = (uword64)*(unsigned int *)&tmp;
- }
- break;
- case fmt_double:
- {
- double tmp = (*(double *)&op1 + *(double *)&op2);
- result = *(uword64 *)&tmp;
- }
- break;
- default:
- fprintf (stderr, "Bad switch\n");
- abort ();
- }
-
-#ifdef DEBUG
- printf("DBG: Add: returning 0x%s (format = %s)\n",pr_addr(result),DOFMT(fmt));
-#endif /* DEBUG */
-
- return(result);
-}
-
-static uword64
-Sub(op1,op2,fmt)
- uword64 op1;
- uword64 op2;
- FP_formats fmt;
-{
- uword64 result = 0;
-
-#ifdef DEBUG
- printf("DBG: Sub: %s: op1 = 0x%s : op2 = 0x%s\n",DOFMT(fmt),pr_addr(op1),pr_addr(op2));
-#endif /* DEBUG */
-
- /* The registers must specify FPRs valid for operands of type
- "fmt". If they are not valid, the result is undefined. */
-
- /* The format type should already have been checked: */
- switch (fmt) {
- case fmt_single:
- {
- unsigned int wop1 = (unsigned int)op1;
- unsigned int wop2 = (unsigned int)op2;
- float tmp = (*(float *)&wop1 - *(float *)&wop2);
- result = (uword64)*(unsigned int *)&tmp;
- }
- break;
- case fmt_double:
- {
- double tmp = (*(double *)&op1 - *(double *)&op2);
- result = *(uword64 *)&tmp;
- }
- break;
- default:
- fprintf (stderr, "Bad switch\n");
- abort ();
- }
-
-#ifdef DEBUG
- printf("DBG: Sub: returning 0x%s (format = %s)\n",pr_addr(result),DOFMT(fmt));
-#endif /* DEBUG */
-
- return(result);
-}
-
-static uword64
-Multiply(op1,op2,fmt)
- uword64 op1;
- uword64 op2;
- FP_formats fmt;
-{
- uword64 result = 0;
-
-#ifdef DEBUG
- printf("DBG: Multiply: %s: op1 = 0x%s : op2 = 0x%s\n",DOFMT(fmt),pr_addr(op1),pr_addr(op2));
-#endif /* DEBUG */
-
- /* The registers must specify FPRs valid for operands of type
- "fmt". If they are not valid, the result is undefined. */
-
- /* The format type should already have been checked: */
- switch (fmt) {
- case fmt_single:
- {
- unsigned int wop1 = (unsigned int)op1;
- unsigned int wop2 = (unsigned int)op2;
- float tmp = (*(float *)&wop1 * *(float *)&wop2);
- result = (uword64)*(unsigned int *)&tmp;
- }
- break;
- case fmt_double:
- {
- double tmp = (*(double *)&op1 * *(double *)&op2);
- result = *(uword64 *)&tmp;
- }
- break;
- default:
- fprintf (stderr, "Bad switch\n");
- abort ();
- }
-
-#ifdef DEBUG
- printf("DBG: Multiply: returning 0x%s (format = %s)\n",pr_addr(result),DOFMT(fmt));
-#endif /* DEBUG */
-
- return(result);
-}
-
-static uword64
-Divide(op1,op2,fmt)
- uword64 op1;
- uword64 op2;
- FP_formats fmt;
-{
- uword64 result = 0;
-
-#ifdef DEBUG
- printf("DBG: Divide: %s: op1 = 0x%s : op2 = 0x%s\n",DOFMT(fmt),pr_addr(op1),pr_addr(op2));
-#endif /* DEBUG */
-
- /* The registers must specify FPRs valid for operands of type
- "fmt". If they are not valid, the result is undefined. */
-
- /* The format type should already have been checked: */
- switch (fmt) {
- case fmt_single:
- {
- unsigned int wop1 = (unsigned int)op1;
- unsigned int wop2 = (unsigned int)op2;
- float tmp = (*(float *)&wop1 / *(float *)&wop2);
- result = (uword64)*(unsigned int *)&tmp;
- }
- break;
- case fmt_double:
- {
- double tmp = (*(double *)&op1 / *(double *)&op2);
- result = *(uword64 *)&tmp;
- }
- break;
- default:
- fprintf (stderr, "Bad switch\n");
- abort ();
- }
-
-#ifdef DEBUG
- printf("DBG: Divide: returning 0x%s (format = %s)\n",pr_addr(result),DOFMT(fmt));
-#endif /* DEBUG */
-
- return(result);
-}
-
-static uword64 UNUSED
-Recip(op,fmt)
- uword64 op;
- FP_formats fmt;
-{
- uword64 result = 0;
-
-#ifdef DEBUG
- printf("DBG: Recip: %s: op = 0x%s\n",DOFMT(fmt),pr_addr(op));
-#endif /* DEBUG */
-
- /* The registers must specify FPRs valid for operands of type
- "fmt". If they are not valid, the result is undefined. */
-
- /* The format type should already have been checked: */
- switch (fmt) {
- case fmt_single:
- {
- unsigned int wop = (unsigned int)op;
- float tmp = ((float)1.0 / *(float *)&wop);
- result = (uword64)*(unsigned int *)&tmp;
- }
- break;
- case fmt_double:
- {
- double tmp = ((double)1.0 / *(double *)&op);
- result = *(uword64 *)&tmp;
- }
- break;
- default:
- fprintf (stderr, "Bad switch\n");
- abort ();
- }
-
-#ifdef DEBUG
- printf("DBG: Recip: returning 0x%s (format = %s)\n",pr_addr(result),DOFMT(fmt));
-#endif /* DEBUG */
-
- return(result);
-}
-
-static uword64
-SquareRoot(op,fmt)
- uword64 op;
- FP_formats fmt;
-{
- uword64 result = 0;
-
-#ifdef DEBUG
- printf("DBG: SquareRoot: %s: op = 0x%s\n",DOFMT(fmt),pr_addr(op));
-#endif /* DEBUG */
-
- /* The registers must specify FPRs valid for operands of type
- "fmt". If they are not valid, the result is undefined. */
-
- /* The format type should already have been checked: */
- switch (fmt) {
- case fmt_single:
- {
- unsigned int wop = (unsigned int)op;
-#ifdef HAVE_SQRT
- float tmp = ((float)sqrt((double)*(float *)&wop));
- result = (uword64)*(unsigned int *)&tmp;
-#else
- /* TODO: Provide square-root */
- result = (uword64)0;
-#endif
- }
- break;
- case fmt_double:
- {
-#ifdef HAVE_SQRT
- double tmp = (sqrt(*(double *)&op));
- result = *(uword64 *)&tmp;
-#else
- /* TODO: Provide square-root */
- result = (uword64)0;
-#endif
- }
- break;
- default:
- fprintf (stderr, "Bad switch\n");
- abort ();
- }
-
-#ifdef DEBUG
- printf("DBG: SquareRoot: returning 0x%s (format = %s)\n",pr_addr(result),DOFMT(fmt));
-#endif /* DEBUG */
-
- return(result);
-}
-
-static uword64
-Convert(rm,op,from,to)
- int rm;
- uword64 op;
- FP_formats from;
- FP_formats to;
-{
- uword64 result = 0;
-
-#ifdef DEBUG
- printf("DBG: Convert: mode %s : op 0x%s : from %s : to %s : (PC = 0x%s)\n",RMMODE(rm),pr_addr(op),DOFMT(from),DOFMT(to),pr_addr(IPC));
-#endif /* DEBUG */
-
- /* The value "op" is converted to the destination format, rounding
- using mode "rm". When the destination is a fixed-point format,
- then a source value of Infinity, NaN or one which would round to
- an integer outside the fixed point range then an IEEE Invalid
- Operation condition is raised. */
- switch (to) {
- case fmt_single:
- {
- float tmp;
- switch (from) {
- case fmt_double:
- tmp = (float)(*(double *)&op);
- break;
-
- case fmt_word:
- tmp = (float)((int)(op & 0xFFFFFFFF));
- break;
-
- case fmt_long:
- tmp = (float)((word64)op);
- break;
- default:
- fprintf (stderr, "Bad switch\n");
- abort ();
- }
-
-#if 0
- /* FIXME: This code is incorrect. The rounding mode does not
- round to integral values; it rounds to the nearest
- representable value in the format. */
-
- switch (rm) {
- case FP_RM_NEAREST:
- /* Round result to nearest representable value. When two
- representable values are equally near, round to the value
- that has a least significant bit of zero (i.e. is even). */
-#ifdef HAVE_ANINT
- tmp = (float)anint((double)tmp);
-#else
- /* TODO: Provide round-to-nearest */
-#endif
- break;
-
- case FP_RM_TOZERO:
- /* Round result to the value closest to, and not greater in
- magnitude than, the result. */
-#ifdef HAVE_AINT
- tmp = (float)aint((double)tmp);
-#else
- /* TODO: Provide round-to-zero */
-#endif
- break;
-
- case FP_RM_TOPINF:
- /* Round result to the value closest to, and not less than,
- the result. */
- tmp = (float)ceil((double)tmp);
- break;
-
- case FP_RM_TOMINF:
- /* Round result to the value closest to, and not greater than,
- the result. */
- tmp = (float)floor((double)tmp);
- break;
- }
-#endif /* 0 */
-
- result = (uword64)*(unsigned int *)&tmp;
- }
- break;
-
- case fmt_double:
- {
- double tmp;
- word64 xxx;
-
- switch (from) {
- case fmt_single:
- {
- unsigned int wop = (unsigned int)op;
- tmp = (double)(*(float *)&wop);
- }
- break;
-
- case fmt_word:
- xxx = SIGNEXTEND((op & 0xFFFFFFFF),32);
- tmp = (double)xxx;
- break;
-
- case fmt_long:
- tmp = (double)((word64)op);
- break;
-
- default:
- fprintf (stderr, "Bad switch\n");
- abort ();
- }
-
-#if 0
- /* FIXME: This code is incorrect. The rounding mode does not
- round to integral values; it rounds to the nearest
- representable value in the format. */
-
- switch (rm) {
- case FP_RM_NEAREST:
-#ifdef HAVE_ANINT
- tmp = anint(*(double *)&tmp);
-#else
- /* TODO: Provide round-to-nearest */
-#endif
- break;
+ case SimulatorFault:
+ {
+ va_list ap;
+ char *msg;
+ va_start(ap,exception);
+ msg = va_arg(ap,char *);
+ va_end(ap);
+ sim_engine_abort (SD, CPU, NULL_CIA,
+ "FATAL: Simulator error \"%s\"\n",msg);
+ }
+ }
- case FP_RM_TOZERO:
-#ifdef HAVE_AINT
- tmp = aint(*(double *)&tmp);
-#else
- /* TODO: Provide round-to-zero */
-#endif
- break;
+ return;
+}
- case FP_RM_TOPINF:
- tmp = ceil(*(double *)&tmp);
- break;
- case FP_RM_TOMINF:
- tmp = floor(*(double *)&tmp);
- break;
- }
-#endif /* 0 */
- result = *(uword64 *)&tmp;
- }
- break;
+/* This function implements what the MIPS32 and MIPS64 ISAs define as
+ "UNPREDICTABLE" behaviour.
- case fmt_word:
- case fmt_long:
- if (Infinity(op,from) || NaN(op,from) || (1 == 0/*TODO: check range */)) {
- printf("DBG: TODO: update FCSR\n");
- SignalException(FPE);
- } else {
- if (to == fmt_word) {
- int tmp = 0;
- switch (from) {
- case fmt_single:
- {
- unsigned int wop = (unsigned int)op;
- tmp = (int)*((float *)&wop);
- }
- break;
- case fmt_double:
- tmp = (int)*((double *)&op);
-#ifdef DEBUG
- printf("DBG: from double %.30f (0x%s) to word: 0x%08X\n",*((double *)&op),pr_addr(op),tmp);
-#endif /* DEBUG */
- break;
- default:
- fprintf (stderr, "Bad switch\n");
- abort ();
- }
- result = (uword64)tmp;
- } else { /* fmt_long */
- word64 tmp = 0;
- switch (from) {
- case fmt_single:
- {
- unsigned int wop = (unsigned int)op;
- tmp = (word64)*((float *)&wop);
- }
- break;
- case fmt_double:
- tmp = (word64)*((double *)&op);
- break;
- default:
- fprintf (stderr, "Bad switch\n");
- abort ();
- }
- result = (uword64)tmp;
- }
- }
- break;
- default:
- fprintf (stderr, "Bad switch\n");
- abort ();
- }
+ About UNPREDICTABLE behaviour they say: "UNPREDICTABLE results
+ may vary from processor implementation to processor implementation,
+ instruction to instruction, or as a function of time on the same
+ implementation or instruction. Software can never depend on results
+ that are UNPREDICTABLE. ..." (MIPS64 Architecture for Programmers
+ Volume II, The MIPS64 Instruction Set. MIPS Document MD00087 revision
+ 0.95, page 2.)
+
+ For UNPREDICTABLE behaviour, we print a message, if possible print
+ the offending instructions mips.igen instruction name (provided by
+ the caller), and stop the simulator.
-#ifdef DEBUG
- printf("DBG: Convert: returning 0x%s (to format = %s)\n",pr_addr(result),DOFMT(to));
-#endif /* DEBUG */
+ XXX FIXME: eventually, stopping the simulator should be made conditional
+ on a command-line option. */
+void
+unpredictable_action(sim_cpu *cpu, address_word cia)
+{
+ SIM_DESC sd = CPU_STATE(cpu);
- return(result);
+ sim_io_eprintf(sd, "UNPREDICTABLE: PC = 0x%s\n", pr_addr (cia));
+ sim_engine_halt (SD, CPU, NULL, cia, sim_stopped, SIM_SIGABRT);
}
-#endif /* HASFPU */
+
/*-- co-processor support routines ------------------------------------------*/
static int UNUSED
-CoProcPresent(coproc_number)
- unsigned int coproc_number;
+CoProcPresent(unsigned int coproc_number)
{
/* Return TRUE if simulator provides a model for the given co-processor number */
return(0);
}
-static void
-COP_LW(coproc_num,coproc_reg,memword)
- int coproc_num, coproc_reg;
- unsigned int memword;
-{
- switch (coproc_num) {
-#if defined(HASFPU)
+void
+cop_lw (SIM_DESC sd,
+ sim_cpu *cpu,
+ address_word cia,
+ int coproc_num,
+ int coproc_reg,
+ unsigned int memword)
+{
+ switch (coproc_num)
+ {
case 1:
+ if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT)
+ {
#ifdef DEBUG
- printf("DBG: COP_LW: memword = 0x%08X (uword64)memword = 0x%s\n",memword,pr_addr(memword));
+ printf("DBG: COP_LW: memword = 0x%08X (uword64)memword = 0x%s\n",memword,pr_addr(memword));
#endif
- StoreFPR(coproc_reg,fmt_word,(uword64)memword);
- fpr_state[coproc_reg] = fmt_uninterpreted;
- break;
-#endif /* HASFPU */
+ StoreFPR(coproc_reg,fmt_uninterpreted_32,(uword64)memword);
+ break;
+ }
default:
#if 0 /* this should be controlled by a configuration option */
- callback->printf_filtered(callback,"COP_LW(%d,%d,0x%08X) at IPC = 0x%s : TODO (architecture specific)\n",coproc_num,coproc_reg,memword,pr_addr(IPC));
+ sim_io_printf(sd,"COP_LW(%d,%d,0x%08X) at PC = 0x%s : TODO (architecture specific)\n",coproc_num,coproc_reg,memword,pr_addr(cia));
#endif
- break;
- }
+ break;
+ }
return;
}
-static void
-COP_LD(coproc_num,coproc_reg,memword)
- int coproc_num, coproc_reg;
- uword64 memword;
+void
+cop_ld (SIM_DESC sd,
+ sim_cpu *cpu,
+ address_word cia,
+ int coproc_num,
+ int coproc_reg,
+ uword64 memword)
{
+
+#ifdef DEBUG
+ printf("DBG: COP_LD: coproc_num = %d, coproc_reg = %d, value = 0x%s : PC = 0x%s\n", coproc_num, coproc_reg, pr_uword64(memword), pr_addr(cia) );
+#endif
+
switch (coproc_num) {
-#if defined(HASFPU)
case 1:
- StoreFPR(coproc_reg,fmt_uninterpreted,memword);
- break;
-#endif /* HASFPU */
+ if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT)
+ {
+ StoreFPR(coproc_reg,fmt_uninterpreted_64,memword);
+ break;
+ }
default:
#if 0 /* this message should be controlled by a configuration option */
- callback->printf_filtered(callback,"COP_LD(%d,%d,0x%s) at IPC = 0x%s : TODO (architecture specific)\n",coproc_num,coproc_reg,pr_addr(memword),pr_addr(IPC));
+ sim_io_printf(sd,"COP_LD(%d,%d,0x%s) at PC = 0x%s : TODO (architecture specific)\n",coproc_num,coproc_reg,pr_addr(memword),pr_addr(cia));
#endif
break;
}
return;
}
-static unsigned int
-COP_SW(coproc_num,coproc_reg)
- int coproc_num, coproc_reg;
+
+
+
+unsigned int
+cop_sw (SIM_DESC sd,
+ sim_cpu *cpu,
+ address_word cia,
+ int coproc_num,
+ int coproc_reg)
{
unsigned int value = 0;
- FP_formats hold;
- switch (coproc_num) {
-#if defined(HASFPU)
+ switch (coproc_num)
+ {
case 1:
-#if 1
- hold = fpr_state[coproc_reg];
- fpr_state[coproc_reg] = fmt_word;
- value = (unsigned int)ValueFPR(coproc_reg,fmt_uninterpreted);
- fpr_state[coproc_reg] = hold;
-#else
-#if 1
- value = (unsigned int)ValueFPR(coproc_reg,fpr_state[coproc_reg]);
-#else
-#ifdef DEBUG
- printf("DBG: COP_SW: reg in format %s (will be accessing as single)\n",DOFMT(fpr_state[coproc_reg]));
-#endif /* DEBUG */
- value = (unsigned int)ValueFPR(coproc_reg,fmt_single);
-#endif
-#endif
- break;
-#endif /* HASFPU */
+ if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT)
+ {
+ value = (unsigned int)ValueFPR(coproc_reg,fmt_uninterpreted_32);
+ break;
+ }
default:
#if 0 /* should be controlled by configuration option */
- callback->printf_filtered(callback,"COP_SW(%d,%d) at IPC = 0x%s : TODO (architecture specific)\n",coproc_num,coproc_reg,pr_addr(IPC));
+ sim_io_printf(sd,"COP_SW(%d,%d) at PC = 0x%s : TODO (architecture specific)\n",coproc_num,coproc_reg,pr_addr(cia));
#endif
- break;
- }
+ break;
+ }
return(value);
}
-static uword64
-COP_SD(coproc_num,coproc_reg)
- int coproc_num, coproc_reg;
+uword64
+cop_sd (SIM_DESC sd,
+ sim_cpu *cpu,
+ address_word cia,
+ int coproc_num,
+ int coproc_reg)
{
uword64 value = 0;
- switch (coproc_num) {
-#if defined(HASFPU)
+ switch (coproc_num)
+ {
case 1:
-#if 1
- value = ValueFPR(coproc_reg,fmt_uninterpreted);
-#else
-#if 1
- value = ValueFPR(coproc_reg,fpr_state[coproc_reg]);
-#else
-#ifdef DEBUG
- printf("DBG: COP_SD: reg in format %s (will be accessing as double)\n",DOFMT(fpr_state[coproc_reg]));
-#endif /* DEBUG */
- value = ValueFPR(coproc_reg,fmt_double);
-#endif
-#endif
- break;
-#endif /* HASFPU */
+ if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT)
+ {
+ value = ValueFPR(coproc_reg,fmt_uninterpreted_64);
+ break;
+ }
default:
#if 0 /* should be controlled by configuration option */
- callback->printf_filtered(callback,"COP_SD(%d,%d) at IPC = 0x%s : TODO (architecture specific)\n",coproc_num,coproc_reg,pr_addr(IPC));
+ sim_io_printf(sd,"COP_SD(%d,%d) at PC = 0x%s : TODO (architecture specific)\n",coproc_num,coproc_reg,pr_addr(cia));
#endif
- break;
- }
+ break;
+ }
return(value);
}
-static void
-decode_coproc(instruction)
- unsigned int instruction;
+
+
+
+void
+decode_coproc (SIM_DESC sd,
+ sim_cpu *cpu,
+ address_word cia,
+ unsigned int instruction)
{
int coprocnum = ((instruction >> 26) & 3);
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--->
DMFC0 Doubleword Move From CP0 (VR4100 = 01000000001tttttddddd00000000000)
DMTC0 Doubleword Move To CP0 (VR4100 = 01000000101tttttddddd00000000000)
MFC0 word Move From CP0 (VR4100 = 01000000000tttttddddd00000000000)
CACHE Cache operation (VR4100 = 101111bbbbbpppppiiiiiiiiiiiiiiii)
ERET Exception return (VR4100 = 01000010000000000000000000011000)
*/
- if (((code == 0x00) || (code == 0x04)) && ((instruction & 0x7FF) == 0))
+ if (((code == 0x00) || (code == 0x04) /* MFC0 / MTC0 */
+ || (code == 0x01) || (code == 0x05)) /* DMFC0 / DMTC0 */
+ && tail == 0)
{
- int rt = ((instruction >> 16) & 0x1F);
- int rd = ((instruction >> 11) & 0x1F);
+ /* Clear double/single coprocessor move bit. */
+ code &= ~1;
+
+ /* M[TF]C0 (32 bits) | DM[TF]C0 (64 bits) */
switch (rd) /* NOTEs: Standard CP0 registers */
{
/* 10 = EntryHi R4000 VR4100 VR4300 */
/* 11 = Compare R4000 VR4100 VR4300 */
/* 12 = SR R4000 VR4100 VR4300 */
+#ifdef SUBTARGET_R3900
+ case 3:
+ /* 3 = Config R3900 */
+ case 7:
+ /* 7 = Cache R3900 */
+ case 15:
+ /* 15 = PRID R3900 */
+
+ /* ignore */
+ break;
+
+ case 8:
+ /* 8 = BadVAddr R4000 VR4100 VR4300 */
+ if (code == 0x00)
+ GPR[rt] = (signed_word) (signed_address) COP0_BADVADDR;
+ else
+ COP0_BADVADDR = GPR[rt];
+ break;
+
+#endif /* SUBTARGET_R3900 */
case 12:
if (code == 0x00)
GPR[rt] = SR;
CAUSE = GPR[rt];
break;
/* 14 = EPC R4000 VR4100 VR4300 */
+ case 14:
+ if (code == 0x00)
+ GPR[rt] = (signed_word) (signed_address) EPC;
+ else
+ EPC = GPR[rt];
+ break;
/* 15 = PRId R4000 VR4100 VR4300 */
+#ifdef SUBTARGET_R3900
+ /* 16 = Debug */
+ case 16:
+ if (code == 0x00)
+ GPR[rt] = Debug;
+ else
+ Debug = GPR[rt];
+ break;
+#else
/* 16 = Config R4000 VR4100 VR4300 */
+ case 16:
+ if (code == 0x00)
+ GPR[rt] = C0_CONFIG;
+ else
+ /* only bottom three bits are writable */
+ C0_CONFIG = (C0_CONFIG & ~0x7) | (GPR[rt] & 0x7);
+ break;
+#endif
+#ifdef SUBTARGET_R3900
+ /* 17 = Debug */
+ case 17:
+ if (code == 0x00)
+ GPR[rt] = DEPC;
+ else
+ DEPC = GPR[rt];
+ break;
+#else
/* 17 = LLAddr R4000 VR4100 VR4300 */
+#endif
/* 18 = WatchLo R4000 VR4100 VR4300 */
/* 19 = WatchHi R4000 VR4100 VR4300 */
/* 20 = XContext R4000 VR4100 VR4300 */
/* 28 = TagLo R4000 VR4100 VR4300 */
/* 29 = TagHi R4000 VR4100 VR4300 */
/* 30 = ErrorEPC R4000 VR4100 VR4300 */
+ if (STATE_VERBOSE_P(SD))
+ sim_io_eprintf (SD,
+ "Warning: PC 0x%lx:interp.c decode_coproc DEADC0DE\n",
+ (unsigned long)cia);
GPR[rt] = 0xDEADC0DE; /* CPR[0,rd] */
/* CPR[0,rd] = GPR[rt]; */
default:
if (code == 0x00)
- callback->printf_filtered(callback,"Warning: MFC0 %d,%d not handled yet (architecture specific)\n",rt,rd);
+ GPR[rt] = (signed_word) (signed32) COP0_GPR[rd];
else
- callback->printf_filtered(callback,"Warning: MTC0 %d,%d not handled yet (architecture specific)\n",rt,rd);
+ COP0_GPR[rd] = GPR[rt];
+#if 0
+ if (code == 0x00)
+ sim_io_printf(sd,"Warning: MFC0 %d,%d ignored, PC=%08x (architecture specific)\n",rt,rd, (unsigned)cia);
+ else
+ sim_io_printf(sd,"Warning: MTC0 %d,%d ignored, PC=%08x (architecture specific)\n",rt,rd, (unsigned)cia);
+#endif
+ }
+ }
+ else if ((code == 0x00 || code == 0x01)
+ && rd == 16)
+ {
+ /* [D]MFC0 RT,C0_CONFIG,SEL */
+ signed32 cfg = 0;
+ switch (tail & 0x07)
+ {
+ case 0:
+ cfg = C0_CONFIG;
+ break;
+ case 1:
+ /* MIPS32 r/o Config1:
+ Config2 present */
+ cfg = 0x80000000;
+ /* MIPS16 implemented.
+ XXX How to check configuration? */
+ cfg |= 0x0000004;
+ if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT)
+ /* MDMX & FPU implemented */
+ cfg |= 0x00000021;
+ break;
+ case 2:
+ /* MIPS32 r/o Config2:
+ Config3 present. */
+ cfg = 0x80000000;
+ break;
+ case 3:
+ /* MIPS32 r/o Config3:
+ SmartMIPS implemented. */
+ cfg = 0x00000002;
+ break;
}
+ GPR[rt] = cfg;
}
- else if (code == 0x10 && (instruction & 0x3f) == 0x18)
+ else if (code == 0x10 && (tail & 0x3f) == 0x18)
{
/* ERET */
if (SR & status_ERL)
{
/* Oops, not yet available */
- callback->printf_filtered(callback,"Warning: ERET when SR[ERL] set not handled yet");
+ sim_io_printf(sd,"Warning: ERET when SR[ERL] set not handled yet");
PC = EPC;
SR &= ~status_ERL;
}
SR &= ~status_EXL;
}
}
+ else if (code == 0x10 && (tail & 0x3f) == 0x10)
+ {
+ /* RFE */
+#ifdef SUBTARGET_R3900
+ /* TX39: Copy IEp/KUp -> IEc/KUc, and IEo/KUo -> IEp/KUp */
+
+ /* shift IE/KU history bits right */
+ SR = LSMASKED32(SR, 31, 4) | LSINSERTED32(LSEXTRACTED32(SR, 5, 2), 3, 0);
+
+ /* TODO: CACHE register */
+#endif /* SUBTARGET_R3900 */
+ }
+ else if (code == 0x10 && (tail & 0x3f) == 0x1F)
+ {
+ /* DERET */
+ Debug &= ~Debug_DM;
+ DELAYSLOT();
+ DSPC = DEPC;
+ }
else
- sim_warning("Unrecognised COP0 instruction 0x%08X at IPC = 0x%s : No handler present",instruction,pr_addr(IPC));
+ sim_io_eprintf(sd,"Unrecognised COP0 instruction 0x%08X at PC = 0x%s : No handler present\n",instruction,pr_addr(cia));
/* TODO: When executing an ERET or RFE instruction we should
clear LLBIT, to ensure that any out-standing atomic
read/modify/write sequence fails. */
}
break;
- case 2: /* undefined co-processor */
- sim_warning("COP2 instruction 0x%08X at IPC = 0x%s : No handler present",instruction,pr_addr(IPC));
- break;
-
+ case 2: /* co-processor 2 */
+ {
+ int handle = 0;
+
+
+ if(! handle)
+ {
+ sim_io_eprintf(sd, "COP2 instruction 0x%08X at PC = 0x%s : No handler present\n",
+ instruction,pr_addr(cia));
+ }
+ }
+ break;
+
case 1: /* should not occur (FPU co-processor) */
case 3: /* should not occur (FPU co-processor) */
SignalException(ReservedInstruction,instruction);
return;
}
-/*-- instruction simulation -------------------------------------------------*/
-
-void
-sim_engine_run (sd, next_cpu_nr, siggnal)
- SIM_DESC sd;
- int next_cpu_nr; /* ignore */
- int siggnal; /* ignore */
-{
-#if !defined(FASTSIM)
- unsigned int pipeline_count = 1;
-#endif
-
-#ifdef DEBUG
- if (STATE_MEMORY (sd) == NULL) {
- printf("DBG: simulate() entered with no memory\n");
- exit(1);
- }
-#endif /* DEBUG */
-
-#if 0 /* Disabled to check that everything works OK */
- /* The VR4300 seems to sign-extend the PC on its first
- access. However, this may just be because it is currently
- configured in 32bit mode. However... */
- PC = SIGNEXTEND(PC,32);
-#endif
-
- /* main controlling loop */
- while (1) {
- /* Fetch the next instruction from the simulator memory: */
- uword64 vaddr = (uword64)PC;
- uword64 paddr;
- int cca;
- unsigned int instruction; /* uword64? what's this used for? FIXME! */
- int dsstate = (state & simDELAYSLOT);
-
-#ifdef DEBUG
- {
- printf("DBG: state = 0x%08X :",state);
-#if 0
- if (state & simSTOP) printf(" simSTOP");
- if (state & simSTEP) printf(" simSTEP");
-#endif
- if (state & simHALTEX) printf(" simHALTEX");
- if (state & simHALTIN) printf(" simHALTIN");
-#if 0
- if (state & simBE) printf(" simBE");
-#endif
- printf("\n");
- }
-#endif /* DEBUG */
-
-#ifdef DEBUG
- if (dsstate)
- callback->printf_filtered(callback,"DBG: DSPC = 0x%s\n",pr_addr(DSPC));
-#endif /* DEBUG */
-
- if (AddressTranslation(PC,isINSTRUCTION,isLOAD,&paddr,&cca,isTARGET,isREAL)) {
- if ((vaddr & 1) == 0) {
- /* Copy the action of the LW instruction */
- unsigned int reverse = (ReverseEndian ? (LOADDRMASK >> 2) : 0);
- unsigned int bigend = (BigEndianCPU ? (LOADDRMASK >> 2) : 0);
- uword64 value;
- unsigned int byte;
- paddr = ((paddr & ~LOADDRMASK) | ((paddr & LOADDRMASK) ^ (reverse << 2)));
- LoadMemory(&value,NULL,cca,AccessLength_WORD,paddr,vaddr,isINSTRUCTION,isREAL);
- byte = ((vaddr & LOADDRMASK) ^ (bigend << 2));
- instruction = ((value >> (8 * byte)) & 0xFFFFFFFF);
- } else {
- /* Copy the action of the LH instruction */
- unsigned int reverse = (ReverseEndian ? (LOADDRMASK >> 1) : 0);
- unsigned int bigend = (BigEndianCPU ? (LOADDRMASK >> 1) : 0);
- uword64 value;
- unsigned int byte;
- paddr = (((paddr & ~ (uword64) 1) & ~LOADDRMASK)
- | (((paddr & ~ (uword64) 1) & LOADDRMASK) ^ (reverse << 1)));
- LoadMemory(&value,NULL,cca, AccessLength_HALFWORD,
- paddr & ~ (uword64) 1,
- vaddr, isINSTRUCTION, isREAL);
- byte = (((vaddr &~ (uword64) 1) & LOADDRMASK) ^ (bigend << 1));
- instruction = ((value >> (8 * byte)) & 0xFFFF);
- }
- } else {
- fprintf(stderr,"Cannot translate address for PC = 0x%s failed\n",pr_addr(PC));
- exit(1);
- }
-
-#ifdef DEBUG
- callback->printf_filtered(callback,"DBG: fetched 0x%08X from PC = 0x%s\n",instruction,pr_addr(PC));
-#endif /* DEBUG */
-
-#if !defined(FASTSIM) || defined(PROFILE)
- instruction_fetches++;
- /* Since we increment above, the value should only ever be zero if
- we have just overflowed: */
- if (instruction_fetches == 0)
- instruction_fetch_overflow++;
-#if defined(PROFILE)
- if ((state & simPROFILE) && ((instruction_fetches % profile_frequency) == 0) && profile_hist) {
- unsigned n = ((unsigned int)(PC - profile_minpc) >> (profile_shift + 2));
- if (n < profile_nsamples) {
- /* NOTE: The counts for the profiling bins are only 16bits wide */
- if (profile_hist[n] != USHRT_MAX)
- (profile_hist[n])++;
- }
- }
-#endif /* PROFILE */
-#endif /* !FASTSIM && PROFILE */
-
- IPC = PC; /* copy PC for this instruction */
- /* This is required by exception processing, to ensure that we can
- cope with exceptions in the delay slots of branches that may
- already have changed the PC. */
- if ((vaddr & 1) == 0)
- PC += 4; /* increment ready for the next fetch */
- else
- PC += 2;
- /* NOTE: If we perform a delay slot change to the PC, this
- increment is not requuired. However, it would make the
- simulator more complicated to try and avoid this small hit. */
-
- /* Currently this code provides a simple model. For more
- complicated models we could perform exception status checks at
- this point, and set the simSTOP state as required. This could
- also include processing any hardware interrupts raised by any
- I/O model attached to the simulator context.
-
- Support for "asynchronous" I/O events within the simulated world
- could be providing by managing a counter, and calling a I/O
- specific handler when a particular threshold is reached. On most
- architectures a decrement and check for zero operation is
- usually quicker than an increment and compare. However, the
- process of managing a known value decrement to zero, is higher
- than the cost of using an explicit value UINT_MAX into the
- future. Which system is used will depend on how complicated the
- I/O model is, and how much it is likely to affect the simulator
- bandwidth.
-
- If events need to be scheduled further in the future than
- UINT_MAX event ticks, then the I/O model should just provide its
- own counter, triggered from the event system. */
-
- /* MIPS pipeline ticks. To allow for future support where the
- pipeline hit of individual instructions is known, this control
- loop manages a "pipeline_count" variable. It is initialised to
- 1 (one), and will only be changed by the simulator engine when
- executing an instruction. If the engine does not have access to
- pipeline cycle count information then all instructions will be
- treated as using a single cycle. NOTE: A standard system is not
- provided by the default simulator because different MIPS
- architectures have different cycle counts for the same
- instructions.
-
- [NOTE: pipeline_count has been replaced the event queue] */
-
-#if defined(HASFPU)
- /* Set previous flag, depending on current: */
- if (state & simPCOC0)
- state |= simPCOC1;
- else
- state &= ~simPCOC1;
- /* and update the current value: */
- if (GETFCC(0))
- state |= simPCOC0;
- else
- state &= ~simPCOC0;
-#endif /* HASFPU */
-
-/* NOTE: For multi-context simulation environments the "instruction"
- variable should be local to this routine. */
-
-/* Shorthand accesses for engine. Note: If we wanted to use global
- variables (and a single-threaded simulator engine), then we can
- create the actual variables with these names. */
-
- if (!(state & simSKIPNEXT)) {
- /* Include the simulator engine */
-#include "engine.c"
-#if ((GPRLEN == 64) && !PROCESSOR_64BIT) || ((GPRLEN == 32) && PROCESSOR_64BIT)
-#error "Mismatch between run-time simulator code and simulation engine"
-#endif
-
-#if defined(WARN_LOHI)
- /* Decrement the HI/LO validity ticks */
- if (HIACCESS > 0)
- HIACCESS--;
- if (LOACCESS > 0)
- LOACCESS--;
- if (HI1ACCESS > 0)
- HI1ACCESS--;
- if (LO1ACCESS > 0)
- LO1ACCESS--;
-#endif /* WARN_LOHI */
-
- /* For certain MIPS architectures, GPR[0] is hardwired to zero. We
- should check for it being changed. It is better doing it here,
- than within the simulator, since it will help keep the simulator
- small. */
- if (ZERO != 0) {
-#if defined(WARN_ZERO)
- sim_warning("The ZERO register has been updated with 0x%s (PC = 0x%s) (reset back to zero)",pr_addr(ZERO),pr_addr(IPC));
-#endif /* WARN_ZERO */
- ZERO = 0; /* reset back to zero before next instruction */
- }
- } else /* simSKIPNEXT check */
- state &= ~simSKIPNEXT;
-
- /* If the delay slot was active before the instruction is
- executed, then update the PC to its new value: */
- if (dsstate) {
-#ifdef DEBUG
- printf("DBG: dsstate set before instruction execution - updating PC to 0x%s\n",pr_addr(DSPC));
-#endif /* DEBUG */
- PC = DSPC;
- state &= ~(simDELAYSLOT | simJALDELAYSLOT);
- }
-
- if (MIPSISA < 4) { /* The following is only required on pre MIPS IV processors: */
- /* Deal with pending register updates: */
-#ifdef DEBUG
- printf("DBG: EMPTY BEFORE pending_in = %d, pending_out = %d, pending_total = %d\n",pending_in,pending_out,pending_total);
-#endif /* DEBUG */
- if (pending_out != pending_in) {
- int loop;
- int index = pending_out;
- int total = pending_total;
- if (pending_total == 0) {
- fprintf(stderr,"FATAL: Mis-match on pending update pointers\n");
- exit(1);
- }
- for (loop = 0; (loop < total); loop++) {
-#ifdef DEBUG
- printf("DBG: BEFORE index = %d, loop = %d\n",index,loop);
-#endif /* DEBUG */
- if (pending_slot_reg[index] != (LAST_EMBED_REGNUM + 1)) {
-#ifdef DEBUG
- printf("pending_slot_count[%d] = %d\n",index,pending_slot_count[index]);
-#endif /* DEBUG */
- if (--(pending_slot_count[index]) == 0) {
-#ifdef DEBUG
- printf("pending_slot_reg[%d] = %d\n",index,pending_slot_reg[index]);
- printf("pending_slot_value[%d] = 0x%s\n",index,pr_addr(pending_slot_value[index]));
-#endif /* DEBUG */
- if (pending_slot_reg[index] == COCIDX) {
- SETFCC(0,((FCR31 & (1 << 23)) ? 1 : 0));
- } else {
- registers[pending_slot_reg[index]] = pending_slot_value[index];
-#if defined(HASFPU)
- /* The only time we have PENDING updates to FPU
- registers, is when performing binary transfers. This
- means we should update the register type field. */
- if ((pending_slot_reg[index] >= FGRIDX) && (pending_slot_reg[index] < (FGRIDX + 32)))
- fpr_state[pending_slot_reg[index] - FGRIDX] = fmt_uninterpreted;
-#endif /* HASFPU */
- }
-#ifdef DEBUG
- printf("registers[%d] = 0x%s\n",pending_slot_reg[index],pr_addr(registers[pending_slot_reg[index]]));
-#endif /* DEBUG */
- pending_slot_reg[index] = (LAST_EMBED_REGNUM + 1);
- pending_out++;
- if (pending_out == PSLOTS)
- pending_out = 0;
- pending_total--;
- }
- }
-#ifdef DEBUG
- printf("DBG: AFTER index = %d, loop = %d\n",index,loop);
-#endif /* DEBUG */
- index++;
- if (index == PSLOTS)
- index = 0;
- }
- }
-#ifdef DEBUG
- printf("DBG: EMPTY AFTER pending_in = %d, pending_out = %d, pending_total = %d\n",pending_in,pending_out,pending_total);
-#endif /* DEBUG */
- }
-
-#if !defined(FASTSIM)
- if (sim_events_tickn (sd, pipeline_count))
- {
- /* cpu->cia = cia; */
- sim_events_process (sd);
- }
-#else
- if (sim_events_tick (sd))
- {
- /* cpu->cia = cia; */
- sim_events_process (sd);
- }
-#endif /* FASTSIM */
- }
-}
/* This code copied from gdb's utils.c. Would like to share this code,
but don't know of a common place where both could get to it. */
#define NUMCELLS 16
#define CELLSIZE 32
static char*
-get_cell()
+get_cell (void)
{
static char buf[NUMCELLS][CELLSIZE];
static int cell=0;
}
+void
+mips_core_signal (SIM_DESC sd,
+ sim_cpu *cpu,
+ sim_cia cia,
+ unsigned map,
+ int nr_bytes,
+ address_word addr,
+ transfer_type transfer,
+ sim_core_signals sig)
+{
+ const char *copy = (transfer == read_transfer ? "read" : "write");
+ address_word ip = CIA_ADDR (cia);
+
+ switch (sig)
+ {
+ case sim_core_unmapped_signal:
+ sim_io_eprintf (sd, "mips-core: %d byte %s to unmapped address 0x%lx at 0x%lx\n",
+ nr_bytes, copy,
+ (unsigned long) addr, (unsigned long) ip);
+ COP0_BADVADDR = addr;
+ SignalExceptionDataReference();
+ break;
+
+ case sim_core_unaligned_signal:
+ sim_io_eprintf (sd, "mips-core: %d byte %s to unaligned address 0x%lx at 0x%lx\n",
+ nr_bytes, copy,
+ (unsigned long) addr, (unsigned long) ip);
+ COP0_BADVADDR = addr;
+ if(transfer == read_transfer)
+ SignalExceptionAddressLoad();
+ else
+ SignalExceptionAddressStore();
+ break;
+
+ default:
+ sim_engine_abort (sd, cpu, cia,
+ "mips_core_signal - internal error - bad switch");
+ }
+}
+
+
+void
+mips_cpu_exception_trigger(SIM_DESC sd, sim_cpu* cpu, address_word cia)
+{
+ ASSERT(cpu != NULL);
+
+ if(cpu->exc_suspended > 0)
+ sim_io_eprintf(sd, "Warning, nested exception triggered (%d)\n", cpu->exc_suspended);
+
+ PC = cia;
+ memcpy(cpu->exc_trigger_registers, cpu->registers, sizeof(cpu->exc_trigger_registers));
+ cpu->exc_suspended = 0;
+}
+
+void
+mips_cpu_exception_suspend(SIM_DESC sd, sim_cpu* cpu, int exception)
+{
+ ASSERT(cpu != NULL);
+
+ if(cpu->exc_suspended > 0)
+ sim_io_eprintf(sd, "Warning, nested exception signal (%d then %d)\n",
+ cpu->exc_suspended, exception);
+
+ memcpy(cpu->exc_suspend_registers, cpu->registers, sizeof(cpu->exc_suspend_registers));
+ memcpy(cpu->registers, cpu->exc_trigger_registers, sizeof(cpu->registers));
+ cpu->exc_suspended = exception;
+}
+
+void
+mips_cpu_exception_resume(SIM_DESC sd, sim_cpu* cpu, int exception)
+{
+ ASSERT(cpu != NULL);
+
+ if(exception == 0 && cpu->exc_suspended > 0)
+ {
+ /* warn not for breakpoints */
+ if(cpu->exc_suspended != sim_signal_to_host(sd, SIM_SIGTRAP))
+ sim_io_eprintf(sd, "Warning, resuming but ignoring pending exception signal (%d)\n",
+ cpu->exc_suspended);
+ }
+ else if(exception != 0 && cpu->exc_suspended > 0)
+ {
+ if(exception != cpu->exc_suspended)
+ sim_io_eprintf(sd, "Warning, resuming with mismatched exception signal (%d vs %d)\n",
+ cpu->exc_suspended, exception);
+
+ memcpy(cpu->registers, cpu->exc_suspend_registers, sizeof(cpu->registers));
+ }
+ else if(exception != 0 && cpu->exc_suspended == 0)
+ {
+ sim_io_eprintf(sd, "Warning, ignoring spontanous exception signal (%d)\n", exception);
+ }
+ cpu->exc_suspended = 0;
+}
+
+
/*---------------------------------------------------------------------------*/
/*> EOF interp.c <*/