Commit | Line | Data |
---|---|---|
646c6f2b | 1 | /* Main simulator entry points for the M32R. |
fbb8b6b9 | 2 | Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. |
646c6f2b DE |
3 | Contributed by Cygnus Support. |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 2, or (at your option) | |
8 | any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License along | |
16 | with this program; if not, write to the Free Software Foundation, Inc., | |
17 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
18 | ||
19 | #include "sim-main.h" | |
646c6f2b DE |
20 | #ifdef HAVE_STDLIB_H |
21 | #include <stdlib.h> | |
22 | #endif | |
5f4c24c0 | 23 | #include "sim-options.h" |
646c6f2b DE |
24 | #include "libiberty.h" |
25 | #include "bfd.h" | |
0e701ac3 | 26 | #include "targ-vals.h" |
646c6f2b | 27 | |
fbb8b6b9 | 28 | static void free_state (SIM_DESC); |
0e701ac3 | 29 | static void print_m32r_misc_cpu (SIM_CPU *cpu, int verbose); |
646c6f2b | 30 | |
fbb8b6b9 AC |
31 | /* Records simulator descriptor so utilities like m32r_dump_regs can be |
32 | called from gdb. */ | |
33 | SIM_DESC current_state; | |
34 | \f | |
fbb8b6b9 AC |
35 | /* Cover function of sim_state_free to free the cpu buffers as well. */ |
36 | ||
37 | static void | |
38 | free_state (SIM_DESC sd) | |
39 | { | |
5f4c24c0 DE |
40 | if (STATE_MODULES (sd) != NULL) |
41 | sim_module_uninstall (sd); | |
42 | sim_cpu_free_all (sd); | |
fbb8b6b9 AC |
43 | sim_state_free (sd); |
44 | } | |
646c6f2b DE |
45 | |
46 | /* Create an instance of the simulator. */ | |
47 | ||
48 | SIM_DESC | |
247fccde | 49 | sim_open (kind, callback, abfd, argv) |
646c6f2b | 50 | SIM_OPEN_KIND kind; |
247fccde AC |
51 | host_callback *callback; |
52 | struct _bfd *abfd; | |
646c6f2b DE |
53 | char **argv; |
54 | { | |
fbb8b6b9 | 55 | SIM_DESC sd = sim_state_alloc (kind, callback); |
646c6f2b | 56 | |
fbb8b6b9 | 57 | /* The cpu data is kept in a separately allocated chunk of memory. */ |
5f4c24c0 | 58 | if (sim_cpu_alloc_all (sd, 1, cgen_cpu_max_extra_bytes ()) != SIM_RC_OK) |
fbb8b6b9 AC |
59 | { |
60 | free_state (sd); | |
61 | return 0; | |
62 | } | |
646c6f2b | 63 | |
5f4c24c0 DE |
64 | #if 0 /* FIXME: pc is in mach-specific struct */ |
65 | /* FIXME: watchpoints code shouldn't need this */ | |
66 | { | |
67 | SIM_CPU *current_cpu = STATE_CPU (sd, 0); | |
68 | STATE_WATCHPOINTS (sd)->pc = &(PC); | |
69 | STATE_WATCHPOINTS (sd)->sizeof_pc = sizeof (PC); | |
70 | } | |
71 | #endif | |
72 | ||
646c6f2b | 73 | if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK) |
fbb8b6b9 AC |
74 | { |
75 | free_state (sd); | |
76 | return 0; | |
77 | } | |
646c6f2b DE |
78 | |
79 | #if 0 /* FIXME: 'twould be nice if we could do this */ | |
80 | /* These options override any module options. | |
81 | Obviously ambiguity should be avoided, however the caller may wish to | |
82 | augment the meaning of an option. */ | |
83 | if (extra_options != NULL) | |
84 | sim_add_option_table (sd, extra_options); | |
85 | #endif | |
86 | ||
fbb8b6b9 AC |
87 | /* Allocate core managed memory */ |
88 | sim_do_commandf (sd, "memory region 0,0x%lx", M32R_DEFAULT_MEM_SIZE); | |
89 | ||
90 | /* Allocate a handler for the MSPR register. */ | |
91 | sim_core_attach (sd, NULL, | |
92 | 0 /*level*/, | |
5f4c24c0 | 93 | access_read_write, |
fbb8b6b9 | 94 | 0 /*space ???*/, |
5f4c24c0 DE |
95 | M32R_DEVICE_ADDR, M32R_DEVICE_LEN /*nr_bytes*/, |
96 | 0 /*modulo*/, | |
97 | &m32r_devices, | |
fbb8b6b9 AC |
98 | NULL /*buffer*/); |
99 | ||
646c6f2b DE |
100 | /* getopt will print the error message so we just have to exit if this fails. |
101 | FIXME: Hmmm... in the case of gdb we need getopt to call | |
102 | print_filtered. */ | |
103 | if (sim_parse_args (sd, argv) != SIM_RC_OK) | |
104 | { | |
fbb8b6b9 AC |
105 | free_state (sd); |
106 | return 0; | |
107 | } | |
108 | ||
5f4c24c0 | 109 | /* check for/establish the reference program image */ |
fbb8b6b9 AC |
110 | if (sim_analyze_program (sd, |
111 | (STATE_PROG_ARGV (sd) != NULL | |
112 | ? *STATE_PROG_ARGV (sd) | |
113 | : NULL), | |
114 | abfd) != SIM_RC_OK) | |
115 | { | |
fbb8b6b9 AC |
116 | free_state (sd); |
117 | return 0; | |
118 | } | |
119 | ||
5f4c24c0 DE |
120 | /* If both cpu model and state architecture are set, ensure they're |
121 | compatible. If only one is set, set the other. If neither are set, | |
122 | use the default model. STATE_ARCHITECTURE is the bfd_arch_info data | |
123 | for the selected "mach" (bfd terminology). */ | |
124 | { | |
125 | SIM_CPU *cpu = STATE_CPU (sd, 0); | |
126 | ||
127 | if (! STATE_ARCHITECTURE (sd) | |
128 | /* Only check cpu 0. STATE_ARCHITECTURE is for that one only. */ | |
129 | && ! CPU_MACH (cpu)) | |
130 | { | |
131 | /* Set the default model. */ | |
132 | const MODEL *model = sim_model_lookup (WITH_DEFAULT_MODEL); | |
133 | sim_model_set (sd, NULL, model); | |
134 | } | |
135 | if (STATE_ARCHITECTURE (sd) | |
136 | && CPU_MACH (cpu)) | |
137 | { | |
138 | if (strcmp (STATE_ARCHITECTURE (sd)->printable_name, | |
139 | MACH_NAME (CPU_MACH (cpu))) != 0) | |
140 | { | |
141 | sim_io_eprintf (sd, "invalid model `%s' for `%s'\n", | |
142 | MODEL_NAME (CPU_MODEL (cpu)), | |
143 | STATE_ARCHITECTURE (sd)->printable_name); | |
144 | free_state (sd); | |
145 | return 0; | |
146 | } | |
147 | } | |
148 | else if (STATE_ARCHITECTURE (sd)) | |
149 | { | |
150 | /* Use the default model for the selected machine. | |
151 | The default model is the first one in the list. */ | |
152 | const MACH *mach = sim_mach_lookup (STATE_ARCHITECTURE (sd)->printable_name); | |
153 | sim_model_set (sd, NULL, MACH_MODELS (mach)); | |
154 | } | |
155 | else | |
156 | { | |
157 | STATE_ARCHITECTURE (sd) = bfd_scan_arch (MACH_NAME (CPU_MACH (cpu))); | |
158 | } | |
159 | } | |
160 | ||
fbb8b6b9 AC |
161 | /* Establish any remaining configuration options. */ |
162 | if (sim_config (sd) != SIM_RC_OK) | |
163 | { | |
fbb8b6b9 | 164 | free_state (sd); |
646c6f2b DE |
165 | return 0; |
166 | } | |
167 | ||
168 | if (sim_post_argv_init (sd) != SIM_RC_OK) | |
169 | { | |
fbb8b6b9 | 170 | free_state (sd); |
646c6f2b DE |
171 | return 0; |
172 | } | |
173 | ||
174 | /* Initialize various cgen things not done by common framework. */ | |
175 | cgen_init (sd); | |
176 | ||
fbb8b6b9 | 177 | { |
5f4c24c0 | 178 | int c; |
247fccde | 179 | |
5f4c24c0 | 180 | for (c = 0; c < MAX_NR_PROCESSORS; ++c) |
0e701ac3 AC |
181 | { |
182 | /* Only needed for profiling, but the structure member is small. */ | |
5f4c24c0 DE |
183 | memset (& CPU_M32R_MISC_PROFILE (STATE_CPU (sd, c)), 0, |
184 | sizeof (CPU_M32R_MISC_PROFILE (STATE_CPU (sd, c)))); | |
0e701ac3 | 185 | /* Hook in callback for reporting these stats */ |
5f4c24c0 | 186 | PROFILE_INFO_CPU_CALLBACK (CPU_PROFILE_DATA (STATE_CPU (sd, c))) |
0e701ac3 AC |
187 | = print_m32r_misc_cpu; |
188 | } | |
fbb8b6b9 AC |
189 | } |
190 | ||
191 | /* Store in a global so things like sparc32_dump_regs can be invoked | |
192 | from the gdb command line. */ | |
193 | current_state = sd; | |
646c6f2b | 194 | |
fbb8b6b9 | 195 | return sd; |
646c6f2b DE |
196 | } |
197 | ||
198 | void | |
199 | sim_close (sd, quitting) | |
200 | SIM_DESC sd; | |
201 | int quitting; | |
202 | { | |
203 | sim_module_uninstall (sd); | |
204 | } | |
fbb8b6b9 | 205 | \f |
646c6f2b | 206 | SIM_RC |
fafce69a | 207 | sim_create_inferior (sd, abfd, argv, envp) |
646c6f2b | 208 | SIM_DESC sd; |
fafce69a | 209 | struct _bfd *abfd; |
646c6f2b DE |
210 | char **argv; |
211 | char **envp; | |
212 | { | |
fbb8b6b9 AC |
213 | SIM_CPU *current_cpu = STATE_CPU (sd, 0); |
214 | SIM_ADDR addr; | |
fbb8b6b9 AC |
215 | |
216 | if (abfd != NULL) | |
217 | addr = bfd_get_start_address (abfd); | |
218 | else | |
219 | addr = 0; | |
5f4c24c0 | 220 | sim_pc_set (current_cpu, addr); |
fbb8b6b9 | 221 | |
646c6f2b DE |
222 | #if 0 |
223 | STATE_ARGV (sd) = sim_copy_argv (argv); | |
224 | STATE_ENVP (sd) = sim_copy_argv (envp); | |
225 | #endif | |
fbb8b6b9 | 226 | |
646c6f2b DE |
227 | return SIM_RC_OK; |
228 | } | |
229 | ||
646c6f2b DE |
230 | int |
231 | sim_stop (SIM_DESC sd) | |
232 | { | |
fbb8b6b9 AC |
233 | switch (STATE_ARCHITECTURE (sd)->mach) |
234 | { | |
235 | case bfd_mach_m32r : | |
5f4c24c0 | 236 | return m32r_engine_stop (sd, NULL, NULL_CIA, sim_stopped, SIM_SIGINT); |
fbb8b6b9 AC |
237 | /* start-sanitize-m32rx */ |
238 | #ifdef HAVE_CPU_M32RX | |
239 | case bfd_mach_m32rx : | |
5f4c24c0 DE |
240 | return m32rx_engine_stop (sd, NULL, NULL_CIA, sim_stopped, SIM_SIGINT); |
241 | #endif | |
242 | /* end-sanitize-m32rx */ | |
243 | default : | |
244 | abort (); | |
245 | } | |
246 | } | |
247 | ||
248 | /* This isn't part of the official interface. | |
249 | This is just a good place to put this for now. */ | |
250 | ||
251 | void | |
252 | sim_sync_stop (SIM_DESC sd, SIM_CPU *cpu, PCADDR pc, enum sim_stop reason, int sigrc) | |
253 | { | |
254 | switch (STATE_ARCHITECTURE (sd)->mach) | |
255 | { | |
256 | case bfd_mach_m32r : | |
257 | (void) m32r_engine_stop (sd, cpu, pc, reason, sigrc); | |
258 | break; | |
259 | /* start-sanitize-m32rx */ | |
260 | #ifdef HAVE_CPU_M32RX | |
261 | case bfd_mach_m32rx : | |
262 | (void) m32rx_engine_stop (sd, cpu, pc, reason, sigrc); | |
263 | break; | |
fbb8b6b9 AC |
264 | #endif |
265 | /* end-sanitize-m32rx */ | |
266 | default : | |
267 | abort (); | |
268 | } | |
646c6f2b DE |
269 | } |
270 | ||
271 | void | |
272 | sim_resume (sd, step, siggnal) | |
273 | SIM_DESC sd; | |
274 | int step, siggnal; | |
275 | { | |
5f4c24c0 DE |
276 | sim_module_resume (sd); |
277 | ||
fbb8b6b9 | 278 | switch (STATE_ARCHITECTURE (sd)->mach) |
646c6f2b | 279 | { |
fbb8b6b9 AC |
280 | case bfd_mach_m32r : |
281 | m32r_engine_run (sd, step, siggnal); | |
646c6f2b | 282 | break; |
fbb8b6b9 AC |
283 | /* start-sanitize-m32rx */ |
284 | #ifdef HAVE_CPU_M32RX | |
285 | case bfd_mach_m32rx : | |
286 | m32rx_engine_run (sd, step, siggnal); | |
646c6f2b | 287 | break; |
fbb8b6b9 AC |
288 | #endif |
289 | /* end-sanitize-m32rx */ | |
290 | default : | |
291 | abort (); | |
646c6f2b | 292 | } |
5f4c24c0 DE |
293 | |
294 | sim_module_suspend (sd); | |
646c6f2b DE |
295 | } |
296 | ||
297 | /* PROFILE_CPU_CALLBACK */ | |
298 | ||
299 | static void | |
300 | print_m32r_misc_cpu (SIM_CPU *cpu, int verbose) | |
301 | { | |
302 | SIM_DESC sd = CPU_STATE (cpu); | |
7a418800 | 303 | char buf[20]; |
646c6f2b DE |
304 | |
305 | if (CPU_PROFILE_FLAGS (cpu) [PROFILE_INSN_IDX]) | |
306 | { | |
307 | sim_io_printf (sd, "Miscellaneous Statistics\n\n"); | |
7a418800 | 308 | sim_io_printf (sd, " %-*s %s\n\n", |
646c6f2b | 309 | PROFILE_LABEL_WIDTH, "Fill nops:", |
7a418800 | 310 | sim_add_commas (buf, sizeof (buf), |
fbb8b6b9 | 311 | CPU_M32R_MISC_PROFILE (cpu).fillnop_count)); |
646c6f2b DE |
312 | } |
313 | } | |
314 | ||
646c6f2b DE |
315 | /* The contents of BUF are in target byte order. */ |
316 | ||
fbb8b6b9 AC |
317 | int |
318 | sim_fetch_register (sd, rn, buf, length) | |
646c6f2b DE |
319 | SIM_DESC sd; |
320 | int rn; | |
321 | unsigned char *buf; | |
fbb8b6b9 | 322 | int length; |
646c6f2b | 323 | { |
5f4c24c0 DE |
324 | SIM_CPU *cpu = STATE_CPU (sd, 0); |
325 | ||
326 | return (* CPU_REG_FETCH (cpu)) (cpu, rn, buf, length); | |
646c6f2b DE |
327 | } |
328 | ||
329 | /* The contents of BUF are in target byte order. */ | |
330 | ||
fbb8b6b9 AC |
331 | int |
332 | sim_store_register (sd, rn, buf, length) | |
646c6f2b DE |
333 | SIM_DESC sd; |
334 | int rn; | |
335 | unsigned char *buf; | |
fbb8b6b9 | 336 | int length; |
646c6f2b | 337 | { |
5f4c24c0 DE |
338 | SIM_CPU *cpu = STATE_CPU (sd, 0); |
339 | ||
340 | return (* CPU_REG_STORE (cpu)) (cpu, rn, buf, length); | |
646c6f2b DE |
341 | } |
342 | ||
343 | void | |
344 | sim_do_command (sd, cmd) | |
345 | SIM_DESC sd; | |
346 | char *cmd; | |
347 | { | |
fbb8b6b9 AC |
348 | if (sim_args_command (sd, cmd) != SIM_RC_OK) |
349 | sim_io_eprintf (sd, "Unknown command `%s'\n", cmd); | |
350 | } | |
351 | \f | |
352 | /* The semantic code invokes this for illegal (unrecognized) instructions. */ | |
353 | ||
354 | void | |
355 | sim_engine_illegal_insn (current_cpu, pc) | |
356 | SIM_CPU *current_cpu; | |
357 | PCADDR pc; | |
358 | { | |
359 | sim_engine_halt (CPU_STATE (current_cpu), current_cpu, NULL, pc, | |
360 | sim_stopped, SIM_SIGILL); | |
646c6f2b | 361 | } |
0e701ac3 | 362 | \f |
5f4c24c0 | 363 | /* Utility fns to access registers, without knowing the current mach. */ |
0e701ac3 AC |
364 | |
365 | SI | |
366 | h_gr_get (SIM_CPU *current_cpu, UINT regno) | |
367 | { | |
368 | switch (STATE_ARCHITECTURE (CPU_STATE (current_cpu))->mach) | |
369 | { | |
370 | case bfd_mach_m32r : | |
371 | return m32r_h_gr_get (current_cpu, regno); | |
372 | /* start-sanitize-m32rx */ | |
373 | #ifdef HAVE_CPU_M32RX | |
374 | case bfd_mach_m32rx : | |
375 | return m32rx_h_gr_get (current_cpu, regno); | |
376 | #endif | |
377 | /* end-sanitize-m32rx */ | |
378 | default : | |
379 | abort (); | |
380 | } | |
381 | } | |
382 | ||
383 | void | |
384 | h_gr_set (SIM_CPU *current_cpu, UINT regno, SI newval) | |
385 | { | |
386 | switch (STATE_ARCHITECTURE (CPU_STATE (current_cpu))->mach) | |
387 | { | |
388 | case bfd_mach_m32r : | |
389 | m32r_h_gr_set (current_cpu, regno, newval); | |
390 | break; | |
391 | /* start-sanitize-m32rx */ | |
392 | #ifdef HAVE_CPU_M32RX | |
393 | case bfd_mach_m32rx : | |
394 | m32rx_h_gr_set (current_cpu, regno, newval); | |
395 | break; | |
396 | #endif | |
397 | /* end-sanitize-m32rx */ | |
398 | default : | |
399 | abort (); | |
400 | } | |
401 | } | |
402 | \f | |
403 | /* Read/write functions for system call interface. */ | |
404 | ||
405 | static int | |
406 | syscall_read_mem (host_callback *cb, struct cb_syscall *sc, | |
407 | unsigned long taddr, char *buf, int bytes) | |
408 | { | |
409 | SIM_DESC sd = (SIM_DESC) sc->p1; | |
410 | SIM_CPU *cpu = (SIM_CPU *) sc->p2; | |
411 | ||
5f4c24c0 | 412 | return sim_core_read_buffer (sd, cpu, read_map, buf, taddr, bytes); |
0e701ac3 AC |
413 | } |
414 | ||
415 | static int | |
416 | syscall_write_mem (host_callback *cb, struct cb_syscall *sc, | |
417 | unsigned long taddr, const char *buf, int bytes) | |
418 | { | |
419 | SIM_DESC sd = (SIM_DESC) sc->p1; | |
420 | SIM_CPU *cpu = (SIM_CPU *) sc->p2; | |
421 | ||
5f4c24c0 | 422 | return sim_core_write_buffer (sd, cpu, write_map, buf, taddr, bytes); |
0e701ac3 AC |
423 | } |
424 | ||
5f4c24c0 DE |
425 | /* Trap support. |
426 | The result is the pc address to continue at. */ | |
0e701ac3 | 427 | |
5f4c24c0 | 428 | USI |
0e701ac3 AC |
429 | do_trap (SIM_CPU *current_cpu, int num) |
430 | { | |
431 | SIM_DESC sd = CPU_STATE (current_cpu); | |
432 | host_callback *cb = STATE_CALLBACK (sd); | |
433 | ||
5f4c24c0 DE |
434 | #ifdef SIM_HAVE_BREAKPOINTS |
435 | /* Check for breakpoints "owned" by the simulator first, regardless | |
436 | of --environment. */ | |
437 | if (num == 1) | |
438 | { | |
439 | /* First try sim-break.c. If it's a breakpoint the simulator "owns" | |
440 | it doesn't return. Otherwise it returns and let's us try. */ | |
441 | sim_handle_breakpoint (sd, current_cpu, sim_pc_get (current_cpu)); | |
442 | /* Fall through. */ | |
443 | } | |
444 | #endif | |
445 | ||
446 | if (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT) | |
447 | { | |
448 | /* The new pc is the trap vector entry. | |
449 | We assume there's a branch there to some handler. */ | |
450 | USI new_pc = num * 4; | |
451 | return new_pc; | |
452 | } | |
453 | ||
0e701ac3 AC |
454 | switch (num) |
455 | { | |
456 | case 0 : | |
457 | /* Trap 0 is used for system calls. */ | |
458 | { | |
459 | CB_SYSCALL s; | |
460 | ||
461 | CB_SYSCALL_INIT (&s); | |
462 | s.func = h_gr_get (current_cpu, 0); | |
463 | s.arg1 = h_gr_get (current_cpu, 1); | |
464 | s.arg2 = h_gr_get (current_cpu, 2); | |
465 | s.arg3 = h_gr_get (current_cpu, 3); | |
466 | ||
467 | if (s.func == TARGET_SYS_exit) | |
468 | { | |
5f4c24c0 | 469 | sim_engine_halt (sd, current_cpu, NULL, sim_pc_get (current_cpu), |
0e701ac3 AC |
470 | sim_exited, s.arg1); |
471 | } | |
472 | ||
473 | s.p1 = (PTR) sd; | |
474 | s.p2 = (PTR) current_cpu; | |
475 | s.read_mem = syscall_read_mem; | |
476 | s.write_mem = syscall_write_mem; | |
477 | cb_syscall (STATE_CALLBACK (sd), &s); | |
478 | h_gr_set (current_cpu, 2, s.errcode); | |
479 | h_gr_set (current_cpu, 0, s.result); | |
480 | h_gr_set (current_cpu, 1, s.result2); | |
481 | break; | |
482 | } | |
483 | ||
484 | case 1: /* breakpoint trap */ | |
485 | sim_engine_halt (sd, current_cpu, NULL, NULL_CIA, | |
486 | sim_stopped, SIM_SIGTRAP); | |
487 | break; | |
488 | ||
489 | default : | |
f99354d0 DE |
490 | { |
491 | USI new_pc = num * 4; | |
492 | return new_pc; | |
493 | } | |
0e701ac3 | 494 | } |
5f4c24c0 DE |
495 | |
496 | /* Fake an "rte" insn. */ | |
497 | return (sim_pc_get (current_cpu) & -4) + 4; | |
0e701ac3 | 498 | } |