Make sure cmp{,eq,u}i use correct casts
[deliverable/binutils-gdb.git] / sim / mips / interp.c
CommitLineData
8bae0a0c
JSC
1/*> interp.c <*/
2/* Simulator for the MIPS architecture.
3
4 This file is part of the MIPS sim
5
6 THIS SOFTWARE IS NOT COPYRIGHTED
7
8 Cygnus offers the following for use in the public domain. Cygnus
9 makes no warranty with regard to the software or it's performance
10 and the user accepts the software "AS IS" with all faults.
11
12 CYGNUS DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO
13 THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
15
16 $Revision$
17 $Author$
18 $Date$
19
20NOTEs:
21
22We only need to take account of the target endianness when moving data
23between the simulator and the host. We do not need to worry about the
24endianness of the host, since this sim code and GDB are executing in
25the same process.
26
27The IDT monitor (found on the VR4300 board), seems to lie about
28register contents. It seems to treat the registers as sign-extended
2932-bit values. This cause *REAL* problems when single-stepping 64-bit
30code on the hardware.
31
32*/
33
34/* The TRACE and PROFILE manifests enable the provision of extra
35 features. If they are not defined then a simpler (quicker)
36 simulator is constructed without the required run-time checks,
37 etc. */
38#if 1 /* 0 to allow user build selection, 1 to force inclusion */
39#define TRACE (1)
40#define PROFILE (1)
41#endif
42
4fa134be
ILT
43#include "config.h"
44
8bae0a0c
JSC
45#include <stdio.h>
46#include <stdarg.h>
47#include <ansidecl.h>
48#include <signal.h>
49#include <ctype.h>
50#include <limits.h>
51#include <math.h>
4fa134be
ILT
52#ifdef HAVE_STDLIB_H
53#include <stdlib.h>
54#endif
55#ifdef HAVE_STRING_H
56#include <string.h>
57#else
58#ifdef HAVE_STRINGS_H
59#include <strings.h>
60#endif
61#endif
8bae0a0c
JSC
62
63#include "getopt.h"
64#include "libiberty.h"
65
66#include "remote-sim.h" /* GDB simulator interface */
67#include "callback.h" /* GDB simulator callback interface */
68
69#include "support.h" /* internal support manifests */
70
f24b7b69
JSC
71#include "sysdep.h"
72
73#ifndef SIGBUS
74#define SIGBUS SIGSEGV
75#endif
76
8bae0a0c
JSC
77/* Get the simulator engine description, without including the code: */
78#define SIM_MANIFESTS
79#include "engine.c"
80#undef SIM_MANIFESTS
81
f7481d45
JSC
82/* This variable holds the GDB view of the target endianness: */
83extern int target_byte_order;
84
8bae0a0c
JSC
85/* The following reserved instruction value is used when a simulator
86 trap is required. NOTE: Care must be taken, since this value may be
87 used in later revisions of the MIPS ISA. */
88#define RSVD_INSTRUCTION (0x7C000000)
89#define RSVD_INSTRUCTION_AMASK (0x03FFFFFF)
90
91/* NOTE: These numbers depend on the processor architecture being
92 simulated: */
93#define Interrupt (0)
94#define TLBModification (1)
95#define TLBLoad (2)
96#define TLBStore (3)
97#define AddressLoad (4)
98#define AddressStore (5)
99#define InstructionFetch (6)
100#define DataReference (7)
101#define SystemCall (8)
102#define BreakPoint (9)
103#define ReservedInstruction (10)
104#define CoProcessorUnusable (11)
105#define IntegerOverflow (12) /* Arithmetic overflow (IDT monitor raises SIGFPE) */
106#define Trap (13)
107#define FPE (15)
108#define Watch (23)
109
110/* The following exception code is actually private to the simulator
111 world. It is *NOT* a processor feature, and is used to signal
112 run-time errors in the simulator. */
113#define SimulatorFault (0xFFFFFFFF)
114
115/* The following are generic to all versions of the MIPS architecture
116 to date: */
117/* Memory Access Types (for CCA): */
118#define Uncached (0)
119#define CachedNoncoherent (1)
120#define CachedCoherent (2)
121#define Cached (3)
122
123#define isINSTRUCTION (1 == 0) /* FALSE */
124#define isDATA (1 == 1) /* TRUE */
125
126#define isLOAD (1 == 0) /* FALSE */
127#define isSTORE (1 == 1) /* TRUE */
128
129#define isREAL (1 == 0) /* FALSE */
130#define isRAW (1 == 1) /* TRUE */
131
132#define isTARGET (1 == 0) /* FALSE */
133#define isHOST (1 == 1) /* TRUE */
134
135/* The "AccessLength" specifications for Loads and Stores. NOTE: This
136 is the number of bytes minus 1. */
137#define AccessLength_BYTE (0)
138#define AccessLength_HALFWORD (1)
139#define AccessLength_TRIPLEBYTE (2)
140#define AccessLength_WORD (3)
141#define AccessLength_QUINTIBYTE (4)
142#define AccessLength_SEXTIBYTE (5)
143#define AccessLength_SEPTIBYTE (6)
144#define AccessLength_DOUBLEWORD (7)
145
146#if defined(HASFPU)
147/* FPU registers must be one of the following types. All other values
148 are reserved (and undefined). */
149typedef enum {
150 fmt_single = 0,
151 fmt_double = 1,
152 fmt_word = 4,
153 fmt_long = 5,
154 /* The following are well outside the normal acceptable format
155 range, and are used in the register status vector. */
156 fmt_unknown = 0x10000000,
157 fmt_uninterpreted = 0x20000000,
158} FP_formats;
159#endif /* HASFPU */
160
161/* NOTE: We cannot avoid globals, since the GDB "sim_" interface does
162 not allow a private variable to be passed around. This means that
163 simulators under GDB can only be single-threaded. However, it would
164 be possible for the simulators to be multi-threaded if GDB allowed
165 for a private pointer to be maintained. i.e. a general "void **ptr"
166 variable that GDB passed around in the argument list to all of
167 sim_xxx() routines. It could be initialised to NULL by GDB, and
168 then updated by sim_open() and used by the other sim_xxx() support
169 functions. This would allow new features in the simulator world,
170 like storing a context - continuing execution to gather a result,
171 and then going back to the point where the context was saved and
172 changing some state before continuing. i.e. the ability to perform
173 UNDOs on simulations. It would also allow the simulation of
174 shared-memory multi-processor systems. */
175
176static host_callback *callback = NULL; /* handle onto the current callback structure */
177
8bae0a0c
JSC
178/* This is nasty, since we have to rely on matching the register
179 numbers used by GDB. Unfortunately, depending on the MIPS target
180 GDB uses different register numbers. We cannot just include the
181 relevant "gdb/tm.h" link, since GDB may not be configured before
182 the sim world, and also the GDB header file requires too much other
183 state. */
184/* TODO: Sort out a scheme for *KNOWING* the mapping between real
185 registers, and the numbers that GDB uses. At the moment due to the
186 order that the tools are built, we cannot rely on a configured GDB
187 world whilst constructing the simulator. This means we have to
188 assume the GDB register number mapping. */
189#define LAST_EMBED_REGNUM (89)
190
191/* To keep this default simulator simple, and fast, we use a direct
192 vector of registers. The internal simulator engine then uses
193 manifests to access the correct slot. */
4fa134be
ILT
194static ut_reg registers[LAST_EMBED_REGNUM + 1];
195static int register_widths[LAST_EMBED_REGNUM + 1];
8bae0a0c
JSC
196
197#define GPR (&registers[0])
198#if defined(HASFPU)
199#define FGRIDX (38)
200#define FGR (&registers[FGRIDX])
201#endif /* HASFPU */
202#define LO (registers[33])
203#define HI (registers[34])
204#define PC (registers[37])
205#define CAUSE (registers[36])
206#define SRIDX (32)
207#define SR (registers[SRIDX]) /* CPU status register */
208#define FCR0IDX (71)
209#define FCR0 (registers[FCR0IDX]) /* really a 32bit register */
210#define FCR31IDX (70)
211#define FCR31 (registers[FCR31IDX]) /* really a 32bit register */
212#define FCSR (FCR31)
213#define COCIDX (LAST_EMBED_REGNUM + 2) /* special case : outside the normal range */
214
215/* The following are pseudonyms for standard registers */
216#define ZERO (registers[0])
217#define V0 (registers[2])
218#define A0 (registers[4])
219#define A1 (registers[5])
220#define A2 (registers[6])
221#define A3 (registers[7])
222#define SP (registers[29])
223#define RA (registers[31])
224
4fa134be 225static ut_reg EPC = 0; /* Exception PC */
8bae0a0c
JSC
226
227#if defined(HASFPU)
228/* Keep the current format state for each register: */
4fa134be 229static FP_formats fpr_state[32];
8bae0a0c
JSC
230#endif /* HASFPU */
231
232/* VR4300 CP0 configuration register: */
4fa134be 233static unsigned int CONFIG = 0;
8bae0a0c
JSC
234
235/* The following are internal simulator state variables: */
4fa134be
ILT
236static ut_reg IPC = 0; /* internal Instruction PC */
237static ut_reg DSPC = 0; /* delay-slot PC */
8bae0a0c
JSC
238
239
240/* TODO : these should be the bitmasks for these bits within the
241 status register. At the moment the following are VR4300
242 bit-positions: */
243#define status_KSU_mask (0x3) /* mask for KSU bits */
244#define status_KSU_shift (3) /* shift for field */
245#define ksu_kernel (0x0)
246#define ksu_supervisor (0x1)
247#define ksu_user (0x2)
248#define ksu_unknown (0x3)
249
250#define status_RE (1 << 25) /* Reverse Endian in user mode */
251#define status_FR (1 << 26) /* enables MIPS III additional FP registers */
252#define status_SR (1 << 20) /* soft reset or NMI */
253#define status_BEV (1 << 22) /* Location of general exception vectors */
254#define status_TS (1 << 21) /* TLB shutdown has occurred */
255#define status_ERL (1 << 2) /* Error level */
256#define status_RP (1 << 27) /* Reduced Power mode */
257
258#define config_EP_mask (0xF)
259#define config_EP_shift (27)
260#define config_EP_D (0x0)
261#define config_EP_DxxDxx (0x6)
262
263#define config_BE (1 << 15)
264
265#define cause_BD ((unsigned)1 << 31) /* Exception in branch delay slot */
266
267#if defined(HASFPU)
268/* Macro to update FPSR condition-code field. This is complicated by
269 the fact that there is a hole in the index range of the bits within
270 the FCSR register. Also, the number of bits visible depends on the
271 MIPS ISA version being supported. */
272#define SETFCC(cc,v) {\
273 int bit = ((cc == 0) ? 23 : (24 + (cc)));\
274 FCSR = ((FCSR & ~(1 << bit)) | ((v) << bit));\
275 }
276#define GETFCC(cc) (((((cc) == 0) ? (FCSR & (1 << 23)) : (FCSR & (1 << (24 + (cc))))) != 0) ? 1 : 0)
277
278/* This should be the COC1 value at the start of the preceding
279 instruction: */
280#define PREVCOC1() ((state & simPCOC1) ? 1 : 0)
281#endif /* HASFPU */
282
283/* Standard FCRS bits: */
284#define IR (0) /* Inexact Result */
285#define UF (1) /* UnderFlow */
286#define OF (2) /* OverFlow */
287#define DZ (3) /* Division by Zero */
288#define IO (4) /* Invalid Operation */
289#define UO (5) /* Unimplemented Operation */
290
291/* Get masks for individual flags: */
292#if 1 /* SAFE version */
293#define FP_FLAGS(b) (((unsigned)(b) < 5) ? (1 << ((b) + 2)) : 0)
294#define FP_ENABLE(b) (((unsigned)(b) < 5) ? (1 << ((b) + 7)) : 0)
295#define FP_CAUSE(b) (((unsigned)(b) < 6) ? (1 << ((b) + 12)) : 0)
296#else
297#define FP_FLAGS(b) (1 << ((b) + 2))
298#define FP_ENABLE(b) (1 << ((b) + 7))
299#define FP_CAUSE(b) (1 << ((b) + 12))
300#endif
301
302#define FP_FS (1 << 24) /* MIPS III onwards : Flush to Zero */
303
304#define FP_MASK_RM (0x3)
305#define FP_SH_RM (0)
306#define FP_RM_NEAREST (0) /* Round to nearest (Round) */
307#define FP_RM_TOZERO (1) /* Round to zero (Trunc) */
308#define FP_RM_TOPINF (2) /* Round to Plus infinity (Ceil) */
309#define FP_RM_TOMINF (3) /* Round to Minus infinity (Floor) */
310#define GETRM() (int)((FCSR >> FP_SH_RM) & FP_MASK_RM)
311
312/* Slots for delayed register updates. For the moment we just have a
313 fixed number of slots (rather than a more generic, dynamic
314 system). This keeps the simulator fast. However, we only allow for
315 the register update to be delayed for a single instruction
316 cycle. */
317#define PSLOTS (5) /* Maximum number of instruction cycles */
4fa134be
ILT
318static int pending_in;
319static int pending_out;
320static int pending_total;
321static int pending_slot_count[PSLOTS];
322static int pending_slot_reg[PSLOTS];
323static ut_reg pending_slot_value[PSLOTS];
8bae0a0c
JSC
324
325/* The following are not used for MIPS IV onwards: */
326#define PENDING_FILL(r,v) {\
f24b7b69 327/* printf("DBG: FILL BEFORE pending_in = %d, pending_out = %d, pending_total = %d\n",pending_in,pending_out,pending_total); */\
8bae0a0c 328 if (pending_slot_reg[pending_in] != (LAST_EMBED_REGNUM + 1))\
f24b7b69 329 sim_warning("Attempt to over-write pending value");\
8bae0a0c
JSC
330 pending_slot_count[pending_in] = 2;\
331 pending_slot_reg[pending_in] = (r);\
e871dd18 332 pending_slot_value[pending_in] = (uword64)(v);\
f24b7b69 333/*printf("DBG: FILL reg %d value = 0x%08X%08X\n",(r),WORD64HI(v),WORD64LO(v));*/\
8bae0a0c
JSC
334 pending_total++;\
335 pending_in++;\
336 if (pending_in == PSLOTS)\
337 pending_in = 0;\
f24b7b69 338/*printf("DBG: FILL AFTER pending_in = %d, pending_out = %d, pending_total = %d\n",pending_in,pending_out,pending_total);*/\
8bae0a0c
JSC
339 }
340
4fa134be 341static int LLBIT = 0;
8bae0a0c
JSC
342/* LLBIT = Load-Linked bit. A bit of "virtual" state used by atomic
343 read-write instructions. It is set when a linked load occurs. It is
344 tested and cleared by the conditional store. It is cleared (during
345 other CPU operations) when a store to the location would no longer
346 be atomic. In particular, it is cleared by exception return
347 instructions. */
348
4fa134be
ILT
349static int HIACCESS = 0;
350static int LOACCESS = 0;
8bae0a0c
JSC
351/* The HIACCESS and LOACCESS counts are used to ensure that
352 corruptions caused by using the HI or LO register to close to a
353 following operation are spotted. */
f24b7b69 354static ut_reg HLPC = 0;
8bae0a0c 355
f24b7b69 356/* TODO: The 4300 has interlocks so we should not need to warn of the possible over-write (CHECK THIS) */
8bae0a0c
JSC
357/* If either of the preceding two instructions have accessed the HI or
358 LO registers, then the values they see should be
359 undefined. However, to keep the simulator world simple, we just let
360 them use the value read and raise a warning to notify the user: */
361#define CHECKHILO(s) {\
362 if ((HIACCESS != 0) || (LOACCESS != 0))\
f24b7b69 363 sim_warning("%s over-writing HI and LO registers values (PC = 0x%08X%08X HLPC = 0x%08X%08X)\n",(s),(unsigned int)(PC>>32),(unsigned int)(PC&0xFFFFFFFF),(unsigned int)(HLPC>>32),(unsigned int)(HLPC&0xFFFFFFFF));\
8bae0a0c
JSC
364 }
365
366/* NOTE: We keep the following status flags as bit values (1 for true,
367 0 for false). This allows them to be used in binary boolean
368 operations without worrying about what exactly the non-zero true
369 value is. */
370
371/* UserMode */
372#define UserMode ((((SR & status_KSU_mask) >> status_KSU_shift) == ksu_user) ? 1 : 0)
373
374/* BigEndianMem */
375/* Hardware configuration. Affects endianness of LoadMemory and
376 StoreMemory and the endianness of Kernel and Supervisor mode
377 execution. The value is 0 for little-endian; 1 for big-endian. */
378#define BigEndianMem ((CONFIG & config_BE) ? 1 : 0)
379/* NOTE: Problems will occur if the simulator memory model does not
380 match the host program expectation. i.e. if the host is writing
381 big-endian values to a little-endian memory model. */
382
383/* ReverseEndian */
384/* This mode is selected if in User mode with the RE bit being set in
385 SR (Status Register). It reverses the endianness of load and store
386 instructions. */
387#define ReverseEndian (((SR & status_RE) && UserMode) ? 1 : 0)
388
389/* BigEndianCPU */
390/* The endianness for load and store instructions (0=little;1=big). In
391 User mode this endianness may be switched by setting the state_RE
392 bit in the SR register. Thus, BigEndianCPU may be computed as
393 (BigEndienMem EOR ReverseEndian). */
394#define BigEndianCPU (BigEndianMem ^ ReverseEndian) /* Already bits */
395
396#if !defined(FASTSIM) || defined(PROFILE)
397/* At the moment these values will be the same, since we do not have
398 access to the pipeline cycle count information from the simulator
399 engine. */
4fa134be
ILT
400static unsigned int instruction_fetches = 0;
401static unsigned int instruction_fetch_overflow = 0;
402static unsigned int pipeline_ticks = 0;
8bae0a0c
JSC
403#endif
404
405/* Flags in the "state" variable: */
406#define simSTOP (1 << 0) /* 0 = execute; 1 = stop simulation */
407#define simSTEP (1 << 1) /* 0 = run; 1 = single-step */
408#define simHALTEX (1 << 2) /* 0 = run; 1 = halt on exception */
409#define simHALTIN (1 << 3) /* 0 = run; 1 = halt on interrupt */
410#define simTRACE (1 << 8) /* 0 = do nothing; 1 = trace address activity */
411#define simPROFILE (1 << 9) /* 0 = do nothing; 1 = gather profiling samples */
412#define simHOSTBE (1 << 10) /* 0 = little-endian; 1 = big-endian (host endianness) */
413/* Whilst simSTOP is not set, the simulator control loop should just
414 keep simulating instructions. The simSTEP flag is used to force
415 single-step execution. */
416#define simBE (1 << 16) /* 0 = little-endian; 1 = big-endian (target endianness) */
417#define simPCOC0 (1 << 17) /* COC[1] from current */
418#define simPCOC1 (1 << 18) /* COC[1] from previous */
419#define simDELAYSLOT (1 << 24) /* 0 = do nothing; 1 = delay slot entry exists */
420#define simSKIPNEXT (1 << 25) /* 0 = do nothing; 1 = skip instruction */
421#define simEXCEPTION (1 << 26) /* 0 = no exception; 1 = exception has occurred */
422#define simEXIT (1 << 27) /* 0 = do nothing; 1 = run-time exit() processing */
423
4fa134be
ILT
424static unsigned int state = 0;
425static unsigned int rcexit = 0; /* _exit() reason code holder */
8bae0a0c
JSC
426
427#define DELAYSLOT() {\
f24b7b69
JSC
428 if (state & simDELAYSLOT)\
429 sim_warning("Delay slot already activated (branch in delay slot?)");\
8bae0a0c
JSC
430 state |= simDELAYSLOT;\
431 }
432
433#define NULLIFY() {\
434 state &= ~simDELAYSLOT;\
435 state |= simSKIPNEXT;\
436 }
437
a9f7253f
JSC
438#define K0BASE (0x80000000)
439#define K0SIZE (0x20000000)
440#define K1BASE (0xA0000000)
441#define K1SIZE (0x20000000)
442
8bae0a0c 443/* Very simple memory model to start with: */
4fa134be
ILT
444static unsigned char *membank = NULL;
445static ut_reg membank_base = K1BASE;
446static unsigned membank_size = (1 << 20); /* (16 << 20); */ /* power-of-2 */
8bae0a0c
JSC
447
448/* Simple run-time monitor support */
4fa134be
ILT
449static unsigned char *monitor = NULL;
450static ut_reg monitor_base = 0xBFC00000;
451static unsigned monitor_size = (1 << 11); /* power-of-2 */
8bae0a0c 452
f24b7b69
JSC
453static char *logfile = NULL; /* logging disabled by default */
454static FILE *logfh = NULL;
455
8bae0a0c 456#if defined(TRACE)
4fa134be
ILT
457static char *tracefile = "trace.din"; /* default filename for trace log */
458static FILE *tracefh = NULL;
8bae0a0c
JSC
459#endif /* TRACE */
460
461#if defined(PROFILE)
4fa134be
ILT
462static unsigned profile_frequency = 256;
463static unsigned profile_nsamples = (128 << 10);
464static unsigned short *profile_hist = NULL;
465static ut_reg profile_minpc;
466static ut_reg profile_maxpc;
467static int profile_shift = 0; /* address shift amount */
8bae0a0c
JSC
468#endif /* PROFILE */
469
f7481d45
JSC
470/* The following are used to provide shortcuts to the required version
471 of host<->target copying. This avoids run-time conditionals, which
472 would slow the simulator throughput. */
473typedef unsigned int (*fnptr_read_word) PARAMS((unsigned char *memory));
474typedef unsigned int (*fnptr_swap_word) PARAMS((unsigned int data));
475typedef uword64 (*fnptr_read_long) PARAMS((unsigned char *memory));
476typedef uword64 (*fnptr_swap_long) PARAMS((uword64 data));
477
4fa134be
ILT
478static fnptr_read_word host_read_word;
479static fnptr_read_long host_read_long;
480static fnptr_swap_word host_swap_word;
481static fnptr_swap_long host_swap_long;
f7481d45 482
8bae0a0c
JSC
483/*---------------------------------------------------------------------------*/
484/*-- GDB simulator interface ------------------------------------------------*/
485/*---------------------------------------------------------------------------*/
486
487static void dotrace PARAMS((FILE *tracefh,int type,unsigned int address,int width,char *comment,...));
f24b7b69 488static void sim_warning PARAMS((char *fmt,...));
8bae0a0c
JSC
489extern void sim_error PARAMS((char *fmt,...));
490static void ColdReset PARAMS((void));
e871dd18
JSC
491static int AddressTranslation PARAMS((uword64 vAddr,int IorD,int LorS,uword64 *pAddr,int *CCA,int host,int raw));
492static void StoreMemory PARAMS((int CCA,int AccessLength,uword64 MemElem,uword64 pAddr,uword64 vAddr,int raw));
493static uword64 LoadMemory PARAMS((int CCA,int AccessLength,uword64 pAddr,uword64 vAddr,int IorD,int raw));
8bae0a0c
JSC
494static void SignalException PARAMS((int exception,...));
495static void simulate PARAMS((void));
f7481d45
JSC
496static long getnum PARAMS((char *value));
497extern void sim_size PARAMS((unsigned int newsize));
498extern void sim_set_profile PARAMS((int frequency));
499static unsigned int power2 PARAMS((unsigned int value));
500
501/*---------------------------------------------------------------------------*/
8bae0a0c
JSC
502
503void
504sim_open (args)
505 char *args;
506{
507 if (callback == NULL) {
508 fprintf(stderr,"SIM Error: sim_open() called without callbacks attached\n");
509 return;
510 }
511
512 /* The following ensures that the standard file handles for stdin,
513 stdout and stderr are initialised: */
514 callback->init(callback);
515
516 state = 0;
517 CHECKSIM();
518 if (state & simEXCEPTION) {
519 fprintf(stderr,"This simulator is not suitable for this host configuration\n");
520 exit(1);
521 }
522
523 {
524 int data = 0x12;
525 if (*((char *)&data) != 0x12)
526 state |= simHOSTBE; /* big-endian host */
527 }
528
529#if defined(HASFPU)
530 /* Check that the host FPU conforms to IEEE 754-1985 for the SINGLE
531 and DOUBLE binary formats. This is a bit nasty, requiring that we
532 trust the explicit manifests held in the source: */
533 {
534 unsigned int s[2];
a9f7253f
JSC
535 s[state & simHOSTBE ? 0 : 1] = 0x40805A5A;
536 s[state & simHOSTBE ? 1 : 0] = 0x00000000;
537
538 /* TODO: We need to cope with the simulated target and the host
539 not having the same endianness. This will require the high and
540 low words of a (double) to be swapped when converting between
541 the host and the simulated target. */
542
543 if (((float)4.01102924346923828125 != *(float *)(s + ((state & simHOSTBE) ? 0 : 1))) || ((double)523.2939453125 != *(double *)s)) {
8bae0a0c 544 fprintf(stderr,"The host executing the simulator does not seem to have IEEE 754-1985 std FP\n");
a9f7253f
JSC
545 fprintf(stderr,"*(float *)s = %.20f (4.01102924346923828125)\n",*(float *)s);
546 fprintf(stderr,"*(double *)s = %.20f (523.2939453125)\n",*(double *)s);
8bae0a0c
JSC
547 exit(1);
548 }
549 }
550#endif /* HASFPU */
551
552 /* This is NASTY, in that we are assuming the size of specific
553 registers: */
554 {
555 int rn;
556 for (rn = 0; (rn < (LAST_EMBED_REGNUM + 1)); rn++) {
557 if (rn < 32)
558 register_widths[rn] = GPRLEN;
559 else if ((rn >= FGRIDX) && (rn < (FGRIDX + 32)))
560 register_widths[rn] = GPRLEN;
561 else if ((rn >= 33) && (rn <= 37))
562 register_widths[rn] = GPRLEN;
563 else if ((rn == SRIDX) || (rn == FCR0IDX) || (rn == FCR31IDX) || ((rn >= 72) && (rn <= 89)))
564 register_widths[rn] = 32;
565 else
566 register_widths[rn] = 0;
567 }
568 }
569
570 /* It would be good if we could select particular named MIPS
571 architecture simulators. However, having a pre-built, fixed
572 engine would mean including multiple engines. If the simulator is
573 changed to a run-time conditional version, then the ability to
574 select a particular architecture would be straightforward. */
575 if (args != NULL) {
576 int c;
577 char *cline;
578 char **argv;
579 int argc;
580 static struct option cmdline[] = {
581 {"help", 0,0,'h'},
f24b7b69 582 {"log", 1,0,'l'},
8bae0a0c
JSC
583 {"name", 1,0,'n'},
584 {"profile", 0,0,'p'},
585 {"size", 1,0,'s'},
586 {"trace", 0,0,'t'},
587 {"tracefile",1,0,'z'},
588 {"frequency",1,0,'y'},
589 {"samples", 1,0,'x'},
590 {0, 0,0,0}
591 };
592
593 /* Unfortunately, getopt_long() is designed to be used with
594 vectors, where the first option is normally program name (and
595 ignored). We cheat by creating a dummy first argument, so that
596 we can use the standard argument processing. */
597#define DUMMYARG "simulator "
598 cline = (char *)malloc(strlen(args) + strlen(DUMMYARG) + 1);
599 if (cline == NULL) {
600 fprintf(stderr,"Failed to allocate memory for command line buffer\n");
601 exit(1);
602 }
603 sprintf(cline,"%s%s",DUMMYARG,args);
604 argv = buildargv(cline);
605 for (argc = 0; argv[argc]; argc++);
606
607 /* Unfortunately, getopt_long() assumes that it is ignoring the
608 first argument (normally the program name). This means it
609 ignores the first option on our "args" line. */
610 optind = 0; /* Force reset of argument processing */
611 while (1) {
612 int option_index = 0;
613
614 c = getopt_long(argc,argv,"hn:s:tp",cmdline,&option_index);
615 if (c == -1)
616 break;
617
618 switch (c) {
619 case 'h':
620 callback->printf_filtered(callback,"Usage:\n\t\
f24b7b69 621target sim [-h] [--log=<file>] [--name=<model>] [--size=<amount>]");
8bae0a0c
JSC
622#if defined(TRACE)
623 callback->printf_filtered(callback," [-t [--tracefile=<name>]]");
624#endif /* TRACE */
625#if defined(PROFILE)
626 callback->printf_filtered(callback," [-p [--frequency=<count>] [--samples=<count>]]");
627#endif /* PROFILE */
628 callback->printf_filtered(callback,"\n");
629 break;
630
f24b7b69
JSC
631 case 'l':
632 if (optarg != NULL) {
633 char *tmp;
634 tmp = (char *)malloc(strlen(optarg) + 1);
635 if (tmp == NULL)
636 callback->printf_filtered(callback,"Failed to allocate buffer for logfile name \"%s\"\n",optarg);
637 else {
638 strcpy(tmp,optarg);
639 logfile = tmp;
640 }
641 }
642 break;
643
8bae0a0c
JSC
644 case 'n':
645 callback->printf_filtered(callback,"Explicit model selection not yet available (Ignoring \"%s\")\n",optarg);
646 break;
647
648 case 's':
649 membank_size = (unsigned)getnum(optarg);
650 break;
651
652 case 't':
653#if defined(TRACE)
654 /* Eventually the simTRACE flag could be treated as a toggle, to
655 allow external control of the program points being traced
656 (i.e. only from main onwards, excluding the run-time setup,
657 etc.). */
658 state |= simTRACE;
659#else /* !TRACE */
660 fprintf(stderr,"\
661Simulator constructed without tracing support (for performance).\n\
662Re-compile simulator with \"-DTRACE\" to enable this option.\n");
663#endif /* !TRACE */
664 break;
665
666 case 'z':
667#if defined(TRACE)
668 if (optarg != NULL) {
669 char *tmp;
670 tmp = (char *)malloc(strlen(optarg) + 1);
671 if (tmp == NULL)
672 callback->printf_filtered(callback,"Failed to allocate buffer for tracefile name \"%s\"\n",optarg);
673 else {
674 strcpy(tmp,optarg);
675 tracefile = tmp;
676 callback->printf_filtered(callback,"Placing trace information into file \"%s\"\n",tracefile);
677 }
678 }
679#endif /* TRACE */
680 break;
681
682 case 'p':
683#if defined(PROFILE)
684 state |= simPROFILE;
685#else /* !PROFILE */
686 fprintf(stderr,"\
687Simulator constructed without profiling support (for performance).\n\
688Re-compile simulator with \"-DPROFILE\" to enable this option.\n");
689#endif /* !PROFILE */
690 break;
691
692 case 'x':
693#if defined(PROFILE)
694 profile_nsamples = (unsigned)getnum(optarg);
695#endif /* PROFILE */
696 break;
697
698 case 'y':
699#if defined(PROFILE)
700 sim_set_profile((int)getnum(optarg));
701#endif /* PROFILE */
702 break;
703
704 default:
705 callback->printf_filtered(callback,"Warning: Simulator getopt returned unrecognised code 0x%08X\n",c);
706 case '?':
707 break;
708 }
709 }
710
f24b7b69 711#if 0
8bae0a0c
JSC
712 if (optind < argc) {
713 callback->printf_filtered(callback,"Warning: Ignoring spurious non-option arguments ");
714 while (optind < argc)
715 callback->printf_filtered(callback,"\"%s\" ",argv[optind++]);
716 callback->printf_filtered(callback,"\n");
717 }
f24b7b69 718#endif
8bae0a0c
JSC
719
720 freeargv(argv);
721 }
722
f24b7b69
JSC
723 if (logfile != NULL) {
724 if (strcmp(logfile,"-") == 0)
725 logfh = stdout;
726 else {
727 logfh = fopen(logfile,"wb+");
728 if (logfh == NULL) {
729 callback->printf_filtered(callback,"Failed to create file \"%s\", writing log information to stderr.\n",tracefile);
730 logfh = stderr;
731 }
732 }
733 }
734
8bae0a0c
JSC
735 /* If the host has "mmap" available we could use it to provide a
736 very large virtual address space for the simulator, since memory
737 would only be allocated within the "mmap" space as it is
738 accessed. This can also be linked to the architecture specific
739 support, required to simulate the MMU. */
740 sim_size(membank_size);
741 /* NOTE: The above will also have enabled any profiling state */
742
743 ColdReset();
744 /* If we were providing a more complete I/O, co-processor or memory
745 simulation, we should perform any "device" initialisation at this
746 point. This can include pre-loading memory areas with particular
747 patterns (e.g. simulating ROM monitors). */
748
749 /* We can start writing to the memory, now that the processor has
750 been reset: */
751 monitor = (unsigned char *)calloc(1,monitor_size);
752 if (!monitor) {
753 fprintf(stderr,"Not enough VM for monitor simulation (%d bytes)\n",monitor_size);
754 } else {
755 int loop;
756 /* Entry into the IDT monitor is via fixed address vectors, and
757 not using machine instructions. To avoid clashing with use of
758 the MIPS TRAP system, we place our own (simulator specific)
759 "undefined" instructions into the relevant vector slots. */
760 for (loop = 0; (loop < monitor_size); loop += 4) {
e871dd18
JSC
761 uword64 vaddr = (monitor_base + loop);
762 uword64 paddr;
8bae0a0c
JSC
763 int cca;
764 if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isRAW))
e871dd18 765 StoreMemory(cca,AccessLength_WORD,(RSVD_INSTRUCTION | ((loop >> 2) & RSVD_INSTRUCTION_AMASK)),paddr,vaddr,isRAW);
8bae0a0c 766 }
a9f7253f
JSC
767 /* The PMON monitor uses the same address space, but rather than
768 branching into it the address of a routine is loaded. We can
769 cheat for the moment, and direct the PMON routine to IDT style
770 instructions within the monitor space. This relies on the IDT
771 monitor not using the locations from 0xBFC00500 onwards as its
772 entry points.*/
773 for (loop = 0; (loop < 24); loop++)
774 {
775 uword64 vaddr = (monitor_base + 0x500 + (loop * 4));
776 uword64 paddr;
777 int cca;
778 unsigned int value = ((0x500 - 8) / 8); /* default UNDEFINED reason code */
779 switch (loop)
780 {
781 case 0: /* read */
782 value = 7;
783 break;
784
785 case 1: /* write */
786 value = 8;
787 break;
788
789 case 2: /* open */
790 value = 6;
791 break;
792
793 case 3: /* close */
794 value = 10;
795 break;
796
797 case 5: /* printf */
798 value = ((0x500 - 16) / 8); /* not an IDT reason code */
799 break;
800
801 case 8: /* cliexit */
802 value = 17;
803 break;
804 }
805 value = (monitor_base + (value * 8));
806 if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isRAW))
807 StoreMemory(cca,AccessLength_WORD,value,paddr,vaddr,isRAW);
808 else
f24b7b69 809 sim_error("Failed to write to monitor space 0x%08X%08X",WORD64HI(vaddr),WORD64LO(vaddr));
a9f7253f 810 }
8bae0a0c
JSC
811 }
812
813#if defined(TRACE)
814 if (state & simTRACE) {
815 tracefh = fopen(tracefile,"wb+");
816 if (tracefh == NULL) {
f24b7b69 817 sim_warning("Failed to create file \"%s\", writing trace information to stderr.",tracefile);
8bae0a0c
JSC
818 tracefh = stderr;
819 }
820 }
821#endif /* TRACE */
822
823 return;
824}
825
826/* For the profile writing, we write the data in the host
827 endianness. This unfortunately means we are assuming that the
828 profile file we create is processed on the same host executing the
829 simulator. The gmon.out file format should either have an explicit
830 endianness, or a method of encoding the endianness in the file
831 header. */
832static int
833writeout32(fh,val)
834 FILE *fh;
835 unsigned int val;
836{
837 char buff[4];
838 int res = 1;
839
840 if (state & simHOSTBE) {
841 buff[3] = ((val >> 0) & 0xFF);
842 buff[2] = ((val >> 8) & 0xFF);
843 buff[1] = ((val >> 16) & 0xFF);
844 buff[0] = ((val >> 24) & 0xFF);
845 } else {
846 buff[0] = ((val >> 0) & 0xFF);
847 buff[1] = ((val >> 8) & 0xFF);
848 buff[2] = ((val >> 16) & 0xFF);
849 buff[3] = ((val >> 24) & 0xFF);
850 }
851 if (fwrite(buff,4,1,fh) != 1) {
f24b7b69 852 sim_warning("Failed to write 4bytes to the profile file");
8bae0a0c
JSC
853 res = 0;
854 }
855 return(res);
856}
857
858static int
859writeout16(fh,val)
860 FILE *fh;
861 unsigned short val;
862{
863 char buff[2];
864 int res = 1;
865 if (state & simHOSTBE) {
866 buff[1] = ((val >> 0) & 0xFF);
867 buff[0] = ((val >> 8) & 0xFF);
868 } else {
869 buff[0] = ((val >> 0) & 0xFF);
870 buff[1] = ((val >> 8) & 0xFF);
871 }
872 if (fwrite(buff,2,1,fh) != 1) {
f24b7b69 873 sim_warning("Failed to write 2bytes to the profile file");
8bae0a0c
JSC
874 res = 0;
875 }
876 return(res);
877}
878
879void
880sim_close (quitting)
881 int quitting;
882{
883#ifdef DEBUG
884 printf("DBG: sim_close: entered (quitting = %d)\n",quitting);
885#endif
886
887 /* Cannot assume sim_kill() has been called */
888 /* "quitting" is non-zero if we cannot hang on errors */
889
890 /* Ensure that any resources allocated through the callback
891 mechanism are released: */
892 callback->shutdown(callback);
893
894#if defined(PROFILE)
895 if ((state & simPROFILE) && (profile_hist != NULL)) {
896 unsigned short *p = profile_hist;
897 FILE *pf = fopen("gmon.out","wb");
898 int loop;
899
900 if (pf == NULL)
f24b7b69 901 sim_warning("Failed to open \"gmon.out\" profile file");
8bae0a0c
JSC
902 else {
903 int ok;
904#ifdef DEBUG
905 printf("DBG: minpc = 0x%08X\n",(unsigned int)profile_minpc);
906 printf("DBG: maxpc = 0x%08X\n",(unsigned int)profile_maxpc);
907#endif /* DEBUG */
908 ok = writeout32(pf,(unsigned int)profile_minpc);
909 if (ok)
910 ok = writeout32(pf,(unsigned int)profile_maxpc);
911 if (ok)
912 ok = writeout32(pf,(profile_nsamples * 2) + 12); /* size of sample buffer (+ header) */
913#ifdef DEBUG
914 printf("DBG: nsamples = %d (size = 0x%08X)\n",profile_nsamples,((profile_nsamples * 2) + 12));
915#endif /* DEBUG */
916 for (loop = 0; (ok && (loop < profile_nsamples)); loop++) {
917 ok = writeout16(pf,profile_hist[loop]);
918 if (!ok)
919 break;
920 }
921
922 fclose(pf);
923 }
924
925 free(profile_hist);
926 profile_hist = NULL;
927 state &= ~simPROFILE;
928 }
929#endif /* PROFILE */
930
931#if defined(TRACE)
932 if (tracefh != stderr)
933 fclose(tracefh);
934 state &= ~simTRACE;
935#endif /* TRACE */
936
f24b7b69
JSC
937 if (logfh != NULL && logfh != stdout && logfh != stderr)
938 fclose(logfh);
939 logfh = NULL;
940
8bae0a0c 941 if (membank)
d0757082 942 free(membank); /* cfree not available on all hosts */
8bae0a0c
JSC
943 membank = NULL;
944
945 return;
946}
947
948void
949sim_resume (step,signal)
950 int step, signal;
951{
952#ifdef DEBUG
953 printf("DBG: sim_resume entered: step = %d, signal = %d (membank = 0x%08X)\n",step,signal,membank);
954#endif /* DEBUG */
955
956 if (step)
957 state |= simSTEP; /* execute only a single instruction */
958 else
959 state &= ~(simSTOP | simSTEP); /* execute until event */
960
961 state |= (simHALTEX | simHALTIN); /* treat interrupt event as exception */
962
963 /* Start executing instructions from the current state (set
964 explicitly by register updates, or by sim_create_inferior): */
965
966 simulate();
967 return;
968}
969
970int
971sim_write (addr,buffer,size)
972 SIM_ADDR addr;
973 unsigned char *buffer;
974 int size;
975{
976 int index = size;
e871dd18 977 uword64 vaddr = (uword64)addr;
8bae0a0c
JSC
978
979 /* Return the number of bytes written, or zero if error. */
980#ifdef DEBUG
e871dd18 981 callback->printf_filtered(callback,"sim_write(0x%08X%08X,buffer,%d);\n",WORD64HI(addr),WORD64LO(addr),size);
8bae0a0c
JSC
982#endif
983
984 /* We provide raw read and write routines, since we do not want to
985 count the GDB memory accesses in our statistics gathering. */
986
987 /* There is a lot of code duplication in the individual blocks
988 below, but the variables are declared locally to a block to give
989 the optimiser the best chance of improving the code. We have to
990 perform slow byte reads from the host memory, to ensure that we
991 get the data into the correct endianness for the (simulated)
992 target memory world. */
993
994 /* Mask count to get odd byte, odd halfword, and odd word out of the
995 way. We can then perform doubleword transfers to and from the
996 simulator memory for optimum performance. */
997 if (index && (index & 1)) {
e871dd18 998 uword64 paddr;
8bae0a0c
JSC
999 int cca;
1000 if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isRAW)) {
e871dd18 1001 uword64 value = ((uword64)(*buffer++));
8bae0a0c
JSC
1002 StoreMemory(cca,AccessLength_BYTE,value,paddr,vaddr,isRAW);
1003 }
1004 vaddr++;
1005 index &= ~1; /* logical operations usually quicker than arithmetic on RISC systems */
1006 }
1007 if (index && (index & 2)) {
e871dd18 1008 uword64 paddr;
8bae0a0c
JSC
1009 int cca;
1010 if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isRAW)) {
e871dd18 1011 uword64 value;
8bae0a0c
JSC
1012 /* We need to perform the following magic to ensure that that
1013 bytes are written into same byte positions in the target memory
1014 world, regardless of the endianness of the host. */
1015 if (BigEndianMem) {
e871dd18
JSC
1016 value = ((uword64)(*buffer++) << 8);
1017 value |= ((uword64)(*buffer++) << 0);
8bae0a0c 1018 } else {
e871dd18
JSC
1019 value = ((uword64)(*buffer++) << 0);
1020 value |= ((uword64)(*buffer++) << 8);
8bae0a0c
JSC
1021 }
1022 StoreMemory(cca,AccessLength_HALFWORD,value,paddr,vaddr,isRAW);
1023 }
1024 vaddr += 2;
1025 index &= ~2;
1026 }
1027 if (index && (index & 4)) {
e871dd18 1028 uword64 paddr;
8bae0a0c
JSC
1029 int cca;
1030 if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isRAW)) {
e871dd18 1031 uword64 value;
8bae0a0c 1032 if (BigEndianMem) {
e871dd18
JSC
1033 value = ((uword64)(*buffer++) << 24);
1034 value |= ((uword64)(*buffer++) << 16);
1035 value |= ((uword64)(*buffer++) << 8);
1036 value |= ((uword64)(*buffer++) << 0);
8bae0a0c 1037 } else {
e871dd18
JSC
1038 value = ((uword64)(*buffer++) << 0);
1039 value |= ((uword64)(*buffer++) << 8);
1040 value |= ((uword64)(*buffer++) << 16);
1041 value |= ((uword64)(*buffer++) << 24);
8bae0a0c
JSC
1042 }
1043 StoreMemory(cca,AccessLength_WORD,value,paddr,vaddr,isRAW);
1044 }
1045 vaddr += 4;
1046 index &= ~4;
1047 }
1048 for (;index; index -= 8) {
e871dd18 1049 uword64 paddr;
8bae0a0c
JSC
1050 int cca;
1051 if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isRAW)) {
e871dd18 1052 uword64 value;
8bae0a0c 1053 if (BigEndianMem) {
e871dd18
JSC
1054 value = ((uword64)(*buffer++) << 56);
1055 value |= ((uword64)(*buffer++) << 48);
1056 value |= ((uword64)(*buffer++) << 40);
1057 value |= ((uword64)(*buffer++) << 32);
1058 value |= ((uword64)(*buffer++) << 24);
1059 value |= ((uword64)(*buffer++) << 16);
1060 value |= ((uword64)(*buffer++) << 8);
1061 value |= ((uword64)(*buffer++) << 0);
8bae0a0c 1062 } else {
e871dd18
JSC
1063 value = ((uword64)(*buffer++) << 0);
1064 value |= ((uword64)(*buffer++) << 8);
1065 value |= ((uword64)(*buffer++) << 16);
1066 value |= ((uword64)(*buffer++) << 24);
1067 value |= ((uword64)(*buffer++) << 32);
1068 value |= ((uword64)(*buffer++) << 40);
1069 value |= ((uword64)(*buffer++) << 48);
1070 value |= ((uword64)(*buffer++) << 56);
8bae0a0c
JSC
1071 }
1072 StoreMemory(cca,AccessLength_DOUBLEWORD,value,paddr,vaddr,isRAW);
1073 }
1074 vaddr += 8;
1075 }
1076
1077 return(size);
1078}
1079
1080int
1081sim_read (addr,buffer,size)
1082 SIM_ADDR addr;
1083 unsigned char *buffer;
1084 int size;
1085{
1086 int index;
1087
1088 /* Return the number of bytes read, or zero if error. */
1089#ifdef DEBUG
e871dd18 1090 callback->printf_filtered(callback,"sim_read(0x%08X%08X,buffer,%d);\n",WORD64HI(addr),WORD64LO(addr),size);
8bae0a0c
JSC
1091#endif /* DEBUG */
1092
1093 /* TODO: Perform same optimisation as the sim_write() code
1094 above. NOTE: This will require a bit more work since we will need
1095 to ensure that the source physical address is doubleword aligned
1096 before, and then deal with trailing bytes. */
1097 for (index = 0; (index < size); index++) {
e871dd18 1098 uword64 vaddr,paddr,value;
8bae0a0c 1099 int cca;
e871dd18 1100 vaddr = (uword64)addr + index;
8bae0a0c
JSC
1101 if (AddressTranslation(vaddr,isDATA,isLOAD,&paddr,&cca,isTARGET,isRAW)) {
1102 value = LoadMemory(cca,AccessLength_BYTE,paddr,vaddr,isDATA,isRAW);
1103 buffer[index] = (unsigned char)(value&0xFF);
1104 } else
1105 break;
1106 }
1107
1108 return(index);
1109}
1110
1111void
1112sim_store_register (rn,memory)
1113 int rn;
1114 unsigned char *memory;
1115{
1116#ifdef DEBUG
1117 callback->printf_filtered(callback,"sim_store_register(%d,*memory=0x%08X%08X);\n",rn,*((unsigned int *)memory),*((unsigned int *)(memory + 4)));
1118#endif /* DEBUG */
1119
1120 /* Unfortunately this suffers from the same problem as the register
1121 numbering one. We need to know what the width of each logical
1122 register number is for the architecture being simulated. */
1123 if (register_widths[rn] == 0)
f24b7b69 1124 sim_warning("Invalid register width for %d (register store ignored)",rn);
8bae0a0c
JSC
1125 else {
1126 if (register_widths[rn] == 32)
f7481d45 1127 registers[rn] = host_read_word(memory);
8bae0a0c 1128 else
f7481d45 1129 registers[rn] = host_read_long(memory);
8bae0a0c
JSC
1130 }
1131
1132 return;
1133}
1134
1135void
1136sim_fetch_register (rn,memory)
1137 int rn;
1138 unsigned char *memory;
1139{
1140#ifdef DEBUG
e871dd18 1141 callback->printf_filtered(callback,"sim_fetch_register(%d=0x%08X%08X,mem) : place simulator registers into memory\n",rn,WORD64HI(registers[rn]),WORD64LO(registers[rn]));
8bae0a0c
JSC
1142#endif /* DEBUG */
1143
1144 if (register_widths[rn] == 0)
f24b7b69 1145 sim_warning("Invalid register width for %d (register fetch ignored)",rn);
8bae0a0c
JSC
1146 else {
1147 if (register_widths[rn] == 32)
f7481d45 1148 *((unsigned int *)memory) = host_swap_word(registers[rn] & 0xFFFFFFFF);
8bae0a0c 1149 else /* 64bit register */
f7481d45 1150 *((uword64 *)memory) = host_swap_long(registers[rn]);
8bae0a0c
JSC
1151 }
1152 return;
1153}
1154
1155void
1156sim_stop_reason (reason,sigrc)
1157 enum sim_stop *reason;
1158 int *sigrc;
1159{
1160/* We can have "*reason = {sim_exited, sim_stopped, sim_signalled}", so
1161 sim_exited *sigrc = argument to exit()
1162 sim_stopped *sigrc = exception number
1163 sim_signalled *sigrc = signal number
1164*/
1165 if (state & simEXCEPTION) {
1166 /* If "sim_signalled" is used, GDB expects normal SIGNAL numbers,
1167 and not the MIPS specific exception codes. */
1168#if 1
1169 /* For some reason, sending GDB a sim_signalled reason cause it to
1170 terminate out. */
1171 *reason = sim_stopped;
1172#else
1173 *reason = sim_signalled;
1174#endif
1175 switch ((CAUSE >> 2) & 0x1F) {
1176 case Interrupt:
1177 *sigrc = SIGINT; /* wrong type of interrupt, but it will do for the moment */
1178 break;
1179
1180 case TLBModification:
1181 case TLBLoad:
1182 case TLBStore:
1183 case AddressLoad:
1184 case AddressStore:
1185 case InstructionFetch:
1186 case DataReference:
1187 *sigrc = SIGBUS;
1188 break;
1189
1190 case ReservedInstruction:
1191 case CoProcessorUnusable:
1192 *sigrc = SIGILL;
1193 break;
1194
1195 case IntegerOverflow:
1196 case FPE:
1197 *sigrc = SIGFPE;
1198 break;
1199
1200 case Trap:
1201 case Watch:
1202 case SystemCall:
1203 case BreakPoint:
1204 *sigrc = SIGTRAP;
1205 break;
1206
1207 default : /* Unknown internal exception */
1208 *sigrc = SIGQUIT;
1209 break;
1210 }
1211 } else if (state & simEXIT) {
f24b7b69 1212#if 0
8bae0a0c 1213 printf("DBG: simEXIT (%d)\n",rcexit);
f24b7b69 1214#endif
8bae0a0c
JSC
1215 *reason = sim_exited;
1216 *sigrc = rcexit;
1217 } else { /* assume single-stepping */
1218 *reason = sim_stopped;
1219 *sigrc = SIGTRAP;
1220 }
1221 state &= ~(simEXCEPTION | simEXIT);
1222 return;
1223}
1224
1225void
1226sim_info (verbose)
1227 int verbose;
1228{
1229 /* Accessed from the GDB "info files" command: */
1230
1231 callback->printf_filtered(callback,"MIPS %d-bit simulator\n",(PROCESSOR_64BIT ? 64 : 32));
1232
1233 callback->printf_filtered(callback,"%s endian memory model\n",(BigEndianMem ? "Big" : "Little"));
1234
e871dd18 1235 callback->printf_filtered(callback,"0x%08X bytes of memory at 0x%08X%08X\n",(unsigned int)membank_size,WORD64HI(membank_base),WORD64LO(membank_base));
8bae0a0c
JSC
1236
1237#if !defined(FASTSIM)
a9f7253f
JSC
1238 if (instruction_fetch_overflow != 0)
1239 callback->printf_filtered(callback,"Instruction fetches = 0x%08X%08X\n",instruction_fetch_overflow,instruction_fetches);
1240 else
1241 callback->printf_filtered(callback,"Instruction fetches = %d\n",instruction_fetches);
8bae0a0c
JSC
1242 callback->printf_filtered(callback,"Pipeline ticks = %d\n",pipeline_ticks);
1243 /* It would be a useful feature, if when performing multi-cycle
1244 simulations (rather than single-stepping) we keep the start and
1245 end times of the execution, so that we can give a performance
1246 figure for the simulator. */
1247#endif /* !FASTSIM */
1248
1249 /* print information pertaining to MIPS ISA and architecture being simulated */
1250 /* things that may be interesting */
1251 /* instructions executed - if available */
1252 /* cycles executed - if available */
1253 /* pipeline stalls - if available */
1254 /* virtual time taken */
1255 /* profiling size */
1256 /* profiling frequency */
1257 /* profile minpc */
1258 /* profile maxpc */
1259
1260 return;
1261}
1262
1263int
1264sim_load (prog,from_tty)
1265 char *prog;
1266 int from_tty;
1267{
1268 /* Return non-zero if the caller should handle the load. Zero if
1269 we have loaded the image. */
1270 return(-1);
1271}
1272
1273void
1274sim_create_inferior (start_address,argv,env)
1275 SIM_ADDR start_address;
1276 char **argv;
1277 char **env;
1278{
1279#ifdef DEBUG
1280 printf("DBG: sim_create_inferior entered: start_address = 0x%08X\n",start_address);
1281#endif /* DEBUG */
1282
1283 /* Prepare to execute the program to be simulated */
1284 /* argv and env are NULL terminated lists of pointers */
1285
1286#if 1
e871dd18 1287 PC = (uword64)start_address;
8bae0a0c
JSC
1288#else
1289 /* TODO: Sort this properly. SIM_ADDR may already be a 64bit value: */
1290 PC = SIGNEXTEND(start_address,32);
1291#endif
1292 /* NOTE: GDB normally sets the PC explicitly. However, this call is
1293 used by other clients of the simulator. */
1294
1295 if (argv || env) {
f24b7b69 1296#if 0 /* def DEBUG */
8bae0a0c 1297 callback->printf_filtered(callback,"sim_create_inferior() : passed arguments ignored\n");
8bae0a0c
JSC
1298 {
1299 char **cptr;
1300 for (cptr = argv; (cptr && *cptr); cptr++)
1301 printf("DBG: arg \"%s\"\n",*cptr);
1302 }
1303#endif /* DEBUG */
1304 /* We should really place the argv slot values into the argument
1305 registers, and onto the stack as required. However, this
1306 assumes that we have a stack defined, which is not necessarily
1307 true at the moment. */
1308 }
1309
1310 return;
1311}
1312
1313void
1314sim_kill ()
1315{
1316#if 1
1317 /* This routine should be for terminating any existing simulation
1318 thread. Since we are single-threaded only at the moment, this is
1319 not an issue. It should *NOT* be used to terminate the
1320 simulator. */
1321#else /* do *NOT* call sim_close */
1322 sim_close(1); /* Do not hang on errors */
1323 /* This would also be the point where any memory mapped areas used
1324 by the simulator should be released. */
1325#endif
1326 return;
1327}
1328
1329int
1330sim_get_quit_code ()
1331{
1332 /* The standard MIPS PCS (Procedure Calling Standard) uses V0(r2) as
1333 the function return value. However, it may be more correct for
1334 this to return the argument to the exit() function (if
1335 called). */
1336 return(V0);
1337}
1338
1339void
1340sim_set_callbacks (p)
1341 host_callback *p;
1342{
1343 callback = p;
1344 return;
1345}
1346
1347typedef enum {e_terminate,e_help,e_setmemsize,e_reset} e_cmds;
1348
1349static struct t_sim_command {
1350 e_cmds id;
1351 const char *name;
1352 const char *help;
1353} sim_commands[] = {
1354 {e_help, "help", ": Show MIPS simulator private commands"},
1355 {e_setmemsize,"set-memory-size","<n> : Specify amount of memory simulated"},
1356 {e_reset, "reset-system", ": Reset the simulated processor"},
1357 {e_terminate, NULL}
1358};
1359
1360void
1361sim_do_command (cmd)
1362 char *cmd;
1363{
1364 struct t_sim_command *cptr;
1365
8b554809
JSC
1366 if (callback == NULL) {
1367 fprintf(stderr,"Simulator not enabled: \"target sim\" should be used to activate\n");
1368 return;
1369 }
1370
8bae0a0c
JSC
1371 if (!(cmd && *cmd != '\0'))
1372 cmd = "help";
1373
1374 /* NOTE: Accessed from the GDB "sim" commmand: */
1375 for (cptr = sim_commands; cptr && cptr->name; cptr++)
1376 if (strncmp(cmd,cptr->name,strlen(cptr->name)) == 0) {
1377 cmd += strlen(cptr->name);
1378 switch (cptr->id) {
1379 case e_help: /* no arguments */
1380 { /* no arguments */
1381 struct t_sim_command *lptr;
1382 callback->printf_filtered(callback,"List of MIPS simulator commands:\n");
1383 for (lptr = sim_commands; lptr->name; lptr++)
1384 callback->printf_filtered(callback,"%s %s\n",lptr->name,lptr->help);
1385 }
1386 break;
1387
1388 case e_setmemsize: /* memory size argument */
1389 {
1390 unsigned int newsize = (unsigned int)getnum(cmd);
1391 sim_size(newsize);
1392 }
1393 break;
1394
1395 case e_reset: /* no arguments */
1396 ColdReset();
1397 /* NOTE: See the comments in sim_open() relating to device
1398 initialisation. */
1399 break;
1400
1401 default:
1402 callback->printf_filtered(callback,"FATAL: Matched \"%s\", but failed to match command id %d.\n",cmd,cptr->id);
1403 break;
1404 }
1405 break;
1406 }
1407
1408 if (!(cptr->name))
1409 callback->printf_filtered(callback,"Error: \"%s\" is not a valid MIPS simulator command.\n",cmd);
1410
1411 return;
1412}
1413
1414/*---------------------------------------------------------------------------*/
1415/* NOTE: The following routines do not seem to be used by GDB at the
1416 moment. However, they may be useful to the standalone simulator
1417 world. */
1418
1419
1420/* The profiling format is described in the "gmon_out.h" header file */
1421void
1422sim_set_profile (n)
1423 int n;
1424{
1425#if defined(PROFILE)
1426 profile_frequency = n;
1427 state |= simPROFILE;
1428#endif /* PROFILE */
1429 return;
1430}
1431
1432void
1433sim_set_profile_size (n)
1434 int n;
1435{
1436#if defined(PROFILE)
1437 if (state & simPROFILE) {
1438 int bsize;
1439
1440 /* Since we KNOW that the memory banks are a power-of-2 in size: */
1441 profile_nsamples = power2(n);
1442 profile_minpc = membank_base;
1443 profile_maxpc = (membank_base + membank_size);
1444
1445 /* Just in-case we are sampling every address: NOTE: The shift
1446 right of 2 is because we only have word-aligned PC addresses. */
1447 if (profile_nsamples > (membank_size >> 2))
1448 profile_nsamples = (membank_size >> 2);
1449
1450 /* Since we are dealing with power-of-2 values: */
1451 profile_shift = (((membank_size >> 2) / profile_nsamples) - 1);
1452
1453 bsize = (profile_nsamples * sizeof(unsigned short));
1454 if (profile_hist == NULL)
1455 profile_hist = (unsigned short *)calloc(64,(bsize / 64));
1456 else
1457 profile_hist = (unsigned short *)realloc(profile_hist,bsize);
1458 if (profile_hist == NULL) {
f24b7b69 1459 sim_warning("Failed to allocate VM for profiling buffer (0x%08X bytes)",bsize);
8bae0a0c
JSC
1460 state &= ~simPROFILE;
1461 }
1462 }
1463#endif /* PROFILE */
1464
1465 return;
1466}
1467
1468void
1469sim_size(newsize)
1470 unsigned int newsize;
1471{
1472 char *new;
1473 /* Used by "run", and internally, to set the simulated memory size */
f24b7b69
JSC
1474 if (newsize == 0) {
1475 callback->printf_filtered(callback,"Zero not valid: Memory size still 0x%08X bytes\n",membank_size);
1476 return;
1477 }
8bae0a0c
JSC
1478 newsize = power2(newsize);
1479 if (membank == NULL)
1480 new = (char *)calloc(64,(membank_size / 64));
1481 else
1482 new = (char *)realloc(membank,newsize);
1483 if (new == NULL) {
1484 if (membank == NULL)
f24b7b69 1485 sim_error("Not enough VM for simulation memory of 0x%08X bytes",membank_size);
8bae0a0c 1486 else
f24b7b69 1487 sim_warning("Failed to resize memory (still 0x%08X bytes)",membank_size);
8bae0a0c
JSC
1488 } else {
1489 membank_size = (unsigned)newsize;
1490 membank = new;
8bae0a0c
JSC
1491#if defined(PROFILE)
1492 /* Ensure that we sample across the new memory range */
1493 sim_set_profile_size(profile_nsamples);
1494#endif /* PROFILE */
1495 }
1496
1497 return;
1498}
1499
1500int
1501sim_trace()
1502{
1503 /* This routine is called by the "run" program, when detailed
1504 execution information is required. Rather than executing a single
1505 instruction, and looping around externally... we just start
1506 simulating, returning TRUE when the simulator stops (for whatever
1507 reason). */
1508
1509#if defined(TRACE)
1510 /* Ensure tracing is enabled, if available */
1511 if (tracefh != NULL)
1512 state |= simTRACE;
1513#endif /* TRACE */
1514
1515 state &= ~(simSTOP | simSTEP); /* execute until event */
1516 state |= (simHALTEX | simHALTIN); /* treat interrupt event as exception */
1517 /* Start executing instructions from the current state (set
1518 explicitly by register updates, or by sim_create_inferior): */
1519 simulate();
1520
1521 return(1);
1522}
1523
1524/*---------------------------------------------------------------------------*/
1525/*-- Private simulator support interface ------------------------------------*/
1526/*---------------------------------------------------------------------------*/
1527
a9f7253f 1528/* Simple monitor interface (currently setup for the IDT and PMON monitors) */
8bae0a0c
JSC
1529static void
1530sim_monitor(reason)
1531 unsigned int reason;
1532{
1533 /* The IDT monitor actually allows two instructions per vector
1534 slot. However, the simulator currently causes a trap on each
1535 individual instruction. We cheat, and lose the bottom bit. */
1536 reason >>= 1;
1537
1538 /* The following callback functions are available, however the
1539 monitor we are simulating does not make use of them: get_errno,
1540 isatty, lseek, rename, system, time and unlink */
1541 switch (reason) {
1542 case 6: /* int open(char *path,int flags) */
1543 {
1544 const char *ptr;
e871dd18 1545 uword64 paddr;
8bae0a0c
JSC
1546 int cca;
1547 if (AddressTranslation(A0,isDATA,isLOAD,&paddr,&cca,isHOST,isREAL))
1548 V0 = callback->open(callback,(char *)((int)paddr),(int)A1);
1549 else
f24b7b69 1550 sim_error("Attempt to pass pointer that does not reference simulated memory");
8bae0a0c
JSC
1551 }
1552 break;
1553
1554 case 7: /* int read(int file,char *ptr,int len) */
1555 {
1556 const char *ptr;
e871dd18 1557 uword64 paddr;
8bae0a0c
JSC
1558 int cca;
1559 if (AddressTranslation(A1,isDATA,isLOAD,&paddr,&cca,isHOST,isREAL))
1560 V0 = callback->read(callback,(int)A0,(char *)((int)paddr),(int)A2);
1561 else
f24b7b69 1562 sim_error("Attempt to pass pointer that does not reference simulated memory");
8bae0a0c
JSC
1563 }
1564 break;
1565
1566 case 8: /* int write(int file,char *ptr,int len) */
1567 {
1568 const char *ptr;
e871dd18 1569 uword64 paddr;
8bae0a0c
JSC
1570 int cca;
1571 if (AddressTranslation(A1,isDATA,isLOAD,&paddr,&cca,isHOST,isREAL))
1572 V0 = callback->write(callback,(int)A0,(const char *)((int)paddr),(int)A2);
1573 else
f24b7b69 1574 sim_error("Attempt to pass pointer that does not reference simulated memory");
8bae0a0c
JSC
1575 }
1576 break;
1577
1578 case 10: /* int close(int file) */
1579 V0 = callback->close(callback,(int)A0);
1580 break;
1581
1582 case 11: /* char inbyte(void) */
1583 {
1584 char tmp;
1585 if (callback->read_stdin(callback,&tmp,sizeof(char)) != sizeof(char)) {
f24b7b69 1586 sim_error("Invalid return from character read");
8bae0a0c
JSC
1587 V0 = -1;
1588 }
1589 else
1590 V0 = tmp;
1591 }
1592 break;
1593
1594 case 12: /* void outbyte(char chr) : write a byte to "stdout" */
1595 {
1596 char tmp = (char)(A0 & 0xFF);
1597 callback->write_stdout(callback,&tmp,sizeof(char));
1598 }
1599 break;
1600
1601 case 17: /* void _exit() */
f24b7b69 1602 sim_warning("sim_monitor(17): _exit(int reason) to be coded");
8bae0a0c
JSC
1603 state |= (simSTOP | simEXIT); /* stop executing code */
1604 rcexit = (unsigned int)(A0 & 0xFFFFFFFF);
1605 break;
1606
1607 case 55: /* void get_mem_info(unsigned int *ptr) */
1608 /* in: A0 = pointer to three word memory location */
1609 /* out: [A0 + 0] = size */
1610 /* [A0 + 4] = instruction cache size */
1611 /* [A0 + 8] = data cache size */
1612 {
e871dd18
JSC
1613 uword64 vaddr = A0;
1614 uword64 paddr, value;
8bae0a0c
JSC
1615 int cca;
1616 int failed = 0;
1617
1618 /* NOTE: We use RAW memory writes here, but since we are not
1619 gathering statistics for the monitor calls we are simulating,
1620 it is not an issue. */
1621
1622 /* Memory size */
1623 if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isREAL)) {
e871dd18 1624 value = (uword64)membank_size;
8bae0a0c
JSC
1625 StoreMemory(cca,AccessLength_WORD,value,paddr,vaddr,isRAW);
1626 /* We re-do the address translations, in-case the block
1627 overlaps a memory boundary: */
1628 value = 0;
1629 vaddr += (AccessLength_WORD + 1);
1630 if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isREAL)) {
1631 StoreMemory(cca,AccessLength_WORD,value,paddr,vaddr,isRAW);
1632 vaddr += (AccessLength_WORD + 1);
1633 if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isREAL))
1634 StoreMemory(cca,AccessLength_WORD,value,paddr,vaddr,isRAW);
1635 else
1636 failed = -1;
1637 } else
1638 failed = -1;
1639 } else
1640 failed = -1;
1641
1642 if (failed)
f24b7b69 1643 sim_error("Invalid pointer passed into monitor call");
8bae0a0c
JSC
1644 }
1645 break;
1646
a9f7253f
JSC
1647 case 158 : /* PMON printf */
1648 /* in: A0 = pointer to format string */
1649 /* A1 = optional argument 1 */
1650 /* A2 = optional argument 2 */
1651 /* A3 = optional argument 3 */
1652 /* out: void */
f24b7b69 1653 /* The following is based on the PMON printf source */
a9f7253f
JSC
1654 {
1655 uword64 paddr;
1656 int cca;
f24b7b69
JSC
1657 /* This isn't the quickest way, since we call the host print
1658 routine for every character almost. But it does avoid
1659 having to allocate and manage a temporary string buffer. */
1660 if (AddressTranslation(A0,isDATA,isLOAD,&paddr,&cca,isHOST,isREAL)) {
1661 char *s = (char *)((int)paddr);
1662 ut_reg *ap = &A1; /* 1st argument */
1663 /* TODO: Include check that we only use three arguments (A1, A2 and A3) */
1664 for (; *s;) {
1665 if (*s == '%') {
1666 char tmp[40];
1667 enum {FMT_RJUST, FMT_LJUST, FMT_RJUST0, FMT_CENTER} fmt = FMT_RJUST;
1668 int width = 0, trunc = 0, haddot = 0, longlong = 0;
1669 int base = 10;
1670 s++;
1671 for (; *s; s++) {
1672 if (strchr ("dobxXulscefg%", *s))
1673 break;
1674 else if (*s == '-')
1675 fmt = FMT_LJUST;
1676 else if (*s == '0')
1677 fmt = FMT_RJUST0;
1678 else if (*s == '~')
1679 fmt = FMT_CENTER;
1680 else if (*s == '*') {
1681 if (haddot)
1682 trunc = (int)*ap++;
1683 else
1684 width = (int)*ap++;
1685 } else if (*s >= '1' && *s <= '9') {
1686 char *t;
1687 unsigned int n;
1688 for (t = s; isdigit (*s); s++);
1689 strncpy (tmp, t, s - t);
1690 tmp[s - t] = '\0';
1691 n = (unsigned int)strtol(tmp,NULL,10);
1692 if (haddot)
1693 trunc = n;
1694 else
1695 width = n;
1696 s--;
1697 } else if (*s == '.')
1698 haddot = 1;
1699 }
1700 if (*s == '%') {
1701 callback->printf_filtered(callback,"%%");
1702 } else if (*s == 's') {
1703 if ((int)*ap != 0) {
1704 if (AddressTranslation(*ap++,isDATA,isLOAD,&paddr,&cca,isHOST,isREAL)) {
1705 char *p = (char *)((int)paddr);;
1706 callback->printf_filtered(callback,p);
1707 } else {
1708 ap++;
1709 sim_error("Attempt to pass pointer that does not reference simulated memory");
1710 }
1711 }
1712 else
1713 callback->printf_filtered(callback,"(null)");
1714 } else if (*s == 'c') {
1715 int n = (int)*ap++;
1716 callback->printf_filtered(callback,"%c",n);
1717 } else {
1718 if (*s == 'l') {
1719 if (*++s == 'l') {
1720 longlong = 1;
1721 ++s;
1722 }
1723 }
1724 if (strchr ("dobxXu", *s)) {
1725 long long lv = (long long)*ap++;
1726 if (*s == 'b')
1727 callback->printf_filtered(callback,"<binary not supported>");
1728 else {
1729 sprintf(tmp,"%%%s%c",longlong ? "ll" : "",*s);
1730 if (longlong)
1731 callback->printf_filtered(callback,tmp,lv);
1732 else
1733 callback->printf_filtered(callback,tmp,(int)lv);
1734 }
1735 } else if (strchr ("eEfgG", *s)) {
1736 double dbl = (double)*ap++;
1737 sprintf(tmp,"%%%d.%d%c",width,trunc,*s);
1738 callback->printf_filtered(callback,tmp,dbl);
1739 trunc = 0;
1740 }
1741 }
1742 s++;
1743 } else
1744 callback->printf_filtered(callback,"%c",*s++);
1745 }
1746 } else
1747 sim_error("Attempt to pass pointer that does not reference simulated memory");
a9f7253f
JSC
1748 }
1749 break;
1750
8bae0a0c 1751 default:
f24b7b69
JSC
1752 sim_warning("TODO: sim_monitor(%d) : PC = 0x%08X%08X",reason,WORD64HI(IPC),WORD64LO(IPC));
1753 sim_warning("(Arguments : A0 = 0x%08X%08X : A1 = 0x%08X%08X : A2 = 0x%08X%08X : A3 = 0x%08X%08X)",WORD64HI(A0),WORD64LO(A0),WORD64HI(A1),WORD64LO(A1),WORD64HI(A2),WORD64LO(A2),WORD64HI(A3),WORD64LO(A3));
8bae0a0c
JSC
1754 break;
1755 }
1756 return;
1757}
1758
f24b7b69
JSC
1759void
1760sim_warning(fmt)
1761 char *fmt;
1762{
1763 va_list ap;
1764 va_start(ap,fmt);
1765 if (logfh != NULL) {
1766#if 1
1767 fprintf(logfh,"SIM Warning: ");
1768 fprintf(logfh,fmt,ap);
1769 fprintf(logfh,"\n");
1770#else /* we should provide a method of routing log messages to the simulator output stream */
1771 callback->printf_filtered(callback,"SIM Warning: ");
1772 callback->printf_filtered(callback,fmt,ap);
1773#endif
1774 }
1775 va_end(ap);
1776 SignalException(SimulatorFault,"");
1777 return;
1778}
1779
8bae0a0c
JSC
1780void
1781sim_error(fmt)
1782 char *fmt;
1783{
1784 va_list ap;
1785 va_start(ap,fmt);
1786 callback->printf_filtered(callback,"SIM Error: ");
1787 callback->printf_filtered(callback,fmt,ap);
1788 va_end(ap);
1789 SignalException(SimulatorFault,"");
1790 return;
1791}
1792
1793static unsigned int
1794power2(value)
1795 unsigned int value;
1796{
1797 int loop,tmp;
1798
1799 /* Round *UP* to the nearest power-of-2 if not already one */
1800 if (value != (value & ~(value - 1))) {
1801 for (tmp = value, loop = 0; (tmp != 0); loop++)
1802 tmp >>= 1;
1803 value = (1 << loop);
1804 }
1805
1806 return(value);
1807}
1808
1809static long
1810getnum(value)
1811 char *value;
1812{
1813 long num;
1814 char *end;
1815
1816 num = strtol(value,&end,10);
1817 if (end == value)
1818 callback->printf_filtered(callback,"Warning: Invalid number \"%s\" ignored, using zero\n",value);
1819 else {
1820 if (*end && ((tolower(*end) == 'k') || (tolower(*end) == 'm'))) {
1821 if (tolower(*end) == 'k')
1822 num *= (1 << 10);
1823 else
1824 num *= (1 << 20);
1825 end++;
1826 }
1827 if (*end)
1828 callback->printf_filtered(callback,"Warning: Spurious characters \"%s\" at end of number ignored\n",end);
1829 }
1830
1831 return(num);
1832}
1833
1834/*-- trace support ----------------------------------------------------------*/
1835
1836/* The TRACE support is provided (if required) in the memory accessing
1837 routines. Since we are also providing the architecture specific
1838 features, the architecture simulation code can also deal with
1839 notifying the TRACE world of cache flushes, etc. Similarly we do
1840 not need to provide profiling support in the simulator engine,
1841 since we can sample in the instruction fetch control loop. By
1842 defining the TRACE manifest, we add tracing as a run-time
1843 option. */
1844
1845#if defined(TRACE)
1846/* Tracing by default produces "din" format (as required by
1847 dineroIII). Each line of such a trace file *MUST* have a din label
1848 and address field. The rest of the line is ignored, so comments can
1849 be included if desired. The first field is the label which must be
1850 one of the following values:
1851
1852 0 read data
1853 1 write data
1854 2 instruction fetch
1855 3 escape record (treated as unknown access type)
1856 4 escape record (causes cache flush)
1857
1858 The address field is a 32bit (lower-case) hexadecimal address
1859 value. The address should *NOT* be preceded by "0x".
1860
1861 The size of the memory transfer is not important when dealing with
1862 cache lines (as long as no more than a cache line can be
1863 transferred in a single operation :-), however more information
1864 could be given following the dineroIII requirement to allow more
1865 complete memory and cache simulators to provide better
1866 results. i.e. the University of Pisa has a cache simulator that can
1867 also take bus size and speed as (variable) inputs to calculate
1868 complete system performance (a much more useful ability when trying
1869 to construct an end product, rather than a processor). They
1870 currently have an ARM version of their tool called ChARM. */
1871
1872static
1873void dotrace(tracefh,type,address,width,comment)
1874 FILE *tracefh;
1875 int type;
1876 unsigned int address;
1877 int width;
1878 char *comment;
1879{
1880 if (state & simTRACE) {
1881 va_list ap;
1882 fprintf(tracefh,"%d %08x ; width %d ; ",type,address,width);
1883 va_start(ap,comment);
1884 fprintf(tracefh,comment,ap);
1885 va_end(ap);
1886 fprintf(tracefh,"\n");
1887 }
1888 /* NOTE: Since the "din" format will only accept 32bit addresses, and
1889 we may be generating 64bit ones, we should put the hi-32bits of the
1890 address into the comment field. */
1891
1892 /* TODO: Provide a buffer for the trace lines. We can then avoid
1893 performing writes until the buffer is filled, or the file is
1894 being closed. */
1895
1896 /* NOTE: We could consider adding a comment field to the "din" file
1897 produced using type 3 markers (unknown access). This would then
1898 allow information about the program that the "din" is for, and
1899 the MIPs world that was being simulated, to be placed into the
1900 trace file. */
1901
1902 return;
1903}
1904#endif /* TRACE */
1905
f7481d45
JSC
1906/*---------------------------------------------------------------------------*/
1907/*-- host<->target transfers ------------------------------------------------*/
1908/*---------------------------------------------------------------------------*/
1909/* The following routines allow conditionals to be avoided during the
1910 simulation, at the cost of increasing the image and source size. */
1911
1912static unsigned int
1913xfer_direct_word(memory)
1914 unsigned char *memory;
1915{
1916 return *((unsigned int *)memory);
1917}
1918
1919static uword64
1920xfer_direct_long(memory)
1921 unsigned char *memory;
1922{
1923 return *((uword64 *)memory);
1924}
1925
1926static unsigned int
1927swap_direct_word(data)
1928 unsigned int data;
1929{
1930 return data;
1931}
1932
1933static uword64
1934swap_direct_long(data)
1935 uword64 data;
1936{
1937 return data;
1938}
1939
1940static unsigned int
1941xfer_big_word(memory)
1942 unsigned char *memory;
1943{
1944 return ((memory[0] << 24) | (memory[1] << 16) | (memory[2] << 8) | memory[3]);
1945}
1946
1947static uword64
1948xfer_big_long(memory)
1949 unsigned char *memory;
1950{
1951 return (((uword64)memory[0] << 56) | ((uword64)memory[1] << 48)
1952 | ((uword64)memory[2] << 40) | ((uword64)memory[3] << 32)
1953 | (memory[4] << 24) | (memory[5] << 16) | (memory[6] << 8) | memory[7]);
1954}
1955
1956static unsigned int
1957xfer_little_word(memory)
1958 unsigned char *memory;
1959{
1960 return ((memory[3] << 24) | (memory[2] << 16) | (memory[1] << 8) | memory[0]);
1961}
1962
1963static uword64
1964xfer_little_long(memory)
1965 unsigned char *memory;
1966{
1967 return (((uword64)memory[7] << 56) | ((uword64)memory[6] << 48)
1968 | ((uword64)memory[5] << 40) | ((uword64)memory[4] << 32)
1969 | (memory[3] << 24) | (memory[2] << 16) | (memory[1] << 8) | memory[0]);
1970}
1971
1972static unsigned int
1973swap_word(data)
1974 unsigned int data;
1975{
1976 unsigned int result;
1977 result = data ^ ((data << 16) | (data >> 16));
1978 result &= ~0x00FF0000;
1979 data = (data << 24) | (data >> 8);
1980 return data ^ (result >> 8);
1981}
1982
1983static uword64
1984swap_long(data)
1985 uword64 data;
1986{
1987 unsigned int tmphi = WORD64HI(data);
1988 unsigned int tmplo = WORD64LO(data);
1989 tmphi = swap_word(tmphi);
1990 tmplo = swap_word(tmplo);
1991 /* Now swap the HI and LO parts */
1992 return SET64LO(tmphi) | SET64HI(tmplo);
1993}
1994
8bae0a0c
JSC
1995/*---------------------------------------------------------------------------*/
1996/*-- simulator engine -------------------------------------------------------*/
1997/*---------------------------------------------------------------------------*/
1998
1999static void
2000ColdReset()
2001{
2002 /* RESET: Fixed PC address: */
e871dd18 2003 PC = (((uword64)0xFFFFFFFF<<32) | 0xBFC00000);
8bae0a0c
JSC
2004 /* The reset vector address is in the unmapped, uncached memory space. */
2005
2006 SR &= ~(status_SR | status_TS | status_RP);
2007 SR |= (status_ERL | status_BEV);
2008 /* VR4300 starts in Big-Endian mode */
2009 CONFIG &= ~(config_EP_mask << config_EP_shift);
2010 CONFIG |= ((config_EP_D << config_EP_shift) | config_BE);
2011 /* TODO: The VR4300 CONFIG register is not modelled fully at the moment */
2012
2013#if defined(HASFPU) && (GPRLEN == (64))
2014 /* Cheat and allow access to the complete register set immediately: */
2015 SR |= status_FR; /* 64bit registers */
2016#endif /* HASFPU and 64bit FP registers */
2017
2018 /* Ensure that any instructions with pending register updates are
2019 cleared: */
2020 {
2021 int loop;
2022 for (loop = 0; (loop < PSLOTS); loop++)
2023 pending_slot_reg[loop] = (LAST_EMBED_REGNUM + 1);
2024 pending_in = pending_out = pending_total = 0;
2025 }
2026
2027#if defined(HASFPU)
2028 /* Initialise the FPU registers to the unknown state */
2029 {
2030 int rn;
2031 for (rn = 0; (rn < 32); rn++)
2032 fpr_state[rn] = fmt_uninterpreted;
2033 }
2034#endif /* HASFPU */
2035
f7481d45
JSC
2036 /* In reality this check should be performed at various points
2037 within the simulation, since it is possible to change the
2038 endianness of user programs. However, we perform the check here
2039 to ensure that the start-of-day values agree: */
2040 state |= (BigEndianCPU ? simBE : 0);
2041 if ((target_byte_order == 1234) != !(state & simBE)) {
2042 fprintf(stderr,"ColdReset: GDB (%s) and simulator (%s) do not agree on target endianness\n",
2043 target_byte_order == 1234 ? "little" : "big",
2044 state & simBE ? "big" : "little");
2045 exit(1);
2046 }
2047
9a739379 2048 if (!(state & simHOSTBE) == !(state & simBE)) {
f7481d45
JSC
2049 host_read_word = xfer_direct_word;
2050 host_read_long = xfer_direct_long;
2051 host_swap_word = swap_direct_word;
2052 host_swap_long = swap_direct_long;
2053 } else if (state & simHOSTBE) {
2054 host_read_word = xfer_little_word;
2055 host_read_long = xfer_little_long;
2056 host_swap_word = swap_word;
2057 host_swap_long = swap_long;
2058 } else { /* HOST little-endian */
2059 host_read_word = xfer_big_word;
2060 host_read_long = xfer_big_long;
2061 host_swap_word = swap_word;
2062 host_swap_long = swap_long;
2063 }
2064
8bae0a0c
JSC
2065 return;
2066}
2067
2068/* Description from page A-22 of the "MIPS IV Instruction Set" manual (revision 3.1) */
2069/* Translate a virtual address to a physical address and cache
2070 coherence algorithm describing the mechanism used to resolve the
2071 memory reference. Given the virtual address vAddr, and whether the
2072 reference is to Instructions ot Data (IorD), find the corresponding
2073 physical address (pAddr) and the cache coherence algorithm (CCA)
2074 used to resolve the reference. If the virtual address is in one of
2075 the unmapped address spaces the physical address and the CCA are
2076 determined directly by the virtual address. If the virtual address
2077 is in one of the mapped address spaces then the TLB is used to
2078 determine the physical address and access type; if the required
2079 translation is not present in the TLB or the desired access is not
2080 permitted the function fails and an exception is taken.
2081
2082 NOTE: This function is extended to return an exception state. This,
2083 along with the exception generation is used to notify whether a
2084 valid address translation occured */
2085
2086static int
2087AddressTranslation(vAddr,IorD,LorS,pAddr,CCA,host,raw)
e871dd18 2088 uword64 vAddr;
8bae0a0c
JSC
2089 int IorD;
2090 int LorS;
e871dd18 2091 uword64 *pAddr;
8bae0a0c
JSC
2092 int *CCA;
2093 int host;
2094 int raw;
2095{
2096 int res = -1; /* TRUE : Assume good return */
2097
2098#ifdef DEBUG
e871dd18 2099 callback->printf_filtered(callback,"AddressTranslation(0x%08X%08X,%s,%s,...);\n",WORD64HI(vAddr),WORD64LO(vAddr),(IorD ? "isDATA" : "isINSTRUCTION"),(LorS ? "iSTORE" : "isLOAD"));
8bae0a0c
JSC
2100#endif
2101
2102 /* Check that the address is valid for this memory model */
2103
2104 /* For a simple (flat) memory model, we simply pass virtual
2105 addressess through (mostly) unchanged. */
2106 vAddr &= 0xFFFFFFFF;
a9f7253f
JSC
2107
2108 /* Treat the kernel memory spaces identically for the moment: */
2109 if ((membank_base == K1BASE) && (vAddr >= K0BASE) && (vAddr < (K0BASE + K0SIZE)))
2110 vAddr += (K1BASE - K0BASE);
2111
2112 /* Also assume that the K1BASE memory wraps. This is required to
2113 allow the PMON run-time __sizemem() routine to function (without
2114 having to provide exception simulation). NOTE: A kludge to work
2115 around the fact that the monitor memory is currently held in the
2116 K1BASE space. */
2117 if (((vAddr < monitor_base) || (vAddr >= (monitor_base + monitor_size))) && (vAddr >= K1BASE && vAddr < (K1BASE + K1SIZE)))
2118 vAddr = (K1BASE | (vAddr & (membank_size - 1)));
2119
8bae0a0c
JSC
2120 *pAddr = vAddr; /* default for isTARGET */
2121 *CCA = Uncached; /* not used for isHOST */
2122
2123 /* NOTE: This is a duplicate of the code that appears in the
2124 LoadMemory and StoreMemory functions. They should be merged into
2125 a single function (that can be in-lined if required). */
2126 if ((vAddr >= membank_base) && (vAddr < (membank_base + membank_size))) {
2127 if (host)
2128 *pAddr = (int)&membank[((unsigned int)(vAddr - membank_base) & (membank_size - 1))];
2129 } else if ((vAddr >= monitor_base) && (vAddr < (monitor_base + monitor_size))) {
2130 if (host)
2131 *pAddr = (int)&monitor[((unsigned int)(vAddr - monitor_base) & (monitor_size - 1))];
2132 } else {
2133#if 1 /* def DEBUG */
f24b7b69 2134 sim_warning("Failed: AddressTranslation(0x%08X%08X,%s,%s,...) IPC = 0x%08X%08X",WORD64HI(vAddr),WORD64LO(vAddr),(IorD ? "isDATA" : "isINSTRUCTION"),(LorS ? "isSTORE" : "isLOAD"),WORD64HI(IPC),WORD64LO(IPC));
8bae0a0c
JSC
2135#endif /* DEBUG */
2136 res = 0; /* AddressTranslation has failed */
2137 *pAddr = -1;
2138 if (!raw) /* only generate exceptions on real memory transfers */
2139 SignalException((LorS == isSTORE) ? AddressStore : AddressLoad);
2140 else
f24b7b69 2141 sim_warning("AddressTranslation for %s %s from 0x%08X%08X failed",(IorD ? "data" : "instruction"),(LorS ? "store" : "load"),WORD64HI(vAddr),WORD64LO(vAddr));
8bae0a0c
JSC
2142 }
2143
2144 return(res);
2145}
2146
2147/* Description from page A-23 of the "MIPS IV Instruction Set" manual (revision 3.1) */
2148/* Prefetch data from memory. Prefetch is an advisory instruction for
2149 which an implementation specific action is taken. The action taken
2150 may increase performance, but must not change the meaning of the
2151 program, or alter architecturally-visible state. */
2152static void
2153Prefetch(CCA,pAddr,vAddr,DATA,hint)
2154 int CCA;
e871dd18
JSC
2155 uword64 pAddr;
2156 uword64 vAddr;
8bae0a0c
JSC
2157 int DATA;
2158 int hint;
2159{
2160#ifdef DEBUG
e871dd18 2161 callback->printf_filtered(callback,"Prefetch(%d,0x%08X%08X,0x%08X%08X,%d,%d);\n",CCA,WORD64HI(pAddr),WORD64LO(pAddr),WORD64HI(vAddr),WORD64LO(vAddr),DATA,hint);
8bae0a0c
JSC
2162#endif /* DEBUG */
2163
2164 /* For our simple memory model we do nothing */
2165 return;
2166}
2167
2168/* Description from page A-22 of the "MIPS IV Instruction Set" manual (revision 3.1) */
2169/* Load a value from memory. Use the cache and main memory as
2170 specified in the Cache Coherence Algorithm (CCA) and the sort of
2171 access (IorD) to find the contents of AccessLength memory bytes
2172 starting at physical location pAddr. The data is returned in the
2173 fixed width naturally-aligned memory element (MemElem). The
2174 low-order two (or three) bits of the address and the AccessLength
2175 indicate which of the bytes within MemElem needs to be given to the
2176 processor. If the memory access type of the reference is uncached
2177 then only the referenced bytes are read from memory and valid
2178 within the memory element. If the access type is cached, and the
2179 data is not present in cache, an implementation specific size and
2180 alignment block of memory is read and loaded into the cache to
2181 satisfy a load reference. At a minimum, the block is the entire
2182 memory element. */
e871dd18 2183static uword64
8bae0a0c
JSC
2184LoadMemory(CCA,AccessLength,pAddr,vAddr,IorD,raw)
2185 int CCA;
2186 int AccessLength;
e871dd18
JSC
2187 uword64 pAddr;
2188 uword64 vAddr;
8bae0a0c
JSC
2189 int IorD;
2190 int raw;
2191{
e871dd18 2192 uword64 value;
8bae0a0c
JSC
2193
2194#ifdef DEBUG
2195 if (membank == NULL)
e871dd18 2196 callback->printf_filtered(callback,"DBG: LoadMemory(%d,%d,0x%08X%08X,0x%08X%08X,%s,%s)\n",CCA,AccessLength,WORD64HI(pAddr),WORD64LO(pAddr),WORD64HI(vAddr),WORD64LO(vAddr),(IorD ? "isDATA" : "isINSTRUCTION"),(raw ? "isRAW" : "isREAL"));
8bae0a0c
JSC
2197#endif /* DEBUG */
2198
2199#if defined(WARN_MEM)
2200 if (CCA != uncached)
f24b7b69 2201 sim_warning("LoadMemory CCA (%d) is not uncached (currently all accesses treated as cached)",CCA);
8bae0a0c
JSC
2202
2203 if (((pAddr & LOADDRMASK) + AccessLength) > LOADDRMASK) {
2204 /* In reality this should be a Bus Error */
f24b7b69 2205 sim_error("AccessLength of %d would extend over %dbit aligned boundary for physical address 0x%08X%08X\n",AccessLength,(LOADDRMASK + 1)<<2,WORD64HI(pAddr),WORD64LO(pAddr));
8bae0a0c
JSC
2206 }
2207#endif /* WARN_MEM */
2208
2209 /* Decide which physical memory locations are being dealt with. At
2210 this point we should be able to split the pAddr bits into the
2211 relevant address map being simulated. If the "raw" variable is
2212 set, the memory read being performed should *NOT* update any I/O
2213 state or affect the CPU state. This also includes avoiding
2214 affecting statistics gathering. */
2215
2216 /* If instruction fetch then we need to check that the two lo-order
2217 bits are zero, otherwise raise a InstructionFetch exception: */
2218 if ((IorD == isINSTRUCTION) && ((pAddr & 0x3) != 0))
2219 SignalException(InstructionFetch);
2220 else {
2221 unsigned int index;
2222 unsigned char *mem = NULL;
2223
8bae0a0c
JSC
2224#if defined(TRACE)
2225 if (!raw)
2226 dotrace(tracefh,((IorD == isDATA) ? 0 : 2),(unsigned int)(pAddr&0xFFFFFFFF),(AccessLength + 1),"load%s",((IorD == isDATA) ? "" : " instruction"));
2227#endif /* TRACE */
2228
2229 /* NOTE: Quicker methods of decoding the address space can be used
2230 when a real memory map is being simulated (i.e. using hi-order
2231 address bits to select device). */
2232 if ((pAddr >= membank_base) && (pAddr < (membank_base + membank_size))) {
2233 index = ((unsigned int)(pAddr - membank_base) & (membank_size - 1));
2234 mem = membank;
2235 } else if ((pAddr >= monitor_base) && (pAddr < (monitor_base + monitor_size))) {
2236 index = ((unsigned int)(pAddr - monitor_base) & (monitor_size - 1));
2237 mem = monitor;
2238 }
2239 if (mem == NULL)
e871dd18 2240 sim_error("Simulator memory not found for physical address 0x%08X%08X\n",WORD64HI(pAddr),WORD64LO(pAddr));
8bae0a0c
JSC
2241 else {
2242 /* If we obtained the endianness of the host, and it is the same
2243 as the target memory system we can optimise the memory
2244 accesses. However, without that information we must perform
2245 slow transfer, and hope that the compiler optimisation will
2246 merge successive loads. */
2247 value = 0; /* no data loaded yet */
2248
2249 /* In reality we should always be loading a doubleword value (or
2250 word value in 32bit memory worlds). The external code then
2251 extracts the required bytes. However, to keep performance
2252 high we only load the required bytes into the relevant
2253 slots. */
2254 if (BigEndianMem)
2255 switch (AccessLength) { /* big-endian memory */
2256 case AccessLength_DOUBLEWORD :
e871dd18 2257 value |= ((uword64)mem[index++] << 56);
8bae0a0c 2258 case AccessLength_SEPTIBYTE :
e871dd18 2259 value |= ((uword64)mem[index++] << 48);
8bae0a0c 2260 case AccessLength_SEXTIBYTE :
e871dd18 2261 value |= ((uword64)mem[index++] << 40);
8bae0a0c 2262 case AccessLength_QUINTIBYTE :
e871dd18 2263 value |= ((uword64)mem[index++] << 32);
8bae0a0c
JSC
2264 case AccessLength_WORD :
2265 value |= ((unsigned int)mem[index++] << 24);
2266 case AccessLength_TRIPLEBYTE :
2267 value |= ((unsigned int)mem[index++] << 16);
2268 case AccessLength_HALFWORD :
2269 value |= ((unsigned int)mem[index++] << 8);
2270 case AccessLength_BYTE :
2271 value |= mem[index];
2272 break;
2273 }
2274 else {
2275 index += (AccessLength + 1);
2276 switch (AccessLength) { /* little-endian memory */
2277 case AccessLength_DOUBLEWORD :
e871dd18 2278 value |= ((uword64)mem[--index] << 56);
8bae0a0c 2279 case AccessLength_SEPTIBYTE :
e871dd18 2280 value |= ((uword64)mem[--index] << 48);
8bae0a0c 2281 case AccessLength_SEXTIBYTE :
e871dd18 2282 value |= ((uword64)mem[--index] << 40);
8bae0a0c 2283 case AccessLength_QUINTIBYTE :
e871dd18 2284 value |= ((uword64)mem[--index] << 32);
8bae0a0c 2285 case AccessLength_WORD :
e871dd18 2286 value |= ((uword64)mem[--index] << 24);
8bae0a0c 2287 case AccessLength_TRIPLEBYTE :
e871dd18 2288 value |= ((uword64)mem[--index] << 16);
8bae0a0c 2289 case AccessLength_HALFWORD :
e871dd18 2290 value |= ((uword64)mem[--index] << 8);
8bae0a0c 2291 case AccessLength_BYTE :
e871dd18 2292 value |= ((uword64)mem[--index] << 0);
8bae0a0c
JSC
2293 break;
2294 }
2295 }
2296
2297#ifdef DEBUG
e871dd18 2298 printf("DBG: LoadMemory() : (offset %d) : value = 0x%08X%08X\n",(int)(pAddr & LOADDRMASK),WORD64HI(value),WORD64LO(value));
8bae0a0c
JSC
2299#endif /* DEBUG */
2300
2301 /* TODO: We could try and avoid the shifts when dealing with raw
2302 memory accesses. This would mean updating the LoadMemory and
2303 StoreMemory routines to avoid shifting the data before
2304 returning or using it. */
2305 if (!raw) { /* do nothing for raw accessess */
2306 if (BigEndianMem)
2307 value <<= (((7 - (pAddr & LOADDRMASK)) - AccessLength) * 8);
2308 else /* little-endian only needs to be shifted up to the correct byte offset */
2309 value <<= ((pAddr & LOADDRMASK) * 8);
2310 }
2311
2312#ifdef DEBUG
e871dd18
JSC
2313 printf("DBG: LoadMemory() : shifted value = 0x%08X%08X\n",WORD64HI(value),WORD64LO(value));
2314#endif /* DEBUG */
8bae0a0c
JSC
2315 }
2316 }
2317
2318 return(value);
2319}
2320
2321/* Description from page A-23 of the "MIPS IV Instruction Set" manual (revision 3.1) */
2322/* Store a value to memory. The specified data is stored into the
2323 physical location pAddr using the memory hierarchy (data caches and
2324 main memory) as specified by the Cache Coherence Algorithm
2325 (CCA). The MemElem contains the data for an aligned, fixed-width
2326 memory element (word for 32-bit processors, doubleword for 64-bit
2327 processors), though only the bytes that will actually be stored to
2328 memory need to be valid. The low-order two (or three) bits of pAddr
2329 and the AccessLength field indicates which of the bytes within the
2330 MemElem data should actually be stored; only these bytes in memory
2331 will be changed. */
2332static void
2333StoreMemory(CCA,AccessLength,MemElem,pAddr,vAddr,raw)
2334 int CCA;
2335 int AccessLength;
e871dd18
JSC
2336 uword64 MemElem;
2337 uword64 pAddr;
2338 uword64 vAddr;
8bae0a0c
JSC
2339 int raw;
2340{
2341#ifdef DEBUG
e871dd18 2342 callback->printf_filtered(callback,"DBG: StoreMemory(%d,%d,0x%08X%08X,0x%08X%08X,0x%08X%08X,%s)\n",CCA,AccessLength,WORD64HI(MemElem),WORD64LO(MemElem),WORD64HI(pAddr),WORD64LO(pAddr),WORD64HI(vAddr),WORD64LO(vAddr),(raw ? "isRAW" : "isREAL"));
8bae0a0c
JSC
2343#endif /* DEBUG */
2344
2345#if defined(WARN_MEM)
2346 if (CCA != uncached)
f24b7b69 2347 sim_warning("StoreMemory CCA (%d) is not uncached (currently all accesses treated as cached)",CCA);
8bae0a0c
JSC
2348
2349 if (((pAddr & LOADDRMASK) + AccessLength) > LOADDRMASK)
f24b7b69 2350 sim_error("AccessLength of %d would extend over %dbit aligned boundary for physical address 0x%08X%08X\n",AccessLength,(LOADDRMASK + 1)<<2,WORD64HI(pAddr),WORD64LO(pAddr));
8bae0a0c
JSC
2351#endif /* WARN_MEM */
2352
2353#if defined(TRACE)
2354 if (!raw)
2355 dotrace(tracefh,1,(unsigned int)(pAddr&0xFFFFFFFF),(AccessLength + 1),"store");
2356#endif /* TRACE */
2357
2358 /* See the comments in the LoadMemory routine about optimising
2359 memory accesses. Also if we wanted to make the simulator smaller,
2360 we could merge a lot of this code with the LoadMemory
2361 routine. However, this would slow the simulator down with
2362 run-time conditionals. */
2363 {
2364 unsigned int index;
2365 unsigned char *mem = NULL;
2366
2367 if ((pAddr >= membank_base) && (pAddr < (membank_base + membank_size))) {
2368 index = ((unsigned int)(pAddr - membank_base) & (membank_size - 1));
2369 mem = membank;
2370 } else if ((pAddr >= monitor_base) && (pAddr < (monitor_base + monitor_size))) {
2371 index = ((unsigned int)(pAddr - monitor_base) & (monitor_size - 1));
2372 mem = monitor;
2373 }
2374
2375 if (mem == NULL)
e871dd18 2376 sim_error("Simulator memory not found for physical address 0x%08X%08X\n",WORD64HI(pAddr),WORD64LO(pAddr));
8bae0a0c
JSC
2377 else {
2378 int shift = 0;
2379
2380#ifdef DEBUG
e871dd18 2381 printf("DBG: StoreMemory: offset = %d MemElem = 0x%08X%08X\n",(unsigned int)(pAddr & LOADDRMASK),WORD64HI(MemElem),WORD64LO(MemElem));
8bae0a0c
JSC
2382#endif /* DEBUG */
2383
2384 if (BigEndianMem) {
2385 if (raw)
2386 shift = ((7 - AccessLength) * 8);
2387 else /* real memory access */
2388 shift = ((pAddr & LOADDRMASK) * 8);
2389 MemElem <<= shift;
2390 } else {
2391 /* no need to shift raw little-endian data */
2392 if (!raw)
2393 MemElem >>= ((pAddr & LOADDRMASK) * 8);
2394 }
2395
2396#ifdef DEBUG
e871dd18 2397 printf("DBG: StoreMemory: shift = %d MemElem = 0x%08X%08X\n",shift,WORD64HI(MemElem),WORD64LO(MemElem));
8bae0a0c
JSC
2398#endif /* DEBUG */
2399
2400 if (BigEndianMem) {
2401 switch (AccessLength) { /* big-endian memory */
2402 case AccessLength_DOUBLEWORD :
2403 mem[index++] = (unsigned char)(MemElem >> 56);
2404 MemElem <<= 8;
2405 case AccessLength_SEPTIBYTE :
2406 mem[index++] = (unsigned char)(MemElem >> 56);
2407 MemElem <<= 8;
2408 case AccessLength_SEXTIBYTE :
2409 mem[index++] = (unsigned char)(MemElem >> 56);
2410 MemElem <<= 8;
2411 case AccessLength_QUINTIBYTE :
2412 mem[index++] = (unsigned char)(MemElem >> 56);
2413 MemElem <<= 8;
2414 case AccessLength_WORD :
2415 mem[index++] = (unsigned char)(MemElem >> 56);
2416 MemElem <<= 8;
2417 case AccessLength_TRIPLEBYTE :
2418 mem[index++] = (unsigned char)(MemElem >> 56);
2419 MemElem <<= 8;
2420 case AccessLength_HALFWORD :
2421 mem[index++] = (unsigned char)(MemElem >> 56);
2422 MemElem <<= 8;
2423 case AccessLength_BYTE :
2424 mem[index++] = (unsigned char)(MemElem >> 56);
2425 break;
2426 }
2427 } else {
2428 index += (AccessLength + 1);
2429 switch (AccessLength) { /* little-endian memory */
2430 case AccessLength_DOUBLEWORD :
2431 mem[--index] = (unsigned char)(MemElem >> 56);
2432 case AccessLength_SEPTIBYTE :
2433 mem[--index] = (unsigned char)(MemElem >> 48);
2434 case AccessLength_SEXTIBYTE :
2435 mem[--index] = (unsigned char)(MemElem >> 40);
2436 case AccessLength_QUINTIBYTE :
2437 mem[--index] = (unsigned char)(MemElem >> 32);
2438 case AccessLength_WORD :
2439 mem[--index] = (unsigned char)(MemElem >> 24);
2440 case AccessLength_TRIPLEBYTE :
2441 mem[--index] = (unsigned char)(MemElem >> 16);
2442 case AccessLength_HALFWORD :
2443 mem[--index] = (unsigned char)(MemElem >> 8);
2444 case AccessLength_BYTE :
2445 mem[--index] = (unsigned char)(MemElem >> 0);
2446 break;
2447 }
2448 }
2449 }
2450 }
2451
2452 return;
2453}
2454
2455/* Description from page A-26 of the "MIPS IV Instruction Set" manual (revision 3.1) */
2456/* Order loads and stores to synchronise shared memory. Perform the
2457 action necessary to make the effects of groups of synchronizable
2458 loads and stores indicated by stype occur in the same order for all
2459 processors. */
2460static void
2461SyncOperation(stype)
2462 int stype;
2463{
2464#ifdef DEBUG
2465 callback->printf_filtered(callback,"SyncOperation(%d) : TODO\n",stype);
2466#endif /* DEBUG */
2467 return;
2468}
2469
2470/* Description from page A-26 of the "MIPS IV Instruction Set" manual (revision 3.1) */
2471/* Signal an exception condition. This will result in an exception
2472 that aborts the instruction. The instruction operation pseudocode
2473 will never see a return from this function call. */
2474static void
2475SignalException(exception)
2476 int exception;
2477{
2478 /* Ensure that any active atomic read/modify/write operation will fail: */
2479 LLBIT = 0;
2480
2481 switch (exception) {
2482 /* TODO: For testing purposes I have been ignoring TRAPs. In
2483 reality we should either simulate them, or allow the user to
2484 ignore them at run-time. */
2485 case Trap :
f24b7b69 2486 sim_warning("Ignoring instruction TRAP (PC 0x%08X%08X)",WORD64HI(IPC),WORD64LO(IPC));
8bae0a0c
JSC
2487 break;
2488
2489 case ReservedInstruction :
2490 {
2491 va_list ap;
2492 unsigned int instruction;
2493 va_start(ap,exception);
2494 instruction = va_arg(ap,unsigned int);
2495 va_end(ap);
2496 /* Provide simple monitor support using ReservedInstruction
2497 exceptions. The following code simulates the fixed vector
2498 entry points into the IDT monitor by causing a simulator
2499 trap, performing the monitor operation, and returning to
2500 the address held in the $ra register (standard PCS return
2501 address). This means we only need to pre-load the vector
2502 space with suitable instruction values. For systems were
2503 actual trap instructions are used, we would not need to
2504 perform this magic. */
2505 if ((instruction & ~RSVD_INSTRUCTION_AMASK) == RSVD_INSTRUCTION) {
2506 sim_monitor(instruction & RSVD_INSTRUCTION_AMASK);
2507 PC = RA; /* simulate the return from the vector entry */
2508 /* NOTE: This assumes that a branch-and-link style
2509 instruction was used to enter the vector (which is the
2510 case with the current IDT monitor). */
2511 break; /* out of the switch statement */
2512 } /* else fall through to normal exception processing */
f24b7b69 2513 sim_warning("ReservedInstruction 0x%08X at IPC = 0x%08X%08X",instruction,WORD64HI(IPC),WORD64LO(IPC));
8bae0a0c
JSC
2514 }
2515
2516 default:
2517#if 1 /* def DEBUG */
f24b7b69
JSC
2518 if (exception != BreakPoint)
2519 callback->printf_filtered(callback,"DBG: SignalException(%d) IPC = 0x%08X%08X\n",exception,WORD64HI(IPC),WORD64LO(IPC));
8bae0a0c
JSC
2520#endif /* DEBUG */
2521 /* Store exception code into current exception id variable (used
2522 by exit code): */
2523
2524 /* TODO: If not simulating exceptions then stop the simulator
2525 execution. At the moment we always stop the simulation. */
f24b7b69
JSC
2526#if 1 /* bodge to allow exit() code to be returned, by assuming that a breakpoint exception after a monitor exit() call should be silent */
2527/* further bodged since the standard libgloss/mips world doesn't use the _exit() monitor call, it just uses a break instruction */
2528 if (exception == BreakPoint /* && state & simEXIT */)
2529 {
2530 state |= simSTOP;
2531#if 1 /* since the _exit() monitor call may not be called */
2532 state |= simEXIT;
2533 rcexit = (unsigned int)(A0 & 0xFFFFFFFF);
2534#endif
2535 }
2536 else
2537 state |= (simSTOP | simEXCEPTION);
2538#else
8bae0a0c 2539 state |= (simSTOP | simEXCEPTION);
f24b7b69 2540#endif
8bae0a0c
JSC
2541 CAUSE = (exception << 2);
2542 if (state & simDELAYSLOT) {
2543 CAUSE |= cause_BD;
2544 EPC = (IPC - 4); /* reference the branch instruction */
2545 } else
2546 EPC = IPC;
2547 /* The following is so that the simulator will continue from the
2548 exception address on breakpoint operations. */
2549 PC = EPC;
2550 break;
2551
2552 case SimulatorFault:
2553 {
2554 va_list ap;
2555 char *msg;
2556 va_start(ap,exception);
2557 msg = va_arg(ap,char *);
2558 fprintf(stderr,"FATAL: Simulator error \"%s\"\n",msg);
2559 va_end(ap);
2560 }
2561 exit(1);
2562 }
2563
2564 return;
2565}
2566
2567#if defined(WARN_RESULT)
2568/* Description from page A-26 of the "MIPS IV Instruction Set" manual (revision 3.1) */
2569/* This function indicates that the result of the operation is
2570 undefined. However, this should not affect the instruction
2571 stream. All that is meant to happen is that the destination
2572 register is set to an undefined result. To keep the simulator
2573 simple, we just don't bother updating the destination register, so
2574 the overall result will be undefined. If desired we can stop the
2575 simulator by raising a pseudo-exception. */
2576static void
2577UndefinedResult()
2578{
f24b7b69 2579 sim_warning("UndefinedResult: IPC = 0x%08X%08X",WORD64HI(IPC),WORD64LO(IPC));
8bae0a0c
JSC
2580#if 0 /* Disabled for the moment, since it actually happens a lot at the moment. */
2581 state |= simSTOP;
2582#endif
2583 return;
2584}
2585#endif /* WARN_RESULT */
2586
2587static void
2588CacheOp(op,pAddr,vAddr,instruction)
2589 int op;
e871dd18
JSC
2590 uword64 pAddr;
2591 uword64 vAddr;
8bae0a0c
JSC
2592 unsigned int instruction;
2593{
f24b7b69
JSC
2594#if 1 /* stop warning message being displayed (we should really just remove the code) */
2595 static int icache_warning = 1;
2596 static int dcache_warning = 1;
2597#else
a9f7253f
JSC
2598 static int icache_warning = 0;
2599 static int dcache_warning = 0;
f24b7b69 2600#endif
a9f7253f 2601
8bae0a0c
JSC
2602 /* If CP0 is not useable (User or Supervisor mode) and the CP0
2603 enable bit in the Status Register is clear - a coprocessor
2604 unusable exception is taken. */
a9f7253f 2605#if 0
e871dd18 2606 callback->printf_filtered(callback,"TODO: Cache availability checking (PC = 0x%08X%08X)\n",WORD64HI(IPC),WORD64LO(IPC));
a9f7253f 2607#endif
8bae0a0c
JSC
2608
2609 switch (op & 0x3) {
2610 case 0: /* instruction cache */
2611 switch (op >> 2) {
2612 case 0: /* Index Invalidate */
2613 case 1: /* Index Load Tag */
2614 case 2: /* Index Store Tag */
2615 case 4: /* Hit Invalidate */
2616 case 5: /* Fill */
2617 case 6: /* Hit Writeback */
a9f7253f
JSC
2618 if (!icache_warning)
2619 {
f24b7b69 2620 sim_warning("Instruction CACHE operation %d to be coded",(op >> 2));
a9f7253f
JSC
2621 icache_warning = 1;
2622 }
8bae0a0c
JSC
2623 break;
2624
2625 default:
2626 SignalException(ReservedInstruction,instruction);
2627 break;
2628 }
2629 break;
2630
2631 case 1: /* data cache */
2632 switch (op >> 2) {
2633 case 0: /* Index Writeback Invalidate */
2634 case 1: /* Index Load Tag */
2635 case 2: /* Index Store Tag */
2636 case 3: /* Create Dirty */
2637 case 4: /* Hit Invalidate */
2638 case 5: /* Hit Writeback Invalidate */
2639 case 6: /* Hit Writeback */
a9f7253f
JSC
2640 if (!dcache_warning)
2641 {
f24b7b69 2642 sim_warning("Data CACHE operation %d to be coded",(op >> 2));
a9f7253f
JSC
2643 dcache_warning = 1;
2644 }
8bae0a0c
JSC
2645 break;
2646
2647 default:
2648 SignalException(ReservedInstruction,instruction);
2649 break;
2650 }
2651 break;
2652
2653 default: /* unrecognised cache ID */
2654 SignalException(ReservedInstruction,instruction);
2655 break;
2656 }
2657
2658 return;
2659}
2660
2661/*-- FPU support routines ---------------------------------------------------*/
2662
2663#if defined(HASFPU) /* Only needed when building FPU aware simulators */
2664
2665#if 1
2666#define SizeFGR() (GPRLEN)
2667#else
2668/* They depend on the CPU being simulated */
2669#define SizeFGR() ((PROCESSOR_64BIT && ((SR & status_FR) == 1)) ? 64 : 32)
2670#endif
2671
2672/* Numbers are held in normalized form. The SINGLE and DOUBLE binary
2673 formats conform to ANSI/IEEE Std 754-1985. */
2674/* SINGLE precision floating:
2675 * seeeeeeeefffffffffffffffffffffff
2676 * s = 1bit = sign
2677 * e = 8bits = exponent
2678 * f = 23bits = fraction
2679 */
2680/* SINGLE precision fixed:
2681 * siiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
2682 * s = 1bit = sign
2683 * i = 31bits = integer
2684 */
2685/* DOUBLE precision floating:
2686 * seeeeeeeeeeeffffffffffffffffffffffffffffffffffffffffffffffffffff
2687 * s = 1bit = sign
2688 * e = 11bits = exponent
2689 * f = 52bits = fraction
2690 */
2691/* DOUBLE precision fixed:
2692 * siiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
2693 * s = 1bit = sign
2694 * i = 63bits = integer
2695 */
2696
2697/* Extract sign-bit: */
2698#define FP_S_s(v) (((v) & ((unsigned)1 << 31)) ? 1 : 0)
e871dd18 2699#define FP_D_s(v) (((v) & ((uword64)1 << 63)) ? 1 : 0)
8bae0a0c
JSC
2700/* Extract biased exponent: */
2701#define FP_S_be(v) (((v) >> 23) & 0xFF)
2702#define FP_D_be(v) (((v) >> 52) & 0x7FF)
2703/* Extract unbiased Exponent: */
2704#define FP_S_e(v) (FP_S_be(v) - 0x7F)
2705#define FP_D_e(v) (FP_D_be(v) - 0x3FF)
2706/* Extract complete fraction field: */
2707#define FP_S_f(v) ((v) & ~((unsigned)0x1FF << 23))
e871dd18 2708#define FP_D_f(v) ((v) & ~((uword64)0xFFF << 52))
8bae0a0c
JSC
2709/* Extract numbered fraction bit: */
2710#define FP_S_fb(b,v) (((v) & (1 << (23 - (b)))) ? 1 : 0)
2711#define FP_D_fb(b,v) (((v) & (1 << (52 - (b)))) ? 1 : 0)
2712
2713/* Explicit QNaN values used when value required: */
2714#define FPQNaN_SINGLE (0x7FBFFFFF)
2715#define FPQNaN_WORD (0x7FFFFFFF)
e871dd18
JSC
2716#define FPQNaN_DOUBLE (((uword64)0x7FF7FFFF << 32) | 0xFFFFFFFF)
2717#define FPQNaN_LONG (((uword64)0x7FFFFFFF << 32) | 0xFFFFFFFF)
8bae0a0c
JSC
2718
2719/* Explicit Infinity values used when required: */
2720#define FPINF_SINGLE (0x7F800000)
e871dd18 2721#define FPINF_DOUBLE (((uword64)0x7FF00000 << 32) | 0x00000000)
8bae0a0c
JSC
2722
2723#if 1 /* def DEBUG */
2724#define RMMODE(v) (((v) == FP_RM_NEAREST) ? "Round" : (((v) == FP_RM_TOZERO) ? "Trunc" : (((v) == FP_RM_TOPINF) ? "Ceil" : "Floor")))
2725#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>"))))))
2726#endif /* DEBUG */
2727
e871dd18 2728static uword64
8bae0a0c
JSC
2729ValueFPR(fpr,fmt)
2730 int fpr;
2731 FP_formats fmt;
2732{
e871dd18 2733 uword64 value;
8bae0a0c
JSC
2734 int err = 0;
2735
2736 /* Treat unused register values, as fixed-point 64bit values: */
2737 if ((fmt == fmt_uninterpreted) || (fmt == fmt_unknown))
2738#if 1
2739 /* If request to read data as "uninterpreted", then use the current
2740 encoding: */
2741 fmt = fpr_state[fpr];
2742#else
2743 fmt = fmt_long;
2744#endif
2745
2746 /* For values not yet accessed, set to the desired format: */
2747 if (fpr_state[fpr] == fmt_uninterpreted) {
2748 fpr_state[fpr] = fmt;
2749#ifdef DEBUG
2750 printf("DBG: Register %d was fmt_uninterpreted. Now %s\n",fpr,DOFMT(fmt));
2751#endif /* DEBUG */
2752 }
2753 if (fmt != fpr_state[fpr]) {
f24b7b69 2754 sim_warning("FPR %d (format %s) being accessed with format %s - setting to unknown (PC = 0x%08X%08X)",fpr,DOFMT(fpr_state[fpr]),DOFMT(fmt),WORD64HI(IPC),WORD64LO(IPC));
8bae0a0c
JSC
2755 fpr_state[fpr] = fmt_unknown;
2756 }
2757
2758 if (fpr_state[fpr] == fmt_unknown) {
2759 /* Set QNaN value: */
2760 switch (fmt) {
2761 case fmt_single:
2762 value = FPQNaN_SINGLE;
2763 break;
2764
2765 case fmt_double:
2766 value = FPQNaN_DOUBLE;
2767 break;
2768
2769 case fmt_word:
2770 value = FPQNaN_WORD;
2771 break;
2772
2773 case fmt_long:
2774 value = FPQNaN_LONG;
2775 break;
2776
2777 default:
2778 err = -1;
2779 break;
2780 }
2781 } else if (SizeFGR() == 64) {
2782 switch (fmt) {
2783 case fmt_single:
2784 case fmt_word:
2785 value = (FGR[fpr] & 0xFFFFFFFF);
2786 break;
2787
2788 case fmt_uninterpreted:
2789 case fmt_double:
2790 case fmt_long:
2791 value = FGR[fpr];
2792 break;
2793
2794 default :
2795 err = -1;
2796 break;
2797 }
2798 } else if ((fpr & 1) == 0) { /* even registers only */
2799 switch (fmt) {
2800 case fmt_single:
2801 case fmt_word:
2802 value = (FGR[fpr] & 0xFFFFFFFF);
2803 break;
2804
2805 case fmt_uninterpreted:
2806 case fmt_double:
2807 case fmt_long:
f24b7b69 2808 value = ((((uword64)FGR[fpr+1]) << 32) | (FGR[fpr] & 0xFFFFFFFF));
8bae0a0c
JSC
2809 break;
2810
2811 default :
2812 err = -1;
2813 break;
2814 }
2815 }
2816
2817 if (err)
2818 SignalException(SimulatorFault,"Unrecognised FP format in ValueFPR()");
2819
2820#ifdef DEBUG
e871dd18 2821 printf("DBG: ValueFPR: fpr = %d, fmt = %s, value = 0x%08X%08X : PC = 0x%08X%08X : SizeFGR() = %d\n",fpr,DOFMT(fmt),WORD64HI(value),WORD64LO(value),WORD64HI(IPC),WORD64LO(IPC),SizeFGR());
8bae0a0c
JSC
2822#endif /* DEBUG */
2823
2824 return(value);
2825}
2826
2827static void
2828StoreFPR(fpr,fmt,value)
2829 int fpr;
2830 FP_formats fmt;
e871dd18 2831 uword64 value;
8bae0a0c
JSC
2832{
2833 int err = 0;
2834
2835#ifdef DEBUG
e871dd18 2836 printf("DBG: StoreFPR: fpr = %d, fmt = %s, value = 0x%08X%08X : PC = 0x%08X%08X : SizeFGR() = %d\n",fpr,DOFMT(fmt),WORD64HI(value),WORD64LO(value),WORD64HI(IPC),WORD64LO(IPC),SizeFGR());
8bae0a0c
JSC
2837#endif /* DEBUG */
2838
2839 if (SizeFGR() == 64) {
2840 switch (fmt) {
2841 case fmt_single :
2842 case fmt_word :
e871dd18 2843 FGR[fpr] = (((uword64)0xDEADC0DE << 32) | (value & 0xFFFFFFFF));
8bae0a0c
JSC
2844 fpr_state[fpr] = fmt;
2845 break;
2846
2847 case fmt_uninterpreted:
2848 case fmt_double :
2849 case fmt_long :
2850 FGR[fpr] = value;
2851 fpr_state[fpr] = fmt;
2852 break;
2853
2854 default :
2855 fpr_state[fpr] = fmt_unknown;
2856 err = -1;
2857 break;
2858 }
2859 } else if ((fpr & 1) == 0) { /* even register number only */
2860 switch (fmt) {
2861 case fmt_single :
2862 case fmt_word :
2863 FGR[fpr+1] = 0xDEADC0DE;
2864 FGR[fpr] = (value & 0xFFFFFFFF);
2865 fpr_state[fpr + 1] = fmt;
2866 fpr_state[fpr] = fmt;
2867 break;
2868
2869 case fmt_uninterpreted:
2870 case fmt_double :
2871 case fmt_long :
2872 FGR[fpr+1] = (value >> 32);
2873 FGR[fpr] = (value & 0xFFFFFFFF);
2874 fpr_state[fpr + 1] = fmt;
2875 fpr_state[fpr] = fmt;
2876 break;
2877
2878 default :
2879 fpr_state[fpr] = fmt_unknown;
2880 err = -1;
2881 break;
2882 }
e871dd18
JSC
2883 }
2884#if defined(WARN_RESULT)
2885 else
2886 UndefinedResult();
2887#endif /* WARN_RESULT */
8bae0a0c
JSC
2888
2889 if (err)
2890 SignalException(SimulatorFault,"Unrecognised FP format in StoreFPR()");
2891
2892#ifdef DEBUG
e871dd18 2893 printf("DBG: StoreFPR: fpr[%d] = 0x%08X%08X (format %s)\n",fpr,WORD64HI(FGR[fpr]),WORD64LO(FGR[fpr]),DOFMT(fmt));
8bae0a0c
JSC
2894#endif /* DEBUG */
2895
2896 return;
2897}
2898
2899static int
2900NaN(op,fmt)
e871dd18 2901 uword64 op;
8bae0a0c
JSC
2902 FP_formats fmt;
2903{
2904 int boolean = 0;
2905
2906 /* Check if (((E - bias) == (E_max + 1)) && (fraction != 0)). We
2907 know that the exponent field is biased... we we cheat and avoid
2908 removing the bias value. */
2909 switch (fmt) {
2910 case fmt_single:
2911 boolean = ((FP_S_be(op) == 0xFF) && (FP_S_f(op) != 0));
2912 /* We could use "FP_S_fb(1,op)" to ascertain whether we are
2913 dealing with a SNaN or QNaN */
2914 break;
2915 case fmt_double:
2916 boolean = ((FP_D_be(op) == 0x7FF) && (FP_D_f(op) != 0));
2917 /* We could use "FP_S_fb(1,op)" to ascertain whether we are
2918 dealing with a SNaN or QNaN */
2919 break;
2920 case fmt_word:
2921 boolean = (op == FPQNaN_WORD);
2922 break;
2923 case fmt_long:
2924 boolean = (op == FPQNaN_LONG);
2925 break;
2926 }
2927
2928#ifdef DEBUG
e871dd18 2929printf("DBG: NaN: returning %d for 0x%08X%08X (format = %s)\n",boolean,WORD64HI(op),WORD64LO(op),DOFMT(fmt));
8bae0a0c
JSC
2930#endif /* DEBUG */
2931
2932 return(boolean);
2933}
2934
2935static int
2936Infinity(op,fmt)
e871dd18 2937 uword64 op;
8bae0a0c
JSC
2938 FP_formats fmt;
2939{
2940 int boolean = 0;
2941
2942#ifdef DEBUG
e871dd18 2943 printf("DBG: Infinity: format %s 0x%08X%08X (PC = 0x%08X%08X)\n",DOFMT(fmt),WORD64HI(op),WORD64LO(op),WORD64HI(IPC),WORD64LO(IPC));
8bae0a0c
JSC
2944#endif /* DEBUG */
2945
2946 /* Check if (((E - bias) == (E_max + 1)) && (fraction == 0)). We
2947 know that the exponent field is biased... we we cheat and avoid
2948 removing the bias value. */
2949 switch (fmt) {
2950 case fmt_single:
2951 boolean = ((FP_S_be(op) == 0xFF) && (FP_S_f(op) == 0));
2952 break;
2953 case fmt_double:
2954 boolean = ((FP_D_be(op) == 0x7FF) && (FP_D_f(op) == 0));
2955 break;
2956 default:
2957 printf("DBG: TODO: unrecognised format (%s) for Infinity check\n",DOFMT(fmt));
2958 break;
2959 }
2960
2961#ifdef DEBUG
e871dd18 2962 printf("DBG: Infinity: returning %d for 0x%08X%08X (format = %s)\n",boolean,WORD64HI(op),WORD64LO(op),DOFMT(fmt));
8bae0a0c
JSC
2963#endif /* DEBUG */
2964
2965 return(boolean);
2966}
2967
2968static int
2969Less(op1,op2,fmt)
e871dd18
JSC
2970 uword64 op1;
2971 uword64 op2;
8bae0a0c
JSC
2972 FP_formats fmt;
2973{
2974 int boolean = 0;
2975
e871dd18
JSC
2976 /* Argument checking already performed by the FPCOMPARE code */
2977
8bae0a0c 2978#ifdef DEBUG
e871dd18 2979 printf("DBG: Less: %s: op1 = 0x%08X%08X : op2 = 0x%08X%08X\n",DOFMT(fmt),WORD64HI(op1),WORD64LO(op1),WORD64HI(op2),WORD64LO(op2));
8bae0a0c
JSC
2980#endif /* DEBUG */
2981
8bae0a0c
JSC
2982 /* The format type should already have been checked: */
2983 switch (fmt) {
2984 case fmt_single:
2985 {
2986 unsigned int wop1 = (unsigned int)op1;
2987 unsigned int wop2 = (unsigned int)op2;
2988 boolean = (*(float *)&wop1 < *(float *)&wop2);
2989 }
2990 break;
2991 case fmt_double:
2992 boolean = (*(double *)&op1 < *(double *)&op2);
2993 break;
2994 }
2995
2996#ifdef DEBUG
2997 printf("DBG: Less: returning %d (format = %s)\n",boolean,DOFMT(fmt));
2998#endif /* DEBUG */
2999
3000 return(boolean);
3001}
3002
3003static int
3004Equal(op1,op2,fmt)
e871dd18
JSC
3005 uword64 op1;
3006 uword64 op2;
8bae0a0c
JSC
3007 FP_formats fmt;
3008{
3009 int boolean = 0;
3010
e871dd18
JSC
3011 /* Argument checking already performed by the FPCOMPARE code */
3012
8bae0a0c 3013#ifdef DEBUG
e871dd18 3014 printf("DBG: Equal: %s: op1 = 0x%08X%08X : op2 = 0x%08X%08X\n",DOFMT(fmt),WORD64HI(op1),WORD64LO(op1),WORD64HI(op2),WORD64LO(op2));
8bae0a0c
JSC
3015#endif /* DEBUG */
3016
8bae0a0c
JSC
3017 /* The format type should already have been checked: */
3018 switch (fmt) {
3019 case fmt_single:
3020 boolean = ((op1 & 0xFFFFFFFF) == (op2 & 0xFFFFFFFF));
3021 break;
3022 case fmt_double:
3023 boolean = (op1 == op2);
3024 break;
3025 }
3026
3027#ifdef DEBUG
3028 printf("DBG: Equal: returning %d (format = %s)\n",boolean,DOFMT(fmt));
3029#endif /* DEBUG */
3030
3031 return(boolean);
3032}
3033
a9f7253f
JSC
3034static uword64
3035AbsoluteValue(op,fmt)
3036 uword64 op;
3037 FP_formats fmt;
3038{
3039 uword64 result;
3040
3041#ifdef DEBUG
3042 printf("DBG: AbsoluteValue: %s: op = 0x%08X%08X\n",DOFMT(fmt),WORD64HI(op),WORD64LO(op));
3043#endif /* DEBUG */
3044
3045 /* The format type should already have been checked: */
3046 switch (fmt) {
3047 case fmt_single:
3048 {
3049 unsigned int wop = (unsigned int)op;
3050 float tmp = ((float)fabs((double)*(float *)&wop));
3051 result = (uword64)*(unsigned int *)&tmp;
3052 }
3053 break;
3054 case fmt_double:
3055 {
3056 double tmp = (fabs(*(double *)&op));
3057 result = *(uword64 *)&tmp;
3058 }
3059 }
3060
3061 return(result);
3062}
3063
e871dd18 3064static uword64
8bae0a0c 3065Negate(op,fmt)
e871dd18 3066 uword64 op;
8bae0a0c
JSC
3067 FP_formats fmt;
3068{
e871dd18 3069 uword64 result;
8bae0a0c
JSC
3070
3071#ifdef DEBUG
e871dd18 3072 printf("DBG: Negate: %s: op = 0x%08X%08X\n",DOFMT(fmt),WORD64HI(op),WORD64LO(op));
8bae0a0c
JSC
3073#endif /* DEBUG */
3074
3075 /* The format type should already have been checked: */
3076 switch (fmt) {
3077 case fmt_single:
3078 {
3079 unsigned int wop = (unsigned int)op;
3080 float tmp = ((float)0.0 - *(float *)&wop);
e871dd18 3081 result = (uword64)*(unsigned int *)&tmp;
8bae0a0c
JSC
3082 }
3083 break;
3084 case fmt_double:
3085 {
3086 double tmp = ((double)0.0 - *(double *)&op);
e871dd18 3087 result = *(uword64 *)&tmp;
8bae0a0c
JSC
3088 }
3089 break;
3090 }
3091
3092 return(result);
3093}
3094
e871dd18 3095static uword64
8bae0a0c 3096Add(op1,op2,fmt)
e871dd18
JSC
3097 uword64 op1;
3098 uword64 op2;
8bae0a0c
JSC
3099 FP_formats fmt;
3100{
e871dd18 3101 uword64 result;
8bae0a0c
JSC
3102
3103#ifdef DEBUG
e871dd18 3104 printf("DBG: Add: %s: op1 = 0x%08X%08X : op2 = 0x%08X%08X\n",DOFMT(fmt),WORD64HI(op1),WORD64LO(op1),WORD64HI(op2),WORD64LO(op2));
8bae0a0c
JSC
3105#endif /* DEBUG */
3106
e871dd18
JSC
3107 /* The registers must specify FPRs valid for operands of type
3108 "fmt". If they are not valid, the result is undefined. */
8bae0a0c
JSC
3109
3110 /* The format type should already have been checked: */
3111 switch (fmt) {
3112 case fmt_single:
3113 {
3114 unsigned int wop1 = (unsigned int)op1;
3115 unsigned int wop2 = (unsigned int)op2;
3116 float tmp = (*(float *)&wop1 + *(float *)&wop2);
e871dd18 3117 result = (uword64)*(unsigned int *)&tmp;
8bae0a0c
JSC
3118 }
3119 break;
3120 case fmt_double:
3121 {
3122 double tmp = (*(double *)&op1 + *(double *)&op2);
e871dd18 3123 result = *(uword64 *)&tmp;
8bae0a0c
JSC
3124 }
3125 break;
3126 }
3127
3128#ifdef DEBUG
e871dd18 3129 printf("DBG: Add: returning 0x%08X%08X (format = %s)\n",WORD64HI(result),WORD64LO(result),DOFMT(fmt));
8bae0a0c
JSC
3130#endif /* DEBUG */
3131
3132 return(result);
3133}
3134
e871dd18 3135static uword64
8bae0a0c 3136Sub(op1,op2,fmt)
e871dd18
JSC
3137 uword64 op1;
3138 uword64 op2;
8bae0a0c
JSC
3139 FP_formats fmt;
3140{
e871dd18 3141 uword64 result;
8bae0a0c
JSC
3142
3143#ifdef DEBUG
a9f7253f 3144 printf("DBG: Sub: %s: op1 = 0x%08X%08X : op2 = 0x%08X%08X\n",DOFMT(fmt),WORD64HI(op1),WORD64LO(op1),WORD64HI(op2),WORD64LO(op2));
8bae0a0c
JSC
3145#endif /* DEBUG */
3146
e871dd18
JSC
3147 /* The registers must specify FPRs valid for operands of type
3148 "fmt". If they are not valid, the result is undefined. */
8bae0a0c
JSC
3149
3150 /* The format type should already have been checked: */
3151 switch (fmt) {
3152 case fmt_single:
3153 {
3154 unsigned int wop1 = (unsigned int)op1;
3155 unsigned int wop2 = (unsigned int)op2;
3156 float tmp = (*(float *)&wop1 - *(float *)&wop2);
e871dd18 3157 result = (uword64)*(unsigned int *)&tmp;
8bae0a0c
JSC
3158 }
3159 break;
3160 case fmt_double:
3161 {
3162 double tmp = (*(double *)&op1 - *(double *)&op2);
e871dd18 3163 result = *(uword64 *)&tmp;
8bae0a0c
JSC
3164 }
3165 break;
3166 }
3167
3168#ifdef DEBUG
e871dd18 3169 printf("DBG: Sub: returning 0x%08X%08X (format = %s)\n",WORD64HI(result),WORD64LO(result),DOFMT(fmt));
8bae0a0c
JSC
3170#endif /* DEBUG */
3171
3172 return(result);
3173}
3174
e871dd18 3175static uword64
8bae0a0c 3176Multiply(op1,op2,fmt)
e871dd18
JSC
3177 uword64 op1;
3178 uword64 op2;
8bae0a0c
JSC
3179 FP_formats fmt;
3180{
e871dd18 3181 uword64 result;
8bae0a0c
JSC
3182
3183#ifdef DEBUG
e871dd18 3184 printf("DBG: Multiply: %s: op1 = 0x%08X%08X : op2 = 0x%08X%08X\n",DOFMT(fmt),WORD64HI(op1),WORD64LO(op1),WORD64HI(op2),WORD64LO(op2));
8bae0a0c
JSC
3185#endif /* DEBUG */
3186
e871dd18
JSC
3187 /* The registers must specify FPRs valid for operands of type
3188 "fmt". If they are not valid, the result is undefined. */
8bae0a0c
JSC
3189
3190 /* The format type should already have been checked: */
3191 switch (fmt) {
3192 case fmt_single:
3193 {
3194 unsigned int wop1 = (unsigned int)op1;
3195 unsigned int wop2 = (unsigned int)op2;
3196 float tmp = (*(float *)&wop1 * *(float *)&wop2);
e871dd18 3197 result = (uword64)*(unsigned int *)&tmp;
8bae0a0c
JSC
3198 }
3199 break;
3200 case fmt_double:
3201 {
3202 double tmp = (*(double *)&op1 * *(double *)&op2);
e871dd18 3203 result = *(uword64 *)&tmp;
8bae0a0c
JSC
3204 }
3205 break;
3206 }
3207
3208#ifdef DEBUG
e871dd18 3209 printf("DBG: Multiply: returning 0x%08X%08X (format = %s)\n",WORD64HI(result),WORD64LO(result),DOFMT(fmt));
8bae0a0c
JSC
3210#endif /* DEBUG */
3211
3212 return(result);
3213}
3214
e871dd18 3215static uword64
8bae0a0c 3216Divide(op1,op2,fmt)
e871dd18
JSC
3217 uword64 op1;
3218 uword64 op2;
8bae0a0c
JSC
3219 FP_formats fmt;
3220{
e871dd18 3221 uword64 result;
8bae0a0c
JSC
3222
3223#ifdef DEBUG
e871dd18 3224 printf("DBG: Divide: %s: op1 = 0x%08X%08X : op2 = 0x%08X%08X\n",DOFMT(fmt),WORD64HI(op1),WORD64LO(op1),WORD64HI(op2),WORD64LO(op2));
8bae0a0c
JSC
3225#endif /* DEBUG */
3226
e871dd18
JSC
3227 /* The registers must specify FPRs valid for operands of type
3228 "fmt". If they are not valid, the result is undefined. */
8bae0a0c
JSC
3229
3230 /* The format type should already have been checked: */
3231 switch (fmt) {
3232 case fmt_single:
3233 {
3234 unsigned int wop1 = (unsigned int)op1;
3235 unsigned int wop2 = (unsigned int)op2;
3236 float tmp = (*(float *)&wop1 / *(float *)&wop2);
e871dd18 3237 result = (uword64)*(unsigned int *)&tmp;
8bae0a0c
JSC
3238 }
3239 break;
3240 case fmt_double:
3241 {
3242 double tmp = (*(double *)&op1 / *(double *)&op2);
e871dd18 3243 result = *(uword64 *)&tmp;
8bae0a0c
JSC
3244 }
3245 break;
3246 }
3247
3248#ifdef DEBUG
e871dd18 3249 printf("DBG: Divide: returning 0x%08X%08X (format = %s)\n",WORD64HI(result),WORD64LO(result),DOFMT(fmt));
8bae0a0c
JSC
3250#endif /* DEBUG */
3251
3252 return(result);
3253}
3254
e871dd18 3255static uword64
8bae0a0c 3256Recip(op,fmt)
e871dd18 3257 uword64 op;
8bae0a0c
JSC
3258 FP_formats fmt;
3259{
e871dd18 3260 uword64 result;
8bae0a0c
JSC
3261
3262#ifdef DEBUG
e871dd18 3263 printf("DBG: Recip: %s: op = 0x%08X%08X\n",DOFMT(fmt),WORD64HI(op),WORD64LO(op));
8bae0a0c
JSC
3264#endif /* DEBUG */
3265
e871dd18
JSC
3266 /* The registers must specify FPRs valid for operands of type
3267 "fmt". If they are not valid, the result is undefined. */
8bae0a0c
JSC
3268
3269 /* The format type should already have been checked: */
3270 switch (fmt) {
3271 case fmt_single:
3272 {
3273 unsigned int wop = (unsigned int)op;
3274 float tmp = ((float)1.0 / *(float *)&wop);
e871dd18 3275 result = (uword64)*(unsigned int *)&tmp;
8bae0a0c
JSC
3276 }
3277 break;
3278 case fmt_double:
3279 {
3280 double tmp = ((double)1.0 / *(double *)&op);
e871dd18 3281 result = *(uword64 *)&tmp;
8bae0a0c
JSC
3282 }
3283 break;
3284 }
3285
3286#ifdef DEBUG
e871dd18 3287 printf("DBG: Recip: returning 0x%08X%08X (format = %s)\n",WORD64HI(result),WORD64LO(result),DOFMT(fmt));
8bae0a0c
JSC
3288#endif /* DEBUG */
3289
3290 return(result);
3291}
3292
e871dd18 3293static uword64
8bae0a0c 3294SquareRoot(op,fmt)
e871dd18 3295 uword64 op;
8bae0a0c
JSC
3296 FP_formats fmt;
3297{
e871dd18 3298 uword64 result;
8bae0a0c
JSC
3299
3300#ifdef DEBUG
e871dd18 3301 printf("DBG: SquareRoot: %s: op = 0x%08X%08X\n",DOFMT(fmt),WORD64HI(op),WORD64LO(op));
8bae0a0c
JSC
3302#endif /* DEBUG */
3303
e871dd18
JSC
3304 /* The registers must specify FPRs valid for operands of type
3305 "fmt". If they are not valid, the result is undefined. */
8bae0a0c
JSC
3306
3307 /* The format type should already have been checked: */
3308 switch (fmt) {
3309 case fmt_single:
3310 {
3311 unsigned int wop = (unsigned int)op;
3312 float tmp = ((float)sqrt((double)*(float *)&wop));
e871dd18 3313 result = (uword64)*(unsigned int *)&tmp;
8bae0a0c
JSC
3314 }
3315 break;
3316 case fmt_double:
3317 {
3318 double tmp = (sqrt(*(double *)&op));
e871dd18 3319 result = *(uword64 *)&tmp;
8bae0a0c
JSC
3320 }
3321 break;
3322 }
3323
3324#ifdef DEBUG
e871dd18 3325 printf("DBG: SquareRoot: returning 0x%08X%08X (format = %s)\n",WORD64HI(result),WORD64LO(result),DOFMT(fmt));
8bae0a0c
JSC
3326#endif /* DEBUG */
3327
3328 return(result);
3329}
3330
e871dd18 3331static uword64
8bae0a0c
JSC
3332Convert(rm,op,from,to)
3333 int rm;
e871dd18 3334 uword64 op;
8bae0a0c
JSC
3335 FP_formats from;
3336 FP_formats to;
3337{
e871dd18 3338 uword64 result;
8bae0a0c
JSC
3339
3340#ifdef DEBUG
e871dd18 3341 printf("DBG: Convert: mode %s : op 0x%08X%08X : from %s : to %s : (PC = 0x%08X%08X)\n",RMMODE(rm),WORD64HI(op),WORD64LO(op),DOFMT(from),DOFMT(to),WORD64HI(IPC),WORD64LO(IPC));
8bae0a0c
JSC
3342#endif /* DEBUG */
3343
3344 /* The value "op" is converted to the destination format, rounding
3345 using mode "rm". When the destination is a fixed-point format,
3346 then a source value of Infinity, NaN or one which would round to
3347 an integer outside the fixed point range then an IEEE Invalid
3348 Operation condition is raised. */
3349 switch (to) {
3350 case fmt_single:
3351 {
3352 float tmp;
3353 switch (from) {
3354 case fmt_double:
3355 tmp = (float)(*(double *)&op);
3356 break;
3357
3358 case fmt_word:
3359 tmp = (float)((int)(op & 0xFFFFFFFF));
3360 break;
3361
3362 case fmt_long:
3363 tmp = (float)((int)op);
3364 break;
3365 }
3366
3367 switch (rm) {
3368 case FP_RM_NEAREST:
e871dd18
JSC
3369 /* Round result to nearest representable value. When two
3370 representable values are equally near, round to the value
3371 that has a least significant bit of zero (i.e. is even). */
4fa134be 3372#ifdef HAVE_ANINT
e871dd18 3373 tmp = (float)anint((double)tmp);
d0757082
JSC
3374#else
3375 /* TODO: Provide round-to-nearest */
3376#endif
8bae0a0c
JSC
3377 break;
3378
3379 case FP_RM_TOZERO:
e871dd18
JSC
3380 /* Round result to the value closest to, and not greater in
3381 magnitude than, the result. */
4fa134be 3382#ifdef HAVE_AINT
e871dd18 3383 tmp = (float)aint((double)tmp);
d0757082
JSC
3384#else
3385 /* TODO: Provide round-to-zero */
3386#endif
8bae0a0c
JSC
3387 break;
3388
3389 case FP_RM_TOPINF:
e871dd18
JSC
3390 /* Round result to the value closest to, and not less than,
3391 the result. */
3392 tmp = (float)ceil((double)tmp);
8bae0a0c
JSC
3393 break;
3394
3395 case FP_RM_TOMINF:
e871dd18
JSC
3396 /* Round result to the value closest to, and not greater than,
3397 the result. */
3398 tmp = (float)floor((double)tmp);
8bae0a0c
JSC
3399 break;
3400 }
e871dd18 3401 result = (uword64)*(unsigned int *)&tmp;
8bae0a0c
JSC
3402 }
3403 break;
3404
3405 case fmt_double:
3406 {
3407 double tmp;
f24b7b69 3408 word64 xxx;
8bae0a0c
JSC
3409
3410 switch (from) {
3411 case fmt_single:
3412 {
3413 unsigned int wop = (unsigned int)op;
3414 tmp = (double)(*(float *)&wop);
3415 }
3416 break;
3417
3418 case fmt_word:
f24b7b69
JSC
3419 xxx = SIGNEXTEND((op & 0xFFFFFFFF),32);
3420 tmp = xxx;
8bae0a0c
JSC
3421 break;
3422
3423 case fmt_long:
e871dd18 3424 tmp = (double)((word64)op);
8bae0a0c
JSC
3425 break;
3426 }
e871dd18 3427
8bae0a0c
JSC
3428 switch (rm) {
3429 case FP_RM_NEAREST:
4fa134be 3430#ifdef HAVE_ANINT
e871dd18 3431 tmp = anint(*(double *)&tmp);
d0757082
JSC
3432#else
3433 /* TODO: Provide round-to-nearest */
3434#endif
8bae0a0c
JSC
3435 break;
3436
3437 case FP_RM_TOZERO:
4fa134be 3438#ifdef HAVE_AINT
e871dd18 3439 tmp = aint(*(double *)&tmp);
d0757082
JSC
3440#else
3441 /* TODO: Provide round-to-zero */
3442#endif
8bae0a0c
JSC
3443 break;
3444
3445 case FP_RM_TOPINF:
3446 tmp = ceil(*(double *)&tmp);
3447 break;
3448
3449 case FP_RM_TOMINF:
3450 tmp = floor(*(double *)&tmp);
3451 break;
3452 }
e871dd18 3453 result = *(uword64 *)&tmp;
8bae0a0c
JSC
3454 }
3455 break;
3456
3457 case fmt_word:
3458 case fmt_long:
3459 if (Infinity(op,from) || NaN(op,from) || (1 == 0/*TODO: check range */)) {
3460 printf("DBG: TODO: update FCSR\n");
3461 SignalException(FPE);
3462 } else {
3463 if (to == fmt_word) {
3464 unsigned int tmp;
3465 switch (from) {
3466 case fmt_single:
3467 {
3468 unsigned int wop = (unsigned int)op;
3469 tmp = (unsigned int)*((float *)&wop);
3470 }
3471 break;
3472 case fmt_double:
3473 tmp = (unsigned int)*((double *)&op);
3474#ifdef DEBUG
e871dd18 3475 printf("DBG: from double %.30f (0x%08X%08X) to word: 0x%08X\n",*((double *)&op),WORD64HI(op),WORD64LO(op),tmp);
8bae0a0c
JSC
3476#endif /* DEBUG */
3477 break;
3478 }
e871dd18 3479 result = (uword64)tmp;
8bae0a0c
JSC
3480 } else { /* fmt_long */
3481 switch (from) {
3482 case fmt_single:
3483 {
3484 unsigned int wop = (unsigned int)op;
e871dd18 3485 result = (uword64)*((float *)&wop);
8bae0a0c
JSC
3486 }
3487 break;
3488 case fmt_double:
e871dd18 3489 result = (uword64)*((double *)&op);
8bae0a0c
JSC
3490 break;
3491 }
3492 }
3493 }
3494 break;
3495 }
3496
3497#ifdef DEBUG
e871dd18 3498 printf("DBG: Convert: returning 0x%08X%08X (to format = %s)\n",WORD64HI(result),WORD64LO(result),DOFMT(to));
8bae0a0c
JSC
3499#endif /* DEBUG */
3500
3501 return(result);
3502}
3503#endif /* HASFPU */
3504
3505/*-- co-processor support routines ------------------------------------------*/
3506
3507static int
3508CoProcPresent(coproc_number)
3509 unsigned int coproc_number;
3510{
3511 /* Return TRUE if simulator provides a model for the given co-processor number */
3512 return(0);
3513}
3514
3515static void
3516COP_LW(coproc_num,coproc_reg,memword)
3517 int coproc_num, coproc_reg;
3518 unsigned int memword;
3519{
3520 switch (coproc_num) {
3521#if defined(HASFPU)
3522 case 1:
3523#ifdef DEBUG
e871dd18 3524 printf("DBG: COP_LW: memword = 0x%08X (uword64)memword = 0x%08X%08X\n",memword,WORD64HI(memword),WORD64LO(memword));
8bae0a0c 3525#endif
e871dd18 3526 StoreFPR(coproc_reg,fmt_uninterpreted,(uword64)memword);
8bae0a0c
JSC
3527 break;
3528#endif /* HASFPU */
3529
3530 default:
f24b7b69 3531#if 0 /* this should be controlled by a configuration option */
e871dd18 3532 callback->printf_filtered(callback,"COP_LW(%d,%d,0x%08X) at IPC = 0x%08X%08X : TODO (architecture specific)\n",coproc_num,coproc_reg,memword,WORD64HI(IPC),WORD64LO(IPC));
f24b7b69 3533#endif
8bae0a0c
JSC
3534 break;
3535 }
3536
3537 return;
3538}
3539
3540static void
3541COP_LD(coproc_num,coproc_reg,memword)
3542 int coproc_num, coproc_reg;
e871dd18 3543 uword64 memword;
8bae0a0c
JSC
3544{
3545 switch (coproc_num) {
3546#if defined(HASFPU)
3547 case 1:
3548 StoreFPR(coproc_reg,fmt_uninterpreted,memword);
3549 break;
3550#endif /* HASFPU */
3551
3552 default:
f24b7b69 3553#if 0 /* this message should be controlled by a configuration option */
e871dd18 3554 callback->printf_filtered(callback,"COP_LD(%d,%d,0x%08X%08X) at IPC = 0x%08X%08X : TODO (architecture specific)\n",coproc_num,coproc_reg,WORD64HI(memword),WORD64LO(memword),WORD64HI(IPC),WORD64LO(IPC));
f24b7b69 3555#endif
8bae0a0c
JSC
3556 break;
3557 }
3558
3559 return;
3560}
3561
3562static unsigned int
3563COP_SW(coproc_num,coproc_reg)
3564 int coproc_num, coproc_reg;
3565{
3566 unsigned int value = 0;
3567 switch (coproc_num) {
3568#if defined(HASFPU)
3569 case 1:
3570#if 1
3571 value = (unsigned int)ValueFPR(coproc_reg,fmt_uninterpreted);
3572#else
3573#if 1
3574 value = (unsigned int)ValueFPR(coproc_reg,fpr_state[coproc_reg]);
3575#else
3576#ifdef DEBUG
3577 printf("DBG: COP_SW: reg in format %s (will be accessing as single)\n",DOFMT(fpr_state[coproc_reg]));
3578#endif /* DEBUG */
3579 value = (unsigned int)ValueFPR(coproc_reg,fmt_single);
3580#endif
3581#endif
3582 break;
3583#endif /* HASFPU */
3584
3585 default:
f24b7b69 3586#if 0 /* should be controlled by configuration option */
e871dd18 3587 callback->printf_filtered(callback,"COP_SW(%d,%d) at IPC = 0x%08X%08X : TODO (architecture specific)\n",coproc_num,coproc_reg,WORD64HI(IPC),WORD64LO(IPC));
f24b7b69 3588#endif
8bae0a0c
JSC
3589 break;
3590 }
3591
3592 return(value);
3593}
3594
e871dd18 3595static uword64
8bae0a0c
JSC
3596COP_SD(coproc_num,coproc_reg)
3597 int coproc_num, coproc_reg;
3598{
e871dd18 3599 uword64 value = 0;
8bae0a0c
JSC
3600 switch (coproc_num) {
3601#if defined(HASFPU)
3602 case 1:
3603#if 1
3604 value = ValueFPR(coproc_reg,fmt_uninterpreted);
3605#else
3606#if 1
3607 value = ValueFPR(coproc_reg,fpr_state[coproc_reg]);
3608#else
3609#ifdef DEBUG
3610 printf("DBG: COP_SD: reg in format %s (will be accessing as double)\n",DOFMT(fpr_state[coproc_reg]));
3611#endif /* DEBUG */
3612 value = ValueFPR(coproc_reg,fmt_double);
3613#endif
3614#endif
3615 break;
3616#endif /* HASFPU */
3617
3618 default:
f24b7b69 3619#if 0 /* should be controlled by configuration option */
e871dd18 3620 callback->printf_filtered(callback,"COP_SD(%d,%d) at IPC = 0x%08X%08X : TODO (architecture specific)\n",coproc_num,coproc_reg,WORD64HI(IPC),WORD64LO(IPC));
f24b7b69 3621#endif
8bae0a0c
JSC
3622 break;
3623 }
3624
3625 return(value);
3626}
3627
3628static void
3629decode_coproc(instruction)
3630 unsigned int instruction;
3631{
3632 int coprocnum = ((instruction >> 26) & 3);
3633
3634 switch (coprocnum) {
3635 case 0: /* standard CPU control and cache registers */
3636 {
3637 /* NOTEs:
3638 Standard CP0 registers
3639 0 = Index R4000 VR4100 VR4300
3640 1 = Random R4000 VR4100 VR4300
3641 2 = EntryLo0 R4000 VR4100 VR4300
3642 3 = EntryLo1 R4000 VR4100 VR4300
3643 4 = Context R4000 VR4100 VR4300
3644 5 = PageMask R4000 VR4100 VR4300
3645 6 = Wired R4000 VR4100 VR4300
3646 8 = BadVAddr R4000 VR4100 VR4300
3647 9 = Count R4000 VR4100 VR4300
3648 10 = EntryHi R4000 VR4100 VR4300
3649 11 = Compare R4000 VR4100 VR4300
3650 12 = SR R4000 VR4100 VR4300
3651 13 = Cause R4000 VR4100 VR4300
3652 14 = EPC R4000 VR4100 VR4300
3653 15 = PRId R4000 VR4100 VR4300
3654 16 = Config R4000 VR4100 VR4300
3655 17 = LLAddr R4000 VR4100 VR4300
3656 18 = WatchLo R4000 VR4100 VR4300
3657 19 = WatchHi R4000 VR4100 VR4300
3658 20 = XContext R4000 VR4100 VR4300
3659 26 = PErr or ECC R4000 VR4100 VR4300
3660 27 = CacheErr R4000 VR4100
3661 28 = TagLo R4000 VR4100 VR4300
3662 29 = TagHi R4000 VR4100 VR4300
3663 30 = ErrorEPC R4000 VR4100 VR4300
3664 */
3665 int code = ((instruction >> 21) & 0x1F);
3666 /* R4000 Users Manual (second edition) lists the following CP0
3667 instructions:
3668 DMFC0 Doubleword Move From CP0 (VR4100 = 01000000001tttttddddd00000000000)
3669 DMTC0 Doubleword Move To CP0 (VR4100 = 01000000101tttttddddd00000000000)
3670 MFC0 word Move From CP0 (VR4100 = 01000000000tttttddddd00000000000)
3671 MTC0 word Move To CP0 (VR4100 = 01000000100tttttddddd00000000000)
3672 TLBR Read Indexed TLB Entry (VR4100 = 01000010000000000000000000000001)
3673 TLBWI Write Indexed TLB Entry (VR4100 = 01000010000000000000000000000010)
3674 TLBWR Write Random TLB Entry (VR4100 = 01000010000000000000000000000110)
3675 TLBP Probe TLB for Matching Entry (VR4100 = 01000010000000000000000000001000)
3676 CACHE Cache operation (VR4100 = 101111bbbbbpppppiiiiiiiiiiiiiiii)
3677 ERET Exception return (VR4100 = 01000010000000000000000000011000)
3678 */
3679 if (((code == 0x00) || (code == 0x04)) && ((instruction & 0x7FF) == 0)) {
3680 int rt = ((instruction >> 16) & 0x1F);
3681 int rd = ((instruction >> 11) & 0x1F);
3682 if (code == 0x00) { /* MF : move from */
f24b7b69 3683#if 0 /* message should be controlled by configuration option */
8bae0a0c 3684 callback->printf_filtered(callback,"Warning: MFC0 %d,%d not handled yet (architecture specific)\n",rt,rd);
f24b7b69 3685#endif
8bae0a0c
JSC
3686 GPR[rt] = 0xDEADC0DE; /* CPR[0,rd] */
3687 } else { /* MT : move to */
3688 /* CPR[0,rd] = GPR[rt]; */
f24b7b69 3689#if 0 /* should be controlled by configuration option */
8bae0a0c 3690 callback->printf_filtered(callback,"Warning: MTC0 %d,%d not handled yet (architecture specific)\n",rt,rd);
f24b7b69 3691#endif
8bae0a0c
JSC
3692 }
3693 } else
f24b7b69 3694 sim_warning("Unrecognised COP0 instruction 0x%08X at IPC = 0x%08X%08X : No handler present",instruction,WORD64HI(IPC),WORD64LO(IPC));
e871dd18 3695 /* TODO: When executing an ERET or RFE instruction we should
8bae0a0c
JSC
3696 clear LLBIT, to ensure that any out-standing atomic
3697 read/modify/write sequence fails. */
3698 }
3699 break;
3700
3701 case 2: /* undefined co-processor */
f24b7b69 3702 sim_warning("COP2 instruction 0x%08X at IPC = 0x%08X%08X : No handler present",instruction,WORD64HI(IPC),WORD64LO(IPC));
8bae0a0c
JSC
3703 break;
3704
3705 case 1: /* should not occur (FPU co-processor) */
3706 case 3: /* should not occur (FPU co-processor) */
3707 SignalException(ReservedInstruction,instruction);
3708 break;
3709 }
3710
3711 return;
3712}
3713
3714/*-- instruction simulation -------------------------------------------------*/
3715
3716static void
3717simulate ()
3718{
3719 unsigned int pipeline_count = 1;
3720
3721#ifdef DEBUG
3722 if (membank == NULL) {
3723 printf("DBG: simulate() entered with no memory\n");
3724 exit(1);
3725 }
3726#endif /* DEBUG */
3727
3728#if 0 /* Disabled to check that everything works OK */
3729 /* The VR4300 seems to sign-extend the PC on its first
3730 access. However, this may just be because it is currently
3731 configured in 32bit mode. However... */
3732 PC = SIGNEXTEND(PC,32);
3733#endif
3734
3735 /* main controlling loop */
3736 do {
3737 /* Fetch the next instruction from the simulator memory: */
e871dd18
JSC
3738 uword64 vaddr = (uword64)PC;
3739 uword64 paddr;
8bae0a0c
JSC
3740 int cca;
3741 unsigned int instruction;
3742 int dsstate = (state & simDELAYSLOT);
3743
3744#ifdef DEBUG
3745 {
3746 printf("DBG: state = 0x%08X :",state);
3747 if (state & simSTOP) printf(" simSTOP");
3748 if (state & simSTEP) printf(" simSTEP");
3749 if (state & simHALTEX) printf(" simHALTEX");
3750 if (state & simHALTIN) printf(" simHALTIN");
3751 if (state & simBE) printf(" simBE");
3752 }
3753#endif /* DEBUG */
3754
3755#ifdef DEBUG
3756 if (dsstate)
e871dd18 3757 callback->printf_filtered(callback,"DBG: DSPC = 0x%08X%08X\n",WORD64HI(DSPC),WORD64LO(DSPC));
8bae0a0c
JSC
3758#endif /* DEBUG */
3759
3760 if (AddressTranslation(PC,isINSTRUCTION,isLOAD,&paddr,&cca,isTARGET,isREAL)) { /* Copy the action of the LW instruction */
f24b7b69
JSC
3761 unsigned int reverse = (ReverseEndian ? (LOADDRMASK >> 2) : 0);
3762 unsigned int bigend = (BigEndianCPU ? (LOADDRMASK >> 2) : 0);
e871dd18 3763 uword64 value;
8bae0a0c 3764 unsigned int byte;
f24b7b69 3765 paddr = ((paddr & ~LOADDRMASK) | ((paddr & LOADDRMASK) ^ (reverse << 2)));
8bae0a0c 3766 value = LoadMemory(cca,AccessLength_WORD,paddr,vaddr,isINSTRUCTION,isREAL);
f24b7b69 3767 byte = ((vaddr & LOADDRMASK) ^ (bigend << 2));
8bae0a0c
JSC
3768 instruction = ((value >> (8 * byte)) & 0xFFFFFFFF);
3769 } else {
e871dd18 3770 fprintf(stderr,"Cannot translate address for PC = 0x%08X%08X failed\n",WORD64HI(PC),WORD64LO(PC));
8bae0a0c
JSC
3771 exit(1);
3772 }
3773
3774#ifdef DEBUG
e871dd18 3775 callback->printf_filtered(callback,"DBG: fetched 0x%08X from PC = 0x%08X%08X\n",instruction,WORD64HI(PC),WORD64LO(PC));
8bae0a0c
JSC
3776#endif /* DEBUG */
3777
3778#if !defined(FASTSIM) || defined(PROFILE)
3779 instruction_fetches++;
a9f7253f
JSC
3780 /* Since we increment above, the value should only ever be zero if
3781 we have just overflowed: */
3782 if (instruction_fetches == 0)
3783 instruction_fetch_overflow++;
8bae0a0c
JSC
3784#if defined(PROFILE)
3785 if ((state & simPROFILE) && ((instruction_fetches % profile_frequency) == 0) && profile_hist) {
3786 int n = ((unsigned int)(PC - profile_minpc) >> (profile_shift + 2));
3787 if (n < profile_nsamples) {
3788 /* NOTE: The counts for the profiling bins are only 16bits wide */
3789 if (profile_hist[n] != USHRT_MAX)
3790 (profile_hist[n])++;
3791 }
3792 }
3793#endif /* PROFILE */
3794#endif /* !FASTSIM && PROFILE */
3795
3796 IPC = PC; /* copy PC for this instruction */
3797 /* This is required by exception processing, to ensure that we can
3798 cope with exceptions in the delay slots of branches that may
3799 already have changed the PC. */
3800 PC += 4; /* increment ready for the next fetch */
3801 /* NOTE: If we perform a delay slot change to the PC, this
3802 increment is not requuired. However, it would make the
3803 simulator more complicated to try and avoid this small hit. */
3804
3805 /* Currently this code provides a simple model. For more
3806 complicated models we could perform exception status checks at
3807 this point, and set the simSTOP state as required. This could
3808 also include processing any hardware interrupts raised by any
3809 I/O model attached to the simulator context.
3810
3811 Support for "asynchronous" I/O events within the simulated world
3812 could be providing by managing a counter, and calling a I/O
3813 specific handler when a particular threshold is reached. On most
3814 architectures a decrement and check for zero operation is
3815 usually quicker than an increment and compare. However, the
3816 process of managing a known value decrement to zero, is higher
3817 than the cost of using an explicit value UINT_MAX into the
3818 future. Which system is used will depend on how complicated the
3819 I/O model is, and how much it is likely to affect the simulator
3820 bandwidth.
3821
3822 If events need to be scheduled further in the future than
3823 UINT_MAX event ticks, then the I/O model should just provide its
3824 own counter, triggered from the event system. */
3825
3826 /* MIPS pipeline ticks. To allow for future support where the
3827 pipeline hit of individual instructions is known, this control
3828 loop manages a "pipeline_count" variable. It is initialised to
3829 1 (one), and will only be changed by the simulator engine when
3830 executing an instruction. If the engine does not have access to
3831 pipeline cycle count information then all instructions will be
3832 treated as using a single cycle. NOTE: A standard system is not
3833 provided by the default simulator because different MIPS
3834 architectures have different cycle counts for the same
3835 instructions. */
3836
3837#if defined(HASFPU)
3838 /* Set previous flag, depending on current: */
3839 if (state & simPCOC0)
3840 state |= simPCOC1;
3841 else
3842 state &= ~simPCOC1;
3843 /* and update the current value: */
3844 if (GETFCC(0))
3845 state |= simPCOC0;
3846 else
3847 state &= ~simPCOC0;
3848#endif /* HASFPU */
3849
3850/* NOTE: For multi-context simulation environments the "instruction"
3851 variable should be local to this routine. */
3852
3853/* Shorthand accesses for engine. Note: If we wanted to use global
3854 variables (and a single-threaded simulator engine), then we can
3855 create the actual variables with these names. */
3856
3857 if (!(state & simSKIPNEXT)) {
3858 /* Include the simulator engine */
3859#include "engine.c"
f24b7b69 3860#if ((GPRLEN == 64) && !PROCESSOR_64BIT) || ((GPRLEN == 32) && PROCESSOR_64BIT)
8bae0a0c
JSC
3861#error "Mismatch between run-time simulator code and simulation engine"
3862#endif
3863
3864#if defined(WARN_LOHI)
3865 /* Decrement the HI/LO validity ticks */
3866 if (HIACCESS > 0)
3867 HIACCESS--;
3868 if (LOACCESS > 0)
3869 LOACCESS--;
3870#endif /* WARN_LOHI */
3871
3872#if defined(WARN_ZERO)
3873 /* For certain MIPS architectures, GPR[0] is hardwired to zero. We
3874 should check for it being changed. It is better doing it here,
3875 than within the simulator, since it will help keep the simulator
3876 small. */
3877 if (ZERO != 0) {
f24b7b69 3878 sim_warning("The ZERO register has been updated with 0x%08X%08X (PC = 0x%08X%08X) (reset back to zero)",WORD64HI(ZERO),WORD64LO(ZERO),WORD64HI(IPC),WORD64LO(IPC));
8bae0a0c
JSC
3879 ZERO = 0; /* reset back to zero before next instruction */
3880 }
3881#endif /* WARN_ZERO */
3882 } else /* simSKIPNEXT check */
3883 state &= ~simSKIPNEXT;
3884
3885 /* If the delay slot was active before the instruction is
3886 executed, then update the PC to its new value: */
3887 if (dsstate) {
3888#ifdef DEBUG
e871dd18 3889 printf("DBG: dsstate set before instruction execution - updating PC to 0x%08X%08X\n",WORD64HI(DSPC),WORD64LO(DSPC));
8bae0a0c
JSC
3890#endif /* DEBUG */
3891 PC = DSPC;
3892 state &= ~simDELAYSLOT;
3893 }
3894
3895 if (MIPSISA < 4) { /* The following is only required on pre MIPS IV processors: */
3896 /* Deal with pending register updates: */
3897#ifdef DEBUG
3898 printf("DBG: EMPTY BEFORE pending_in = %d, pending_out = %d, pending_total = %d\n",pending_in,pending_out,pending_total);
3899#endif /* DEBUG */
3900 if (pending_out != pending_in) {
3901 int loop;
3902 int index = pending_out;
3903 int total = pending_total;
3904 if (pending_total == 0) {
3905 fprintf(stderr,"FATAL: Mis-match on pending update pointers\n");
3906 exit(1);
3907 }
3908 for (loop = 0; (loop < total); loop++) {
3909#ifdef DEBUG
3910 printf("DBG: BEFORE index = %d, loop = %d\n",index,loop);
3911#endif /* DEBUG */
3912 if (pending_slot_reg[index] != (LAST_EMBED_REGNUM + 1)) {
3913#ifdef DEBUG
3914 printf("pending_slot_count[%d] = %d\n",index,pending_slot_count[index]);
3915#endif /* DEBUG */
3916 if (--(pending_slot_count[index]) == 0) {
3917#ifdef DEBUG
3918 printf("pending_slot_reg[%d] = %d\n",index,pending_slot_reg[index]);
e871dd18 3919 printf("pending_slot_value[%d] = 0x%08X%08X\n",index,WORD64HI(pending_slot_value[index]),WORD64LO(pending_slot_value[index]));
8bae0a0c
JSC
3920#endif /* DEBUG */
3921 if (pending_slot_reg[index] == COCIDX) {
3922 SETFCC(0,((FCR31 & (1 << 23)) ? 1 : 0));
3923 } else {
3924 registers[pending_slot_reg[index]] = pending_slot_value[index];
3925#if defined(HASFPU)
3926 /* The only time we have PENDING updates to FPU
3927 registers, is when performing binary transfers. This
3928 means we should update the register type field. */
3929 if ((pending_slot_reg[index] >= FGRIDX) && (pending_slot_reg[index] < (FGRIDX + 32)))
3930 fpr_state[pending_slot_reg[index]] = fmt_uninterpreted;
3931#endif /* HASFPU */
3932 }
3933#ifdef DEBUG
e871dd18 3934 printf("registers[%d] = 0x%08X%08X\n",pending_slot_reg[index],WORD64HI(registers[pending_slot_reg[index]]),WORD64LO(registers[pending_slot_reg[index]]));
8bae0a0c
JSC
3935#endif /* DEBUG */
3936 pending_slot_reg[index] = (LAST_EMBED_REGNUM + 1);
3937 pending_out++;
3938 if (pending_out == PSLOTS)
3939 pending_out = 0;
3940 pending_total--;
3941 }
3942 }
3943#ifdef DEBUG
3944 printf("DBG: AFTER index = %d, loop = %d\n",index,loop);
3945#endif /* DEBUG */
3946 index++;
3947 if (index == PSLOTS)
3948 index = 0;
3949 }
3950 }
3951#ifdef DEBUG
3952 printf("DBG: EMPTY AFTER pending_in = %d, pending_out = %d, pending_total = %d\n",pending_in,pending_out,pending_total);
3953#endif /* DEBUG */
3954 }
3955
3956#if !defined(FASTSIM)
3957 pipeline_ticks += pipeline_count;
3958#endif /* FASTSIM */
3959
3960 if (state & simSTEP)
3961 state |= simSTOP;
3962 } while (!(state & simSTOP));
3963
3964#ifdef DEBUG
3965 if (membank == NULL) {
3966 printf("DBG: simulate() LEAVING with no memory\n");
3967 exit(1);
3968 }
3969#endif /* DEBUG */
3970
3971 return;
3972}
3973
3974/*---------------------------------------------------------------------------*/
3975/*> EOF interp.c <*/
This page took 0.200561 seconds and 4 git commands to generate.