1999-04-16 03:35:26 +02:00
|
|
|
/* 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>
|
2002-06-09 17:45:54 +02:00
|
|
|
#include "gdb/callback.h"
|
|
|
|
#include "gdb/remote-sim.h"
|
1999-04-16 03:35:26 +02:00
|
|
|
#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);
|
|
|
|
}
|