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