xref: /netbsd-src/external/gpl3/gdb/dist/sim/erc32/interf.c (revision 1f4e7eb9e5e045e008f1894823a8e4e6c9f46890)
1 /* This file is part of SIS (SPARC instruction simulator)
2 
3    Copyright (C) 1995-2024 Free Software Foundation, Inc.
4    Contributed by Jiri Gaisler, European Space Agency
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/>.  */
18 
19 /* This must come before any other includes.  */
20 #include "defs.h"
21 
22 #include <signal.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <sys/fcntl.h>
27 #include "sis.h"
28 #include "libiberty.h"
29 #include "bfd.h"
30 #include <dis-asm.h>
31 #include "sim-config.h"
32 
33 #include "sim/sim.h"
34 #include "gdb/signals.h"
35 
36 #define PSR_CWP 0x7
37 
38 extern struct disassemble_info dinfo;
39 extern struct pstate sregs;
40 extern struct estate ebase;
41 
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
65 run_sim(struct pstate *sregs, uint64_t icount, int dis)
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();
73    sregs->starttime = get_time();
74    irq = 0;
75    if ((sregs->pc != 0) && (ebase.simtime == 0))
76 	boot_init();
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
93         mexc = memory_iread (sregs->pc, &sregs->inst, &sregs->hold);
94 #if 0	/* DELETE ME! for debugging purposes only */
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);
122 			return BPT_HIT;
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();
139     sregs->tottime += get_time() - sregs->starttime;
140     restore_stdio();
141     clearerr(stdin);
142     if (sregs->err_mode)
143 	error_mode(sregs->pc);
144     if (sregs->err_mode)
145 	return ERROR;
146     if (sregs->bphit) {
147 	if (sis_verbose)
148 	    (*sim_callback->printf_filtered) (sim_callback,
149 					      "HW BP hit at %x\n", sregs->pc);
150 	return BPT_HIT;
151     }
152     if (ctrl_c) {
153 	ctrl_c = 0;
154 	return CTRL_C;
155     }
156     return TIME_OUT;
157 }
158 
159 static int ATTRIBUTE_PRINTF (3, 4)
160 fprintf_styled (void *stream, enum disassembler_style style,
161 		const char *fmt, ...)
162 {
163   int ret;
164   FILE *out = (FILE *) stream;
165   va_list args;
166 
167   va_start (args, fmt);
168   ret = vfprintf (out, fmt, args);
169   va_end (args);
170 
171   return ret;
172 }
173 
174 SIM_DESC
175 sim_open (SIM_OPEN_KIND kind, struct host_callback_struct *callback,
176 	  struct bfd *abfd, char * const *argv)
177 {
178 
179     int             argc = 0;
180     int             stat = 1;
181     int             freq = 0;
182 
183     sim_callback = callback;
184 
185     argc = countargv (argv);
186     while (stat < argc) {
187 	if (argv[stat][0] == '-') {
188 	    if (strcmp(argv[stat], "-v") == 0) {
189 		sis_verbose++;
190 	    } else
191 	    if (strcmp(argv[stat], "-nfp") == 0) {
192 		nfp = 1;
193 	    } else
194             if (strcmp(argv[stat], "-ift") == 0) {
195                 ift = 1;
196 	    } else
197 	    if (strcmp(argv[stat], "-sparclite") == 0) {
198 		sparclite = 1;
199 	    } else
200 	    if (strcmp(argv[stat], "-sparclite-board") == 0) {
201 		sparclite_board = 1;
202             } else
203             if (strcmp(argv[stat], "-dumbio") == 0) {
204 		dumbio = 1;
205 	    } else
206             if (strcmp(argv[stat], "-wrp") == 0) {
207                 wrp = 1;
208 	    } else
209             if (strcmp(argv[stat], "-rom8") == 0) {
210                 rom8 = 1;
211 	    } else
212             if (strcmp(argv[stat], "-uben") == 0) {
213                 uben = 1;
214 	    } else
215 	    if (strcmp(argv[stat], "-uart1") == 0) {
216 		if ((stat + 1) < argc)
217 		    strcpy(uart_dev1, argv[++stat]);
218 	    } else
219 	    if (strcmp(argv[stat], "-uart2") == 0) {
220 		if ((stat + 1) < argc)
221 		    strcpy(uart_dev2, argv[++stat]);
222 	    } else
223 	    if (strcmp(argv[stat], "-nogdb") == 0) {
224 		sis_gdb_break = 0;
225 	    } else
226 	    if (strcmp(argv[stat], "-freq") == 0) {
227 		if ((stat + 1) < argc) {
228 		    freq = strtol(argv[++stat], (char **)NULL, 0);
229 		}
230 	    } else
231 	    if (strncmp(argv[stat], "--sysroot=", sizeof("--sysroot=") - 1) == 0) {
232 		/* Ignore until we start to support this.  */
233 	    } else {
234 		(*sim_callback->printf_filtered) (sim_callback,
235 						  "unknown option %s\n",
236 						  argv[stat]);
237 	    }
238 	} else
239 	    bfd_load(argv[stat]);
240 	stat++;
241     }
242 
243     if (sis_verbose) {
244 	(*sim_callback->printf_filtered) (sim_callback, "\n SIS - SPARC instruction simulator %s\n", sis_version);
245 	(*sim_callback->printf_filtered) (sim_callback, " Bug-reports to Jiri Gaisler ESA/ESTEC (jgais@wd.estec.esa.nl)\n");
246 	if (nfp)
247 	  (*sim_callback->printf_filtered) (sim_callback, "no FPU\n");
248 	if (sparclite)
249 	  (*sim_callback->printf_filtered) (sim_callback, "simulating Sparclite\n");
250 	if (dumbio)
251 	  (*sim_callback->printf_filtered) (sim_callback, "dumb IO (no input, dumb output)\n");
252 	if (sis_gdb_break == 0)
253 	  (*sim_callback->printf_filtered) (sim_callback, "disabling GDB trap handling for breakpoints\n");
254 	if (freq)
255 	  (*sim_callback->printf_filtered) (sim_callback, " ERC32 freq %d Mhz\n", freq);
256     }
257 
258     sregs.freq = freq ? freq : 15;
259 #ifdef F_GETFL
260     termsave = fcntl(0, F_GETFL, 0);
261 #endif
262     INIT_DISASSEMBLE_INFO(dinfo, stdout,(fprintf_ftype)fprintf,
263 			  fprintf_styled);
264 #ifdef HOST_LITTLE_ENDIAN
265     dinfo.endian = BFD_ENDIAN_LITTLE;
266 #else
267     dinfo.endian = BFD_ENDIAN_BIG;
268 #endif
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(SIM_DESC sd, int quitting)
281 {
282 
283     exit_sim();
284 #ifdef F_SETFL
285     fcntl(0, F_SETFL, termsave);
286 #endif
287 }
288 
289 SIM_RC
290 sim_load(SIM_DESC sd, const char *prog, bfd *abfd, int from_tty)
291 {
292     bfd_load (prog);
293     return SIM_RC_OK;
294 }
295 
296 SIM_RC
297 sim_create_inferior(SIM_DESC sd, bfd *abfd, char * const *argv,
298 		    char * const *env)
299 {
300     bfd_vma start_address = 0;
301     if (abfd != NULL)
302       start_address = bfd_get_start_address (abfd);
303 
304     ebase.simtime = 0;
305     reset_all();
306     reset_stat(&sregs);
307     sregs.pc = start_address & ~3;
308     sregs.npc = sregs.pc + 4;
309     return SIM_RC_OK;
310 }
311 
312 int
313 sim_store_register(SIM_DESC sd, int regno, const void *buf, int length)
314 {
315     const unsigned char *value = buf;
316     int regval;
317 
318     regval = (value[0] << 24) | (value[1] << 16)
319 		 | (value[2] << 8) | value[3];
320     set_regi(&sregs, regno, regval);
321     return length;
322 }
323 
324 
325 int
326 sim_fetch_register(SIM_DESC sd, int regno, void *buf, int length)
327 {
328     get_regi(&sregs, regno, buf);
329     return -1;
330 }
331 
332 uint64_t
333 sim_write (SIM_DESC sd, uint64_t addr, const void *buffer, uint64_t length)
334 {
335     int i;
336     const unsigned char *data = buffer;
337 
338     for (i = 0; i < length; i++) {
339 	sis_memory_write ((addr + i) ^ EBT, &data[i], 1);
340     }
341     return length;
342 }
343 
344 uint64_t
345 sim_read (SIM_DESC sd, uint64_t addr, void *buffer, uint64_t length)
346 {
347     int i;
348     unsigned char *data = buffer;
349 
350     for (i = 0; i < length; i++) {
351 	sis_memory_read ((addr + i) ^ EBT, &data[i], 1);
352     }
353     return length;
354 }
355 
356 void
357 sim_info(SIM_DESC sd, bool verbose)
358 {
359     show_stat(&sregs);
360 }
361 
362 int             simstat = OK;
363 
364 void
365 sim_stop_reason(SIM_DESC sd, enum sim_stop *reason, int *sigrc)
366 {
367 
368     switch (simstat) {
369 	case CTRL_C:
370 	*reason = sim_stopped;
371 	*sigrc = GDB_SIGNAL_INT;
372 	break;
373     case OK:
374     case TIME_OUT:
375     case BPT_HIT:
376 	*reason = sim_stopped;
377 	*sigrc = GDB_SIGNAL_TRAP;
378 	break;
379     case ERROR:
380 	*sigrc = 0;
381 	*reason = sim_exited;
382     }
383     ctrl_c = 0;
384     simstat = OK;
385 }
386 
387 /* Flush all register windows out to the stack.  Starting after the invalid
388    window, flush all windows up to, and including the current window.  This
389    allows GDB to do backtraces and look at local variables for frames that
390    are still in the register windows.  Note that strictly speaking, this
391    behavior is *wrong* for several reasons.  First, it doesn't use the window
392    overflow handlers.  It therefore assumes standard frame layouts and window
393    handling policies.  Second, it changes system state behind the back of the
394    target program.  I expect this to mainly pose problems when debugging trap
395    handlers.
396 */
397 
398 static void
399 flush_windows (void)
400 {
401   int invwin;
402   int cwp;
403   int win;
404   int ws;
405 
406   /* Keep current window handy */
407 
408   cwp = sregs.psr & PSR_CWP;
409 
410   /* Calculate the invalid window from the wim. */
411 
412   for (invwin = 0; invwin <= PSR_CWP; invwin++)
413     if ((sregs.wim >> invwin) & 1)
414       break;
415 
416   /* Start saving with the window after the invalid window. */
417 
418   invwin = (invwin - 1) & PSR_CWP;
419 
420   for (win = invwin; ; win = (win - 1) & PSR_CWP)
421     {
422       uint32_t sp;
423       int i;
424 
425       sp = sregs.r[(win * 16 + 14) & 0x7f];
426 #if 1
427       if (sis_verbose > 2) {
428 	uint32_t fp = sregs.r[(win * 16 + 30) & 0x7f];
429 	printf("flush_window: win %d, sp %x, fp %x\n", win, sp, fp);
430       }
431 #endif
432 
433       for (i = 0; i < 16; i++)
434 	memory_write (11, sp + 4 * i, &sregs.r[(win * 16 + 16 + i) & 0x7f], 2,
435 		      &ws);
436 
437       if (win == cwp)
438 	break;
439     }
440 }
441 
442 void
443 sim_resume(SIM_DESC sd, int step, int siggnal)
444 {
445     simstat = run_sim(&sregs, UINT64_MAX, 0);
446 
447     if (sis_gdb_break) flush_windows ();
448 }
449 
450 void
451 sim_do_command(SIM_DESC sd, const char *cmd)
452 {
453     exec_cmd(&sregs, cmd);
454 }
455 
456 char **
457 sim_complete_command (SIM_DESC sd, const char *text, const char *word)
458 {
459   return NULL;
460 }
461 
462 char *
463 sim_memory_map (SIM_DESC sd)
464 {
465   return NULL;
466 }
467 
468 #if 0 /* FIXME: These shouldn't exist.  */
469 
470 int
471 sim_insert_breakpoint(int addr)
472 {
473     if (sregs.bptnum < BPT_MAX) {
474 	sregs.bpts[sregs.bptnum] = addr & ~0x3;
475 	sregs.bptnum++;
476 	if (sis_verbose)
477 	    (*sim_callback->printf_filtered) (sim_callback, "inserted HW BP at %x\n", addr);
478 	return 0;
479     } else
480 	return 1;
481 }
482 
483 int
484 sim_remove_breakpoint(int addr)
485 {
486     int             i = 0;
487 
488     while ((i < sregs.bptnum) && (sregs.bpts[i] != addr))
489 	i++;
490     if (addr == sregs.bpts[i]) {
491 	for (; i < sregs.bptnum - 1; i++)
492 	    sregs.bpts[i] = sregs.bpts[i + 1];
493 	sregs.bptnum -= 1;
494 	if (sis_verbose)
495 	    (*sim_callback->printf_filtered) (sim_callback, "removed HW BP at %x\n", addr);
496 	return 0;
497     }
498     return 1;
499 }
500 
501 #endif
502