blob: e3cdc736e03670909aa8298986f7c330ef7af0ab [file] [log] [blame]
/* 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 "gdb/callback.h"
#include "gdb/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);
}