aboutsummaryrefslogtreecommitdiff
path: root/sim/rl78/rl78.c
diff options
context:
space:
mode:
authorDJ Delorie <dj@redhat.com>2011-11-29 03:49:09 +0000
committerDJ Delorie <dj@redhat.com>2011-11-29 03:49:09 +0000
commit87326c782a97fdacdd003599c8633b28114f8ed9 (patch)
treefcce7203ce754ec2a269d2dea60c76fa6985c5c7 /sim/rl78/rl78.c
parent1e3a8f45c5a6e5d922e6e981d1572f2db35fb7a9 (diff)
downloadgdb-87326c782a97fdacdd003599c8633b28114f8ed9.zip
gdb-87326c782a97fdacdd003599c8633b28114f8ed9.tar.gz
gdb-87326c782a97fdacdd003599c8633b28114f8ed9.tar.bz2
[sim]
* configure.tgt: Add rl78 support. * configure: Regenerate. * rl78: New directory. * MAINTAINERS: Add myself as RL78 maintainer. [gdb] * NEWS: Mention RL78 simulator.
Diffstat (limited to 'sim/rl78/rl78.c')
-rw-r--r--sim/rl78/rl78.c915
1 files changed, 915 insertions, 0 deletions
diff --git a/sim/rl78/rl78.c b/sim/rl78/rl78.c
new file mode 100644
index 0000000..ceb2334
--- /dev/null
+++ b/sim/rl78/rl78.c
@@ -0,0 +1,915 @@
+/* rl78.c --- opcode semantics for stand-alone RL78 simulator.
+
+ Copyright (C) 2008, 2009, 2010, 2011 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/>.
+*/
+
+#include "config.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;
+
+ if (size == RL78_Word)
+ {
+ cmask = 0x10000;
+ vmask = 0xffff;
+ amask = 0x100;
+ avmask = 0x0ff;
+ }
+ else
+ {
+ cmask = 0x100;
+ vmask = 0xff;
+ amask = 0x10;
+ avmask = 0x0f;
+ }
+
+ int 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_data.dpc = pc;
+ opcode_size = rl78_decode_opcode (pc, &opcode,
+ rl78_get_byte, &rl78_data);
+
+ 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);
+ 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 ();
+}