mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 18:14:13 +08:00
6df01ab8ab
The defs.h header will take care of including the various config.h headers. For now, it's just config.h, but we'll add more when we integrate gnulib in. This header should be used instead of config.h, and should be the first include in every .c file. We won't rely on the old behavior where we expected files to include the port's sim-main.h which then includes the common sim-basics.h which then includes config.h. We have a ton of code that includes things before sim-main.h, and it sometimes needs to be that way. Creating a dedicated header avoids the ordering mess and implicit inclusion that shows up otherwise.
925 lines
19 KiB
C
925 lines
19 KiB
C
/* rl78.c --- opcode semantics for stand-alone RL78 simulator.
|
|
|
|
Copyright (C) 2008-2021 Free Software Foundation, Inc.
|
|
Contributed by Red Hat, Inc.
|
|
|
|
This file is part of the GNU simulators.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/* This must come before any other includes. */
|
|
#include "defs.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <setjmp.h>
|
|
#include <time.h>
|
|
|
|
#include "opcode/rl78.h"
|
|
#include "cpu.h"
|
|
#include "mem.h"
|
|
|
|
extern int skip_init;
|
|
static int opcode_pc = 0;
|
|
|
|
jmp_buf decode_jmp_buf;
|
|
#define DO_RETURN(x) longjmp (decode_jmp_buf, x)
|
|
|
|
#define tprintf if (trace) printf
|
|
|
|
#define WILD_JUMP_CHECK(new_pc) \
|
|
do { \
|
|
if (new_pc == 0 || new_pc > 0xfffff) \
|
|
{ \
|
|
pc = opcode_pc; \
|
|
fprintf (stderr, "Wild jump to 0x%x from 0x%x!\n", new_pc, pc); \
|
|
DO_RETURN (RL78_MAKE_HIT_BREAK ()); \
|
|
} \
|
|
} while (0)
|
|
|
|
typedef struct {
|
|
unsigned long dpc;
|
|
} RL78_Data;
|
|
|
|
static int
|
|
rl78_get_byte (void *vdata)
|
|
{
|
|
RL78_Data *rl78_data = (RL78_Data *)vdata;
|
|
int rv = mem_get_pc (rl78_data->dpc);
|
|
rl78_data->dpc ++;
|
|
return rv;
|
|
}
|
|
|
|
static int
|
|
op_addr (const RL78_Opcode_Operand *o, int for_data)
|
|
{
|
|
int v = o->addend;
|
|
if (o->reg != RL78_Reg_None)
|
|
v += get_reg (o->reg);
|
|
if (o->reg2 != RL78_Reg_None)
|
|
v += get_reg (o->reg2);
|
|
if (o->use_es)
|
|
v |= (get_reg (RL78_Reg_ES) & 0xf) << 16;
|
|
else if (for_data)
|
|
v |= 0xf0000;
|
|
v &= 0xfffff;
|
|
return v;
|
|
}
|
|
|
|
static int
|
|
get_op (const RL78_Opcode_Decoded *rd, int i, int for_data)
|
|
{
|
|
int v, r;
|
|
const RL78_Opcode_Operand *o = rd->op + i;
|
|
|
|
switch (o->type)
|
|
{
|
|
case RL78_Operand_None:
|
|
/* condition code does this. */
|
|
v = 0;
|
|
break;
|
|
|
|
case RL78_Operand_Immediate:
|
|
tprintf (" #");
|
|
v = o->addend;
|
|
break;
|
|
|
|
case RL78_Operand_Register:
|
|
tprintf (" %s=", reg_names[o->reg]);
|
|
v = get_reg (o->reg);
|
|
break;
|
|
|
|
case RL78_Operand_Bit:
|
|
tprintf (" %s.%d=", reg_names[o->reg], o->bit_number);
|
|
v = get_reg (o->reg);
|
|
v = (v & (1 << o->bit_number)) ? 1 : 0;
|
|
break;
|
|
|
|
case RL78_Operand_Indirect:
|
|
v = op_addr (o, for_data);
|
|
tprintf (" [0x%x]=", v);
|
|
if (rd->size == RL78_Word)
|
|
v = mem_get_hi (v);
|
|
else
|
|
v = mem_get_qi (v);
|
|
break;
|
|
|
|
case RL78_Operand_BitIndirect:
|
|
v = op_addr (o, for_data);
|
|
tprintf (" [0x%x].%d=", v, o->bit_number);
|
|
v = (mem_get_qi (v) & (1 << o->bit_number)) ? 1 : 0;
|
|
break;
|
|
|
|
case RL78_Operand_PreDec:
|
|
r = get_reg (o->reg);
|
|
tprintf (" [--%s]", reg_names[o->reg]);
|
|
if (rd->size == RL78_Word)
|
|
{
|
|
r -= 2;
|
|
v = mem_get_hi (r | 0xf0000);
|
|
}
|
|
else
|
|
{
|
|
r -= 1;
|
|
v = mem_get_qi (r | 0xf0000);
|
|
}
|
|
set_reg (o->reg, r);
|
|
break;
|
|
|
|
case RL78_Operand_PostInc:
|
|
tprintf (" [%s++]", reg_names[o->reg]);
|
|
r = get_reg (o->reg);
|
|
if (rd->size == RL78_Word)
|
|
{
|
|
v = mem_get_hi (r | 0xf0000);
|
|
r += 2;
|
|
}
|
|
else
|
|
{
|
|
v = mem_get_qi (r | 0xf0000);
|
|
r += 1;
|
|
}
|
|
set_reg (o->reg, r);
|
|
break;
|
|
|
|
default:
|
|
abort ();
|
|
}
|
|
tprintf ("%d", v);
|
|
return v;
|
|
}
|
|
|
|
static void
|
|
put_op (const RL78_Opcode_Decoded *rd, int i, int for_data, int v)
|
|
{
|
|
int r, a;
|
|
const RL78_Opcode_Operand *o = rd->op + i;
|
|
|
|
tprintf (" -> ");
|
|
|
|
switch (o->type)
|
|
{
|
|
case RL78_Operand_Register:
|
|
tprintf ("%s", reg_names[o->reg]);
|
|
set_reg (o->reg, v);
|
|
break;
|
|
|
|
case RL78_Operand_Bit:
|
|
tprintf ("%s.%d", reg_names[o->reg], o->bit_number);
|
|
r = get_reg (o->reg);
|
|
if (v)
|
|
r |= (1 << o->bit_number);
|
|
else
|
|
r &= ~(1 << o->bit_number);
|
|
set_reg (o->reg, r);
|
|
break;
|
|
|
|
case RL78_Operand_Indirect:
|
|
r = op_addr (o, for_data);
|
|
tprintf ("[0x%x]", r);
|
|
if (rd->size == RL78_Word)
|
|
mem_put_hi (r, v);
|
|
else
|
|
mem_put_qi (r, v);
|
|
break;
|
|
|
|
case RL78_Operand_BitIndirect:
|
|
a = op_addr (o, for_data);
|
|
tprintf ("[0x%x].%d", a, o->bit_number);
|
|
r = mem_get_qi (a);
|
|
if (v)
|
|
r |= (1 << o->bit_number);
|
|
else
|
|
r &= ~(1 << o->bit_number);
|
|
mem_put_qi (a, r);
|
|
break;
|
|
|
|
case RL78_Operand_PreDec:
|
|
r = get_reg (o->reg);
|
|
tprintf ("[--%s]", reg_names[o->reg]);
|
|
if (rd->size == RL78_Word)
|
|
{
|
|
r -= 2;
|
|
set_reg (o->reg, r);
|
|
mem_put_hi (r | 0xf0000, v);
|
|
}
|
|
else
|
|
{
|
|
r -= 1;
|
|
set_reg (o->reg, r);
|
|
mem_put_qi (r | 0xf0000, v);
|
|
}
|
|
break;
|
|
|
|
case RL78_Operand_PostInc:
|
|
tprintf ("[%s++]", reg_names[o->reg]);
|
|
r = get_reg (o->reg);
|
|
if (rd->size == RL78_Word)
|
|
{
|
|
mem_put_hi (r | 0xf0000, v);
|
|
r += 2;
|
|
}
|
|
else
|
|
{
|
|
mem_put_qi (r | 0xf0000, v);
|
|
r += 1;
|
|
}
|
|
set_reg (o->reg, r);
|
|
break;
|
|
|
|
default:
|
|
abort ();
|
|
}
|
|
tprintf ("\n");
|
|
}
|
|
|
|
static void
|
|
op_flags (int before, int after, int mask, RL78_Size size)
|
|
{
|
|
int vmask, cmask, amask, avmask;
|
|
int psw;
|
|
|
|
if (size == RL78_Word)
|
|
{
|
|
cmask = 0x10000;
|
|
vmask = 0xffff;
|
|
amask = 0x100;
|
|
avmask = 0x0ff;
|
|
}
|
|
else
|
|
{
|
|
cmask = 0x100;
|
|
vmask = 0xff;
|
|
amask = 0x10;
|
|
avmask = 0x0f;
|
|
}
|
|
|
|
psw = get_reg (RL78_Reg_PSW);
|
|
psw &= ~mask;
|
|
|
|
if (mask & RL78_PSW_CY)
|
|
{
|
|
if ((after & cmask) != (before & cmask))
|
|
psw |= RL78_PSW_CY;
|
|
}
|
|
if (mask & RL78_PSW_AC)
|
|
{
|
|
if ((after & amask) != (before & amask)
|
|
&& (after & avmask) < (before & avmask))
|
|
psw |= RL78_PSW_AC;
|
|
}
|
|
if (mask & RL78_PSW_Z)
|
|
{
|
|
if (! (after & vmask))
|
|
psw |= RL78_PSW_Z;
|
|
}
|
|
|
|
set_reg (RL78_Reg_PSW, psw);
|
|
}
|
|
|
|
#define FLAGS(before,after) if (opcode.flags) op_flags (before, after, opcode.flags, opcode.size)
|
|
|
|
#define PD(x) put_op (&opcode, 0, 1, x)
|
|
#define PS(x) put_op (&opcode, 1, 1, x)
|
|
#define GD() get_op (&opcode, 0, 1)
|
|
#define GS() get_op (&opcode, 1, 1)
|
|
|
|
#define GPC() gpc (&opcode, 0)
|
|
static int
|
|
gpc (RL78_Opcode_Decoded *opcode, int idx)
|
|
{
|
|
int a = get_op (opcode, 0, 1);
|
|
if (opcode->op[idx].type == RL78_Operand_Register)
|
|
a =(a & 0x0ffff) | ((get_reg (RL78_Reg_CS) & 0x0f) << 16);
|
|
else
|
|
a &= 0xfffff;
|
|
return a;
|
|
}
|
|
|
|
static int
|
|
get_carry (void)
|
|
{
|
|
return (get_reg (RL78_Reg_PSW) & RL78_PSW_CY) ? 1 : 0;
|
|
}
|
|
|
|
static void
|
|
set_carry (int c)
|
|
{
|
|
int p = get_reg (RL78_Reg_PSW);
|
|
tprintf ("set_carry (%d)\n", c ? 1 : 0);
|
|
if (c)
|
|
p |= RL78_PSW_CY;
|
|
else
|
|
p &= ~RL78_PSW_CY;
|
|
set_reg (RL78_Reg_PSW, p);
|
|
}
|
|
|
|
/* We simulate timer TM00 in interval mode, no clearing, with
|
|
interrupts. I.e. it's a cycle counter. */
|
|
|
|
unsigned int counts_per_insn[0x100000];
|
|
|
|
int pending_clocks = 0;
|
|
long long total_clocks = 0;
|
|
|
|
#define TCR0 0xf0180
|
|
#define MK1 0xfffe6
|
|
static void
|
|
process_clock_tick (void)
|
|
{
|
|
unsigned short cnt;
|
|
unsigned short ivect;
|
|
unsigned short mask;
|
|
unsigned char psw;
|
|
int save_trace;
|
|
|
|
save_trace = trace;
|
|
trace = 0;
|
|
|
|
pending_clocks ++;
|
|
|
|
counts_per_insn[opcode_pc] += pending_clocks;
|
|
total_clocks += pending_clocks;
|
|
|
|
while (pending_clocks)
|
|
{
|
|
pending_clocks --;
|
|
cnt = mem_get_hi (TCR0);
|
|
cnt --;
|
|
mem_put_hi (TCR0, cnt);
|
|
if (cnt != 0xffff)
|
|
continue;
|
|
|
|
/* overflow. */
|
|
psw = get_reg (RL78_Reg_PSW);
|
|
ivect = mem_get_hi (0x0002c);
|
|
mask = mem_get_hi (MK1);
|
|
|
|
if ((psw & RL78_PSW_IE)
|
|
&& (ivect != 0)
|
|
&& !(mask & 0x0010))
|
|
{
|
|
unsigned short sp = get_reg (RL78_Reg_SP);
|
|
set_reg (RL78_Reg_SP, sp - 4);
|
|
sp --;
|
|
mem_put_qi (sp | 0xf0000, psw);
|
|
sp -= 3;
|
|
mem_put_psi (sp | 0xf0000, pc);
|
|
psw &= ~RL78_PSW_IE;
|
|
set_reg (RL78_Reg_PSW, psw);
|
|
pc = ivect;
|
|
/* Spec says 9-14 clocks */
|
|
pending_clocks += 9;
|
|
}
|
|
}
|
|
|
|
trace = save_trace;
|
|
}
|
|
|
|
void
|
|
dump_counts_per_insn (const char * filename)
|
|
{
|
|
int i;
|
|
FILE *f;
|
|
f = fopen (filename, "w");
|
|
if (!f)
|
|
{
|
|
perror (filename);
|
|
return;
|
|
}
|
|
for (i = 0; i < 0x100000; i ++)
|
|
{
|
|
if (counts_per_insn[i])
|
|
fprintf (f, "%05x %d\n", i, counts_per_insn[i]);
|
|
}
|
|
fclose (f);
|
|
}
|
|
|
|
static void
|
|
CLOCKS (int n)
|
|
{
|
|
pending_clocks += n - 1;
|
|
}
|
|
|
|
int
|
|
decode_opcode (void)
|
|
{
|
|
RL78_Data rl78_data;
|
|
RL78_Opcode_Decoded opcode;
|
|
int opcode_size;
|
|
int a, b, v, v2;
|
|
unsigned int u, u2;
|
|
int obits;
|
|
RL78_Dis_Isa isa;
|
|
|
|
isa = (rl78_g10_mode ? RL78_ISA_G10
|
|
: g14_multiply ? RL78_ISA_G14
|
|
: g13_multiply ? RL78_ISA_G13
|
|
: RL78_ISA_DEFAULT);
|
|
|
|
rl78_data.dpc = pc;
|
|
opcode_size = rl78_decode_opcode (pc, &opcode,
|
|
rl78_get_byte, &rl78_data, isa);
|
|
|
|
opcode_pc = pc;
|
|
pc += opcode_size;
|
|
|
|
trace_register_words = opcode.size == RL78_Word ? 1 : 0;
|
|
|
|
/* Used by shfit/rotate instructions */
|
|
obits = opcode.size == RL78_Word ? 16 : 8;
|
|
|
|
switch (opcode.id)
|
|
{
|
|
case RLO_add:
|
|
tprintf ("ADD: ");
|
|
a = GS ();
|
|
b = GD ();
|
|
v = a + b;
|
|
FLAGS (b, v);
|
|
PD (v);
|
|
if (opcode.op[0].type == RL78_Operand_Indirect)
|
|
CLOCKS (2);
|
|
break;
|
|
|
|
case RLO_addc:
|
|
tprintf ("ADDC: ");
|
|
a = GS ();
|
|
b = GD ();
|
|
v = a + b + get_carry ();
|
|
FLAGS (b, v);
|
|
PD (v);
|
|
if (opcode.op[0].type == RL78_Operand_Indirect)
|
|
CLOCKS (2);
|
|
break;
|
|
|
|
case RLO_and:
|
|
tprintf ("AND: ");
|
|
a = GS ();
|
|
b = GD ();
|
|
v = a & b;
|
|
FLAGS (b, v);
|
|
PD (v);
|
|
if (opcode.op[0].type == RL78_Operand_Indirect)
|
|
CLOCKS (2);
|
|
break;
|
|
|
|
case RLO_branch_cond:
|
|
case RLO_branch_cond_clear:
|
|
tprintf ("BRANCH_COND: ");
|
|
if (!condition_true (opcode.op[1].condition, GS ()))
|
|
{
|
|
tprintf (" false\n");
|
|
if (opcode.op[1].condition == RL78_Condition_T
|
|
|| opcode.op[1].condition == RL78_Condition_F)
|
|
CLOCKS (3);
|
|
else
|
|
CLOCKS (2);
|
|
break;
|
|
}
|
|
if (opcode.id == RLO_branch_cond_clear)
|
|
PS (0);
|
|
tprintf (" ");
|
|
if (opcode.op[1].condition == RL78_Condition_T
|
|
|| opcode.op[1].condition == RL78_Condition_F)
|
|
CLOCKS (3); /* note: adds two clocks, total 5 clocks */
|
|
else
|
|
CLOCKS (2); /* note: adds one clock, total 4 clocks */
|
|
case RLO_branch:
|
|
tprintf ("BRANCH: ");
|
|
v = GPC ();
|
|
WILD_JUMP_CHECK (v);
|
|
pc = v;
|
|
tprintf (" => 0x%05x\n", pc);
|
|
CLOCKS (3);
|
|
break;
|
|
|
|
case RLO_break:
|
|
tprintf ("BRK: ");
|
|
CLOCKS (5);
|
|
if (rl78_in_gdb)
|
|
DO_RETURN (RL78_MAKE_HIT_BREAK ());
|
|
else
|
|
DO_RETURN (RL78_MAKE_EXITED (1));
|
|
break;
|
|
|
|
case RLO_call:
|
|
tprintf ("CALL: ");
|
|
a = get_reg (RL78_Reg_SP);
|
|
set_reg (RL78_Reg_SP, a - 4);
|
|
mem_put_psi ((a - 4) | 0xf0000, pc);
|
|
v = GPC ();
|
|
WILD_JUMP_CHECK (v);
|
|
pc = v;
|
|
#if 0
|
|
/* Enable this code to dump the arguments for each call. */
|
|
if (trace)
|
|
{
|
|
int i;
|
|
skip_init ++;
|
|
for (i = 0; i < 8; i ++)
|
|
printf (" %02x", mem_get_qi (0xf0000 | (a + i)) & 0xff);
|
|
skip_init --;
|
|
}
|
|
#endif
|
|
tprintf ("\n");
|
|
CLOCKS (3);
|
|
break;
|
|
|
|
case RLO_cmp:
|
|
tprintf ("CMP: ");
|
|
a = GD ();
|
|
b = GS ();
|
|
v = a - b;
|
|
FLAGS (b, v);
|
|
tprintf (" (%d)\n", v);
|
|
break;
|
|
|
|
case RLO_divhu:
|
|
a = get_reg (RL78_Reg_AX);
|
|
b = get_reg (RL78_Reg_DE);
|
|
tprintf (" %d / %d = ", a, b);
|
|
if (b == 0)
|
|
{
|
|
tprintf ("%d rem %d\n", 0xffff, a);
|
|
set_reg (RL78_Reg_AX, 0xffff);
|
|
set_reg (RL78_Reg_DE, a);
|
|
}
|
|
else
|
|
{
|
|
v = a / b;
|
|
a = a % b;
|
|
tprintf ("%d rem %d\n", v, a);
|
|
set_reg (RL78_Reg_AX, v);
|
|
set_reg (RL78_Reg_DE, a);
|
|
}
|
|
CLOCKS (9);
|
|
break;
|
|
|
|
case RLO_divwu:
|
|
{
|
|
unsigned long bcax, hlde, quot, rem;
|
|
bcax = get_reg (RL78_Reg_AX) + 65536 * get_reg (RL78_Reg_BC);
|
|
hlde = get_reg (RL78_Reg_DE) + 65536 * get_reg (RL78_Reg_HL);
|
|
|
|
tprintf (" %lu / %lu = ", bcax, hlde);
|
|
if (hlde == 0)
|
|
{
|
|
tprintf ("%lu rem %lu\n", 0xffffLU, bcax);
|
|
set_reg (RL78_Reg_AX, 0xffffLU);
|
|
set_reg (RL78_Reg_BC, 0xffffLU);
|
|
set_reg (RL78_Reg_DE, bcax);
|
|
set_reg (RL78_Reg_HL, bcax >> 16);
|
|
}
|
|
else
|
|
{
|
|
quot = bcax / hlde;
|
|
rem = bcax % hlde;
|
|
tprintf ("%lu rem %lu\n", quot, rem);
|
|
set_reg (RL78_Reg_AX, quot);
|
|
set_reg (RL78_Reg_BC, quot >> 16);
|
|
set_reg (RL78_Reg_DE, rem);
|
|
set_reg (RL78_Reg_HL, rem >> 16);
|
|
}
|
|
}
|
|
CLOCKS (17);
|
|
break;
|
|
|
|
case RLO_halt:
|
|
tprintf ("HALT.\n");
|
|
DO_RETURN (RL78_MAKE_EXITED (get_reg (RL78_Reg_A)));
|
|
|
|
case RLO_mov:
|
|
tprintf ("MOV: ");
|
|
a = GS ();
|
|
FLAGS (a, a);
|
|
PD (a);
|
|
break;
|
|
|
|
#define MACR 0xffff0
|
|
case RLO_mach:
|
|
tprintf ("MACH:");
|
|
a = sign_ext (get_reg (RL78_Reg_AX), 16);
|
|
b = sign_ext (get_reg (RL78_Reg_BC), 16);
|
|
v = sign_ext (mem_get_si (MACR), 32);
|
|
tprintf ("%08x %d + %d * %d = ", v, v, a, b);
|
|
v2 = sign_ext (v + a * b, 32);
|
|
tprintf ("%08x %d\n", v2, v2);
|
|
mem_put_si (MACR, v2);
|
|
a = get_reg (RL78_Reg_PSW);
|
|
v ^= v2;
|
|
if (v & (1<<31))
|
|
a |= RL78_PSW_CY;
|
|
else
|
|
a &= ~RL78_PSW_CY;
|
|
if (v2 & (1 << 31))
|
|
a |= RL78_PSW_AC;
|
|
else
|
|
a &= ~RL78_PSW_AC;
|
|
set_reg (RL78_Reg_PSW, a);
|
|
CLOCKS (3);
|
|
break;
|
|
|
|
case RLO_machu:
|
|
tprintf ("MACHU:");
|
|
a = get_reg (RL78_Reg_AX);
|
|
b = get_reg (RL78_Reg_BC);
|
|
u = mem_get_si (MACR);
|
|
tprintf ("%08x %u + %u * %u = ", u, u, a, b);
|
|
u2 = (u + (unsigned)a * (unsigned)b) & 0xffffffffUL;
|
|
tprintf ("%08x %u\n", u2, u2);
|
|
mem_put_si (MACR, u2);
|
|
a = get_reg (RL78_Reg_PSW);
|
|
if (u2 < u)
|
|
a |= RL78_PSW_CY;
|
|
else
|
|
a &= ~RL78_PSW_CY;
|
|
a &= ~RL78_PSW_AC;
|
|
set_reg (RL78_Reg_PSW, a);
|
|
CLOCKS (3);
|
|
break;
|
|
|
|
case RLO_mulu:
|
|
tprintf ("MULU:");
|
|
a = get_reg (RL78_Reg_A);
|
|
b = get_reg (RL78_Reg_X);
|
|
v = a * b;
|
|
tprintf (" %d * %d = %d\n", a, b, v);
|
|
set_reg (RL78_Reg_AX, v);
|
|
break;
|
|
|
|
case RLO_mulh:
|
|
tprintf ("MUL:");
|
|
a = sign_ext (get_reg (RL78_Reg_AX), 16);
|
|
b = sign_ext (get_reg (RL78_Reg_BC), 16);
|
|
v = a * b;
|
|
tprintf (" %d * %d = %d\n", a, b, v);
|
|
set_reg (RL78_Reg_BC, v >> 16);
|
|
set_reg (RL78_Reg_AX, v);
|
|
CLOCKS (2);
|
|
break;
|
|
|
|
case RLO_mulhu:
|
|
tprintf ("MULHU:");
|
|
a = get_reg (RL78_Reg_AX);
|
|
b = get_reg (RL78_Reg_BC);
|
|
v = a * b;
|
|
tprintf (" %d * %d = %d\n", a, b, v);
|
|
set_reg (RL78_Reg_BC, v >> 16);
|
|
set_reg (RL78_Reg_AX, v);
|
|
CLOCKS (2);
|
|
break;
|
|
|
|
case RLO_nop:
|
|
tprintf ("NOP.\n");
|
|
break;
|
|
|
|
case RLO_or:
|
|
tprintf ("OR:");
|
|
a = GS ();
|
|
b = GD ();
|
|
v = a | b;
|
|
FLAGS (b, v);
|
|
PD (v);
|
|
if (opcode.op[0].type == RL78_Operand_Indirect)
|
|
CLOCKS (2);
|
|
break;
|
|
|
|
case RLO_ret:
|
|
tprintf ("RET: ");
|
|
a = get_reg (RL78_Reg_SP);
|
|
v = mem_get_psi (a | 0xf0000);
|
|
WILD_JUMP_CHECK (v);
|
|
pc = v;
|
|
set_reg (RL78_Reg_SP, a + 4);
|
|
#if 0
|
|
/* Enable this code to dump the return values for each return. */
|
|
if (trace)
|
|
{
|
|
int i;
|
|
skip_init ++;
|
|
for (i = 0; i < 8; i ++)
|
|
printf (" %02x", mem_get_qi (0xffef0 + i) & 0xff);
|
|
skip_init --;
|
|
}
|
|
#endif
|
|
tprintf ("\n");
|
|
CLOCKS (6);
|
|
break;
|
|
|
|
case RLO_reti:
|
|
tprintf ("RETI: ");
|
|
a = get_reg (RL78_Reg_SP);
|
|
v = mem_get_psi (a | 0xf0000);
|
|
WILD_JUMP_CHECK (v);
|
|
pc = v;
|
|
b = mem_get_qi ((a + 3) | 0xf0000);
|
|
set_reg (RL78_Reg_PSW, b);
|
|
set_reg (RL78_Reg_SP, a + 4);
|
|
tprintf ("\n");
|
|
break;
|
|
|
|
case RLO_rol:
|
|
tprintf ("ROL:"); /* d <<= s */
|
|
a = GS ();
|
|
b = GD ();
|
|
v = b;
|
|
while (a --)
|
|
{
|
|
v = b << 1;
|
|
v |= (b >> (obits - 1)) & 1;
|
|
set_carry ((b >> (obits - 1)) & 1);
|
|
b = v;
|
|
}
|
|
PD (v);
|
|
break;
|
|
|
|
case RLO_rolc:
|
|
tprintf ("ROLC:"); /* d <<= s */
|
|
a = GS ();
|
|
b = GD ();
|
|
v = b;
|
|
while (a --)
|
|
{
|
|
v = b << 1;
|
|
v |= get_carry ();
|
|
set_carry ((b >> (obits - 1)) & 1);
|
|
b = v;
|
|
}
|
|
PD (v);
|
|
break;
|
|
|
|
case RLO_ror:
|
|
tprintf ("ROR:"); /* d >>= s */
|
|
a = GS ();
|
|
b = GD ();
|
|
v = b;
|
|
while (a --)
|
|
{
|
|
v = b >> 1;
|
|
v |= (b & 1) << (obits - 1);
|
|
set_carry (b & 1);
|
|
b = v;
|
|
}
|
|
PD (v);
|
|
break;
|
|
|
|
case RLO_rorc:
|
|
tprintf ("RORC:"); /* d >>= s */
|
|
a = GS ();
|
|
b = GD ();
|
|
v = b;
|
|
while (a --)
|
|
{
|
|
v = b >> 1;
|
|
v |= (get_carry () << (obits - 1));
|
|
set_carry (b & 1);
|
|
b = v;
|
|
}
|
|
PD (v);
|
|
break;
|
|
|
|
case RLO_sar:
|
|
tprintf ("SAR:"); /* d >>= s */
|
|
a = GS ();
|
|
b = GD ();
|
|
v = b;
|
|
while (a --)
|
|
{
|
|
v = b >> 1;
|
|
v |= b & (1 << (obits - 1));
|
|
set_carry (b & 1);
|
|
b = v;
|
|
}
|
|
PD (v);
|
|
break;
|
|
|
|
case RLO_sel:
|
|
tprintf ("SEL:");
|
|
a = GS ();
|
|
b = get_reg (RL78_Reg_PSW);
|
|
b &= ~(RL78_PSW_RBS1 | RL78_PSW_RBS0);
|
|
if (a & 1)
|
|
b |= RL78_PSW_RBS0;
|
|
if (a & 2)
|
|
b |= RL78_PSW_RBS1;
|
|
set_reg (RL78_Reg_PSW, b);
|
|
tprintf ("\n");
|
|
break;
|
|
|
|
case RLO_shl:
|
|
tprintf ("SHL%d:", obits); /* d <<= s */
|
|
a = GS ();
|
|
b = GD ();
|
|
v = b;
|
|
while (a --)
|
|
{
|
|
v = b << 1;
|
|
tprintf ("b = 0x%x & 0x%x\n", b, 1<<(obits - 1));
|
|
set_carry (b & (1<<(obits - 1)));
|
|
b = v;
|
|
}
|
|
PD (v);
|
|
break;
|
|
|
|
case RLO_shr:
|
|
tprintf ("SHR:"); /* d >>= s */
|
|
a = GS ();
|
|
b = GD ();
|
|
v = b;
|
|
while (a --)
|
|
{
|
|
v = b >> 1;
|
|
set_carry (b & 1);
|
|
b = v;
|
|
}
|
|
PD (v);
|
|
break;
|
|
|
|
case RLO_skip:
|
|
tprintf ("SKIP: ");
|
|
if (!condition_true (opcode.op[1].condition, GS ()))
|
|
{
|
|
tprintf (" false\n");
|
|
break;
|
|
}
|
|
|
|
rl78_data.dpc = pc;
|
|
opcode_size = rl78_decode_opcode (pc, &opcode,
|
|
rl78_get_byte, &rl78_data, isa);
|
|
pc += opcode_size;
|
|
tprintf (" skipped: %s\n", opcode.syntax);
|
|
break;
|
|
|
|
case RLO_stop:
|
|
tprintf ("STOP.\n");
|
|
DO_RETURN (RL78_MAKE_EXITED (get_reg (RL78_Reg_A)));
|
|
DO_RETURN (RL78_MAKE_HIT_BREAK ());
|
|
|
|
case RLO_sub:
|
|
tprintf ("SUB: ");
|
|
a = GS ();
|
|
b = GD ();
|
|
v = b - a;
|
|
FLAGS (b, v);
|
|
PD (v);
|
|
tprintf ("%d (0x%x) - %d (0x%x) = %d (0x%x)\n", b, b, a, a, v, v);
|
|
if (opcode.op[0].type == RL78_Operand_Indirect)
|
|
CLOCKS (2);
|
|
break;
|
|
|
|
case RLO_subc:
|
|
tprintf ("SUBC: ");
|
|
a = GS ();
|
|
b = GD ();
|
|
v = b - a - get_carry ();
|
|
FLAGS (b, v);
|
|
PD (v);
|
|
if (opcode.op[0].type == RL78_Operand_Indirect)
|
|
CLOCKS (2);
|
|
break;
|
|
|
|
case RLO_xch:
|
|
tprintf ("XCH: ");
|
|
a = GS ();
|
|
b = GD ();
|
|
PD (a);
|
|
PS (b);
|
|
break;
|
|
|
|
case RLO_xor:
|
|
tprintf ("XOR:");
|
|
a = GS ();
|
|
b = GD ();
|
|
v = a ^ b;
|
|
FLAGS (b, v);
|
|
PD (v);
|
|
if (opcode.op[0].type == RL78_Operand_Indirect)
|
|
CLOCKS (2);
|
|
break;
|
|
|
|
default:
|
|
tprintf ("Unknown opcode?\n");
|
|
DO_RETURN (RL78_MAKE_HIT_BREAK ());
|
|
}
|
|
|
|
if (timer_enabled)
|
|
process_clock_tick ();
|
|
|
|
return RL78_MAKE_STEPPED ();
|
|
}
|