summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/cpu/i8051
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2007-12-17 15:19:59 +0000
committer Aaron Giles <aaron@aarongiles.com>2007-12-17 15:19:59 +0000
commit7b77f1218624ea26dbb2efd85a19f795f5d4e02e (patch)
tree19209304095572b4fd61c2a2d6a5aa75c4e471ad /src/emu/cpu/i8051
parent3da7f476068b3ffef713218ba2fc1bd5030f2c38 (diff)
Initial checkin of MAME 0.121.mame0121
Diffstat (limited to 'src/emu/cpu/i8051')
-rw-r--r--src/emu/cpu/i8051/8051dasm.c1034
-rw-r--r--src/emu/cpu/i8051/i8051.c2583
-rw-r--r--src/emu/cpu/i8051/i8051.h157
-rw-r--r--src/emu/cpu/i8051/i8051ops.c960
4 files changed, 4734 insertions, 0 deletions
diff --git a/src/emu/cpu/i8051/8051dasm.c b/src/emu/cpu/i8051/8051dasm.c
new file mode 100644
index 00000000000..fa98d8aaab9
--- /dev/null
+++ b/src/emu/cpu/i8051/8051dasm.c
@@ -0,0 +1,1034 @@
+/*****************************************************************************
+ *
+ * i8051dasm.c
+ * Portable MCS-51 Family Emulator
+ *
+ * Chips in the family:
+ * 8051 Product Line (8031,8051,8751)
+ * 8052 Product Line (8032,8052,8752)
+ * 8054 Product Line (8054)
+ * 8058 Product Line (8058)
+ *
+ * Copyright (c) 2003 Steve Ellenoff, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * sellenoff@hotmail.com
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * This work is based on:
+ * #1) 'Intel(tm) MC51 Microcontroller Family Users Manual' and
+ * #2) 8051 simulator by Travis Marlatte
+ * #3) Portable UPI-41/8041/8741/8042/8742 emulator V0.1 by Juergen Buchmueller (MAME CORE)
+ *
+ *****************************************************************************
+ * Symbol Memory Name Tables borrowed from:
+ * D52 8052 Disassembler - Copyright (C) 1995-2002 by
+ * Jeffery L. Post
+ *****************************************************************************/
+
+#include "debugger.h"
+#include "i8051.h"
+
+#define SHOW_MEMORY_NAMES 1
+
+#ifdef SHOW_MEMORY_NAMES
+
+/*Display the memory address names for data & bit address access*/
+
+//SFR Names
+static const char sfr[128][7] = {
+ "p0", "sp", "dpl", "dph", /* 80 - 83 */
+ "adat", "85h", "86h", "pcon", /* 84 - 87 */
+ "tcon", "tmod", "tl0", "tl1", /* 88 - 8b */
+ "th0", "th1", "pwcm", "pwmp", /* 8a - 8f */
+ "p1", "91h", "92h", "93h", /* 90 - 93 */
+ "94h", "95h", "96h", "97h", /* 94 - 97 */
+ "scon", "sbuf", "9ah", "9bh", /* 98 - 9b */
+ "9ch", "9dh", "9eh", "9fh", /* 9c - 9f */
+ "p2", "0a1h", "0a2h", "0a3h", /* a0 - a3 */
+ "0a4h", "0a5h", "0a6h", "0a7h", /* a4 - a7 */
+ "ie", "cml0", "cml1", "cml2", /* a8 - ab */
+ "ctl0", "ctl1", "ctl2", "ctl3", /* ac - af */
+ "p3", "0b1h", "0b2h", "0b3h", /* b0 - b3 */
+ "0b4h", "0b5h", "0b6h", "0b7h", /* b4 - b7 */
+ "ip", "0b9h", "0bah", "0bbh", /* b8 - bb */
+ "0bch", "0bdh", "0beh", "0bfh", /* bc - bf */
+ "p4", "0c1h", "0c2h", "0c3h", /* c0 - c3 */
+ "p5", "adcon", "adch", "0c7h", /* c4 - c7 */
+ "t2con", "cmh0", "rcap2l", "rcap2h", /* c8 - cb */
+ "tl2", "th2", "cth2", "cth3", /* cc - cf */
+ "psw", "0d1h", "0d2h", "0d3h", /* d0 - d3 */
+ "0d4h", "0d5h", "0d6h", "0d7h", /* d4 - d7 */
+ "i2cfg", "s1sta", "s1dat", "s1adr", /* d8 - db */
+ "0dch", "0ddh", "0deh", "0dfh", /* dc - df */
+ "acc", "0e1h", "0e2h", "0e3h", /* e0 - e3 */
+ "0e4h", "0e5h", "0e6h", "0e7h", /* e4 - e7 */
+ "csr", "0e9h", "tm2con", "ctcon", /* e8 - eb */
+ "tml2", "tmh2", "ste", "rte", /* ec - ef */
+ "b", "0f1h", "0f2h", "0f3h", /* f0 - f3 */
+ "0f4h", "0f5h", "0f6h", "0f7h", /* f4 - f7 */
+ "i2sta", "0f9h", "0fah", "0fbh", /* f8 - fb */
+ "pwm0", "pwm1", "pwena", "t3" /* fc - ff */
+};
+
+//SFR Addressable bits
+static const char sfrbits[128][8] = {
+ "p0.0", "p0.1", "p0.2", "p0.3", /* 80 - 83 */
+ "p0.4", "p0.5", "p0.6", "p0.7", /* 84 - 87 */
+ "it0", "ie0", "it1", "ie1", /* 88 - 8b */
+ "tr0", "tf0", "tr1", "tf1", /* 8c - 8f */
+ "p1.0", "p1.1", "p1.2", "p1.3", /* 90 - 93 */
+ "p1.4", "p1.5", "p1.6", "p1.7", /* 94 - 97 */
+ "ri", "ti", "rb8", "tb8", /* 98 - 9b */
+ "ren", "sm2", "sm1", "sm0", /* 9c - 9f */
+ "p2.0", "p2.1", "p2.2", "p2.3", /* a0 - a3 */
+ "p2.4", "p2.5", "p2.6", "p2.7", /* a4 - a7 */
+ "ex0", "et0", "ex1", "et1", /* a8 - ab */
+ "es", "ie.5", "ie.6", "ea", /* ac - af */
+ "rxd", "txd", "int0", "int1", /* b0 - b3 */
+ "t0", "t1", "wr", "rd", /* b4 - b7 */
+ "px0", "pt0", "px1", "pt1", /* b8 - bb */
+ "ps", "ip.5", "ip.6", "ip.7", /* bc - bf */
+ "0c0h.0", "0c0h.1", "0c0h.2", "0c0h.3", /* c0 - c3 */
+ "0c0h.4", "0c0h.5", "0c0h.6", "0c0h.7", /* c4 - c7 */
+ "cprl2", "ct2", "tr2", "exen2", /* c8 - cb */
+ "tclk", "rclk", "exf2", "tf2", /* cc - cf */
+ "p", "psw.1", "ov", "rs0", /* d0 - d3 */
+ "rs1", "f0", "ac", "cy", /* d4 - d7 */
+ "ct0", "ct1", "i2cfg.2","i2cfg.3",/* d8 - db */
+ "tirun", "clrti", "mastrq", "slaven", /* dc - df */
+ "acc.0", "acc.1", "acc.2", "acc.3", /* e0 - e3 */
+ "acc.4", "acc.5", "acc.6", "acc.7", /* e4 - e7 */
+ "ibf", "obf", "idsm", "obfc", /* e8 - eb */
+ "ma0", "ma1", "mb0", "mb1", /* ec - ef */
+ "b.0", "b.1", "b.2", "b.3", /* f0 - f3 */
+ "b.4", "b.5", "b.6", "b.7", /* f4 - f7 */
+ "xstp", "xstr", "makstp", "makstr", /* f8 - fb */
+ "xactv", "xdata", "idle", "i2sta.7" /* fc - ff */
+} ;
+
+//Names for bit addressable memory
+static const char membits[128][6] = {
+ "20h.0", "20h.1", "20h.2", "20h.3",
+ "20h.4", "20h.5", "20h.6", "20h.7",
+ "21h.0", "21h.1", "21h.2", "21h.3",
+ "21h.4", "21h.5", "21h.6", "21h.7",
+ "22h.0", "22h.1", "22h.2", "22h.3",
+ "22h.4", "22h.5", "22h.6", "22h.7",
+ "23h.0", "23h.1", "23h.2", "23h.3",
+ "23h.4", "23h.5", "23h.6", "23h.7",
+ "24h.0", "24h.1", "24h.2", "24h.3",
+ "24h.4", "24h.5", "24h.6", "24h.7",
+ "25h.0", "25h.1", "25h.2", "25h.3",
+ "25h.4", "25h.5", "25h.6", "25h.7",
+ "26h.0", "26h.1", "26h.2", "26h.3",
+ "26h.4", "26h.5", "26h.6", "26h.7",
+ "27h.0", "27h.1", "27h.2", "27h.3",
+ "27h.4", "27h.5", "27h.6", "27h.7",
+ "28h.0", "28h.1", "28h.2", "28h.3",
+ "28h.4", "28h.5", "28h.6", "28h.7",
+ "29h.0", "29h.1", "29h.2", "29h.3",
+ "29h.4", "29h.5", "29h.6", "29h.7",
+ "2ah.0", "2ah.1", "2ah.2", "2ah.3",
+ "2ah.4", "2ah.5", "2ah.6", "2ah.7",
+ "2bh.0", "2bh.1", "2bh.2", "2bh.3",
+ "2bh.4", "2bh.5", "2bh.6", "2bh.7",
+ "2ch.0", "2ch.1", "2ch.2", "2ch.3",
+ "2ch.4", "2ch.5", "2ch.6", "2ch.7",
+ "2dh.0", "2dh.1", "2dh.2", "2dh.3",
+ "2dh.4", "2dh.5", "2dh.6", "2dh.7",
+ "2eh.0", "2eh.1", "2eh.2", "2eh.3",
+ "2eh.4", "2eh.5", "2eh.6", "2eh.7",
+ "2fh.0", "2fh.1", "2fh.2", "2fh.3",
+ "2fh.4", "2fh.5", "2fh.6", "2fh.7"
+};
+
+//Regiser Bank memory names
+static const char regbank[][6] = {
+ "rb0r0", "rb0r1", "rb0r2", "rb0r3",
+ "rb0r4", "rb0r5", "rb0r6", "rb0r7",
+ "rb1r0", "rb1r1", "rb1r2", "rb1r3",
+ "rb1r4", "rb1r5", "rb1r6", "rb1r7",
+ "rb2r0", "rb2r1", "rb2r2", "rb2r3",
+ "rb2r4", "rb2r5", "rb2r6", "rb2r7",
+ "rb3r0", "rb3r1", "rb3r2", "rb3r3",
+ "rb3r4", "rb3r5", "rb3r6", "rb3r7"
+};
+
+static const char *get_data_address( UINT8 arg )
+{
+ char *buffer = cpuintrf_temp_str();
+
+ if(arg < 0x80)
+ {
+ //Ram locations 0-0x1F are considered register access in 3 banks
+ if(arg < 0x1f)
+ sprintf(buffer,"%s",regbank[arg]);
+ else
+ sprintf(buffer,"$%02X",arg);
+ }
+ else
+ sprintf(buffer,"%s",sfr[arg-0x80]);
+ return buffer;
+}
+
+static const char *get_bit_address( UINT8 arg )
+{
+ char *buffer = cpuintrf_temp_str();
+
+ if(arg < 0x80)
+ {
+ //Bit address 0-7F can be referred to as 20.0, 20.1, to 20.7 for address 0, and 2f.0,2f.1 to 2f.7 for address 7f
+ if(arg < 0x7f)
+ sprintf(buffer,"%s",membits[arg]);
+ else
+ sprintf(buffer,"$%02X",arg);
+ }
+ else
+ sprintf(buffer,"%s",sfrbits[arg-0x80]);
+ return buffer;
+}
+
+#else
+
+/*Just display the actual memory address for data & bit address access*/
+
+static const char *get_data_address( UINT8 arg )
+{
+ char *buffer = cpuintrf_temp_str();
+ sprintf(buffer,"$%02X",arg);
+ return buffer;
+}
+
+static const char *get_bit_address( UINT8 arg )
+{
+ char *buffer = cpuintrf_temp_str();
+ sprintf(buffer,"$%02X",arg);
+ return buffer;
+}
+
+#endif
+
+
+unsigned i8051_dasm(char *dst, unsigned pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT32 flags = 0;
+ unsigned PC = pc;
+ const char *sym, *sym2;
+ UINT8 op, data;
+ UINT16 addr;
+ INT8 rel;
+
+ op = oprom[PC++ - pc];
+ switch( op )
+ {
+ //NOP
+ case 0x00: /* 1: 0000 0000 */
+ sprintf(dst, "nop");
+ break;
+
+ //AJMP code addr /* 1: aaa0 0001 */
+ case 0x01:
+ case 0x21:
+ case 0x41:
+ case 0x61:
+ case 0x81:
+ case 0xa1:
+ case 0xc1:
+ case 0xe1:
+ addr = opram[PC++ - pc];
+ addr|= (PC++ & 0xf800) | ((op & 0xe0) << 3);
+ sprintf(dst, "ajmp $%04X", addr);
+ break;
+
+ //LJMP code addr
+ case 0x02: /* 1: 0000 0010 */
+ addr = (opram[PC++ - pc]<<8) & 0xff00;
+ addr|= opram[PC++ - pc];
+ sprintf(dst, "ljmp $%04X", addr);
+ break;
+
+ //RR A
+ case 0x03: /* 1: 0000 0011 */
+ sprintf(dst, "rr a");
+ break;
+
+ //INC A
+ case 0x04: /* 1: 0000 0100 */
+ sprintf(dst, "inc a");
+ break;
+
+ //INC data addr
+ case 0x05: /* 1: 0000 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "inc %s", sym);
+ break;
+
+ //INC @R0/@R1 /* 1: 0000 011i */
+ case 0x06:
+ case 0x07:
+ sprintf(dst, "inc @r%d", op&1);
+ break;
+
+ //INC R0 to R7 /* 1: 0000 1rrr */
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ sprintf(dst, "inc r%d", op&7);
+ break;
+
+ //JBC bit addr, code addr
+ case 0x10: /* 1: 0001 0000 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ rel = opram[PC++ - pc];
+ sprintf(dst, "jbc %s,$%04X", sym, PC + rel);
+ break;
+
+ //ACALL code addr /* 1: aaa1 0001 */
+ case 0x11:
+ case 0x31:
+ case 0x51:
+ case 0x71:
+ case 0x91:
+ case 0xb1:
+ case 0xd1:
+ case 0xf1:
+ sprintf(dst, "acall $%04X", (PC & 0xf800) | ((op & 0xe0) << 3) | opram[PC - pc]);
+ PC++;
+ flags = DASMFLAG_STEP_OVER;
+ break;
+
+ //LCALL code addr
+ case 0x12: /* 1: 0001 0010 */
+ addr = (opram[PC++ - pc]<<8) & 0xff00;
+ addr|= opram[PC++ - pc];
+ sprintf(dst, "lcall $%04X", addr);
+ flags = DASMFLAG_STEP_OVER;
+ break;
+
+ //RRC A
+ case 0x13: /* 1: 0001 0011 */
+ sprintf(dst, "rrc a");
+ break;
+
+ //DEC A
+ case 0x14: /* 1: 0001 0100 */
+ sprintf(dst, "dec a");
+ break;
+
+ //DEC data addr
+ case 0x15: /* 1: 0001 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "dec %s", sym);
+ break;
+
+ //Unable to test
+ //DEC @R0/@R1 /* 1: 0001 011i */
+ case 0x16:
+ case 0x17:
+ sprintf(dst, "dec @r%d", op&1);
+ break;
+
+ //DEC R0 to R7 /* 1: 0001 1rrr */
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x1e:
+ case 0x1f:
+ sprintf(dst, "dec r%d", op&7);
+ break;
+
+ //JB bit addr, code addr
+ case 0x20: /* 1: 0010 0000 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ rel = opram[PC++ - pc];
+ sprintf(dst, "jb %s,$%04X", sym, (PC + rel));
+ break;
+
+ //RET
+ case 0x22: /* 1: 0010 0010 */
+ sprintf(dst, "ret");
+ flags = DASMFLAG_STEP_OUT;
+ break;
+
+ //RL A
+ case 0x23: /* 1: 0010 0011 */
+ sprintf(dst, "rl a");
+ break;
+
+ //ADD A, #data
+ case 0x24: /* 1: 0010 0100 */
+ sprintf(dst, "add a,#$%02X", opram[PC++ - pc]);
+ break;
+
+ //ADD A, data addr
+ case 0x25: /* 1: 0010 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "add a,%s", sym);
+ break;
+
+ //Unable to Test
+ //ADD A, @R0/@R1 /* 1: 0010 011i */
+ case 0x26:
+ case 0x27:
+ sprintf(dst, "add a,@r%d", op&1);
+ break;
+
+ //ADD A, R0 to R7 /* 1: 0010 1rrr */
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f:
+ sprintf(dst, "add a,r%d", op&7);
+ break;
+
+ //JNB bit addr, code addr
+ case 0x30: /* 1: 0011 0000 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ rel = opram[PC++ - pc];
+ sprintf(dst, "jnb %s,$%04X", sym, (PC + rel));
+ break;
+
+ //RETI
+ case 0x32: /* 1: 0011 0010 */
+ sprintf(dst, "reti");
+ flags = DASMFLAG_STEP_OUT;
+ break;
+
+ //RLC A
+ case 0x33: /* 1: 0011 0011 */
+ sprintf(dst, "rlc a");
+ break;
+
+ //ADDC A, #data
+ case 0x34: /* 1: 0011 0100 */
+ sprintf(dst, "addc a,#$%02X", opram[PC++ - pc]);
+ break;
+
+ //ADDC A, data addr
+ case 0x35: /* 1: 0011 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "addc a,%s", sym);
+ break;
+
+ //ADDC A, @R0/@R1 /* 1: 0011 011i */
+ case 0x36:
+ case 0x37:
+ sprintf(dst, "addc a,@r%d", op&1);
+ break;
+
+ //ADDC A, R0 to R7 /* 1: 0011 1rrr */
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f:
+ sprintf(dst, "addc a,r%d", op&7);
+ break;
+
+ //JC code addr
+ case 0x40: /* 1: 0100 0000 */
+ rel = opram[PC++ - pc];
+ sprintf(dst, "jc $%04X", PC + rel);
+ break;
+
+ //ORL data addr, A
+ case 0x42: /* 1: 0100 0010 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "orl %s,a", sym);
+ break;
+
+ //ORL data addr, #data
+ case 0x43: /* 1: 0100 0011 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "orl %s,#$%02X", sym, opram[PC++ - pc]);
+ break;
+
+ //Unable to Test
+ //ORL A, #data
+ case 0x44: /* 1: 0100 0100 */
+ sprintf(dst, "orl a,#$%02X", opram[PC++ - pc]);
+ break;
+
+ //ORL A, data addr
+ case 0x45: /* 1: 0100 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "orl a,%s", sym);
+ break;
+
+ //ORL A, @RO/@R1 /* 1: 0100 011i */
+ case 0x46:
+ case 0x47:
+ sprintf(dst, "orl a,@r%d", op&1);
+ break;
+
+ //ORL A, RO to R7 /* 1: 0100 1rrr */
+ case 0x48:
+ case 0x49:
+ case 0x4a:
+ case 0x4b:
+ case 0x4c:
+ case 0x4d:
+ case 0x4e:
+ case 0x4f:
+ sprintf(dst, "orl a,r%d", op&7);
+ break;
+
+ //JNC code addr
+ case 0x50: /* 1: 0101 0000 */
+ rel = opram[PC++ - pc];
+ sprintf(dst, "jnc $%04X", PC + rel);
+ break;
+
+ //Unable to test
+ //ANL data addr, A
+ case 0x52: /* 1: 0101 0010 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "anl %s,a", sym);
+ break;
+
+ //Unable to test
+ //ANL data addr, #data
+ case 0x53: /* 1: 0101 0011 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "anl %s,#$%02X", sym, opram[PC++ - pc]);
+ break;
+
+ //ANL A, #data
+ case 0x54: /* 1: 0101 0100 */
+ sprintf(dst, "anl a,#$%02X", opram[PC++ - pc]);
+ break;
+
+ //ANL A, data addr
+ case 0x55: /* 1: 0101 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "anl a,%s", sym);
+ break;
+
+ //Unable to test
+ //ANL A, @RO/@R1 /* 1: 0101 011i */
+ case 0x56:
+ case 0x57:
+ sprintf(dst, "anl a,@r%d", op&1);
+ break;
+
+ //ANL A, RO to R7 /* 1: 0101 1rrr */
+ case 0x58:
+ case 0x59:
+ case 0x5a:
+ case 0x5b:
+ case 0x5c:
+ case 0x5d:
+ case 0x5e:
+ case 0x5f:
+ sprintf(dst, "anl a,r%d", op&7);
+ break;
+
+ //JZ code addr
+ case 0x60: /* 1: 0110 0000 */
+ rel = opram[PC++ - pc];
+ sprintf(dst, "jz $%04X", PC + rel);
+ break;
+
+ //Unable to test
+ //XRL data addr, A
+ case 0x62: /* 1: 0110 0010 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "xrl %s,a", sym);
+ break;
+
+ //XRL data addr, #data
+ case 0x63: /* 1: 0110 0011 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "xrl %s,#$%02X", sym, opram[PC++ - pc]);
+ break;
+
+ //XRL A, #data
+ case 0x64: /* 1: 0110 0100 */
+ sprintf(dst, "xrl a,#$%02X", opram[PC++ - pc]);
+ break;
+
+ //XRL A, data addr
+ case 0x65: /* 1: 0110 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "xrl a,%s", sym);
+ break;
+
+ //Unable to test
+ //XRL A, @R0/@R1 /* 1: 0110 011i */
+ case 0x66:
+ case 0x67:
+ sprintf(dst, "xrl a,@r%d", op&1);
+ break;
+
+ //XRL A, R0 to R7 /* 1: 0110 1rrr */
+ case 0x68:
+ case 0x69:
+ case 0x6a:
+ case 0x6b:
+ case 0x6c:
+ case 0x6d:
+ case 0x6e:
+ case 0x6f:
+ sprintf(dst, "xrl a,r%d", op&7);
+ break;
+
+ //JNZ code addr
+ case 0x70: /* 1: 0111 0000 */
+ rel = opram[PC++ - pc];
+ sprintf(dst, "jnz $%04X", PC + rel);
+ break;
+
+ //Unable to test
+ //ORL C, bit addr
+ case 0x72: /* 1: 0111 0010 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ sprintf(dst, "orl c,%s", sym);
+ break;
+
+ //Unable to test
+ //JMP @A+DPTR
+ case 0x73: /* 1: 0111 0011 */
+ sprintf(dst, "jmp @a+dptr");
+ break;
+
+ //MOV A, #data
+ case 0x74: /* 1: 0111 0100 */
+ sprintf(dst, "mov a,#$%02X", opram[PC++ - pc]);
+ break;
+
+ //MOV data addr, #data
+ case 0x75: /* 1: 0111 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "mov %s,#$%02X", sym, opram[PC++ - pc]);
+ break;
+
+ //Unable to test
+ //MOV @R0/@R1, #data /* 1: 0111 011i */
+ case 0x76:
+ case 0x77:
+ sprintf(dst, "mov @r%d,#$%02X", op&1, opram[PC++ - pc]);
+ break;
+
+ //MOV R0 to R7, #data /* 1: 0111 1rrr */
+ case 0x78:
+ case 0x79:
+ case 0x7a:
+ case 0x7b:
+ case 0x7c:
+ case 0x7d:
+ case 0x7e:
+ case 0x7f:
+ sprintf(dst, "mov r%d,#$%02X", (op & 7), opram[PC++ - pc]);
+ break;
+
+ //SJMP code addr
+ case 0x80: /* 1: 1000 0000 */
+ rel = opram[PC++ - pc];
+ sprintf(dst, "sjmp $%04X", PC + rel);
+ break;
+
+ //ANL C, bit addr
+ case 0x82: /* 1: 1000 0010 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ sprintf(dst, "anl c,%s", sym);
+ break;
+
+ //MOVC A, @A + PC
+ case 0x83: /* 1: 1000 0011 */
+ sprintf(dst, "movc a,@a+pc");
+ break;
+
+ //DIV AB
+ case 0x84: /* 1: 1000 0100 */
+ sprintf(dst, "div ab");
+ break;
+
+ //MOV data addr, data addr (Note: 1st address is src, 2nd is dst, but the mov command works as mov dst,src)
+ case 0x85: /* 1: 1000 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sym2 = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "mov %s,%s", sym2, sym);
+ break;
+
+ //Unable to test
+ //MOV data addr, @R0/@R1/* 1: 1000 011i */
+ case 0x86:
+ case 0x87:
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "mov %s,@r%d", sym, op&1);
+ break;
+
+ //MOV data addr,R0 to R7/* 1: 1000 1rrr */
+ case 0x88:
+ case 0x89:
+ case 0x8a:
+ case 0x8b:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ case 0x8f:
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "mov %s,r%d", sym, op&7);
+ break;
+
+ //MOV DPTR, #data16
+ case 0x90: /* 1: 1001 0000 */
+ addr = (opram[PC++ - pc]<<8) & 0xff00;
+ addr|= opram[PC++ - pc];
+ sprintf(dst, "mov dptr,#$%04X", addr);
+ break;
+
+ //MOV bit addr, C
+ case 0x92: /* 1: 1001 0010 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ sprintf(dst, "mov %s,c", sym);
+ break;
+
+ //MOVC A, @A + DPTR
+ case 0x93: /* 1: 1001 0011 */
+ sprintf(dst, "movc a,@a+dptr");
+ break;
+
+ //SUBB A, #data
+ case 0x94: /* 1: 1001 0100 */
+ sprintf(dst, "subb a,#$%02X", opram[PC++ - pc]);
+ break;
+
+ //SUBB A, data addr
+ case 0x95: /* 1: 1001 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "subb a,%s", sym);
+ break;
+
+ //Unable to test
+ //SUBB A, @R0/@R1 /* 1: 1001 011i */
+ case 0x96:
+ case 0x97:
+ sprintf(dst, "subb a,@r%d", op&1);
+ break;
+
+ //SUBB A, R0 to R7 /* 1: 1001 1rrr */
+ case 0x98:
+ case 0x99:
+ case 0x9a:
+ case 0x9b:
+ case 0x9c:
+ case 0x9d:
+ case 0x9e:
+ case 0x9f:
+ sprintf(dst, "subb a,r%d", op&7);
+ break;
+
+ //Unable to test
+ //ORL C, /bit addr
+ case 0xa0: /* 1: 1010 0000 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ sprintf(dst, "orl c,/%s", sym);
+ break;
+
+ //MOV C, bit addr
+ case 0xa2: /* 1: 1010 0010 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ sprintf(dst, "mov c,%s", sym);
+ break;
+
+ //INC DPTR
+ case 0xa3: /* 1: 1010 0011 */
+ sprintf(dst, "inc dptr");
+ break;
+
+ //MUL AB
+ case 0xa4: /* 1: 1010 0100 */
+ sprintf(dst, "mul ab");
+ break;
+
+ //reserved
+ case 0xa5: /* 1: 1010 0101 */
+ sprintf(dst, "ill/rsv");
+ break;
+
+ //Unable to test
+ //MOV @R0/@R1, data addr /* 1: 1010 011i */
+ case 0xa6:
+ case 0xa7:
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "mov @r%d,%s", op&1, sym);
+ break;
+
+ //MOV R0 to R7, data addr /* 1: 1010 1rrr */
+ case 0xa8:
+ case 0xa9:
+ case 0xaa:
+ case 0xab:
+ case 0xac:
+ case 0xad:
+ case 0xae:
+ case 0xaf:
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "mov r%d,%s", op&7, sym);
+ break;
+
+ //ANL C,/bit addr
+ case 0xb0: /* 1: 1011 0000 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ sprintf(dst, "anl c,/%s", sym);
+ break;
+
+ //CPL bit addr
+ case 0xb2: /* 1: 1011 0010 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ sprintf(dst, "cpl %s", sym);
+ break;
+
+ //Unable to test
+ //CPL C
+ case 0xb3: /* 1: 1011 0011 */
+ sprintf(dst, "cpl c");
+ break;
+
+ //CJNE A, #data, code addr
+ case 0xb4: /* 1: 1011 0100 */
+ data = opram[PC++ - pc];
+ rel = opram[PC++ - pc];
+ sprintf(dst, "cjne a,#$%02X,$%04X", data, PC + rel);
+ break;
+
+ //CJNE A, data addr, code addr
+ case 0xb5: /* 1: 1011 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ rel = opram[PC++ - pc];
+ sprintf(dst, "cjne a,%s,$%04X", sym, PC + rel);
+ break;
+
+ //Unable to test
+ //CJNE @R0/@R1, #data, code addr /* 1: 1011 011i */
+ case 0xb6:
+ case 0xb7:
+ data = opram[PC++ - pc];
+ rel = opram[PC++ - pc];
+ sprintf(dst, "cjne @r%d,#$%02X,$%04X", op&1, data, PC + rel);
+ break;
+
+ //CJNE R0 to R7, #data, code addr/* 1: 1011 1rrr */
+ case 0xb8:
+ case 0xb9:
+ case 0xba:
+ case 0xbb:
+ case 0xbc:
+ case 0xbd:
+ case 0xbe:
+ case 0xbf:
+ data = opram[PC++ - pc];
+ rel = opram[PC++ - pc];
+ sprintf(dst, "cjne r%d,#$%02X,$%04X", op&7, data, PC + rel);
+ break;
+
+ //PUSH data addr
+ case 0xc0: /* 1: 1100 0000 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "push %s", sym);
+ break;
+
+ //CLR bit addr
+ case 0xc2: /* 1: 1100 0010 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ sprintf(dst, "clr %s", sym);
+ break;
+
+ //CLR C
+ case 0xc3: /* 1: 1100 0011 */
+ sprintf(dst, "clr c");
+ break;
+
+ //SWAP A
+ case 0xc4: /* 1: 1100 0100 */
+ sprintf(dst, "swap a");
+ break;
+
+ //XCH A, data addr
+ case 0xc5: /* 1: 1100 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "xch a,%s", sym);
+ break;
+
+ //XCH A, @RO/@R1 /* 1: 1100 011i */
+ case 0xc6:
+ case 0xc7:
+ sprintf(dst, "xch a,@r%d", op&1);
+ break;
+
+ //XCH A, RO to R7 /* 1: 1100 1rrr */
+ case 0xc8:
+ case 0xc9:
+ case 0xca:
+ case 0xcb:
+ case 0xcc:
+ case 0xcd:
+ case 0xce:
+ case 0xcf:
+ sprintf(dst, "xch a,r%d", op&7);
+ break;
+
+ //POP data addr
+ case 0xd0: /* 1: 1101 0000 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "pop %s", sym);
+ break;
+
+ //SETB bit addr
+ case 0xd2: /* 1: 1101 0010 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ sprintf(dst, "setb %s", sym);
+ break;
+
+ //SETB C
+ case 0xd3: /* 1: 1101 0011 */
+ sprintf(dst, "setb c");
+ break;
+
+ //Unable to test
+ //DA A
+ case 0xd4: /* 1: 1101 0100 */
+ sprintf(dst, "da a");
+ break;
+
+ //DJNZ data addr, code addr
+ case 0xd5: /* 1: 1101 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ rel = opram[PC++ - pc];
+ sprintf(dst, "djnz %s,$%04X", sym, PC + rel);
+ flags = DASMFLAG_STEP_OVER;
+ break;
+
+ //XCHD A, @R0/@R1 /* 1: 1101 011i */
+ case 0xd6:
+ case 0xd7:
+ sprintf(dst, "xchd a,@r%d", op&1);
+ break;
+
+ //DJNZ R0 to R7,code addr /* 1: 1101 1rrr */
+ case 0xd8:
+ case 0xd9:
+ case 0xda:
+ case 0xdb:
+ case 0xdc:
+ case 0xdd:
+ case 0xde:
+ case 0xdf:
+ rel = opram[PC++ - pc];
+ sprintf(dst, "djnz r%d,$%04X", op&7, (PC + rel));
+ flags = DASMFLAG_STEP_OVER;
+ break;
+
+ //MOVX A,@DPTR
+ case 0xe0: /* 1: 1110 0000 */
+ sprintf(dst, "movx a,@dptr");
+ break;
+
+ //Unable to test
+ //MOVX A, @R0/@R1 /* 1: 1110 001i */
+ case 0xe2:
+ case 0xe3:
+ sprintf(dst, "movx a,@r%d", op&1);
+ break;
+
+ //CLR A
+ case 0xe4: /* 1: 1110 0100 */
+ sprintf(dst, "clr a");
+ break;
+
+ //MOV A, data addr
+ case 0xe5: /* 1: 1110 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "mov a,%s", sym);
+ break;
+
+ //Unable to test
+ //MOV A,@RO/@R1 /* 1: 1110 011i */
+ case 0xe6:
+ case 0xe7:
+ sprintf(dst, "mov a,@r%d", op&1);
+ break;
+
+ //MOV A,R0 to R7 /* 1: 1110 1rrr */
+ case 0xe8:
+ case 0xe9:
+ case 0xea:
+ case 0xeb:
+ case 0xec:
+ case 0xed:
+ case 0xee:
+ case 0xef:
+ sprintf(dst, "mov a,r%d", op&7);
+ break;
+
+ //MOVX @DPTR,A
+ case 0xf0: /* 1: 1111 0000 */
+ sprintf(dst, "movx @dptr,a");
+ break;
+
+ //Unable to test
+ //MOVX @R0/@R1,A /* 1: 1111 001i */
+ case 0xf2:
+ case 0xf3:
+ sprintf(dst, "movx @r%d,a", op&1);
+ break;
+
+ //CPL A
+ case 0xf4: /* 1: 1111 0100 */
+ sprintf(dst, "cpl a");
+ break;
+
+ //MOV data addr, A
+ case 0xf5: /* 1: 1111 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "mov %s,a", sym);
+ break;
+
+ //MOV @R0/@R1, A /* 1: 1111 011i */
+ case 0xf6:
+ case 0xf7:
+ sprintf(dst, "mov @r%d,a", op&1);
+ break;
+
+ //MOV R0 to R7, A /* 1: 1111 1rrr */
+ case 0xf8:
+ case 0xf9:
+ case 0xfa:
+ case 0xfb:
+ case 0xfc:
+ case 0xfd:
+ case 0xfe:
+ case 0xff:
+ sprintf(dst, "mov r%d,a", op&7);
+ break;
+
+ default:
+ sprintf(dst, "illegal");
+ }
+ return (PC - pc) | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/i8051/i8051.c b/src/emu/cpu/i8051/i8051.c
new file mode 100644
index 00000000000..3231cb69ffc
--- /dev/null
+++ b/src/emu/cpu/i8051/i8051.c
@@ -0,0 +1,2583 @@
+/*****************************************************************************
+ *
+ * i8051.c
+ * Portable MCS-51 Family Emulator
+ *
+ * Chips in the family:
+ * 8051 Product Line (8031,8051,8751)
+ * 8052 Product Line (8032,8052,8752)
+ * 8054 Product Line (8054)
+ * 8058 Product Line (8058)
+ *
+ * Copyright (c) 2003 Steve Ellenoff, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * sellenoff@hotmail.com
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * This work is based on:
+ * #1) 'Intel(tm) MC51 Microcontroller Family Users Manual' and
+ * #2) 8051 simulator by Travis Marlatte
+ * #3) Portable UPI-41/8041/8741/8042/8742 emulator V0.1 by Juergen Buchmueller (MAME CORE)
+ *
+ *****************************************************************************/
+
+/******************************************************************************
+ * Notes:
+ * *Important*: Internal ROM needs to be treated the same as external rom by the programmer
+ * creating the driver (ie, use standard cpu rom region)
+ *
+ * The term cycles is used here to really refer to clock oscilations, because 1 machine cycle
+ * actually takes 12 oscilations.
+ *
+ * Read/Write/Modify Instruction -
+ * Data is read from the Port Latch (not the Port Pin!), possibly modified, and
+ * written back to (the pin? and) the latch!
+ *
+ * The following all perform this on a port address..
+ * (anl, orl, xrl, jbc, cpl, inc, dec, djnz, mov px.y,c, clr px.y, setb px.y)
+ *
+ * Serial UART emulation is not really accurate, but faked enough to work as far as i can tell
+ *
+ * August 27,2003: Currently support for only 8031/8051/8751 chips (ie 128 RAM)
+ * October 14,2003: Added initial support for the 8752 (ie 256 RAM)
+ * October 22,2003: Full support for the 8752 (ie 256 RAM)
+ * July 28,2004: Fixed MOVX command and added External Ram Paging Support
+ * July 31,2004: Added Serial Mode 0 Support & Fixed Interrupt Flags for Serial Port
+ *
+ * Todo: Full Timer support (all modes)
+ *
+ * NOW Implemented: RAM paging using hardware configured addressing...
+ * (July 28,2004) the "MOVX a,@R0/R1" and "MOVX @R0/R1,a" commands can use any of the other ports
+ * to output a page offset into external ram, but it is totally based on the hardware setup.
+ *
+ * Timing needs to be implemented via MAME timers perhaps?
+ *
+ *****************************************************************************/
+
+#include "debugger.h"
+#include "i8051.h"
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+
+//Prototypes
+INLINE void push_pc(void);
+INLINE void pop_pc(void);
+INLINE void set_parity(void);
+INLINE void do_add_flags(UINT8 a, UINT8 data, UINT8 c);
+INLINE void do_sub_flags(UINT8 a, UINT8 data, UINT8 c);
+INLINE UINT8 check_interrupts(void);
+INLINE void update_timer(int cyc);
+INLINE void update_serial(int cyc);
+INLINE void serial_transmit(UINT8 data);
+static READ8_HANDLER(internal_ram_read);
+static WRITE8_HANDLER(internal_ram_write);
+static READ8_HANDLER(internal_ram_iread);
+static READ32_HANDLER(external_ram_iaddr);
+static WRITE8_HANDLER(internal_ram_iwrite);
+static READ8_HANDLER(sfr_read);
+static WRITE8_HANDLER(sfr_write);
+static WRITE8_HANDLER( bit_address_w );
+static READ8_HANDLER( bit_address_r );
+
+#if (HAS_I8052 || HAS_I8752)
+static READ8_HANDLER(i8052_internal_ram_iread);
+static WRITE8_HANDLER(i8052_internal_ram_iwrite);
+#endif
+//
+
+typedef struct {
+ UINT8 timerbaud; //Flag set if timer overflow is controlling baud
+ UINT8 sending; //Flag set when uart is sending
+ UINT8 data_out; //Data to send out
+ UINT8 bits_to_send; //How many bits left to send when transmitting out the serial port
+ UINT8 bitcycles; //# of bitcycles passed since last bit was sent
+} I8051_UART;
+
+typedef struct {
+
+ //Internal stuff
+ UINT16 ppc; //previous pc
+ UINT16 pc; //current pc
+ UINT16 subtype; //specific version of the cpu, ie 8031, or 8051 for example
+ UINT8 cur_irq; //Holds value of any current IRQ being serviced
+ UINT8 irq_priority; //Holds value of the current IRQ Priority Level
+ UINT8 rwm; //Signals that the current instruction is a read/write/modify instruction
+ int prev_used_cycles; //Track previous # of used cycles
+ int last_int0; //Store state of int0
+ int last_int1; //Store state of int1
+ UINT8 int_vec; //Pending Interrupt Vector
+ int priority_request; //Priority level of incoming new irq
+ //SFR Registers (Note: Appear in order as they do in memory)
+ UINT8 po; //Port 0
+ UINT8 sp; //Stack Pointer
+ UINT8 dpl; //Data Pointer (DPTR) (Hi bit)
+ UINT8 dph; //Data Pointer (DPTR) (Lo bit)
+ UINT8 pcon; //Power Mode Control
+ UINT8 tcon; //Timer/Counter Control
+ UINT8 tmod; //Timer/Counter Mode Control
+ UINT8 tl0; //Timer 0 Lo
+ UINT8 tl1; //Timer 1 Lo
+ UINT8 th0; //Timer 0 Hi
+ UINT8 th1; //Timer 1 Hi
+ UINT8 p1; //Port 1
+ UINT8 scon; //Serial Control
+ UINT8 sbuf; //Serial Data Buffer
+ UINT8 p2; //Port 2
+ UINT8 ie; //Interrupt Enable
+ UINT8 p3; //Port 3
+ UINT8 ip; //Interrupt Priority
+ //8052 Only registers
+ #if (HAS_I8052 || HAS_I8752)
+ UINT8 t2con; //Timer/Counter 2 Control
+ UINT8 rcap2l; //Timer/Counter 2 Capture Register Lo
+ UINT8 rcap2h; //Timer/Counter 2 Capture Register Hi
+ UINT8 tl2; //Timer 2 Lo
+ UINT8 th2; //Timer 2 Hi
+ #endif
+ UINT8 psw; //Program Status Word
+ UINT8 acc; //Accumulator
+ UINT8 b; //Register B
+
+ //Internal Ram
+ UINT8 IntRam[0xff+1]; //Max 256 Bytes of Internal RAM (8031/51 have 128, 8032/52 have 256)
+
+ //Interrupt Callback
+ int (*irq_callback)(int irqline);
+
+ //Serial Port TX/RX Call backs
+ void (*serial_tx_callback)(int data); //Call back funciton when sending data out of serial port
+ int (*serial_rx_callback)(void); //Call back function to retrieve data when receiving serial port data
+
+ //Internal Indirect Read/Write Handlers
+ READ8_HANDLER((*iram_iread));
+ WRITE8_HANDLER((*iram_iwrite));
+
+ //External Ram Address Callback for generating the hardware specific access to external ram
+ READ32_HANDLER((*eram_iaddr_callback));
+
+} I8051;
+
+int i8051_icount;
+
+static I8051 i8051;
+static I8051_UART uart;
+
+//Hold callback functions so they can be set by caller (before the cpu reset)
+static void (*hold_serial_tx_callback)(int data);
+static int (*hold_serial_rx_callback)(void);
+static READ32_HANDLER((*hold_eram_iaddr_callback));
+
+/*Short cuts*/
+
+/***************************************************************
+ * Read Opcode/Opcode Arguments from Program Code
+ ***************************************************************/
+#define ROP(pc) cpu_readop(pc)
+#define ROP_ARG(pc) cpu_readop_arg(pc)
+/*****************************************************************************
+ * Read a byte from External Code Memory (Usually Program Rom(s) Space)
+ *****************************************************************************
+ This area is mapped from 0-FFFF internally (64K) */
+#define CODEMEM_R(a) (UINT8)program_read_byte_8(a)
+/*****************************************************************************
+ * Read/Write a byte from/to External Data Memory (Usually RAM or other I/O)
+ *****************************************************************************
+ This area is *ALSO* mapped from 0-FFFF internally (64K)
+ ** HOWEVER **
+ We *FORCE* the address space into the range 10000-1FFFF to allow both
+ Code Memory and Data Memory to be pyshically separate while mapped @ the same
+ addresses, w/o any contention.
+ As far as the 8051 program code which is executing knows data memory still lives
+ in the 0-FFFF range.*/
+#define DATAMEM_R(a) (UINT8)data_read_byte_8(a)
+#define DATAMEM_W(a,v) data_write_byte_8(a,v)
+
+/***************************************************************
+ * Read/Write a byte from/to the Internal RAM
+ ***************************************************************/
+#define IRAM_R(a) internal_ram_read(a)
+#define IRAM_W(a,v) internal_ram_write(a,v)
+/***************************************************************
+ * Read/Write a byte from/to the Internal RAM indirectly (called from indirect addressing)
+ ***************************************************************/
+#define IRAM_IR(a) internal_ram_iread(a)
+#define IRAM_IW(a,v) internal_ram_iwrite(a,v)
+/***************************************************************
+ * Form an Address to Read/Write to External RAM indirectly (called from indirect addressing)
+ ***************************************************************/
+#define ERAM_ADDR(a,m) external_ram_iaddr(a,m)
+/***************************************************************
+ * Read/Write a byte from/to the SFR Registers
+ ***************************************************************/
+#define SFR_R(a) sfr_read(a)
+#define SFR_W(a,v) sfr_write(a,v)
+/***************************************************************
+ * Read/Write a bit from Bit Addressable Memory
+ ***************************************************************/
+#define BIT_R(a) bit_address_r(a)
+#define BIT_W(a,v) bit_address_w(a,v)
+/***************************************************************
+ * Input/Output a byte from given I/O port
+ ***************************************************************/
+#define IN(port) ((UINT8)io_read_byte(port))
+#define OUT(port,value) io_write_byte(port,value)
+/***************************************************************
+ * Access the 4 banks of R registers (R0...R7)
+ ***************************************************************/
+#define R_R(n) i8051.IntRam[(GET_RS*8)+(n)]
+/***************************************************************
+ * Easy macro for working with 16 bit DPTR
+ ***************************************************************/
+#define R_DPTR ((R_DPH<<8) | R_DPL)
+#define DPTR_W(n) SFR_W(DPH, ((n)>>8)&0xff);\
+ SFR_W(DPL, ((n)&0xff));
+/***************************************************************
+ * Easy macros for Setting Flags
+ ***************************************************************/
+/*PSW Flags*/
+#define SET_CY(n) R_PSW = (R_PSW & 0x7f) | (n<<7); //Carry Flag
+#define SET_AC(n) R_PSW = (R_PSW & 0xbf) | (n<<6); //Aux.Carry Flag
+#define SET_FO(n) R_PSW = (R_PSW & 0xdf) | (n<<5); //User Flag
+#define SET_RS(n) R_PSW = (R_PSW & 0xe7) | (n<<3); //R Bank Select
+#define SET_OV(n) R_PSW = (R_PSW & 0xfb) | (n<<2); //Overflow Flag
+#define SET_P(n) R_PSW = (R_PSW & 0xfe) | (n<<0); //Parity Flag
+/*IE Flags*/
+#define SET_EA(n) R_IE = (R_IE & 0x7f) | (n<<7); //Global Interrupt Enable/Disable
+#if (HAS_I8052 || HAS_I8752)
+ #define SET_ET2(n) R_IE = (R_IE & 0xdf) | (n<<5); //Timer 2 Interrupt Enable/Disable
+#endif
+#define SET_ES(n) R_IE = (R_IE & 0xef) | (n<<4); //Serial Interrupt Enable/Disable
+#define SET_ET1(n) R_IE = (R_IE & 0xf7) | (n<<3); //Timer 1 Interrupt Enable/Disable
+#define SET_EX1(n) R_IE = (R_IE & 0xfb) | (n<<2); //External Int 1 Interrupt Enable/Disable
+#define SET_ET0(n) R_IE = (R_IE & 0xfd) | (n<<1); //Timer 0 Interrupt Enable/Disable
+#define SET_EX0(n) R_IE = (R_IE & 0xfe) | (n<<0); //External Int 0 Interrupt Enable/Disable
+/*IP Flags*/
+#if (HAS_I8052 || HAS_I8752)
+ #define SET_PT2(n) R_IP = (R_IP & 0xdf) | (n<<5); //Set Timer 2 Priority Level
+#endif
+#define SET_PS0(n) R_IP = (R_IP & 0xef) | (n<<4); //Set Serial Priority Level
+#define SET_PT1(n) R_IP = (R_IP & 0xf7) | (n<<3); //Set Timer 1 Priority Level
+#define SET_PX1(n) R_IP = (R_IP & 0xfb) | (n<<2); //Set External Int 1 Priority Level
+#define SET_PT0(n) R_IP = (R_IP & 0xfd) | (n<<1); //Set Timer 0 Priority Level
+#define SET_PX0(n) R_IP = (R_IP & 0xfe) | (n<<0); //Set External Int 0 Priority Level
+/*TCON Flags*/
+#define SET_TF1(n) R_TCON = (R_TCON & 0x7f) | (n<<7); //Indicated Timer 1 Overflow Int Triggered
+#define SET_TR1(n) R_TCON = (R_TCON & 0xbf) | (n<<6); //IndicateS Timer 1 is running
+#define SET_TF0(n) R_TCON = (R_TCON & 0xdf) | (n<<5); //Indicated Timer 0 Overflow Int Triggered
+#define SET_TR0(n) R_TCON = (R_TCON & 0xef) | (n<<4); //IndicateS Timer 0 is running
+#define SET_IE1(n) R_TCON = (R_TCON & 0xf7) | (n<<3); //Indicated External Int 1 Triggered
+#define SET_IT1(n) R_TCON = (R_TCON & 0xfb) | (n<<2); //Indicates how External Int 1 is Triggered
+#define SET_IE0(n) R_TCON = (R_TCON & 0xfd) | (n<<1); //Indicated External Int 0 Triggered
+#define SET_IT0(n) R_TCON = (R_TCON & 0xfe) | (n<<0); //Indicates how External Int 0 is Triggered
+/*SCON Flags*/
+#define SET_SM0(n) R_SCON = (R_SCON & 0x7f) | (n<<7); //Sets Serial Port Mode
+#define SET_SM1(n) R_SCON = (R_SCON & 0xbf) | (n<<6); //Sets Serial Port Mode
+#define SET_SM2(n) R_SCON = (R_SCON & 0xdf) | (n<<5); //Sets Serial Port Mode (Multiprocesser mode)
+#define SET_REN(n) R_SCON = (R_SCON & 0xef) | (n<<4); //Sets Serial Port Receive Enable
+#define SET_TB8(n) R_SCON = (R_SCON & 0xf7) | (n<<3); //Transmit 8th Bit
+#define SET_RB8(n) R_SCON = (R_SCON & 0xfb) | (n<<2); //Receive 8th Bit
+#define SET_TI(n) R_SCON = (R_SCON & 0xfd) | (n<<1); //Indicates Transmit Interrupt Occurred
+#define SET_RI(n) R_SCON = (R_SCON & 0xfe) | (n<<0); //Indicates Receive Interrupt Occurred
+/*TMOD Flags*/
+#define SET_GATE1(n) R_TMOD = (R_TMOD & 0x7f) | (n<<7); //Timer 1 Gate Mode
+#define SET_CT1(n) R_TMOD = (R_TMOD & 0xbf) | (n<<6); //Timer 1 Counter Mode
+#define SET_M1_1(n) R_TMOD = (R_TMOD & 0xdf) | (n<<5); //Timer 1 Timer Mode Bit 1
+#define SET_M1_0(n) R_TMOD = (R_TMOD & 0xef) | (n<<4); //Timer 1 Timer Mode Bit 0
+#define SET_GATE0(n) R_TMOD = (R_TMOD & 0xf7) | (n<<3); //Timer 0 Gate Mode
+#define SET_CT0(n) R_TMOD = (R_TMOD & 0xfb) | (n<<2); //Timer 0 Counter Mode
+#define SET_M0_1(n) R_TMOD = (R_TMOD & 0xfd) | (n<<1); //Timer 0 Timer Mode Bit 1
+#define SET_M0_0(n) R_TMOD = (R_TMOD & 0xfe) | (n<<0); //Timer 0 Timer Mode Bit 0
+
+#if (HAS_I8052 || HAS_I8752)
+ /*T2CON Flags*/
+ #define SET_TF2(n) R_T2CON = (R_T2CON & 0x7f) | (n<<7); //Indicated Timer 2 Overflow Int Triggered
+ #define SET_EXF2(n) R_T2CON = (R_T2CON & 0xbf) | (n<<6); //Indicates Timer 2 External Flag
+ #define SET_RCLK(n) R_T2CON = (R_T2CON & 0xdf) | (n<<5); //Receive Clock
+ #define SET_TCLK(n) R_T2CON = (R_T2CON & 0xef) | (n<<4); //Transmit Clock
+ #define SET_EXEN2(n) R_T2CON = (R_T2CON & 0xf7) | (n<<3); //Timer 2 External Interrupt Enable
+ #define SET_TR2(n) R_T2CON = (R_T2CON & 0xfb) | (n<<2); //Indicates Timer 2 is running
+ #define SET_CT2(n) R_T2CON = (R_T2CON & 0xfd) | (n<<1); //Sets Timer 2 Counter/Timer Mode
+ #define SET_CP(n) R_T2CON = (R_T2CON & 0xfe) | (n<<0); //Sets Timer 2 Capture/Reload Mode
+#endif
+
+/***************************************************************
+ * Easy macros for Getting Flags
+ ***************************************************************/
+/*PSW Flags*/
+#define GET_CY ((R_PSW & 0x80)>>7)
+#define GET_AC ((R_PSW & 0x40)>>6)
+#define GET_FO ((R_PSW & 0x20)>>5)
+#define GET_RS ((R_PSW & 0x18)>>3)
+#define GET_OV ((R_PSW & 0x04)>>2)
+#define GET_P ((R_PSW & 0x01)>>0)
+/*IE Flags*/
+#define GET_EA ((R_IE & 0x80)>>7)
+#define GET_ET2 ((R_IE & 0x20)>>5)
+#define GET_ES ((R_IE & 0x10)>>4)
+#define GET_ET1 ((R_IE & 0x08)>>3)
+#define GET_EX1 ((R_IE & 0x04)>>2)
+#define GET_ET0 ((R_IE & 0x02)>>1)
+#define GET_EX0 ((R_IE & 0x01)>>0)
+/*IP Flags*/
+#if (HAS_I8052 || HAS_I8752)
+ #define GET_PT2 ((R_IP & 0x20)>>5)
+#endif
+#define GET_PS ((R_IP & 0x10)>>4)
+#define GET_PT1 ((R_IP & 0x08)>>3)
+#define GET_PX1 ((R_IP & 0x04)>>2)
+#define GET_PT0 ((R_IP & 0x02)>>1)
+#define GET_PX0 ((R_IP & 0x01)>>0)
+/*TCON Flags*/
+#define GET_TF1 ((R_TCON & 0x80)>>7)
+#define GET_TR1 ((R_TCON & 0x40)>>6)
+#define GET_TF0 ((R_TCON & 0x20)>>5)
+#define GET_TR0 ((R_TCON & 0x10)>>4)
+#define GET_IE1 ((R_TCON & 0x08)>>3)
+#define GET_IT1 ((R_TCON & 0x04)>>2)
+#define GET_IE0 ((R_TCON & 0x02)>>1)
+#define GET_IT0 ((R_TCON & 0x01)>>0)
+/*SCON Flags*/
+#define GET_SM0 ((R_SCON & 0x80)>>7)
+#define GET_SM1 ((R_SCON & 0x40)>>6)
+#define GET_SM2 ((R_SCON & 0x20)>>5)
+#define GET_REN ((R_SCON & 0x10)>>4)
+#define GET_TB8 ((R_SCON & 0x08)>>3)
+#define GET_RB8 ((R_SCON & 0x04)>>2)
+#define GET_TI ((R_SCON & 0x02)>>1)
+#define GET_RI ((R_SCON & 0x01)>>0)
+/*TMOD Flags*/
+#define GET_GATE1 ((R_TMOD & 0x80)>>7)
+#define GET_CT1 ((R_TMOD & 0x40)>>6)
+#define GET_M1_1 ((R_TMOD & 0x20)>>5)
+#define GET_M1_0 ((R_TMOD & 0x10)>>4)
+#define GET_GATE0 ((R_TMOD & 0x08)>>3)
+#define GET_CT0 ((R_TMOD & 0x04)>>2)
+#define GET_M0_1 ((R_TMOD & 0x02)>>1)
+#define GET_M0_0 ((R_TMOD & 0x01)>>0)
+
+#if (HAS_I8052 || HAS_I8752)
+ /*T2CON Flags*/
+ #define GET_TF2 ((R_T2CON & 0x80)>>7)
+ #define GET_EXF2 ((R_T2CON & 0x40)>>6)
+ #define GET_RCLK ((R_T2CON & 0x20)>>5)
+ #define GET_TCLK ((R_T2CON & 0x10)>>4)
+ #define GET_EXEN2 ((R_T2CON & 0x08)>>3)
+ #define GET_TR2 ((R_T2CON & 0x04)>>2)
+ #define GET_CT2 ((R_T2CON & 0x02)>>1)
+ #define GET_CP ((R_T2CON & 0x01)>>0)
+#endif
+
+/*Add and Subtract Flag settings*/
+#define DO_ADD_FLAGS(a,d,c) do_add_flags(a,d,c);
+#define DO_SUB_FLAGS(a,d,c) do_sub_flags(a,d,c);
+
+#define SET_PARITY set_parity();
+#define PUSH_PC push_pc();
+#define POP_PC pop_pc();
+
+/* PC vectors */
+#define V_RESET 0x000 /* power on address */
+#define V_IE0 0x003 /* External Interrupt 0 */
+#define V_TF0 0x00b /* Timer 0 Overflow */
+#define V_IE1 0x013 /* External Interrupt 1 */
+#define V_TF1 0x01b /* Timer 1 Overflow */
+#define V_RITI 0x023 /* Serial Receive/Transmit */
+
+#if (HAS_I8052 || HAS_I8752)
+#define V_TF2 0x02b /* Timer 2 Overflow */
+#endif
+
+/* Any pending IRQ */
+#define SERIALPORT_IRQ ((R_SCON & 0x03) && GET_ES)
+
+#if (HAS_I8052 || HAS_I8752)
+#define NO_PENDING_IRQ !(R_TCON & 0xaa) && !(SERIALPORT_IRQ) && !GET_ET2 //!GET_TF2 && !GET_EXF2
+#else
+#define NO_PENDING_IRQ !(R_TCON & 0xaa) && !(SERIALPORT_IRQ)
+#endif
+
+/* Clear Current IRQ */
+#define CLEAR_CURRENT_IRQ i8051.cur_irq = 0xff;\
+ i8051.irq_priority = 0;
+
+/* shorter names for the I8051 structure elements */
+
+//Internal stuff
+#define PPC i8051.ppc
+#define PC i8051.pc
+#define TYPE i8051.subtype
+#define RWM i8051.rwm
+
+//SFR Registers
+#define R_P0 i8051.po
+#define R_SP i8051.sp
+#define R_DPL i8051.dpl
+#define R_DPH i8051.dph
+#define R_PCON i8051.pcon
+#define R_TCON i8051.tcon
+#define R_TMOD i8051.tmod
+#define R_TL0 i8051.tl0
+#define R_TL1 i8051.tl1
+#define R_TH0 i8051.th0
+#define R_TH1 i8051.th1
+#define R_P1 i8051.p1
+#define R_SCON i8051.scon
+#define R_SBUF i8051.sbuf
+#define R_P2 i8051.p2
+#define R_IE i8051.ie
+#define R_P3 i8051.p3
+#define R_IP i8051.ip
+//8052 Only registers
+#if (HAS_I8052 || HAS_I8752)
+ #define R_T2CON i8051.t2con
+ #define R_RCAP2L i8051.rcap2l
+ #define R_RCAP2H i8051.rcap2h
+ #define R_TL2 i8051.tl2
+ #define R_TH2 i8051.th2
+#endif
+#define R_PSW i8051.psw
+#define R_ACC i8051.acc
+#define R_B i8051.b
+
+/* # of oscilations each opcode requires*/
+static UINT8 i8051_cycles[] = {
+ 12,24,24,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 24,24,24,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 24,24,24,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 24,24,24,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 24,24,12,24,12,12,12,12,12,12,12,12,12,12,12,12,
+ 24,24,12,24,12,12,12,12,12,12,12,12,12,12,12,12,
+ 24,24,12,24,12,12,12,12,12,12,12,12,12,12,12,12,
+ 24,24,24,24,12,24,12,12,12,12,12,12,12,12,12,12,
+ 24,24,24,24,48,24,24,24,24,24,24,24,24,24,24,24,
+ 24,24,24,24,12,12,12,12,12,12,12,12,12,12,12,12,
+ 24,24,12,24,48,12,24,24,24,24,24,24,24,24,24,24,
+ 24,24,12,12,24,24,24,24,24,24,24,24,24,24,24,24,
+ 24,24,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 24,24,12,12,12,24,12,12,24,24,24,24,24,24,24,24,
+ 24,24,24,24,12,12,12,12,12,12,12,12,12,12,12,12,
+ 24,24,24,24,12,12,12,12,12,12,12,12,12,12,12,12
+};
+
+/* Include Opcode functions */
+#include "i8051ops.c"
+
+void i8051_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ i8051_set_irq_callback(irqcallback);
+
+ //Internal stuff
+ state_save_register_item("i8051", index, i8051.ppc);
+ state_save_register_item("i8051", index, i8051.pc);
+ state_save_register_item("i8051", index, i8051.subtype);
+ state_save_register_item("i8051", index, i8051.rwm );
+ state_save_register_item("i8051", index, i8051.cur_irq );
+ //SFR Registers
+ state_save_register_item("i8051", index, i8051.po);
+ state_save_register_item("i8051", index, i8051.sp);
+ state_save_register_item("i8051", index, i8051.dpl);
+ state_save_register_item("i8051", index, i8051.dph);
+ state_save_register_item("i8051", index, i8051.pcon);
+ state_save_register_item("i8051", index, i8051.tcon);
+ state_save_register_item("i8051", index, i8051.tmod);
+ state_save_register_item("i8051", index, i8051.tl0);
+ state_save_register_item("i8051", index, i8051.tl1);
+ state_save_register_item("i8051", index, i8051.th0);
+ state_save_register_item("i8051", index, i8051.th1);
+ state_save_register_item("i8051", index, i8051.p1);
+ state_save_register_item("i8051", index, i8051.scon);
+ state_save_register_item("i8051", index, i8051.sbuf);
+ state_save_register_item("i8051", index, i8051.p2);
+ state_save_register_item("i8051", index, i8051.ie);
+ state_save_register_item("i8051", index, i8051.p3);
+ state_save_register_item("i8051", index, i8051.ip);
+ //8052 Only registers
+ #if (HAS_I8052 || HAS_I8752)
+ state_save_register_item("i8051", index, i8051.rcap2l);
+ state_save_register_item("i8051", index, i8051.rcap2h);
+ state_save_register_item("i8051", index, i8051.tl2);
+ state_save_register_item("i8051", index, i8051.th2);
+ #endif
+ state_save_register_item("i8051", index, i8051.psw);
+ state_save_register_item("i8051", index, i8051.acc);
+ state_save_register_item("i8051", index, i8051.b);
+}
+
+/* Reset registers to the initial values */
+void i8051_reset(void)
+{
+ int (*save_irqcallback)(int);
+
+ save_irqcallback = i8051.irq_callback;
+ memset(&i8051, 0, sizeof(I8051));
+ i8051.irq_callback = save_irqcallback;
+
+ memset(&uart, 0, sizeof(I8051_UART));
+ i8051.subtype = 8051;
+
+ //Set up 8051 specific internal read/write (indirect) handlers..
+ i8051.iram_iread = internal_ram_read; //Indirect ram read/write handled the same as direct for 8051!
+ i8051.iram_iwrite = internal_ram_write; //Indirect ram read/write handled the same as direct for 8051!
+
+ //Set up serial call back handlers
+ i8051.serial_tx_callback = hold_serial_tx_callback;
+ hold_serial_tx_callback = NULL;
+ i8051.serial_rx_callback = hold_serial_rx_callback;
+ hold_serial_rx_callback = NULL;
+
+ //Setup External ram callback handlers
+ i8051.eram_iaddr_callback = hold_eram_iaddr_callback;
+ hold_eram_iaddr_callback = NULL;
+
+ //Clear Ram (w/0xff)
+ memset(&i8051.IntRam,0xff,sizeof(i8051.IntRam));
+
+ /* these are all defined reset states */
+ PC = 0;
+ SFR_W(SP, 0x7);
+ SFR_W(PSW, 0);
+ SFR_W(DPH, 0);
+ SFR_W(DPL, 0);
+ SFR_W(ACC, 0);
+ SFR_W(B, 0);
+ SFR_W(IP, 0);
+ SFR_W(IE, 0);
+ SFR_W(SCON, 0);
+ SFR_W(TCON, 0);
+ SFR_W(TMOD, 0);
+ SFR_W(TH1, 0);
+ SFR_W(TH0, 0);
+ SFR_W(TL1, 0);
+ SFR_W(TL0, 0);
+ /* set the port configurations to all 1's */
+ SFR_W(P3, 0xff);
+ SFR_W(P2, 0xff);
+ SFR_W(P1, 0xff);
+ SFR_W(P0, 0xff);
+
+ /* Flag as NO IRQ in Progress */
+ CLEAR_CURRENT_IRQ
+}
+
+/* Shut down CPU core */
+void i8051_exit(void)
+{
+ /* nothing to do */
+}
+
+/* Execute cycles - returns number of cycles actually run */
+int i8051_execute(int cycles)
+{
+ i8051_icount = cycles;
+
+ do
+ {
+ //Read next opcode
+ UINT8 op = cpu_readop(PC);
+
+ //Store previous PC
+ PPC = PC;
+
+ //Call Debugger
+ CALL_MAME_DEBUG;
+
+ //remove after testing
+ if(PC != PPC) op = cpu_readop(PC);
+
+ //Update Timer (if any timers are running)
+ if(R_TCON & 0x50)
+ update_timer(i8051.prev_used_cycles);
+
+ //Update Serial (if serial port sending data)
+ if(uart.sending)
+ update_serial(i8051.prev_used_cycles);
+
+ //Update PC
+ PC += 1;
+ //Decrement total count by # of cycles used for this opcode
+ i8051_icount -= (i8051_cycles[op]);
+
+ switch( op )
+ {
+ //NOP
+ case 0x00: /* 1: 0000 0000 */
+ nop();
+ break;
+ //AJMP code addr /* 1: aaa0 0001 */
+ case 0x01:
+ ajmp();
+ break;
+ //LJMP code addr
+ case 0x02: /* 1: 0000 0010 */
+ ljmp();
+ break;
+ //RR A
+ case 0x03: /* 1: 0000 0011 */
+ rr_a();
+ break;
+ //INC A
+ case 0x04: /* 1: 0000 0100 */
+ inc_a();
+ break;
+ //INC data addr
+ case 0x05: /* 1: 0000 0101 */
+ RWM=1;
+ inc_mem();
+ RWM=0;
+ break;
+ //INC @R0/@R1 /* 1: 0000 011i */
+ case 0x06:
+ case 0x07:
+ inc_ir(op&1);
+ break;
+ //INC R0 to R7 /* 1: 0000 1rrr */
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ inc_r(op&7);
+ break;
+ //JBC bit addr, code addr
+ case 0x10: /* 1: 0001 0000 */
+ RWM=1;
+ jbc();
+ RWM=0;
+ break;
+ //ACALL code addr /* 1: aaa1 0001 */
+ case 0x11:
+ acall();
+ break;
+ //LCALL code addr
+ case 0x12: /* 1: 0001 0010 */
+ lcall();
+ break;
+ //RRC A
+ case 0x13: /* 1: 0001 0011 */
+ rrc_a();
+ break;
+ //DEC A
+ case 0x14: /* 1: 0001 0100 */
+ dec_a();
+ break;
+ //DEC data addr
+ case 0x15: /* 1: 0001 0101 */
+ RWM=1;
+ dec_mem();
+ RWM=0;
+ break;
+ //DEC @R0/@R1 /* 1: 0001 011i */
+ case 0x16:
+ case 0x17:
+ dec_ir(op&1);
+ break;
+ //DEC R0 to R7 /* 1: 0001 1rrr */
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x1e:
+ case 0x1f:
+ dec_r(op&7);
+ break;
+ //JB bit addr, code addr
+ case 0x20: /* 1: 0010 0000 */
+ jb();
+ break;
+ //AJMP code addr /* 1: aaa0 0001 */
+ case 0x21:
+ ajmp();
+ break;
+ //RET
+ case 0x22: /* 1: 0010 0010 */
+ ret();
+ break;
+ //RL A
+ case 0x23: /* 1: 0010 0011 */
+ rl_a();
+ break;
+ //ADD A, #data
+ case 0x24: /* 1: 0010 0100 */
+ add_a_byte();
+ break;
+ //ADD A, data addr
+ case 0x25: /* 1: 0010 0101 */
+ add_a_mem();
+ break;
+ //ADD A, @R0/@R1 /* 1: 0010 011i */
+ case 0x26:
+ case 0x27:
+ add_a_ir(op&1);
+ break;
+ //ADD A, R0 to R7 /* 1: 0010 1rrr */
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f:
+ add_a_r(op&7);
+ break;
+ //JNB bit addr, code addr
+ case 0x30: /* 1: 0011 0000 */
+ jnb();
+ break;
+ //ACALL code addr /* 1: aaa1 0001 */
+ case 0x31:
+ acall();
+ break;
+ //RETI
+ case 0x32: /* 1: 0011 0010 */
+ reti();
+ break;
+ //RLC A
+ case 0x33: /* 1: 0011 0011 */
+ rlc_a();
+ break;
+ //ADDC A, #data
+ case 0x34: /* 1: 0011 0100 */
+ addc_a_byte();
+ break;
+ //ADDC A, data addr
+ case 0x35: /* 1: 0011 0101 */
+ addc_a_mem();
+ break;
+ //ADDC A, @R0/@R1 /* 1: 0011 011i */
+ case 0x36:
+ case 0x37:
+ addc_a_ir(op&1);
+ break;
+ //ADDC A, R0 to R7 /* 1: 0011 1rrr */
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f:
+ addc_a_r(op&7);
+ break;
+ //JC code addr
+ case 0x40: /* 1: 0100 0000 */
+ jc();
+ break;
+ //AJMP code addr /* 1: aaa0 0001 */
+ case 0x41:
+ ajmp();
+ break;
+ //ORL data addr, A
+ case 0x42: /* 1: 0100 0010 */
+ RWM=1;
+ orl_mem_a();
+ RWM=0;
+ break;
+ //ORL data addr, #data
+ case 0x43: /* 1: 0100 0011 */
+ RWM=1;
+ orl_mem_byte();
+ RWM=0;
+ break;
+ //ORL A, #data
+ case 0x44: /* 1: 0100 0100 */
+ orl_a_byte();
+ break;
+ //ORL A, data addr
+ case 0x45: /* 1: 0100 0101 */
+ orl_a_mem();
+ break;
+ //ORL A, @RO/@R1 /* 1: 0100 011i */
+ case 0x46:
+ case 0x47:
+ orl_a_ir(op&1);
+ break;
+ //ORL A, RO to R7 /* 1: 0100 1rrr */
+ case 0x48:
+ case 0x49:
+ case 0x4a:
+ case 0x4b:
+ case 0x4c:
+ case 0x4d:
+ case 0x4e:
+ case 0x4f:
+ orl_a_r(op&7);
+ break;
+ //JNC code addr
+ case 0x50: /* 1: 0101 0000 */
+ jnc();
+ break;
+ //ACALL code addr /* 1: aaa1 0001 */
+ case 0x51:
+ acall();
+ break;
+ //ANL data addr, A
+ case 0x52: /* 1: 0101 0010 */
+ RWM=1;
+ anl_mem_a();
+ RWM=0;
+ break;
+ //ANL data addr, #data
+ case 0x53: /* 1: 0101 0011 */
+ RWM=1;
+ anl_mem_byte();
+ RWM=0;
+ break;
+ //ANL A, #data
+ case 0x54: /* 1: 0101 0100 */
+ anl_a_byte();
+ break;
+ //ANL A, data addr
+ case 0x55: /* 1: 0101 0101 */
+ anl_a_mem();
+ break;
+ //ANL A, @RO/@R1 /* 1: 0101 011i */
+ case 0x56:
+ case 0x57:
+ anl_a_ir(op&1);
+ break;
+ //ANL A, RO to R7 /* 1: 0101 1rrr */
+ case 0x58:
+ case 0x59:
+ case 0x5a:
+ case 0x5b:
+ case 0x5c:
+ case 0x5d:
+ case 0x5e:
+ case 0x5f:
+ anl_a_r(op&7);
+ break;
+ //JZ code addr
+ case 0x60: /* 1: 0110 0000 */
+ jz();
+ break;
+ //AJMP code addr /* 1: aaa0 0001 */
+ case 0x61:
+ ajmp();
+ break;
+ //XRL data addr, A
+ case 0x62: /* 1: 0110 0010 */
+ RWM=1;
+ xrl_mem_a();
+ RWM=0;
+ break;
+ //XRL data addr, #data
+ case 0x63: /* 1: 0110 0011 */
+ RWM=1;
+ xrl_mem_byte();
+ RWM=0;
+ break;
+ //XRL A, #data
+ case 0x64: /* 1: 0110 0100 */
+ xrl_a_byte();
+ break;
+ //XRL A, data addr
+ case 0x65: /* 1: 0110 0101 */
+ xrl_a_mem();
+ break;
+ //XRL A, @R0/@R1 /* 1: 0110 011i */
+ case 0x66:
+ case 0x67:
+ xrl_a_ir(op&1);
+ break;
+ //XRL A, R0 to R7 /* 1: 0110 1rrr */
+ case 0x68:
+ case 0x69:
+ case 0x6a:
+ case 0x6b:
+ case 0x6c:
+ case 0x6d:
+ case 0x6e:
+ case 0x6f:
+ xrl_a_r(op&7);
+ break;
+ //JNZ code addr
+ case 0x70: /* 1: 0111 0000 */
+ jnz();
+ break;
+ //ACALL code addr /* 1: aaa1 0001 */
+ case 0x71:
+ acall();
+ break;
+ //ORL C, bit addr
+ case 0x72: /* 1: 0111 0010 */
+ orl_c_bitaddr();
+ break;
+ //JMP @A+DPTR
+ case 0x73: /* 1: 0111 0011 */
+ jmp_iadptr();
+ break;
+ //MOV A, #data
+ case 0x74: /* 1: 0111 0100 */
+ mov_a_byte();
+ break;
+ //MOV data addr, #data
+ case 0x75: /* 1: 0111 0101 */
+ mov_mem_byte();
+ break;
+ //MOV @R0/@R1, #data /* 1: 0111 011i */
+ case 0x76:
+ case 0x77:
+ mov_ir_byte(op&1);
+ break;
+ //MOV R0 to R7, #data /* 1: 0111 1rrr */
+ case 0x78:
+ case 0x79:
+ case 0x7a:
+ case 0x7b:
+ case 0x7c:
+ case 0x7d:
+ case 0x7e:
+ case 0x7f:
+ mov_r_byte(op&7);
+ break;
+ //SJMP code addr
+ case 0x80: /* 1: 1000 0000 */
+ sjmp();
+ break;
+ //AJMP code addr /* 1: aaa0 0001 */
+ case 0x81:
+ ajmp();
+ break;
+ //ANL C, bit addr
+ case 0x82: /* 1: 1000 0010 */
+ anl_c_bitaddr();
+ break;
+ //MOVC A, @A + PC
+ case 0x83: /* 1: 1000 0011 */
+ movc_a_iapc();
+ break;
+ //DIV AB
+ case 0x84: /* 1: 1000 0100 */
+ div_ab();
+ break;
+ //MOV data addr, data addr
+ case 0x85: /* 1: 1000 0101 */
+ mov_mem_mem();
+ break;
+ //MOV data addr, @R0/@R1 /* 1: 1000 011i */
+ case 0x86:
+ case 0x87:
+ mov_mem_ir(op&1);
+ break;
+ //MOV data addr,R0 to R7 /* 1: 1000 1rrr */
+ case 0x88:
+ case 0x89:
+ case 0x8a:
+ case 0x8b:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ case 0x8f:
+ mov_mem_r(op&7);
+ break;
+ //MOV DPTR, #data
+ case 0x90: /* 1: 1001 0000 */
+ mov_dptr_byte();
+ break;
+ //ACALL code addr /* 1: aaa1 0001 */
+ case 0x91:
+ acall();
+ break;
+ //MOV bit addr, C
+ case 0x92: /* 1: 1001 0010 */
+ RWM = 1;
+ mov_bitaddr_c();
+ RWM = 0;
+ break;
+ //MOVC A, @A + DPTR
+ case 0x93: /* 1: 1001 0011 */
+ movc_a_iadptr();
+ break;
+ //SUBB A, #data
+ case 0x94: /* 1: 1001 0100 */
+ subb_a_byte();
+ break;
+ //SUBB A, data addr
+ case 0x95: /* 1: 1001 0101 */
+ subb_a_mem();
+ break;
+ //SUBB A, @R0/@R1 /* 1: 1001 011i */
+ case 0x96:
+ case 0x97:
+ subb_a_ir(op&1);
+ break;
+ //SUBB A, R0 to R7 /* 1: 1001 1rrr */
+ case 0x98:
+ case 0x99:
+ case 0x9a:
+ case 0x9b:
+ case 0x9c:
+ case 0x9d:
+ case 0x9e:
+ case 0x9f:
+ subb_a_r(op&7);
+ break;
+ //ORL C, /bit addr
+ case 0xa0: /* 1: 1010 0000 */
+ orl_c_nbitaddr();
+ break;
+ //AJMP code addr /* 1: aaa0 0001 */
+ case 0xa1:
+ ajmp();
+ break;
+ //MOV C, bit addr
+ case 0xa2: /* 1: 1010 0010 */
+ mov_c_bitaddr();
+ break;
+ //INC DPTR
+ case 0xa3: /* 1: 1010 0011 */
+ inc_dptr();
+ break;
+ //MUL AB
+ case 0xa4: /* 1: 1010 0100 */
+ mul_ab();
+ break;
+ //reserved
+ case 0xa5: /* 1: 1010 0101 */
+ illegal();
+ break;
+ //MOV @R0/@R1, data addr /* 1: 1010 011i */
+ case 0xa6:
+ case 0xa7:
+ mov_ir_mem(op&1);
+ break;
+ //MOV R0 to R7, data addr /* 1: 1010 1rrr */
+ case 0xa8:
+ case 0xa9:
+ case 0xaa:
+ case 0xab:
+ case 0xac:
+ case 0xad:
+ case 0xae:
+ case 0xaf:
+ mov_r_mem(op&7);
+ break;
+ //ANL C,/bit addr
+ case 0xb0: /* 1: 1011 0000 */
+ anl_c_nbitaddr();
+ break;
+ //ACALL code addr /* 1: aaa1 0001 */
+ case 0xb1:
+ acall();
+ break;
+ //CPL bit addr
+ case 0xb2: /* 1: 1011 0010 */
+ RWM=1;
+ cpl_bitaddr();
+ RWM=0;
+ break;
+ //CPL C
+ case 0xb3: /* 1: 1011 0011 */
+ cpl_c();
+ break;
+ //CJNE A, #data, code addr
+ case 0xb4: /* 1: 1011 0100 */
+ cjne_a_byte();
+ break;
+ //CJNE A, data addr, code addr
+ case 0xb5: /* 1: 1011 0101 */
+ cjne_a_mem();
+ break;
+ //CJNE @R0/@R1, #data, code addr /* 1: 1011 011i */
+ case 0xb6:
+ case 0xb7:
+ cjne_ir_byte(op&1);
+ break;
+ //CJNE R0 to R7, #data, code addr/* 1: 1011 1rrr */
+ case 0xb8:
+ case 0xb9:
+ case 0xba:
+ case 0xbb:
+ case 0xbc:
+ case 0xbd:
+ case 0xbe:
+ case 0xbf:
+ cjne_r_byte(op&7);
+ break;
+ //PUSH data addr
+ case 0xc0: /* 1: 1100 0000 */
+ push();
+ break;
+ //AJMP code addr /* 1: aaa0 0001 */
+ case 0xc1:
+ ajmp();
+ break;
+ //CLR bit addr
+ case 0xc2: /* 1: 1100 0010 */
+ RWM=1;
+ clr_bitaddr();
+ RWM=0;
+ break;
+ //CLR C
+ case 0xc3: /* 1: 1100 0011 */
+ clr_c();
+ break;
+ //SWAP A
+ case 0xc4: /* 1: 1100 0100 */
+ swap_a();
+ break;
+ //XCH A, data addr
+ case 0xc5: /* 1: 1100 0101 */
+ xch_a_mem();
+ break;
+ //XCH A, @RO/@R1 /* 1: 1100 011i */
+ case 0xc6:
+ case 0xc7:
+ xch_a_ir(op&1);
+ break;
+ //XCH A, RO to R7 /* 1: 1100 1rrr */
+ case 0xc8:
+ case 0xc9:
+ case 0xca:
+ case 0xcb:
+ case 0xcc:
+ case 0xcd:
+ case 0xce:
+ case 0xcf:
+ xch_a_r(op&7);
+ break;
+ //POP data addr
+ case 0xd0: /* 1: 1101 0000 */
+ pop();
+ break;
+ //ACALL code addr /* 1: aaa1 0001 */
+ case 0xd1:
+ acall();
+ break;
+ //SETB bit addr
+ case 0xd2: /* 1: 1101 0010 */
+ RWM=1;
+ setb_bitaddr();
+ RWM=0;
+ break;
+ //SETB C
+ case 0xd3: /* 1: 1101 0011 */
+ setb_c();
+ break;
+ //DA A
+ case 0xd4: /* 1: 1101 0100 */
+ da_a();
+ break;
+ //DJNZ data addr, code addr
+ case 0xd5: /* 1: 1101 0101 */
+ RWM=1;
+ djnz_mem();
+ RWM=0;
+ break;
+ //XCHD A, @R0/@R1 /* 1: 1101 011i */
+ case 0xd6:
+ case 0xd7:
+ xchd_a_ir(op&1);
+ break;
+ //DJNZ R0 to R7,code addr /* 1: 1101 1rrr */
+ case 0xd8:
+ case 0xd9:
+ case 0xda:
+ case 0xdb:
+ case 0xdc:
+ case 0xdd:
+ case 0xde:
+ case 0xdf:
+ djnz_r(op&7);
+ break;
+ //MOVX A,@DPTR
+ case 0xe0: /* 1: 1110 0000 */
+ movx_a_idptr();
+ break;
+ //AJMP code addr /* 1: aaa0 0001 */
+ case 0xe1:
+ ajmp();
+ break;
+ //MOVX A, @R0/@R1 /* 1: 1110 001i */
+ case 0xe2:
+ case 0xe3:
+ movx_a_ir(op&1);
+ break;
+ //CLR A
+ case 0xe4: /* 1: 1110 0100 */
+ clr_a();
+ break;
+ //MOV A, data addr
+ case 0xe5: /* 1: 1110 0101 */
+ mov_a_mem();
+ break;
+ //MOV A,@RO/@R1 /* 1: 1110 011i */
+ case 0xe6:
+ case 0xe7:
+ mov_a_ir(op&1);
+ break;
+ //MOV A,R0 to R7 /* 1: 1110 1rrr */
+ case 0xe8:
+ case 0xe9:
+ case 0xea:
+ case 0xeb:
+ case 0xec:
+ case 0xed:
+ case 0xee:
+ case 0xef:
+ mov_a_r(op&7);
+ break;
+ //MOVX @DPTR,A
+ case 0xf0: /* 1: 1111 0000 */
+ movx_idptr_a();
+ break;
+ //ACALL code addr /* 1: aaa1 0001 */
+ case 0xf1:
+ acall();
+ break;
+ //MOVX @R0/@R1,A /* 1: 1111 001i */
+ case 0xf2:
+ case 0xf3:
+ movx_ir_a(op&1);
+ break;
+ //CPL A
+ case 0xf4: /* 1: 1111 0100 */
+ cpl_a();
+ break;
+ //MOV data addr, A
+ case 0xf5: /* 1: 1111 0101 */
+ mov_mem_a();
+ break;
+ //MOV @R0/@R1, A /* 1: 1111 011i */
+ case 0xf6:
+ case 0xf7:
+ mov_ir_a(op&1);
+ break;
+ //MOV R0 to R7, A /* 1: 1111 1rrr */
+ case 0xf8:
+ case 0xf9:
+ case 0xfa:
+ case 0xfb:
+ case 0xfc:
+ case 0xfd:
+ case 0xfe:
+ case 0xff:
+ mov_r_a(op&7);
+ break;
+ default:
+ illegal();
+ }
+
+ //Store # of used cycles for this opcode (for timer & serial check at top of code)
+ i8051.prev_used_cycles = i8051_cycles[op];
+
+ //Check for pending interrupts & handle - remove cycles used
+ i8051_icount-=check_interrupts();
+
+ } while( i8051_icount > 0 );
+
+ return cycles - i8051_icount;
+}
+
+/* Get registers, return context size */
+void i8051_get_context(void *dst)
+{
+ if( dst )
+ memcpy(dst, &i8051, sizeof(I8051));
+}
+
+/* Set registers */
+void i8051_set_context(void *src)
+{
+ if( src )
+ memcpy(&i8051, src, sizeof(I8051));
+}
+
+/* Get Internal RAM value */
+unsigned i8051_get_intram(int offset)
+{
+ UINT8 ram_ret = 0;
+ RWM = 1;
+ ram_ret = IRAM_R(offset);
+ RWM = 0;
+ return ram_ret;
+}
+
+/*NOTE: These are not used by the opcode functions, they are here only for MAME requirements*/
+unsigned i8051_get_reg(int regnum)
+{
+ switch( regnum )
+ {
+ case REG_PREVIOUSPC: return PPC;
+ case REG_PC:
+ case I8051_PC: return PC;
+ case REG_SP:
+ case I8051_SP: return R_SP;
+ case I8051_ACC: return R_ACC;
+ case I8051_PSW: return R_PSW;
+ case I8051_B: return R_B;
+ case I8051_DPH: return R_DPH;
+ case I8051_DPL: return R_DPL;
+ case I8051_IE: return R_IE;
+ //Not real registers
+ case I8051_R0: return R_R(0);
+ case I8051_R1: return R_R(1);
+ case I8051_R2: return R_R(2);
+ case I8051_R3: return R_R(3);
+ case I8051_R4: return R_R(4);
+ case I8051_R5: return R_R(5);
+ case I8051_R6: return R_R(6);
+ case I8051_R7: return R_R(7);
+ case I8051_RB: return GET_RS;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+/*NOTE: These are not used by the opcode functions, they are here only for MAME requirements*/
+void i8051_set_reg (int regnum, unsigned val)
+{
+ switch( regnum )
+ {
+ case REG_PC:
+ case I8051_PC: PC = val & 0xffff; break;
+ case REG_SP:
+ case I8051_SP: SFR_W(SP,val); break; //Use SFR to handle error checking
+ case I8051_ACC: SFR_W(ACC,val); break;
+ case I8051_PSW: SFR_W(PSW,val); break;
+ case I8051_B: SFR_W(B,val); break;
+ case I8051_DPH: SFR_W(DPH,val); break;
+ case I8051_DPL: SFR_W(DPL,val); break;
+ case I8051_IE: SFR_W(IE,val); break;
+ //Not real registers
+ case I8051_R0: R_R(0) = val; break;
+ case I8051_R1: R_R(1) = val; break;
+ case I8051_R2: R_R(2) = val; break;
+ case I8051_R3: R_R(3) = val; break;
+ case I8051_R4: R_R(4) = val; break;
+ case I8051_R5: R_R(5) = val; break;
+ case I8051_R6: R_R(6) = val; break;
+ case I8051_R7: R_R(7) = val; break;
+ case I8051_RB: SET_RS( (val&3) ); break;
+
+ default:
+ return;
+ }
+}
+
+void i8051_set_irq_line(int irqline, int state)
+{
+ switch( irqline )
+ {
+ //External Interrupt 0
+ case I8051_INT0_LINE:
+ //Line Asserted?
+ if (state != CLEAR_LINE) {
+ //Is the enable flag for this interrupt set?
+ if(GET_EX0) {
+ //Need cleared->active line transition? (Logical 1-0 Pulse on the line) - CLEAR->ASSERT Transition since INT0 active lo!
+ if(GET_IT0){
+ if(i8051.last_int0 == CLEAR_LINE)
+ SET_IE0(1);
+ }
+ else
+ SET_IE0(1); //Nope, just set it..
+ }
+ }
+ else
+ SET_IE0(0); //Clear Int occurred flag
+ i8051.last_int0 = state;
+
+ //Do the interrupt & handle - remove machine cycles used
+ if(GET_IE0)
+ i8051_icount-=check_interrupts();
+ break;
+
+ //External Interrupt 1
+ case I8051_INT1_LINE:
+
+ //Line Asserted?
+ if (state != CLEAR_LINE) {
+ if(GET_EX1) {
+ //Need cleared->active line transition? (Logical 1-0 Pulse on the line) - CLEAR->ASSERT Transition since INT1 active lo!
+ if(GET_IT1){
+ if(i8051.last_int1 == CLEAR_LINE)
+ SET_IE1(1);
+ }
+ else
+ SET_IE1(1); //Nope, just set it..
+ }
+ }
+ else
+ SET_IE1(0); //Clear Int occurred flag
+ i8051.last_int1 = state;
+
+ //Do the interrupt & handle - remove machine cycles used
+ if(GET_IE1)
+ i8051_icount-=check_interrupts();
+ break;
+
+ //Serial Port Receive
+ case I8051_RX_LINE:
+ //Is the enable flags for this interrupt set?
+ if(GET_ES && GET_REN) {
+ int data = 0;
+ //Call our callball function to retrieve the data
+ if(i8051.serial_rx_callback)
+ data = i8051.serial_rx_callback();
+ //Update the register directly, since SFR_W() will trigger a serial transmit instead!
+ R_SBUF=data;
+ //Flag the IRQ
+ SET_RI(1);
+ }
+ break;
+ //Note: we won't call check interrupts, we'll let the main loop catch it
+ }
+}
+
+/***********************************************************************************
+ Check for pending Interrupts and process - returns # of cycles used for the int
+
+ Note about priority & interrupting interrupts..
+ 1) A high priority interrupt cannot be interrupted by anything!
+ 2) A low priority interrupt can ONLY be interrupted by a high priority interrupt
+ 3) If more than 1 Interrupt Flag is set (ie, 2 simultaneous requests occur),
+ the following logic works as follows:
+ 1) If two requests come in of different priority levels, the higher one is selected..
+ 2) If the requests are of the same level, an internal order is used:
+ a) IEO
+ b) TFO
+ c) IE1
+ d) TF1
+ e) RI+TI
+ f) TF2+EXF2
+ **********************************************************************************/
+INLINE UINT8 check_interrupts(void)
+{
+ //If All Inerrupts Disabled or no pending abort..
+ if(!GET_EA) return 0;
+
+ //Any Interrupts Pending?
+ if(NO_PENDING_IRQ) return 0;
+
+ //Skip if current irq in progress is high priority!
+ if(i8051.irq_priority) { /* LOG(("high priority irq in progress, skipping irq request\n")); */ return 0; }
+
+ //Check which interrupt(s) requests have occurred..
+ //NOTE: The order of checking is based on the internal/default priority levels when levels are the same
+
+ //External Int 0
+ if(GET_IE0) {
+ //Set vector & priority level request
+ i8051.int_vec = V_IE0;
+ i8051.priority_request = GET_PX0;
+ }
+ //Timer 0 overflow
+ if(!i8051.priority_request && GET_TF0 && (!i8051.int_vec || (i8051.int_vec && GET_PT0))) {
+ //Set vector & priority level request
+ i8051.int_vec = V_TF0;
+ i8051.priority_request = GET_PT0;
+ }
+ //External Int 1
+ if(!i8051.priority_request && GET_IE1 && (!i8051.int_vec || (i8051.int_vec && GET_PX1))) {
+ //Set vector & priority level request
+ i8051.int_vec = V_IE1;
+ i8051.priority_request = GET_PX1;
+ }
+ //Timer 1 overflow
+ if(!i8051.priority_request && GET_TF1 && (!i8051.int_vec || (i8051.int_vec && GET_PT1))) {
+ //Set vector & priority level request
+ i8051.int_vec = V_TF1;
+ i8051.priority_request = GET_PT1;
+ }
+ //Serial Interrupt Transmit/Receive Interrupts (Note: ES Bit - Serial Interrupts must be enabled)
+ if(!i8051.priority_request && GET_ES && (GET_TI || GET_RI) && (!i8051.int_vec || (i8051.int_vec && GET_PS))) {
+ //Set vector & priority level request
+ i8051.int_vec = V_RITI;
+ i8051.priority_request = GET_PS;
+ }
+#if (HAS_I8052 || HAS_I8752)
+ //Timer 2 overflow (Either Timer Overflow OR External Interrupt)
+ if(!i8051.priority_request && GET_ET2 && (GET_TF2 || GET_EXF2) && (!i8051.int_vec || (i8051.int_vec && GET_PT2))) {
+ //Set vector & priority level request
+ i8051.int_vec = V_TF2;
+ i8051.priority_request = GET_PT2;
+ }
+#endif
+
+ //Skip the interrupt request if currently processing is lo priority, and the new request IS NOT HI PRIORITY!
+ if(i8051.cur_irq < 0xff && !i8051.priority_request)
+ { LOG(("low priority irq in progress already, skipping low irq request\n")); return 0; }
+
+ /*** --- Perform the interrupt --- ***/
+
+ //Save current pc to stack, set pc to new interrupt vector
+ push_pc();
+ PC = i8051.int_vec;
+
+ //Set current Irq & Priority being serviced
+ i8051.cur_irq = i8051.int_vec;
+ i8051.irq_priority = i8051.priority_request;
+
+ //Clear any interrupt flags that should be cleared since we're servicing the irq!
+ switch(i8051.cur_irq) {
+ case V_IE0:
+ //External Int Flag only cleared when configured as Edge Triggered..
+ //if(GET_IT0) - for some reason having this, breaks alving dmd games
+ SET_IE0(0);
+ break;
+ case V_TF0:
+ //Timer 0 - Always clear Flag
+ SET_TF0(0);
+ break;
+ case V_IE1:
+ //External Int Flag only cleared when configured as Edge Triggered..
+ //if(GET_IT1) - for some reason having this, breaks alving dmd games
+ SET_IE1(0);
+ break;
+ case V_TF1:
+ //Timer 0 - Always clear Flag
+ SET_TF1(0);
+ break;
+ case V_RITI:
+ // no flags are cleared, TI and RI remain set until reset by software
+ break;
+#if (HAS_I8052 || HAS_I8752)
+ case V_TF2:
+ // no flags are cleared according to manual
+ break;
+#endif
+ }
+
+ //Clear vars.. (these are part of the 8051 structure for speed, so we don't have to dynamically allocate space each time)
+ i8051.int_vec = 0;
+ i8051.priority_request = 0;
+
+ //All interrupts use 2 machine cycles
+ return 24;
+}
+
+
+void i8051_set_irq_callback(int (*callback)(int irqline))
+{
+ i8051.irq_callback = callback;
+}
+
+void i8051_set_serial_tx_callback(void (*callback)(int data))
+{
+ //Hold in static variable since this function can get called before reset has run, which wipes i8051 memory clean
+ hold_serial_tx_callback = callback;
+}
+void i8051_set_serial_rx_callback(int (*callback)(void))
+{
+ //Hold in static variable since this function can get called before reset has run, which wipes i8051 memory clean
+ hold_serial_rx_callback = callback;
+}
+
+void i8051_set_eram_iaddr_callback(READ32_HANDLER((*callback)))
+{
+ //Hold in static variable since this function can get called before reset has run, which wipes i8051 memory clean
+ hold_eram_iaddr_callback = callback;
+}
+
+
+void i8051_state_save(void *file)
+{
+}
+
+void i8051_state_load(void *file)
+{
+}
+
+/* HELPER FUNCTIONS */
+
+/*All writes to SFR are handled here*/
+static WRITE8_HANDLER(sfr_write)
+{
+ data &= 0xff; //Ensure only 8 bits
+ switch (offset)
+ {
+ case P0:
+ R_P0 = data;
+ OUT(0,data);
+ break;
+
+ case SP:
+ if(offset > 0xff)
+ LOG(("i8051 #%d: attemping to write value to SP past 256 bytes at 0x%04x\n", cpu_getactivecpu(), PC));
+ R_SP = data&0xff; //keep sp w/in 256 bytes
+ break;
+
+ case DPL: R_DPL = data; break;
+ case DPH: R_DPH = data; break;
+ case PCON: R_PCON= data; break;
+ case TCON: R_TCON= data; break;
+ case TMOD: R_TMOD= data; break;
+ case TL0: R_TL0 = data; break;
+ case TL1: R_TL1 = data; break;
+ case TH0: R_TH0 = data; break;
+ case TH1: R_TH1 = data; break;
+
+ case P1:
+ R_P1 = data;
+ OUT(1,data);
+ break;
+
+ case SCON: {
+ //Update register
+ R_SCON = data;
+ break;
+ }
+
+ case SBUF:
+ //R_SBUF = data; //This register is used only for "Receiving data coming in!"
+ serial_transmit(data); //Set up to transmit the data
+ break;
+
+ case P2:
+ R_P2 = data;
+ OUT(2,data);
+ break;
+
+ case IE: R_IE = data; break;
+
+ case P3:
+ R_P3 = data;
+ OUT(3,data);
+ break;
+
+ case IP: R_IP = data; break;
+
+ //8052 Only registers
+ #if (HAS_I8052 || HAS_I8752)
+ case T2CON: R_T2CON = data; break;
+ case RCAP2L: R_RCAP2L = data; break;
+ case RCAP2H: R_RCAP2H = data; break;
+ case TL2: R_TL2 = data; break;
+ case TH2: R_TH2 = data; break;
+ #endif
+
+ case PSW:
+ R_PSW = data;
+ SET_PARITY;
+ break;
+
+ case ACC:
+ R_ACC = data;
+ SET_PARITY;
+ break;
+
+ case B: R_B = data; break;
+
+ /* Illegal or non-implemented sfr */
+ default:
+ LOG(("i8051 #%d: attemping to write to an invalid/non-implemented SFR address: %x at 0x%04x, data=%x\n", cpu_getactivecpu(), offset,PC,data));
+ }
+}
+
+/*All reads to SFR are handled here*/
+static READ8_HANDLER(sfr_read)
+{
+ switch (offset)
+ {
+ case P0:
+ if(RWM)
+ return R_P0; //Read directly from port latch
+ else
+ return IN(0); //Read from actual port
+ case SP: return R_SP;
+ case DPL: return R_DPL;
+ case DPH: return R_DPH;
+ case PCON: return R_PCON;
+ case TCON: return R_TCON;
+ case TMOD: return R_TMOD;
+ case TL0: return R_TL0;
+ case TL1: return R_TL1;
+ case TH0: return R_TH0;
+ case TH1: return R_TH1;
+ case P1:
+ if(RWM)
+ return R_P1; //Read directly from port latch
+ else
+ return IN(1); //Read from actual port
+ case SCON: return R_SCON;
+ case SBUF: return R_SBUF;
+ case P2:
+ if(RWM)
+ return R_P2; //Read directly from port latch
+ else
+ return IN(2); //Read from actual port
+ case IE: return R_IE;
+ case P3:
+ if(RWM)
+ return R_P3; //Read directly from port latch
+ else
+ return IN(3); //Read from actual port
+ case IP: return R_IP;
+ //8052 Only registers
+ #if (HAS_I8052 || HAS_I8752)
+ case T2CON: return R_T2CON;
+ case RCAP2L: return R_RCAP2L;
+ case RCAP2H: return R_RCAP2H;
+ case TL2: return R_TL2;
+ case TH2: return R_TH2;
+ #endif
+ case PSW: return R_PSW;
+ case ACC: return R_ACC;
+ case B: return R_B;
+
+ /* Illegal or non-implemented sfr */
+ default:
+ LOG(("i8051 #%d: attemping to read an invalid/non-implemented SFR address: %x at 0x%04x\n", cpu_getactivecpu(), offset,PC));
+ }
+ return 0xff;
+}
+
+/* Reads the contents of the Internal RAM memory */
+/* Anything above 0x7f is a sfr/register */
+static READ8_HANDLER(internal_ram_read)
+{
+ if (offset < 0x80)
+ return i8051.IntRam[offset];
+ else {
+ if (offset < 0x100)
+ return SFR_R(offset);
+ else
+ LOG(("i8051 #%d: attemping to read from an invalid Internal Ram address: %x at 0x%04x\n", cpu_getactivecpu(), offset,PC));
+ }
+ return 0xff;
+}
+
+/* Writes the contents of the Internal RAM memory */
+/* Anything above 0x7f is a sfr/register */
+static WRITE8_HANDLER(internal_ram_write)
+{
+ data &= 0xff; //Ensure it's only 8 bits
+ if (offset < 0x80)
+ i8051.IntRam[offset] = data;
+ else {
+ if (offset < 0x100)
+ SFR_W(offset,data);
+ else
+ LOG(("i8051 #%d: attemping to write to invalid Internal Ram address: %x at 0x%04x\n", cpu_getactivecpu(), offset,PC));
+ }
+}
+
+/* Reads the contents of the Internal RAM memory (BUT CALLED FROM AN INDIRECT ADDRESSING MODE) */
+/* Different chip types handle differently, for speed, simply call the chip's handler */
+static READ8_HANDLER(internal_ram_iread)
+{
+ return i8051.iram_iread(offset);
+}
+
+/* Writes the contents of the Internal RAM memory (BUT CALLED FROM AN INDIRECT ADDRESSING MODE) */
+/* Different chip types handle differently, for speed, simply call the chip's handler */
+static WRITE8_HANDLER(internal_ram_iwrite)
+{
+ i8051.iram_iwrite(offset,data);
+}
+
+/*Generate an external ram address for read/writing using indirect addressing mode */
+/*The lowest 8 bits of the address are passed in (from the R0/R1 register), however
+ the hardware can be configured to set the rest of the address lines to any available output port pins, which
+ means the only way we can implement this is to allow the driver to setup a callback to generate the
+ address as defined by the specific hardware setup. We'll assume the address won't be bigger than 32 bits
+*/
+static READ32_HANDLER(external_ram_iaddr)
+{
+ if(i8051.eram_iaddr_callback)
+ return i8051.eram_iaddr_callback(offset,mem_mask);
+ else
+ LOG(("i8051 #%d: external ram address requested (8 bit offset=%02x), but no callback available! at PC:%04x\n", cpu_getactivecpu(), offset, PC));
+
+ return offset;
+}
+
+/*Push the current PC to the stack*/
+INLINE void push_pc()
+{
+ UINT8 tmpSP = R_SP; //Grab and Increment Stack Pointer
+ tmpSP++; // ""
+ SFR_W(SP,tmpSP); // ""
+ if (tmpSP == R_SP) //Ensure it was able to write to new stack location
+ IRAM_IW(tmpSP, (PC & 0xff)); //Store low byte of PC to Internal Ram (Use IRAM_IW to store stack above 128 bytes)
+ tmpSP = R_SP; //Increment Stack Pointer
+ tmpSP++; // ""
+ SFR_W(SP,tmpSP); // ""
+ if (tmpSP == R_SP) //Ensure it was able to write to new stack location
+ IRAM_IW(tmpSP, ( (PC & 0xff00) >> 8)); //Store hi byte of PC to next address in Internal Ram (Use IRAM_IW to store stack above 128 bytes)
+}
+
+/*Pop the current PC off the stack and into the pc*/
+INLINE void pop_pc()
+{
+ UINT8 tmpSP = R_SP; //Grab Stack Pointer
+ PC = (IRAM_IR(tmpSP) & 0xff) << 8; //Store hi byte to PC (must use IRAM_IR to access stack pointing above 128 bytes)
+ tmpSP = R_SP-1; //Decrement Stack Pointer
+ SFR_W(SP,tmpSP); // ""
+ if (tmpSP == R_SP) //Ensure it was able to write to new stack location
+ PC = PC | IRAM_IR(tmpSP); //Store lo byte to PC (must use IRAM_IR to access stack pointing above 128 bytes)
+ SFR_W(SP,tmpSP-1); //Decrement Stack Pointer
+}
+
+//Set the PSW Parity Flag
+INLINE void set_parity()
+{
+ //This flag will be set when the accumulator contains an odd # of bits set..
+ int i,
+ p = 0;
+ for (i=1; i<=128; i=i*2) { //Test for each of the 8 bits in the ACC!
+ if ((R_ACC & i) != 0)
+ p++; //Keep track of how many bits are set
+ }
+
+ //Update the PSW Pairty bit
+ SET_P(p & 1);
+}
+
+static READ8_HANDLER(bit_address_r)
+{
+ int word;
+ int mask;
+ int bit_pos;
+ int base; /* base of bit space or sfr */
+ int distance; /* distance between bit addressable words */
+ /* 1 for normal bits, 8 for sfr bit addresses */
+
+ offset &= 0xff;
+
+ //User defined bit addresses 0x20-0x2f (values are 0x0-0x7f)
+ if (offset < 0x80) {
+ base = 0x20;
+ distance = 1;
+ }
+ //SFR bit addressable registers
+ else {
+ base = 0x80;
+ distance = 8;
+ }
+ word = ( (offset & 0x78) >> 3) * distance + base;
+ bit_pos = offset & 0x7;
+ mask = 0x1 << bit_pos;
+ return((IRAM_R(word) & mask) >> bit_pos); //Do not use IRAM_IR
+}
+
+
+static WRITE8_HANDLER(bit_address_w)
+{
+ int word;
+ int mask;
+ int bit_pos;
+ int result;
+ int base;
+ int distance;
+
+ offset &= 0xff;
+
+ //User defined bit addresses 0x20-0x2f (values are 0x0-0x7f)
+ if (offset < 0x80) {
+ base = 0x20;
+ distance = 1;
+ }
+ //SFR bit addressable registers
+ else {
+ base = 0x80;
+ distance = 8;
+ }
+ word = ((offset & 0x78) >> 3) * distance + base;
+ bit_pos = offset & 0x7;
+ data = (data & 0x1) << bit_pos;
+ mask = ~(1 << bit_pos) & 0xff;
+ result = IRAM_R(word) & mask; //Do not use IRAM_IR
+ result = result | data;
+ IRAM_W(word, result); //Do not use IRAM_IW
+}
+
+/* The following two handlers are used by the MAME Debugger Memory Window...
+ By keeping these functions separate from the internally used IRAM_W/IRAM_R functions,
+ we can manipulate and display internal memory in the debugger memory window in a layout
+ that is not necessarily how the real memory is.. this will be especially useful for
+ the 8052 chip where both the SFR and the upper 128 bytes of ram are mapped to the same
+ address, so we can handle that here by mapping the sfr to a different address */
+
+READ8_HANDLER(i8051_internal_r)
+{
+ //Restrict internal ram to 256 Bytes max
+ if(offset < 0x100)
+ return IRAM_R(offset);
+ else
+ return 0;
+}
+WRITE8_HANDLER(i8051_internal_w)
+{
+ //Restrict internal ram to 256 Bytes max
+ if(offset < 0x100)
+ IRAM_W(offset,data);
+}
+
+INLINE void do_add_flags(UINT8 a, UINT8 data, UINT8 c)
+{
+ UINT16 result = a+data+c;
+ INT16 result1 = (INT8)a+(INT8)data+c;
+ int cy, ac, ov;
+
+ cy = (result & 0x100) >> 8;
+ result = (a&0x0f)+(data&0x0f)+c;
+ ac = (result & 0x10) >> 4;
+ ov = (result1 < -128 || result1 > 127);
+
+ SET_CY(cy);
+ SET_AC(ac);
+ SET_OV(ov);
+
+#ifdef MAME_DEBUG
+// mame_printf_debug("add: result=%x, c=%x, ac=%x, ov=%x\n",a+data+c,cy,ac,ov);
+#endif
+}
+
+INLINE void do_sub_flags(UINT8 a, UINT8 data, UINT8 c)
+{
+ UINT16 result = a-(data+c);
+ INT16 result1 = (INT8)a-(INT8)(data+c);
+ int cy, ac, ov;
+ cy = (result & 0x100) >> 8;
+ result = (a&0x0f)-((data&0x0f)+c);
+ ac = (result & 0x10) >> 4;
+ ov = (result1 < -128 || result1 > 127);
+ SET_CY(cy);
+ SET_AC(ac);
+ SET_OV(ov);
+
+#ifdef MAME_DEBUG
+// mame_printf_debug("sub: a=%x, d=%x, c=%x, result=%x, cy=%x, ac=%x, ov=%x\n",a,data,c,a-data-c,cy,ac,ov);
+#endif
+}
+
+INLINE void update_timer(int cyc)
+{
+ //This code sucks, needs to be rewritten SJE
+
+ //Todo: Probably better to store the current mode of the timer on a write, so we don't waste time reading it.
+
+ //Note: Counting modes increment on 1 machine cycle (12 oscilator periods) - except Timer 2 in certain modes
+
+ //Update Timer 0
+ if(GET_TR0) {
+ //Determine Mode
+ int mode = (GET_M0_1<<1) | GET_M0_0;
+ int overflow;
+ UINT16 count = 0;
+ switch(mode) {
+ case 0: //13 Bit Timer Mode
+ count = ((R_TH0<<8) | R_TL0);
+ overflow = 0x3fff;
+ //Todo - really, we update HI counter when LO counter hits 0x20
+ case 1: //16 Bit Timer Mode
+ count = ((R_TH0<<8) | R_TL0);
+ overflow = 0xffff;
+ //Check for overflow
+ if((UINT32)(count+(cyc/12))>overflow) {
+ //Any overflow from cycles?
+ cyc-= (overflow-count)*12;
+ count = 0;
+ SET_TF0(1);
+ }
+ //Update the timer
+ if(cyc) {
+ int inctimer = 0;
+ //Gate Bit Set? Timer only incremented if Int0 is set!
+ if(GET_GATE0 && GET_IE0)
+ inctimer = (cyc/12);
+ //Counter Mode? Only increment on 1-0 transition of the Port 3's T0 Line
+ if(GET_CT0) {
+ //Not supported
+ }
+ //Neither, regular timer mode
+ if(!GET_GATE0 && !GET_CT0)
+ inctimer = (cyc/12);
+
+ count+=inctimer; //Increment counter
+ }
+ //Update new values of the counter
+ R_TH0 = (count>>8) & 0xff;
+ R_TL0 = count & 0xff;
+ break;
+ case 2: //8 Bit Autoreload
+ overflow = 0xff;
+ count = R_TL0;
+ //Check for overflow
+ if(count+(cyc/12)>overflow) {
+ SET_TF0(1);
+ //Reload
+ count = R_TH0+(overflow-count);
+ }
+ else
+ count+=(cyc/12);
+ //Update new values of the counter
+ R_TL0 = count & 0xff;
+ break;
+ case 3: //Split Timer
+ //Split Timer 1
+ overflow = 0xff;
+ count = R_TL0;
+ //Check for overflow
+ if(count+(cyc/12)>overflow) {
+ count = overflow-count;
+ SET_TF0(1);
+ }
+ else
+ count+=(cyc/12);
+ //Update new values of the counter
+ R_TL0 = count & 0xff;
+
+ //Split Timer 2
+ if(GET_TR1) {
+ overflow = 0xff;
+ count = R_TH0;
+ //Check for overflow
+ if(count+(cyc/12)>overflow) {
+ count = overflow-count;
+ SET_TF1(1);
+ }
+ else
+ count+=(cyc/12);
+ //Update new values of the counter
+ R_TH0 = count & 0xff;
+ }
+ break;
+ }
+ }
+
+ //Update Timer 1
+ if(GET_TR1) {
+ //Determine Mode
+ int mode = (GET_M1_1<<1) | GET_M1_0;
+ int overflow;
+ UINT16 count = 0;
+ switch(mode) {
+ case 0: //13 Bit Timer Mode
+ count = ((R_TH1<<8) | R_TL1);
+ overflow = 0x3fff;
+ //Todo - really, we update HI counter when LO counter hits 0x20
+ case 1: //16 Bit Timer Mode
+ count = ((R_TH1<<8) | R_TL1);
+ overflow = 0xffff;
+ //Check for overflow
+ if((UINT32)(count+(cyc/12))>overflow) {
+
+ //TODO: Timer 1 can be set as Serial Baud Rate in the 8051 only... process bits here..
+
+ //Any overflow from cycles?
+ cyc-= (overflow-count)*12;
+ count = 0;
+ SET_TF1(1);
+ }
+ //Update the timer
+ if(cyc) {
+ int inctimer = 0;
+ //Gate Bit Set? Timer only incremented if Int0 is set!
+ if(GET_GATE1 && GET_IE1)
+ inctimer = (cyc/12);
+ //Counter Mode? Only increment on 1-0 transition of the Port 3's T0 Line
+ if(GET_CT1) {
+ //Not supported
+ }
+ //Neither, regular timer mode
+ if(!GET_GATE1 && !GET_CT1)
+ inctimer = (cyc/12);
+
+ count+=inctimer; //Increment counter
+ }
+ //Update new values of the counter
+ R_TH1 = (count>>8) & 0xff;
+ R_TL1 = count & 0xff;
+ break;
+ case 2: //8 Bit Autoreload
+ overflow = 0xff;
+ count = R_TL1;
+ //Check for overflow
+ if(count+(cyc/12)>overflow) {
+ SET_TF1(1);
+ //Reload
+ count = R_TH1+(overflow-count);
+ }
+ else
+ count+=(cyc/12);
+ //Update new values of the counter
+ R_TL1 = count & 0xff;
+ break;
+ case 3: //Split Timer
+ break;
+ }
+ }
+
+#if (HAS_I8052 || HAS_I8752)
+ //Update Timer 2
+ if(GET_TR2) {
+ int timerinc, overflow, isoverflow;
+ UINT16 count = ((R_TH2<<8) | R_TL2);
+ timerinc = overflow = isoverflow = 0;
+
+ //Are we in counter mode?
+ if(GET_CT2) {
+ //Not supported
+ }
+ //Are we in timer mode?
+ else {
+ //16 Bit Timer Mode
+ overflow = 0xffff;
+ //Timer 2 Used as Baud Generator? (For now, only *same* send/receive rates supported)
+ if(GET_TCLK || GET_RCLK)
+ timerinc = cyc/2; //Timer increments ever 1/2 cycle in baud mode
+ else
+ //REGULAR TIMER -
+ timerinc = cyc/12; //Timer increments ever 1/12 cycles in normal mode
+
+ //Check for overflow
+ if((UINT32)(count+timerinc)>overflow) {
+ //Set Interrupt flag *unless* used as baud generator
+ if(!GET_TCLK && !GET_RCLK) {
+ SET_TF2(1);
+ }
+ else {
+ //Update bits sent if sending & bits left to send!
+ if(uart.sending && uart.bits_to_send && uart.timerbaud)
+ uart.bits_to_send-=1;
+ }
+ //Auto reload?
+ if(!GET_CP)
+ count = ((R_RCAP2H<<8) | R_RCAP2L); //+(overflow-count);
+ else
+ count = overflow-count;
+ }
+ else {
+ //No overflow, just increment timer
+ count+=timerinc;
+ }
+ //Update flags
+ R_TH2 = (count>>8) & 0xff;
+ R_TL2 = count & 0xff;
+ }
+ }
+#endif
+}
+
+//Set up to transmit data out of serial port
+//NOTE: Enable Serial Port Interrupt bit is NOT required to send/receive data!
+INLINE void serial_transmit(UINT8 data)
+{
+ int mode = (GET_SM0<<1) | GET_SM1;
+
+ //Flag that we're sending data
+ uart.sending = 1;
+ uart.data_out = data;
+ switch(mode) {
+ //8 bit shifter ( + start,stop bit ) - baud set by clock freq / 12
+ case 0:
+ uart.timerbaud = 0;
+ uart.bitcycles = 0;
+ uart.bits_to_send = 8+2;
+ break;
+ //8 bit uart ( + start,stop bit ) - baud set by timer1 or timer2
+ case 1:
+ uart.timerbaud = 1;
+ uart.bits_to_send = 8+2;
+ break;
+ //9 bit uart
+ case 2:
+ case 3:
+ LOG(("Serial mode 2 & 3 not supported in i8051!\n"));
+ break;
+ }
+}
+
+//Check and update status of serial port
+INLINE void update_serial(int cyc)
+{
+ //Any bits left to send?
+ if(uart.bits_to_send) {
+ //Timer Generated baud?
+ if(uart.timerbaud) {
+ //Let Timer overflow handle removing bits
+ }
+ else {
+ //Oscillator Based baud rate = Osc/12 baud rate, however it also means 1 bit = 12 cycles.
+ uart.bitcycles+=cyc;
+ if(uart.bitcycles > 11) {
+ int bits_sent = uart.bitcycles / 12;
+ int diff = uart.bitcycles % 12;
+ //don't allow more bits sent than ready to send
+ if(bits_sent > uart.bits_to_send) {
+ bits_sent = uart.bits_to_send;
+ diff = 0;
+ }
+ uart.bits_to_send-=bits_sent;
+ uart.bitcycles = diff;
+ }
+ }
+ }
+ //If no bits left to send - flag the interrupt & call the callback
+ if(!uart.bits_to_send) {
+ //Clear sending flag
+ uart.sending = 0;
+ uart.bitcycles = 0;
+ //Call the callback function
+ if(i8051.serial_tx_callback)
+ i8051.serial_tx_callback(uart.data_out);
+ //Set Interrupt Flag
+ SET_TI(1);
+ //Note: we'll let the main loop catch the interrupt
+ }
+}
+
+
+/****************************************************************************
+ * 8752 Section
+ ****************************************************************************/
+#if (HAS_I8052 || HAS_I8752)
+void i8752_init (int index, int clock, const void *config, int (*irqcallback)(int)) { i8051_init(index, clock, config, irqcallback); }
+void i8752_reset (void)
+{
+ memset(&i8051, 0, sizeof(I8051));
+ memset(&uart, 0, sizeof(I8051_UART));
+ i8051.subtype = 8752;
+
+ //Set up 8052 specific internal read/write (indirect) handlers..
+ i8051.iram_iread = i8052_internal_ram_iread;
+ i8051.iram_iwrite = i8052_internal_ram_iwrite;
+
+ //Set up serial call back handlers
+ i8051.serial_tx_callback = hold_serial_tx_callback;
+ hold_serial_tx_callback = NULL;
+ i8051.serial_rx_callback = hold_serial_rx_callback;
+ hold_serial_rx_callback = NULL;
+
+ //Setup External ram callback handlers
+ i8051.eram_iaddr_callback = hold_eram_iaddr_callback;
+ hold_eram_iaddr_callback = NULL;
+
+ //Clear Ram (w/0xff)
+ memset(&i8051.IntRam,0xff,sizeof(i8051.IntRam));
+
+ /* these are all defined reset states */
+ PC = 0;
+ SFR_W(SP, 0x7);
+ SFR_W(PSW, 0);
+ SFR_W(DPH, 0);
+ SFR_W(DPL, 0);
+ SFR_W(ACC, 0);
+ SFR_W(B, 0);
+ SFR_W(IP, 0);
+ SFR_W(IE, 0);
+ SFR_W(SCON, 0);
+ SFR_W(TCON, 0);
+ SFR_W(TMOD, 0);
+ SFR_W(TH1, 0);
+ SFR_W(TH0, 0);
+ SFR_W(TL1, 0);
+ SFR_W(TL0, 0);
+ //8052 Only registers
+ SFR_W(T2CON, 0);
+ SFR_W(RCAP2L, 0);
+ SFR_W(RCAP2H, 0);
+ SFR_W(TL2, 0);
+ SFR_W(TH2, 0);
+
+ /* set the port configurations to all 1's */
+ SFR_W(P3, 0xff);
+ SFR_W(P2, 0xff);
+ SFR_W(P1, 0xff);
+ SFR_W(P0, 0xff);
+
+ /* Flag as NO IRQ in Progress */
+ CLEAR_CURRENT_IRQ
+}
+
+void i8752_exit (void) { i8051_exit(); }
+int i8752_execute(int cycles) { return i8051_execute(cycles); }
+void i8752_get_context (void *dst) { i8051_get_context(dst); }
+void i8752_set_context (void *src) { i8051_set_context(src); }
+unsigned i8752_get_reg (int regnum) { return i8051_get_reg(regnum); }
+void i8752_set_reg (int regnum, unsigned val) { i8051_set_reg(regnum,val); }
+void i8752_set_irq_line(int irqline, int state) { i8051_set_irq_line(irqline,state); }
+void i8752_set_irq_callback(int (*callback)(int irqline)) { i8051_set_irq_callback(callback); }
+void i8752_set_serial_tx_callback(void (*callback)(int data)) { i8051_set_serial_tx_callback(callback); }
+void i8752_set_serial_rx_callback(int (*callback)(void)) { i8051_set_serial_rx_callback(callback); }
+void i8752_state_save(void *file) { i8051_state_save(file); }
+void i8752_state_load(void *file) { i8051_state_load(file); }
+#if 0
+const char *i8752_info(void *context, int regnum)
+{
+ switch( regnum )
+ {
+ case CPU_INFO_NAME: return "I8752";
+ }
+ return i8051_info(context,regnum);
+}
+#endif
+
+/* The following two handlers are used by the MAME Debugger Memory Window...
+ By keeping these functions separate from the internally used IRAM_W/IRAM_R functions,
+ we can manipulate and display internal memory in the debugger memory window in a layout
+ that is not necessarily how the real memory is.. this will be especially useful for
+ the 8052 chip where both the SFR and the upper 128 bytes of ram are mapped to the same
+ address, so we can handle that here by mapping the sfr to a different address */
+
+READ8_HANDLER(i8752_internal_r)
+{
+ //USE INDIRECT READ TO ALLOW FULL 256 Bytes of RAM to show in the debugger
+ if(offset < 0x100)
+ return IRAM_IR(offset);
+ else
+ //MAP SFR registers starting at 256 (they are only 128 bytes in size)
+ if(offset < 0x100+0x80)
+ return SFR_R(offset-0x80);
+ else
+ //Everything else is 0 (and invalid)
+ return 0;
+}
+WRITE8_HANDLER(i8752_internal_w)
+{
+ //USE INDIRECT WRITE TO ALLOW FULL 256 Bytes of RAM to show in the debugger
+ if(offset < 0x100)
+ IRAM_IW(offset,data);
+ else
+ if(offset < 0x100+0x80)
+ SFR_W(offset-0x80,data);
+}
+
+/* Reads the contents of the Internal RAM memory INDIRECTLY */
+/* Anything above 0x7f is NOT sfr/register, but rather UPPER 128K OF INTERNAL RAM */
+static READ8_HANDLER(i8052_internal_ram_iread)
+{
+ if (offset < 0x100)
+ return i8051.IntRam[offset];
+ else
+ LOG(("i8051 #%d: attemping to read from an invalid Internal Ram address: %x at 0x%04x\n", cpu_getactivecpu(), offset,PC));
+ return 0xff;
+}
+
+/* Writes the contents of the Internal RAM memory INDIRECTLY */
+/* Anything above 0x7f is NOT sfr/register, but rather UPPER 128K OF INTERNAL RAM */
+static WRITE8_HANDLER(i8052_internal_ram_iwrite)
+{
+ data &= 0xff; //Ensure it's only 8 bits
+ if (offset < 0x100)
+ i8051.IntRam[offset] = data;
+ else
+ LOG(("i8051 #%d: attemping to write to an invalid Internal Ram address: %x at 0x%04x\n", cpu_getactivecpu(), offset,PC));
+}
+
+#endif //(HAS_8752)
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void i8051_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_PC: PC = info->i; break;
+ case CPUINFO_INT_SP: i8051.sp = info->i; break;
+
+ case CPUINFO_INT_INPUT_STATE + I8051_INT0_LINE: i8051_set_irq_line(I8051_INT0_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + I8051_INT1_LINE: i8051_set_irq_line(I8051_INT1_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + I8051_T0_LINE: i8051_set_irq_line(I8051_T0_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + I8051_T1_LINE: i8051_set_irq_line(I8051_T1_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + I8051_RX_LINE: i8051_set_irq_line(I8051_RX_LINE, info->i); break;
+
+ case CPUINFO_INT_REGISTER + I8051_PC: PC = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_SP: R_SP = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_PSW: i8051.psw = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_ACC: i8051.acc = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_B: i8051.b = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_DPH: i8051.dph = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_DPL: i8051.dpl = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_IE: i8051.ie = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_R0: i8051.IntRam[0+(8*((i8051.psw & 0x18)>>3))] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_R1: i8051.IntRam[1+(8*((i8051.psw & 0x18)>>3))] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_R2: i8051.IntRam[2+(8*((i8051.psw & 0x18)>>3))] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_R3: i8051.IntRam[3+(8*((i8051.psw & 0x18)>>3))] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_R4: i8051.IntRam[4+(8*((i8051.psw & 0x18)>>3))] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_R5: i8051.IntRam[5+(8*((i8051.psw & 0x18)>>3))] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_R6: i8051.IntRam[6+(8*((i8051.psw & 0x18)>>3))] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_R7: i8051.IntRam[7+(8*((i8051.psw & 0x18)>>3))] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_RB: i8051.IntRam[8+(8*((i8051.psw & 0x18)>>3))] = info->i; break;
+ }
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void i8051_get_info(UINT32 state, cpuinfo *info)
+{
+ I8051 *r = &i8051;
+
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(i8051); break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 5; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 20; /* rough guess */ break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 3; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = PPC; break;
+ case CPUINFO_INT_PC: info->i = PC; break;
+ case CPUINFO_INT_SP: info->i = R_SP; break;
+
+ case CPUINFO_INT_REGISTER + I8051_PC: info->i = PC; break;
+ case CPUINFO_INT_REGISTER + I8051_SP: info->i = R_SP; break;
+ case CPUINFO_INT_REGISTER + I8051_PSW: info->i = i8051.psw; break;
+ case CPUINFO_INT_REGISTER + I8051_ACC: info->i = i8051.acc; break;
+ case CPUINFO_INT_REGISTER + I8051_B: info->i = i8051.b; break;
+ case CPUINFO_INT_REGISTER + I8051_DPH: info->i = i8051.dph; break;
+ case CPUINFO_INT_REGISTER + I8051_DPL: info->i = i8051.dpl; break;
+ case CPUINFO_INT_REGISTER + I8051_IE: info->i = i8051.ie; break;
+ case CPUINFO_INT_REGISTER + I8051_R0: info->i = i8051.IntRam[0+(8*((i8051.psw & 0x18)>>3))]; break;
+ case CPUINFO_INT_REGISTER + I8051_R1: info->i = i8051.IntRam[1+(8*((i8051.psw & 0x18)>>3))]; break;
+ case CPUINFO_INT_REGISTER + I8051_R2: info->i = i8051.IntRam[2+(8*((i8051.psw & 0x18)>>3))]; break;
+ case CPUINFO_INT_REGISTER + I8051_R3: info->i = i8051.IntRam[3+(8*((i8051.psw & 0x18)>>3))]; break;
+ case CPUINFO_INT_REGISTER + I8051_R4: info->i = i8051.IntRam[4+(8*((i8051.psw & 0x18)>>3))]; break;
+ case CPUINFO_INT_REGISTER + I8051_R5: info->i = i8051.IntRam[5+(8*((i8051.psw & 0x18)>>3))]; break;
+ case CPUINFO_INT_REGISTER + I8051_R6: info->i = i8051.IntRam[6+(8*((i8051.psw & 0x18)>>3))]; break;
+ case CPUINFO_INT_REGISTER + I8051_R7: info->i = i8051.IntRam[7+(8*((i8051.psw & 0x18)>>3))]; break;
+ case CPUINFO_INT_REGISTER + I8051_RB: info->i = i8051.IntRam[8+(8*((i8051.psw & 0x18)>>3))]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = i8051_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = i8051_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = i8051_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = i8051_init; break;
+ case CPUINFO_PTR_RESET: info->reset = i8051_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = i8051_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = i8051_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = i8051_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &i8051_icount; break;
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = 0; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_DATA: info->internal_map = 0; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_IO: info->internal_map = 0; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "I8051"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "MCS-51"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (c) 2003-2004 Steve Ellenoff"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ r->psw & 0x80 ? 'C':'.',
+ r->psw & 0x40 ? 'A':'.',
+ r->psw & 0x20 ? 'F':'.',
+ r->psw & 0x10 ? '0':'.',
+ r->psw & 0x08 ? '1':'.',
+ r->psw & 0x04 ? 'V':'.',
+ r->psw & 0x02 ? '?':'.',
+ r->psw & 0x01 ? 'P':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + I8051_PC: sprintf(info->s, "PC:%04X", r->pc); break;
+ case CPUINFO_STR_REGISTER + I8051_SP: sprintf(info->s, "SP:%02X", r->sp); break;
+ case CPUINFO_STR_REGISTER + I8051_PSW: sprintf(info->s, "PSW:%02X", r->psw); break;
+ case CPUINFO_STR_REGISTER + I8051_ACC: sprintf(info->s, "A:%02X", r->acc); break;
+ case CPUINFO_STR_REGISTER + I8051_B: sprintf(info->s, "B:%02X", r->b); break;
+ case CPUINFO_STR_REGISTER + I8051_DPH: sprintf(info->s, "DPH:%02X", r->dph); break;
+ case CPUINFO_STR_REGISTER + I8051_DPL: sprintf(info->s, "DPL:%02X", r->dpl); break;
+ case CPUINFO_STR_REGISTER + I8051_IE: sprintf(info->s, "IE:%02X", r->ie); break;
+ case CPUINFO_STR_REGISTER + I8051_R0: sprintf(info->s, "R0:%02X", r->IntRam[0+(8*((r->psw & 0x18)>>3))]); break;
+ case CPUINFO_STR_REGISTER + I8051_R1: sprintf(info->s, "R1:%02X", r->IntRam[1+(8*((r->psw & 0x18)>>3))]); break;
+ case CPUINFO_STR_REGISTER + I8051_R2: sprintf(info->s, "R2:%02X", r->IntRam[2+(8*((r->psw & 0x18)>>3))]); break;
+ case CPUINFO_STR_REGISTER + I8051_R3: sprintf(info->s, "R3:%02X", r->IntRam[3+(8*((r->psw & 0x18)>>3))]); break;
+ case CPUINFO_STR_REGISTER + I8051_R4: sprintf(info->s, "R4:%02X", r->IntRam[4+(8*((r->psw & 0x18)>>3))]); break;
+ case CPUINFO_STR_REGISTER + I8051_R5: sprintf(info->s, "R5:%02X", r->IntRam[5+(8*((r->psw & 0x18)>>3))]); break;
+ case CPUINFO_STR_REGISTER + I8051_R6: sprintf(info->s, "R6:%02X", r->IntRam[6+(8*((r->psw & 0x18)>>3))]); break;
+ case CPUINFO_STR_REGISTER + I8051_R7: sprintf(info->s, "R7:%02X", r->IntRam[7+(8*((r->psw & 0x18)>>3))]); break;
+ case CPUINFO_STR_REGISTER + I8051_RB: sprintf(info->s, "RB:%02X", ((r->psw & 0x18)>>3)); break;
+ }
+}
+
+#if (HAS_I8052)
+void i8052_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = i8752_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = i8752_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = i8752_init; break;
+ case CPUINFO_PTR_RESET: info->reset = i8752_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = i8752_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = i8752_execute; break;
+
+ case CPUINFO_STR_NAME: strcpy(info->s, "I8052"); break;
+
+ default: i8051_get_info(state, info); break;
+ }
+}
+#endif
+
+#if (HAS_I8751)
+void i8751_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_STR_NAME: strcpy(info->s, "I8751"); break;
+
+ default: i8051_get_info(state, info); break;
+ }
+}
+#endif
+
+#if (HAS_I8752)
+void i8752_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = i8752_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = i8752_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = i8752_init; break;
+ case CPUINFO_PTR_RESET: info->reset = i8752_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = i8752_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = i8752_execute; break;
+
+ case CPUINFO_STR_NAME: strcpy(info->s, "I8752"); break;
+
+ default: i8051_get_info(state, info); break;
+ }
+}
+#endif
diff --git a/src/emu/cpu/i8051/i8051.h b/src/emu/cpu/i8051/i8051.h
new file mode 100644
index 00000000000..6b5178d3400
--- /dev/null
+++ b/src/emu/cpu/i8051/i8051.h
@@ -0,0 +1,157 @@
+/*****************************************************************************
+ *
+ * i8051.h
+ * Portable MCS-51 Family Emulator
+ *
+ * Chips in the family:
+ * 8051 Product Line (8031,8051,8751)
+ * 8052 Product Line (8032,8052,8752)
+ * 8054 Product Line (8054)
+ * 8058 Product Line (8058)
+ *
+ * Copyright (c) 2003 Steve Ellenoff, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * sellenoff@hotmail.com
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * This work is based on:
+ * #1) 'Intel(tm) MC51 Microcontroller Family Users Manual' and
+ * #2) 8051 simulator by Travis Marlatte
+ * #3) Portable UPI-41/8041/8741/8042/8742 emulator V0.1 by Juergen Buchmueller (MAME CORE)
+ *
+ *****************************************************************************/
+
+#ifndef _I8051_H
+#define _I8051_H
+
+#include "cpuintrf.h"
+
+enum {
+ I8051_PC=1, I8051_SP, I8051_PSW, I8051_ACC, I8051_B, I8051_DPH, I8051_DPL, I8051_IE,
+ I8051_R0, I8051_R1, I8051_R2, I8051_R3, I8051_R4, I8051_R5, I8051_R6, I8051_R7, I8051_RB
+};
+
+#define I8051_INT0_LINE 0 /* External Interrupt 0 */
+#define I8051_INT1_LINE 1 /* External Interrupt 1 */
+#define I8051_T0_LINE 2 /* Timer 0 External Input */
+#define I8051_T1_LINE 3 /* Timer 1 External Input */
+#define I8051_RX_LINE 4 /* Serial Port Receive Line */
+
+/* definition of the special function registers. Note that the values are */
+/* the same as the internal memory address in the 8051 */
+#define P0 0x80
+#define SP 0x81
+#define DPL 0x82
+#define DPH 0x83
+#define PCON 0x87
+#define TCON 0x88
+#define TMOD 0x89
+#define TL0 0x8a
+#define TL1 0x8b
+#define TH0 0x8c
+#define TH1 0x8d
+#define P1 0x90
+#define SCON 0x98
+#define SBUF 0x99
+#define P2 0xa0
+#define IE 0xa8
+#define P3 0xb0
+#define IP 0xb8
+//8052 Only registers
+#if (HAS_I8052 || HAS_I8752)
+ #define T2CON 0xc8
+ #define RCAP2L 0xca
+ #define RCAP2H 0xcb
+ #define TL2 0xcc
+ #define TH2 0xcd
+#endif
+#define PSW 0xd0
+#define ACC 0xe0
+#define B 0xf0
+
+/* commonly used bit address for the 8051 */
+#define C 0xd7
+#define P 0xd0
+#define AC 0xd6
+#define OV 0xd2
+#define TF0 0x8d
+#define TF1 0x8f
+#define IE0 0x89
+#define IE1 0x8b
+#define TI 0x99
+#define RI 0x98
+
+#define TI_FLAG 1
+#define RI_FLAG 2
+
+extern int i8051_icount; /* cycle count */
+
+extern void i8051_init (int index, int clock, const void *config, int (*irqcallback)(int)); /* Initialize save states */
+extern void i8051_reset (void); /* Reset registers to the initial values */
+extern void i8051_exit (void); /* Shut down CPU core */
+extern int i8051_execute(int cycles); /* Execute cycles - returns number of cycles actually run */
+extern void i8051_get_context (void *dst); /* Get registers, return context size */
+extern void i8051_set_context (void *src); /* Set registers */
+extern unsigned i8051_get_intram (int offset);
+extern unsigned i8051_get_reg (int regnum);
+extern void i8051_set_reg (int regnum, unsigned val);
+extern void i8051_set_irq_line(int irqline, int state);
+extern void i8051_set_irq_callback(int (*callback)(int irqline));
+extern void i8051_state_save(void *file);
+extern void i8051_state_load(void *file);
+extern const char *i8051_info(void *context, int regnum);
+
+WRITE8_HANDLER( i8051_internal_w );
+READ8_HANDLER( i8051_internal_r );
+
+extern void i8051_set_serial_tx_callback(void (*callback)(int data));
+extern void i8051_set_serial_rx_callback(int (*callback)(void));
+extern void i8051_set_eram_iaddr_callback(READ32_HANDLER((*callback)));
+
+#ifdef MAME_DEBUG
+extern offs_t i8051_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif /* MAME_DEBUG */
+
+/****************************************************************************
+ * 8752 Section
+ ****************************************************************************/
+#if (HAS_I8752)
+#define i8752_icount i8051_icount
+
+extern void i8752_init (int index, int clock, const void *config, int (*irqcallback)(int)); /* Initialize save states */
+extern void i8752_reset (void); /* Reset registers to the initial values */
+extern void i8752_exit (void); /* Shut down CPU core */
+extern int i8752_execute(int cycles); /* Execute cycles - returns number of cycles actually run */
+extern void i8752_get_context (void *dst); /* Get registers, return context size */
+extern void i8752_set_context (void *src); /* Set registers */
+extern unsigned i8752_get_reg (int regnum);
+extern void i8752_set_reg (int regnum, unsigned val);
+extern void i8752_set_irq_line(int irqline, int state);
+extern void i8752_set_irq_callback(int (*callback)(int irqline));
+extern void i8752_state_save(void *file);
+extern void i8752_state_load(void *file);
+extern const char *i8752_info(void *context, int regnum);
+extern void i8752_set_serial_tx_callback(void (*callback)(int data));
+extern void i8752_set_serial_rx_callback(int (*callback)(void));
+WRITE8_HANDLER( i8752_internal_w );
+READ8_HANDLER( i8752_internal_r );
+#endif //(HAS_8752)
+
+
+void i8051_get_info(UINT32 state, cpuinfo *info);
+void i8052_get_info(UINT32 state, cpuinfo *info);
+void i8751_get_info(UINT32 state, cpuinfo *info);
+void i8752_get_info(UINT32 state, cpuinfo *info);
+
+#endif /* _I8051_H */
+
+
diff --git a/src/emu/cpu/i8051/i8051ops.c b/src/emu/cpu/i8051/i8051ops.c
new file mode 100644
index 00000000000..ce1d5a76349
--- /dev/null
+++ b/src/emu/cpu/i8051/i8051ops.c
@@ -0,0 +1,960 @@
+/*******************************************************************************************
+ NOTE: All registers are accessed directly, instead of using the SFR_R() function for speed
+ Direct register access is availabe from the R_(register name) macros.. ex: R_ACC for the ACC
+ with the exception of the PC
+********************************************************************************************/
+
+//ACALL code addr /* 1: aaa1 0001 */
+INLINE void acall(void)
+{
+ UINT8 op = ROP(PC-1); //Grab the opcode for ACALL
+ UINT8 addr = ROP_ARG(PC++); //Grab code address byte
+ PUSH_PC //Save PC to the stack
+ //Thanks Gerrit for help with this! :)
+ PC = (PC & 0xf800) | ((op & 0xe0) << 3) | addr;
+}
+
+//ADD A, #data /* 1: 0010 0100 */
+INLINE void add_a_byte(void)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ UINT8 result = R_ACC + data; //Add data to accumulator
+ DO_ADD_FLAGS(R_ACC,data,0) //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//ADD A, data addr /* 1: 0010 0101 */
+INLINE void add_a_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr); //Grab data from data address
+ UINT8 result = R_ACC + data; //Add data to accumulator
+ DO_ADD_FLAGS(R_ACC,data,0); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//ADD A, @R0/@R1 /* 1: 0010 011i */
+INLINE void add_a_ir(int r)
+{
+ UINT8 data = IRAM_IR(R_R(r)); //Grab data from memory pointed to by R0 or R1
+ UINT8 result = R_ACC + data; //Add data to accumulator
+ DO_ADD_FLAGS(R_ACC,data,0); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//ADD A, R0 to R7 /* 1: 0010 1rrr */
+INLINE void add_a_r(int r)
+{
+ UINT8 data = R_R(r); //Grab data from R0 - R7
+ UINT8 result = R_ACC + data; //Add data to accumulator
+ DO_ADD_FLAGS(R_ACC,data,0); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//ADDC A, #data /* 1: 0011 0100 */
+INLINE void addc_a_byte(void)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ UINT8 result = R_ACC + data + GET_CY; //Add data + carry flag to accumulator
+ DO_ADD_FLAGS(R_ACC,data,GET_CY); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//ADDC A, data addr /* 1: 0011 0101 */
+INLINE void addc_a_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr); //Grab data from data address
+ UINT8 result = R_ACC + data + GET_CY; //Add data + carry flag to accumulator
+ DO_ADD_FLAGS(R_ACC,data,GET_CY); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//ADDC A, @R0/@R1 /* 1: 0011 011i */
+INLINE void addc_a_ir(int r)
+{
+ UINT8 data = IRAM_IR(R_R(r)); //Grab data from memory pointed to by R0 or R1
+ UINT8 result = R_ACC + data + GET_CY; //Add data + carry flag to accumulator
+ DO_ADD_FLAGS(R_ACC,data,GET_CY); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//ADDC A, R0 to R7 /* 1: 0011 1rrr */
+INLINE void addc_a_r(int r)
+{
+ UINT8 data = R_R(r); //Grab data from R0 - R7
+ UINT8 result = R_ACC + data + GET_CY; //Add data + carry flag to accumulator
+ DO_ADD_FLAGS(R_ACC,data,GET_CY); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//AJMP code addr /* 1: aaa0 0001 */
+INLINE void ajmp(void)
+{
+ UINT8 op = ROP(PC-1); //Grab the opcode for AJMP
+ UINT8 addr = ROP_ARG(PC++); //Grab code address byte
+ //Thanks Gerrit for help with this! :)
+ PC = (PC & 0xf800) | ((op & 0xe0) << 3) | addr;
+}
+
+//ANL data addr, A /* 1: 0101 0010 */
+INLINE void anl_mem_a(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr); //Grab data from data address
+ IRAM_W(addr,data & R_ACC); //Set data address value to it's value Logical AND with ACC
+}
+
+//ANL data addr, #data /* 1: 0101 0011 */
+INLINE void anl_mem_byte(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ UINT8 srcdata = IRAM_R(addr); //Grab data from data address
+ IRAM_W(addr,srcdata & data); //Set data address value to it's value Logical AND with Data
+}
+
+//ANL A, #data /* 1: 0101 0100 */
+INLINE void anl_a_byte(void)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ SFR_W(ACC,R_ACC & data); //Set ACC to value of ACC Logical AND with Data
+}
+
+//ANL A, data addr /* 1: 0101 0101 */
+INLINE void anl_a_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr); //Grab data from data address
+ SFR_W(ACC,R_ACC & data); //Set ACC to value of ACC Logical AND with Data
+}
+
+//ANL A, @RO/@R1 /* 1: 0101 011i */
+INLINE void anl_a_ir(int r)
+{
+ UINT8 data = IRAM_IR(R_R(r)); //Grab data from address R0 or R1 points to
+ SFR_W(ACC,R_ACC & data); //Set ACC to value of ACC Logical AND with Data
+}
+
+//ANL A, RO to R7 /* 1: 0101 1rrr */
+INLINE void anl_a_r(int r)
+{
+ UINT8 data = R_R(r); //Grab data from R0 - R7
+ SFR_W(ACC,R_ACC & data); //Set ACC to value of ACC Logical AND with Data
+}
+
+//ANL C, bit addr /* 1: 1000 0010 */
+INLINE void anl_c_bitaddr(void)
+{
+ int cy = GET_CY;
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ UINT8 bit = BIT_R(addr); //Grab bit data from bit address
+ SET_CY( (cy & bit) ); //Set Carry flag to Carry Flag Value Logical AND with Bit
+}
+
+//ANL C,/bit addr /* 1: 1011 0000 */
+INLINE void anl_c_nbitaddr(void)
+{
+ int cy = GET_CY;
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ UINT8 bit = BIT_R(addr); //Grab bit data from bit address
+ bit = ((~bit)&1); //Complement bit
+ SET_CY( (cy & bit) ); //Set Carry flag to Carry Flag Value Logical AND with Complemented Bit
+}
+
+//CJNE A, #data, code addr /* 1: 1011 0100 */
+INLINE void cjne_a_byte(void)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+
+ if(R_ACC != data) //Jump if values are not equal
+ PC = PC + rel_addr;
+
+ //Set carry flag to 1 if 1st compare value is < 2nd compare value
+ SET_CY( (R_ACC < data) );
+}
+
+//CJNE A, data addr, code addr /* 1: 1011 0101 */
+INLINE void cjne_a_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ UINT8 data = IRAM_R(addr); //Pull value from data address
+
+ if(R_ACC != data) //Jump if values are not equal
+ PC = PC + rel_addr;
+
+ //Set carry flag to 1 if 1st compare value is < 2nd compare value
+ SET_CY( (R_ACC < data) );
+}
+
+//CJNE @R0/@R1, #data, code addr /* 1: 1011 011i */
+INLINE void cjne_ir_byte(int r)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ UINT8 srcdata = IRAM_IR(R_R(r)); //Grab value pointed to by R0 or R1
+
+ if(srcdata != data) //Jump if values are not equal
+ PC = PC + rel_addr;
+
+ //Set carry flag to 1 if 1st compare value is < 2nd compare value
+ SET_CY( (srcdata < data) );
+}
+
+//CJNE R0 to R7, #data, code addr /* 1: 1011 1rrr */
+INLINE void cjne_r_byte(int r)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ UINT8 srcdata = R_R(r); //Grab value of R0 - R7
+
+ if(srcdata != data) //Jump if values are not equal
+ PC = PC + rel_addr;
+
+ //Set carry flag to 1 if 1st compare value is < 2nd compare value
+ SET_CY( (srcdata < data) );
+}
+
+//CLR bit addr /* 1: 1100 0010 */
+INLINE void clr_bitaddr(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ BIT_W(addr,0); //Clear bit at specified bit address
+}
+
+//CLR C /* 1: 1100 0011 */
+INLINE void clr_c(void)
+{
+ SET_CY(0); //Clear Carry Flag
+}
+
+//CLR A /* 1: 1110 0100 */
+INLINE void clr_a(void)
+{
+ SFR_W(ACC,0); //Clear Accumulator
+}
+
+//CPL bit addr /* 1: 1011 0010 */
+INLINE void cpl_bitaddr(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ UINT8 data = (~BIT_R(addr))&1;
+ BIT_W(addr,data); //Complement bit at specified bit address
+}
+
+//CPL C /* 1: 1011 0011 */
+INLINE void cpl_c(void)
+{
+ UINT8 bit = (~GET_CY)&1; //Complement Carry Flag
+ SET_CY(bit);
+}
+
+//CPL A /* 1: 1111 0100 */
+INLINE void cpl_a(void)
+{
+ UINT8 data = ((~R_ACC)&0xff);
+ SFR_W(ACC,data); //Complement Accumulator
+}
+
+//DA A /* 1: 1101 0100 */
+INLINE void da_a(void)
+{
+/*From several sources, since none said the same thing:
+ The decimal adjust instruction is associated with the use of the ADD and ADDC instructions.
+ The eight-bit value in the accumulator is adjusted to form two BCD digits of four bits each.
+ If the accumulator contents bits 0-3 are greater than 9, OR the AC flag is set, then six is added to
+ produce a proper BCD digit.
+ If the carry is set, OR the four high bits 4-7 exceed nine, six is added to the value of these bits.
+ The carry flag will be set if the result is > 0x99, but not cleared otherwise */
+
+ UINT16 new_acc = R_ACC & 0xff;
+ if(GET_AC || (R_ACC & 0x0f) > 0x09)
+ new_acc += 0x06;
+ if(GET_CY || (R_ACC & 0xf0) > 0x90)
+ new_acc += 0x60;
+ SFR_W(ACC,new_acc&0xff);
+ if(new_acc & ~0xff)
+ SET_CY(1);
+}
+
+//DEC A /* 1: 0001 0100 */
+INLINE void dec_a(void)
+{
+ SFR_W(ACC,R_ACC-1);
+}
+
+//DEC data addr /* 1: 0001 0101 */
+INLINE void dec_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr);
+ IRAM_W(addr,data-1);
+}
+
+//DEC @R0/@R1 /* 1: 0001 011i */
+INLINE void dec_ir(int r)
+{
+ UINT8 data = IRAM_IR(R_R(r));
+ IRAM_W(R_R(r),data-1);
+}
+
+//DEC R0 to R7 /* 1: 0001 1rrr */
+INLINE void dec_r(int r)
+{
+ R_R(r) = R_R(r) - 1;
+}
+
+//DIV AB /* 1: 1000 0100 */
+INLINE void div_ab(void)
+{
+ if( R_B == 0 ) {
+ //Overflow flag is set!
+ SET_OV(1);
+ //Really the values are undefined according to the manual, but we'll just leave them as is..
+ //SFR_W(ACC,0xff);
+ //SFR_W(B,0xff);
+ }
+ else {
+ int a = (int)R_ACC/R_B;
+ int b = (int)R_ACC%R_B;
+ //A gets quotient byte, B gets remainder byte
+ SFR_W(ACC,a);
+ SFR_W(B, b);
+ //Overflow flag is cleared
+ SET_OV(0);
+ }
+ //Carry Flag is always cleared
+ SET_CY(0);
+}
+
+//DJNZ data addr, code addr /* 1: 1101 0101 */
+INLINE void djnz_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ IRAM_W(addr,IRAM_R(addr) - 1); //Decrement value contained at data address
+ if(IRAM_R(addr) != 0) //Branch if contents of data address is not 0
+ PC = PC + rel_addr;
+}
+
+//DJNZ R0 to R7,code addr /* 1: 1101 1rrr */
+INLINE void djnz_r(int r)
+{
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ R_R(r) = R_R(r) - 1; //Decrement value
+ if(R_R(r) != 0) //Branch if contents of R0 - R7 is not 0
+ PC = PC + rel_addr;
+}
+
+//INC A /* 1: 0000 0100 */
+INLINE void inc_a(void)
+{
+ SFR_W(ACC,R_ACC+1);
+}
+
+//INC data addr /* 1: 0000 0101 */
+INLINE void inc_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr);
+ IRAM_W(addr,data+1);
+}
+
+//INC @R0/@R1 /* 1: 0000 011i */
+INLINE void inc_ir(int r)
+{
+ UINT8 data = IRAM_IR(R_R(r));
+ IRAM_W(R_R(r),data+1);
+}
+
+//INC R0 to R7 /* 1: 0000 1rrr */
+INLINE void inc_r(int r)
+{
+ UINT8 data = R_R(r);
+ R_R(r) = data + 1;
+}
+
+//INC DPTR /* 1: 1010 0011 */
+INLINE void inc_dptr(void)
+{
+ UINT16 dptr = (R_DPTR)+1;
+ DPTR_W(dptr);
+}
+
+//JB bit addr, code addr /* 1: 0010 0000 */
+INLINE void jb(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ if(BIT_R(addr)) //If bit set at specified bit address, jump
+ PC = PC + rel_addr;
+}
+
+//JBC bit addr, code addr /* 1: 0001 0000 */
+INLINE void jbc(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ if(BIT_R(addr)) { //If bit set at specified bit address, jump
+ PC = PC + rel_addr;
+ BIT_W(addr,0); //Clear Bit also
+ }
+}
+
+//JC code addr /* 1: 0100 0000 */
+INLINE void jc(void)
+{
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ if(GET_CY) //Jump if Carry Flag Set
+ PC = PC + rel_addr;
+}
+
+//JMP @A+DPTR /* 1: 0111 0011 */
+INLINE void jmp_iadptr(void)
+{
+ PC = R_ACC+R_DPTR;
+}
+
+//JNB bit addr, code addr /* 1: 0011 0000 */
+INLINE void jnb(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ if(!BIT_R(addr)) //If bit NOT set at specified bit address, jump
+ PC = PC + rel_addr;
+}
+
+//JNC code addr /* 1: 0101 0000 */
+INLINE void jnc(void)
+{
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ if(!GET_CY) //Jump if Carry Flag not set
+ PC = PC + rel_addr;
+}
+
+//JNZ code addr /* 1: 0111 0000 */
+INLINE void jnz(void)
+{
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ if(R_ACC != 0) //Branch if ACC is not 0
+ PC = PC+rel_addr;
+}
+
+//JZ code addr /* 1: 0110 0000 */
+INLINE void jz(void)
+{
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ if(R_ACC == 0) //Branch if ACC is 0
+ PC = PC+rel_addr;
+}
+
+//LCALL code addr /* 1: 0001 0010 */
+INLINE void lcall(void)
+{
+ UINT8 addr_hi, addr_lo;
+ addr_hi = ROP_ARG(PC++);
+ addr_lo = ROP_ARG(PC++);
+ PUSH_PC
+ PC = (UINT16)((addr_hi<<8) | addr_lo);
+}
+
+//LJMP code addr /* 1: 0000 0010 */
+INLINE void ljmp(void)
+{
+ UINT8 addr_hi, addr_lo;
+ addr_hi = ROP_ARG(PC++);
+ addr_lo = ROP_ARG(PC++);
+ PC = (UINT16)((addr_hi<<8) | addr_lo);
+}
+
+//MOV A, #data /* 1: 0111 0100 */
+INLINE void mov_a_byte(void)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ SFR_W(ACC,data); //Store data to ACC
+}
+
+//MOV A, data addr /* 1: 1110 0101 */
+INLINE void mov_a_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ SFR_W(ACC,IRAM_R(addr)); //Store contents of data address to ACC
+}
+
+//MOV A,@RO/@R1 /* 1: 1110 011i */
+INLINE void mov_a_ir(int r)
+{
+ SFR_W(ACC,IRAM_IR(R_R(r))); //Store contents of address pointed by R0 or R1 to ACC
+}
+
+//MOV A,R0 to R7 /* 1: 1110 1rrr */
+INLINE void mov_a_r(int r)
+{
+ SFR_W(ACC,R_R(r)); //Store contents of R0 - R7 to ACC
+}
+
+//MOV data addr, #data /* 1: 0111 0101 */
+INLINE void mov_mem_byte(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ IRAM_W(addr,data); //Store data to data address location
+}
+
+//MOV data addr, data addr /* 1: 1000 0101 */
+INLINE void mov_mem_mem(void)
+{
+ //1st address is src, 2nd is dst, but the mov command works as mov dst,src)
+ UINT8 src,dst;
+ src = ROP_ARG(PC++); //Grab source data address
+ dst = ROP_ARG(PC++); //Grab destination data address
+ IRAM_W(dst,IRAM_R(src)); //Read source address contents and store to destination address
+}
+
+//MOV @R0/@R1, #data /* 1: 0111 011i */
+INLINE void mov_ir_byte(int r)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ IRAM_IW(R_R(r),data); //Store data to address pointed by R0 or R1
+}
+
+//MOV R0 to R7, #data /* 1: 0111 1rrr */
+INLINE void mov_r_byte(int r)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ R_R(r) = data; //Store to R0 - R7
+}
+
+//MOV data addr, @R0/@R1 /* 1: 1000 011i */
+INLINE void mov_mem_ir(int r)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ IRAM_W(addr,IRAM_IR(R_R(r))); //Store contents pointed to by R0 or R1 to data address
+}
+
+//MOV data addr,R0 to R7 /* 1: 1000 1rrr */
+INLINE void mov_mem_r(int r)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ IRAM_W(addr,R_R(r)); //Store contents of R0 - R7 to data address
+}
+
+//MOV DPTR, #data16 /* 1: 1001 0000 */
+INLINE void mov_dptr_byte(void)
+{
+ UINT8 data_hi, data_lo;
+ data_hi = ROP_ARG(PC++); //Grab hi byte
+ data_lo = ROP_ARG(PC++); //Grab lo byte
+ DPTR_W((UINT16)((data_hi<<8)|data_lo)); //Store to DPTR
+}
+
+//MOV bit addr, C /* 1: 1001 0010 */
+INLINE void mov_bitaddr_c(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ BIT_W(addr,GET_CY); //Store Carry Flag to Bit Address
+}
+
+//MOV @R0/@R1, data addr /* 1: 1010 011i */
+INLINE void mov_ir_mem(int r)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ IRAM_IW(R_R(r),IRAM_R(addr)); //Store data from data address to address pointed to by R0 or R1
+}
+
+//MOV R0 to R7, data addr /* 1: 1010 1rrr */
+INLINE void mov_r_mem(int r)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ R_R(r) = IRAM_R(addr); //Store to R0 - R7
+}
+
+//MOV data addr, A /* 1: 1111 0101 */
+INLINE void mov_mem_a(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ IRAM_W(addr,R_ACC); //Store A to data address
+}
+
+//MOV @R0/@R1, A /* 1: 1111 011i */
+INLINE void mov_ir_a(int r)
+{
+ IRAM_IW(R_R(r),R_ACC); //Store A to location pointed to by R0 or R1
+}
+
+//MOV R0 to R7, A /* 1: 1111 1rrr */
+INLINE void mov_r_a(int r)
+{
+ R_R(r) = R_ACC; //Store A to R0-R7
+}
+
+//MOVC A, @A + PC /* 1: 1000 0011 */
+INLINE void movc_a_iapc(void)
+{
+ UINT8 data;
+ data = CODEMEM_R(R_ACC+PC); //Move a byte from CODE(Program) Memory and store to ACC
+ SFR_W(ACC,data);
+}
+
+//MOV C, bit addr /* 1: 1010 0010 */
+INLINE void mov_c_bitaddr(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ SET_CY( (BIT_R(addr)) ); //Store Bit from Bit Address to Carry Flag
+}
+
+//MOVC A, @A + DPTR /* 1: 1001 0011 */
+INLINE void movc_a_iadptr(void)
+{
+ UINT8 data;
+ data = CODEMEM_R(R_ACC+R_DPTR); //Move a byte from CODE(Program) Memory and store to ACC
+ SFR_W(ACC,data);
+}
+
+//MOVX A,@DPTR /* 1: 1110 0000 */
+//(Move External Ram 16 bit address to A)
+INLINE void movx_a_idptr(void)
+{
+// UINT8 byte = DATAMEM_R(R_DPTR); //Grab 1 byte from External DATA memory pointed to by dptr
+ UINT32 addr = ERAM_ADDR(R_DPTR,0xFFFF);
+ UINT8 byte = DATAMEM_R(addr); //Grab 1 byte from External DATA memory pointed to by dptr
+ SFR_W(ACC,byte); //Store to ACC
+}
+
+//MOVX A, @R0/@R1 /* 1: 1110 001i */
+//(Move External Ram 8 bit address to A)
+INLINE void movx_a_ir(int r)
+{
+ UINT32 addr = ERAM_ADDR(R_R(r),0xFF); //Grab address by reading location pointed to by R0 or R1
+ UINT8 byte = DATAMEM_R(addr); //Grab 1 byte from External DATA memory pointed to by address
+ SFR_W(ACC,byte); //Store to ACC
+}
+
+//MOVX @DPTR,A /* 1: 1111 0000 */
+//(Move A to External Ram 16 bit address)
+INLINE void movx_idptr_a(void)
+{
+// DATAMEM_W(R_DPTR, R_ACC); //Store ACC to External DATA memory address pointed to by DPTR
+ UINT32 addr = ERAM_ADDR(R_DPTR,0xFFFF);
+ DATAMEM_W(addr, R_ACC); //Store ACC to External DATA memory address pointed to by DPTR
+}
+
+//MOVX @R0/@R1,A /* 1: 1111 001i */
+//(Move A to External Ram 8 bit address)
+INLINE void movx_ir_a(int r)
+{
+ UINT32 addr = ERAM_ADDR(R_R(r),0xFF); //Grab address by reading location pointed to by R0 or R1
+ DATAMEM_W(addr, R_ACC); //Store ACC to External DATA memory address
+}
+
+//MUL AB /* 1: 1010 0100 */
+INLINE void mul_ab(void)
+{
+ UINT16 result = R_ACC * R_B;
+ //A gets lo bits, B gets hi bits of result
+ SFR_W(B,(UINT8)((result & 0xFF00) >> 8));
+ SFR_W(ACC,(UINT8)(result & 0x00FF));
+ //Set flags
+ SET_OV( ((result & 0x100) >> 8) ); //Set/Clear Overflow Flag if result > 255
+ SET_CY(0); //Carry Flag always cleared
+}
+
+//NOP /* 1: 0000 0000 */
+INLINE void nop(void)
+{
+}
+
+//ORL data addr, A /* 1: 0100 0010 */
+INLINE void orl_mem_a(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr); //Grab data from data address
+ IRAM_W(addr,data | R_ACC); //Set data address value to it's value Logical OR with ACC
+}
+
+//ORL data addr, #data /* 1: 0100 0011 */
+INLINE void orl_mem_byte(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ UINT8 srcdata = IRAM_R(addr); //Grab data from data address
+ IRAM_W(addr,srcdata | data); //Set data address value to it's value Logical OR with Data
+}
+
+//ORL A, #data /* 1: 0100 0100 */
+INLINE void orl_a_byte(void)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ SFR_W(ACC,R_ACC | data); //Set ACC to value of ACC Logical OR with Data
+}
+
+//ORL A, data addr /* 1: 0100 0101 */
+INLINE void orl_a_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr); //Grab data from data address
+ SFR_W(ACC,R_ACC | data); //Set ACC to value of ACC Logical OR with Data
+}
+
+//ORL A, @RO/@R1 /* 1: 0100 011i */
+INLINE void orl_a_ir(int r)
+{
+ UINT8 data = IRAM_IR(R_R(r)); //Grab data from address R0 or R1 points to
+ SFR_W(ACC,R_ACC | data); //Set ACC to value of ACC Logical OR with Data
+}
+
+//ORL A, RO to R7 /* 1: 0100 1rrr */
+INLINE void orl_a_r(int r)
+{
+ UINT8 data = R_R(r); //Grab data from R0 - R7
+ SFR_W(ACC,R_ACC | data); //Set ACC to value of ACC Logical OR with Data
+}
+
+//ORL C, bit addr /* 1: 0111 0010 */
+INLINE void orl_c_bitaddr(void)
+{
+ int cy = GET_CY;
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ UINT8 bit = BIT_R(addr); //Grab bit data from bit address
+ SET_CY( (cy | bit) ); //Set Carry flag to Carry Flag Value Logical OR with Bit
+}
+
+//ORL C, /bit addr /* 1: 1010 0000 */
+INLINE void orl_c_nbitaddr(void)
+{
+ int cy = GET_CY;
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ UINT8 bit = BIT_R(addr); //Grab bit data from bit address
+ bit = ((~bit)&1); //Complement bit
+ SET_CY( (cy | bit) ); //Set Carry flag to Carry Flag Value Logical OR with Complemented Bit
+}
+
+//POP data addr /* 1: 1101 0000 */
+INLINE void pop(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ IRAM_W(addr, IRAM_IR(R_SP)); //Store to contents of data addr, data pointed to by Stack - IRAM_IR needed to access upper 128 bytes of stack
+ //IRAM_IW(addr, IRAM_IR(R_SP)); //Store to contents of data addr, data pointed to by Stack - doesn't work, sfr's are not restored this way and it's not an indirect access anyway
+ SFR_W(SP,R_SP-1); //Decrement SP
+}
+
+//PUSH data addr /* 1: 1100 0000 */
+INLINE void push(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 tmpSP = R_SP; //Grab and Increment Stack Pointer
+ tmpSP++; // ""
+ SFR_W(SP,tmpSP); // ""
+ if (tmpSP == R_SP) //Ensure it was able to write to new stack location
+ IRAM_IW(tmpSP, IRAM_R(addr)); //Store to stack contents of data address - IRAM_IW needed to store to upper 128 bytes of stack, however, can't use IRAM_IR because that won't store the sfrs and it's not an indirect access anyway
+}
+
+//RET /* 1: 0010 0010 */
+INLINE void ret(void)
+{
+ POP_PC
+}
+
+//RETI /* 1: 0011 0010 */
+INLINE void reti(void)
+{
+ POP_PC
+ CLEAR_CURRENT_IRQ
+}
+
+//RL A /* 1: 0010 0011 */
+INLINE void rl_a(void)
+{
+ //Left Shift A, Bit 7 carries to Bit 0
+ int carry = ((R_ACC & 0x80) >> 7);
+ int data = (R_ACC<<1) & 0xfe;
+ SFR_W(ACC, data | carry);
+}
+
+//RLC A /* 1: 0011 0011 */
+INLINE void rlc_a(void)
+{
+ //Left Shift A, Bit 7 goes to Carry Flag, Original Carry Flag goes to Bit 0 of ACC
+ int carry = ((R_ACC & 0x80) >> 7);
+ int data = ((R_ACC<<1) & 0xfe) | GET_CY;
+ SFR_W(ACC, data);
+ SET_CY(carry);
+}
+
+//RR A /* 1: 0000 0011 */
+INLINE void rr_a(void)
+{
+ //Right Shift A, Bit 0 carries to Bit 7
+ int carry = ((R_ACC & 1) << 7);
+ int data = (R_ACC>>1) & 0x7f;
+ SFR_W(ACC, data | carry);
+}
+
+//RRC A /* 1: 0001 0011 */
+INLINE void rrc_a(void)
+{
+ //Right Shift A, Bit 0 goes to Carry Flag, Bit 7 of ACC gets set to original Carry Flag
+ int carry = (R_ACC & 1);
+ int data = ((R_ACC>>1) & 0x7f) | (GET_CY<<7);
+ SFR_W(ACC, data);
+ SET_CY(carry);
+}
+
+//SETB C /* 1: 1101 0011 */
+INLINE void setb_c(void)
+{
+ SET_CY(1); //Set Carry Flag
+}
+
+//SETB bit addr /* 1: 1101 0010 */
+INLINE void setb_bitaddr(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ BIT_W(addr,1); //Set Bit at Bit Address
+}
+
+//SJMP code addr /* 1: 1000 0000 */
+INLINE void sjmp(void)
+{
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ PC = PC + rel_addr; //Update PC
+}
+
+//SUBB A, #data /* 1: 1001 0100 */
+INLINE void subb_a_byte(void)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ UINT8 result = R_ACC - data - GET_CY; //Subtract data & carry flag from accumulator
+ DO_SUB_FLAGS(R_ACC,data,GET_CY); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+
+}
+
+//SUBB A, data addr /* 1: 1001 0101 */
+INLINE void subb_a_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr); //Grab data from data address
+ UINT8 result = R_ACC - data - GET_CY; //Subtract data & carry flag from accumulator
+ DO_SUB_FLAGS(R_ACC,data,GET_CY); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//SUBB A, @R0/@R1 /* 1: 1001 011i */
+INLINE void subb_a_ir(int r)
+{
+ UINT8 data = IRAM_IR(R_R(r)); //Grab data from memory pointed to by R0 or R1
+ UINT8 result = R_ACC - data - GET_CY; //Subtract data & carry flag from accumulator
+ DO_SUB_FLAGS(R_ACC,data,GET_CY); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//SUBB A, R0 to R7 /* 1: 1001 1rrr */
+INLINE void subb_a_r(int r)
+{
+ UINT8 data = R_R(r); //Grab data from R0 - R7
+ UINT8 result = R_ACC - data - GET_CY; //Subtract data & carry flag from accumulator
+ DO_SUB_FLAGS(R_ACC,data,GET_CY); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//SWAP A /* 1: 1100 0100 */
+INLINE void swap_a(void)
+{
+ UINT8 a_nib_lo, a_nib_hi;
+ a_nib_hi = (R_ACC & 0x0f) << 4; //Grab lo byte of ACC and move to hi
+ a_nib_lo = (R_ACC & 0xf0) >> 4; //Grab hi byte of ACC and move to lo
+ SFR_W(ACC, a_nib_hi | a_nib_lo);
+}
+
+//XCH A, data addr /* 1: 1100 0101 */
+INLINE void xch_a_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr); //Grab data
+ UINT8 oldACC = R_ACC; //Hold value of ACC
+ SFR_W(ACC,data); //Sets ACC to data
+ IRAM_W(addr,oldACC); //Sets data address to old value of ACC
+}
+
+//XCH A, @RO/@R1 /* 1: 1100 011i */
+INLINE void xch_a_ir(int r)
+{
+ UINT8 data = IRAM_IR(R_R(r)); //Grab data pointed to by R0 or R1
+ UINT8 oldACC = R_ACC; //Hold value of ACC
+ SFR_W(ACC,data); //Sets ACC to data
+ IRAM_W(R_R(r),oldACC); //Sets data address to old value of ACC
+}
+
+//XCH A, RO to R7 /* 1: 1100 1rrr */
+INLINE void xch_a_r(int r)
+{
+ UINT8 data = R_R(r); //Grab data from R0-R7
+ UINT8 oldACC = R_ACC; //Hold value of ACC
+ SFR_W(ACC,data); //Sets ACC to data
+ R_R(r) = oldACC; //Sets data address to old value of ACC
+}
+
+//XCHD A, @R0/@R1 /* 1: 1101 011i */
+INLINE void xchd_a_ir(int r)
+{
+ UINT8 acc, ir_data;
+ ir_data = IRAM_IR(R_R(r)); //Grab data pointed to by R0 or R1
+ acc = R_ACC; //Grab ACC value
+ SFR_W(ACC, (acc & 0xf0) | (ir_data & 0x0f) ); //Set ACC to lower nibble of data pointed to by R0 or R1
+ IRAM_W(R_R(r), (ir_data & 0xf0) | (acc & 0x0f) ); //Set data pointed to by R0 or R1 to lower nibble of ACC
+}
+
+//XRL data addr, A /* 1: 0110 0010 */
+INLINE void xrl_mem_a(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr); //Grab data from data address
+ IRAM_W(addr,data ^ R_ACC); //Set data address value to it's value Logical XOR with ACC
+}
+
+//XRL data addr, #data /* 1: 0110 0011 */
+INLINE void xrl_mem_byte(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ UINT8 srcdata = IRAM_R(addr); //Grab data from data address
+ IRAM_W(addr,srcdata ^ data); //Set data address value to it's value Logical XOR with Data
+}
+
+//XRL A, #data /* 1: 0110 0100 */
+INLINE void xrl_a_byte(void)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ SFR_W(ACC,R_ACC ^ data); //Set ACC to value of ACC Logical XOR with Data
+}
+
+//XRL A, data addr /* 1: 0110 0101 */
+INLINE void xrl_a_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr); //Grab data from data address
+ SFR_W(ACC,R_ACC ^ data); //Set ACC to value of ACC Logical XOR with Data
+}
+
+//XRL A, @R0/@R1 /* 1: 0110 011i */
+INLINE void xrl_a_ir(int r)
+{
+ UINT8 data = IRAM_IR(R_R(r)); //Grab data from address R0 or R1 points to
+ SFR_W(ACC,R_ACC ^ data); //Set ACC to value of ACC Logical XOR with Data
+}
+
+//XRL A, R0 to R7 /* 1: 0110 1rrr */
+INLINE void xrl_a_r(int r)
+{
+ UINT8 data = R_R(r); //Grab data from R0 - R7
+ SFR_W(ACC,R_ACC ^ data); //Set ACC to value of ACC Logical XOR with Data
+}
+
+//illegal opcodes
+INLINE void illegal(void)
+{
+ LOG(("i8051 #%d: illegal opcode at 0x%03x: %02x\n", cpu_getactivecpu(), PC, ROP(PC)));
+}