summaryrefslogtreecommitdiff
path: root/sim/z8k/support.c
diff options
context:
space:
mode:
Diffstat (limited to 'sim/z8k/support.c')
-rw-r--r--sim/z8k/support.c784
1 files changed, 784 insertions, 0 deletions
diff --git a/sim/z8k/support.c b/sim/z8k/support.c
new file mode 100644
index 00000000000..73923640628
--- /dev/null
+++ b/sim/z8k/support.c
@@ -0,0 +1,784 @@
+/* support routines for interpreted instructions
+ Copyright (C) 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of Z8KSIM
+
+Z8KSIM is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+Z8KSIM is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Z8KZIM; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "config.h"
+
+#include <ansidecl.h>
+#include <signal.h>
+#include <errno.h>
+
+#include "tm.h"
+#include "sim.h"
+#include "mem.h"
+#include <stdio.h>
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#ifdef HAVE_SYS_TIMES_H
+#include <sys/times.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include "callback.h"
+#include "remote-sim.h"
+#include "syscall.h"
+
+static int get_now PARAMS ((void));
+static int now_persec PARAMS ((void));
+static int put_long PARAMS ((sim_state_type * context, int ptr, int value));
+static int put_short PARAMS ((sim_state_type * context, int ptr, int value));
+
+int sim_z8001_mode;
+
+static int
+get_now ()
+{
+#ifdef HAVE_SYS_TIMES_H
+ struct tms b;
+
+ times (&b);
+ return b.tms_utime + b.tms_stime;
+#else
+ return time (0);
+#endif
+}
+
+static int
+now_persec ()
+{
+ return 50;
+}
+
+
+/* #define LOG /* define this to print instruction use counts */
+
+#ifdef __GNUC__
+#define INLINE __inline__
+#include "inlines.h"
+#else
+#include "inlines.h"
+#endif
+
+/* This holds the entire cpu context */
+static sim_state_type the_state;
+
+int
+fail (context, dummy)
+ sim_state_type *context;
+ int dummy;
+{
+ context->exception = SIM_BAD_INST;
+ return 1;
+}
+
+void
+sfop_bad1 (context)
+ sim_state_type *context;
+{
+ context->exception
+ = SIM_BAD_INST;
+}
+
+void
+bfop_bad1 (context)
+ sim_state_type *context;
+{
+ context->exception
+ = SIM_BAD_INST;
+}
+
+void
+fop_bad (context)
+ sim_state_type *context;
+{
+ context->exception =
+ SIM_BAD_INST;
+}
+
+/* Table of bit counts for all byte values */
+
+char the_parity[256] =
+{
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3,
+ 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4,
+ 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2,
+ 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5,
+ 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4,
+ 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3,
+ 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2,
+ 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,
+ 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5,
+ 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5,
+ 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6,
+ 7, 7, 8};
+
+
+int read ();
+int write ();
+int open ();
+int close ();
+int open ();
+int close ();
+
+int link ();
+int fstat ();
+
+static int
+put_short (context, ptr, value)
+ sim_state_type *context;
+ int ptr;
+ int value;
+{
+ put_word_mem_da (context, ptr, value);
+ return ptr + 2;
+}
+
+static int
+put_long (context, ptr, value)
+ sim_state_type *context;
+ int
+ ptr;
+ int value;
+{
+ put_long_mem_da (context, ptr, value);
+ return ptr + 4;
+}
+
+#define aptr(x) ((sitoptr(x)) + (char *)(context->memory))
+
+static int args[3];
+static int arg_index; /* Translate a z8k system call into a host system call */
+void
+support_call (context, sc)
+ sim_state_type *context;
+ int sc;
+{
+ extern int errno;
+ int ret;
+ int retnext = 0;
+ int fd;
+
+ int olderrno = errno;
+ errno = 0;
+ switch (sc)
+ {
+ case SYS_ARG:
+ args[arg_index++] = context->regs[0].word << 16 | context->regs[1].word;
+ break;
+ case SYS_exit:
+ context->exception = SIM_DONE;
+ ret = args[0];
+ arg_index = 0;
+ break;
+ case SYS_close:
+ ret = close ((int) (args[0]));
+ arg_index = 0;
+ break;
+ case SYS_creat:
+ ret = creat (aptr (args[0]), args[1]);
+ arg_index = 0;
+ break;
+ case SYS_isatty:
+ ret = isatty (args[0]);
+ arg_index = 0;
+ break;
+ case SYS_open:
+ ret = open (aptr (args[0]), args[1], args[2]);
+ arg_index = 0;
+ break;
+ case SYS_lseek:
+ ret = lseek (args[0], (off_t) args[1], args[2]);
+ arg_index = 0;
+ break;
+ case SYS_read:
+ ret = read (args[0], aptr (args[1]), args[2]);
+ arg_index = 0;
+ break;
+ case SYS_write:
+ ret = write (args[0],aptr (args[1]), args[2]);
+ arg_index = 0;
+ break;
+ case SYS_time:
+ {
+ int dst = args[0];
+
+ ret = time (0);
+ if (dst)
+ {
+ put_long_mem_da (context,
+ sitoptr (dst), ret);
+ }
+ retnext = ret;
+ ret = retnext >> 16;
+ arg_index = 0;
+ }
+ break;
+ case SYS_fstat:
+ {
+ int buf;
+ struct stat host_stat;
+ fd = args[0];
+ buf = sitoptr (args[1]);
+ ret = fstat (fd, &host_stat);
+ buf = put_short (context, buf, host_stat.st_dev);
+ buf = put_short (context, buf, host_stat.st_ino);
+ /* FIXME: Isn't mode_t 4 bytes? */
+ buf = put_short (context, buf, host_stat.st_mode);
+ buf = put_short (context, buf, host_stat.st_nlink);
+ buf = put_short (context, buf, host_stat.st_uid);
+ buf = put_short (context, buf, host_stat.st_uid);
+ buf = put_short (context, buf, host_stat.st_rdev);
+ buf = put_long (context, buf, host_stat.st_size);
+ buf = put_long (context, buf, host_stat.st_atime);
+ arg_index = 0;
+ } break;
+ default:
+ case SYS_link:
+ context->exception = SIM_BAD_SYSCALL;
+ arg_index = 0;
+ break;
+ }
+ context->regs[2].word = ret;
+ context->regs[3].word = retnext;
+ context->regs[5].word = errno;
+
+
+ /* support for the stdcall calling convention */
+ context->regs[6].word = retnext;
+ context->regs[7].word = ret;
+
+ errno = olderrno;
+}
+
+#undef get_word_mem_da
+
+int
+get_word_mem_da (context, addr)
+ sim_state_type *context;
+ int addr;
+{
+ return (get_byte_mem_da (context, addr) << 8) | (get_byte_mem_da (context, addr + 1));
+
+}
+
+#undef get_word_reg
+int
+get_word_reg (context, reg) sim_state_type
+* context;
+ int reg;
+{
+ return context->regs[reg].word;
+}
+
+#ifdef LOG
+int log[64 * 1024];
+
+#endif
+
+void
+tm_store_register (regno, value)
+ int regno;
+ int value;
+{
+ switch
+ (regno)
+ {
+ case REG_PC:
+ the_state.sometimes_pc = value;
+ break;
+
+ default:
+ put_word_reg (&the_state, regno, value);
+ }
+}
+
+void
+swap_long (buf, val)
+ char *buf;
+ int val;
+{
+ buf[0] = val >> 24;
+ buf[1] = val >> 16;
+ buf[2] = val >> 8;
+ buf[3] = val >> 0;
+}
+
+void
+swap_word (buf, val)
+ char *buf;
+ int val;
+{
+ buf[0] = val >> 8;
+ buf[1] = val >> 0;
+}
+
+void
+tm_fetch_register (regno, buf)
+ int regno;
+ char *buf;
+{
+ switch
+ (regno)
+ {
+ case REG_CYCLES:
+ swap_long (buf, the_state.cycles);
+ break;
+ case REG_INSTS:
+ swap_long (buf, the_state.insts);
+ break;
+ case
+ REG_TIME:
+ swap_long (buf, the_state.ticks);
+ break;
+ case REG_PC:
+ swap_long (buf, the_state.sometimes_pc);
+ break;
+ case REG_SP:
+ {
+ if (sim_z8001_mode)
+ {
+ swap_long (buf, get_long_reg (&the_state, 14));
+ }
+ else
+ {
+ swap_long (buf, get_word_reg (&the_state, 15));
+ }
+ }
+ break;
+ case
+ REG_FP:
+ {
+ if (sim_z8001_mode)
+ {
+ swap_long (buf, get_long_reg
+ (&the_state, 10));
+ }
+ else
+ {
+ swap_long (buf,
+ get_word_reg (&the_state, 10));
+ }
+ }
+ break;
+ default:
+ {
+ swap_word (buf,
+ get_word_reg (&the_state, regno));
+ }
+ }
+}
+
+void
+tm_resume (step)
+ int step;
+{
+ int now = get_now ();
+ struct op_info
+ *p;
+ int word;
+ int pc;
+ extern int (*(sfop_table[])) ();
+ extern int (*(bfop_table[])) ();
+ int (*((*table))) ();
+ sim_state_type *context = &the_state;
+
+ if (step)
+ {
+ context->exception = SIM_SINGLE_STEP;
+ }
+ else
+ {
+ context->exception = 0;
+ }
+
+ pc = context->sometimes_pc;
+ if (sim_z8001_mode)
+ {
+ table = bfop_table;
+ pc = MAP_PHYSICAL_TO_LOGICAL (pc);
+ }
+ else
+ {
+ table = sfop_table;
+ }
+
+
+ do
+ {
+ word = get_word_mem_da (context, pc);
+ p = op_info_table + word;
+
+#ifdef LOG
+ log[word]++;
+#endif
+ pc = table[p->exec] (context, pc, word);
+ context->insts++;
+
+ }
+ while (!context->exception);
+
+
+
+ context->sometimes_pc = MAP_LOGICAL_TO_PHYSICAL (pc);
+ context->ticks += get_now () - now;
+}
+
+int
+tm_signal ()
+{
+ return the_state.exception;
+}
+
+void
+tm_info_print (x)
+ sim_state_type *x;
+{
+ double timetaken = (double) x->ticks / (double) now_persec ();
+ double virttime = x->cycles / 4.0e6;
+
+ printf ("instructions executed : %9d\n", x->insts);
+ printf ("cycles counted : %9d \n", x->cycles);
+ printf ("cycles / inst : %9.1f \n", (double) x->cycles / (double) x->insts);
+ printf ("virtual time taked (at 4 Mhz) : %9.1f \n", virttime);
+ printf ("real time taken : %9.1f \n", timetaken);
+
+ if (timetaken)
+ {
+ printf ("virtual instructions per second : %9.1f\n", x->insts / timetaken);
+ printf ("emulation speed : %9.1f%%\n", virttime / timetaken * 100.0);
+ }
+#ifdef LOG
+ {
+ extern int quick[];
+
+ for (i = 0; quick[i]; i++)
+ {
+ log[quick[i]] += 100000;
+ }
+ }
+
+ for (i = 0; i < 64 * 1024; i++)
+ {
+ if (log[i])
+ {
+ printf (" /*%7d*/ 0x%x,\n", log[i], i);
+ }
+ }
+#endif
+
+}
+
+int
+sim_trace (sd)
+ SIM_DESC sd;
+{
+ int i;
+ char buffer[10];
+ int r;
+
+ printf ("\n");
+ for (r = 0; r < 16; r++)
+ {
+ int m;
+
+ printf ("r%2d", r);
+ printf ("=%04x ", get_word_reg (&the_state,
+ r));
+ for (m = -4; m < 8; m++)
+ {
+ if (m == 0)
+ printf (">");
+ printf ("%04x ",
+ get_word_mem_da (&the_state, (0xfffe & get_word_reg (&the_state, r)) + m * 2));
+ }
+ printf ("\n");
+ }
+
+ printf ("\n");
+ printf ("%9d %9d %08x ", the_state.cycles,
+ the_state.insts, the_state.sometimes_pc);
+
+ for (i = 0; i < 6; i++)
+ {
+ buffer[i] = get_byte_mem_da (&the_state,
+ the_state.sometimes_pc + i);
+ }
+
+ print_insn_z8001 (the_state.sometimes_pc, buffer, stdout);
+ printf
+ ("\n");
+ tm_resume (1);
+ if (the_state.exception != SIM_SINGLE_STEP)
+ return 1;
+ return 0;
+}
+
+void
+tm_state (x)
+ sim_state_type *x;
+{
+ *x = the_state;
+}
+
+void
+tm_exception (x)
+ int x;
+{
+ the_state.exception = x;
+}
+
+int
+tm_read_byte (x)
+ int x;
+{
+ x &= 0x3f00ffff;
+ return sim_read_byte (&the_state, x);
+}
+
+void
+tm_write_byte (x, y)
+ int x, y;
+{
+ x &= 0x3f00ffff;
+ sim_write_byte (&the_state, x, y);
+}
+
+#define SIGN(x) ((x) & MASK)
+normal_flags_32(context,d,sa,sb,sub)
+sim_state_type *context;
+unsigned int d;
+unsigned int sa;
+unsigned int sb;
+unsigned int sub;
+{
+#undef MASK
+#define MASK (1<<31)
+ context->broken_flags = 0;
+ if (sub)
+ PSW_CARRY = sa < sb;
+ else
+ PSW_CARRY = d < sa;
+ if (sub)
+ PSW_OVERFLOW = (SIGN(sa) != SIGN(sb)) && (SIGN(d) == SIGN(sb));
+ else
+ PSW_OVERFLOW = (SIGN(sa) == SIGN(sb)) && (SIGN(d) != SIGN(sb));
+
+ PSW_SIGN = ((int)d) <0;
+ PSW_ZERO = d == 0;
+}
+
+normal_flags_16(context,d,sal,sbl,sub)
+sim_state_type *context;
+unsigned int d;
+unsigned int sal;
+unsigned int sbl;
+unsigned short int sub;
+{
+ unsigned short sa = sal;
+ unsigned short sb = sbl;
+#undef MASK
+#define MASK (1<<15)
+ context->broken_flags = 0;
+ if (sub)
+ PSW_CARRY = sal < sbl;
+ else
+ PSW_CARRY = (d & 0x10000) != 0;
+
+ if (sub)
+ PSW_OVERFLOW = (SIGN(sa) != SIGN(sb)) && (SIGN(d) == SIGN(sb));
+ else
+ PSW_OVERFLOW = (SIGN(sa) == SIGN(sb)) && (SIGN(d) != SIGN(sb));
+
+ PSW_SIGN = ((short int)d) <0;
+ PSW_ZERO = ((short)d) == 0;
+}
+
+normal_flags_8(context,d,sa,sb,sub)
+sim_state_type *context;
+unsigned char d;
+unsigned char sa;
+unsigned char sb;
+unsigned char sub;
+{
+#undef MASK
+#define MASK (1<<7)
+ context->broken_flags = 0;
+ if (sub)
+ PSW_CARRY = sa < sb;
+ else
+ PSW_CARRY = d < sa;
+ if (sub)
+ PSW_OVERFLOW = (SIGN(sa) != SIGN(sb)) && (SIGN(d) == SIGN(sb));
+ else
+ PSW_OVERFLOW = (SIGN(sa) == SIGN(sb)) && (SIGN(d) != SIGN(sb));
+ PSW_SIGN = ((char)d) <0;
+ PSW_ZERO = d == 0;
+}
+
+
+static int
+is_cond_true (context, c)
+ sim_state_type *context;
+ int c;
+{
+ switch (c)
+ {
+ case T:
+ return 1;
+ case F:
+ return 0; /* F */
+ case LE:
+ return (PSW_ZERO | (PSW_SIGN ^ PSW_OVERFLOW)) & 1; /*LE */
+ case GT:
+ return (~(PSW_ZERO | (PSW_SIGN ^ PSW_OVERFLOW))) & 1; /*GT */
+ case 0x5:
+ return (PSW_SIGN & 1); /* sign */
+ case 0xd:
+ return (~(PSW_SIGN)) & 1; /* not sign */
+ case 0x3:
+ return ((PSW_CARRY | PSW_ZERO) & 1); /* ule*/
+ case UGT:
+ return ((~(PSW_CARRY | PSW_ZERO)) & 1); /* ugt */
+ case 0x4:
+ return (PSW_OVERFLOW & 1);/* overflow */
+ case 0xc:
+ return (~(PSW_OVERFLOW)) & 1; /* not overflow */
+ case LT:
+ return (PSW_SIGN ^ PSW_OVERFLOW) & 1; /* LT */
+ case GE:
+ return (~(PSW_SIGN ^ PSW_OVERFLOW)) & 1; /* GE */
+ case EQ:
+ return (PSW_ZERO) & 1; /* zero */
+ case NE:
+ return ((~PSW_ZERO) & 1); /* not zero */
+ case 0x7:
+ return (PSW_CARRY) & 1; /* carry */
+ case 0xf:
+ return (~PSW_CARRY) & 1; /* not carry */
+ default:
+ abort ();
+ }
+}
+
+int
+COND (context, c)
+ sim_state_type *context;
+ int c;
+{
+ if (c == 8)
+ return 1;
+
+ /* We can calculate what the flags would have been by
+ looking at the src and dst and size of the operation */
+
+ if (context->broken_flags)
+ {
+ int slow = 0;
+ int size;
+ int dst;
+ int srca;
+ int srcb;
+ int mask;
+ int ans;
+
+ /* see if we can short-cut the nasty flag calcs */
+
+ switch (size = context->size)
+ {
+ default:
+ abort();
+ return 0;
+ case 8:
+ srca = (char) (context->srca);
+ srcb = (char) (context->srcb);
+ dst = (char) (context->dst);
+ mask = 0xff;
+ break;
+ case 16:
+ srca = (short) (context->srca);
+ srcb = (short) (context->srcb);
+ dst = (short) (context->dst);
+ mask = 0xffff;
+ break;
+ case 32:
+ srca = (long) (context->srca);
+ srcb = (long) (context->srcb);
+ dst = (long) (context->dst);
+ mask = 0xffffffff;
+ break;
+ }
+
+ switch (c)
+ {
+ case T:
+ return 1;
+ case F:
+ return 0;
+ case EQ:
+ return !dst;
+ case NE:
+ return dst;
+ case GT:
+ ans = ((dst)) > 0;
+ if (slow)
+ {
+ if (is_cond_true (context, c) != ans)
+ abort ();
+ }
+ return ans;
+ case LE:
+ ans = ((dst)) <= 0;
+ if (slow)
+ {
+ if (is_cond_true (context, c) != ans)
+ abort ();
+ }
+ return ans;
+ case GE:
+ ans = ((dst)) >= 0;
+ if (slow)
+ {
+ if (is_cond_true (context, c) != ans)
+ abort ();
+ }
+ return ans;
+ case LT:
+ ans = ((dst)) < 0;
+ if (slow)
+ {
+ if (is_cond_true (context, c) != ans)
+ abort ();
+ }
+ return ans;
+ default:
+ break;
+ }
+
+ /* Can't fake it, we'll have to work out the flags the
+ hard way */
+
+ makeflags (context, mask);
+ }
+
+ /* don't know how to fake a test, inspect the flags
+ the hard way */
+
+ return is_cond_true (context, c);
+}