1 |
330 |
jeremybenn |
/*> 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 |
|
|
NOTEs:
|
17 |
|
|
|
18 |
|
|
The IDT monitor (found on the VR4300 board), seems to lie about
|
19 |
|
|
register contents. It seems to treat the registers as sign-extended
|
20 |
|
|
32-bit values. This cause *REAL* problems when single-stepping 64-bit
|
21 |
|
|
code on the hardware.
|
22 |
|
|
|
23 |
|
|
*/
|
24 |
|
|
|
25 |
|
|
/* The TRACE manifests enable the provision of extra features. If they
|
26 |
|
|
are not defined then a simpler (quicker) simulator is constructed
|
27 |
|
|
without the required run-time checks, etc. */
|
28 |
|
|
#if 1 /* 0 to allow user build selection, 1 to force inclusion */
|
29 |
|
|
#define TRACE (1)
|
30 |
|
|
#endif
|
31 |
|
|
|
32 |
|
|
#include "bfd.h"
|
33 |
|
|
#include "sim-main.h"
|
34 |
|
|
#include "sim-utils.h"
|
35 |
|
|
#include "sim-options.h"
|
36 |
|
|
#include "sim-assert.h"
|
37 |
|
|
#include "sim-hw.h"
|
38 |
|
|
|
39 |
|
|
#include "itable.h"
|
40 |
|
|
|
41 |
|
|
|
42 |
|
|
#include "config.h"
|
43 |
|
|
|
44 |
|
|
#include <stdio.h>
|
45 |
|
|
#include <stdarg.h>
|
46 |
|
|
#include <ansidecl.h>
|
47 |
|
|
#include <ctype.h>
|
48 |
|
|
#include <limits.h>
|
49 |
|
|
#include <math.h>
|
50 |
|
|
#ifdef HAVE_STDLIB_H
|
51 |
|
|
#include <stdlib.h>
|
52 |
|
|
#endif
|
53 |
|
|
#ifdef HAVE_STRING_H
|
54 |
|
|
#include <string.h>
|
55 |
|
|
#else
|
56 |
|
|
#ifdef HAVE_STRINGS_H
|
57 |
|
|
#include <strings.h>
|
58 |
|
|
#endif
|
59 |
|
|
#endif
|
60 |
|
|
|
61 |
|
|
#include "getopt.h"
|
62 |
|
|
#include "libiberty.h"
|
63 |
|
|
#include "bfd.h"
|
64 |
|
|
#include "gdb/callback.h" /* GDB simulator callback interface */
|
65 |
|
|
#include "gdb/remote-sim.h" /* GDB simulator interface */
|
66 |
|
|
|
67 |
|
|
#ifndef PARAMS
|
68 |
|
|
#define PARAMS(x)
|
69 |
|
|
#endif
|
70 |
|
|
|
71 |
|
|
char* pr_addr PARAMS ((SIM_ADDR addr));
|
72 |
|
|
char* pr_uword64 PARAMS ((uword64 addr));
|
73 |
|
|
|
74 |
|
|
|
75 |
|
|
/* Within interp.c we refer to the sim_state and sim_cpu directly. */
|
76 |
|
|
#define CPU cpu
|
77 |
|
|
#define SD sd
|
78 |
|
|
|
79 |
|
|
|
80 |
|
|
/* The following reserved instruction value is used when a simulator
|
81 |
|
|
trap is required. NOTE: Care must be taken, since this value may be
|
82 |
|
|
used in later revisions of the MIPS ISA. */
|
83 |
|
|
|
84 |
|
|
#define RSVD_INSTRUCTION (0x00000005)
|
85 |
|
|
#define RSVD_INSTRUCTION_MASK (0xFC00003F)
|
86 |
|
|
|
87 |
|
|
#define RSVD_INSTRUCTION_ARG_SHIFT 6
|
88 |
|
|
#define RSVD_INSTRUCTION_ARG_MASK 0xFFFFF
|
89 |
|
|
|
90 |
|
|
|
91 |
|
|
/* Bits in the Debug register */
|
92 |
|
|
#define Debug_DBD 0x80000000 /* Debug Branch Delay */
|
93 |
|
|
#define Debug_DM 0x40000000 /* Debug Mode */
|
94 |
|
|
#define Debug_DBp 0x00000002 /* Debug Breakpoint indicator */
|
95 |
|
|
|
96 |
|
|
/*---------------------------------------------------------------------------*/
|
97 |
|
|
/*-- GDB simulator interface ------------------------------------------------*/
|
98 |
|
|
/*---------------------------------------------------------------------------*/
|
99 |
|
|
|
100 |
|
|
static void ColdReset PARAMS((SIM_DESC sd));
|
101 |
|
|
|
102 |
|
|
/*---------------------------------------------------------------------------*/
|
103 |
|
|
|
104 |
|
|
|
105 |
|
|
|
106 |
|
|
#define DELAYSLOT() {\
|
107 |
|
|
if (STATE & simDELAYSLOT)\
|
108 |
|
|
sim_io_eprintf(sd,"Delay slot already activated (branch in delay slot?)\n");\
|
109 |
|
|
STATE |= simDELAYSLOT;\
|
110 |
|
|
}
|
111 |
|
|
|
112 |
|
|
#define JALDELAYSLOT() {\
|
113 |
|
|
DELAYSLOT ();\
|
114 |
|
|
STATE |= simJALDELAYSLOT;\
|
115 |
|
|
}
|
116 |
|
|
|
117 |
|
|
#define NULLIFY() {\
|
118 |
|
|
STATE &= ~simDELAYSLOT;\
|
119 |
|
|
STATE |= simSKIPNEXT;\
|
120 |
|
|
}
|
121 |
|
|
|
122 |
|
|
#define CANCELDELAYSLOT() {\
|
123 |
|
|
DSSTATE = 0;\
|
124 |
|
|
STATE &= ~(simDELAYSLOT | simJALDELAYSLOT);\
|
125 |
|
|
}
|
126 |
|
|
|
127 |
|
|
#define INDELAYSLOT() ((STATE & simDELAYSLOT) != 0)
|
128 |
|
|
#define INJALDELAYSLOT() ((STATE & simJALDELAYSLOT) != 0)
|
129 |
|
|
|
130 |
|
|
/* Note that the monitor code essentially assumes this layout of memory.
|
131 |
|
|
If you change these, change the monitor code, too. */
|
132 |
|
|
/* FIXME Currently addresses are truncated to 32-bits, see
|
133 |
|
|
mips/sim-main.c:address_translation(). If that changes, then these
|
134 |
|
|
values will need to be extended, and tested for more carefully. */
|
135 |
|
|
#define K0BASE (0x80000000)
|
136 |
|
|
#define K0SIZE (0x20000000)
|
137 |
|
|
#define K1BASE (0xA0000000)
|
138 |
|
|
#define K1SIZE (0x20000000)
|
139 |
|
|
|
140 |
|
|
/* Simple run-time monitor support.
|
141 |
|
|
|
142 |
|
|
We emulate the monitor by placing magic reserved instructions at
|
143 |
|
|
the monitor's entry points; when we hit these instructions, instead
|
144 |
|
|
of raising an exception (as we would normally), we look at the
|
145 |
|
|
instruction and perform the appropriate monitory operation.
|
146 |
|
|
|
147 |
|
|
`*_monitor_base' are the physical addresses at which the corresponding
|
148 |
|
|
monitor vectors are located. `0' means none. By default,
|
149 |
|
|
install all three.
|
150 |
|
|
The RSVD_INSTRUCTION... macros specify the magic instructions we
|
151 |
|
|
use at the monitor entry points. */
|
152 |
|
|
static int firmware_option_p = 0;
|
153 |
|
|
static SIM_ADDR idt_monitor_base = 0xBFC00000;
|
154 |
|
|
static SIM_ADDR pmon_monitor_base = 0xBFC00500;
|
155 |
|
|
static SIM_ADDR lsipmon_monitor_base = 0xBFC00200;
|
156 |
|
|
|
157 |
|
|
static SIM_RC sim_firmware_command (SIM_DESC sd, char* arg);
|
158 |
|
|
|
159 |
|
|
|
160 |
|
|
#define MEM_SIZE (8 << 20) /* 8 MBytes */
|
161 |
|
|
|
162 |
|
|
|
163 |
|
|
#if defined(TRACE)
|
164 |
|
|
static char *tracefile = "trace.din"; /* default filename for trace log */
|
165 |
|
|
FILE *tracefh = NULL;
|
166 |
|
|
static void open_trace PARAMS((SIM_DESC sd));
|
167 |
|
|
#endif /* TRACE */
|
168 |
|
|
|
169 |
|
|
static const char * get_insn_name (sim_cpu *, int);
|
170 |
|
|
|
171 |
|
|
/* simulation target board. NULL=canonical */
|
172 |
|
|
static char* board = NULL;
|
173 |
|
|
|
174 |
|
|
|
175 |
|
|
static DECLARE_OPTION_HANDLER (mips_option_handler);
|
176 |
|
|
|
177 |
|
|
enum {
|
178 |
|
|
OPTION_DINERO_TRACE = OPTION_START,
|
179 |
|
|
OPTION_DINERO_FILE,
|
180 |
|
|
OPTION_FIRMWARE,
|
181 |
|
|
OPTION_INFO_MEMORY,
|
182 |
|
|
OPTION_BOARD
|
183 |
|
|
};
|
184 |
|
|
|
185 |
|
|
static int display_mem_info = 0;
|
186 |
|
|
|
187 |
|
|
static SIM_RC
|
188 |
|
|
mips_option_handler (sd, cpu, opt, arg, is_command)
|
189 |
|
|
SIM_DESC sd;
|
190 |
|
|
sim_cpu *cpu;
|
191 |
|
|
int opt;
|
192 |
|
|
char *arg;
|
193 |
|
|
int is_command;
|
194 |
|
|
{
|
195 |
|
|
int cpu_nr;
|
196 |
|
|
switch (opt)
|
197 |
|
|
{
|
198 |
|
|
case OPTION_DINERO_TRACE: /* ??? */
|
199 |
|
|
#if defined(TRACE)
|
200 |
|
|
/* Eventually the simTRACE flag could be treated as a toggle, to
|
201 |
|
|
allow external control of the program points being traced
|
202 |
|
|
(i.e. only from main onwards, excluding the run-time setup,
|
203 |
|
|
etc.). */
|
204 |
|
|
for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++)
|
205 |
|
|
{
|
206 |
|
|
sim_cpu *cpu = STATE_CPU (sd, cpu_nr);
|
207 |
|
|
if (arg == NULL)
|
208 |
|
|
STATE |= simTRACE;
|
209 |
|
|
else if (strcmp (arg, "yes") == 0)
|
210 |
|
|
STATE |= simTRACE;
|
211 |
|
|
else if (strcmp (arg, "no") == 0)
|
212 |
|
|
STATE &= ~simTRACE;
|
213 |
|
|
else if (strcmp (arg, "on") == 0)
|
214 |
|
|
STATE |= simTRACE;
|
215 |
|
|
else if (strcmp (arg, "off") == 0)
|
216 |
|
|
STATE &= ~simTRACE;
|
217 |
|
|
else
|
218 |
|
|
{
|
219 |
|
|
fprintf (stderr, "Unrecognized dinero-trace option `%s'\n", arg);
|
220 |
|
|
return SIM_RC_FAIL;
|
221 |
|
|
}
|
222 |
|
|
}
|
223 |
|
|
return SIM_RC_OK;
|
224 |
|
|
#else /* !TRACE */
|
225 |
|
|
fprintf(stderr,"\
|
226 |
|
|
Simulator constructed without dinero tracing support (for performance).\n\
|
227 |
|
|
Re-compile simulator with \"-DTRACE\" to enable this option.\n");
|
228 |
|
|
return SIM_RC_FAIL;
|
229 |
|
|
#endif /* !TRACE */
|
230 |
|
|
|
231 |
|
|
case OPTION_DINERO_FILE:
|
232 |
|
|
#if defined(TRACE)
|
233 |
|
|
if (optarg != NULL) {
|
234 |
|
|
char *tmp;
|
235 |
|
|
tmp = (char *)malloc(strlen(optarg) + 1);
|
236 |
|
|
if (tmp == NULL)
|
237 |
|
|
{
|
238 |
|
|
sim_io_printf(sd,"Failed to allocate buffer for tracefile name \"%s\"\n",optarg);
|
239 |
|
|
return SIM_RC_FAIL;
|
240 |
|
|
}
|
241 |
|
|
else {
|
242 |
|
|
strcpy(tmp,optarg);
|
243 |
|
|
tracefile = tmp;
|
244 |
|
|
sim_io_printf(sd,"Placing trace information into file \"%s\"\n",tracefile);
|
245 |
|
|
}
|
246 |
|
|
}
|
247 |
|
|
#endif /* TRACE */
|
248 |
|
|
return SIM_RC_OK;
|
249 |
|
|
|
250 |
|
|
case OPTION_FIRMWARE:
|
251 |
|
|
return sim_firmware_command (sd, arg);
|
252 |
|
|
|
253 |
|
|
case OPTION_BOARD:
|
254 |
|
|
{
|
255 |
|
|
if (arg)
|
256 |
|
|
{
|
257 |
|
|
board = zalloc(strlen(arg) + 1);
|
258 |
|
|
strcpy(board, arg);
|
259 |
|
|
}
|
260 |
|
|
return SIM_RC_OK;
|
261 |
|
|
}
|
262 |
|
|
|
263 |
|
|
case OPTION_INFO_MEMORY:
|
264 |
|
|
display_mem_info = 1;
|
265 |
|
|
break;
|
266 |
|
|
}
|
267 |
|
|
|
268 |
|
|
return SIM_RC_OK;
|
269 |
|
|
}
|
270 |
|
|
|
271 |
|
|
|
272 |
|
|
static const OPTION mips_options[] =
|
273 |
|
|
{
|
274 |
|
|
{ {"dinero-trace", optional_argument, NULL, OPTION_DINERO_TRACE},
|
275 |
|
|
'\0', "on|off", "Enable dinero tracing",
|
276 |
|
|
mips_option_handler },
|
277 |
|
|
{ {"dinero-file", required_argument, NULL, OPTION_DINERO_FILE},
|
278 |
|
|
'\0', "FILE", "Write dinero trace to FILE",
|
279 |
|
|
mips_option_handler },
|
280 |
|
|
{ {"firmware", required_argument, NULL, OPTION_FIRMWARE},
|
281 |
|
|
'\0', "[idt|pmon|lsipmon|none][@ADDRESS]", "Emulate ROM monitor",
|
282 |
|
|
mips_option_handler },
|
283 |
|
|
{ {"board", required_argument, NULL, OPTION_BOARD},
|
284 |
|
|
'\0', "none" /* rely on compile-time string concatenation for other options */
|
285 |
|
|
|
286 |
|
|
#define BOARD_JMR3904 "jmr3904"
|
287 |
|
|
"|" BOARD_JMR3904
|
288 |
|
|
#define BOARD_JMR3904_PAL "jmr3904pal"
|
289 |
|
|
"|" BOARD_JMR3904_PAL
|
290 |
|
|
#define BOARD_JMR3904_DEBUG "jmr3904debug"
|
291 |
|
|
"|" BOARD_JMR3904_DEBUG
|
292 |
|
|
#define BOARD_BSP "bsp"
|
293 |
|
|
"|" BOARD_BSP
|
294 |
|
|
|
295 |
|
|
, "Customize simulation for a particular board.", mips_option_handler },
|
296 |
|
|
|
297 |
|
|
/* These next two options have the same names as ones found in the
|
298 |
|
|
memory_options[] array in common/sim-memopt.c. This is because
|
299 |
|
|
the intention is to provide an alternative handler for those two
|
300 |
|
|
options. We need an alternative handler because the memory
|
301 |
|
|
regions are not set up until after the command line arguments
|
302 |
|
|
have been parsed, and so we cannot display the memory info whilst
|
303 |
|
|
processing the command line. There is a hack in sim_open to
|
304 |
|
|
remove these handlers when we want the real --memory-info option
|
305 |
|
|
to work. */
|
306 |
|
|
{ { "info-memory", no_argument, NULL, OPTION_INFO_MEMORY },
|
307 |
|
|
'\0', NULL, "List configured memory regions", mips_option_handler },
|
308 |
|
|
{ { "memory-info", no_argument, NULL, OPTION_INFO_MEMORY },
|
309 |
|
|
'\0', NULL, NULL, mips_option_handler },
|
310 |
|
|
|
311 |
|
|
{ {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
|
312 |
|
|
};
|
313 |
|
|
|
314 |
|
|
|
315 |
|
|
int interrupt_pending;
|
316 |
|
|
|
317 |
|
|
void
|
318 |
|
|
interrupt_event (SIM_DESC sd, void *data)
|
319 |
|
|
{
|
320 |
|
|
sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
|
321 |
|
|
address_word cia = CIA_GET (cpu);
|
322 |
|
|
if (SR & status_IE)
|
323 |
|
|
{
|
324 |
|
|
interrupt_pending = 0;
|
325 |
|
|
SignalExceptionInterrupt (1); /* interrupt "1" */
|
326 |
|
|
}
|
327 |
|
|
else if (!interrupt_pending)
|
328 |
|
|
sim_events_schedule (sd, 1, interrupt_event, data);
|
329 |
|
|
}
|
330 |
|
|
|
331 |
|
|
|
332 |
|
|
/*---------------------------------------------------------------------------*/
|
333 |
|
|
/*-- Device registration hook -----------------------------------------------*/
|
334 |
|
|
/*---------------------------------------------------------------------------*/
|
335 |
|
|
static void device_init(SIM_DESC sd) {
|
336 |
|
|
#ifdef DEVICE_INIT
|
337 |
|
|
extern void register_devices(SIM_DESC);
|
338 |
|
|
register_devices(sd);
|
339 |
|
|
#endif
|
340 |
|
|
}
|
341 |
|
|
|
342 |
|
|
/*---------------------------------------------------------------------------*/
|
343 |
|
|
/*-- GDB simulator interface ------------------------------------------------*/
|
344 |
|
|
/*---------------------------------------------------------------------------*/
|
345 |
|
|
|
346 |
|
|
SIM_DESC
|
347 |
|
|
sim_open (kind, cb, abfd, argv)
|
348 |
|
|
SIM_OPEN_KIND kind;
|
349 |
|
|
host_callback *cb;
|
350 |
|
|
struct bfd *abfd;
|
351 |
|
|
char **argv;
|
352 |
|
|
{
|
353 |
|
|
SIM_DESC sd = sim_state_alloc (kind, cb);
|
354 |
|
|
sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
|
355 |
|
|
|
356 |
|
|
SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
|
357 |
|
|
|
358 |
|
|
/* FIXME: watchpoints code shouldn't need this */
|
359 |
|
|
STATE_WATCHPOINTS (sd)->pc = &(PC);
|
360 |
|
|
STATE_WATCHPOINTS (sd)->sizeof_pc = sizeof (PC);
|
361 |
|
|
STATE_WATCHPOINTS (sd)->interrupt_handler = interrupt_event;
|
362 |
|
|
|
363 |
|
|
/* Initialize the mechanism for doing insn profiling. */
|
364 |
|
|
CPU_INSN_NAME (cpu) = get_insn_name;
|
365 |
|
|
CPU_MAX_INSNS (cpu) = nr_itable_entries;
|
366 |
|
|
|
367 |
|
|
STATE = 0;
|
368 |
|
|
|
369 |
|
|
if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
|
370 |
|
|
return 0;
|
371 |
|
|
sim_add_option_table (sd, NULL, mips_options);
|
372 |
|
|
|
373 |
|
|
|
374 |
|
|
/* getopt will print the error message so we just have to exit if this fails.
|
375 |
|
|
FIXME: Hmmm... in the case of gdb we need getopt to call
|
376 |
|
|
print_filtered. */
|
377 |
|
|
if (sim_parse_args (sd, argv) != SIM_RC_OK)
|
378 |
|
|
{
|
379 |
|
|
/* Uninstall the modules to avoid memory leaks,
|
380 |
|
|
file descriptor leaks, etc. */
|
381 |
|
|
sim_module_uninstall (sd);
|
382 |
|
|
return 0;
|
383 |
|
|
}
|
384 |
|
|
|
385 |
|
|
/* handle board-specific memory maps */
|
386 |
|
|
if (board == NULL)
|
387 |
|
|
{
|
388 |
|
|
/* Allocate core managed memory */
|
389 |
|
|
sim_memopt *entry, *match = NULL;
|
390 |
|
|
address_word mem_size = 0;
|
391 |
|
|
int mapped = 0;
|
392 |
|
|
|
393 |
|
|
/* For compatibility with the old code - under this (at level one)
|
394 |
|
|
are the kernel spaces K0 & K1. Both of these map to a single
|
395 |
|
|
smaller sub region */
|
396 |
|
|
sim_do_command(sd," memory region 0x7fff8000,0x8000") ; /* MTZ- 32 k stack */
|
397 |
|
|
|
398 |
|
|
/* Look for largest memory region defined on command-line at
|
399 |
|
|
phys address 0. */
|
400 |
|
|
#ifdef SIM_HAVE_FLATMEM
|
401 |
|
|
mem_size = STATE_MEM_SIZE (sd);
|
402 |
|
|
#endif
|
403 |
|
|
for (entry = STATE_MEMOPT (sd); entry != NULL; entry = entry->next)
|
404 |
|
|
{
|
405 |
|
|
/* If we find an entry at address 0, then we will end up
|
406 |
|
|
allocating a new buffer in the "memory alias" command
|
407 |
|
|
below. The region at address 0 will be deleted. */
|
408 |
|
|
address_word size = (entry->modulo != 0
|
409 |
|
|
? entry->modulo : entry->nr_bytes);
|
410 |
|
|
if (entry->addr == 0
|
411 |
|
|
&& (!match || entry->level < match->level))
|
412 |
|
|
match = entry;
|
413 |
|
|
else if (entry->addr == K0BASE || entry->addr == K1BASE)
|
414 |
|
|
mapped = 1;
|
415 |
|
|
else
|
416 |
|
|
{
|
417 |
|
|
sim_memopt *alias;
|
418 |
|
|
for (alias = entry->alias; alias != NULL; alias = alias->next)
|
419 |
|
|
{
|
420 |
|
|
if (alias->addr == 0
|
421 |
|
|
&& (!match || entry->level < match->level))
|
422 |
|
|
match = entry;
|
423 |
|
|
else if (alias->addr == K0BASE || alias->addr == K1BASE)
|
424 |
|
|
mapped = 1;
|
425 |
|
|
}
|
426 |
|
|
}
|
427 |
|
|
}
|
428 |
|
|
|
429 |
|
|
if (!mapped)
|
430 |
|
|
{
|
431 |
|
|
if (match)
|
432 |
|
|
{
|
433 |
|
|
/* Get existing memory region size. */
|
434 |
|
|
mem_size = (match->modulo != 0
|
435 |
|
|
? match->modulo : match->nr_bytes);
|
436 |
|
|
/* Delete old region. */
|
437 |
|
|
sim_do_commandf (sd, "memory delete %d:0x%lx@%d",
|
438 |
|
|
match->space, match->addr, match->level);
|
439 |
|
|
}
|
440 |
|
|
else if (mem_size == 0)
|
441 |
|
|
mem_size = MEM_SIZE;
|
442 |
|
|
/* Limit to KSEG1 size (512MB) */
|
443 |
|
|
if (mem_size > K1SIZE)
|
444 |
|
|
mem_size = K1SIZE;
|
445 |
|
|
/* memory alias K1BASE@1,K1SIZE%MEMSIZE,K0BASE */
|
446 |
|
|
sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx%%0x%lx,0x%0x",
|
447 |
|
|
K1BASE, K1SIZE, (long)mem_size, K0BASE);
|
448 |
|
|
}
|
449 |
|
|
|
450 |
|
|
device_init(sd);
|
451 |
|
|
}
|
452 |
|
|
else if (board != NULL
|
453 |
|
|
&& (strcmp(board, BOARD_BSP) == 0))
|
454 |
|
|
{
|
455 |
|
|
int i;
|
456 |
|
|
|
457 |
|
|
STATE_ENVIRONMENT (sd) = OPERATING_ENVIRONMENT;
|
458 |
|
|
|
459 |
|
|
/* ROM: 0x9FC0_0000 - 0x9FFF_FFFF and 0xBFC0_0000 - 0xBFFF_FFFF */
|
460 |
|
|
sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx,0x%0x",
|
461 |
|
|
0x9FC00000,
|
462 |
|
|
4 * 1024 * 1024, /* 4 MB */
|
463 |
|
|
0xBFC00000);
|
464 |
|
|
|
465 |
|
|
/* SRAM: 0x8000_0000 - 0x803F_FFFF and 0xA000_0000 - 0xA03F_FFFF */
|
466 |
|
|
sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx,0x%0x",
|
467 |
|
|
0x80000000,
|
468 |
|
|
4 * 1024 * 1024, /* 4 MB */
|
469 |
|
|
0xA0000000);
|
470 |
|
|
|
471 |
|
|
/* DRAM: 0x8800_0000 - 0x89FF_FFFF and 0xA800_0000 - 0xA9FF_FFFF */
|
472 |
|
|
for (i=0; i<8; i++) /* 32 MB total */
|
473 |
|
|
{
|
474 |
|
|
unsigned size = 4 * 1024 * 1024; /* 4 MB */
|
475 |
|
|
sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx,0x%0x",
|
476 |
|
|
0x88000000 + (i * size),
|
477 |
|
|
size,
|
478 |
|
|
0xA8000000 + (i * size));
|
479 |
|
|
}
|
480 |
|
|
}
|
481 |
|
|
#if (WITH_HW)
|
482 |
|
|
else if (board != NULL
|
483 |
|
|
&& (strcmp(board, BOARD_JMR3904) == 0 ||
|
484 |
|
|
strcmp(board, BOARD_JMR3904_PAL) == 0 ||
|
485 |
|
|
strcmp(board, BOARD_JMR3904_DEBUG) == 0))
|
486 |
|
|
{
|
487 |
|
|
/* match VIRTUAL memory layout of JMR-TX3904 board */
|
488 |
|
|
int i;
|
489 |
|
|
|
490 |
|
|
/* --- disable monitor unless forced on by user --- */
|
491 |
|
|
|
492 |
|
|
if (! firmware_option_p)
|
493 |
|
|
{
|
494 |
|
|
idt_monitor_base = 0;
|
495 |
|
|
pmon_monitor_base = 0;
|
496 |
|
|
lsipmon_monitor_base = 0;
|
497 |
|
|
}
|
498 |
|
|
|
499 |
|
|
/* --- environment --- */
|
500 |
|
|
|
501 |
|
|
STATE_ENVIRONMENT (sd) = OPERATING_ENVIRONMENT;
|
502 |
|
|
|
503 |
|
|
/* --- memory --- */
|
504 |
|
|
|
505 |
|
|
/* ROM: 0x9FC0_0000 - 0x9FFF_FFFF and 0xBFC0_0000 - 0xBFFF_FFFF */
|
506 |
|
|
sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx,0x%0x",
|
507 |
|
|
0x9FC00000,
|
508 |
|
|
4 * 1024 * 1024, /* 4 MB */
|
509 |
|
|
0xBFC00000);
|
510 |
|
|
|
511 |
|
|
/* SRAM: 0x8000_0000 - 0x803F_FFFF and 0xA000_0000 - 0xA03F_FFFF */
|
512 |
|
|
sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx,0x%0x",
|
513 |
|
|
0x80000000,
|
514 |
|
|
4 * 1024 * 1024, /* 4 MB */
|
515 |
|
|
0xA0000000);
|
516 |
|
|
|
517 |
|
|
/* DRAM: 0x8800_0000 - 0x89FF_FFFF and 0xA800_0000 - 0xA9FF_FFFF */
|
518 |
|
|
for (i=0; i<8; i++) /* 32 MB total */
|
519 |
|
|
{
|
520 |
|
|
unsigned size = 4 * 1024 * 1024; /* 4 MB */
|
521 |
|
|
sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx,0x%0x",
|
522 |
|
|
0x88000000 + (i * size),
|
523 |
|
|
size,
|
524 |
|
|
0xA8000000 + (i * size));
|
525 |
|
|
}
|
526 |
|
|
|
527 |
|
|
/* Dummy memory regions for unsimulated devices - sorted by address */
|
528 |
|
|
|
529 |
|
|
sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx", 0xB1000000, 0x400); /* ISA I/O */
|
530 |
|
|
sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx", 0xB2100000, 0x004); /* ISA ctl */
|
531 |
|
|
sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx", 0xB2500000, 0x004); /* LED/switch */
|
532 |
|
|
sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx", 0xB2700000, 0x004); /* RTC */
|
533 |
|
|
sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx", 0xB3C00000, 0x004); /* RTC */
|
534 |
|
|
sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx", 0xFFFF8000, 0x900); /* DRAMC */
|
535 |
|
|
sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx", 0xFFFF9000, 0x200); /* EBIF */
|
536 |
|
|
sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx", 0xFFFFE000, 0x01c); /* EBIF */
|
537 |
|
|
sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx", 0xFFFFF500, 0x300); /* PIO */
|
538 |
|
|
|
539 |
|
|
|
540 |
|
|
/* --- simulated devices --- */
|
541 |
|
|
sim_hw_parse (sd, "/tx3904irc@0xffffc000/reg 0xffffc000 0x20");
|
542 |
|
|
sim_hw_parse (sd, "/tx3904cpu");
|
543 |
|
|
sim_hw_parse (sd, "/tx3904tmr@0xfffff000/reg 0xfffff000 0x100");
|
544 |
|
|
sim_hw_parse (sd, "/tx3904tmr@0xfffff100/reg 0xfffff100 0x100");
|
545 |
|
|
sim_hw_parse (sd, "/tx3904tmr@0xfffff200/reg 0xfffff200 0x100");
|
546 |
|
|
sim_hw_parse (sd, "/tx3904sio@0xfffff300/reg 0xfffff300 0x100");
|
547 |
|
|
{
|
548 |
|
|
/* FIXME: poking at dv-sockser internals, use tcp backend if
|
549 |
|
|
--sockser_addr option was given.*/
|
550 |
|
|
extern char* sockser_addr;
|
551 |
|
|
if(sockser_addr == NULL)
|
552 |
|
|
sim_hw_parse (sd, "/tx3904sio@0xfffff300/backend stdio");
|
553 |
|
|
else
|
554 |
|
|
sim_hw_parse (sd, "/tx3904sio@0xfffff300/backend tcp");
|
555 |
|
|
}
|
556 |
|
|
sim_hw_parse (sd, "/tx3904sio@0xfffff400/reg 0xfffff400 0x100");
|
557 |
|
|
sim_hw_parse (sd, "/tx3904sio@0xfffff400/backend stdio");
|
558 |
|
|
|
559 |
|
|
/* -- device connections --- */
|
560 |
|
|
sim_hw_parse (sd, "/tx3904irc > ip level /tx3904cpu");
|
561 |
|
|
sim_hw_parse (sd, "/tx3904tmr@0xfffff000 > int tmr0 /tx3904irc");
|
562 |
|
|
sim_hw_parse (sd, "/tx3904tmr@0xfffff100 > int tmr1 /tx3904irc");
|
563 |
|
|
sim_hw_parse (sd, "/tx3904tmr@0xfffff200 > int tmr2 /tx3904irc");
|
564 |
|
|
sim_hw_parse (sd, "/tx3904sio@0xfffff300 > int sio0 /tx3904irc");
|
565 |
|
|
sim_hw_parse (sd, "/tx3904sio@0xfffff400 > int sio1 /tx3904irc");
|
566 |
|
|
|
567 |
|
|
/* add PAL timer & I/O module */
|
568 |
|
|
if(! strcmp(board, BOARD_JMR3904_PAL))
|
569 |
|
|
{
|
570 |
|
|
/* the device */
|
571 |
|
|
sim_hw_parse (sd, "/pal@0xffff0000");
|
572 |
|
|
sim_hw_parse (sd, "/pal@0xffff0000/reg 0xffff0000 64");
|
573 |
|
|
|
574 |
|
|
/* wire up interrupt ports to irc */
|
575 |
|
|
sim_hw_parse (sd, "/pal@0x31000000 > countdown tmr0 /tx3904irc");
|
576 |
|
|
sim_hw_parse (sd, "/pal@0x31000000 > timer tmr1 /tx3904irc");
|
577 |
|
|
sim_hw_parse (sd, "/pal@0x31000000 > int int0 /tx3904irc");
|
578 |
|
|
}
|
579 |
|
|
|
580 |
|
|
if(! strcmp(board, BOARD_JMR3904_DEBUG))
|
581 |
|
|
{
|
582 |
|
|
/* -- DEBUG: glue interrupt generators --- */
|
583 |
|
|
sim_hw_parse (sd, "/glue@0xffff0000/reg 0xffff0000 0x50");
|
584 |
|
|
sim_hw_parse (sd, "/glue@0xffff0000 > int0 int0 /tx3904irc");
|
585 |
|
|
sim_hw_parse (sd, "/glue@0xffff0000 > int1 int1 /tx3904irc");
|
586 |
|
|
sim_hw_parse (sd, "/glue@0xffff0000 > int2 int2 /tx3904irc");
|
587 |
|
|
sim_hw_parse (sd, "/glue@0xffff0000 > int3 int3 /tx3904irc");
|
588 |
|
|
sim_hw_parse (sd, "/glue@0xffff0000 > int4 int4 /tx3904irc");
|
589 |
|
|
sim_hw_parse (sd, "/glue@0xffff0000 > int5 int5 /tx3904irc");
|
590 |
|
|
sim_hw_parse (sd, "/glue@0xffff0000 > int6 int6 /tx3904irc");
|
591 |
|
|
sim_hw_parse (sd, "/glue@0xffff0000 > int7 int7 /tx3904irc");
|
592 |
|
|
sim_hw_parse (sd, "/glue@0xffff0000 > int8 dmac0 /tx3904irc");
|
593 |
|
|
sim_hw_parse (sd, "/glue@0xffff0000 > int9 dmac1 /tx3904irc");
|
594 |
|
|
sim_hw_parse (sd, "/glue@0xffff0000 > int10 dmac2 /tx3904irc");
|
595 |
|
|
sim_hw_parse (sd, "/glue@0xffff0000 > int11 dmac3 /tx3904irc");
|
596 |
|
|
sim_hw_parse (sd, "/glue@0xffff0000 > int12 sio0 /tx3904irc");
|
597 |
|
|
sim_hw_parse (sd, "/glue@0xffff0000 > int13 sio1 /tx3904irc");
|
598 |
|
|
sim_hw_parse (sd, "/glue@0xffff0000 > int14 tmr0 /tx3904irc");
|
599 |
|
|
sim_hw_parse (sd, "/glue@0xffff0000 > int15 tmr1 /tx3904irc");
|
600 |
|
|
sim_hw_parse (sd, "/glue@0xffff0000 > int16 tmr2 /tx3904irc");
|
601 |
|
|
sim_hw_parse (sd, "/glue@0xffff0000 > int17 nmi /tx3904cpu");
|
602 |
|
|
}
|
603 |
|
|
|
604 |
|
|
device_init(sd);
|
605 |
|
|
}
|
606 |
|
|
#endif
|
607 |
|
|
|
608 |
|
|
if (display_mem_info)
|
609 |
|
|
{
|
610 |
|
|
struct option_list * ol;
|
611 |
|
|
struct option_list * prev;
|
612 |
|
|
|
613 |
|
|
/* This is a hack. We want to execute the real --memory-info command
|
614 |
|
|
line switch which is handled in common/sim-memopts.c, not the
|
615 |
|
|
override we have defined in this file. So we remove the
|
616 |
|
|
mips_options array from the state options list. This is safe
|
617 |
|
|
because we have now processed all of the command line. */
|
618 |
|
|
for (ol = STATE_OPTIONS (sd), prev = NULL;
|
619 |
|
|
ol != NULL;
|
620 |
|
|
prev = ol, ol = ol->next)
|
621 |
|
|
if (ol->options == mips_options)
|
622 |
|
|
break;
|
623 |
|
|
|
624 |
|
|
SIM_ASSERT (ol != NULL);
|
625 |
|
|
|
626 |
|
|
if (prev == NULL)
|
627 |
|
|
STATE_OPTIONS (sd) = ol->next;
|
628 |
|
|
else
|
629 |
|
|
prev->next = ol->next;
|
630 |
|
|
|
631 |
|
|
sim_do_commandf (sd, "memory-info");
|
632 |
|
|
}
|
633 |
|
|
|
634 |
|
|
/* check for/establish the a reference program image */
|
635 |
|
|
if (sim_analyze_program (sd,
|
636 |
|
|
(STATE_PROG_ARGV (sd) != NULL
|
637 |
|
|
? *STATE_PROG_ARGV (sd)
|
638 |
|
|
: NULL),
|
639 |
|
|
abfd) != SIM_RC_OK)
|
640 |
|
|
{
|
641 |
|
|
sim_module_uninstall (sd);
|
642 |
|
|
return 0;
|
643 |
|
|
}
|
644 |
|
|
|
645 |
|
|
/* Configure/verify the target byte order and other runtime
|
646 |
|
|
configuration options */
|
647 |
|
|
if (sim_config (sd) != SIM_RC_OK)
|
648 |
|
|
{
|
649 |
|
|
sim_module_uninstall (sd);
|
650 |
|
|
return 0;
|
651 |
|
|
}
|
652 |
|
|
|
653 |
|
|
if (sim_post_argv_init (sd) != SIM_RC_OK)
|
654 |
|
|
{
|
655 |
|
|
/* Uninstall the modules to avoid memory leaks,
|
656 |
|
|
file descriptor leaks, etc. */
|
657 |
|
|
sim_module_uninstall (sd);
|
658 |
|
|
return 0;
|
659 |
|
|
}
|
660 |
|
|
|
661 |
|
|
/* verify assumptions the simulator made about the host type system.
|
662 |
|
|
This macro does not return if there is a problem */
|
663 |
|
|
SIM_ASSERT (sizeof(int) == (4 * sizeof(char)));
|
664 |
|
|
SIM_ASSERT (sizeof(word64) == (8 * sizeof(char)));
|
665 |
|
|
|
666 |
|
|
/* This is NASTY, in that we are assuming the size of specific
|
667 |
|
|
registers: */
|
668 |
|
|
{
|
669 |
|
|
int rn;
|
670 |
|
|
for (rn = 0; (rn < (LAST_EMBED_REGNUM + 1)); rn++)
|
671 |
|
|
{
|
672 |
|
|
if (rn < 32)
|
673 |
|
|
cpu->register_widths[rn] = WITH_TARGET_WORD_BITSIZE;
|
674 |
|
|
else if ((rn >= FGR_BASE) && (rn < (FGR_BASE + NR_FGR)))
|
675 |
|
|
cpu->register_widths[rn] = WITH_TARGET_FLOATING_POINT_BITSIZE;
|
676 |
|
|
else if ((rn >= 33) && (rn <= 37))
|
677 |
|
|
cpu->register_widths[rn] = WITH_TARGET_WORD_BITSIZE;
|
678 |
|
|
else if ((rn == SRIDX)
|
679 |
|
|
|| (rn == FCR0IDX)
|
680 |
|
|
|| (rn == FCR31IDX)
|
681 |
|
|
|| ((rn >= 72) && (rn <= 89)))
|
682 |
|
|
cpu->register_widths[rn] = 32;
|
683 |
|
|
else
|
684 |
|
|
cpu->register_widths[rn] = 0;
|
685 |
|
|
}
|
686 |
|
|
|
687 |
|
|
|
688 |
|
|
}
|
689 |
|
|
|
690 |
|
|
#if defined(TRACE)
|
691 |
|
|
if (STATE & simTRACE)
|
692 |
|
|
open_trace(sd);
|
693 |
|
|
#endif /* TRACE */
|
694 |
|
|
|
695 |
|
|
/*
|
696 |
|
|
sim_io_eprintf (sd, "idt@%x pmon@%x lsipmon@%x\n",
|
697 |
|
|
idt_monitor_base,
|
698 |
|
|
pmon_monitor_base,
|
699 |
|
|
lsipmon_monitor_base);
|
700 |
|
|
*/
|
701 |
|
|
|
702 |
|
|
/* Write the monitor trap address handlers into the monitor (eeprom)
|
703 |
|
|
address space. This can only be done once the target endianness
|
704 |
|
|
has been determined. */
|
705 |
|
|
if (idt_monitor_base != 0)
|
706 |
|
|
{
|
707 |
|
|
unsigned loop;
|
708 |
|
|
unsigned idt_monitor_size = 1 << 11;
|
709 |
|
|
|
710 |
|
|
/* the default monitor region */
|
711 |
|
|
sim_do_commandf (sd, "memory region 0x%x,0x%x",
|
712 |
|
|
idt_monitor_base, idt_monitor_size);
|
713 |
|
|
|
714 |
|
|
/* Entry into the IDT monitor is via fixed address vectors, and
|
715 |
|
|
not using machine instructions. To avoid clashing with use of
|
716 |
|
|
the MIPS TRAP system, we place our own (simulator specific)
|
717 |
|
|
"undefined" instructions into the relevant vector slots. */
|
718 |
|
|
for (loop = 0; (loop < idt_monitor_size); loop += 4)
|
719 |
|
|
{
|
720 |
|
|
address_word vaddr = (idt_monitor_base + loop);
|
721 |
|
|
unsigned32 insn = (RSVD_INSTRUCTION |
|
722 |
|
|
(((loop >> 2) & RSVD_INSTRUCTION_ARG_MASK)
|
723 |
|
|
<< RSVD_INSTRUCTION_ARG_SHIFT));
|
724 |
|
|
H2T (insn);
|
725 |
|
|
sim_write (sd, vaddr, (char *)&insn, sizeof (insn));
|
726 |
|
|
}
|
727 |
|
|
}
|
728 |
|
|
|
729 |
|
|
if ((pmon_monitor_base != 0) || (lsipmon_monitor_base != 0))
|
730 |
|
|
{
|
731 |
|
|
/* The PMON monitor uses the same address space, but rather than
|
732 |
|
|
branching into it the address of a routine is loaded. We can
|
733 |
|
|
cheat for the moment, and direct the PMON routine to IDT style
|
734 |
|
|
instructions within the monitor space. This relies on the IDT
|
735 |
|
|
monitor not using the locations from 0xBFC00500 onwards as its
|
736 |
|
|
entry points.*/
|
737 |
|
|
unsigned loop;
|
738 |
|
|
for (loop = 0; (loop < 24); loop++)
|
739 |
|
|
{
|
740 |
|
|
unsigned32 value = ((0x500 - 8) / 8); /* default UNDEFINED reason code */
|
741 |
|
|
switch (loop)
|
742 |
|
|
{
|
743 |
|
|
case 0: /* read */
|
744 |
|
|
value = 7;
|
745 |
|
|
break;
|
746 |
|
|
case 1: /* write */
|
747 |
|
|
value = 8;
|
748 |
|
|
break;
|
749 |
|
|
case 2: /* open */
|
750 |
|
|
value = 6;
|
751 |
|
|
break;
|
752 |
|
|
case 3: /* close */
|
753 |
|
|
value = 10;
|
754 |
|
|
break;
|
755 |
|
|
case 5: /* printf */
|
756 |
|
|
value = ((0x500 - 16) / 8); /* not an IDT reason code */
|
757 |
|
|
break;
|
758 |
|
|
case 8: /* cliexit */
|
759 |
|
|
value = 17;
|
760 |
|
|
break;
|
761 |
|
|
case 11: /* flush_cache */
|
762 |
|
|
value = 28;
|
763 |
|
|
break;
|
764 |
|
|
}
|
765 |
|
|
|
766 |
|
|
SIM_ASSERT (idt_monitor_base != 0);
|
767 |
|
|
value = ((unsigned int) idt_monitor_base + (value * 8));
|
768 |
|
|
H2T (value);
|
769 |
|
|
|
770 |
|
|
if (pmon_monitor_base != 0)
|
771 |
|
|
{
|
772 |
|
|
address_word vaddr = (pmon_monitor_base + (loop * 4));
|
773 |
|
|
sim_write (sd, vaddr, (char *)&value, sizeof (value));
|
774 |
|
|
}
|
775 |
|
|
|
776 |
|
|
if (lsipmon_monitor_base != 0)
|
777 |
|
|
{
|
778 |
|
|
address_word vaddr = (lsipmon_monitor_base + (loop * 4));
|
779 |
|
|
sim_write (sd, vaddr, (char *)&value, sizeof (value));
|
780 |
|
|
}
|
781 |
|
|
}
|
782 |
|
|
|
783 |
|
|
/* Write an abort sequence into the TRAP (common) exception vector
|
784 |
|
|
addresses. This is to catch code executing a TRAP (et.al.)
|
785 |
|
|
instruction without installing a trap handler. */
|
786 |
|
|
if ((idt_monitor_base != 0) ||
|
787 |
|
|
(pmon_monitor_base != 0) ||
|
788 |
|
|
(lsipmon_monitor_base != 0))
|
789 |
|
|
{
|
790 |
|
|
unsigned32 halt[2] = { 0x2404002f /* addiu r4, r0, 47 */,
|
791 |
|
|
HALT_INSTRUCTION /* BREAK */ };
|
792 |
|
|
H2T (halt[0]);
|
793 |
|
|
H2T (halt[1]);
|
794 |
|
|
sim_write (sd, 0x80000000, (char *) halt, sizeof (halt));
|
795 |
|
|
sim_write (sd, 0x80000180, (char *) halt, sizeof (halt));
|
796 |
|
|
sim_write (sd, 0x80000200, (char *) halt, sizeof (halt));
|
797 |
|
|
/* XXX: Write here unconditionally? */
|
798 |
|
|
sim_write (sd, 0xBFC00200, (char *) halt, sizeof (halt));
|
799 |
|
|
sim_write (sd, 0xBFC00380, (char *) halt, sizeof (halt));
|
800 |
|
|
sim_write (sd, 0xBFC00400, (char *) halt, sizeof (halt));
|
801 |
|
|
}
|
802 |
|
|
}
|
803 |
|
|
|
804 |
|
|
|
805 |
|
|
|
806 |
|
|
return sd;
|
807 |
|
|
}
|
808 |
|
|
|
809 |
|
|
#if defined(TRACE)
|
810 |
|
|
static void
|
811 |
|
|
open_trace(sd)
|
812 |
|
|
SIM_DESC sd;
|
813 |
|
|
{
|
814 |
|
|
tracefh = fopen(tracefile,"wb+");
|
815 |
|
|
if (tracefh == NULL)
|
816 |
|
|
{
|
817 |
|
|
sim_io_eprintf(sd,"Failed to create file \"%s\", writing trace information to stderr.\n",tracefile);
|
818 |
|
|
tracefh = stderr;
|
819 |
|
|
}
|
820 |
|
|
}
|
821 |
|
|
#endif /* TRACE */
|
822 |
|
|
|
823 |
|
|
/* Return name of an insn, used by insn profiling. */
|
824 |
|
|
static const char *
|
825 |
|
|
get_insn_name (sim_cpu *cpu, int i)
|
826 |
|
|
{
|
827 |
|
|
return itable[i].name;
|
828 |
|
|
}
|
829 |
|
|
|
830 |
|
|
void
|
831 |
|
|
sim_close (sd, quitting)
|
832 |
|
|
SIM_DESC sd;
|
833 |
|
|
int quitting;
|
834 |
|
|
{
|
835 |
|
|
#ifdef DEBUG
|
836 |
|
|
printf("DBG: sim_close: entered (quitting = %d)\n",quitting);
|
837 |
|
|
#endif
|
838 |
|
|
|
839 |
|
|
|
840 |
|
|
/* "quitting" is non-zero if we cannot hang on errors */
|
841 |
|
|
|
842 |
|
|
/* shut down modules */
|
843 |
|
|
sim_module_uninstall (sd);
|
844 |
|
|
|
845 |
|
|
/* Ensure that any resources allocated through the callback
|
846 |
|
|
mechanism are released: */
|
847 |
|
|
sim_io_shutdown (sd);
|
848 |
|
|
|
849 |
|
|
#if defined(TRACE)
|
850 |
|
|
if (tracefh != NULL && tracefh != stderr)
|
851 |
|
|
fclose(tracefh);
|
852 |
|
|
tracefh = NULL;
|
853 |
|
|
#endif /* TRACE */
|
854 |
|
|
|
855 |
|
|
/* FIXME - free SD */
|
856 |
|
|
|
857 |
|
|
return;
|
858 |
|
|
}
|
859 |
|
|
|
860 |
|
|
|
861 |
|
|
int
|
862 |
|
|
sim_write (sd,addr,buffer,size)
|
863 |
|
|
SIM_DESC sd;
|
864 |
|
|
SIM_ADDR addr;
|
865 |
|
|
const unsigned char *buffer;
|
866 |
|
|
int size;
|
867 |
|
|
{
|
868 |
|
|
int index;
|
869 |
|
|
sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
|
870 |
|
|
|
871 |
|
|
/* Return the number of bytes written, or zero if error. */
|
872 |
|
|
#ifdef DEBUG
|
873 |
|
|
sim_io_printf(sd,"sim_write(0x%s,buffer,%d);\n",pr_addr(addr),size);
|
874 |
|
|
#endif
|
875 |
|
|
|
876 |
|
|
/* We use raw read and write routines, since we do not want to count
|
877 |
|
|
the GDB memory accesses in our statistics gathering. */
|
878 |
|
|
|
879 |
|
|
for (index = 0; index < size; index++)
|
880 |
|
|
{
|
881 |
|
|
address_word vaddr = (address_word)addr + index;
|
882 |
|
|
address_word paddr;
|
883 |
|
|
int cca;
|
884 |
|
|
if (!address_translation (SD, CPU, NULL_CIA, vaddr, isDATA, isSTORE, &paddr, &cca, isRAW))
|
885 |
|
|
break;
|
886 |
|
|
if (sim_core_write_buffer (SD, CPU, read_map, buffer + index, paddr, 1) != 1)
|
887 |
|
|
break;
|
888 |
|
|
}
|
889 |
|
|
|
890 |
|
|
return(index);
|
891 |
|
|
}
|
892 |
|
|
|
893 |
|
|
int
|
894 |
|
|
sim_read (sd,addr,buffer,size)
|
895 |
|
|
SIM_DESC sd;
|
896 |
|
|
SIM_ADDR addr;
|
897 |
|
|
unsigned char *buffer;
|
898 |
|
|
int size;
|
899 |
|
|
{
|
900 |
|
|
int index;
|
901 |
|
|
sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
|
902 |
|
|
|
903 |
|
|
/* Return the number of bytes read, or zero if error. */
|
904 |
|
|
#ifdef DEBUG
|
905 |
|
|
sim_io_printf(sd,"sim_read(0x%s,buffer,%d);\n",pr_addr(addr),size);
|
906 |
|
|
#endif /* DEBUG */
|
907 |
|
|
|
908 |
|
|
for (index = 0; (index < size); index++)
|
909 |
|
|
{
|
910 |
|
|
address_word vaddr = (address_word)addr + index;
|
911 |
|
|
address_word paddr;
|
912 |
|
|
int cca;
|
913 |
|
|
if (!address_translation (SD, CPU, NULL_CIA, vaddr, isDATA, isLOAD, &paddr, &cca, isRAW))
|
914 |
|
|
break;
|
915 |
|
|
if (sim_core_read_buffer (SD, CPU, read_map, buffer + index, paddr, 1) != 1)
|
916 |
|
|
break;
|
917 |
|
|
}
|
918 |
|
|
|
919 |
|
|
return(index);
|
920 |
|
|
}
|
921 |
|
|
|
922 |
|
|
int
|
923 |
|
|
sim_store_register (sd,rn,memory,length)
|
924 |
|
|
SIM_DESC sd;
|
925 |
|
|
int rn;
|
926 |
|
|
unsigned char *memory;
|
927 |
|
|
int length;
|
928 |
|
|
{
|
929 |
|
|
sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
|
930 |
|
|
/* NOTE: gdb (the client) stores registers in target byte order
|
931 |
|
|
while the simulator uses host byte order */
|
932 |
|
|
#ifdef DEBUG
|
933 |
|
|
sim_io_printf(sd,"sim_store_register(%d,*memory=0x%s);\n",rn,pr_addr(*((SIM_ADDR *)memory)));
|
934 |
|
|
#endif /* DEBUG */
|
935 |
|
|
|
936 |
|
|
/* Unfortunately this suffers from the same problem as the register
|
937 |
|
|
numbering one. We need to know what the width of each logical
|
938 |
|
|
register number is for the architecture being simulated. */
|
939 |
|
|
|
940 |
|
|
if (cpu->register_widths[rn] == 0)
|
941 |
|
|
{
|
942 |
|
|
sim_io_eprintf(sd,"Invalid register width for %d (register store ignored)\n",rn);
|
943 |
|
|
return 0;
|
944 |
|
|
}
|
945 |
|
|
|
946 |
|
|
|
947 |
|
|
|
948 |
|
|
if (rn >= FGR_BASE && rn < FGR_BASE + NR_FGR)
|
949 |
|
|
{
|
950 |
|
|
cpu->fpr_state[rn - FGR_BASE] = fmt_uninterpreted;
|
951 |
|
|
if (cpu->register_widths[rn] == 32)
|
952 |
|
|
{
|
953 |
|
|
if (length == 8)
|
954 |
|
|
{
|
955 |
|
|
cpu->fgr[rn - FGR_BASE] =
|
956 |
|
|
(unsigned32) T2H_8 (*(unsigned64*)memory);
|
957 |
|
|
return 8;
|
958 |
|
|
}
|
959 |
|
|
else
|
960 |
|
|
{
|
961 |
|
|
cpu->fgr[rn - FGR_BASE] = T2H_4 (*(unsigned32*)memory);
|
962 |
|
|
return 4;
|
963 |
|
|
}
|
964 |
|
|
}
|
965 |
|
|
else
|
966 |
|
|
{
|
967 |
|
|
if (length == 8)
|
968 |
|
|
{
|
969 |
|
|
cpu->fgr[rn - FGR_BASE] = T2H_8 (*(unsigned64*)memory);
|
970 |
|
|
return 8;
|
971 |
|
|
}
|
972 |
|
|
else
|
973 |
|
|
{
|
974 |
|
|
cpu->fgr[rn - FGR_BASE] = T2H_4 (*(unsigned32*)memory);
|
975 |
|
|
return 4;
|
976 |
|
|
}
|
977 |
|
|
}
|
978 |
|
|
}
|
979 |
|
|
|
980 |
|
|
if (cpu->register_widths[rn] == 32)
|
981 |
|
|
{
|
982 |
|
|
if (length == 8)
|
983 |
|
|
{
|
984 |
|
|
cpu->registers[rn] =
|
985 |
|
|
(unsigned32) T2H_8 (*(unsigned64*)memory);
|
986 |
|
|
return 8;
|
987 |
|
|
}
|
988 |
|
|
else
|
989 |
|
|
{
|
990 |
|
|
cpu->registers[rn] = T2H_4 (*(unsigned32*)memory);
|
991 |
|
|
return 4;
|
992 |
|
|
}
|
993 |
|
|
}
|
994 |
|
|
else
|
995 |
|
|
{
|
996 |
|
|
if (length == 8)
|
997 |
|
|
{
|
998 |
|
|
cpu->registers[rn] = T2H_8 (*(unsigned64*)memory);
|
999 |
|
|
return 8;
|
1000 |
|
|
}
|
1001 |
|
|
else
|
1002 |
|
|
{
|
1003 |
|
|
cpu->registers[rn] = (signed32) T2H_4(*(unsigned32*)memory);
|
1004 |
|
|
return 4;
|
1005 |
|
|
}
|
1006 |
|
|
}
|
1007 |
|
|
|
1008 |
|
|
return 0;
|
1009 |
|
|
}
|
1010 |
|
|
|
1011 |
|
|
int
|
1012 |
|
|
sim_fetch_register (sd,rn,memory,length)
|
1013 |
|
|
SIM_DESC sd;
|
1014 |
|
|
int rn;
|
1015 |
|
|
unsigned char *memory;
|
1016 |
|
|
int length;
|
1017 |
|
|
{
|
1018 |
|
|
sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
|
1019 |
|
|
/* NOTE: gdb (the client) stores registers in target byte order
|
1020 |
|
|
while the simulator uses host byte order */
|
1021 |
|
|
#ifdef DEBUG
|
1022 |
|
|
#if 0 /* FIXME: doesn't compile */
|
1023 |
|
|
sim_io_printf(sd,"sim_fetch_register(%d=0x%s,mem) : place simulator registers into memory\n",rn,pr_addr(registers[rn]));
|
1024 |
|
|
#endif
|
1025 |
|
|
#endif /* DEBUG */
|
1026 |
|
|
|
1027 |
|
|
if (cpu->register_widths[rn] == 0)
|
1028 |
|
|
{
|
1029 |
|
|
sim_io_eprintf (sd, "Invalid register width for %d (register fetch ignored)\n",rn);
|
1030 |
|
|
return 0;
|
1031 |
|
|
}
|
1032 |
|
|
|
1033 |
|
|
|
1034 |
|
|
|
1035 |
|
|
/* Any floating point register */
|
1036 |
|
|
if (rn >= FGR_BASE && rn < FGR_BASE + NR_FGR)
|
1037 |
|
|
{
|
1038 |
|
|
if (cpu->register_widths[rn] == 32)
|
1039 |
|
|
{
|
1040 |
|
|
if (length == 8)
|
1041 |
|
|
{
|
1042 |
|
|
*(unsigned64*)memory =
|
1043 |
|
|
H2T_8 ((unsigned32) (cpu->fgr[rn - FGR_BASE]));
|
1044 |
|
|
return 8;
|
1045 |
|
|
}
|
1046 |
|
|
else
|
1047 |
|
|
{
|
1048 |
|
|
*(unsigned32*)memory = H2T_4 (cpu->fgr[rn - FGR_BASE]);
|
1049 |
|
|
return 4;
|
1050 |
|
|
}
|
1051 |
|
|
}
|
1052 |
|
|
else
|
1053 |
|
|
{
|
1054 |
|
|
if (length == 8)
|
1055 |
|
|
{
|
1056 |
|
|
*(unsigned64*)memory = H2T_8 (cpu->fgr[rn - FGR_BASE]);
|
1057 |
|
|
return 8;
|
1058 |
|
|
}
|
1059 |
|
|
else
|
1060 |
|
|
{
|
1061 |
|
|
*(unsigned32*)memory = H2T_4 ((unsigned32)(cpu->fgr[rn - FGR_BASE]));
|
1062 |
|
|
return 4;
|
1063 |
|
|
}
|
1064 |
|
|
}
|
1065 |
|
|
}
|
1066 |
|
|
|
1067 |
|
|
if (cpu->register_widths[rn] == 32)
|
1068 |
|
|
{
|
1069 |
|
|
if (length == 8)
|
1070 |
|
|
{
|
1071 |
|
|
*(unsigned64*)memory =
|
1072 |
|
|
H2T_8 ((unsigned32) (cpu->registers[rn]));
|
1073 |
|
|
return 8;
|
1074 |
|
|
}
|
1075 |
|
|
else
|
1076 |
|
|
{
|
1077 |
|
|
*(unsigned32*)memory = H2T_4 ((unsigned32)(cpu->registers[rn]));
|
1078 |
|
|
return 4;
|
1079 |
|
|
}
|
1080 |
|
|
}
|
1081 |
|
|
else
|
1082 |
|
|
{
|
1083 |
|
|
if (length == 8)
|
1084 |
|
|
{
|
1085 |
|
|
*(unsigned64*)memory =
|
1086 |
|
|
H2T_8 ((unsigned64) (cpu->registers[rn]));
|
1087 |
|
|
return 8;
|
1088 |
|
|
}
|
1089 |
|
|
else
|
1090 |
|
|
{
|
1091 |
|
|
*(unsigned32*)memory = H2T_4 ((unsigned32)(cpu->registers[rn]));
|
1092 |
|
|
return 4;
|
1093 |
|
|
}
|
1094 |
|
|
}
|
1095 |
|
|
|
1096 |
|
|
return 0;
|
1097 |
|
|
}
|
1098 |
|
|
|
1099 |
|
|
|
1100 |
|
|
SIM_RC
|
1101 |
|
|
sim_create_inferior (sd, abfd, argv,env)
|
1102 |
|
|
SIM_DESC sd;
|
1103 |
|
|
struct bfd *abfd;
|
1104 |
|
|
char **argv;
|
1105 |
|
|
char **env;
|
1106 |
|
|
{
|
1107 |
|
|
|
1108 |
|
|
#ifdef DEBUG
|
1109 |
|
|
#if 0 /* FIXME: doesn't compile */
|
1110 |
|
|
printf("DBG: sim_create_inferior entered: start_address = 0x%s\n",
|
1111 |
|
|
pr_addr(PC));
|
1112 |
|
|
#endif
|
1113 |
|
|
#endif /* DEBUG */
|
1114 |
|
|
|
1115 |
|
|
ColdReset(sd);
|
1116 |
|
|
|
1117 |
|
|
if (abfd != NULL)
|
1118 |
|
|
{
|
1119 |
|
|
/* override PC value set by ColdReset () */
|
1120 |
|
|
int cpu_nr;
|
1121 |
|
|
for (cpu_nr = 0; cpu_nr < sim_engine_nr_cpus (sd); cpu_nr++)
|
1122 |
|
|
{
|
1123 |
|
|
sim_cpu *cpu = STATE_CPU (sd, cpu_nr);
|
1124 |
|
|
CIA_SET (cpu, (unsigned64) bfd_get_start_address (abfd));
|
1125 |
|
|
}
|
1126 |
|
|
}
|
1127 |
|
|
|
1128 |
|
|
#if 0 /* def DEBUG */
|
1129 |
|
|
if (argv || env)
|
1130 |
|
|
{
|
1131 |
|
|
/* We should really place the argv slot values into the argument
|
1132 |
|
|
registers, and onto the stack as required. However, this
|
1133 |
|
|
assumes that we have a stack defined, which is not
|
1134 |
|
|
necessarily true at the moment. */
|
1135 |
|
|
char **cptr;
|
1136 |
|
|
sim_io_printf(sd,"sim_create_inferior() : passed arguments ignored\n");
|
1137 |
|
|
for (cptr = argv; (cptr && *cptr); cptr++)
|
1138 |
|
|
printf("DBG: arg \"%s\"\n",*cptr);
|
1139 |
|
|
}
|
1140 |
|
|
#endif /* DEBUG */
|
1141 |
|
|
|
1142 |
|
|
return SIM_RC_OK;
|
1143 |
|
|
}
|
1144 |
|
|
|
1145 |
|
|
void
|
1146 |
|
|
sim_do_command (sd,cmd)
|
1147 |
|
|
SIM_DESC sd;
|
1148 |
|
|
char *cmd;
|
1149 |
|
|
{
|
1150 |
|
|
if (sim_args_command (sd, cmd) != SIM_RC_OK)
|
1151 |
|
|
sim_io_printf (sd, "Error: \"%s\" is not a valid MIPS simulator command.\n",
|
1152 |
|
|
cmd);
|
1153 |
|
|
}
|
1154 |
|
|
|
1155 |
|
|
/*---------------------------------------------------------------------------*/
|
1156 |
|
|
/*-- Private simulator support interface ------------------------------------*/
|
1157 |
|
|
/*---------------------------------------------------------------------------*/
|
1158 |
|
|
|
1159 |
|
|
/* Read a null terminated string from memory, return in a buffer */
|
1160 |
|
|
static char *
|
1161 |
|
|
fetch_str (SIM_DESC sd,
|
1162 |
|
|
address_word addr)
|
1163 |
|
|
{
|
1164 |
|
|
char *buf;
|
1165 |
|
|
int nr = 0;
|
1166 |
|
|
char null;
|
1167 |
|
|
while (sim_read (sd, addr + nr, &null, 1) == 1 && null != 0)
|
1168 |
|
|
nr++;
|
1169 |
|
|
buf = NZALLOC (char, nr + 1);
|
1170 |
|
|
sim_read (sd, addr, buf, nr);
|
1171 |
|
|
return buf;
|
1172 |
|
|
}
|
1173 |
|
|
|
1174 |
|
|
|
1175 |
|
|
/* Implements the "sim firmware" command:
|
1176 |
|
|
sim firmware NAME[@ADDRESS] --- emulate ROM monitor named NAME.
|
1177 |
|
|
NAME can be idt, pmon, or lsipmon. If omitted, ADDRESS
|
1178 |
|
|
defaults to the normal address for that monitor.
|
1179 |
|
|
sim firmware none --- don't emulate any ROM monitor. Useful
|
1180 |
|
|
if you need a clean address space. */
|
1181 |
|
|
static SIM_RC
|
1182 |
|
|
sim_firmware_command (SIM_DESC sd, char *arg)
|
1183 |
|
|
{
|
1184 |
|
|
int address_present = 0;
|
1185 |
|
|
SIM_ADDR address;
|
1186 |
|
|
|
1187 |
|
|
/* Signal occurrence of this option. */
|
1188 |
|
|
firmware_option_p = 1;
|
1189 |
|
|
|
1190 |
|
|
/* Parse out the address, if present. */
|
1191 |
|
|
{
|
1192 |
|
|
char *p = strchr (arg, '@');
|
1193 |
|
|
if (p)
|
1194 |
|
|
{
|
1195 |
|
|
char *q;
|
1196 |
|
|
address_present = 1;
|
1197 |
|
|
p ++; /* skip over @ */
|
1198 |
|
|
|
1199 |
|
|
address = strtoul (p, &q, 0);
|
1200 |
|
|
if (*q != '\0')
|
1201 |
|
|
{
|
1202 |
|
|
sim_io_printf (sd, "Invalid address given to the"
|
1203 |
|
|
"`sim firmware NAME@ADDRESS' command: %s\n",
|
1204 |
|
|
p);
|
1205 |
|
|
return SIM_RC_FAIL;
|
1206 |
|
|
}
|
1207 |
|
|
}
|
1208 |
|
|
else
|
1209 |
|
|
{
|
1210 |
|
|
address_present = 0;
|
1211 |
|
|
address = -1; /* Dummy value. */
|
1212 |
|
|
}
|
1213 |
|
|
}
|
1214 |
|
|
|
1215 |
|
|
if (! strncmp (arg, "idt", 3))
|
1216 |
|
|
{
|
1217 |
|
|
idt_monitor_base = address_present ? address : 0xBFC00000;
|
1218 |
|
|
pmon_monitor_base = 0;
|
1219 |
|
|
lsipmon_monitor_base = 0;
|
1220 |
|
|
}
|
1221 |
|
|
else if (! strncmp (arg, "pmon", 4))
|
1222 |
|
|
{
|
1223 |
|
|
/* pmon uses indirect calls. Hook into implied idt. */
|
1224 |
|
|
pmon_monitor_base = address_present ? address : 0xBFC00500;
|
1225 |
|
|
idt_monitor_base = pmon_monitor_base - 0x500;
|
1226 |
|
|
lsipmon_monitor_base = 0;
|
1227 |
|
|
}
|
1228 |
|
|
else if (! strncmp (arg, "lsipmon", 7))
|
1229 |
|
|
{
|
1230 |
|
|
/* lsipmon uses indirect calls. Hook into implied idt. */
|
1231 |
|
|
pmon_monitor_base = 0;
|
1232 |
|
|
lsipmon_monitor_base = address_present ? address : 0xBFC00200;
|
1233 |
|
|
idt_monitor_base = lsipmon_monitor_base - 0x200;
|
1234 |
|
|
}
|
1235 |
|
|
else if (! strncmp (arg, "none", 4))
|
1236 |
|
|
{
|
1237 |
|
|
if (address_present)
|
1238 |
|
|
{
|
1239 |
|
|
sim_io_printf (sd,
|
1240 |
|
|
"The `sim firmware none' command does "
|
1241 |
|
|
"not take an `ADDRESS' argument.\n");
|
1242 |
|
|
return SIM_RC_FAIL;
|
1243 |
|
|
}
|
1244 |
|
|
idt_monitor_base = 0;
|
1245 |
|
|
pmon_monitor_base = 0;
|
1246 |
|
|
lsipmon_monitor_base = 0;
|
1247 |
|
|
}
|
1248 |
|
|
else
|
1249 |
|
|
{
|
1250 |
|
|
sim_io_printf (sd, "\
|
1251 |
|
|
Unrecognized name given to the `sim firmware NAME' command: %s\n\
|
1252 |
|
|
Recognized firmware names are: `idt', `pmon', `lsipmon', and `none'.\n",
|
1253 |
|
|
arg);
|
1254 |
|
|
return SIM_RC_FAIL;
|
1255 |
|
|
}
|
1256 |
|
|
|
1257 |
|
|
return SIM_RC_OK;
|
1258 |
|
|
}
|
1259 |
|
|
|
1260 |
|
|
|
1261 |
|
|
|
1262 |
|
|
/* Simple monitor interface (currently setup for the IDT and PMON monitors) */
|
1263 |
|
|
int
|
1264 |
|
|
sim_monitor (SIM_DESC sd,
|
1265 |
|
|
sim_cpu *cpu,
|
1266 |
|
|
address_word cia,
|
1267 |
|
|
unsigned int reason)
|
1268 |
|
|
{
|
1269 |
|
|
#ifdef DEBUG
|
1270 |
|
|
printf("DBG: sim_monitor: entered (reason = %d)\n",reason);
|
1271 |
|
|
#endif /* DEBUG */
|
1272 |
|
|
|
1273 |
|
|
/* The IDT monitor actually allows two instructions per vector
|
1274 |
|
|
slot. However, the simulator currently causes a trap on each
|
1275 |
|
|
individual instruction. We cheat, and lose the bottom bit. */
|
1276 |
|
|
reason >>= 1;
|
1277 |
|
|
|
1278 |
|
|
/* The following callback functions are available, however the
|
1279 |
|
|
monitor we are simulating does not make use of them: get_errno,
|
1280 |
|
|
isatty, lseek, rename, system, time and unlink */
|
1281 |
|
|
switch (reason)
|
1282 |
|
|
{
|
1283 |
|
|
|
1284 |
|
|
case 6: /* int open(char *path,int flags) */
|
1285 |
|
|
{
|
1286 |
|
|
char *path = fetch_str (sd, A0);
|
1287 |
|
|
V0 = sim_io_open (sd, path, (int)A1);
|
1288 |
|
|
zfree (path);
|
1289 |
|
|
break;
|
1290 |
|
|
}
|
1291 |
|
|
|
1292 |
|
|
case 7: /* int read(int file,char *ptr,int len) */
|
1293 |
|
|
{
|
1294 |
|
|
int fd = A0;
|
1295 |
|
|
int nr = A2;
|
1296 |
|
|
char *buf = zalloc (nr);
|
1297 |
|
|
V0 = sim_io_read (sd, fd, buf, nr);
|
1298 |
|
|
sim_write (sd, A1, buf, nr);
|
1299 |
|
|
zfree (buf);
|
1300 |
|
|
}
|
1301 |
|
|
break;
|
1302 |
|
|
|
1303 |
|
|
case 8: /* int write(int file,char *ptr,int len) */
|
1304 |
|
|
{
|
1305 |
|
|
int fd = A0;
|
1306 |
|
|
int nr = A2;
|
1307 |
|
|
char *buf = zalloc (nr);
|
1308 |
|
|
sim_read (sd, A1, buf, nr);
|
1309 |
|
|
V0 = sim_io_write (sd, fd, buf, nr);
|
1310 |
|
|
if (fd == 1)
|
1311 |
|
|
sim_io_flush_stdout (sd);
|
1312 |
|
|
else if (fd == 2)
|
1313 |
|
|
sim_io_flush_stderr (sd);
|
1314 |
|
|
zfree (buf);
|
1315 |
|
|
break;
|
1316 |
|
|
}
|
1317 |
|
|
|
1318 |
|
|
case 10: /* int close(int file) */
|
1319 |
|
|
{
|
1320 |
|
|
V0 = sim_io_close (sd, (int)A0);
|
1321 |
|
|
break;
|
1322 |
|
|
}
|
1323 |
|
|
|
1324 |
|
|
case 2: /* Densan monitor: char inbyte(int waitflag) */
|
1325 |
|
|
{
|
1326 |
|
|
if (A0 == 0) /* waitflag == NOWAIT */
|
1327 |
|
|
V0 = (unsigned_word)-1;
|
1328 |
|
|
}
|
1329 |
|
|
/* Drop through to case 11 */
|
1330 |
|
|
|
1331 |
|
|
case 11: /* char inbyte(void) */
|
1332 |
|
|
{
|
1333 |
|
|
char tmp;
|
1334 |
|
|
/* ensure that all output has gone... */
|
1335 |
|
|
sim_io_flush_stdout (sd);
|
1336 |
|
|
if (sim_io_read_stdin (sd, &tmp, sizeof(char)) != sizeof(char))
|
1337 |
|
|
{
|
1338 |
|
|
sim_io_error(sd,"Invalid return from character read");
|
1339 |
|
|
V0 = (unsigned_word)-1;
|
1340 |
|
|
}
|
1341 |
|
|
else
|
1342 |
|
|
V0 = (unsigned_word)tmp;
|
1343 |
|
|
break;
|
1344 |
|
|
}
|
1345 |
|
|
|
1346 |
|
|
case 3: /* Densan monitor: void co(char chr) */
|
1347 |
|
|
case 12: /* void outbyte(char chr) : write a byte to "stdout" */
|
1348 |
|
|
{
|
1349 |
|
|
char tmp = (char)(A0 & 0xFF);
|
1350 |
|
|
sim_io_write_stdout (sd, &tmp, sizeof(char));
|
1351 |
|
|
break;
|
1352 |
|
|
}
|
1353 |
|
|
|
1354 |
|
|
case 17: /* void _exit() */
|
1355 |
|
|
{
|
1356 |
|
|
sim_io_eprintf (sd, "sim_monitor(17): _exit(int reason) to be coded\n");
|
1357 |
|
|
sim_engine_halt (SD, CPU, NULL, NULL_CIA, sim_exited,
|
1358 |
|
|
(unsigned int)(A0 & 0xFFFFFFFF));
|
1359 |
|
|
break;
|
1360 |
|
|
}
|
1361 |
|
|
|
1362 |
|
|
case 28: /* PMON flush_cache */
|
1363 |
|
|
break;
|
1364 |
|
|
|
1365 |
|
|
case 55: /* void get_mem_info(unsigned int *ptr) */
|
1366 |
|
|
/* in: A0 = pointer to three word memory location */
|
1367 |
|
|
/* out: [A0 + 0] = size */
|
1368 |
|
|
/* [A0 + 4] = instruction cache size */
|
1369 |
|
|
/* [A0 + 8] = data cache size */
|
1370 |
|
|
{
|
1371 |
|
|
unsigned_4 value;
|
1372 |
|
|
unsigned_4 zero = 0;
|
1373 |
|
|
address_word mem_size;
|
1374 |
|
|
sim_memopt *entry, *match = NULL;
|
1375 |
|
|
|
1376 |
|
|
/* Search for memory region mapped to KSEG0 or KSEG1. */
|
1377 |
|
|
for (entry = STATE_MEMOPT (sd);
|
1378 |
|
|
entry != NULL;
|
1379 |
|
|
entry = entry->next)
|
1380 |
|
|
{
|
1381 |
|
|
if ((entry->addr == K0BASE || entry->addr == K1BASE)
|
1382 |
|
|
&& (!match || entry->level < match->level))
|
1383 |
|
|
match = entry;
|
1384 |
|
|
else
|
1385 |
|
|
{
|
1386 |
|
|
sim_memopt *alias;
|
1387 |
|
|
for (alias = entry->alias;
|
1388 |
|
|
alias != NULL;
|
1389 |
|
|
alias = alias->next)
|
1390 |
|
|
if ((alias->addr == K0BASE || alias->addr == K1BASE)
|
1391 |
|
|
&& (!match || entry->level < match->level))
|
1392 |
|
|
match = entry;
|
1393 |
|
|
}
|
1394 |
|
|
}
|
1395 |
|
|
|
1396 |
|
|
/* Get region size, limit to KSEG1 size (512MB). */
|
1397 |
|
|
SIM_ASSERT (match != NULL);
|
1398 |
|
|
mem_size = (match->modulo != 0
|
1399 |
|
|
? match->modulo : match->nr_bytes);
|
1400 |
|
|
if (mem_size > K1SIZE)
|
1401 |
|
|
mem_size = K1SIZE;
|
1402 |
|
|
|
1403 |
|
|
value = mem_size;
|
1404 |
|
|
H2T (value);
|
1405 |
|
|
sim_write (sd, A0 + 0, (char *)&value, 4);
|
1406 |
|
|
sim_write (sd, A0 + 4, (char *)&zero, 4);
|
1407 |
|
|
sim_write (sd, A0 + 8, (char *)&zero, 4);
|
1408 |
|
|
/* sim_io_eprintf (sd, "sim: get_mem_info() deprecated\n"); */
|
1409 |
|
|
break;
|
1410 |
|
|
}
|
1411 |
|
|
|
1412 |
|
|
case 158: /* PMON printf */
|
1413 |
|
|
/* in: A0 = pointer to format string */
|
1414 |
|
|
/* A1 = optional argument 1 */
|
1415 |
|
|
/* A2 = optional argument 2 */
|
1416 |
|
|
/* A3 = optional argument 3 */
|
1417 |
|
|
/* out: void */
|
1418 |
|
|
/* The following is based on the PMON printf source */
|
1419 |
|
|
{
|
1420 |
|
|
address_word s = A0;
|
1421 |
|
|
char c;
|
1422 |
|
|
signed_word *ap = &A1; /* 1st argument */
|
1423 |
|
|
/* This isn't the quickest way, since we call the host print
|
1424 |
|
|
routine for every character almost. But it does avoid
|
1425 |
|
|
having to allocate and manage a temporary string buffer. */
|
1426 |
|
|
/* TODO: Include check that we only use three arguments (A1,
|
1427 |
|
|
A2 and A3) */
|
1428 |
|
|
while (sim_read (sd, s++, &c, 1) && c != '\0')
|
1429 |
|
|
{
|
1430 |
|
|
if (c == '%')
|
1431 |
|
|
{
|
1432 |
|
|
char tmp[40];
|
1433 |
|
|
enum {FMT_RJUST, FMT_LJUST, FMT_RJUST0, FMT_CENTER} fmt = FMT_RJUST;
|
1434 |
|
|
int width = 0, trunc = 0, haddot = 0, longlong = 0;
|
1435 |
|
|
while (sim_read (sd, s++, &c, 1) && c != '\0')
|
1436 |
|
|
{
|
1437 |
|
|
if (strchr ("dobxXulscefg%", c))
|
1438 |
|
|
break;
|
1439 |
|
|
else if (c == '-')
|
1440 |
|
|
fmt = FMT_LJUST;
|
1441 |
|
|
else if (c == '0')
|
1442 |
|
|
fmt = FMT_RJUST0;
|
1443 |
|
|
else if (c == '~')
|
1444 |
|
|
fmt = FMT_CENTER;
|
1445 |
|
|
else if (c == '*')
|
1446 |
|
|
{
|
1447 |
|
|
if (haddot)
|
1448 |
|
|
trunc = (int)*ap++;
|
1449 |
|
|
else
|
1450 |
|
|
width = (int)*ap++;
|
1451 |
|
|
}
|
1452 |
|
|
else if (c >= '1' && c <= '9')
|
1453 |
|
|
{
|
1454 |
|
|
address_word t = s;
|
1455 |
|
|
unsigned int n;
|
1456 |
|
|
while (sim_read (sd, s++, &c, 1) == 1 && isdigit (c))
|
1457 |
|
|
tmp[s - t] = c;
|
1458 |
|
|
tmp[s - t] = '\0';
|
1459 |
|
|
n = (unsigned int)strtol(tmp,NULL,10);
|
1460 |
|
|
if (haddot)
|
1461 |
|
|
trunc = n;
|
1462 |
|
|
else
|
1463 |
|
|
width = n;
|
1464 |
|
|
s--;
|
1465 |
|
|
}
|
1466 |
|
|
else if (c == '.')
|
1467 |
|
|
haddot = 1;
|
1468 |
|
|
}
|
1469 |
|
|
switch (c)
|
1470 |
|
|
{
|
1471 |
|
|
case '%':
|
1472 |
|
|
sim_io_printf (sd, "%%");
|
1473 |
|
|
break;
|
1474 |
|
|
case 's':
|
1475 |
|
|
if ((int)*ap != 0)
|
1476 |
|
|
{
|
1477 |
|
|
address_word p = *ap++;
|
1478 |
|
|
char ch;
|
1479 |
|
|
while (sim_read (sd, p++, &ch, 1) == 1 && ch != '\0')
|
1480 |
|
|
sim_io_printf(sd, "%c", ch);
|
1481 |
|
|
}
|
1482 |
|
|
else
|
1483 |
|
|
sim_io_printf(sd,"(null)");
|
1484 |
|
|
break;
|
1485 |
|
|
case 'c':
|
1486 |
|
|
sim_io_printf (sd, "%c", (int)*ap++);
|
1487 |
|
|
break;
|
1488 |
|
|
default:
|
1489 |
|
|
if (c == 'l')
|
1490 |
|
|
{
|
1491 |
|
|
sim_read (sd, s++, &c, 1);
|
1492 |
|
|
if (c == 'l')
|
1493 |
|
|
{
|
1494 |
|
|
longlong = 1;
|
1495 |
|
|
sim_read (sd, s++, &c, 1);
|
1496 |
|
|
}
|
1497 |
|
|
}
|
1498 |
|
|
if (strchr ("dobxXu", c))
|
1499 |
|
|
{
|
1500 |
|
|
word64 lv = (word64) *ap++;
|
1501 |
|
|
if (c == 'b')
|
1502 |
|
|
sim_io_printf(sd,"<binary not supported>");
|
1503 |
|
|
else
|
1504 |
|
|
{
|
1505 |
|
|
sprintf (tmp, "%%%s%c", longlong ? "ll" : "", c);
|
1506 |
|
|
if (longlong)
|
1507 |
|
|
sim_io_printf(sd, tmp, lv);
|
1508 |
|
|
else
|
1509 |
|
|
sim_io_printf(sd, tmp, (int)lv);
|
1510 |
|
|
}
|
1511 |
|
|
}
|
1512 |
|
|
else if (strchr ("eEfgG", c))
|
1513 |
|
|
{
|
1514 |
|
|
double dbl = *(double*)(ap++);
|
1515 |
|
|
sprintf (tmp, "%%%d.%d%c", width, trunc, c);
|
1516 |
|
|
sim_io_printf (sd, tmp, dbl);
|
1517 |
|
|
trunc = 0;
|
1518 |
|
|
}
|
1519 |
|
|
}
|
1520 |
|
|
}
|
1521 |
|
|
else
|
1522 |
|
|
sim_io_printf(sd, "%c", c);
|
1523 |
|
|
}
|
1524 |
|
|
break;
|
1525 |
|
|
}
|
1526 |
|
|
|
1527 |
|
|
default:
|
1528 |
|
|
/* Unknown reason. */
|
1529 |
|
|
return 0;
|
1530 |
|
|
}
|
1531 |
|
|
return 1;
|
1532 |
|
|
}
|
1533 |
|
|
|
1534 |
|
|
/* Store a word into memory. */
|
1535 |
|
|
|
1536 |
|
|
static void
|
1537 |
|
|
store_word (SIM_DESC sd,
|
1538 |
|
|
sim_cpu *cpu,
|
1539 |
|
|
address_word cia,
|
1540 |
|
|
uword64 vaddr,
|
1541 |
|
|
signed_word val)
|
1542 |
|
|
{
|
1543 |
|
|
address_word paddr;
|
1544 |
|
|
int uncached;
|
1545 |
|
|
|
1546 |
|
|
if ((vaddr & 3) != 0)
|
1547 |
|
|
SignalExceptionAddressStore ();
|
1548 |
|
|
else
|
1549 |
|
|
{
|
1550 |
|
|
if (AddressTranslation (vaddr, isDATA, isSTORE, &paddr, &uncached,
|
1551 |
|
|
isTARGET, isREAL))
|
1552 |
|
|
{
|
1553 |
|
|
const uword64 mask = 7;
|
1554 |
|
|
uword64 memval;
|
1555 |
|
|
unsigned int byte;
|
1556 |
|
|
|
1557 |
|
|
paddr = (paddr & ~mask) | ((paddr & mask) ^ (ReverseEndian << 2));
|
1558 |
|
|
byte = (vaddr & mask) ^ (BigEndianCPU << 2);
|
1559 |
|
|
memval = ((uword64) val) << (8 * byte);
|
1560 |
|
|
StoreMemory (uncached, AccessLength_WORD, memval, 0, paddr, vaddr,
|
1561 |
|
|
isREAL);
|
1562 |
|
|
}
|
1563 |
|
|
}
|
1564 |
|
|
}
|
1565 |
|
|
|
1566 |
|
|
/* Load a word from memory. */
|
1567 |
|
|
|
1568 |
|
|
static signed_word
|
1569 |
|
|
load_word (SIM_DESC sd,
|
1570 |
|
|
sim_cpu *cpu,
|
1571 |
|
|
address_word cia,
|
1572 |
|
|
uword64 vaddr)
|
1573 |
|
|
{
|
1574 |
|
|
if ((vaddr & 3) != 0)
|
1575 |
|
|
{
|
1576 |
|
|
SIM_CORE_SIGNAL (SD, cpu, cia, read_map, AccessLength_WORD+1, vaddr, read_transfer, sim_core_unaligned_signal);
|
1577 |
|
|
}
|
1578 |
|
|
else
|
1579 |
|
|
{
|
1580 |
|
|
address_word paddr;
|
1581 |
|
|
int uncached;
|
1582 |
|
|
|
1583 |
|
|
if (AddressTranslation (vaddr, isDATA, isLOAD, &paddr, &uncached,
|
1584 |
|
|
isTARGET, isREAL))
|
1585 |
|
|
{
|
1586 |
|
|
const uword64 mask = 0x7;
|
1587 |
|
|
const unsigned int reverse = ReverseEndian ? 1 : 0;
|
1588 |
|
|
const unsigned int bigend = BigEndianCPU ? 1 : 0;
|
1589 |
|
|
uword64 memval;
|
1590 |
|
|
unsigned int byte;
|
1591 |
|
|
|
1592 |
|
|
paddr = (paddr & ~mask) | ((paddr & mask) ^ (reverse << 2));
|
1593 |
|
|
LoadMemory (&memval,NULL,uncached, AccessLength_WORD, paddr, vaddr,
|
1594 |
|
|
isDATA, isREAL);
|
1595 |
|
|
byte = (vaddr & mask) ^ (bigend << 2);
|
1596 |
|
|
return EXTEND32 (memval >> (8 * byte));
|
1597 |
|
|
}
|
1598 |
|
|
}
|
1599 |
|
|
|
1600 |
|
|
return 0;
|
1601 |
|
|
}
|
1602 |
|
|
|
1603 |
|
|
/* Simulate the mips16 entry and exit pseudo-instructions. These
|
1604 |
|
|
would normally be handled by the reserved instruction exception
|
1605 |
|
|
code, but for ease of simulation we just handle them directly. */
|
1606 |
|
|
|
1607 |
|
|
static void
|
1608 |
|
|
mips16_entry (SIM_DESC sd,
|
1609 |
|
|
sim_cpu *cpu,
|
1610 |
|
|
address_word cia,
|
1611 |
|
|
unsigned int insn)
|
1612 |
|
|
{
|
1613 |
|
|
int aregs, sregs, rreg;
|
1614 |
|
|
|
1615 |
|
|
#ifdef DEBUG
|
1616 |
|
|
printf("DBG: mips16_entry: entered (insn = 0x%08X)\n",insn);
|
1617 |
|
|
#endif /* DEBUG */
|
1618 |
|
|
|
1619 |
|
|
aregs = (insn & 0x700) >> 8;
|
1620 |
|
|
sregs = (insn & 0x0c0) >> 6;
|
1621 |
|
|
rreg = (insn & 0x020) >> 5;
|
1622 |
|
|
|
1623 |
|
|
/* This should be checked by the caller. */
|
1624 |
|
|
if (sregs == 3)
|
1625 |
|
|
abort ();
|
1626 |
|
|
|
1627 |
|
|
if (aregs < 5)
|
1628 |
|
|
{
|
1629 |
|
|
int i;
|
1630 |
|
|
signed_word tsp;
|
1631 |
|
|
|
1632 |
|
|
/* This is the entry pseudo-instruction. */
|
1633 |
|
|
|
1634 |
|
|
for (i = 0; i < aregs; i++)
|
1635 |
|
|
store_word (SD, CPU, cia, (uword64) (SP + 4 * i), GPR[i + 4]);
|
1636 |
|
|
|
1637 |
|
|
tsp = SP;
|
1638 |
|
|
SP -= 32;
|
1639 |
|
|
|
1640 |
|
|
if (rreg)
|
1641 |
|
|
{
|
1642 |
|
|
tsp -= 4;
|
1643 |
|
|
store_word (SD, CPU, cia, (uword64) tsp, RA);
|
1644 |
|
|
}
|
1645 |
|
|
|
1646 |
|
|
for (i = 0; i < sregs; i++)
|
1647 |
|
|
{
|
1648 |
|
|
tsp -= 4;
|
1649 |
|
|
store_word (SD, CPU, cia, (uword64) tsp, GPR[16 + i]);
|
1650 |
|
|
}
|
1651 |
|
|
}
|
1652 |
|
|
else
|
1653 |
|
|
{
|
1654 |
|
|
int i;
|
1655 |
|
|
signed_word tsp;
|
1656 |
|
|
|
1657 |
|
|
/* This is the exit pseudo-instruction. */
|
1658 |
|
|
|
1659 |
|
|
tsp = SP + 32;
|
1660 |
|
|
|
1661 |
|
|
if (rreg)
|
1662 |
|
|
{
|
1663 |
|
|
tsp -= 4;
|
1664 |
|
|
RA = load_word (SD, CPU, cia, (uword64) tsp);
|
1665 |
|
|
}
|
1666 |
|
|
|
1667 |
|
|
for (i = 0; i < sregs; i++)
|
1668 |
|
|
{
|
1669 |
|
|
tsp -= 4;
|
1670 |
|
|
GPR[i + 16] = load_word (SD, CPU, cia, (uword64) tsp);
|
1671 |
|
|
}
|
1672 |
|
|
|
1673 |
|
|
SP += 32;
|
1674 |
|
|
|
1675 |
|
|
if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT)
|
1676 |
|
|
{
|
1677 |
|
|
if (aregs == 5)
|
1678 |
|
|
{
|
1679 |
|
|
FGR[0] = WORD64LO (GPR[4]);
|
1680 |
|
|
FPR_STATE[0] = fmt_uninterpreted;
|
1681 |
|
|
}
|
1682 |
|
|
else if (aregs == 6)
|
1683 |
|
|
{
|
1684 |
|
|
FGR[0] = WORD64LO (GPR[5]);
|
1685 |
|
|
FGR[1] = WORD64LO (GPR[4]);
|
1686 |
|
|
FPR_STATE[0] = fmt_uninterpreted;
|
1687 |
|
|
FPR_STATE[1] = fmt_uninterpreted;
|
1688 |
|
|
}
|
1689 |
|
|
}
|
1690 |
|
|
|
1691 |
|
|
PC = RA;
|
1692 |
|
|
}
|
1693 |
|
|
|
1694 |
|
|
}
|
1695 |
|
|
|
1696 |
|
|
/*-- trace support ----------------------------------------------------------*/
|
1697 |
|
|
|
1698 |
|
|
/* The TRACE support is provided (if required) in the memory accessing
|
1699 |
|
|
routines. Since we are also providing the architecture specific
|
1700 |
|
|
features, the architecture simulation code can also deal with
|
1701 |
|
|
notifying the TRACE world of cache flushes, etc. Similarly we do
|
1702 |
|
|
not need to provide profiling support in the simulator engine,
|
1703 |
|
|
since we can sample in the instruction fetch control loop. By
|
1704 |
|
|
defining the TRACE manifest, we add tracing as a run-time
|
1705 |
|
|
option. */
|
1706 |
|
|
|
1707 |
|
|
#if defined(TRACE)
|
1708 |
|
|
/* Tracing by default produces "din" format (as required by
|
1709 |
|
|
dineroIII). Each line of such a trace file *MUST* have a din label
|
1710 |
|
|
and address field. The rest of the line is ignored, so comments can
|
1711 |
|
|
be included if desired. The first field is the label which must be
|
1712 |
|
|
one of the following values:
|
1713 |
|
|
|
1714 |
|
|
|
1715 |
|
|
1 write data
|
1716 |
|
|
2 instruction fetch
|
1717 |
|
|
3 escape record (treated as unknown access type)
|
1718 |
|
|
4 escape record (causes cache flush)
|
1719 |
|
|
|
1720 |
|
|
The address field is a 32bit (lower-case) hexadecimal address
|
1721 |
|
|
value. The address should *NOT* be preceded by "0x".
|
1722 |
|
|
|
1723 |
|
|
The size of the memory transfer is not important when dealing with
|
1724 |
|
|
cache lines (as long as no more than a cache line can be
|
1725 |
|
|
transferred in a single operation :-), however more information
|
1726 |
|
|
could be given following the dineroIII requirement to allow more
|
1727 |
|
|
complete memory and cache simulators to provide better
|
1728 |
|
|
results. i.e. the University of Pisa has a cache simulator that can
|
1729 |
|
|
also take bus size and speed as (variable) inputs to calculate
|
1730 |
|
|
complete system performance (a much more useful ability when trying
|
1731 |
|
|
to construct an end product, rather than a processor). They
|
1732 |
|
|
currently have an ARM version of their tool called ChARM. */
|
1733 |
|
|
|
1734 |
|
|
|
1735 |
|
|
void
|
1736 |
|
|
dotrace (SIM_DESC sd,
|
1737 |
|
|
sim_cpu *cpu,
|
1738 |
|
|
FILE *tracefh,
|
1739 |
|
|
int type,
|
1740 |
|
|
SIM_ADDR address,
|
1741 |
|
|
int width,
|
1742 |
|
|
char *comment,...)
|
1743 |
|
|
{
|
1744 |
|
|
if (STATE & simTRACE) {
|
1745 |
|
|
va_list ap;
|
1746 |
|
|
fprintf(tracefh,"%d %s ; width %d ; ",
|
1747 |
|
|
type,
|
1748 |
|
|
pr_addr(address),
|
1749 |
|
|
width);
|
1750 |
|
|
va_start(ap,comment);
|
1751 |
|
|
vfprintf(tracefh,comment,ap);
|
1752 |
|
|
va_end(ap);
|
1753 |
|
|
fprintf(tracefh,"\n");
|
1754 |
|
|
}
|
1755 |
|
|
/* NOTE: Since the "din" format will only accept 32bit addresses, and
|
1756 |
|
|
we may be generating 64bit ones, we should put the hi-32bits of the
|
1757 |
|
|
address into the comment field. */
|
1758 |
|
|
|
1759 |
|
|
/* TODO: Provide a buffer for the trace lines. We can then avoid
|
1760 |
|
|
performing writes until the buffer is filled, or the file is
|
1761 |
|
|
being closed. */
|
1762 |
|
|
|
1763 |
|
|
/* NOTE: We could consider adding a comment field to the "din" file
|
1764 |
|
|
produced using type 3 markers (unknown access). This would then
|
1765 |
|
|
allow information about the program that the "din" is for, and
|
1766 |
|
|
the MIPs world that was being simulated, to be placed into the
|
1767 |
|
|
trace file. */
|
1768 |
|
|
|
1769 |
|
|
return;
|
1770 |
|
|
}
|
1771 |
|
|
#endif /* TRACE */
|
1772 |
|
|
|
1773 |
|
|
/*---------------------------------------------------------------------------*/
|
1774 |
|
|
/*-- simulator engine -------------------------------------------------------*/
|
1775 |
|
|
/*---------------------------------------------------------------------------*/
|
1776 |
|
|
|
1777 |
|
|
static void
|
1778 |
|
|
ColdReset (SIM_DESC sd)
|
1779 |
|
|
{
|
1780 |
|
|
int cpu_nr;
|
1781 |
|
|
for (cpu_nr = 0; cpu_nr < sim_engine_nr_cpus (sd); cpu_nr++)
|
1782 |
|
|
{
|
1783 |
|
|
sim_cpu *cpu = STATE_CPU (sd, cpu_nr);
|
1784 |
|
|
/* RESET: Fixed PC address: */
|
1785 |
|
|
PC = (unsigned_word) UNSIGNED64 (0xFFFFFFFFBFC00000);
|
1786 |
|
|
/* The reset vector address is in the unmapped, uncached memory space. */
|
1787 |
|
|
|
1788 |
|
|
SR &= ~(status_SR | status_TS | status_RP);
|
1789 |
|
|
SR |= (status_ERL | status_BEV);
|
1790 |
|
|
|
1791 |
|
|
/* Cheat and allow access to the complete register set immediately */
|
1792 |
|
|
if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT
|
1793 |
|
|
&& WITH_TARGET_WORD_BITSIZE == 64)
|
1794 |
|
|
SR |= status_FR; /* 64bit registers */
|
1795 |
|
|
|
1796 |
|
|
/* Ensure that any instructions with pending register updates are
|
1797 |
|
|
cleared: */
|
1798 |
|
|
PENDING_INVALIDATE();
|
1799 |
|
|
|
1800 |
|
|
/* Initialise the FPU registers to the unknown state */
|
1801 |
|
|
if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT)
|
1802 |
|
|
{
|
1803 |
|
|
int rn;
|
1804 |
|
|
for (rn = 0; (rn < 32); rn++)
|
1805 |
|
|
FPR_STATE[rn] = fmt_uninterpreted;
|
1806 |
|
|
}
|
1807 |
|
|
|
1808 |
|
|
/* Initialise the Config0 register. */
|
1809 |
|
|
C0_CONFIG = 0x80000000 /* Config1 present */
|
1810 |
|
|
| 2; /* KSEG0 uncached */
|
1811 |
|
|
if (WITH_TARGET_WORD_BITSIZE == 64)
|
1812 |
|
|
{
|
1813 |
|
|
/* FIXME Currently mips/sim-main.c:address_translation()
|
1814 |
|
|
truncates all addresses to 32-bits. */
|
1815 |
|
|
if (0 && WITH_TARGET_ADDRESS_BITSIZE == 64)
|
1816 |
|
|
C0_CONFIG |= (2 << 13); /* MIPS64, 64-bit addresses */
|
1817 |
|
|
else
|
1818 |
|
|
C0_CONFIG |= (1 << 13); /* MIPS64, 32-bit addresses */
|
1819 |
|
|
}
|
1820 |
|
|
if (BigEndianMem)
|
1821 |
|
|
C0_CONFIG |= 0x00008000; /* Big Endian */
|
1822 |
|
|
}
|
1823 |
|
|
}
|
1824 |
|
|
|
1825 |
|
|
|
1826 |
|
|
|
1827 |
|
|
|
1828 |
|
|
/* Description from page A-26 of the "MIPS IV Instruction Set" manual (revision 3.1) */
|
1829 |
|
|
/* Signal an exception condition. This will result in an exception
|
1830 |
|
|
that aborts the instruction. The instruction operation pseudocode
|
1831 |
|
|
will never see a return from this function call. */
|
1832 |
|
|
|
1833 |
|
|
void
|
1834 |
|
|
signal_exception (SIM_DESC sd,
|
1835 |
|
|
sim_cpu *cpu,
|
1836 |
|
|
address_word cia,
|
1837 |
|
|
int exception,...)
|
1838 |
|
|
{
|
1839 |
|
|
/* int vector; */
|
1840 |
|
|
|
1841 |
|
|
#ifdef DEBUG
|
1842 |
|
|
sim_io_printf(sd,"DBG: SignalException(%d) PC = 0x%s\n",exception,pr_addr(cia));
|
1843 |
|
|
#endif /* DEBUG */
|
1844 |
|
|
|
1845 |
|
|
/* Ensure that any active atomic read/modify/write operation will fail: */
|
1846 |
|
|
LLBIT = 0;
|
1847 |
|
|
|
1848 |
|
|
/* Save registers before interrupt dispatching */
|
1849 |
|
|
#ifdef SIM_CPU_EXCEPTION_TRIGGER
|
1850 |
|
|
SIM_CPU_EXCEPTION_TRIGGER(sd, cpu, cia);
|
1851 |
|
|
#endif
|
1852 |
|
|
|
1853 |
|
|
switch (exception) {
|
1854 |
|
|
|
1855 |
|
|
case DebugBreakPoint:
|
1856 |
|
|
if (! (Debug & Debug_DM))
|
1857 |
|
|
{
|
1858 |
|
|
if (INDELAYSLOT())
|
1859 |
|
|
{
|
1860 |
|
|
CANCELDELAYSLOT();
|
1861 |
|
|
|
1862 |
|
|
Debug |= Debug_DBD; /* signaled from within in delay slot */
|
1863 |
|
|
DEPC = cia - 4; /* reference the branch instruction */
|
1864 |
|
|
}
|
1865 |
|
|
else
|
1866 |
|
|
{
|
1867 |
|
|
Debug &= ~Debug_DBD; /* not signaled from within a delay slot */
|
1868 |
|
|
DEPC = cia;
|
1869 |
|
|
}
|
1870 |
|
|
|
1871 |
|
|
Debug |= Debug_DM; /* in debugging mode */
|
1872 |
|
|
Debug |= Debug_DBp; /* raising a DBp exception */
|
1873 |
|
|
PC = 0xBFC00200;
|
1874 |
|
|
sim_engine_restart (SD, CPU, NULL, NULL_CIA);
|
1875 |
|
|
}
|
1876 |
|
|
break;
|
1877 |
|
|
|
1878 |
|
|
case ReservedInstruction:
|
1879 |
|
|
{
|
1880 |
|
|
va_list ap;
|
1881 |
|
|
unsigned int instruction;
|
1882 |
|
|
va_start(ap,exception);
|
1883 |
|
|
instruction = va_arg(ap,unsigned int);
|
1884 |
|
|
va_end(ap);
|
1885 |
|
|
/* Provide simple monitor support using ReservedInstruction
|
1886 |
|
|
exceptions. The following code simulates the fixed vector
|
1887 |
|
|
entry points into the IDT monitor by causing a simulator
|
1888 |
|
|
trap, performing the monitor operation, and returning to
|
1889 |
|
|
the address held in the $ra register (standard PCS return
|
1890 |
|
|
address). This means we only need to pre-load the vector
|
1891 |
|
|
space with suitable instruction values. For systems were
|
1892 |
|
|
actual trap instructions are used, we would not need to
|
1893 |
|
|
perform this magic. */
|
1894 |
|
|
if ((instruction & RSVD_INSTRUCTION_MASK) == RSVD_INSTRUCTION)
|
1895 |
|
|
{
|
1896 |
|
|
int reason = (instruction >> RSVD_INSTRUCTION_ARG_SHIFT) & RSVD_INSTRUCTION_ARG_MASK;
|
1897 |
|
|
if (!sim_monitor (SD, CPU, cia, reason))
|
1898 |
|
|
sim_io_error (sd, "sim_monitor: unhandled reason = %d, pc = 0x%s\n", reason, pr_addr (cia));
|
1899 |
|
|
|
1900 |
|
|
/* NOTE: This assumes that a branch-and-link style
|
1901 |
|
|
instruction was used to enter the vector (which is the
|
1902 |
|
|
case with the current IDT monitor). */
|
1903 |
|
|
sim_engine_restart (SD, CPU, NULL, RA);
|
1904 |
|
|
}
|
1905 |
|
|
/* Look for the mips16 entry and exit instructions, and
|
1906 |
|
|
simulate a handler for them. */
|
1907 |
|
|
else if ((cia & 1) != 0
|
1908 |
|
|
&& (instruction & 0xf81f) == 0xe809
|
1909 |
|
|
&& (instruction & 0x0c0) != 0x0c0)
|
1910 |
|
|
{
|
1911 |
|
|
mips16_entry (SD, CPU, cia, instruction);
|
1912 |
|
|
sim_engine_restart (sd, NULL, NULL, NULL_CIA);
|
1913 |
|
|
}
|
1914 |
|
|
/* else fall through to normal exception processing */
|
1915 |
|
|
sim_io_eprintf(sd,"ReservedInstruction at PC = 0x%s\n", pr_addr (cia));
|
1916 |
|
|
}
|
1917 |
|
|
|
1918 |
|
|
default:
|
1919 |
|
|
/* Store exception code into current exception id variable (used
|
1920 |
|
|
by exit code): */
|
1921 |
|
|
|
1922 |
|
|
/* TODO: If not simulating exceptions then stop the simulator
|
1923 |
|
|
execution. At the moment we always stop the simulation. */
|
1924 |
|
|
|
1925 |
|
|
#ifdef SUBTARGET_R3900
|
1926 |
|
|
/* update interrupt-related registers */
|
1927 |
|
|
|
1928 |
|
|
/* insert exception code in bits 6:2 */
|
1929 |
|
|
CAUSE = LSMASKED32(CAUSE, 31, 7) | LSINSERTED32(exception, 6, 2);
|
1930 |
|
|
/* shift IE/KU history bits left */
|
1931 |
|
|
SR = LSMASKED32(SR, 31, 4) | LSINSERTED32(LSEXTRACTED32(SR, 3, 0), 5, 2);
|
1932 |
|
|
|
1933 |
|
|
if (STATE & simDELAYSLOT)
|
1934 |
|
|
{
|
1935 |
|
|
STATE &= ~simDELAYSLOT;
|
1936 |
|
|
CAUSE |= cause_BD;
|
1937 |
|
|
EPC = (cia - 4); /* reference the branch instruction */
|
1938 |
|
|
}
|
1939 |
|
|
else
|
1940 |
|
|
EPC = cia;
|
1941 |
|
|
|
1942 |
|
|
if (SR & status_BEV)
|
1943 |
|
|
PC = (signed)0xBFC00000 + 0x180;
|
1944 |
|
|
else
|
1945 |
|
|
PC = (signed)0x80000000 + 0x080;
|
1946 |
|
|
#else
|
1947 |
|
|
/* See figure 5-17 for an outline of the code below */
|
1948 |
|
|
if (! (SR & status_EXL))
|
1949 |
|
|
{
|
1950 |
|
|
CAUSE = (exception << 2);
|
1951 |
|
|
if (STATE & simDELAYSLOT)
|
1952 |
|
|
{
|
1953 |
|
|
STATE &= ~simDELAYSLOT;
|
1954 |
|
|
CAUSE |= cause_BD;
|
1955 |
|
|
EPC = (cia - 4); /* reference the branch instruction */
|
1956 |
|
|
}
|
1957 |
|
|
else
|
1958 |
|
|
EPC = cia;
|
1959 |
|
|
/* FIXME: TLB et.al. */
|
1960 |
|
|
/* vector = 0x180; */
|
1961 |
|
|
}
|
1962 |
|
|
else
|
1963 |
|
|
{
|
1964 |
|
|
CAUSE = (exception << 2);
|
1965 |
|
|
/* vector = 0x180; */
|
1966 |
|
|
}
|
1967 |
|
|
SR |= status_EXL;
|
1968 |
|
|
/* Store exception code into current exception id variable (used
|
1969 |
|
|
by exit code): */
|
1970 |
|
|
|
1971 |
|
|
if (SR & status_BEV)
|
1972 |
|
|
PC = (signed)0xBFC00200 + 0x180;
|
1973 |
|
|
else
|
1974 |
|
|
PC = (signed)0x80000000 + 0x180;
|
1975 |
|
|
#endif
|
1976 |
|
|
|
1977 |
|
|
switch ((CAUSE >> 2) & 0x1F)
|
1978 |
|
|
{
|
1979 |
|
|
case Interrupt:
|
1980 |
|
|
/* Interrupts arrive during event processing, no need to
|
1981 |
|
|
restart */
|
1982 |
|
|
return;
|
1983 |
|
|
|
1984 |
|
|
case NMIReset:
|
1985 |
|
|
/* Ditto */
|
1986 |
|
|
#ifdef SUBTARGET_3900
|
1987 |
|
|
/* Exception vector: BEV=0 BFC00000 / BEF=1 BFC00000 */
|
1988 |
|
|
PC = (signed)0xBFC00000;
|
1989 |
|
|
#endif /* SUBTARGET_3900 */
|
1990 |
|
|
return;
|
1991 |
|
|
|
1992 |
|
|
case TLBModification:
|
1993 |
|
|
case TLBLoad:
|
1994 |
|
|
case TLBStore:
|
1995 |
|
|
case AddressLoad:
|
1996 |
|
|
case AddressStore:
|
1997 |
|
|
case InstructionFetch:
|
1998 |
|
|
case DataReference:
|
1999 |
|
|
/* The following is so that the simulator will continue from the
|
2000 |
|
|
exception handler address. */
|
2001 |
|
|
sim_engine_halt (SD, CPU, NULL, PC,
|
2002 |
|
|
sim_stopped, SIM_SIGBUS);
|
2003 |
|
|
|
2004 |
|
|
case ReservedInstruction:
|
2005 |
|
|
case CoProcessorUnusable:
|
2006 |
|
|
PC = EPC;
|
2007 |
|
|
sim_engine_halt (SD, CPU, NULL, PC,
|
2008 |
|
|
sim_stopped, SIM_SIGILL);
|
2009 |
|
|
|
2010 |
|
|
case IntegerOverflow:
|
2011 |
|
|
case FPE:
|
2012 |
|
|
sim_engine_halt (SD, CPU, NULL, PC,
|
2013 |
|
|
sim_stopped, SIM_SIGFPE);
|
2014 |
|
|
|
2015 |
|
|
case BreakPoint:
|
2016 |
|
|
sim_engine_halt (SD, CPU, NULL, PC, sim_stopped, SIM_SIGTRAP);
|
2017 |
|
|
break;
|
2018 |
|
|
|
2019 |
|
|
case SystemCall:
|
2020 |
|
|
case Trap:
|
2021 |
|
|
sim_engine_restart (SD, CPU, NULL, PC);
|
2022 |
|
|
break;
|
2023 |
|
|
|
2024 |
|
|
case Watch:
|
2025 |
|
|
PC = EPC;
|
2026 |
|
|
sim_engine_halt (SD, CPU, NULL, PC,
|
2027 |
|
|
sim_stopped, SIM_SIGTRAP);
|
2028 |
|
|
|
2029 |
|
|
default: /* Unknown internal exception */
|
2030 |
|
|
PC = EPC;
|
2031 |
|
|
sim_engine_halt (SD, CPU, NULL, PC,
|
2032 |
|
|
sim_stopped, SIM_SIGABRT);
|
2033 |
|
|
|
2034 |
|
|
}
|
2035 |
|
|
|
2036 |
|
|
case SimulatorFault:
|
2037 |
|
|
{
|
2038 |
|
|
va_list ap;
|
2039 |
|
|
char *msg;
|
2040 |
|
|
va_start(ap,exception);
|
2041 |
|
|
msg = va_arg(ap,char *);
|
2042 |
|
|
va_end(ap);
|
2043 |
|
|
sim_engine_abort (SD, CPU, NULL_CIA,
|
2044 |
|
|
"FATAL: Simulator error \"%s\"\n",msg);
|
2045 |
|
|
}
|
2046 |
|
|
}
|
2047 |
|
|
|
2048 |
|
|
return;
|
2049 |
|
|
}
|
2050 |
|
|
|
2051 |
|
|
|
2052 |
|
|
|
2053 |
|
|
/* This function implements what the MIPS32 and MIPS64 ISAs define as
|
2054 |
|
|
"UNPREDICTABLE" behaviour.
|
2055 |
|
|
|
2056 |
|
|
About UNPREDICTABLE behaviour they say: "UNPREDICTABLE results
|
2057 |
|
|
may vary from processor implementation to processor implementation,
|
2058 |
|
|
instruction to instruction, or as a function of time on the same
|
2059 |
|
|
implementation or instruction. Software can never depend on results
|
2060 |
|
|
that are UNPREDICTABLE. ..." (MIPS64 Architecture for Programmers
|
2061 |
|
|
Volume II, The MIPS64 Instruction Set. MIPS Document MD00087 revision
|
2062 |
|
|
0.95, page 2.)
|
2063 |
|
|
|
2064 |
|
|
For UNPREDICTABLE behaviour, we print a message, if possible print
|
2065 |
|
|
the offending instructions mips.igen instruction name (provided by
|
2066 |
|
|
the caller), and stop the simulator.
|
2067 |
|
|
|
2068 |
|
|
XXX FIXME: eventually, stopping the simulator should be made conditional
|
2069 |
|
|
on a command-line option. */
|
2070 |
|
|
void
|
2071 |
|
|
unpredictable_action(sim_cpu *cpu, address_word cia)
|
2072 |
|
|
{
|
2073 |
|
|
SIM_DESC sd = CPU_STATE(cpu);
|
2074 |
|
|
|
2075 |
|
|
sim_io_eprintf(sd, "UNPREDICTABLE: PC = 0x%s\n", pr_addr (cia));
|
2076 |
|
|
sim_engine_halt (SD, CPU, NULL, cia, sim_stopped, SIM_SIGABRT);
|
2077 |
|
|
}
|
2078 |
|
|
|
2079 |
|
|
|
2080 |
|
|
/*-- co-processor support routines ------------------------------------------*/
|
2081 |
|
|
|
2082 |
|
|
static int UNUSED
|
2083 |
|
|
CoProcPresent(unsigned int coproc_number)
|
2084 |
|
|
{
|
2085 |
|
|
/* Return TRUE if simulator provides a model for the given co-processor number */
|
2086 |
|
|
return(0);
|
2087 |
|
|
}
|
2088 |
|
|
|
2089 |
|
|
void
|
2090 |
|
|
cop_lw (SIM_DESC sd,
|
2091 |
|
|
sim_cpu *cpu,
|
2092 |
|
|
address_word cia,
|
2093 |
|
|
int coproc_num,
|
2094 |
|
|
int coproc_reg,
|
2095 |
|
|
unsigned int memword)
|
2096 |
|
|
{
|
2097 |
|
|
switch (coproc_num)
|
2098 |
|
|
{
|
2099 |
|
|
case 1:
|
2100 |
|
|
if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT)
|
2101 |
|
|
{
|
2102 |
|
|
#ifdef DEBUG
|
2103 |
|
|
printf("DBG: COP_LW: memword = 0x%08X (uword64)memword = 0x%s\n",memword,pr_addr(memword));
|
2104 |
|
|
#endif
|
2105 |
|
|
StoreFPR(coproc_reg,fmt_uninterpreted_32,(uword64)memword);
|
2106 |
|
|
break;
|
2107 |
|
|
}
|
2108 |
|
|
|
2109 |
|
|
default:
|
2110 |
|
|
#if 0 /* this should be controlled by a configuration option */
|
2111 |
|
|
sim_io_printf(sd,"COP_LW(%d,%d,0x%08X) at PC = 0x%s : TODO (architecture specific)\n",coproc_num,coproc_reg,memword,pr_addr(cia));
|
2112 |
|
|
#endif
|
2113 |
|
|
break;
|
2114 |
|
|
}
|
2115 |
|
|
|
2116 |
|
|
return;
|
2117 |
|
|
}
|
2118 |
|
|
|
2119 |
|
|
void
|
2120 |
|
|
cop_ld (SIM_DESC sd,
|
2121 |
|
|
sim_cpu *cpu,
|
2122 |
|
|
address_word cia,
|
2123 |
|
|
int coproc_num,
|
2124 |
|
|
int coproc_reg,
|
2125 |
|
|
uword64 memword)
|
2126 |
|
|
{
|
2127 |
|
|
|
2128 |
|
|
#ifdef DEBUG
|
2129 |
|
|
printf("DBG: COP_LD: coproc_num = %d, coproc_reg = %d, value = 0x%s : PC = 0x%s\n", coproc_num, coproc_reg, pr_uword64(memword), pr_addr(cia) );
|
2130 |
|
|
#endif
|
2131 |
|
|
|
2132 |
|
|
switch (coproc_num) {
|
2133 |
|
|
case 1:
|
2134 |
|
|
if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT)
|
2135 |
|
|
{
|
2136 |
|
|
StoreFPR(coproc_reg,fmt_uninterpreted_64,memword);
|
2137 |
|
|
break;
|
2138 |
|
|
}
|
2139 |
|
|
|
2140 |
|
|
default:
|
2141 |
|
|
#if 0 /* this message should be controlled by a configuration option */
|
2142 |
|
|
sim_io_printf(sd,"COP_LD(%d,%d,0x%s) at PC = 0x%s : TODO (architecture specific)\n",coproc_num,coproc_reg,pr_addr(memword),pr_addr(cia));
|
2143 |
|
|
#endif
|
2144 |
|
|
break;
|
2145 |
|
|
}
|
2146 |
|
|
|
2147 |
|
|
return;
|
2148 |
|
|
}
|
2149 |
|
|
|
2150 |
|
|
|
2151 |
|
|
|
2152 |
|
|
|
2153 |
|
|
unsigned int
|
2154 |
|
|
cop_sw (SIM_DESC sd,
|
2155 |
|
|
sim_cpu *cpu,
|
2156 |
|
|
address_word cia,
|
2157 |
|
|
int coproc_num,
|
2158 |
|
|
int coproc_reg)
|
2159 |
|
|
{
|
2160 |
|
|
unsigned int value = 0;
|
2161 |
|
|
|
2162 |
|
|
switch (coproc_num)
|
2163 |
|
|
{
|
2164 |
|
|
case 1:
|
2165 |
|
|
if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT)
|
2166 |
|
|
{
|
2167 |
|
|
value = (unsigned int)ValueFPR(coproc_reg,fmt_uninterpreted_32);
|
2168 |
|
|
break;
|
2169 |
|
|
}
|
2170 |
|
|
|
2171 |
|
|
default:
|
2172 |
|
|
#if 0 /* should be controlled by configuration option */
|
2173 |
|
|
sim_io_printf(sd,"COP_SW(%d,%d) at PC = 0x%s : TODO (architecture specific)\n",coproc_num,coproc_reg,pr_addr(cia));
|
2174 |
|
|
#endif
|
2175 |
|
|
break;
|
2176 |
|
|
}
|
2177 |
|
|
|
2178 |
|
|
return(value);
|
2179 |
|
|
}
|
2180 |
|
|
|
2181 |
|
|
uword64
|
2182 |
|
|
cop_sd (SIM_DESC sd,
|
2183 |
|
|
sim_cpu *cpu,
|
2184 |
|
|
address_word cia,
|
2185 |
|
|
int coproc_num,
|
2186 |
|
|
int coproc_reg)
|
2187 |
|
|
{
|
2188 |
|
|
uword64 value = 0;
|
2189 |
|
|
switch (coproc_num)
|
2190 |
|
|
{
|
2191 |
|
|
case 1:
|
2192 |
|
|
if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT)
|
2193 |
|
|
{
|
2194 |
|
|
value = ValueFPR(coproc_reg,fmt_uninterpreted_64);
|
2195 |
|
|
break;
|
2196 |
|
|
}
|
2197 |
|
|
|
2198 |
|
|
default:
|
2199 |
|
|
#if 0 /* should be controlled by configuration option */
|
2200 |
|
|
sim_io_printf(sd,"COP_SD(%d,%d) at PC = 0x%s : TODO (architecture specific)\n",coproc_num,coproc_reg,pr_addr(cia));
|
2201 |
|
|
#endif
|
2202 |
|
|
break;
|
2203 |
|
|
}
|
2204 |
|
|
|
2205 |
|
|
return(value);
|
2206 |
|
|
}
|
2207 |
|
|
|
2208 |
|
|
|
2209 |
|
|
|
2210 |
|
|
|
2211 |
|
|
void
|
2212 |
|
|
decode_coproc (SIM_DESC sd,
|
2213 |
|
|
sim_cpu *cpu,
|
2214 |
|
|
address_word cia,
|
2215 |
|
|
unsigned int instruction)
|
2216 |
|
|
{
|
2217 |
|
|
int coprocnum = ((instruction >> 26) & 3);
|
2218 |
|
|
|
2219 |
|
|
switch (coprocnum)
|
2220 |
|
|
{
|
2221 |
|
|
case 0: /* standard CPU control and cache registers */
|
2222 |
|
|
{
|
2223 |
|
|
int code = ((instruction >> 21) & 0x1F);
|
2224 |
|
|
int rt = ((instruction >> 16) & 0x1F);
|
2225 |
|
|
int rd = ((instruction >> 11) & 0x1F);
|
2226 |
|
|
int tail = instruction & 0x3ff;
|
2227 |
|
|
/* R4000 Users Manual (second edition) lists the following CP0
|
2228 |
|
|
instructions:
|
2229 |
|
|
CODE><-RT><RD-><--TAIL--->
|
2230 |
|
|
DMFC0 Doubleword Move From CP0 (VR4100 = 01000000001tttttddddd00000000000)
|
2231 |
|
|
DMTC0 Doubleword Move To CP0 (VR4100 = 01000000101tttttddddd00000000000)
|
2232 |
|
|
MFC0 word Move From CP0 (VR4100 = 01000000000tttttddddd00000000000)
|
2233 |
|
|
MTC0 word Move To CP0 (VR4100 = 01000000100tttttddddd00000000000)
|
2234 |
|
|
TLBR Read Indexed TLB Entry (VR4100 = 01000010000000000000000000000001)
|
2235 |
|
|
TLBWI Write Indexed TLB Entry (VR4100 = 01000010000000000000000000000010)
|
2236 |
|
|
TLBWR Write Random TLB Entry (VR4100 = 01000010000000000000000000000110)
|
2237 |
|
|
TLBP Probe TLB for Matching Entry (VR4100 = 01000010000000000000000000001000)
|
2238 |
|
|
CACHE Cache operation (VR4100 = 101111bbbbbpppppiiiiiiiiiiiiiiii)
|
2239 |
|
|
ERET Exception return (VR4100 = 01000010000000000000000000011000)
|
2240 |
|
|
*/
|
2241 |
|
|
if (((code == 0x00) || (code == 0x04) /* MFC0 / MTC0 */
|
2242 |
|
|
|| (code == 0x01) || (code == 0x05)) /* DMFC0 / DMTC0 */
|
2243 |
|
|
&& tail == 0)
|
2244 |
|
|
{
|
2245 |
|
|
/* Clear double/single coprocessor move bit. */
|
2246 |
|
|
code &= ~1;
|
2247 |
|
|
|
2248 |
|
|
/* M[TF]C0 (32 bits) | DM[TF]C0 (64 bits) */
|
2249 |
|
|
|
2250 |
|
|
switch (rd) /* NOTEs: Standard CP0 registers */
|
2251 |
|
|
{
|
2252 |
|
|
/* 0 = Index R4000 VR4100 VR4300 */
|
2253 |
|
|
/* 1 = Random R4000 VR4100 VR4300 */
|
2254 |
|
|
/* 2 = EntryLo0 R4000 VR4100 VR4300 */
|
2255 |
|
|
/* 3 = EntryLo1 R4000 VR4100 VR4300 */
|
2256 |
|
|
/* 4 = Context R4000 VR4100 VR4300 */
|
2257 |
|
|
/* 5 = PageMask R4000 VR4100 VR4300 */
|
2258 |
|
|
/* 6 = Wired R4000 VR4100 VR4300 */
|
2259 |
|
|
/* 8 = BadVAddr R4000 VR4100 VR4300 */
|
2260 |
|
|
/* 9 = Count R4000 VR4100 VR4300 */
|
2261 |
|
|
/* 10 = EntryHi R4000 VR4100 VR4300 */
|
2262 |
|
|
/* 11 = Compare R4000 VR4100 VR4300 */
|
2263 |
|
|
/* 12 = SR R4000 VR4100 VR4300 */
|
2264 |
|
|
#ifdef SUBTARGET_R3900
|
2265 |
|
|
case 3:
|
2266 |
|
|
/* 3 = Config R3900 */
|
2267 |
|
|
case 7:
|
2268 |
|
|
/* 7 = Cache R3900 */
|
2269 |
|
|
case 15:
|
2270 |
|
|
/* 15 = PRID R3900 */
|
2271 |
|
|
|
2272 |
|
|
/* ignore */
|
2273 |
|
|
break;
|
2274 |
|
|
|
2275 |
|
|
case 8:
|
2276 |
|
|
/* 8 = BadVAddr R4000 VR4100 VR4300 */
|
2277 |
|
|
if (code == 0x00)
|
2278 |
|
|
GPR[rt] = (signed_word) (signed_address) COP0_BADVADDR;
|
2279 |
|
|
else
|
2280 |
|
|
COP0_BADVADDR = GPR[rt];
|
2281 |
|
|
break;
|
2282 |
|
|
|
2283 |
|
|
#endif /* SUBTARGET_R3900 */
|
2284 |
|
|
case 12:
|
2285 |
|
|
if (code == 0x00)
|
2286 |
|
|
GPR[rt] = SR;
|
2287 |
|
|
else
|
2288 |
|
|
SR = GPR[rt];
|
2289 |
|
|
break;
|
2290 |
|
|
/* 13 = Cause R4000 VR4100 VR4300 */
|
2291 |
|
|
case 13:
|
2292 |
|
|
if (code == 0x00)
|
2293 |
|
|
GPR[rt] = CAUSE;
|
2294 |
|
|
else
|
2295 |
|
|
CAUSE = GPR[rt];
|
2296 |
|
|
break;
|
2297 |
|
|
/* 14 = EPC R4000 VR4100 VR4300 */
|
2298 |
|
|
case 14:
|
2299 |
|
|
if (code == 0x00)
|
2300 |
|
|
GPR[rt] = (signed_word) (signed_address) EPC;
|
2301 |
|
|
else
|
2302 |
|
|
EPC = GPR[rt];
|
2303 |
|
|
break;
|
2304 |
|
|
/* 15 = PRId R4000 VR4100 VR4300 */
|
2305 |
|
|
#ifdef SUBTARGET_R3900
|
2306 |
|
|
/* 16 = Debug */
|
2307 |
|
|
case 16:
|
2308 |
|
|
if (code == 0x00)
|
2309 |
|
|
GPR[rt] = Debug;
|
2310 |
|
|
else
|
2311 |
|
|
Debug = GPR[rt];
|
2312 |
|
|
break;
|
2313 |
|
|
#else
|
2314 |
|
|
/* 16 = Config R4000 VR4100 VR4300 */
|
2315 |
|
|
case 16:
|
2316 |
|
|
if (code == 0x00)
|
2317 |
|
|
GPR[rt] = C0_CONFIG;
|
2318 |
|
|
else
|
2319 |
|
|
/* only bottom three bits are writable */
|
2320 |
|
|
C0_CONFIG = (C0_CONFIG & ~0x7) | (GPR[rt] & 0x7);
|
2321 |
|
|
break;
|
2322 |
|
|
#endif
|
2323 |
|
|
#ifdef SUBTARGET_R3900
|
2324 |
|
|
/* 17 = Debug */
|
2325 |
|
|
case 17:
|
2326 |
|
|
if (code == 0x00)
|
2327 |
|
|
GPR[rt] = DEPC;
|
2328 |
|
|
else
|
2329 |
|
|
DEPC = GPR[rt];
|
2330 |
|
|
break;
|
2331 |
|
|
#else
|
2332 |
|
|
/* 17 = LLAddr R4000 VR4100 VR4300 */
|
2333 |
|
|
#endif
|
2334 |
|
|
/* 18 = WatchLo R4000 VR4100 VR4300 */
|
2335 |
|
|
/* 19 = WatchHi R4000 VR4100 VR4300 */
|
2336 |
|
|
/* 20 = XContext R4000 VR4100 VR4300 */
|
2337 |
|
|
/* 26 = PErr or ECC R4000 VR4100 VR4300 */
|
2338 |
|
|
/* 27 = CacheErr R4000 VR4100 */
|
2339 |
|
|
/* 28 = TagLo R4000 VR4100 VR4300 */
|
2340 |
|
|
/* 29 = TagHi R4000 VR4100 VR4300 */
|
2341 |
|
|
/* 30 = ErrorEPC R4000 VR4100 VR4300 */
|
2342 |
|
|
if (STATE_VERBOSE_P(SD))
|
2343 |
|
|
sim_io_eprintf (SD,
|
2344 |
|
|
"Warning: PC 0x%lx:interp.c decode_coproc DEADC0DE\n",
|
2345 |
|
|
(unsigned long)cia);
|
2346 |
|
|
GPR[rt] = 0xDEADC0DE; /* CPR[0,rd] */
|
2347 |
|
|
/* CPR[0,rd] = GPR[rt]; */
|
2348 |
|
|
default:
|
2349 |
|
|
if (code == 0x00)
|
2350 |
|
|
GPR[rt] = (signed_word) (signed32) COP0_GPR[rd];
|
2351 |
|
|
else
|
2352 |
|
|
COP0_GPR[rd] = GPR[rt];
|
2353 |
|
|
#if 0
|
2354 |
|
|
if (code == 0x00)
|
2355 |
|
|
sim_io_printf(sd,"Warning: MFC0 %d,%d ignored, PC=%08x (architecture specific)\n",rt,rd, (unsigned)cia);
|
2356 |
|
|
else
|
2357 |
|
|
sim_io_printf(sd,"Warning: MTC0 %d,%d ignored, PC=%08x (architecture specific)\n",rt,rd, (unsigned)cia);
|
2358 |
|
|
#endif
|
2359 |
|
|
}
|
2360 |
|
|
}
|
2361 |
|
|
else if ((code == 0x00 || code == 0x01)
|
2362 |
|
|
&& rd == 16)
|
2363 |
|
|
{
|
2364 |
|
|
/* [D]MFC0 RT,C0_CONFIG,SEL */
|
2365 |
|
|
signed32 cfg = 0;
|
2366 |
|
|
switch (tail & 0x07)
|
2367 |
|
|
{
|
2368 |
|
|
case 0:
|
2369 |
|
|
cfg = C0_CONFIG;
|
2370 |
|
|
break;
|
2371 |
|
|
case 1:
|
2372 |
|
|
/* MIPS32 r/o Config1:
|
2373 |
|
|
Config2 present */
|
2374 |
|
|
cfg = 0x80000000;
|
2375 |
|
|
/* MIPS16 implemented.
|
2376 |
|
|
XXX How to check configuration? */
|
2377 |
|
|
cfg |= 0x0000004;
|
2378 |
|
|
if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT)
|
2379 |
|
|
/* MDMX & FPU implemented */
|
2380 |
|
|
cfg |= 0x00000021;
|
2381 |
|
|
break;
|
2382 |
|
|
case 2:
|
2383 |
|
|
/* MIPS32 r/o Config2:
|
2384 |
|
|
Config3 present. */
|
2385 |
|
|
cfg = 0x80000000;
|
2386 |
|
|
break;
|
2387 |
|
|
case 3:
|
2388 |
|
|
/* MIPS32 r/o Config3:
|
2389 |
|
|
SmartMIPS implemented. */
|
2390 |
|
|
cfg = 0x00000002;
|
2391 |
|
|
break;
|
2392 |
|
|
}
|
2393 |
|
|
GPR[rt] = cfg;
|
2394 |
|
|
}
|
2395 |
|
|
else if (code == 0x10 && (tail & 0x3f) == 0x18)
|
2396 |
|
|
{
|
2397 |
|
|
/* ERET */
|
2398 |
|
|
if (SR & status_ERL)
|
2399 |
|
|
{
|
2400 |
|
|
/* Oops, not yet available */
|
2401 |
|
|
sim_io_printf(sd,"Warning: ERET when SR[ERL] set not handled yet");
|
2402 |
|
|
PC = EPC;
|
2403 |
|
|
SR &= ~status_ERL;
|
2404 |
|
|
}
|
2405 |
|
|
else
|
2406 |
|
|
{
|
2407 |
|
|
PC = EPC;
|
2408 |
|
|
SR &= ~status_EXL;
|
2409 |
|
|
}
|
2410 |
|
|
}
|
2411 |
|
|
else if (code == 0x10 && (tail & 0x3f) == 0x10)
|
2412 |
|
|
{
|
2413 |
|
|
/* RFE */
|
2414 |
|
|
#ifdef SUBTARGET_R3900
|
2415 |
|
|
/* TX39: Copy IEp/KUp -> IEc/KUc, and IEo/KUo -> IEp/KUp */
|
2416 |
|
|
|
2417 |
|
|
/* shift IE/KU history bits right */
|
2418 |
|
|
SR = LSMASKED32(SR, 31, 4) | LSINSERTED32(LSEXTRACTED32(SR, 5, 2), 3, 0);
|
2419 |
|
|
|
2420 |
|
|
/* TODO: CACHE register */
|
2421 |
|
|
#endif /* SUBTARGET_R3900 */
|
2422 |
|
|
}
|
2423 |
|
|
else if (code == 0x10 && (tail & 0x3f) == 0x1F)
|
2424 |
|
|
{
|
2425 |
|
|
/* DERET */
|
2426 |
|
|
Debug &= ~Debug_DM;
|
2427 |
|
|
DELAYSLOT();
|
2428 |
|
|
DSPC = DEPC;
|
2429 |
|
|
}
|
2430 |
|
|
else
|
2431 |
|
|
sim_io_eprintf(sd,"Unrecognised COP0 instruction 0x%08X at PC = 0x%s : No handler present\n",instruction,pr_addr(cia));
|
2432 |
|
|
/* TODO: When executing an ERET or RFE instruction we should
|
2433 |
|
|
clear LLBIT, to ensure that any out-standing atomic
|
2434 |
|
|
read/modify/write sequence fails. */
|
2435 |
|
|
}
|
2436 |
|
|
break;
|
2437 |
|
|
|
2438 |
|
|
case 2: /* co-processor 2 */
|
2439 |
|
|
{
|
2440 |
|
|
int handle = 0;
|
2441 |
|
|
|
2442 |
|
|
|
2443 |
|
|
if(! handle)
|
2444 |
|
|
{
|
2445 |
|
|
sim_io_eprintf(sd, "COP2 instruction 0x%08X at PC = 0x%s : No handler present\n",
|
2446 |
|
|
instruction,pr_addr(cia));
|
2447 |
|
|
}
|
2448 |
|
|
}
|
2449 |
|
|
break;
|
2450 |
|
|
|
2451 |
|
|
case 1: /* should not occur (FPU co-processor) */
|
2452 |
|
|
case 3: /* should not occur (FPU co-processor) */
|
2453 |
|
|
SignalException(ReservedInstruction,instruction);
|
2454 |
|
|
break;
|
2455 |
|
|
}
|
2456 |
|
|
|
2457 |
|
|
return;
|
2458 |
|
|
}
|
2459 |
|
|
|
2460 |
|
|
|
2461 |
|
|
/* This code copied from gdb's utils.c. Would like to share this code,
|
2462 |
|
|
but don't know of a common place where both could get to it. */
|
2463 |
|
|
|
2464 |
|
|
/* Temporary storage using circular buffer */
|
2465 |
|
|
#define NUMCELLS 16
|
2466 |
|
|
#define CELLSIZE 32
|
2467 |
|
|
static char*
|
2468 |
|
|
get_cell (void)
|
2469 |
|
|
{
|
2470 |
|
|
static char buf[NUMCELLS][CELLSIZE];
|
2471 |
|
|
static int cell=0;
|
2472 |
|
|
if (++cell>=NUMCELLS) cell=0;
|
2473 |
|
|
return buf[cell];
|
2474 |
|
|
}
|
2475 |
|
|
|
2476 |
|
|
/* Print routines to handle variable size regs, etc */
|
2477 |
|
|
|
2478 |
|
|
/* Eliminate warning from compiler on 32-bit systems */
|
2479 |
|
|
static int thirty_two = 32;
|
2480 |
|
|
|
2481 |
|
|
char*
|
2482 |
|
|
pr_addr(addr)
|
2483 |
|
|
SIM_ADDR addr;
|
2484 |
|
|
{
|
2485 |
|
|
char *paddr_str=get_cell();
|
2486 |
|
|
switch (sizeof(addr))
|
2487 |
|
|
{
|
2488 |
|
|
case 8:
|
2489 |
|
|
sprintf(paddr_str,"%08lx%08lx",
|
2490 |
|
|
(unsigned long)(addr>>thirty_two),(unsigned long)(addr&0xffffffff));
|
2491 |
|
|
break;
|
2492 |
|
|
case 4:
|
2493 |
|
|
sprintf(paddr_str,"%08lx",(unsigned long)addr);
|
2494 |
|
|
break;
|
2495 |
|
|
case 2:
|
2496 |
|
|
sprintf(paddr_str,"%04x",(unsigned short)(addr&0xffff));
|
2497 |
|
|
break;
|
2498 |
|
|
default:
|
2499 |
|
|
sprintf(paddr_str,"%x",addr);
|
2500 |
|
|
}
|
2501 |
|
|
return paddr_str;
|
2502 |
|
|
}
|
2503 |
|
|
|
2504 |
|
|
char*
|
2505 |
|
|
pr_uword64(addr)
|
2506 |
|
|
uword64 addr;
|
2507 |
|
|
{
|
2508 |
|
|
char *paddr_str=get_cell();
|
2509 |
|
|
sprintf(paddr_str,"%08lx%08lx",
|
2510 |
|
|
(unsigned long)(addr>>thirty_two),(unsigned long)(addr&0xffffffff));
|
2511 |
|
|
return paddr_str;
|
2512 |
|
|
}
|
2513 |
|
|
|
2514 |
|
|
|
2515 |
|
|
void
|
2516 |
|
|
mips_core_signal (SIM_DESC sd,
|
2517 |
|
|
sim_cpu *cpu,
|
2518 |
|
|
sim_cia cia,
|
2519 |
|
|
unsigned map,
|
2520 |
|
|
int nr_bytes,
|
2521 |
|
|
address_word addr,
|
2522 |
|
|
transfer_type transfer,
|
2523 |
|
|
sim_core_signals sig)
|
2524 |
|
|
{
|
2525 |
|
|
const char *copy = (transfer == read_transfer ? "read" : "write");
|
2526 |
|
|
address_word ip = CIA_ADDR (cia);
|
2527 |
|
|
|
2528 |
|
|
switch (sig)
|
2529 |
|
|
{
|
2530 |
|
|
case sim_core_unmapped_signal:
|
2531 |
|
|
sim_io_eprintf (sd, "mips-core: %d byte %s to unmapped address 0x%lx at 0x%lx\n",
|
2532 |
|
|
nr_bytes, copy,
|
2533 |
|
|
(unsigned long) addr, (unsigned long) ip);
|
2534 |
|
|
COP0_BADVADDR = addr;
|
2535 |
|
|
SignalExceptionDataReference();
|
2536 |
|
|
break;
|
2537 |
|
|
|
2538 |
|
|
case sim_core_unaligned_signal:
|
2539 |
|
|
sim_io_eprintf (sd, "mips-core: %d byte %s to unaligned address 0x%lx at 0x%lx\n",
|
2540 |
|
|
nr_bytes, copy,
|
2541 |
|
|
(unsigned long) addr, (unsigned long) ip);
|
2542 |
|
|
COP0_BADVADDR = addr;
|
2543 |
|
|
if(transfer == read_transfer)
|
2544 |
|
|
SignalExceptionAddressLoad();
|
2545 |
|
|
else
|
2546 |
|
|
SignalExceptionAddressStore();
|
2547 |
|
|
break;
|
2548 |
|
|
|
2549 |
|
|
default:
|
2550 |
|
|
sim_engine_abort (sd, cpu, cia,
|
2551 |
|
|
"mips_core_signal - internal error - bad switch");
|
2552 |
|
|
}
|
2553 |
|
|
}
|
2554 |
|
|
|
2555 |
|
|
|
2556 |
|
|
void
|
2557 |
|
|
mips_cpu_exception_trigger(SIM_DESC sd, sim_cpu* cpu, address_word cia)
|
2558 |
|
|
{
|
2559 |
|
|
ASSERT(cpu != NULL);
|
2560 |
|
|
|
2561 |
|
|
if(cpu->exc_suspended > 0)
|
2562 |
|
|
sim_io_eprintf(sd, "Warning, nested exception triggered (%d)\n", cpu->exc_suspended);
|
2563 |
|
|
|
2564 |
|
|
PC = cia;
|
2565 |
|
|
memcpy(cpu->exc_trigger_registers, cpu->registers, sizeof(cpu->exc_trigger_registers));
|
2566 |
|
|
cpu->exc_suspended = 0;
|
2567 |
|
|
}
|
2568 |
|
|
|
2569 |
|
|
void
|
2570 |
|
|
mips_cpu_exception_suspend(SIM_DESC sd, sim_cpu* cpu, int exception)
|
2571 |
|
|
{
|
2572 |
|
|
ASSERT(cpu != NULL);
|
2573 |
|
|
|
2574 |
|
|
if(cpu->exc_suspended > 0)
|
2575 |
|
|
sim_io_eprintf(sd, "Warning, nested exception signal (%d then %d)\n",
|
2576 |
|
|
cpu->exc_suspended, exception);
|
2577 |
|
|
|
2578 |
|
|
memcpy(cpu->exc_suspend_registers, cpu->registers, sizeof(cpu->exc_suspend_registers));
|
2579 |
|
|
memcpy(cpu->registers, cpu->exc_trigger_registers, sizeof(cpu->registers));
|
2580 |
|
|
cpu->exc_suspended = exception;
|
2581 |
|
|
}
|
2582 |
|
|
|
2583 |
|
|
void
|
2584 |
|
|
mips_cpu_exception_resume(SIM_DESC sd, sim_cpu* cpu, int exception)
|
2585 |
|
|
{
|
2586 |
|
|
ASSERT(cpu != NULL);
|
2587 |
|
|
|
2588 |
|
|
if(exception == 0 && cpu->exc_suspended > 0)
|
2589 |
|
|
{
|
2590 |
|
|
/* warn not for breakpoints */
|
2591 |
|
|
if(cpu->exc_suspended != sim_signal_to_host(sd, SIM_SIGTRAP))
|
2592 |
|
|
sim_io_eprintf(sd, "Warning, resuming but ignoring pending exception signal (%d)\n",
|
2593 |
|
|
cpu->exc_suspended);
|
2594 |
|
|
}
|
2595 |
|
|
else if(exception != 0 && cpu->exc_suspended > 0)
|
2596 |
|
|
{
|
2597 |
|
|
if(exception != cpu->exc_suspended)
|
2598 |
|
|
sim_io_eprintf(sd, "Warning, resuming with mismatched exception signal (%d vs %d)\n",
|
2599 |
|
|
cpu->exc_suspended, exception);
|
2600 |
|
|
|
2601 |
|
|
memcpy(cpu->registers, cpu->exc_suspend_registers, sizeof(cpu->registers));
|
2602 |
|
|
}
|
2603 |
|
|
else if(exception != 0 && cpu->exc_suspended == 0)
|
2604 |
|
|
{
|
2605 |
|
|
sim_io_eprintf(sd, "Warning, ignoring spontanous exception signal (%d)\n", exception);
|
2606 |
|
|
}
|
2607 |
|
|
cpu->exc_suspended = 0;
|
2608 |
|
|
}
|
2609 |
|
|
|
2610 |
|
|
|
2611 |
|
|
/*---------------------------------------------------------------------------*/
|
2612 |
|
|
/*> EOF interp.c <*/
|