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