mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-27 04:52:05 +08:00
2520 lines
53 KiB
C
2520 lines
53 KiB
C
/* Simulator for the Hitachi H8/500 architecture.
|
|
|
|
Written by Steve Chamberlain of Cygnus Support.
|
|
sac@cygnus.com
|
|
|
|
This file is part of H8/500 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 <signal.h>
|
|
#ifdef HAVE_STDLIB_H
|
|
#include <stdlib.h>
|
|
#endif
|
|
#ifdef HAVE_TIME_H
|
|
#include <time.h>
|
|
#endif
|
|
#include <sys/param.h>
|
|
#include <setjmp.h>
|
|
#include "ansidecl.h"
|
|
#include "bfd.h"
|
|
#include "callback.h"
|
|
#include "remote-sim.h"
|
|
|
|
#define O_RECOMPILE 85
|
|
#define DEFINE_TABLE
|
|
#define DISASSEMBLER_TABLE
|
|
|
|
/* FIXME: Needs to live in header file.
|
|
This header should also include the things in remote-sim.h.
|
|
One could move this to remote-sim.h but this function isn't needed
|
|
by gdb. */
|
|
void sim_set_simcache_size PARAMS ((int));
|
|
|
|
int debug;
|
|
|
|
host_callback *sim_callback;
|
|
|
|
static SIM_OPEN_KIND sim_kind;
|
|
static char *myname;
|
|
|
|
/* This code can be compiled with any old C compiler, in which case
|
|
four or five switch statements will be executed for each
|
|
instruction simulated. It can be compiled with GCC, then the
|
|
simulated instructions thread through the code fragments, and
|
|
everything goes much faster.
|
|
|
|
These definitions make the code work either way
|
|
*/
|
|
#ifdef __GNUC__
|
|
#define DISPATCH(X) goto *(X); do
|
|
#define LABEL(X) X##_L
|
|
#define LABELN(X,N) X##_L##N
|
|
#define LABEL_REF(X) &&X##_L
|
|
#define LABEL_REFN(X,N) &&X##_L##N
|
|
#define ENDDISPATCH while (0);
|
|
#define fastref void *
|
|
|
|
#define DEFAULT ;
|
|
#define INLINE __inline__
|
|
#else
|
|
#define DEFAULT default :
|
|
#define DISPATCH(X) switch (X)
|
|
#define LABEL(X) case X
|
|
#define LABELN(X,N) case X
|
|
#define LABEL_REF(X) X
|
|
#define LABEL_REFN(X,N) X
|
|
#define ENDDISPATCH
|
|
#define fastref int
|
|
|
|
|
|
|
|
#define INLINE
|
|
#define STORE_REG_B 1
|
|
#define STORE_REG_W 2
|
|
#define STORE_INC_B 3
|
|
#define STORE_INC_W 4
|
|
#define STORE_DEC_B 5
|
|
#define STORE_DEC_W 6
|
|
#define STORE_DISP_B 7
|
|
#define STORE_DISP_W 8
|
|
#define STORE_CRB 9
|
|
#define STORE_CRW 10
|
|
#define STORE_REG_L 11
|
|
#define STORE_NOP 12
|
|
|
|
#define FETCH_NOP 9
|
|
#define FETCH_REG_B 10
|
|
#define FETCH_REG_W 11
|
|
#define FETCH_INC_B 12
|
|
#define FETCH_INC_W 13
|
|
#define FETCH_DEC_B 14
|
|
#define FETCH_DEC_W 15
|
|
#define FETCH_DISP_B 16
|
|
#define FETCH_DISP_W 17
|
|
#define FETCH_IMM 18
|
|
#define FETCH_CRB 19
|
|
#define FETCH_CRW 20
|
|
#define FETCH_LVAL 21
|
|
#define FETCH_LVAL24 22
|
|
#define FETCH_REG_L 23
|
|
|
|
#define FLAG_m 20
|
|
#define FLAG_M 21
|
|
#define FLAG_A 22
|
|
#define FLAG_NONE 23
|
|
#define FLAG_NOSTORE 24
|
|
#define FLAG_CLEAR 25
|
|
#define FLAG_a 26
|
|
#define FLAG_BRANCH 27
|
|
#define FLAG_special 28
|
|
|
|
#define FLAG_shiftword 29
|
|
#define FLAG_shiftbyte 30
|
|
|
|
#define FLAG_multword 31
|
|
#define FLAG_multbyte 32
|
|
#endif
|
|
|
|
|
|
#define h8500_table h8500_compile_table
|
|
#include "../opcodes/h8500-opc.h"
|
|
|
|
#include "inst.h"
|
|
|
|
#define LOW_BYTE(x) ((x) & 0xff)
|
|
#define HIGH_BYTE(x) (((x)>>8) & 0xff)
|
|
#define NORMAL_CP ((cpu.regs[R_CP].c - cpu.memory)>>16)
|
|
#define NORMAL_DP ((cpu.regs[R_DP].c - cpu.memory)>>16)
|
|
#define NORMAL_EP ((cpu.regs[R_EP].c - cpu.memory)>>16)
|
|
#define NORMAL_TP ((cpu.regs[R_TP].c - cpu.memory)>>16)
|
|
#define SET_NORMREG(x,y) ((cpu.regs[x].l = (y)))
|
|
#define GET_NORMREG(x) (cpu.regs[x].l)
|
|
#define SET_SEGREG(x,y) { cpu.regs[x].c = ((y) & 0xff0000) + cpu.memory;}
|
|
#define GET_SEGREG(x) ( (cpu.regs[x].c - cpu.memory ) >> 16)
|
|
#define SET_NORMAL_CPPC(x) { pc = (x) & 0xffff; SET_SEGREG(R_CP, (x));}
|
|
#define NORMAL_SR ((N<<3)|(Z<<2)|(V<<1)|(C))
|
|
#define P(X,Y) ((X<<8) | Y)
|
|
|
|
#define BUILDSR() cpu.regs[R_SR].s[LOW] = (N << 3) | (Z << 2) | (V<<1) | C;
|
|
|
|
#define GETSR() \
|
|
C = (cpu.regs[R_SR].s[LOW] >> 0) & 1;\
|
|
V = (cpu.regs[R_SR].s[LOW] >> 1) & 1;\
|
|
Z = (cpu.regs[R_SR].s[LOW] >> 2) & 1;\
|
|
N = (cpu.regs[R_SR].s[LOW] >> 3) & 1;
|
|
|
|
#ifdef __CHAR_IS_SIGNED__
|
|
#define SEXTCHAR(x) ((char)(x))
|
|
#endif
|
|
|
|
#ifndef SEXTCHAR
|
|
#define SEXTCHAR(x) ((x & 0x80) ? (x | ~0xff):x)
|
|
#endif
|
|
|
|
#define SEXTSHORT(x) ((short)(x))
|
|
|
|
/* Which segment registers go with which pointer registers */
|
|
static unsigned char **segmap[R_LAST];
|
|
static unsigned char *(regptr[R_LAST][3]);
|
|
static unsigned char *(segregptr[R_LAST][3]);
|
|
static cpu_state_type cpu;
|
|
|
|
static int segforreg[] = {R_DP, R_DP, R_DP, R_DP,
|
|
R_EP, R_EP, R_TP, R_TP,
|
|
R_DP, R_DP, R_DP, R_DP,
|
|
R_EP, R_EP, R_TP, R_TP};
|
|
int LOW;
|
|
int HIGH;
|
|
|
|
/* routines for getting and storing args */
|
|
#define elval(struct, lit) \
|
|
(((*(struct.reg.wptr) + lit) & 0xffff) + (*(struct.r2.segreg)))
|
|
|
|
#define displval(s) elval((s),(s).literal)
|
|
|
|
#define ireglval(struct) elval(struct, 0)
|
|
#define wordat(x) (((x)[0] << 8) | (x)[1])
|
|
#define longat(x) ((wordat((x))<<16)|(wordat((x)+2)))
|
|
#define byteat(x) ((x)[0])
|
|
|
|
#define setwordat(x,y) {x[0] =( y)>>8; x[1] = y;}
|
|
#define setbyteat(x,y) {x[0] = y;}
|
|
|
|
/*#define setalignedwordat(x,y) {((short *)x)[0] =y;}*/
|
|
/*
|
|
statics
|
|
*/
|
|
|
|
ea_type rd;
|
|
ea_type rs;
|
|
ea_type imm;
|
|
ea_type cr;
|
|
ea_type ea;
|
|
ea_type nop;
|
|
ea_type lval;
|
|
ea_type lval24;
|
|
|
|
ea_type eavector[2];
|
|
|
|
int disp;
|
|
|
|
#define JBYTE 0
|
|
#define JWORD 1
|
|
#define JLONG 2
|
|
|
|
typedef union
|
|
{
|
|
struct
|
|
{
|
|
fastref srcabyte;
|
|
fastref srcaword;
|
|
fastref srcalong;
|
|
|
|
fastref srcbbyte;
|
|
fastref srcbword;
|
|
fastref srcblong;
|
|
|
|
fastref dstbyte;
|
|
fastref dstword;
|
|
fastref dstlong;
|
|
} s;
|
|
struct
|
|
{
|
|
fastref byte;
|
|
fastref word;
|
|
fastref lon;
|
|
} a[3];
|
|
|
|
fastref j[9];
|
|
} size_ptr;
|
|
|
|
union
|
|
{
|
|
struct ea_struct
|
|
{
|
|
size_ptr ea_nop;
|
|
size_ptr ea_reg;
|
|
size_ptr ea_inc;
|
|
size_ptr ea_dec;
|
|
size_ptr ea_disp;
|
|
|
|
size_ptr ea_imm;
|
|
size_ptr ea_cr;
|
|
size_ptr ea_lval;
|
|
size_ptr ea_lval24;
|
|
} s;
|
|
#define N_EATYPES (sizeof(struct ea_struct) / sizeof(size_ptr))
|
|
size_ptr a[N_EATYPES];
|
|
} eas;
|
|
|
|
/* This function takes an ea structure filled in for the 1st source
|
|
operand and modifies it to be for either the 1st, 2nd or dst operand */
|
|
|
|
static void
|
|
howto_workout (encoded, semiencoded, n)
|
|
ea_type *encoded;
|
|
ea_type *semiencoded;
|
|
int n;
|
|
{
|
|
int i;
|
|
*encoded = *semiencoded;
|
|
|
|
for (i = 0; i < N_EATYPES; i++)
|
|
{
|
|
if (encoded->type == eas.a[i].s.srcabyte)
|
|
{
|
|
encoded->type = eas.a[i].a[n].byte;
|
|
return;
|
|
}
|
|
else if (encoded->type == eas.a[i].s.srcaword)
|
|
{
|
|
encoded->type = eas.a[i].a[n].word;
|
|
return;
|
|
}
|
|
else if (encoded->type == eas.a[i].s.srcalong)
|
|
{
|
|
encoded->type = eas.a[i].a[n].lon;
|
|
return;
|
|
}
|
|
}
|
|
|
|
abort ();
|
|
}
|
|
|
|
fastref flag_shiftword;
|
|
fastref flag_shiftbyte;
|
|
fastref flag_multword;
|
|
fastref flag_multbyte;
|
|
fastref flag_mp;
|
|
fastref flag_special;
|
|
fastref flag_Mp;
|
|
fastref flag_ap;
|
|
fastref flag_Ap;
|
|
fastref flag_nonep;
|
|
fastref flag_nostorep;
|
|
fastref flag_clearp;
|
|
fastref flag_branch;
|
|
fastref exec_dispatch[100];
|
|
|
|
static int
|
|
get_now ()
|
|
{
|
|
return time (0);
|
|
}
|
|
|
|
static int
|
|
now_persec ()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
gotcr (ptr, n)
|
|
ea_type *ptr;
|
|
int n;
|
|
{
|
|
int size;
|
|
n &= 0x7;
|
|
if (n == 0)
|
|
{
|
|
abort ();
|
|
}
|
|
else
|
|
{
|
|
ptr->type = eas.s.ea_cr.j[JBYTE];
|
|
ptr->reg.bptr = segregptr[n][JLONG];
|
|
}
|
|
}
|
|
static void
|
|
gotreg (ptr, n, size)
|
|
ea_type *ptr;
|
|
int n;
|
|
int size;
|
|
{
|
|
n &= 0x7;
|
|
ptr->type = eas.s.ea_reg.j[size];
|
|
ptr->reg.bptr = regptr[n][size];
|
|
}
|
|
|
|
static void
|
|
gotinc (ptr, n, inc, size)
|
|
ea_type *ptr;
|
|
int n;
|
|
int size;
|
|
{
|
|
n &= 0x7;
|
|
if (inc > 0)
|
|
{
|
|
ptr->type = eas.s.ea_inc.j[size];
|
|
}
|
|
else
|
|
{
|
|
ptr->type = eas.s.ea_dec.j[size];
|
|
}
|
|
ptr->reg.bptr = regptr[n][JWORD];
|
|
ptr->r2.segreg = segmap[n];
|
|
}
|
|
|
|
|
|
static void
|
|
gotabs (ptr, disp, reg, size)
|
|
ea_type *ptr;
|
|
int disp;
|
|
int reg;
|
|
int size;
|
|
{
|
|
ptr->type = eas.s.ea_disp.j[size];
|
|
ptr->reg.bptr = regptr[reg][JWORD];
|
|
ptr->r2.segreg = segmap[reg];
|
|
ptr->literal = disp;
|
|
}
|
|
|
|
static void
|
|
gotind (ptr, disp, reg, size)
|
|
ea_type *ptr;
|
|
int disp;
|
|
int reg;
|
|
int size;
|
|
{
|
|
gotabs (ptr, disp, reg & 0x7, size);
|
|
}
|
|
|
|
static void
|
|
gotimm (ptr, val)
|
|
ea_type *ptr;
|
|
int val;
|
|
{
|
|
ptr->type = eas.s.ea_imm.j[0];
|
|
ptr->literal = val;
|
|
}
|
|
|
|
static void
|
|
indoff (ptr)
|
|
ea_type *ptr;
|
|
{
|
|
int i;
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
if (ptr->type == eas.s.ea_disp.j[i])
|
|
{
|
|
ptr->type = eas.s.ea_lval.j[i];
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
thinkabout_shifts (d, bytesized)
|
|
decoded_inst *d;
|
|
int bytesized;
|
|
{
|
|
if (bytesized)
|
|
{
|
|
/* Got a byte shift, fake up second arg */
|
|
d->srcb.type = eas.s.ea_imm.s.srcbword;
|
|
d->srcb.literal = 8;
|
|
}
|
|
else
|
|
{
|
|
/* got a word shift, fake up second arg */
|
|
d->srcb.type = eas.s.ea_imm.s.srcbword;
|
|
d->srcb.literal = 16;
|
|
}
|
|
}
|
|
|
|
/* Calculate the number of cycles required to run this
|
|
instruction
|
|
*/
|
|
static void
|
|
compcycles (dst, opcode)
|
|
decoded_inst *dst;
|
|
h8500_opcode_info *opcode;
|
|
{
|
|
int cycles = 0;
|
|
/* Guess for the time being - 1 cycle for the first two bytes in the
|
|
opcode - to fecth the operand, and 3 cycles for all the rest of
|
|
the bytes, since they mean that there is probably an operand to
|
|
fetch */
|
|
|
|
switch (opcode->length)
|
|
{
|
|
case 1:
|
|
case 2:
|
|
cycles += opcode->length;
|
|
break;
|
|
default:
|
|
cycles += opcode->length * 3;
|
|
break;
|
|
}
|
|
|
|
dst->cycles = cycles;
|
|
}
|
|
|
|
static void
|
|
translate (ptr, from, to)
|
|
ea_type *ptr;
|
|
fastref from;
|
|
fastref to;
|
|
{
|
|
if (ptr->reg.wptr == &cpu.regs[7].s[LOW]
|
|
&& ptr->type == from)
|
|
{
|
|
ptr->type = to;
|
|
}
|
|
}
|
|
|
|
static
|
|
void
|
|
fix_incdecs (dst)
|
|
decoded_inst *dst;
|
|
{
|
|
if (dst->dst.type == eas.s.ea_inc.s.dstbyte
|
|
&& (dst->srca.type == eas.s.ea_inc.s.srcabyte
|
|
|| dst->srcb.type == eas.s.ea_inc.s.srcbbyte))
|
|
{
|
|
dst->dst.type = eas.s.ea_disp.s.dstbyte;
|
|
}
|
|
|
|
if (dst->dst.type == eas.s.ea_inc.s.dstword
|
|
&& (dst->srca.type == eas.s.ea_inc.s.srcaword
|
|
|| dst->srcb.type == eas.s.ea_inc.s.srcbword))
|
|
{
|
|
dst->dst.type = eas.s.ea_disp.s.dstword;
|
|
}
|
|
|
|
if (dst->dst.type == eas.s.ea_dec.s.dstbyte
|
|
|| dst->dst.type == eas.s.ea_dec.s.dstword)
|
|
{
|
|
if (dst->srca.type == eas.s.ea_dec.s.srcabyte)
|
|
{
|
|
dst->srca.type = eas.s.ea_disp.s.srcabyte;
|
|
}
|
|
else if (dst->srca.type == eas.s.ea_dec.s.srcaword)
|
|
{
|
|
dst->srca.type = eas.s.ea_disp.s.srcaword;
|
|
}
|
|
else if (dst->srcb.type == eas.s.ea_dec.s.srcbbyte)
|
|
{
|
|
dst->srcb.type = eas.s.ea_disp.s.srcbbyte;
|
|
}
|
|
else if (dst->srcb.type == eas.s.ea_dec.s.srcbword)
|
|
{
|
|
dst->srcb.type = eas.s.ea_disp.s.srcbword;
|
|
}
|
|
}
|
|
|
|
|
|
/* Turn a byte ops from the sp into word ops */
|
|
translate (&dst->dst, eas.s.ea_dec.s.dstbyte, eas.s.ea_dec.s.dstword);
|
|
translate (&dst->dst, eas.s.ea_inc.s.dstbyte, eas.s.ea_inc.s.dstword);
|
|
|
|
translate (&dst->srca, eas.s.ea_dec.s.srcabyte, eas.s.ea_dec.s.srcaword);
|
|
translate (&dst->srca, eas.s.ea_inc.s.srcabyte, eas.s.ea_inc.s.srcaword);
|
|
|
|
translate (&dst->srcb, eas.s.ea_dec.s.srcbbyte, eas.s.ea_dec.s.srcbword);
|
|
translate (&dst->srcb, eas.s.ea_inc.s.srcbbyte, eas.s.ea_inc.s.srcbword);
|
|
|
|
|
|
}
|
|
|
|
|
|
static void
|
|
find (pc, buffer, dst)
|
|
int pc;
|
|
unsigned char *buffer;
|
|
decoded_inst *dst;
|
|
{
|
|
h8500_opcode_info *opcode;
|
|
int i;
|
|
int idx;
|
|
int hadimm = 0;
|
|
dst->srca.reg.rptr = 0;
|
|
|
|
/* Run down the table to find the one which matches */
|
|
for (opcode = h8500_table; opcode->name; opcode++)
|
|
{
|
|
int byte;
|
|
int rn;
|
|
int rd;
|
|
int rs;
|
|
int disp;
|
|
int abs;
|
|
int imm;
|
|
int pcrel;
|
|
int qim;
|
|
int i;
|
|
int cr;
|
|
|
|
|
|
dst->opcode = exec_dispatch[opcode->flavor & 0x7f];
|
|
|
|
for (byte = 0; byte < opcode->length; byte++)
|
|
{
|
|
if ((buffer[byte] & opcode->bytes[byte].mask)
|
|
!= (opcode->bytes[byte].contents))
|
|
{
|
|
goto next;
|
|
}
|
|
else
|
|
{
|
|
/* extract any info parts */
|
|
switch (opcode->bytes[byte].insert)
|
|
{
|
|
case 0:
|
|
case FP:
|
|
break;
|
|
default:
|
|
abort ();
|
|
break;
|
|
case RN:
|
|
rn = buffer[byte] & 0x7;
|
|
break;
|
|
case RS:
|
|
rs = buffer[byte] & 0x7;
|
|
break;
|
|
case CRB:
|
|
cr = buffer[byte] & 0x7;
|
|
if (cr == 0)
|
|
goto next;
|
|
break;
|
|
case CRW:
|
|
cr = buffer[byte] & 0x7;
|
|
if (cr != 0)
|
|
goto next;
|
|
break;
|
|
case DISP16:
|
|
disp = (buffer[byte] << 8) | (buffer[byte + 1]);
|
|
break;
|
|
case FPIND_D8:
|
|
case DISP8:
|
|
disp = ((char) (buffer[byte]));
|
|
break;
|
|
case RD:
|
|
case RDIND:
|
|
rd = buffer[byte] & 0x7;
|
|
break;
|
|
case ABS24:
|
|
abs =
|
|
(buffer[byte] << 16)
|
|
| (buffer[byte + 1] << 8)
|
|
| (buffer[byte + 2]);
|
|
break;
|
|
case ABS16:
|
|
abs = (buffer[byte] << 8) | (buffer[byte + 1]);
|
|
break;
|
|
case ABS8:
|
|
abs = (buffer[byte]);
|
|
break;
|
|
case IMM16:
|
|
imm = (buffer[byte] << 8) | (buffer[byte + 1]);
|
|
break;
|
|
case IMM4:
|
|
imm = (buffer[byte]) & 0xf;
|
|
break;
|
|
case IMM8:
|
|
case RLIST:
|
|
imm = SEXTCHAR (buffer[byte]);
|
|
break;
|
|
case PCREL16:
|
|
pcrel = SEXTSHORT ((buffer[byte] << 8) | (buffer[byte + 1]));
|
|
break;
|
|
case PCREL8:
|
|
pcrel = SEXTCHAR ((buffer[byte]));
|
|
break;
|
|
case QIM:
|
|
switch (buffer[byte] & 0x7)
|
|
{
|
|
case 0:
|
|
imm = 1;
|
|
break;
|
|
case 1:
|
|
imm = 2;
|
|
break;
|
|
case 4:
|
|
imm = -1;
|
|
break;
|
|
case 5:
|
|
imm = -2;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
if (opcode->flavor & O_BYTE)
|
|
{
|
|
idx = 0;
|
|
switch (opcode->flags)
|
|
{
|
|
case 'h':
|
|
dst->flags = flag_shiftbyte;
|
|
break;
|
|
case 'p':
|
|
dst->flags = flag_multbyte;
|
|
break;
|
|
case 'B':
|
|
dst->flags = flag_branch;
|
|
break;
|
|
case 'm':
|
|
dst->flags = flag_mp;
|
|
break;
|
|
case 'a':
|
|
dst->flags = flag_ap;
|
|
break;
|
|
case '-':
|
|
dst->flags = flag_nonep;
|
|
break;
|
|
case 0:
|
|
dst->flags = flag_nostorep;
|
|
break;
|
|
case 'c':
|
|
dst->flags = flag_clearp;
|
|
break;
|
|
case 's':
|
|
/* special */
|
|
dst->flags = flag_special;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
idx = 1;
|
|
switch (opcode->flags)
|
|
{
|
|
case 'h':
|
|
dst->flags = flag_shiftword;
|
|
break;
|
|
case 'p':
|
|
dst->flags = flag_multword;
|
|
break;
|
|
case 'B':
|
|
dst->flags = flag_branch;
|
|
break;
|
|
case 'm':
|
|
dst->flags = flag_Mp;
|
|
break;
|
|
case 'a':
|
|
dst->flags = flag_Ap;
|
|
break;
|
|
case '-':
|
|
dst->flags = flag_nonep;
|
|
break;
|
|
case 0:
|
|
dst->flags = flag_nostorep;
|
|
break;
|
|
case 'c':
|
|
dst->flags = flag_clearp;
|
|
break;
|
|
case 's':
|
|
/* special */
|
|
dst->flags = flag_special;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < opcode->nargs; i++)
|
|
{
|
|
ea_type *p = eavector + i;
|
|
|
|
switch (opcode->arg_type[i])
|
|
{
|
|
default:
|
|
abort ();
|
|
|
|
case FP:
|
|
gotreg (p, 6, idx);
|
|
break;
|
|
case RNIND:
|
|
disp = 0;
|
|
case RNIND_D16:
|
|
case RNIND_D8:
|
|
gotind (p, disp, rn, idx);
|
|
break;
|
|
break;
|
|
case RDIND:
|
|
disp = 0;
|
|
case RDIND_D16:
|
|
case RDIND_D8:
|
|
gotind (p, disp, rd, idx);
|
|
break;
|
|
case FPIND_D8:
|
|
gotind (p, disp, 6, idx);
|
|
break;
|
|
case CRB:
|
|
case CRW:
|
|
gotcr (p, cr);
|
|
break;
|
|
case RN:
|
|
gotreg (p, rn, idx);
|
|
break;
|
|
case RD:
|
|
gotreg (p, rd, idx);
|
|
break;
|
|
case RS:
|
|
gotreg (p, rs, idx);
|
|
break;
|
|
case RNDEC:
|
|
gotinc (p, rn, -1, idx);
|
|
break;
|
|
case RNINC:
|
|
gotinc (p, rn, 1, idx);
|
|
break;
|
|
case SPINC:
|
|
gotinc (p, 7, 1, idx);
|
|
break;
|
|
case SPDEC:
|
|
gotinc (p, 7, -1, idx);
|
|
break;
|
|
case ABS24:
|
|
case ABS16:
|
|
gotabs (p, abs, R_HARD_0, idx);
|
|
break;
|
|
case ABS8:
|
|
gotabs (p, abs, R_HARD8_0, idx);
|
|
break;
|
|
case IMM16:
|
|
case RLIST:
|
|
case QIM:
|
|
case IMM4:
|
|
case IMM8:
|
|
gotimm (p, imm);
|
|
break;
|
|
case PCREL16:
|
|
case PCREL8:
|
|
gotimm (p,
|
|
((pcrel + pc + opcode->length) & 0xffff) | (pc & 0xff0000),
|
|
R_HARD_0, JLONG);
|
|
|
|
}
|
|
}
|
|
|
|
/* Finished and done - turn from two operand stuff into three */
|
|
|
|
dst->srca.type = eas.s.ea_nop.s.srcabyte;
|
|
dst->srcb.type = eas.s.ea_nop.s.srcbbyte;
|
|
dst->dst.type = eas.s.ea_nop.s.dstbyte;
|
|
|
|
if (opcode->nargs)
|
|
{
|
|
switch (opcode->nargs)
|
|
{
|
|
case 1:
|
|
howto_workout (&dst->srca, &eavector[0], 0);
|
|
if (opcode->dst != '!')
|
|
howto_workout (&dst->dst, &eavector[0], 2);
|
|
break;
|
|
case 2:
|
|
if (opcode->src2 == '!')
|
|
{
|
|
howto_workout (&dst->srca, &eavector[0], 0);
|
|
howto_workout (&dst->dst, &eavector[1], 2);
|
|
}
|
|
else
|
|
{
|
|
howto_workout (&dst->srca, &eavector[0], 0);
|
|
howto_workout (&dst->srcb, &eavector[1], 1);
|
|
if (opcode->dst != '!')
|
|
{
|
|
howto_workout (&dst->dst, &eavector[1], 2);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
|
|
/* Some extra stuff with pre inc and post dec,
|
|
make sure that if the same ea is there twice, only one of the
|
|
ops is auto inc/dec */
|
|
|
|
fix_incdecs (dst);
|
|
|
|
|
|
/* Some special cases */
|
|
if (dst->opcode == exec_dispatch[O_PJSR]
|
|
|| dst->opcode == exec_dispatch[O_PJMP])
|
|
{
|
|
/* Both the @abs:24 and @rn turn into a disp word,
|
|
chose the right a mode since @abs:24 is 4 bytes
|
|
long */
|
|
|
|
if (opcode->length == 4)
|
|
{
|
|
dst->srca.type = eas.s.ea_lval24.s.srcabyte;
|
|
}
|
|
else
|
|
{
|
|
dst->srca.type = eas.s.ea_reg.s.srcalong;
|
|
}
|
|
|
|
dst->srca.r2.rptr = &cpu.regs[R_HARD_0];
|
|
|
|
/* For [P]JSR, keep return address precomputed */
|
|
dst->srcb.literal = pc + opcode->length;
|
|
dst->srcb.type = eas.s.ea_imm.s.srcbword;
|
|
}
|
|
else if (dst->opcode == exec_dispatch[O_MULXU])
|
|
{
|
|
/* This is a multiply -fix the destination op */
|
|
if (dst->dst.type == eas.s.ea_reg.s.dstword)
|
|
{
|
|
dst->dst.type = eas.s.ea_reg.s.dstlong;
|
|
}
|
|
else
|
|
{
|
|
dst->dst.type = eas.s.ea_reg.s.dstword;
|
|
}
|
|
dst->dst.reg.bptr = regptr[rd][JWORD];
|
|
}
|
|
else if (dst->opcode == exec_dispatch[O_DIVXU])
|
|
{
|
|
/* This is a wider than normal, fix the source operand */
|
|
dst->srcb.type
|
|
= (dst->srcb.type == eas.s.ea_reg.s.srcbword)
|
|
? eas.s.ea_reg.s.srcblong
|
|
: eas.s.ea_reg.s.srcbword;
|
|
|
|
dst->dst.type
|
|
= (dst->dst.type == eas.s.ea_reg.s.dstword)
|
|
? eas.s.ea_reg.s.dstlong
|
|
: eas.s.ea_reg.s.dstword;
|
|
|
|
}
|
|
|
|
else if (dst->opcode == exec_dispatch[O_LDM])
|
|
{
|
|
/* Turn of the stack ref */
|
|
dst->srca.type = eas.s.ea_nop.s.srcabyte;
|
|
}
|
|
else if (dst->opcode == exec_dispatch[O_STM])
|
|
{
|
|
/* Turn of the stack ref */
|
|
dst->srcb.type = eas.s.ea_nop.s.srcbbyte;
|
|
}
|
|
|
|
|
|
/* extends read one size and write another */
|
|
else if (dst->opcode == exec_dispatch[O_EXTS]
|
|
|| dst->opcode == exec_dispatch[O_EXTU])
|
|
{
|
|
dst->dst.type = eas.s.ea_reg.s.dstword;
|
|
dst->dst.reg.bptr = regptr[rd][JWORD];
|
|
dst->flags = flag_Ap;
|
|
}
|
|
|
|
|
|
if (opcode->flags == 'h')
|
|
thinkabout_shifts (dst, opcode->flavor & O_BYTE);
|
|
|
|
|
|
/* For a branch, turn off one level of indirection */
|
|
if (opcode->src1 == 'B')
|
|
{
|
|
indoff (&dst->srca, 0);
|
|
}
|
|
|
|
}
|
|
dst->next_pc = pc + opcode->length;
|
|
|
|
compcycles (dst, opcode);
|
|
|
|
return;
|
|
|
|
|
|
next:;
|
|
}
|
|
|
|
/* Couldn't understand anything */
|
|
dst->opcode = exec_dispatch[O_TRAPA];
|
|
dst->next_pc = pc + 1;
|
|
|
|
}
|
|
|
|
compile (pc)
|
|
{
|
|
int idx;
|
|
|
|
/* find the next cache entry to use */
|
|
|
|
idx = cpu.cache_top + 1;
|
|
cpu.compiles++;
|
|
if (idx >= cpu.csize)
|
|
{
|
|
idx = 1;
|
|
}
|
|
cpu.cache_top = idx;
|
|
|
|
/* Throw away its old meaning */
|
|
cpu.cache_idx[cpu.cache[idx].oldpc] = 0;
|
|
|
|
/* set to new address */
|
|
cpu.cache[idx].oldpc = pc;
|
|
|
|
/* fill in instruction info */
|
|
find (pc, cpu.memory + pc, cpu.cache + idx);
|
|
|
|
/* point to new cache entry */
|
|
cpu.cache_idx[pc] = idx;
|
|
}
|
|
|
|
baddefault (x)
|
|
{
|
|
printf ("bad default %d\n", x);
|
|
}
|
|
|
|
static int fetch_l (arg)
|
|
ea_type *arg;
|
|
{
|
|
int l, r;
|
|
|
|
int h = *(arg->reg.wptr);
|
|
r = (union rtype *) (arg->reg.wptr) - &cpu.regs[0];
|
|
r++;
|
|
|
|
l = cpu.regs[r].s[LOW];
|
|
return (h << 16) | l;
|
|
|
|
}
|
|
|
|
#define FETCH(dst, arg, n) \
|
|
{ \
|
|
int r; unsigned char*lval; \
|
|
DISPATCH((arg).type) \
|
|
{ LABELN(FETCH_NOP,n): \
|
|
dst= 0; \
|
|
break; \
|
|
DEFAULT baddefault((arg).type); break; \
|
|
LABELN(FETCH_LVAL,n): \
|
|
dst = (*(((arg).reg.wptr)) + (arg.literal)) ; \
|
|
break; \
|
|
LABELN(FETCH_LVAL24,n): \
|
|
dst = (*(((arg).reg.wptr)) + *(((arg).r2.wptr)) + (arg.literal)) &0xffffff; \
|
|
break; \
|
|
LABELN(FETCH_CRB,n): \
|
|
dst = (*((arg).reg.segptr) - cpu.memory)>>16; \
|
|
break; \
|
|
LABELN(FETCH_CRW,n): \
|
|
dst = BUILDSR();\
|
|
break; \
|
|
LABELN(FETCH_REG_B,n): \
|
|
dst = *((arg).reg.bptr); \
|
|
break; \
|
|
LABELN(FETCH_REG_W,n): \
|
|
dst = *((arg).reg.wptr); \
|
|
break; \
|
|
LABELN(FETCH_REG_L,n): \
|
|
dst = fetch_l(&(arg));\
|
|
break; \
|
|
LABELN(FETCH_INC_B,n): \
|
|
lval = elval ((arg), 0); \
|
|
dst = byteat (lval); \
|
|
(*((arg).reg.wptr))++; \
|
|
break; \
|
|
LABELN(FETCH_INC_W,n): \
|
|
lval = elval ((arg), 0); \
|
|
dst = wordat (lval); \
|
|
(*(((arg).reg.wptr))) += 2; \
|
|
break; \
|
|
LABELN(FETCH_DEC_B, n): \
|
|
(*(arg).reg.wptr)--; \
|
|
lval = elval ((arg), 0); \
|
|
r = byteat (lval); \
|
|
dst = r; \
|
|
break; \
|
|
LABELN(FETCH_DEC_W, n): \
|
|
(*((arg).reg.wptr)) -= 2; \
|
|
lval = elval ((arg), 0); \
|
|
r = wordat (lval); \
|
|
dst = r; \
|
|
break; \
|
|
LABELN(FETCH_DISP_B,n): \
|
|
lval = displval ((arg)); \
|
|
dst = byteat (lval); \
|
|
break; \
|
|
LABELN(FETCH_DISP_W,n): \
|
|
lval = displval ((arg)); \
|
|
dst = wordat (lval); \
|
|
break; \
|
|
LABELN(FETCH_IMM, n): \
|
|
dst = (arg).literal; \
|
|
break; \
|
|
} \
|
|
ENDDISPATCH; \
|
|
}
|
|
|
|
static union
|
|
{
|
|
short int i;
|
|
struct
|
|
{
|
|
char low;
|
|
char high;
|
|
}
|
|
u;
|
|
}
|
|
|
|
littleendian;
|
|
|
|
static
|
|
void
|
|
init_pointers ()
|
|
{
|
|
static int init;
|
|
|
|
if (!init)
|
|
{
|
|
int i;
|
|
|
|
init = 1;
|
|
littleendian.i = 1;
|
|
|
|
for (i = 0; i < (int) R_LAST; i++)
|
|
{
|
|
if (littleendian.u.high)
|
|
{
|
|
/* big endian host */
|
|
|
|
|
|
LOW = 1;
|
|
HIGH = 0;
|
|
|
|
regptr[i][0] = ((unsigned char *) (cpu.regs + i)) + 3;
|
|
regptr[i][1] = ((unsigned char *) (cpu.regs + i)) + 2;
|
|
}
|
|
else
|
|
{
|
|
LOW = 0;
|
|
HIGH = 1;
|
|
|
|
regptr[i][0] = (unsigned char *) &(cpu.regs[i]);
|
|
regptr[i][1] = (unsigned char *) (&(cpu.regs[i]));
|
|
}
|
|
|
|
regptr[i][2] = (unsigned char *) &(cpu.regs[i]);
|
|
}
|
|
|
|
memcpy (segregptr + 0, regptr + R_SR, sizeof (segregptr[0]));
|
|
memcpy (segregptr + 1, regptr + R_TP, sizeof (segregptr[1]));
|
|
memcpy (segregptr + 3, regptr + R_BR, sizeof (segregptr[3]));
|
|
memcpy (segregptr + 4, regptr + R_EP, sizeof (segregptr[4]));
|
|
memcpy (segregptr + 5, regptr + R_DP, sizeof (segregptr[5]));
|
|
memcpy (segregptr + 6, regptr + R_CP, sizeof (segregptr[6]));
|
|
memcpy (segregptr + 7, regptr + R_TP, sizeof (segregptr[7]));
|
|
|
|
/* Pointers to into the cpu state for the seg registers */
|
|
|
|
segmap[R0] = &cpu.regs[R_DP].c;
|
|
segmap[R1] = &cpu.regs[R_DP].c;
|
|
segmap[R2] = &cpu.regs[R_DP].c;
|
|
segmap[R3] = &cpu.regs[R_DP].c;
|
|
segmap[R4] = &cpu.regs[R_EP].c;
|
|
segmap[R5] = &cpu.regs[R_EP].c;
|
|
segmap[R6] = &cpu.regs[R_TP].c;
|
|
segmap[R7] = &cpu.regs[R_TP].c;
|
|
segmap[R_HARD_0] = &cpu.regs[R_DP].c;
|
|
segmap[R_HARD8_0] = &cpu.regs[R_BP].c;
|
|
|
|
cpu.memory = (unsigned char *) calloc (sizeof (char), H8500_MSIZE);
|
|
cpu.cache_idx = (unsigned short *) calloc (sizeof (short), H8500_MSIZE);
|
|
|
|
/* initialize the seg registers */
|
|
|
|
cpu.regs[R_DP].c = cpu.memory;
|
|
cpu.regs[R_TP].c = cpu.memory;
|
|
cpu.regs[R_CP].c = cpu.memory;
|
|
cpu.regs[R_BP].c = cpu.memory;
|
|
cpu.regs[R_EP].c = cpu.memory;
|
|
cpu.regs[R7].s[LOW] = 0xfffe;
|
|
cpu.regs[R6].s[LOW] = 0xfffe;
|
|
if (!cpu.cache)
|
|
sim_set_simcache_size (CSIZE);
|
|
}
|
|
}
|
|
|
|
#define PUSHWORD(x) \
|
|
{ \
|
|
int sp = cpu.regs[R7].s[LOW]; \
|
|
unsigned char *p; \
|
|
\
|
|
sp -= 2; \
|
|
p = (sp & 0xffff) + (cpu.regs[R_TP].c); \
|
|
cpu.regs[R7].s[LOW] = sp; \
|
|
setwordat (p, x); \
|
|
} \
|
|
|
|
#define POPWORD(d) \
|
|
{ \
|
|
int spx= cpu.regs[R7].s[LOW]; \
|
|
unsigned char *p; \
|
|
\
|
|
p = (spx& 0xffff) + (cpu.regs[R_TP].c); \
|
|
spx+= 2; \
|
|
cpu.regs[R7].s[LOW] = spx; \
|
|
d = wordat (p); \
|
|
} \
|
|
|
|
/* simulate a monitor trap */
|
|
trap ()
|
|
{
|
|
switch (cpu.regs[R3].s[LOW] & 0xff)
|
|
{
|
|
case 33:
|
|
/* exit */
|
|
cpu.exception = SIGQUIT;
|
|
break;
|
|
case 34:
|
|
/* abort */
|
|
cpu.exception = SIGABRT;
|
|
break;
|
|
case 6:
|
|
/* print char in r0 */
|
|
printf ("%c", cpu.regs[R0].s[LOW]);
|
|
break;
|
|
}
|
|
}
|
|
void
|
|
control_c (sig, code, scp, addr)
|
|
int sig;
|
|
int code;
|
|
char *scp;
|
|
char *addr;
|
|
{
|
|
cpu.exception = SIGINT;
|
|
}
|
|
|
|
static jmp_buf jbuf;
|
|
static void
|
|
segv ()
|
|
{
|
|
cpu.exception = SIGSEGV;
|
|
longjmp (jbuf, 1);
|
|
}
|
|
|
|
int
|
|
sim_stop (sd)
|
|
SIM_DESC sd;
|
|
{
|
|
cpu.exception = SIGINT;
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
sim_resume (sd, step, siggnal)
|
|
SIM_DESC sd;
|
|
{
|
|
static int init1;
|
|
int res;
|
|
int tmp;
|
|
int arga;
|
|
int argb;
|
|
int bit;
|
|
int pc;
|
|
int C, Z, V, N;
|
|
int cycles = 0;
|
|
int insts = 0;
|
|
int tick_start = get_now ();
|
|
void (*prev) ();
|
|
void (*prev_seg) ();
|
|
|
|
if (!init1)
|
|
{
|
|
int i;
|
|
|
|
init1 = 1;
|
|
init_pointers ();
|
|
|
|
for (i = 0; i < N_EATYPES; i++)
|
|
{
|
|
eas.a[i].s.srcabyte = LABEL_REFN (FETCH_NOP, 0);
|
|
eas.a[i].s.srcaword = LABEL_REFN (FETCH_NOP, 0);
|
|
eas.a[i].s.srcalong = LABEL_REFN (FETCH_NOP, 0);
|
|
|
|
eas.a[i].s.srcbbyte = LABEL_REFN (FETCH_NOP, 1);
|
|
eas.a[i].s.srcbword = LABEL_REFN (FETCH_NOP, 1);
|
|
eas.a[i].s.srcblong = LABEL_REFN (FETCH_NOP, 1);
|
|
|
|
eas.a[i].s.dstbyte = LABEL_REF (STORE_NOP);
|
|
eas.a[i].s.dstword = LABEL_REF (STORE_NOP);
|
|
eas.a[i].s.dstlong = LABEL_REF (STORE_NOP);
|
|
}
|
|
|
|
eas.s.ea_lval.s.srcabyte = LABEL_REFN (FETCH_LVAL, 0);
|
|
eas.s.ea_lval.s.srcaword = LABEL_REFN (FETCH_LVAL, 0);
|
|
eas.s.ea_lval24.s.srcabyte = LABEL_REFN (FETCH_LVAL24, 0);
|
|
eas.s.ea_lval24.s.srcaword = LABEL_REFN (FETCH_LVAL24, 0);
|
|
|
|
eas.s.ea_nop.s.srcabyte = LABEL_REFN (FETCH_NOP, 0);
|
|
eas.s.ea_nop.s.srcaword = LABEL_REFN (FETCH_NOP, 0);
|
|
eas.s.ea_nop.s.srcbbyte = LABEL_REFN (FETCH_NOP, 1);
|
|
eas.s.ea_nop.s.srcbword = LABEL_REFN (FETCH_NOP, 1);
|
|
eas.s.ea_nop.s.dstbyte = LABEL_REF (STORE_NOP);
|
|
eas.s.ea_nop.s.dstword = LABEL_REF (STORE_NOP);
|
|
|
|
eas.s.ea_cr.s.srcabyte = LABEL_REFN (FETCH_CRB, 0);
|
|
eas.s.ea_cr.s.srcaword = LABEL_REFN (FETCH_CRW, 0);
|
|
|
|
eas.s.ea_cr.s.srcbbyte = LABEL_REFN (FETCH_CRB, 1);
|
|
eas.s.ea_cr.s.srcbword = LABEL_REFN (FETCH_CRW, 1);
|
|
|
|
eas.s.ea_cr.s.dstbyte = LABEL_REF (STORE_CRB);
|
|
eas.s.ea_cr.s.dstword = LABEL_REF (STORE_CRW);
|
|
|
|
eas.s.ea_reg.s.srcabyte = LABEL_REFN (FETCH_REG_B, 0);
|
|
eas.s.ea_reg.s.srcaword = LABEL_REFN (FETCH_REG_W, 0);
|
|
eas.s.ea_reg.s.srcalong = LABEL_REFN (FETCH_REG_L, 0);
|
|
|
|
eas.s.ea_reg.s.srcbbyte = LABEL_REFN (FETCH_REG_B, 1);
|
|
eas.s.ea_reg.s.srcbword = LABEL_REFN (FETCH_REG_W, 1);
|
|
eas.s.ea_reg.s.srcblong = LABEL_REFN (FETCH_REG_L, 1);
|
|
|
|
eas.s.ea_reg.s.dstbyte = LABEL_REF (STORE_REG_B);
|
|
eas.s.ea_reg.s.dstword = LABEL_REF (STORE_REG_W);
|
|
eas.s.ea_reg.s.dstlong = LABEL_REF (STORE_REG_L);
|
|
|
|
eas.s.ea_inc.s.srcabyte = LABEL_REFN (FETCH_INC_B, 0);
|
|
eas.s.ea_inc.s.srcaword = LABEL_REFN (FETCH_INC_W, 0);
|
|
eas.s.ea_inc.s.srcbbyte = LABEL_REFN (FETCH_INC_B, 1);
|
|
eas.s.ea_inc.s.srcbword = LABEL_REFN (FETCH_INC_W, 1);
|
|
eas.s.ea_inc.s.dstbyte = LABEL_REF (STORE_INC_B);
|
|
eas.s.ea_inc.s.dstword = LABEL_REF (STORE_INC_W);
|
|
|
|
eas.s.ea_dec.s.srcabyte = LABEL_REFN (FETCH_DEC_B, 0);
|
|
eas.s.ea_dec.s.srcaword = LABEL_REFN (FETCH_DEC_W, 0);
|
|
eas.s.ea_dec.s.srcbbyte = LABEL_REFN (FETCH_DEC_B, 1);
|
|
eas.s.ea_dec.s.srcbword = LABEL_REFN (FETCH_DEC_W, 1);
|
|
eas.s.ea_dec.s.dstbyte = LABEL_REF (STORE_DEC_B);
|
|
eas.s.ea_dec.s.dstword = LABEL_REF (STORE_DEC_W);
|
|
|
|
eas.s.ea_disp.s.srcabyte = LABEL_REFN (FETCH_DISP_B, 0);
|
|
eas.s.ea_disp.s.srcaword = LABEL_REFN (FETCH_DISP_W, 0);
|
|
eas.s.ea_disp.s.srcbbyte = LABEL_REFN (FETCH_DISP_B, 1);
|
|
eas.s.ea_disp.s.srcbword = LABEL_REFN (FETCH_DISP_W, 1);
|
|
eas.s.ea_disp.s.dstbyte = LABEL_REF (STORE_DISP_B);
|
|
eas.s.ea_disp.s.dstword = LABEL_REF (STORE_DISP_W);
|
|
|
|
eas.s.ea_imm.s.srcabyte = LABEL_REFN (FETCH_IMM, 0);
|
|
eas.s.ea_imm.s.srcaword = LABEL_REFN (FETCH_IMM, 0);
|
|
eas.s.ea_imm.s.srcbbyte = LABEL_REFN (FETCH_IMM, 1);
|
|
eas.s.ea_imm.s.srcbword = LABEL_REFN (FETCH_IMM, 1);
|
|
|
|
flag_special = LABEL_REF (FLAG_special);
|
|
flag_mp = LABEL_REF (FLAG_m);
|
|
flag_Mp = LABEL_REF (FLAG_M);
|
|
flag_ap = LABEL_REF (FLAG_a);
|
|
flag_Ap = LABEL_REF (FLAG_A);
|
|
flag_nonep = LABEL_REF (FLAG_NONE);
|
|
flag_nostorep = LABEL_REF (FLAG_NOSTORE);
|
|
flag_clearp = LABEL_REF (FLAG_CLEAR);
|
|
flag_shiftbyte = LABEL_REF (FLAG_shiftbyte);
|
|
flag_shiftword = LABEL_REF (FLAG_shiftword);
|
|
flag_multbyte = LABEL_REF (FLAG_multbyte);
|
|
flag_multword = LABEL_REF (FLAG_multword);
|
|
|
|
|
|
exec_dispatch[O_ADDS] = LABEL_REF (O_ADDS);
|
|
exec_dispatch[O_ADDX] = LABEL_REF (O_ADDX);
|
|
exec_dispatch[O_ADD] = LABEL_REF (O_ADD);
|
|
exec_dispatch[O_ANDC] = LABEL_REF (O_ANDC);
|
|
exec_dispatch[O_AND] = LABEL_REF (O_AND);
|
|
exec_dispatch[O_BCC] = LABEL_REF (O_BCC);
|
|
exec_dispatch[O_BCLR] = LABEL_REF (O_BCLR);
|
|
exec_dispatch[O_BCS] = LABEL_REF (O_BCS);
|
|
exec_dispatch[O_BEQ] = LABEL_REF (O_BEQ);
|
|
exec_dispatch[O_BF] = LABEL_REF (O_BF);
|
|
exec_dispatch[O_BGE] = LABEL_REF (O_BGE);
|
|
exec_dispatch[O_BGT] = LABEL_REF (O_BGT);
|
|
exec_dispatch[O_BHI] = LABEL_REF (O_BHI);
|
|
exec_dispatch[O_BHS] = LABEL_REF (O_BHS);
|
|
exec_dispatch[O_BLE] = LABEL_REF (O_BLE);
|
|
exec_dispatch[O_BLO] = LABEL_REF (O_BLO);
|
|
exec_dispatch[O_BLS] = LABEL_REF (O_BLS);
|
|
exec_dispatch[O_BLT] = LABEL_REF (O_BLT);
|
|
exec_dispatch[O_BMI] = LABEL_REF (O_BMI);
|
|
exec_dispatch[O_BNE] = LABEL_REF (O_BNE);
|
|
exec_dispatch[O_BNOT] = LABEL_REF (O_BNOT);
|
|
exec_dispatch[O_BPL] = LABEL_REF (O_BPL);
|
|
exec_dispatch[O_BPT] = LABEL_REF (O_BPT);
|
|
exec_dispatch[O_BRA] = LABEL_REF (O_BRA);
|
|
exec_dispatch[O_BRN] = LABEL_REF (O_BRN);
|
|
exec_dispatch[O_BSET] = LABEL_REF (O_BSET);
|
|
exec_dispatch[O_BSR] = LABEL_REF (O_BSR);
|
|
exec_dispatch[O_BTST] = LABEL_REF (O_BTST);
|
|
exec_dispatch[O_BT] = LABEL_REF (O_BT);
|
|
exec_dispatch[O_BVC] = LABEL_REF (O_BVC);
|
|
exec_dispatch[O_BVS] = LABEL_REF (O_BVS);
|
|
exec_dispatch[O_CLR] = LABEL_REF (O_CLR);
|
|
exec_dispatch[O_CMP] = LABEL_REF (O_CMP);
|
|
exec_dispatch[O_DADD] = LABEL_REF (O_DADD);
|
|
exec_dispatch[O_DIVXU] = LABEL_REF (O_DIVXU);
|
|
exec_dispatch[O_DSUB] = LABEL_REF (O_DSUB);
|
|
exec_dispatch[O_EXTS] = LABEL_REF (O_EXTS);
|
|
exec_dispatch[O_EXTU] = LABEL_REF (O_EXTU);
|
|
exec_dispatch[O_JMP] = LABEL_REF (O_JMP);
|
|
exec_dispatch[O_JSR] = LABEL_REF (O_JSR);
|
|
exec_dispatch[O_LDC] = LABEL_REF (O_LDC);
|
|
exec_dispatch[O_LDM] = LABEL_REF (O_LDM);
|
|
exec_dispatch[O_LINK] = LABEL_REF (O_LINK);
|
|
exec_dispatch[O_MOVFPE] = LABEL_REF (O_MOVFPE);
|
|
exec_dispatch[O_MOVTPE] = LABEL_REF (O_MOVTPE);
|
|
exec_dispatch[O_MOV] = LABEL_REF (O_MOV);
|
|
exec_dispatch[O_MULXU] = LABEL_REF (O_MULXU);
|
|
exec_dispatch[O_NEG] = LABEL_REF (O_NEG);
|
|
exec_dispatch[O_NOP] = LABEL_REF (O_NOP);
|
|
exec_dispatch[O_NOT] = LABEL_REF (O_NOT);
|
|
exec_dispatch[O_ORC] = LABEL_REF (O_ORC);
|
|
exec_dispatch[O_OR] = LABEL_REF (O_OR);
|
|
exec_dispatch[O_PJMP] = LABEL_REF (O_PJMP);
|
|
exec_dispatch[O_PJSR] = LABEL_REF (O_PJSR);
|
|
exec_dispatch[O_PRTD] = LABEL_REF (O_PRTD);
|
|
exec_dispatch[O_PRTS] = LABEL_REF (O_PRTS);
|
|
exec_dispatch[O_RECOMPILE] = LABEL_REF (O_RECOMPILE);
|
|
|
|
exec_dispatch[O_ROTL] = LABEL_REF (O_ROTL);
|
|
exec_dispatch[O_ROTR] = LABEL_REF (O_ROTR);
|
|
exec_dispatch[O_ROTXL] = LABEL_REF (O_ROTXL);
|
|
exec_dispatch[O_ROTXR] = LABEL_REF (O_ROTXR);
|
|
|
|
exec_dispatch[O_RTD] = LABEL_REF (O_RTD);
|
|
exec_dispatch[O_RTS] = LABEL_REF (O_RTS);
|
|
exec_dispatch[O_SCB_EQ] = LABEL_REF (O_SCB_EQ);
|
|
exec_dispatch[O_SCB_F] = LABEL_REF (O_SCB_F);
|
|
exec_dispatch[O_SCB_NE] = LABEL_REF (O_SCB_NE);
|
|
exec_dispatch[O_SHAL] = LABEL_REF (O_SHAL);
|
|
exec_dispatch[O_SHAR] = LABEL_REF (O_SHAR);
|
|
exec_dispatch[O_SHLL] = LABEL_REF (O_SHLL);
|
|
exec_dispatch[O_SHLR] = LABEL_REF (O_SHLR);
|
|
|
|
exec_dispatch[O_SLEEP] = LABEL_REF (O_SLEEP);
|
|
exec_dispatch[O_STC] = LABEL_REF (O_STC);
|
|
exec_dispatch[O_STM] = LABEL_REF (O_STM);
|
|
exec_dispatch[O_SUBS] = LABEL_REF (O_SUBS);
|
|
exec_dispatch[O_SUBX] = LABEL_REF (O_SUBX);
|
|
exec_dispatch[O_SUB] = LABEL_REF (O_SUB);
|
|
exec_dispatch[O_SWAP] = LABEL_REF (O_SWAP);
|
|
exec_dispatch[O_TAS] = LABEL_REF (O_TAS);
|
|
exec_dispatch[O_TRAPA] = LABEL_REF (O_TRAPA);
|
|
exec_dispatch[O_TRAP_VS] = LABEL_REF (O_TRAP_VS);
|
|
exec_dispatch[O_TST] = LABEL_REF (O_TST);
|
|
exec_dispatch[O_UNLK] = LABEL_REF (O_UNLK);
|
|
exec_dispatch[O_XCH] = LABEL_REF (O_XCH);
|
|
exec_dispatch[O_XORC] = LABEL_REF (O_XORC);
|
|
exec_dispatch[O_XOR] = LABEL_REF (O_XOR);
|
|
nop.type = eas.s.ea_nop.s.srcabyte;
|
|
cpu.cache[0].opcode = exec_dispatch[O_RECOMPILE];
|
|
cpu.cache[0].srca.type = eas.s.ea_nop.s.srcabyte;
|
|
cpu.cache[0].srcb.type = eas.s.ea_nop.s.srcbbyte;
|
|
}
|
|
|
|
prev = signal (SIGINT, control_c);
|
|
prev_seg = signal (SIGSEGV, segv);
|
|
|
|
if (step)
|
|
{
|
|
cpu.exception = SIGTRAP;
|
|
}
|
|
else
|
|
{
|
|
cpu.exception = 0;
|
|
}
|
|
|
|
pc = cpu.regs[R_PC].s[LOW] + (NORMAL_CP << 16);
|
|
|
|
GETSR ();
|
|
|
|
if (setjmp (jbuf) == 0) {
|
|
do
|
|
{
|
|
int cidx;
|
|
decoded_inst *code;
|
|
|
|
top:
|
|
cidx = cpu.cache_idx[pc];
|
|
code = cpu.cache + cidx;
|
|
|
|
FETCH (arga, code->srca, 0);
|
|
FETCH (argb, code->srcb, 1);
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
if (debug)
|
|
{
|
|
printf ("%x %d %s\n", pc, code->opcode,
|
|
code->op ? code->op->name : "**");
|
|
}
|
|
#endif
|
|
|
|
cycles += code->cycles;
|
|
insts++;
|
|
DISPATCH (code->opcode)
|
|
{
|
|
LABEL (O_RECOMPILE):
|
|
/* This opcode is a fake for when we get to an instruction which
|
|
hasn't been compiled */
|
|
compile (pc);
|
|
goto top;
|
|
break;
|
|
LABEL (O_NEG):
|
|
arga = -arga;
|
|
argb = 0;
|
|
res = arga + argb;
|
|
break;
|
|
LABEL (O_SUBX):
|
|
arga += C;
|
|
LABEL (O_SUB):
|
|
LABEL (O_SUBS):
|
|
arga = -arga;
|
|
LABEL (O_ADD):
|
|
LABEL (O_ADDS):
|
|
res = arga + argb;
|
|
break;
|
|
|
|
LABEL (O_ADDX):
|
|
res = arga + argb + C;
|
|
break;
|
|
|
|
LABEL (O_AND):
|
|
LABEL (O_ANDC):
|
|
res = arga & argb;
|
|
break;
|
|
break;
|
|
|
|
LABEL (O_BCLR):
|
|
arga &= 0xf;
|
|
bit = (argb & (1 << arga));
|
|
res = argb & ~(1 << arga);
|
|
goto bitop;
|
|
|
|
|
|
LABEL (O_BRA):
|
|
LABEL (O_BT):
|
|
if (1)
|
|
goto condtrue;
|
|
|
|
LABEL (O_BRN):
|
|
LABEL (O_BF):
|
|
if (0)
|
|
goto condtrue;
|
|
break;
|
|
|
|
LABEL (O_BHI):
|
|
if ((C || Z) == 0)
|
|
goto condtrue;
|
|
break;
|
|
|
|
LABEL (O_BLS):
|
|
if ((C || Z))
|
|
goto condtrue;
|
|
break;
|
|
|
|
LABEL (O_BCS):
|
|
LABEL (O_BLO):
|
|
if ((C == 1))
|
|
goto condtrue;
|
|
break;
|
|
|
|
LABEL (O_BCC):
|
|
LABEL (O_BHS):
|
|
if ((C == 0))
|
|
goto condtrue;
|
|
break;
|
|
|
|
LABEL (O_BEQ):
|
|
if (Z)
|
|
goto condtrue;
|
|
break;
|
|
LABEL (O_BGT):
|
|
if (((Z || (N ^ V)) == 0))
|
|
goto condtrue;
|
|
break;
|
|
|
|
|
|
LABEL (O_BLE):
|
|
if (((Z || (N ^ V)) == 1))
|
|
goto condtrue;
|
|
break;
|
|
|
|
LABEL (O_BGE):
|
|
if ((N ^ V) == 0)
|
|
goto condtrue;
|
|
break;
|
|
LABEL (O_BLT):
|
|
if ((N ^ V))
|
|
goto condtrue;
|
|
break;
|
|
LABEL (O_BMI):
|
|
if ((N))
|
|
goto condtrue;
|
|
break;
|
|
LABEL (O_BNE):
|
|
if ((Z == 0))
|
|
goto condtrue;
|
|
break;
|
|
LABEL (O_BPL):
|
|
if (N == 0)
|
|
goto condtrue;
|
|
break;
|
|
break;
|
|
LABEL (O_BVC):
|
|
if ((V == 0))
|
|
goto condtrue;
|
|
break;
|
|
LABEL (O_BVS):
|
|
if ((V == 1))
|
|
goto condtrue;
|
|
break;
|
|
|
|
LABEL (O_BNOT):
|
|
bit = argb & (1<<(arga & 0xf));
|
|
res = argb ^ (1<<(arga & 0xf));
|
|
goto bitop;
|
|
break;
|
|
|
|
LABEL (O_BSET):
|
|
arga = 1 << (arga & 0xf);
|
|
bit = argb & arga;
|
|
res = argb | arga;
|
|
goto bitop;
|
|
break;
|
|
|
|
LABEL (O_PJMP):
|
|
pc = arga;
|
|
goto next;
|
|
|
|
LABEL (O_UNLK):
|
|
{
|
|
int t;
|
|
SET_NORMREG (R7, GET_NORMREG (R6));
|
|
POPWORD (t);
|
|
SET_NORMREG (R6, t);
|
|
pc = code->next_pc;
|
|
goto next;
|
|
}
|
|
|
|
LABEL (O_RTS):
|
|
{
|
|
int cp = pc & 0xff0000;
|
|
POPWORD (pc);
|
|
pc |= cp;
|
|
goto next;
|
|
}
|
|
break;
|
|
|
|
LABEL (O_PRTS):
|
|
{
|
|
int cp;
|
|
int off;
|
|
POPWORD (cp);
|
|
POPWORD (off);
|
|
cp <<= 16;
|
|
SET_SEGREG (R_CP, cp);
|
|
pc = cp + off;
|
|
}
|
|
goto next;
|
|
|
|
LABEL (O_PJSR):
|
|
PUSHWORD (argb & 0xffff);
|
|
PUSHWORD (argb >> 16);
|
|
pc = (arga & 0xffffff);
|
|
goto next;
|
|
|
|
LABEL (O_BSR):
|
|
LABEL (O_JSR):
|
|
PUSHWORD (code->next_pc);
|
|
pc = arga | (pc & 0xff0000);
|
|
goto next;
|
|
|
|
LABEL (O_BTST):
|
|
Z = (((argb >> (arga & 0xf)) & 1) == 0);
|
|
pc = code->next_pc;
|
|
goto next;
|
|
|
|
LABEL (O_CLR):
|
|
res = 0;
|
|
break;
|
|
|
|
LABEL (O_CMP):
|
|
arga = -arga;
|
|
res = arga + argb;
|
|
break;
|
|
|
|
LABEL (O_DADD):
|
|
res = arga + argb + C;
|
|
if (res > 99)
|
|
{
|
|
res -= 100;
|
|
C = 1;
|
|
}
|
|
else
|
|
{
|
|
C = 0;
|
|
}
|
|
Z = Z && (res == 0);
|
|
break;
|
|
|
|
|
|
LABEL (O_DSUB):
|
|
res = argb - arga - C;
|
|
if (res < 0)
|
|
{
|
|
res += 100;
|
|
C = 1;
|
|
}
|
|
else
|
|
{
|
|
C = 0;
|
|
}
|
|
Z = Z && (res == 0);
|
|
break;
|
|
|
|
LABEL (O_EXTS):
|
|
res = SEXTCHAR (arga);
|
|
break;
|
|
|
|
LABEL (O_EXTU):
|
|
res = (unsigned char) arga;
|
|
break;
|
|
|
|
LABEL (O_JMP):
|
|
pc = arga | (pc & 0xff0000);
|
|
goto next;
|
|
break;
|
|
|
|
LABEL (O_LDM):
|
|
|
|
for (tmp = 0; tmp < 7; tmp++)
|
|
{
|
|
if (argb & (1 << tmp))
|
|
{
|
|
POPWORD (cpu.regs[tmp].s[LOW]);
|
|
}
|
|
}
|
|
if (argb & 0x80)
|
|
POPWORD (tmp); /* dummy ready for sp */
|
|
goto nextpc;
|
|
break;
|
|
|
|
LABEL (O_LINK):
|
|
PUSHWORD (cpu.regs[R6].s[LOW]);
|
|
cpu.regs[R6].s[LOW] = cpu.regs[R7].s[LOW];
|
|
cpu.regs[R7].s[LOW] += argb;
|
|
goto nextpc;
|
|
|
|
LABEL (O_STC):
|
|
LABEL (O_LDC):
|
|
LABEL (O_MOVFPE):
|
|
LABEL (O_MOVTPE):
|
|
LABEL (O_MOV):
|
|
LABEL (O_TST):
|
|
res = arga;
|
|
break;
|
|
|
|
LABEL (O_TRAPA):
|
|
if (arga == 15)
|
|
{
|
|
trap ();
|
|
}
|
|
else
|
|
{
|
|
PUSHWORD (pc & 0xffff);
|
|
if (cpu.maximum)
|
|
{
|
|
PUSHWORD (NORMAL_CP);
|
|
}
|
|
PUSHWORD (NORMAL_SR);
|
|
if (cpu.maximum)
|
|
{
|
|
arga = arga * 4 + 0x40;
|
|
SET_NORMAL_CPPC (longat (cpu.memory + arga));
|
|
}
|
|
else
|
|
{
|
|
arga = arga * 2 + 0x20;
|
|
SET_NORMAL_CPPC (wordat (cpu.memory + arga));
|
|
}
|
|
}
|
|
break;
|
|
|
|
LABEL (O_OR):
|
|
LABEL (O_ORC):
|
|
res = arga | argb;
|
|
break;
|
|
|
|
LABEL (O_XOR):
|
|
LABEL (O_XORC):
|
|
res = arga ^ argb;
|
|
break;
|
|
|
|
LABEL (O_SCB_F):
|
|
{
|
|
scb_f:
|
|
res = arga - 1;
|
|
code->srca.reg.wptr[0] = res;
|
|
if (res != -1)
|
|
{
|
|
pc = argb;
|
|
goto next;
|
|
}
|
|
}
|
|
break;
|
|
|
|
LABEL (O_SCB_EQ):
|
|
if (Z == 1)
|
|
break;
|
|
else
|
|
goto scb_f;
|
|
|
|
LABEL (O_SCB_NE):
|
|
if (Z == 0)
|
|
break;
|
|
else
|
|
goto scb_f;
|
|
|
|
LABEL (O_NOP):
|
|
/* If only they were all as simple as this */
|
|
break;
|
|
|
|
LABEL (O_ROTL):
|
|
res = arga << 1;
|
|
C = (res >> argb) & 1;
|
|
res |= C;
|
|
break;
|
|
|
|
|
|
LABEL (O_ROTR):
|
|
C = arga & 1;
|
|
res = arga >> 1;
|
|
res |= (C << (argb - 1));
|
|
break;
|
|
|
|
LABEL (O_ROTXL):
|
|
res = arga << 1;
|
|
res |= C;
|
|
C = (res >> argb) & 1;
|
|
break;
|
|
|
|
LABEL (O_ROTXR):
|
|
res = arga >> 1;
|
|
res |= (C << (argb - 1));
|
|
C = arga & 1;
|
|
break;
|
|
|
|
LABEL (O_SHAL):
|
|
res = arga << 1;
|
|
if (argb == 16)
|
|
{
|
|
C = (res >> (16)) & 1;
|
|
Z = ((res & 0xffff) == 0);
|
|
N = ((res & 0x8000) != 0);
|
|
}
|
|
|
|
else
|
|
{
|
|
C = (res >> (8)) & 1;
|
|
Z = ((res & 0xff) == 0);
|
|
N = ((res & 0x80) != 0);
|
|
|
|
}
|
|
V = C ^ N;
|
|
goto none;
|
|
|
|
LABEL (O_SHAR):
|
|
C = arga & 1;
|
|
if (argb == 16)
|
|
{
|
|
res = ((short) arga) >> 1;
|
|
}
|
|
else
|
|
{
|
|
res = (SEXTCHAR (arga)) >> 1;
|
|
}
|
|
break;
|
|
|
|
LABEL (O_SHLL):
|
|
res = arga << 1;
|
|
C = (res >> argb) & 1;
|
|
break;
|
|
|
|
LABEL (O_SHLR):
|
|
C = arga & 1;
|
|
res = arga >> 1;
|
|
break;
|
|
|
|
LABEL (O_DIVXU):
|
|
if (arga == 0)
|
|
{
|
|
N = V = C = 0;
|
|
Z = 1;
|
|
cpu.exception = SIGILL;
|
|
}
|
|
else
|
|
{
|
|
int d = argb / arga;
|
|
int m = argb % arga;
|
|
if (code->dst.type == eas.s.ea_reg.s.dstlong)
|
|
{
|
|
res = (m << 16) | (d & 0xffff);
|
|
}
|
|
else
|
|
{
|
|
res = (m << 8) | (d & 0xff);
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
LABEL (O_MULXU):
|
|
res = arga * argb;
|
|
break;
|
|
|
|
LABEL (O_NOT):
|
|
res = ~arga;
|
|
break;
|
|
|
|
LABEL (O_SWAP):
|
|
res = ((arga >> 8) & 0xff) | ((arga << 8) & 0xff00);
|
|
break;
|
|
|
|
|
|
LABEL (O_STM):
|
|
for (tmp = 7; tmp >= 0; tmp--)
|
|
{
|
|
if (arga & (1 << tmp))
|
|
{
|
|
PUSHWORD (cpu.regs[tmp].s[LOW]);
|
|
}
|
|
}
|
|
goto nextpc;
|
|
|
|
LABEL (O_TAS):
|
|
C = 0;
|
|
V = 0;
|
|
Z = arga == 0;
|
|
N = arga < 0;
|
|
res = arga | 0x80;
|
|
goto none;
|
|
|
|
LABEL (O_PRTD):
|
|
LABEL (O_XCH):
|
|
LABEL (O_RTD):
|
|
cpu.exception = SIGILL;
|
|
goto next;
|
|
|
|
LABEL (O_TRAP_VS):
|
|
LABEL (O_SLEEP):
|
|
LABEL (O_BPT):
|
|
cpu.exception = SIGTRAP;
|
|
goto next;
|
|
break;
|
|
}
|
|
|
|
ENDDISPATCH;
|
|
|
|
DISPATCH (code->flags)
|
|
{
|
|
bitop:
|
|
Z = (res & bit) == 0;
|
|
pc = code->next_pc;
|
|
break;
|
|
LABEL (FLAG_multword):
|
|
Z = (res & 0xffff) == 0;
|
|
N = (res & 0x8000) != 0;
|
|
V = 0;
|
|
C = 0;
|
|
pc = code->next_pc;
|
|
break;
|
|
|
|
LABEL (FLAG_multbyte):
|
|
/* 8*8 -> 16 */
|
|
Z = (res & 0xff) == 0;
|
|
N = (res & 0x80) != 0;
|
|
V = 0;
|
|
C = 0;
|
|
pc = code->next_pc;
|
|
break;
|
|
|
|
LABEL (FLAG_shiftword):
|
|
N = (res & 0x8000) != 0;
|
|
Z = (res & 0xffff) == 0;
|
|
V = 0;
|
|
pc = code->next_pc;
|
|
break;
|
|
|
|
LABEL (FLAG_shiftbyte):
|
|
N = (res & 0x80) != 0;
|
|
Z = (res & 0xff) == 0;
|
|
V = 0;
|
|
pc = code->next_pc;
|
|
break;
|
|
|
|
LABEL (FLAG_special):
|
|
pc = code->next_pc;
|
|
break;
|
|
|
|
LABEL (FLAG_m):
|
|
/* Move byte flags */
|
|
/* after a logical instruction */
|
|
N = (res & 0x80) != 0;
|
|
Z = (res & 0xff) == 0;
|
|
V = (((~arga & ~argb & res) | (arga & argb & ~res)) & 0x80) != 0;
|
|
pc = code->next_pc;
|
|
break;
|
|
|
|
LABEL (FLAG_M):
|
|
/* Move word flags */
|
|
/* after a logical instruction */
|
|
N = (res & 0x8000) != 0;
|
|
Z = (res & 0xffff) == 0;
|
|
V = (((~arga & ~argb & res) | (arga & argb & ~res)) & 0x8000) != 0;
|
|
pc = code->next_pc;
|
|
break;
|
|
|
|
LABEL (FLAG_a):
|
|
/* after byte sized arith */
|
|
C = (res & 0x100) != 0;
|
|
N = (res & 0x80) != 0;
|
|
Z = (res & 0xff) == 0;
|
|
V = (((~arga & ~argb & res) | (arga & argb & ~res)) & 0x80) != 0;
|
|
pc = code->next_pc;
|
|
break;
|
|
|
|
LABEL (FLAG_A):
|
|
/* after word sized arith */
|
|
C = (res & 0x10000) != 0;
|
|
N = (res & 0x8000) != 0;
|
|
Z = (res & 0xffff) == 0;
|
|
V = (((~arga & ~argb & res) | (arga & argb & ~res)) & 0x8000) != 0;
|
|
pc = code->next_pc;
|
|
break;
|
|
|
|
LABEL (FLAG_NONE):
|
|
none:;
|
|
/* no flags but store */
|
|
pc = code->next_pc;
|
|
break;
|
|
LABEL (FLAG_NOSTORE):
|
|
/* no flags and no store */
|
|
pc = code->next_pc;
|
|
break;
|
|
LABEL (FLAG_CLEAR):
|
|
/* clear flags */
|
|
N = 0;
|
|
Z = 1;
|
|
V = 0;
|
|
C = 0;
|
|
pc = code->next_pc;
|
|
break;
|
|
condtrue:
|
|
pc = arga;
|
|
goto next;
|
|
}
|
|
ENDDISPATCH;
|
|
|
|
DISPATCH (code->dst.type)
|
|
{
|
|
unsigned char *lval;
|
|
|
|
LABEL (STORE_CRB):
|
|
(*(code->dst.reg.segptr)) = cpu.memory + (res << 16);
|
|
break;
|
|
|
|
LABEL (STORE_NOP):
|
|
break;
|
|
|
|
LABEL (STORE_REG_B):
|
|
(*(code->dst.reg.bptr)) = res;
|
|
break;
|
|
|
|
LABEL (STORE_REG_W):
|
|
(*(code->dst.reg.wptr)) = res;
|
|
break;
|
|
|
|
LABEL (STORE_REG_L):
|
|
{
|
|
int l, r;
|
|
|
|
r = (union rtype *) (code->dst.reg.wptr) - &cpu.regs[0];
|
|
r++;
|
|
*(code->dst.reg.wptr) = res >> 16;
|
|
cpu.regs[r].s[LOW] = res & 0xffff;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
LABEL (STORE_DISP_W):
|
|
lval = displval (code->dst);
|
|
setwordat (lval, res);
|
|
break;
|
|
|
|
LABEL (STORE_DISP_B):
|
|
lval = displval (code->dst);
|
|
setbyteat (lval, res);
|
|
break;
|
|
|
|
LABEL (STORE_INC_B):
|
|
lval = elval (code->dst, 0);
|
|
setbyteat (lval, res);
|
|
(*(code->dst.reg.wptr))++;
|
|
break;
|
|
|
|
LABEL (STORE_INC_W):
|
|
lval = elval (code->dst, 0);
|
|
setwordat (lval, res);
|
|
(*(code->dst.reg.wptr)) += 2;
|
|
break;
|
|
|
|
LABEL (STORE_DEC_B):
|
|
(*(code->dst.reg.wptr))--;
|
|
lval = elval (code->dst, 0);
|
|
setbyteat (lval, res);
|
|
break;
|
|
|
|
LABEL (STORE_CRW):
|
|
/* Make an up to date sr from the flag state */
|
|
cpu.regs[R_SR].s[LOW] = res;
|
|
GETSR ();
|
|
break;
|
|
|
|
LABEL (STORE_DEC_W):
|
|
(*(code->dst.reg.wptr)) -= 2;
|
|
lval = elval (code->dst, 0);
|
|
setwordat (lval, res);
|
|
|
|
break;
|
|
|
|
nextpc:
|
|
pc = code->next_pc;
|
|
|
|
}
|
|
ENDDISPATCH;
|
|
next:;
|
|
}
|
|
while (!cpu.exception);
|
|
}
|
|
|
|
cpu.ticks += get_now () - tick_start;
|
|
cpu.cycles += cycles;
|
|
cpu.insts += insts;
|
|
cpu.regs[R_PC].s[LOW] = pc;
|
|
BUILDSR ();
|
|
|
|
signal (SIGINT, prev);
|
|
signal (SIGSEGV, prev_seg);
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
sim_write (sd, addr, buffer, size)
|
|
SIM_DESC sd;
|
|
SIM_ADDR addr;
|
|
unsigned char *buffer;
|
|
int size;
|
|
{
|
|
int i;
|
|
|
|
init_pointers ();
|
|
if (addr < 0 || addr + size > H8500_MSIZE)
|
|
return 0;
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
cpu.memory[addr + i] = buffer[i];
|
|
cpu.cache_idx[addr + i] = 0;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
int
|
|
sim_read (sd, addr, buffer, size)
|
|
SIM_DESC sd;
|
|
SIM_ADDR addr;
|
|
unsigned char *buffer;
|
|
int size;
|
|
{
|
|
init_pointers ();
|
|
if (addr < 0 || addr + size > H8500_MSIZE)
|
|
return 0;
|
|
memcpy (buffer, cpu.memory + addr, size);
|
|
return size;
|
|
}
|
|
|
|
/* Ripped off from tm-h8500.h */
|
|
|
|
#define R0_REGNUM 0
|
|
#define R1_REGNUM 1
|
|
#define R2_REGNUM 2
|
|
#define R3_REGNUM 3
|
|
#define R4_REGNUM 4
|
|
#define R5_REGNUM 5
|
|
#define R6_REGNUM 6
|
|
#define R7_REGNUM 7
|
|
|
|
/* As above, but with correct seg register glued on */
|
|
#define PR0_REGNUM 8
|
|
#define PR1_REGNUM 9
|
|
#define PR2_REGNUM 10
|
|
#define PR3_REGNUM 11
|
|
#define PR4_REGNUM 12
|
|
#define PR5_REGNUM 13
|
|
#define PR6_REGNUM 14
|
|
#define PR7_REGNUM 15
|
|
|
|
#define SP_REGNUM PR7_REGNUM /* Contains address of top of stack */
|
|
#define FP_REGNUM PR6_REGNUM /* Contains address of executing stack frame */
|
|
|
|
|
|
#define SEG_C_REGNUM 16 /* Segment registers */
|
|
#define SEG_D_REGNUM 17
|
|
#define SEG_E_REGNUM 18
|
|
#define SEG_T_REGNUM 19
|
|
|
|
#define CCR_REGNUM 20 /* Contains processor status */
|
|
#define PC_REGNUM 21 /* Contains program counter */
|
|
|
|
#define CYCLE_REGNUM 22
|
|
#define INST_REGNUM 23
|
|
#define TICK_REGNUM 24
|
|
|
|
int
|
|
sim_store_register (sd, rn, value, length)
|
|
SIM_DESC sd;
|
|
int rn;
|
|
unsigned char *value;
|
|
int length;
|
|
{
|
|
int seg = 0;
|
|
int reg = -1;
|
|
|
|
init_pointers ();
|
|
switch (rn)
|
|
{
|
|
case PC_REGNUM:
|
|
SET_SEGREG (R_CP, (value[1]<<16));
|
|
cpu.regs[R_PC].s[LOW] = (value[2] << 8) | value[3];
|
|
break;
|
|
case SEG_C_REGNUM:
|
|
case SEG_D_REGNUM:
|
|
case SEG_E_REGNUM:
|
|
case SEG_T_REGNUM:
|
|
seg = rn - SEG_C_REGNUM + R_CP;
|
|
reg = -1;
|
|
break;
|
|
default:
|
|
abort ();
|
|
case R0_REGNUM:
|
|
case R1_REGNUM:
|
|
case R2_REGNUM:
|
|
case R3_REGNUM:
|
|
case R4_REGNUM:
|
|
case R5_REGNUM:
|
|
case R6_REGNUM:
|
|
case R7_REGNUM:
|
|
seg = 0;
|
|
reg = rn - R0_REGNUM;
|
|
break;
|
|
case CCR_REGNUM:
|
|
seg = 0;
|
|
reg = R_SR;
|
|
break;
|
|
case CYCLE_REGNUM:
|
|
cpu.cycles = (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3];
|
|
return;
|
|
case INST_REGNUM:
|
|
cpu.insts = (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3];
|
|
return;
|
|
case TICK_REGNUM:
|
|
cpu.ticks = (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3];
|
|
return;
|
|
case PR0_REGNUM:
|
|
case PR1_REGNUM:
|
|
case PR2_REGNUM:
|
|
case PR3_REGNUM:
|
|
case PR4_REGNUM:
|
|
case PR5_REGNUM:
|
|
case PR6_REGNUM:
|
|
case PR7_REGNUM:
|
|
SET_SEGREG (segforreg[rn], value[1]);
|
|
reg = rn - PR0_REGNUM;
|
|
cpu.regs[reg].s[LOW] = (value[2] << 8) | value[3];
|
|
return;
|
|
}
|
|
|
|
if (seg)
|
|
SET_SEGREG (seg, value[0] << 16);
|
|
|
|
if (reg > 0)
|
|
{
|
|
cpu.regs[reg].s[LOW] = (value[0] << 8) | value[1];
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int
|
|
sim_fetch_register (sd, rn, buf, length)
|
|
SIM_DESC sd;
|
|
int rn;
|
|
unsigned char *buf;
|
|
int length;
|
|
{
|
|
init_pointers ();
|
|
|
|
switch (rn)
|
|
{
|
|
default:
|
|
abort ();
|
|
case SEG_C_REGNUM:
|
|
case SEG_D_REGNUM:
|
|
case SEG_E_REGNUM:
|
|
case SEG_T_REGNUM:
|
|
buf[0] = GET_SEGREG(rn - SEG_C_REGNUM + R_CP);
|
|
break;
|
|
case CCR_REGNUM:
|
|
buf[0] = cpu.regs[R_SR].s[HIGH];
|
|
buf[1] = cpu.regs[R_SR].s[LOW];
|
|
break;
|
|
case PC_REGNUM:
|
|
buf[0] = 0;
|
|
buf[1] = GET_SEGREG(R_CP);
|
|
buf[2] = HIGH_BYTE (cpu.regs[R_PC].s[LOW]);
|
|
buf[3] = LOW_BYTE (cpu.regs[R_PC].s[LOW]);
|
|
break;
|
|
|
|
case PR0_REGNUM:
|
|
case PR1_REGNUM:
|
|
case PR2_REGNUM:
|
|
case PR3_REGNUM:
|
|
case PR4_REGNUM:
|
|
case PR5_REGNUM:
|
|
case PR6_REGNUM:
|
|
case PR7_REGNUM:
|
|
rn -= PR0_REGNUM;
|
|
buf[0] = 0;
|
|
buf[1] = GET_SEGREG(segforreg[rn]);
|
|
buf[2] = HIGH_BYTE (cpu.regs[rn].s[LOW]);
|
|
buf[3] = LOW_BYTE (cpu.regs[rn].s[LOW]);
|
|
break;
|
|
case R0_REGNUM:
|
|
case R1_REGNUM:
|
|
case R2_REGNUM:
|
|
case R3_REGNUM:
|
|
case R4_REGNUM:
|
|
case R5_REGNUM:
|
|
case R6_REGNUM:
|
|
case R7_REGNUM:
|
|
buf[0] = HIGH_BYTE (cpu.regs[rn].s[LOW]);
|
|
buf[1] = LOW_BYTE (cpu.regs[rn].s[LOW]);
|
|
break;
|
|
case CYCLE_REGNUM:
|
|
buf[0] = cpu.cycles >> 24;
|
|
buf[1] = cpu.cycles >> 16;
|
|
buf[2] = cpu.cycles >> 8;
|
|
buf[3] = cpu.cycles >> 0;
|
|
break;
|
|
|
|
case TICK_REGNUM:
|
|
buf[0] = cpu.ticks >> 24;
|
|
buf[1] = cpu.ticks >> 16;
|
|
buf[2] = cpu.ticks >> 8;
|
|
buf[3] = cpu.ticks >> 0;
|
|
break;
|
|
|
|
case INST_REGNUM:
|
|
buf[0] = cpu.insts >> 24;
|
|
buf[1] = cpu.insts >> 16;
|
|
buf[2] = cpu.insts >> 8;
|
|
buf[3] = cpu.insts >> 0;
|
|
break;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int
|
|
sim_trace (sd)
|
|
SIM_DESC sd;
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 12; i += 2)
|
|
{
|
|
unsigned char *p = cpu.regs[R_TP].c + ((cpu.regs[R6].s[LOW] + i) & 0xffff);
|
|
unsigned short *j = (unsigned short *) p;
|
|
|
|
printf ("%04x ", *j);
|
|
}
|
|
printf ("\n");
|
|
printf ("%02x %02x %02x %02x:%04x %04x %04x %04x %04x %04x %04x %04x %04x\n",
|
|
NORMAL_DP,
|
|
NORMAL_EP,
|
|
NORMAL_TP,
|
|
NORMAL_CP,
|
|
cpu.regs[R_PC].s[LOW],
|
|
cpu.regs[0].s[LOW],
|
|
cpu.regs[1].s[LOW],
|
|
cpu.regs[2].s[LOW],
|
|
cpu.regs[3].s[LOW],
|
|
cpu.regs[4].s[LOW],
|
|
cpu.regs[5].s[LOW],
|
|
cpu.regs[6].s[LOW],
|
|
cpu.regs[7].s[LOW]);
|
|
sim_resume (sd, 1, 0);
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
sim_stop_reason (sd, reason, sigrc)
|
|
SIM_DESC sd;
|
|
enum sim_stop *reason;
|
|
int *sigrc;
|
|
{
|
|
*reason = sim_stopped;
|
|
*sigrc = cpu.exception;
|
|
}
|
|
|
|
void
|
|
sim_set_simcache_size (n)
|
|
{
|
|
if (cpu.cache)
|
|
free (cpu.cache);
|
|
if (n < 2)
|
|
n = 2;
|
|
cpu.cache = (decoded_inst *) malloc (sizeof (decoded_inst) * n);
|
|
cpu.csize = n;
|
|
}
|
|
|
|
void
|
|
sim_size (n)
|
|
int n;
|
|
{
|
|
/* Fixed size. */
|
|
}
|
|
|
|
void
|
|
sim_info (sd, verbose)
|
|
SIM_DESC sd;
|
|
int verbose;
|
|
{
|
|
double timetaken = (double) cpu.ticks / (double) now_persec ();
|
|
double virttime = cpu.cycles / 10.0e6;
|
|
|
|
(*sim_callback->printf_filtered) (sim_callback,
|
|
"\n\ninstructions executed %10d\n",
|
|
cpu.insts);
|
|
(*sim_callback->printf_filtered) (sim_callback,
|
|
"cycles (v approximate) %10d\n",
|
|
cpu.cycles);
|
|
(*sim_callback->printf_filtered) (sim_callback,
|
|
"real time taken %10.4f\n",
|
|
timetaken);
|
|
(*sim_callback->printf_filtered) (sim_callback,
|
|
"virtual time taked %10.4f\n",
|
|
virttime);
|
|
if (timetaken)
|
|
{
|
|
(*sim_callback->printf_filtered) (sim_callback,
|
|
"simulation ratio %10.4f\n",
|
|
virttime / timetaken);
|
|
}
|
|
|
|
(*sim_callback->printf_filtered) (sim_callback,
|
|
"compiles %10d\n",
|
|
cpu.compiles);
|
|
(*sim_callback->printf_filtered) (sim_callback,
|
|
"cache size %10d\n",
|
|
cpu.csize);
|
|
}
|
|
|
|
SIM_DESC
|
|
sim_open (kind, cb, abfd, argv)
|
|
SIM_OPEN_KIND kind;
|
|
host_callback *cb;
|
|
struct _bfd *abfd;
|
|
char **argv;
|
|
{
|
|
sim_kind = kind;
|
|
myname = argv[0];
|
|
sim_callback = cb;
|
|
/* fudge our descriptor */
|
|
return (SIM_DESC) 1;
|
|
}
|
|
|
|
void
|
|
sim_close (sd, quitting)
|
|
SIM_DESC sd;
|
|
int quitting;
|
|
{
|
|
/* nothing to do */
|
|
}
|
|
|
|
SIM_RC
|
|
sim_load (sd, prog, abfd, from_tty)
|
|
SIM_DESC sd;
|
|
char *prog;
|
|
bfd *abfd;
|
|
int from_tty;
|
|
{
|
|
extern bfd *sim_load_file (); /* ??? Don't know where this should live. */
|
|
bfd *prog_bfd;
|
|
|
|
prog_bfd = sim_load_file (sd, myname, sim_callback, prog, abfd,
|
|
sim_kind == SIM_OPEN_DEBUG,
|
|
0, sim_write);
|
|
if (prog_bfd == NULL)
|
|
return SIM_RC_FAIL;
|
|
if (abfd == NULL)
|
|
bfd_close (prog_bfd);
|
|
return SIM_RC_OK;
|
|
}
|
|
|
|
SIM_RC
|
|
sim_create_inferior (sd, abfd, argv, env)
|
|
SIM_DESC sd;
|
|
struct _bfd *abfd;
|
|
char **argv;
|
|
char **env;
|
|
{
|
|
int pc;
|
|
bfd_vma start_address;
|
|
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 (sd, PC_REGNUM, (unsigned char *) &pc, 4);
|
|
return SIM_RC_OK;
|
|
}
|
|
|
|
void
|
|
sim_do_command (sd, cmd)
|
|
SIM_DESC sd;
|
|
char *cmd;
|
|
{
|
|
(*sim_callback->printf_filtered) (sim_callback,
|
|
"This simulator does not accept any commands.\n");
|
|
}
|
|
|
|
void
|
|
sim_set_callbacks (ptr)
|
|
struct host_callback_struct *ptr;
|
|
{
|
|
sim_callback = ptr;
|
|
}
|