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