diff options
author | 2007-12-17 15:19:59 +0000 | |
---|---|---|
committer | 2007-12-17 15:19:59 +0000 | |
commit | 7b77f1218624ea26dbb2efd85a19f795f5d4e02e (patch) | |
tree | 19209304095572b4fd61c2a2d6a5aa75c4e471ad /src/emu/cpu/i8051 | |
parent | 3da7f476068b3ffef713218ba2fc1bd5030f2c38 (diff) |
Initial checkin of MAME 0.121.mame0121
Diffstat (limited to 'src/emu/cpu/i8051')
-rw-r--r-- | src/emu/cpu/i8051/8051dasm.c | 1034 | ||||
-rw-r--r-- | src/emu/cpu/i8051/i8051.c | 2583 | ||||
-rw-r--r-- | src/emu/cpu/i8051/i8051.h | 157 | ||||
-rw-r--r-- | src/emu/cpu/i8051/i8051ops.c | 960 |
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))); +} |