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
run_sim(struct pstate * sregs,uint64_t icount,int dis)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)
fprintf_styled(void * stream,enum disassembler_style style,const char * fmt,...)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
sim_open(SIM_OPEN_KIND kind,struct host_callback_struct * callback,struct bfd * abfd,char * const * argv)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
sim_close(SIM_DESC sd,int quitting)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
sim_load(SIM_DESC sd,const char * prog,bfd * abfd,int from_tty)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
sim_create_inferior(SIM_DESC sd,bfd * abfd,char * const * argv,char * const * env)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
sim_store_register(SIM_DESC sd,int regno,const void * buf,int length)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
sim_fetch_register(SIM_DESC sd,int regno,void * buf,int length)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
sim_write(SIM_DESC sd,uint64_t addr,const void * buffer,uint64_t length)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
sim_read(SIM_DESC sd,uint64_t addr,void * buffer,uint64_t length)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
sim_info(SIM_DESC sd,bool verbose)357 sim_info(SIM_DESC sd, bool verbose)
358 {
359     show_stat(&sregs);
360 }
361 
362 int             simstat = OK;
363 
364 void
sim_stop_reason(SIM_DESC sd,enum sim_stop * reason,int * sigrc)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
flush_windows(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
sim_resume(SIM_DESC sd,int step,int siggnal)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
sim_do_command(SIM_DESC sd,const char * cmd)451 sim_do_command(SIM_DESC sd, const char *cmd)
452 {
453     exec_cmd(&sregs, cmd);
454 }
455 
456 char **
sim_complete_command(SIM_DESC sd,const char * text,const char * word)457 sim_complete_command (SIM_DESC sd, const char *text, const char *word)
458 {
459   return NULL;
460 }
461 
462 char *
sim_memory_map(SIM_DESC sd)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