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