Commit | Line | Data |
---|---|---|
c906108c SS |
1 | /* |
2 | * This file is part of SIS. | |
3 | * | |
4 | * SIS, SPARC instruction simulator V1.6 Copyright (C) 1995 Jiri Gaisler, | |
5 | * European Space Agency | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify it under | |
8 | * the terms of the GNU General Public License as published by the Free | |
3fd725ef | 9 | * Software Foundation; either version 3 of the License, or (at your option) |
c906108c SS |
10 | * any later version. |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
15 | * more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License along with | |
51b318de | 18 | * this program; if not, see <http://www.gnu.org/licenses/>. |
c906108c SS |
19 | * |
20 | */ | |
21 | ||
5272643f | 22 | #include "config.h" |
c906108c SS |
23 | #include <signal.h> |
24 | #include <string.h> | |
25 | #include <stdio.h> | |
26 | #include <stdlib.h> | |
27 | #include <time.h> | |
28 | #include <sys/fcntl.h> | |
29 | #include "sis.h" | |
2b3cc94f | 30 | #include "libiberty.h" |
c906108c SS |
31 | #include "bfd.h" |
32 | #include <dis-asm.h> | |
33 | #include "sim-config.h" | |
34 | ||
3c25f8c7 | 35 | #include "gdb/remote-sim.h" |
aba6488e | 36 | #include "gdb/signals.h" |
c906108c | 37 | |
c906108c SS |
38 | #define PSR_CWP 0x7 |
39 | ||
c906108c SS |
40 | extern struct disassemble_info dinfo; |
41 | extern struct pstate sregs; | |
42 | extern struct estate ebase; | |
43 | ||
44 | extern int current_target_byte_order; | |
45 | extern int ctrl_c; | |
46 | extern int nfp; | |
47 | extern int ift; | |
48 | extern int rom8; | |
49 | extern int wrp; | |
50 | extern int uben; | |
51 | extern int sis_verbose; | |
52 | extern char *sis_version; | |
53 | extern struct estate ebase; | |
54 | extern struct evcell evbuf[]; | |
55 | extern struct irqcell irqarr[]; | |
56 | extern int irqpend, ext_irl; | |
57 | extern int sparclite; | |
58 | extern int dumbio; | |
59 | extern int sparclite_board; | |
60 | extern int termsave; | |
61 | extern char uart_dev1[], uart_dev2[]; | |
62 | ||
63 | int sis_gdb_break = 1; | |
64 | ||
65 | host_callback *sim_callback; | |
66 | ||
67 | int | |
68 | run_sim(sregs, icount, dis) | |
69 | struct pstate *sregs; | |
94110024 | 70 | uint64 icount; |
c906108c SS |
71 | int dis; |
72 | { | |
73 | int mexc, irq; | |
74 | ||
75 | if (sis_verbose) | |
76 | (*sim_callback->printf_filtered) (sim_callback, "resuming at %x\n", | |
77 | sregs->pc); | |
78 | init_stdio(); | |
79 | sregs->starttime = time(NULL); | |
80 | irq = 0; | |
81 | while (!sregs->err_mode & (icount > 0)) { | |
82 | ||
83 | sregs->fhold = 0; | |
84 | sregs->hold = 0; | |
85 | sregs->icnt = 1; | |
86 | ||
87 | if (sregs->psr & 0x080) | |
88 | sregs->asi = 8; | |
89 | else | |
90 | sregs->asi = 9; | |
91 | ||
92 | #if 0 /* DELETE ME! for debugging purposes only */ | |
93 | if (sis_verbose > 1) | |
94 | if (sregs->pc == 0 || sregs->npc == 0) | |
95 | printf ("bogus pc or npc\n"); | |
96 | #endif | |
97 | mexc = memory_read(sregs->asi, sregs->pc, &sregs->inst, | |
98 | 2, &sregs->hold); | |
99 | #if 1 /* DELETE ME! for debugging purposes only */ | |
100 | if (sis_verbose > 2) | |
101 | printf("pc %x, np %x, sp %x, fp %x, wm %x, cw %x, i %08x\n", | |
102 | sregs->pc, sregs->npc, | |
103 | sregs->r[(((sregs->psr & 7) << 4) + 14) & 0x7f], | |
104 | sregs->r[(((sregs->psr & 7) << 4) + 30) & 0x7f], | |
105 | sregs->wim, | |
106 | sregs->psr & 7, | |
107 | sregs->inst); | |
108 | #endif | |
109 | if (sregs->annul) { | |
110 | sregs->annul = 0; | |
111 | sregs->icnt = 1; | |
112 | sregs->pc = sregs->npc; | |
113 | sregs->npc = sregs->npc + 4; | |
114 | } else { | |
115 | if (ext_irl) irq = check_interrupts(sregs); | |
116 | if (!irq) { | |
117 | if (mexc) { | |
118 | sregs->trap = I_ACC_EXC; | |
119 | } else { | |
120 | if ((sis_gdb_break) && (sregs->inst == 0x91d02001)) { | |
121 | if (sis_verbose) | |
122 | (*sim_callback->printf_filtered) (sim_callback, | |
123 | "SW BP hit at %x\n", sregs->pc); | |
124 | sim_halt(); | |
125 | restore_stdio(); | |
126 | clearerr(stdin); | |
127 | return (BPT_HIT); | |
128 | } else | |
129 | dispatch_instruction(sregs); | |
130 | } | |
131 | icount--; | |
132 | } | |
133 | if (sregs->trap) { | |
134 | irq = 0; | |
135 | sregs->err_mode = execute_trap(sregs); | |
136 | } | |
137 | } | |
138 | advance_time(sregs); | |
139 | if (ctrl_c) { | |
140 | icount = 0; | |
141 | } | |
142 | } | |
143 | sim_halt(); | |
144 | sregs->tottime += time(NULL) - sregs->starttime; | |
145 | restore_stdio(); | |
146 | clearerr(stdin); | |
147 | if (sregs->err_mode) | |
148 | error_mode(sregs->pc); | |
149 | if (sregs->err_mode) | |
150 | return (ERROR); | |
151 | if (sregs->bphit) { | |
152 | if (sis_verbose) | |
153 | (*sim_callback->printf_filtered) (sim_callback, | |
154 | "HW BP hit at %x\n", sregs->pc); | |
155 | return (BPT_HIT); | |
156 | } | |
157 | if (ctrl_c) { | |
158 | ctrl_c = 0; | |
159 | return (CTRL_C); | |
160 | } | |
161 | return (TIME_OUT); | |
162 | } | |
163 | ||
164 | void | |
165 | sim_set_callbacks (ptr) | |
166 | host_callback *ptr; | |
167 | { | |
168 | sim_callback = ptr; | |
169 | } | |
170 | ||
171 | void | |
172 | sim_size (memsize) | |
173 | int memsize; | |
174 | { | |
175 | } | |
176 | ||
177 | SIM_DESC | |
178 | sim_open (kind, callback, abfd, argv) | |
179 | SIM_OPEN_KIND kind; | |
180 | struct host_callback_struct *callback; | |
6b4a8935 | 181 | struct bfd *abfd; |
c906108c SS |
182 | char **argv; |
183 | { | |
184 | ||
185 | int argc = 0; | |
186 | int stat = 1; | |
187 | int freq = 0; | |
188 | ||
189 | sim_callback = callback; | |
190 | ||
191 | while (argv[argc]) | |
192 | argc++; | |
193 | while (stat < argc) { | |
194 | if (argv[stat][0] == '-') { | |
195 | if (strcmp(argv[stat], "-v") == 0) { | |
196 | sis_verbose++; | |
197 | } else | |
198 | if (strcmp(argv[stat], "-nfp") == 0) { | |
199 | nfp = 1; | |
200 | } else | |
201 | if (strcmp(argv[stat], "-ift") == 0) { | |
202 | ift = 1; | |
203 | } else | |
204 | if (strcmp(argv[stat], "-sparclite") == 0) { | |
205 | sparclite = 1; | |
206 | } else | |
207 | if (strcmp(argv[stat], "-sparclite-board") == 0) { | |
208 | sparclite_board = 1; | |
209 | } else | |
210 | if (strcmp(argv[stat], "-dumbio") == 0) { | |
211 | dumbio = 1; | |
212 | } else | |
213 | if (strcmp(argv[stat], "-wrp") == 0) { | |
214 | wrp = 1; | |
215 | } else | |
216 | if (strcmp(argv[stat], "-rom8") == 0) { | |
217 | rom8 = 1; | |
218 | } else | |
219 | if (strcmp(argv[stat], "-uben") == 0) { | |
220 | uben = 1; | |
221 | } else | |
222 | if (strcmp(argv[stat], "-uart1") == 0) { | |
223 | if ((stat + 1) < argc) | |
224 | strcpy(uart_dev1, argv[++stat]); | |
225 | } else | |
226 | if (strcmp(argv[stat], "-uart2") == 0) { | |
227 | if ((stat + 1) < argc) | |
228 | strcpy(uart_dev2, argv[++stat]); | |
229 | } else | |
230 | if (strcmp(argv[stat], "-nogdb") == 0) { | |
231 | sis_gdb_break = 0; | |
232 | } else | |
233 | if (strcmp(argv[stat], "-freq") == 0) { | |
234 | if ((stat + 1) < argc) { | |
94110024 | 235 | freq = strtol(argv[++stat], (char **)NULL, 0); |
c906108c | 236 | } |
ce6f492f MF |
237 | } else |
238 | if (strncmp(argv[stat], "--sysroot=", sizeof("--sysroot=") - 1) == 0) { | |
239 | /* Ignore until we start to support this. */ | |
c906108c SS |
240 | } else { |
241 | (*sim_callback->printf_filtered) (sim_callback, | |
242 | "unknown option %s\n", | |
243 | argv[stat]); | |
244 | } | |
245 | } else | |
246 | bfd_load(argv[stat]); | |
247 | stat++; | |
248 | } | |
249 | ||
250 | if (sis_verbose) { | |
251 | (*sim_callback->printf_filtered) (sim_callback, "\n SIS - SPARC instruction simulator %s\n", sis_version); | |
252 | (*sim_callback->printf_filtered) (sim_callback, " Bug-reports to Jiri Gaisler ESA/ESTEC (jgais@wd.estec.esa.nl)\n"); | |
253 | if (nfp) | |
254 | (*sim_callback->printf_filtered) (sim_callback, "no FPU\n"); | |
255 | if (sparclite) | |
256 | (*sim_callback->printf_filtered) (sim_callback, "simulating Sparclite\n"); | |
257 | if (dumbio) | |
258 | (*sim_callback->printf_filtered) (sim_callback, "dumb IO (no input, dumb output)\n"); | |
259 | if (sis_gdb_break == 0) | |
260 | (*sim_callback->printf_filtered) (sim_callback, "disabling GDB trap handling for breakpoints\n"); | |
261 | if (freq) | |
262 | (*sim_callback->printf_filtered) (sim_callback, " ERC32 freq %d Mhz\n", freq); | |
263 | } | |
264 | ||
265 | sregs.freq = freq ? freq : 15; | |
266 | termsave = fcntl(0, F_GETFL, 0); | |
267 | INIT_DISASSEMBLE_INFO(dinfo, stdout,(fprintf_ftype)fprintf); | |
268 | dinfo.endian = BFD_ENDIAN_BIG; | |
269 | reset_all(); | |
270 | ebase.simtime = 0; | |
271 | init_sim(); | |
272 | init_bpt(&sregs); | |
273 | reset_stat(&sregs); | |
274 | ||
275 | /* Fudge our descriptor for now. */ | |
276 | return (SIM_DESC) 1; | |
277 | } | |
278 | ||
279 | void | |
280 | sim_close(sd, quitting) | |
281 | SIM_DESC sd; | |
282 | int quitting; | |
283 | { | |
284 | ||
285 | exit_sim(); | |
286 | fcntl(0, F_SETFL, termsave); | |
287 | ||
288 | }; | |
289 | ||
290 | SIM_RC | |
291 | sim_load(sd, prog, abfd, from_tty) | |
292 | SIM_DESC sd; | |
293 | char *prog; | |
294 | bfd *abfd; | |
295 | int from_tty; | |
296 | { | |
297 | bfd_load (prog); | |
298 | return SIM_RC_OK; | |
299 | } | |
300 | ||
301 | SIM_RC | |
302 | sim_create_inferior(sd, abfd, argv, env) | |
303 | SIM_DESC sd; | |
6b4a8935 | 304 | struct bfd *abfd; |
c906108c SS |
305 | char **argv; |
306 | char **env; | |
307 | { | |
308 | bfd_vma start_address = 0; | |
309 | if (abfd != NULL) | |
310 | start_address = bfd_get_start_address (abfd); | |
311 | ||
312 | ebase.simtime = 0; | |
313 | reset_all(); | |
314 | reset_stat(&sregs); | |
315 | sregs.pc = start_address & ~3; | |
316 | sregs.npc = sregs.pc + 4; | |
317 | return SIM_RC_OK; | |
318 | } | |
319 | ||
320 | int | |
321 | sim_store_register(sd, regno, value, length) | |
322 | SIM_DESC sd; | |
323 | int regno; | |
324 | unsigned char *value; | |
325 | int length; | |
326 | { | |
327 | /* FIXME: Review the computation of regval. */ | |
328 | int regval; | |
329 | if (current_target_byte_order == BIG_ENDIAN) | |
330 | regval = (value[0] << 24) | (value[1] << 16) | |
331 | | (value[2] << 8) | value[3]; | |
332 | else | |
333 | regval = (value[3] << 24) | (value[2] << 16) | |
334 | | (value[1] << 8) | value[0]; | |
335 | set_regi(&sregs, regno, regval); | |
dae477fe | 336 | return length; |
c906108c SS |
337 | } |
338 | ||
339 | ||
340 | int | |
341 | sim_fetch_register(sd, regno, buf, length) | |
342 | SIM_DESC sd; | |
343 | int regno; | |
344 | unsigned char *buf; | |
345 | int length; | |
346 | { | |
347 | get_regi(&sregs, regno, buf); | |
348 | return -1; | |
349 | } | |
350 | ||
351 | int | |
352 | sim_write(sd, mem, buf, length) | |
353 | SIM_DESC sd; | |
354 | SIM_ADDR mem; | |
5558e7e6 | 355 | const unsigned char *buf; |
c906108c SS |
356 | int length; |
357 | { | |
358 | return (sis_memory_write(mem, buf, length)); | |
359 | } | |
360 | ||
361 | int | |
362 | sim_read(sd, mem, buf, length) | |
363 | SIM_DESC sd; | |
364 | SIM_ADDR mem; | |
365 | unsigned char *buf; | |
366 | int length; | |
367 | { | |
368 | return (sis_memory_read(mem, buf, length)); | |
369 | } | |
370 | ||
371 | void | |
372 | sim_info(sd, verbose) | |
373 | SIM_DESC sd; | |
374 | int verbose; | |
375 | { | |
376 | show_stat(&sregs); | |
377 | } | |
378 | ||
379 | int simstat = OK; | |
380 | ||
381 | void | |
382 | sim_stop_reason(sd, reason, sigrc) | |
383 | SIM_DESC sd; | |
384 | enum sim_stop * reason; | |
385 | int *sigrc; | |
386 | { | |
387 | ||
388 | switch (simstat) { | |
389 | case CTRL_C: | |
390 | *reason = sim_stopped; | |
a493e3e2 | 391 | *sigrc = GDB_SIGNAL_INT; |
c906108c SS |
392 | break; |
393 | case OK: | |
394 | case TIME_OUT: | |
395 | case BPT_HIT: | |
396 | *reason = sim_stopped; | |
a493e3e2 | 397 | *sigrc = GDB_SIGNAL_TRAP; |
c906108c SS |
398 | break; |
399 | case ERROR: | |
400 | *sigrc = 0; | |
401 | *reason = sim_exited; | |
402 | } | |
403 | ctrl_c = 0; | |
404 | simstat = OK; | |
405 | } | |
406 | ||
407 | /* Flush all register windows out to the stack. Starting after the invalid | |
408 | window, flush all windows up to, and including the current window. This | |
409 | allows GDB to do backtraces and look at local variables for frames that | |
410 | are still in the register windows. Note that strictly speaking, this | |
411 | behavior is *wrong* for several reasons. First, it doesn't use the window | |
412 | overflow handlers. It therefore assumes standard frame layouts and window | |
413 | handling policies. Second, it changes system state behind the back of the | |
414 | target program. I expect this to mainly pose problems when debugging trap | |
415 | handlers. | |
416 | */ | |
417 | ||
418 | static void | |
419 | flush_windows () | |
420 | { | |
421 | int invwin; | |
422 | int cwp; | |
423 | int win; | |
424 | int ws; | |
425 | ||
426 | /* Keep current window handy */ | |
427 | ||
428 | cwp = sregs.psr & PSR_CWP; | |
429 | ||
430 | /* Calculate the invalid window from the wim. */ | |
431 | ||
432 | for (invwin = 0; invwin <= PSR_CWP; invwin++) | |
433 | if ((sregs.wim >> invwin) & 1) | |
434 | break; | |
435 | ||
436 | /* Start saving with the window after the invalid window. */ | |
437 | ||
438 | invwin = (invwin - 1) & PSR_CWP; | |
439 | ||
440 | for (win = invwin; ; win = (win - 1) & PSR_CWP) | |
441 | { | |
442 | uint32 sp; | |
443 | int i; | |
444 | ||
445 | sp = sregs.r[(win * 16 + 14) & 0x7f]; | |
446 | #if 1 | |
447 | if (sis_verbose > 2) { | |
448 | uint32 fp = sregs.r[(win * 16 + 30) & 0x7f]; | |
449 | printf("flush_window: win %d, sp %x, fp %x\n", win, sp, fp); | |
450 | } | |
451 | #endif | |
452 | ||
453 | for (i = 0; i < 16; i++) | |
454 | memory_write (11, sp + 4 * i, &sregs.r[(win * 16 + 16 + i) & 0x7f], 2, | |
455 | &ws); | |
456 | ||
457 | if (win == cwp) | |
458 | break; | |
459 | } | |
460 | } | |
461 | ||
462 | void | |
463 | sim_resume(SIM_DESC sd, int step, int siggnal) | |
464 | { | |
94110024 | 465 | simstat = run_sim(&sregs, UINT64_MAX, 0); |
c906108c SS |
466 | |
467 | if (sis_gdb_break) flush_windows (); | |
468 | } | |
469 | ||
470 | int | |
471 | sim_trace (sd) | |
472 | SIM_DESC sd; | |
473 | { | |
474 | /* FIXME: unfinished */ | |
475 | sim_resume (sd, 0, 0); | |
476 | return 1; | |
477 | } | |
478 | ||
479 | void | |
480 | sim_do_command(sd, cmd) | |
481 | SIM_DESC sd; | |
482 | char *cmd; | |
483 | { | |
484 | exec_cmd(&sregs, cmd); | |
485 | } | |
486 | ||
248d2a8f JB |
487 | char ** |
488 | sim_complete_command (SIM_DESC sd, char *text, char *word) | |
489 | { | |
490 | return NULL; | |
491 | } | |
492 | ||
c906108c SS |
493 | #if 0 /* FIXME: These shouldn't exist. */ |
494 | ||
495 | int | |
496 | sim_insert_breakpoint(int addr) | |
497 | { | |
498 | if (sregs.bptnum < BPT_MAX) { | |
499 | sregs.bpts[sregs.bptnum] = addr & ~0x3; | |
500 | sregs.bptnum++; | |
501 | if (sis_verbose) | |
502 | (*sim_callback->printf_filtered) (sim_callback, "inserted HW BP at %x\n", addr); | |
503 | return 0; | |
504 | } else | |
505 | return 1; | |
506 | } | |
507 | ||
508 | int | |
509 | sim_remove_breakpoint(int addr) | |
510 | { | |
511 | int i = 0; | |
512 | ||
513 | while ((i < sregs.bptnum) && (sregs.bpts[i] != addr)) | |
514 | i++; | |
515 | if (addr == sregs.bpts[i]) { | |
516 | for (; i < sregs.bptnum - 1; i++) | |
517 | sregs.bpts[i] = sregs.bpts[i + 1]; | |
518 | sregs.bptnum -= 1; | |
519 | if (sis_verbose) | |
520 | (*sim_callback->printf_filtered) (sim_callback, "removed HW BP at %x\n", addr); | |
521 | return 0; | |
522 | } | |
523 | return 1; | |
524 | } | |
525 | ||
526 | #endif |