| /* Simulator for the WDC 65816 architecture. |
| |
| Written by Steve Chamberlain of Cygnus Support. |
| sac@cygnus.com |
| |
| This file is part of W65 sim |
| |
| |
| THIS SOFTWARE IS NOT COPYRIGHTED |
| |
| Cygnus offers the following for use in the public domain. Cygnus |
| makes no warranty with regard to the software or it's performance |
| and the user accepts the software "AS IS" with all faults. |
| |
| CYGNUS DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO |
| THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
| |
| */ |
| |
| #include "config.h" |
| |
| #include <stdio.h> |
| #include <signal.h> |
| #ifdef HAVE_STDLIB_H |
| #include <stdlib.h> |
| #endif |
| #ifdef HAVE_TIME_H |
| #include <time.h> |
| #endif |
| #ifdef HAVE_UNISTD_H |
| #include <unistd.h> |
| #endif |
| #include <sys/param.h> |
| #include "bfd.h" |
| #include "callback.h" |
| #include "remote-sim.h" |
| #include "../../newlib/libc/sys/w65/sys/syscall.h" |
| |
| #include "interp.h" |
| |
| saved_state_type saved_state; |
| |
| int |
| get_now () |
| { |
| return time ((long *) 0); |
| } |
| void |
| control_c (sig, code, scp, addr) |
| int sig; |
| int code; |
| char *scp; |
| char *addr; |
| { |
| saved_state.exception = SIGINT; |
| } |
| |
| wai () |
| { |
| saved_state.exception = SIGTRAP; |
| } |
| |
| |
| |
| wdm (acc, x) |
| int acc; |
| int x; |
| |
| { |
| int cycles; |
| /* The x points to where the registers live, acc has code */ |
| |
| #define R(arg) (x + arg * 2) |
| unsigned R0 = R(0); |
| unsigned R4 = R(4); |
| unsigned R5 = R(5); |
| unsigned R6 = R(6); |
| unsigned R7 = R(7); |
| unsigned R8 = R(8); |
| unsigned char *memory = saved_state.memory; |
| int a1 = fetch16 (R (4)); |
| switch (a1) |
| { |
| case SYS_write: |
| { |
| int file = fetch16 (R5); |
| unsigned char *buf = fetch24 (R6) + memory; |
| int len = fetch16 (R8); |
| int res = write (file, buf, len); |
| store16 (R0, res); |
| break; |
| } |
| case 0: |
| printf ("%c", acc); |
| fflush (stdout); |
| break; |
| case 1: |
| saved_state.exception = SIGTRAP; |
| break; |
| default: |
| saved_state.exception = SIGILL; |
| break; |
| } |
| } |
| |
| |
| void |
| sim_resume (step, insignal) |
| int step; |
| int insignal; |
| { |
| void (*prev) (); |
| register unsigned char *memory; |
| if (step) |
| { |
| saved_state.exception = SIGTRAP; |
| } |
| else |
| { |
| saved_state.exception = 0; |
| } |
| |
| |
| prev = signal (SIGINT, control_c); |
| do |
| { |
| int x = (saved_state.p >> 4) & 1; |
| int m = (saved_state.p >> 5) & 1; |
| if (x == 0 && m == 0) |
| { |
| ifunc_X0_M0 (); |
| } |
| else if (x == 0 && m == 1) |
| { |
| ifunc_X0_M1 (); |
| } |
| else if (x == 1 && m == 0) |
| { |
| ifunc_X1_M0 (); |
| } |
| else if (x == 1 && m == 1) |
| { |
| ifunc_X1_M1 (); |
| } |
| } |
| while (saved_state.exception == 0); |
| |
| signal (SIGINT, prev); |
| } |
| |
| |
| |
| |
| init_pointers () |
| { |
| if (!saved_state.memory) |
| { |
| saved_state.memory = calloc (64 * 1024, NUMSEGS); |
| } |
| } |
| |
| int |
| sim_write (addr, buffer, size) |
| SIM_ADDR addr; |
| unsigned char *buffer; |
| int size; |
| { |
| int i; |
| init_pointers (); |
| |
| for (i = 0; i < size; i++) |
| { |
| saved_state.memory[(addr + i) & MMASK] = buffer[i]; |
| } |
| return size; |
| } |
| |
| int |
| sim_read (addr, buffer, size) |
| SIM_ADDR addr; |
| unsigned char *buffer; |
| int size; |
| { |
| int i; |
| |
| init_pointers (); |
| |
| for (i = 0; i < size; i++) |
| { |
| buffer[i] = saved_state.memory[(addr + i) & MMASK]; |
| } |
| return size; |
| } |
| |
| |
| |
| struct |
| { |
| unsigned int *ptr; |
| int size; |
| } |
| rinfo[] = |
| |
| { |
| &saved_state.r[0], 2, |
| &saved_state.r[1], 2, |
| &saved_state.r[2], 2, |
| &saved_state.r[3], 2, |
| &saved_state.r[4], 2, |
| &saved_state.r[5], 2, |
| &saved_state.r[6], 2, |
| &saved_state.r[7], 2, |
| &saved_state.r[8], 2, |
| &saved_state.r[9], 2, |
| &saved_state.r[10], 2, |
| &saved_state.r[11], 2, |
| &saved_state.r[12], 2, |
| &saved_state.r[13], 2, |
| &saved_state.r[14], 2, |
| &saved_state.r[15], 4, |
| &saved_state.pc, 4, |
| &saved_state.a, 4, |
| &saved_state.x, 4, |
| &saved_state.y, 4, |
| &saved_state.dbr, 4, |
| &saved_state.d, 4, |
| &saved_state.s, 4, |
| &saved_state.p, 4, |
| &saved_state.ticks, 4, |
| &saved_state.cycles, 4, |
| &saved_state.insts, 4, |
| 0 |
| }; |
| |
| int |
| sim_store_register (rn, value, length) |
| int rn; |
| unsigned char *value; |
| int length; |
| { |
| unsigned int val; |
| int i; |
| val = 0; |
| for (i = 0; i < rinfo[rn].size; i++) |
| { |
| val |= (*value++) << (i * 8); |
| } |
| |
| *(rinfo[rn].ptr) = val; |
| return -1; |
| } |
| |
| int |
| sim_fetch_register (rn, buf, length) |
| int rn; |
| unsigned char *buf; |
| int length; |
| { |
| unsigned int val = *(rinfo[rn].ptr); |
| int i; |
| |
| for (i = 0; i < rinfo[rn].size; i++) |
| { |
| *buf++ = val; |
| val = val >> 8; |
| } |
| return -1; |
| } |
| |
| |
| sim_reg_size (n) |
| { |
| return rinfo[n].size; |
| } |
| int |
| sim_trace () |
| { |
| return 0; |
| } |
| |
| void |
| sim_stop_reason (reason, sigrc) |
| enum sim_stop *reason; |
| int *sigrc; |
| { |
| *reason = sim_stopped; |
| *sigrc = saved_state.exception; |
| } |
| |
| int |
| sim_set_pc (x) |
| SIM_ADDR x; |
| { |
| saved_state.pc = x; |
| return 0; |
| } |
| |
| |
| void |
| sim_info (verbose) |
| int verbose; |
| { |
| double timetaken = (double) saved_state.ticks; |
| double virttime = saved_state.cycles / 2.0e6; |
| |
| printf ("\n\n# instructions executed %10d\n", saved_state.insts); |
| printf ("# cycles %10d\n", saved_state.cycles); |
| printf ("# real time taken %10.4f\n", timetaken); |
| printf ("# virtual time taken %10.4f\n", virttime); |
| |
| if (timetaken != 0) |
| { |
| printf ("# cycles/second %10d\n", (int) (saved_state.cycles / timetaken)); |
| printf ("# simulation ratio %10.4f\n", virttime / timetaken); |
| } |
| |
| } |
| |
| |
| |
| void |
| sim_open (kind, cb, abfd, argv) |
| SIM_OPEN_KIND kind; |
| host_callback *cb; |
| struct _bfd *abfd; |
| char **argv; |
| { |
| } |
| |
| |
| |
| #undef fetch8 |
| fetch8func (x) |
| { |
| if (x & ~MMASK) |
| { |
| saved_state.exception = SIGBUS; |
| return 0; |
| } |
| return saved_state.memory[x]; |
| } |
| |
| fetch8 (x) |
| { |
| return fetch8func(x); |
| } |
| |
| void |
| sim_close (quitting) |
| int quitting; |
| { |
| /* nothing to do */ |
| } |
| |
| int |
| sim_load (prog, from_tty) |
| char *prog; |
| int from_tty; |
| { |
| /* Return nonzero so gdb will handle it. */ |
| return 1; |
| } |
| |
| |
| void |
| sim_create_inferior (abfd, argv, env) |
| struct _bfd *abfd; |
| char **argv; |
| char **env; |
| { |
| SIM_ADDR start_address; |
| int pc; |
| if (abfd != NULL) |
| start_address = bfd_get_start_address (abfd); |
| else |
| start_address = 0; /*??*/ |
| /* ??? We assume this is a 4 byte quantity. */ |
| pc = start_address; |
| sim_store_register (16, (unsigned char *) &pc); |
| } |
| |
| void |
| sim_set_callbacks (ptr) |
| struct host_callback_struct *ptr; |
| { |
| |
| } |