diff options
Diffstat (limited to 'src/emu/cpu/pps4')
-rw-r--r-- | src/emu/cpu/pps4/pps4.c | 1776 | ||||
-rw-r--r-- | src/emu/cpu/pps4/pps4.h | 196 | ||||
-rw-r--r-- | src/emu/cpu/pps4/pps4dasm.c | 529 |
3 files changed, 2012 insertions, 489 deletions
diff --git a/src/emu/cpu/pps4/pps4.c b/src/emu/cpu/pps4/pps4.c index 130b70d5b39..2611bbab53e 100644 --- a/src/emu/cpu/pps4/pps4.c +++ b/src/emu/cpu/pps4/pps4.c @@ -1,5 +1,6 @@ // license:BSD-3-Clause -// copyright-holders:Miodrag Milanovic +// copyright-holders:Juergen Buchmueller <pullmoll@t-online.de> + /***************************************************************************** * * pps4.c @@ -31,300 +32,1448 @@ #include "debugger.h" #include "pps4.h" -#define VERBOSE 0 -#define LOG(x) do { if (VERBOSE) logerror x; } while (0) +#define VERBOSE 0 //!< set to 1 to log certain instruction conditions +#if VERBOSE +#define LOG(x) logerror x +#else +#define LOG(x) +#endif const device_type PPS4 = &device_creator<pps4_device>; - pps4_device::pps4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : cpu_device(mconfig, PPS4, "PPS4", tag, owner, clock, "pps4", __FILE__ ) - , m_program_config("program", ENDIANNESS_LITTLE, 8, 12) - , m_data_config("data", ENDIANNESS_LITTLE, 8, 12) // 4bit RAM - , m_io_config("io", ENDIANNESS_LITTLE, 8, 8) // 4bit IO + : cpu_device(mconfig, PPS4, "PPS4", tag, owner, clock, "pps4", __FILE__ ) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 12) + , m_data_config("data", ENDIANNESS_LITTLE, 8, 12) // 4bit RAM + , m_io_config("io", ENDIANNESS_LITTLE, 8, 8) // 4bit IO { } +/** + * @brief pps4_device::M Return the memory at address B + * @return ROM/RAM(B) + */ +UINT8 pps4_device::M() +{ + UINT8 ret = m_data->read_byte(m_B & ~m_SAG); + m_SAG = 0; + return ret; +} -offs_t pps4_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) + +/** + * @brief pps4_device::W Write to the memory address at B + * @return ROM/RAM(B) + */ +void pps4_device::W(UINT8 data) { - extern CPU_DISASSEMBLE( pps4 ); - return CPU_DISASSEMBLE_NAME(pps4)(this, buffer, pc, oprom, opram, options); + m_data->write_byte(m_B & ~m_SAG, data); + m_SAG = 0; } +offs_t pps4_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( pps4 ); + return CPU_DISASSEMBLE_NAME(pps4)(this, buffer, pc, oprom, opram, options); +} +/** + * @brief pps4_device::ROP Read the next opcode (instruction) + * @return m_I + */ inline UINT8 pps4_device::ROP() { - UINT8 retVal = m_direct->read_decrypted_byte(m_P.w.l); - m_P.w.l = (m_P.w.l + 1) & 0x0fff; - return retVal; + m_Ip = m_I & 0xf0; // set previous opcode mask + m_I = m_direct->read_decrypted_byte(m_P & 0xFFF); + m_P = (m_P + 1) & 0xFFF; + m_icount -= 1; + return m_I; } +/** + * @brief pps4_device::ARG Read the next argument (instrunction 2) + * @return m_I2 + */ inline UINT8 pps4_device::ARG() { - UINT8 retVal = m_direct->read_raw_byte(m_P.w.l); - m_P.w.l = (m_P.w.l + 1) & 0x0fff; - return retVal; -} - -inline void pps4_device::DO_SKIP() -{ - m_P.w.l = (m_P.w.l + 1) & 0x0fff; -} - -void pps4_device::execute_one(int opcode) -{ - m_icount -= 1; - switch (opcode) - { - // Arithmetic instructions - case 0x0b: // AD - break; - case 0x0a: // ADC - break; - case 0x09: // ADSK - break; - case 0x08: // ADCSK - break; - case 0x60: case 0x61: case 0x62: case 0x63: - case 0x64: case 0x66: case 0x67: case 0x68: - case 0x69: case 0x6a: case 0x6b: case 0x6c: - case 0x6d: case 0x6e: - // ADI - break; - case 0x65: //DC - m_A = (m_A + 10) & 0x0f; - break; - // Logical instructions - case 0x0d: // AND - break; - case 0x0f: // OR - break; - case 0x0c: // EOR - break; - case 0x0e: // COMP - m_A ^= 0x0f; - break; - // Data transfer instructions - case 0x20: // SC - m_C = 1; - break; - case 0x24: //RC - m_C = 0; - break; - case 0x22: // SF1 - m_FF1 = 1; - break; - case 0x26: // RF1 - m_FF1 = 0; - break; - case 0x21: // SF2 - m_FF2 = 1; - break; - case 0x25: // RF2 - m_FF2 = 0; - break; - case 0x30: case 0x31: case 0x32: case 0x33: - case 0x34: case 0x35: case 0x36: case 0x37: - // LD - break; - case 0x38: case 0x39: case 0x3a: case 0x3b: - case 0x3c: case 0x3d: case 0x3e: case 0x3f: - // EX - break; - case 0x28: case 0x29: case 0x2a: case 0x2b: - case 0x2c: case 0x2d: case 0x2e: case 0x2f: - // EXD - break; - case 0x70: case 0x71: case 0x72: case 0x73: - case 0x74: case 0x75: case 0x76: case 0x77: - case 0x78: case 0x79: case 0x7a: case 0x7b: - case 0x7c: case 0x7d: case 0x7e: case 0x7f: - // LDI - m_A = opcode & 0x0f; - break; - case 0x12: // LAX - m_A = m_X; - break; - case 0x1b: // LXA - m_X = m_A; - break; - case 0x11: // LABL - m_A = m_B.w.l & 0x00f; - break; - case 0x10: // LBMX - m_B.w.l &= 0xf0f; - m_B.w.l |= (m_X << 4); - break; - case 0x04: // LBUA - break; - case 0x19: // XABL - { - UINT8 tmp = m_B.w.l & 0x00f; - m_B.w.l &= 0xff0; - m_B.w.l |= m_A; - m_A = tmp; - } - break; - case 0x18: // XBMX - { - UINT8 tmp = (m_B.w.l & 0x0f0) >> 4; - m_B.w.l &= 0xf0f; - m_B.w.l |= (m_X << 4); - m_X = tmp; - } - break; - case 0x1a: // XAX - { - UINT8 tmp = m_A; - m_A = m_X; - m_X = tmp; - } - break; - case 0x06: // XS - { - PAIR tmp = m_SA; - m_SA = m_SB; - m_SB = tmp; - } - break; - case 0x6f: // CYS - break; - case 0xc0: case 0xc1: case 0xc2: case 0xc3: - case 0xc4: case 0xc5: case 0xc6: case 0xc7: - case 0xc8: case 0xc9: case 0xca: case 0xcb: - case 0xcc: case 0xcd: case 0xce: case 0xcf: - // LB - { - //UINT8 tmp = ARG(); - m_icount -= 1; - } - break; - case 0x00: // LBL - { - UINT8 tmp = ARG(); - m_icount -= 1; - m_B.w.l = tmp; - } - break; - case 0x17: // INCB - if ((m_B.w.l & 0x0f) == 0x0f) { - m_B.w.l &= 0xff0; - DO_SKIP(); - } else { - m_B.w.l += 1; - } - break; - case 0x1f: // DECB - if ((m_B.w.l & 0x0f) == 0x00) { - m_B.w.l |= 0x00f; - DO_SKIP(); - } else { - m_B.w.l -= 1; - } - break; - // Control transfer instructions - case 0x80: case 0x81: case 0x82: case 0x83: - case 0x84: case 0x85: case 0x86: case 0x87: - case 0x88: case 0x89: case 0x8a: case 0x8b: - case 0x8c: case 0x8d: case 0x8e: case 0x8f: - case 0x90: case 0x91: case 0x92: case 0x93: - case 0x94: case 0x95: case 0x96: case 0x97: - case 0x98: case 0x99: case 0x9a: case 0x9b: - case 0x9c: case 0x9d: case 0x9e: case 0x9f: - case 0xa0: case 0xa1: case 0xa2: case 0xa3: - case 0xa4: case 0xa5: case 0xa6: case 0xa7: - case 0xa8: case 0xa9: case 0xaa: case 0xab: - case 0xac: case 0xad: case 0xae: case 0xaf: - case 0xb0: case 0xb1: case 0xb2: case 0xb3: - case 0xb4: case 0xb5: case 0xb6: case 0xb7: - case 0xb8: case 0xb9: case 0xba: case 0xbb: - case 0xbc: case 0xbd: case 0xbe: case 0xbf: - // T - m_P.w.l = (m_P.w.l & 0xfc0) | (opcode & 0x3f); - break; - case 0xd0: case 0xd1: case 0xd2: case 0xd3: - case 0xd4: case 0xd5: case 0xd6: case 0xd7: - case 0xd8: case 0xd9: case 0xda: case 0xdb: - case 0xdc: case 0xdd: case 0xde: case 0xdf: - case 0xe0: case 0xe1: case 0xe2: case 0xe3: - case 0xe4: case 0xe5: case 0xe6: case 0xe7: - case 0xe8: case 0xe9: case 0xea: case 0xeb: - case 0xec: case 0xed: case 0xee: case 0xef: - case 0xf0: case 0xf1: case 0xf2: case 0xf3: - case 0xf4: case 0xf5: case 0xf6: case 0xf7: - case 0xf8: case 0xf9: case 0xfa: case 0xfb: - case 0xfc: case 0xfd: case 0xfe: case 0xff: - // TM - break; - case 0x50: case 0x51: case 0x52: case 0x53: - case 0x54: case 0x55: case 0x56: case 0x57: - case 0x58: case 0x59: case 0x5a: case 0x5b: - case 0x5c: case 0x5d: case 0x5e: case 0x5f: - // TL - { - //UINT8 tmp = ARG(); - m_icount -= 1; - } - break; - case 0x01: case 0x02: case 0x03: - // TML - { - //UINT8 tmp = ARG(); - m_icount -= 1; - } - break; - case 0x15: // SKC - break; - case 0x1e: // SKZ - break; - case 0x40: case 0x41: case 0x42: case 0x43: - case 0x44: case 0x45: case 0x46: case 0x47: - case 0x48: case 0x49: case 0x4a: case 0x4b: - case 0x4c: case 0x4d: case 0x4e: case 0x4f: - // SKBI - break; - case 0x16: // SKF1 - break; - case 0x14: // SKF2 - break; - case 0x05: // RTN - break; - case 0x07: // RTNSK - break; - // Input/Output instructions - case 0x1c: // IOL - { - //UINT8 tmp = ARG(); - m_icount -= 1; - } - break; - case 0x27: // DIA - break; - case 0x23: // DIB - break; - case 0x1d: // DOA - break; - // Special instructions - case 0x13: // SAG - break; - } + m_I2 = m_direct->read_raw_byte(m_P & 0xFFF); + m_P = (m_P + 1) & 0xFFF; + m_icount -= 1; + return m_I2; +} + +/** + * @brief Note3 + * + * Instructions ADI, LD, EX, EXD, LDI, LB and LBL have a numeric + * value coded as part of the instruction in the immediate field. + * This numeric value must be in complementary form on the bus. + * All of these immediate fields which are inverted are shown + * in brackets. + * For example: ADI 1, as written by the programmer who wishes + * to add one to the value in the accumulator, is converted to + * 0x6E = 01001 [1110]; the bracketed binary value is the value + * as seen on the data bus. + * If the programmer is using the Rockwell Assembler he does not + * have to manually determine the proper inverted value as the + * assembler does this for him. + * + * [And we do in MAME as well :-] + */ + +/** + * @brief pps4_device::iAD Add + * OPCODE cycles mnemonic + * ----------------------------- + * 0000 1011 1 cyc AD + * + * Symbolic equation + * ----------------------------- + * C, A <- A + M + * + * The result of the binary addition of contents of accumulator + * and 4-bit contents of RAM currently addressed by B register, + * replaces the contents of the accumulator. The resulting + * carry-out is loaded into C flip-flop. + */ +void pps4_device::iAD() +{ + m_A = m_A + M(); + m_C = m_A >> 4; + m_A = m_A & 15; +} + +/** + * @brief pps4_device::iADC Add with carry-in + * OPCODE cycles mnemonic + * ----------------------------- + * 0000 1010 1 cyc ADC + * + * Symbolic equation + * ----------------------------- + * C, A <- A + M + C + * + * Same as AD except the C flip-flop serves as a carry-in + * to the adder. + */ +void pps4_device::iADC() +{ + m_A = m_A + M() + m_C; + m_C = m_A >> 4; + m_A = m_A & 15; +} + +/** + * @brief pps4_device::iADSK Add and skip if carry-out + * OPCODE cycles mnemonic + * ----------------------------- + * 0000 1001 1 cyc ADSK + * + * Symbolic equation + * ----------------------------- + * C, A <- A + M + * Skip if C = 1 + * + * Same as AD except the next ROM word will be + * skipped (ignored) if a carry-out is generated. + */ +void pps4_device::iADSK() +{ + m_A = m_A + M(); + m_C = m_A >> 4; + m_A = m_A & 15; + m_P = (m_P + m_C) & 0xFFF; +} + +/** + * @brief pps4_device::iADCSK Add with carry-in and skip if carry-out + * OPCODE cycles mnemonic + * ----------------------------- + * 0000 1000 1 cyc ADCSK + * + * Symbolic equation + * ----------------------------- + * C, A <- A + M + C + * Skip if C = 1 + * + * Same as ADC except the next ROM word will be + * skipped (ignored) if a carry-out is generated. + */ +void pps4_device::iADCSK() +{ + m_A = m_A + M() + m_C; + m_C = m_A >> 4; + m_A = m_A & 15; + m_P = (m_P + m_C) & 0xFFF; +} + +/** + * @brief pps4_device::iAND Logical AND + * OPCODE cycles mnemonic + * ----------------------------- + * 0000 1101 1 cyc AND + * + * Symbolic equation + * ----------------------------- + * A <- A & M + * + * The result of logical AND of accumulator and + * 4-bit contents of RAM currently addressed by + * B register replaces contents of accumulator. + */ +void pps4_device::iAND() +{ + m_A = m_A & M(); +} + +/** + * @brief pps4_device::iADI Add immediate + * OPCODE cycles mnemonic + * ----------------------------- + * 0110 xxxx 1 cyc ADI #x + * + * Symbolic equation + * ----------------------------- + * A <- A + [I(4:1)] + * + * The result of the binary addition of contents of + * accumulator and 4-bit immediate field of instruction + * word replaces the contents of accumulator. + * The next ROM word will be skipped (ignored) if a + * carry-out is generated. + * __ The instruction does not use or change the C flip-flop. __ + * The immediate field I(4:1) of this instruction may not + * be equal to binary 0 (CYS) or 0101 (DC) + * + * See %Note3 + */ +void pps4_device::iADI() +{ + const UINT8 imm = ~m_I & 15; + m_A = m_A + imm; + m_P = m_P + (m_A > 15) ? 1 : 0; + m_A = m_A & 15; + m_P = m_P & 0xFFF; +} + +/** + * @brief pps4_device::iDC Decimal correction + * OPCODE cycles mnemonic + * ----------------------------- + * 0110 0110 1 cyc DC + * + * Symbolic equation + * ----------------------------- + * A <- A + 1010b + * + * Decimal correction of accumulator. + * Binary 1010 is added to the contents of the accumulator. + * Result is stored in accumulator. Instruction does not + * use or change carry flip-flop or skip. + */ +void pps4_device::iDC() +{ + m_A = m_A + 10; +} + +/** + * @brief pps4_device::iOR Logical OR + * OPCODE cycles mnemonic + * ----------------------------- + * 0000 1111 1 cyc OR + * + * Symbolic equation + * ----------------------------- + * A <- A | M + * + * The result of logical OIR of accumulator and + * 4-bit contents of RAM currently addressed by + * B register replaces contents of accumulator. + */ +void pps4_device::iOR() +{ + m_A = m_A | M(); +} + +/** + * @brief pps4_device::iEOR Logical exclusive-OR + * OPCODE cycles mnemonic + * ----------------------------- + * 0000 1100 1 cyc EOR + * + * Symbolic equation + * ----------------------------- + * A <- A ^ M + * + * The result of logical exclusive-OR of + * accumulator and 4-bit contents of RAM + * currently addressed by B register + * replaces contents of accumulator. + */ +void pps4_device::iEOR() +{ + m_A = m_A ^ M(); +} + +/** + * @brief pps4_device::iCOMP Complement + * OPCODE cycles mnemonic + * ----------------------------- + * 0000 1110 1 cyc COMP + * + * Symbolic equation + * ----------------------------- + * A <- ~A + * + * Each bit of the accumulator is logically + * complemented and placed in accumulator. + */ +void pps4_device::iCOMP() +{ + m_A = ~m_A & 15; +} + +/** + * @brief pps4_device::iSC Set carry flip-flop + * OPCODE cycles mnemonic + * ----------------------------- + * 0010 0000 1 cyc SC + * + * Symbolic equation + * ----------------------------- + * C <- 1 + * + * The C flip-flop is set to 1. + */ +void pps4_device::iSC() +{ + m_C = 1; +} + +/** + * @brief pps4_device::iRC Reset carry flip-flop + * OPCODE cycles mnemonic + * ----------------------------- + * 0010 0100 1 cyc RC + * + * Symbolic equation + * ----------------------------- + * C <- 0 + * + * The C flip-flop is set to 0. + */ +void pps4_device::iRC() +{ + m_C = 0; +} + +/** + * @brief pps4_device::iSF1 Set flip-flop FF1 + * OPCODE cycles mnemonic + * ----------------------------- + * 0010 0010 1 cyc SF1 + * + * Symbolic equation + * ----------------------------- + * FF1 <- 1 + * + * The Flip-flop FF1 is set to 1. + */ +void pps4_device::iSF1() +{ + m_FF1 = 1; +} + +/** + * @brief pps4_device::iRF1 Reset flip-flop FF1 + * OPCODE cycles mnemonic + * ----------------------------- + * 0010 0100 1 cyc RF1 + * + * Symbolic equation + * ----------------------------- + * FF1 <- 0 + * + * The Flip-flop FF1 is set to 0. + */ +void pps4_device::iRF1() +{ + m_FF1 = 0; +} + +/** + * @brief pps4_device::iSF2 Set flip-flop FF2 + * OPCODE cycles mnemonic + * ----------------------------- + * 0010 0001 1 cyc SF2 + * + * Symbolic equation + * ----------------------------- + * FF2 <- 1 + * + * The Flip-flop FF2 is set to 1. + */ +void pps4_device::iSF2() +{ + m_FF2 = 1; +} + +/** + * @brief pps4_device::iRF2 Reset flip-flop FF2 + * OPCODE cycles mnemonic + * ----------------------------- + * 0010 0101 1 cyc RF2 + * + * Symbolic equation + * ----------------------------- + * FF2 <- 0 + * + * The flip-flop FF2 is set to 0. + */ +void pps4_device::iRF2() +{ + m_FF2 = 0; +} + +/** + * @brief pps4_device::iLD Load accumulator from memory + * OPCODE cycles mnemonic + * ----------------------------- + * 0011 0xxx 1 cyc LDx + * + * Symbolic equation + * ----------------------------- + * A <- M + * B(7:5) <- B(7:5) ^ [I(3:1)] + * + * The 4-bit contents of RAM currently addressed + * by B register are placed in the accumulator. + * The RAM address in the B register is then + * modified by the result of an exclusive-OR of + * the 3-b it immediate field I(3:1) and B(7:5) + * + * See %Note3 + */ +void pps4_device::iLD() +{ + const UINT16 imm = ~m_I & 7; + m_A = M(); + m_B = m_B ^ (imm << 4); +} + +/** + * @brief pps4_device::iEX Exchange accumulator and memory + * OPCODE cycles mnemonic + * ----------------------------- + * 0011 1xxx 1 cyc EXx + * + * Symbolic equation + * ----------------------------- + * A <-> M + * B(7:5) <- B(7:5) ^ [I(3:1)] + * + * The same as LD except the contents of accumulator + * are also placed in currently addressed RAM location. + * + * See %Note3 + */ +void pps4_device::iEX() +{ + const UINT16 imm = ~m_I & 7; + const UINT8 mem = M(); + W(m_A); + m_A = mem; + m_B = m_B ^ (imm << 4); +} + +/** + * @brief pps4_device::iEXD Exchange accumulator and memory and decrement BL + * OPCODE cycles mnemonic + * ----------------------------- + * 0010 1xxx 1 cyc EXD x + * + * Symbolic equation + * ----------------------------- + * A <-> M + * B(7:5) <- B(7:5) ^ [I(3:1)] + * BL <- BL - 1 + * Skip on BL = 1111b + * + * The same as EX except RAM address in B register + * is further modified by decrementing BL by 1. + * If the new contents of BL is 1111, the next + * ROM word will be ignored. + * + * See %Note3 + */ +void pps4_device::iEXD() +{ + const UINT8 imm = ~m_I & 7; + const UINT8 mem = M(); + UINT8 bl = m_B & 15; + W(m_A); + m_A = mem; + m_B = m_B ^ (imm << 4); + if (0 == bl) { + // decrement BL wraps to 1111b + bl = 15; + m_P = (m_P + 1) & 0xFFF; + } else { + // decrement BL + bl = bl - 1; + } + m_B = (m_B & ~15) | bl; } +/** + * @brief pps4_device::iLDI Load accumualtor immediate + * OPCODE cycles mnemonic + * ----------------------------- + * 0111 xxxx 1 cyc LDI x + * + * Symbolic equation + * ----------------------------- + * A <- [I(4:1)] + * + * The 4-bit contents, immediate field I(4:1), + * of the instruction are placed in the accumulator. + * + * Note: Only the first occurence of an LDI in a consecutive + * string of LDIs will be executed. The program will ignore + * remaining LDIs and execute next valid instruction. + * + * See %Note3 + */ +void pps4_device::iLDI() +{ + // previous LDI instruction? + if (0x70 == m_Ip) { + LOG(("%s: skip prev:%02x\n", __FUNCTION__, m_Ip)); + return; + } + m_A = ~m_I & 15; +} + +/** + * @brief pps4_device::iLAX + * OPCODE cycles mnemonic + * ----------------------------- + * 0001 0010 1 cyc LAX + * + * Symbolic equation + * ----------------------------- + * A <- X + * + * The 4-bit contents of the X register are + * placed in the accumulator. + */ +void pps4_device::iLAX() +{ + m_A = m_X; +} + +/** + * @brief pps4_device::iLXA + * OPCODE cycles mnemonic + * ----------------------------- + * 0001 1011 1 cyc LAX + * + * Symbolic equation + * ----------------------------- + * X <- A + * + * The contents of the accumulator are + * tansferred to the X register. + */ +void pps4_device::iLXA() +{ + m_X = m_A; +} + +/** + * @brief pps4_device::iLABL + * OPCODE cycles mnemonic + * ----------------------------- + * 0001 0001 1 cyc LABL + * + * Symbolic equation + * ----------------------------- + * A <- BL + * + * The contents of BL register are + * tansferred to the accumulator. + */ +void pps4_device::iLABL() +{ + m_A = m_B & 15; +} + +/** + * @brief pps4_device::iLBMX + * OPCODE cycles mnemonic + * ----------------------------- + * 0001 0000 1 cyc LBMX + * + * Symbolic equation + * ----------------------------- + * BM <- X + * + * The contents of X register are + * tansferred to BM register. + */ +void pps4_device::iLBMX() +{ + m_B = (m_B & ~(15 << 4)) | (m_X << 4); +} + +/** + * @brief pps4_device::iLBUA + * OPCODE cycles mnemonic + * ----------------------------- + * 0001 0000 1 cyc LBUA + * + * Symbolic equation + * ----------------------------- + * BU <- A + * A <- M + * + * The contents of accumulator are tansferred to + * BU register. Also, the contents of the currently + * addressed RAM are transferred to accumulator. + */ +void pps4_device::iLBUA() +{ + m_B = (m_B & ~(15 << 8)) | (m_A << 8); + m_A = M(); +} + +/** + * @brief pps4_device::iXABL + * OPCODE cycles mnemonic + * ----------------------------- + * 0001 1001 1 cyc XABL + * + * Symbolic equation + * ----------------------------- + * A <-> BL + * + * The contents of accumulator and BL register + * are exchanged. + */ +void pps4_device::iXABL() +{ + // swap A and BL + UINT8 bl = m_B & 15; + m_B = (m_B & ~15) | m_A; + m_A = bl; +} + +/** + * @brief pps4_device::iXMBX + * OPCODE cycles mnemonic + * ----------------------------- + * 0001 1000 1 cyc XMBX + * + * Symbolic equation + * ----------------------------- + * X <-> BM + * + * The contents of accumulator and BL register + * are exchanged. + */ +void pps4_device::iXBMX() +{ + // swap X and BM + UINT8 bm = (m_B >> 4) & 15; + m_B = (m_B & ~(15 << 4)) | (m_X << 4); + m_X = bm; +} + +/** + * @brief pps4_device::iXAX + * OPCODE cycles mnemonic + * ----------------------------- + * 0001 1010 1 cyc XAX + * + * Symbolic equation + * ----------------------------- + * A <-> X + * + * The contents of accumulator and X register + * are exchanged. + */ +void pps4_device::iXAX() +{ + // swap A and X + m_A ^= m_X; + m_X ^= m_A; + m_A ^= m_X; +} + +/** + * @brief pps4_device::iXS + * OPCODE cycles mnemonic + * ----------------------------- + * 0000 0110 1 cyc XS + * + * Symbolic equation + * ----------------------------- + * SA <-> SB + * + * The 12-bit contents of SA and SB register + * are exchanged. + */ +void pps4_device::iXS() +{ + // swap SA and SB + m_SA ^= m_SB; + m_SB ^= m_SA; + m_SA ^= m_SB; +} + +/** + * @brief pps4_device::iCYS + * OPCODE cycles mnemonic + * ----------------------------- + * 0110 1111 1 cyc CYS + * + * Symbolic equation + * ----------------------------- + * A <- SA(4:1) + * SA(4:1) <- SA(8:5) + * SA(8:5) <- SA(12:9) + * SA(12:9) <- A + * + * A 4-bit right shift of the SA register takes place + * with the four bits which are shifted off the end + * of SA being transferred into the accumulator. + * The contents of the accumulator are placed in the + * left end of the SA register + * + */ +void pps4_device::iCYS() +{ + const UINT16 sa = (m_SA >> 4) | (m_A << 12); + m_A = m_SA & 15; + m_SA = sa; +} + +/** + * @brief pps4_device::iLB + * OPCODE cycles mnemonic + * ----------------------------- + * 1100 0000 2 cyc LB + * + * Symbolic equation + * ----------------------------- + * SB <- SA, SA <- P + * P(12:5) <- 0000 1100 + * P(4:1) <- I(4:1) + * + * BU <- 0000 + * B(8:1) <- [I2(8:1)] + * P <- SA, SA <-> SB + * + * Sixteen consecutive locations on ROM page 3 (I2) contain + * data which can be loaded into the eight least significant + * bits of the B register by use of any LB instruction. + * The four most significant bits of B register will be loaded + * with zeros. The contents of the SB register will be destroyed. + * This instruction takes two cycles to execute but occupies + * only one ROM word. (Automatic return) + * + * Only the first occurence of an LB or LBL instruction in a + * consecutive string of LB or LBL will be executed. The + * program will ignore the remaining LB or LBL and execute + * the next valid instruction. Within subroutines the LB + * instruction must be used with caution because the contents + * of SB have been modified. + * + * See %Note3 and %Note4 + */ +void pps4_device::iLB() +{ + // previous LB or LBL instruction? + if (0xc0 == m_Ip|| 0x00 == m_Ip) { + LOG(("%s: skip prev:%02X\n", __FUNCTION__, m_Ip)); + return; + } + m_SB = m_SA; + m_SA = (m_P + 1) & 0xFFF; + m_P = (3 << 8) | (m_I & 15); + m_B = ~ARG() & 255; + m_P = m_SA; + // swap SA and SB + m_SA ^= m_SB; + m_SB ^= m_SA; + m_SA ^= m_SB; +} + +/** + * @brief pps4_device::iLBL + * OPCODE cycles mnemonic + * ----------------------------- + * 0000 0000 2 cyc LBL + * + * Symbolic equation + * ----------------------------- + * BU <- 0000 + * B(8:1) <- [I2(8:1)] + * + * This instruction occupies two ROM words, the second of + * which will be loaded into the eight least significant + * bits of the B register. The four most significant bits + * of B (BU) will be loaded with zeroes. + * + * Only the first occurence of an LB or LBL instruction in a + * consecutive string of LB or LBL will be executed. The + * program will ignore the remaining LB or LBL and execute + * the next valid instruction. + * + * See %Note3 + */ +void pps4_device::iLBL() +{ + // previous LB or LBL instruction? + if (0xc0 == m_Ip || 0x00 == m_Ip) { + LOG(("%s: skip prev:%02X\n", __FUNCTION__, m_Ip)); + return; + } + m_B = ~ARG() & 255; +} + +/** + * @brief pps4_device::INCB + * OPCODE cycles mnemonic + * ----------------------------- + * 0001 0111 1 cyc INCB + * + * Symbolic equation + * ----------------------------- + * BL <- BL + 1 + * Skip on BL = 0000 + * + * BL register (least significant four bits of B register) + * is incremented by 1. If the new contents of BL is 0000b, + * then the next ROM word will be ignored. + */ +void pps4_device::iINCB() +{ + UINT8 bl = m_B & 15; + bl = (bl + 1) & 15; + if (0 == bl) { + LOG(("%s: skip BL=%x\n", __FUNCTION__, bl)); + m_P = (m_P + 1) & 0xFFF; + } + m_B = (m_B & ~15) | bl; +} + +/** + * @brief pps4_device::iDECB + * OPCODE cycles mnemonic + * ----------------------------- + * 0001 1111 1 cyc DECB + * + * Symbolic equation + * ----------------------------- + * BL <- BL - 1 + * Skip on BL = 1111 + * + * BL register is decremented by 1. If the new + * contents of BL is 1111b, then the next ROM + * word will be ignored. + */ +void pps4_device::iDECB() +{ + UINT8 bl = m_B & 15; + bl = (bl - 1) & 15; + if (15 == bl) { + LOG(("%s: skip BL=%x\n", __FUNCTION__, bl)); + m_P = (m_P + 1) & 0xFFF; + } + m_B = (m_B & ~15) | bl; +} + +/** + * @brief pps4_device::iT Transfer + * OPCODE cycles mnemonic + * ----------------------------- + * 10xx xxxx 1 cyc T * + * + * Symbolic equation + * ----------------------------- + * P(6:1) <- I(6:1) + * + * An unconditional transfer to a ROM word on the current + * page takes place. The least significant 6-bits of P + * register P(6:1) are replaced by six bit immediate + * field I(6:1) + */ +void pps4_device::iT() +{ + const UINT16 p = (m_P & ~63) | (m_I & 63); + LOG(("%s: P=%03x I=%02x -> P=%03x\n", __FUNCTION__, m_P, m_I, p)); + m_P = p; +} + +/** + * @brief pps4_device::iTM Transfer and mark indirect + * OPCODE cycles mnemonic + * ----------------------------- + * 11xx xxxx 2 cyc TM * + * yyyy yyyy from page 3 + * + * Symbolic equation + * ----------------------------- + * SB <- SA, SA <- P + * P(12:7) <- 000011 + * P(6:1) <- I1(6:1) + * + * P(12:9) <- 0001 + * P(8:1) <- I2(8:1) + * + * 48 consecutive locations on ROM page 3 contains pointer data + * which indentify subroutine entry addresses. These subroutine + * entry addresses are limited to pages 4 through 7. This TM + * instruction will save the address of the next ROM word in + * the SA register after loading the original contents of SA + * into SB. A transfer then occurs to one of the subroutine + * entry addresses. This instruction occupies one ROM word + * but takes two cycles for execution. + */ +void pps4_device::iTM() +{ + m_SB = m_SA; + m_SA = m_P; + m_P = 3 << 6; + m_P = m_P | (m_I & 63); + ARG(); + m_P = 1 << 8; + m_P |= m_I2; +} + +/** + * @brief pps4_device::iTL Transfer long + * OPCODE cycles mnemonic + * ----------------------------- + * 0101 xxxx 2 cyc TL * + * yyyy yyyy + * + * Symbolic equation + * ----------------------------- + * P(12:9) <- I1(4:1) + * P(8:1) <- I2(8:1) + * + * The instruction executes a transfer to any ROM word on any + * page. It occupies two ROM words an requires two cycles for + * execution. The first byte loads P(12:9) with field I1(4:1) + * and then the second byte I2(8:1) is placed in P(8:1). + */ +void pps4_device::iTL() +{ + ARG(); + m_P = (m_I & 15) << 8; + m_P = m_P | m_I2; +} + +/** + * @brief pps4_device::iTML Transfer and mark long + * OPCODE cycles mnemonic + * ----------------------------- + * 0101 xxxx 2 cyc TML * + * yyyy yyyy + * + * Symbolic equation + * ----------------------------- + * SB <- SA, SA <- P + * P(12:9) <- I1(4:1) + * P(8:1) <- I2(8:1) + * + * Note I1(2:1) != 00 + * + * This instruction executes a transfer and mark to any + * location on ROM pages 4 through 15. It occupies two + * ROM words and requires two cycle times for execution. + */ +void pps4_device::iTML() +{ + ARG(); + m_SB = m_SA; + m_SA = m_P; + m_P = (m_I & 15) << 8; + m_P = m_P | m_I2; +} + +/** + * @brief pps4_device::iSKC Skip on carry flip-flop + * OPCODE cycles mnemonic + * ----------------------------- + * 0001 0101 1 cyc SKC + * + * Symbolic equation + * ----------------------------- + * Skip if C = 1 + * + * The next ROM word will be ignored if C flip-flop is 1. + */ +void pps4_device::iSKC() +{ + m_P = m_P + m_C; + m_P = m_P & 0xFFF; +} + +/** + * @brief pps4_device::iSKC Skip on carry flip-flop + * OPCODE cycles mnemonic + * ----------------------------- + * 0001 1110 1 cyc SKZ + * + * Symbolic equation + * ----------------------------- + * Skip if A = 0 + * + * The next ROM word will be ignored if C flip-flop is 1. + */ +void pps4_device::iSKZ() +{ + m_P = m_P + (0 == m_A) ? 1 : 0; + m_P = m_P & 0xFFF; +} + +/** + * @brief pps4_device::iSKBI Skip if BL equal to immediate + * OPCODE cycles mnemonic + * ----------------------------- + * 0100 xxxx 1 cyc SKBI x + * + * Symbolic equation + * ----------------------------- + * Skip if BL = I(4:1) + * + * The next ROM word will be ignored if the least significant + * four bits of B register (BL) is equal to the 4-bit immediate + * field I(4:1) of instruction. + */ +void pps4_device::iSKBI() +{ + const unsigned imm = m_I & 15; + m_P = m_P + (imm == (m_B & 15)) ? 1 : 0; + m_P = m_P & 0xFFF; +} + +/** + * @brief pps4_device::iSKF1 Skip if FF1 equals 1 + * OPCODE cycles mnemonic + * ----------------------------- + * 0001 0110 1 cyc SKF1 + * + * Symbolic equation + * ----------------------------- + * Skip if FF1 = 1 + */ +void pps4_device::iSKF1() +{ + m_P = m_P + m_FF1; + m_P = m_P & 0xFFF; +} + +/** + * @brief pps4_device::iSKF2 Skip if FF2 equals 1 + * OPCODE cycles mnemonic + * ----------------------------- + * 0001 0100 1 cyc SKF2 + * + * Symbolic equation + * ----------------------------- + * Skip if FF2 = 1 + */ +void pps4_device::iSKF2() +{ + m_P = m_P + m_FF2; + m_P = m_P & 0xFFF; +} + +/** + * @brief pps4_device::iRTN Return + * OPCODE cycles mnemonic + * ----------------------------- + * 0000 0101 1 cyc RET + * + * Symbolic equation + * ----------------------------- + * P <- SA, SA <-> SB + * + * This instruction executes a return from subroutine + * by loading contents of SA register into P register + * and interchanges the SB and SA registers. + */ +void pps4_device::iRTN() +{ + m_P = m_SA; + // swap SA and SB + m_SA ^= m_SB; + m_SB ^= m_SA; + m_SA ^= m_SB; +} + +/** + * @brief pps4_device::iRTN Return + * OPCODE cycles mnemonic + * ----------------------------- + * 0000 0111 1 cyc RETSK + * + * Symbolic equation + * ----------------------------- + * P <- SA, SA <-> SB + * P <- P + 1 + * + * Same as RTN expect the first ROM word encountered + * after the return from subroutine is skipped. + */ +void pps4_device::iRTNSK() +{ + m_P = m_SA; + ROP(); // ignored + m_I = 0; // avoid LB/LBL or LDI skipping + // swap SA and SB + m_SA ^= m_SB; + m_SB ^= m_SA; + m_SA ^= m_SB; + m_P = m_P & 0xFFF; +} + +/** + * @brief pps4_device::IOL + * OPCODE cycles mnemonic + * ----------------------------- + * 0001 1100 2 cyc IOL + * yyyy yyyy + * + * Symbolic equation + * ----------------------------- + * ~A -> Data Bus + * A <- ~Data Bus + * I2 -> I/O device + * + * This instruction occupies two ROM words and requires two + * cycles for execution. The first ROM word is received by + * the CPU and sets up the I/O enable signal. The second + * ROM word is then received by the I/O devices and decoded + * for address and command. The contents of the accumulator + * inverted are placed on the data lines for acceptance by + * the I/O. At the same time, input data received by the I/O + * device is transferred to the accumulator inverted. + */ +void pps4_device::iIOL() +{ + const unsigned a = ~m_A & 15; + ARG(); + LOG(("%s: port:%X <- %02X\n", __FUNCTION__, m_I2, a)); + m_io->write_byte(m_I2, a); + m_A = ~m_io->read_byte(m_I2) & 15; + LOG(("%s: port:%X -> %02X\n", __FUNCTION__, m_I2, m_A)); +} + +/** + * @brief pps4_device::iDIA Discrete input group A + * OPCODE cycles mnemonic + * ----------------------------- + * 0010 0111 1 cyc DIA + * + * Symbolic equation + * ----------------------------- + * A <- DIA + * + * Data at the inputs to discrete group A is + * transferred to the accumulator. + */ +void pps4_device::iDIA() +{ + m_A = m_io->read_byte(PPS4_PORT_A); +} + +/** + * @brief pps4_device::iDIB Discrete input group B + * OPCODE cycles mnemonic + * ----------------------------- + * 0010 0011 1 cyc DIB + * + * Symbolic equation + * ----------------------------- + * A <- DIB + * + * Data at the inputs to discrete group B is + * transferred to the accumulator. + */ +void pps4_device::iDIB() +{ + m_A = m_io->read_byte(PPS4_PORT_B); +} + +/** + * @brief pps4_device::iDIA Discrete input group A + * OPCODE cycles mnemonic + * ----------------------------- + * 0010 1101 1 cyc DOA + * + * Symbolic equation + * ----------------------------- + * DOA <- A + * + * The contents of the accumulator are transferred + * to the discrete output register. + */ +void pps4_device::iDOA() +{ + m_io->write_byte(PPS4_PORT_A, m_A); +} + +/** + * @brief pps4_device::iSAG Special address generation + * OPCODE cycles mnemonic + * ----------------------------- + * 0010 1101 1 cyc SAG + * + * Symbolic equation + * ----------------------------- + * A/B Bus (12:5) <- 0000 0000 + * A/B Bus (4:1) <- BL(4:1) + * Contents of B remains unchanged + * + * The instruction causes the eight most significant bits + * of the RAM address output to be zeroed during the next + * cycle only. Note that this instruction does not alter + * the contents of the B register. + */ +void pps4_device::iSAG() +{ + // mask bits 12:5 + m_SAG = 0xff0; +} /*************************************************************************** COMMON EXECUTION ***************************************************************************/ +void pps4_device::execute_one() +{ + m_I = ROP(); + switch (m_I) { + case 0x00: + iLBL(); + break; + case 0x01: + iTML(); + break; + case 0x02: + iTML(); + break; + case 0x03: + iTML(); + break; + case 0x04: + iLBUA(); + break; + case 0x05: + iRTN(); + break; + case 0x06: + iXS(); + break; + case 0x07: + iRTNSK(); + break; + case 0x08: + iADCSK(); + break; + case 0x09: + iADSK(); + break; + case 0x0a: + iADC(); + break; + case 0x0b: + iAD(); + break; + case 0x0c: + iEOR(); + break; + case 0x0d: + iAND(); + break; + case 0x0e: + iCOMP(); + break; + case 0x0f: + iOR(); + break; + + case 0x10: + iLBMX(); + break; + case 0x11: + iLABL(); + break; + case 0x12: + iLAX(); + break; + case 0x13: + iSAG(); + break; + case 0x14: + iSKF2(); + break; + case 0x15: + iSKC(); + break; + case 0x16: + iSKF1(); + break; + case 0x17: + iINCB(); + break; + case 0x18: + iXBMX(); + break; + case 0x19: + iXABL(); + break; + case 0x1a: + iXAX(); + break; + case 0x1b: + iLXA(); + break; + case 0x1c: + iIOL(); + break; + case 0x1d: + iDOA(); + break; + case 0x1e: + iSKZ(); + break; + case 0x1f: + iDECB(); + break; + + case 0x20: + iSC(); + break; + case 0x21: + iSF2(); + break; + case 0x22: + iSF1(); + break; + case 0x23: + iDIB(); + break; + case 0x24: + iRC(); + break; + case 0x25: + iRF2(); + break; + case 0x26: + iRF1(); + break; + case 0x27: + iDIA(); + break; + + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + iEXD(); + break; + + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + iLD(); + break; + + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + iEX(); + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + iSKBI(); + break; + + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: case 0x5e: case 0x5f: + iTL(); + break; + + case 0x65: + iDC(); + break; + + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: + iADI(); + break; + + case 0x6f: + iCYS(); + break; + + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + iLDI(); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + iT(); + break; + + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + iLB(); + break; + + default: + iTM(); + } +} + void pps4_device::execute_run() { - do - { - debugger_instruction_hook(this, m_P.d); - execute_one(ROP()); + do + { + debugger_instruction_hook(this, m_P); + execute_one(); - } while (m_icount > 0); + } while (m_icount > 0); } /*************************************************************************** @@ -333,44 +1482,51 @@ void pps4_device::execute_run() void pps4_device::device_start() { - m_program = &space(AS_PROGRAM); - m_direct = &m_program->direct(); - m_data = &space(AS_DATA); - m_io = &space(AS_IO); - - save_item(NAME(m_A)); - save_item(NAME(m_X)); - save_item(NAME(m_P)); - save_item(NAME(m_SA)); - save_item(NAME(m_SB)); - save_item(NAME(m_B)); - save_item(NAME(m_C)); - save_item(NAME(m_FF1)); - save_item(NAME(m_FF2)); - - state_add( PPS4_PC, "PC", m_P.d ).mask(0xfff).formatstr("%03X"); - state_add( PPS4_A, "A", m_A ).formatstr("%02X"); // TODO: size? - state_add( PPS4_X, "X", m_X ).formatstr("%02X"); // TODO: size? - state_add( PPS4_SA, "SA", m_SA.d ).formatstr("%04X"); // TODO: size? - state_add( PPS4_SB, "SB", m_SB.d ).formatstr("%04X"); // TODO: size? - state_add( PPS4_B, "B", m_B.d ).formatstr("%04X"); // TODO: size? - state_add( STATE_GENPC, "GENPC", m_P.d ).noshow(); - state_add( STATE_GENFLAGS, "GENFLAGS", m_C ).formatstr("%3s").noshow(); - - m_icountptr = &m_icount; + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_data = &space(AS_DATA); + m_io = &space(AS_IO); + + save_item(NAME(m_A)); + save_item(NAME(m_X)); + save_item(NAME(m_P)); + save_item(NAME(m_SA)); + save_item(NAME(m_SB)); + save_item(NAME(m_SAG)); + save_item(NAME(m_B)); + save_item(NAME(m_C)); + save_item(NAME(m_FF1)); + save_item(NAME(m_FF2)); + save_item(NAME(m_I)); + save_item(NAME(m_I2)); + save_item(NAME(m_Ip)); + + state_add( PPS4_PC, "PC", m_P ).mask(0xFFF).formatstr("%03X"); + state_add( PPS4_A, "A", m_A ).formatstr("%01X"); + state_add( PPS4_X, "X", m_X ).formatstr("%01X"); + state_add( PPS4_SA, "SA", m_SA ).formatstr("%03X"); + state_add( PPS4_SB, "SB", m_SB ).formatstr("%03X"); + state_add( PPS4_B, "B", m_B ).formatstr("%03X"); + state_add( PPS4_SAG, "SAG", m_SAG ).formatstr("%03X"); + state_add( PPS4_I2, "I2", m_I2 ).formatstr("%02X").noshow(); + state_add( PPS4_Ip, "Ip", m_Ip ).formatstr("%02X").noshow(); + state_add( STATE_GENPC, "GENPC", m_P ).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_C).formatstr("%3s").noshow(); + + m_icountptr = &m_icount; } void pps4_device::state_string_export(const device_state_entry &entry, astring &string) { - switch (entry.index()) - { - case STATE_GENFLAGS: - string.printf("%c%c%c", - m_C ? 'C':'.', - m_FF1 ? '1':'.', - m_FF2 ? '2':'.'); - break; - } + switch (entry.index()) + { + case STATE_GENFLAGS: + string.printf("%c%c%c", + m_C ? 'C':'.', + m_FF1 ? '1':'.', + m_FF2 ? '2':'.'); + break; + } } /*************************************************************************** @@ -379,11 +1535,17 @@ void pps4_device::state_string_export(const device_state_entry &entry, astring & void pps4_device::device_reset() { - m_A = m_X = 0; - m_C = m_FF1 = m_FF2 = 0; - - m_P.d = 0; - m_SA.d = 0; - m_SB.d = 0; - m_B.d = 0; + m_A = 0; // Accumulator A(4:1) + m_X = 0; // X register X(4:1) + m_P = 0; // program counter P(12:1) + m_SA = 0; // Shift register SA(12:1) + m_SB = 0; // Shift register SB(12:1) + m_SAG = 0; // Special address generation mask + m_B = 0; // B address register B(12:1) (BL, BM and BU) + m_C = 0; // Carry flip-flop + m_FF1 = 0; // Flip-flop 1 + m_FF2 = 0; // Flip-flop 2 + m_I = 0; // Most recent instruction I(8:1) + m_I2 = 0; // Most recent parameter I2(8:1) + m_Ip = 0; // Previous instruction I(8:1) } diff --git a/src/emu/cpu/pps4/pps4.h b/src/emu/cpu/pps4/pps4.h index 1fa8f7dc377..35aebd0db2f 100644 --- a/src/emu/cpu/pps4/pps4.h +++ b/src/emu/cpu/pps4/pps4.h @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Miodrag Milanovic +// copyright-holders:Juergen Buchmueller <pullmoll@t-online.de> #ifndef __PPS4_H__ #define __PPS4_H__ @@ -9,11 +9,20 @@ ***************************************************************************/ enum { - PPS4_PC, - PPS4_A,PPS4_X,PPS4_SA,PPS4_SB,PPS4_B, - PPS4_GENPC = STATE_GENPC, - PPS4_GENSP = STATE_GENSP, - PPS4_GENPCBASE = STATE_GENPCBASE + PPS4_PC, + PPS4_A, + PPS4_X, + PPS4_SA, + PPS4_SB, + PPS4_B, + PPS4_SAG, + PPS4_I2, + PPS4_Ip, + PPS4_GENPC = STATE_GENPC, + PPS4_GENSP = STATE_GENSP, + PPS4_GENPCBASE = STATE_GENPCBASE, + PPS4_PORT_A = 256, + PPS4_PORT_B = 257 }; /*************************************************************************** @@ -26,69 +35,130 @@ enum extern const device_type PPS4; - class pps4_device : public cpu_device { public: - // construction/destruction - pps4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + // construction/destruction + pps4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); protected: - // device-level overrides - virtual void device_start(); - virtual void device_reset(); - - // device_execute_interface overrides - virtual UINT32 execute_min_cycles() const { return 1; } - virtual UINT32 execute_max_cycles() const { return 2; } - virtual UINT32 execute_input_lines() const { return 0; } - virtual UINT32 execute_default_irq_vector() const { return 0; } - virtual void execute_run(); - - // device_memory_interface overrides - virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const - { - return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : ( (spacenum == AS_DATA) ? &m_data_config : NULL ) ); - } - - // device_state_interface overrides - void state_string_export(const device_state_entry &entry, astring &string); - - // device_disasm_interface overrides - virtual UINT32 disasm_min_opcode_bytes() const { return 1; } - virtual UINT32 disasm_max_opcode_bytes() const { return 2; } - virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 3; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual UINT32 execute_default_irq_vector() const { return 0; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const + { + return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : ( (spacenum == AS_DATA) ? &m_data_config : NULL ) ); + } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, astring &string); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 2; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); private: - address_space_config m_program_config; - address_space_config m_data_config; - address_space_config m_io_config; - - UINT8 m_A; // Accumulator - UINT8 m_X; - - PAIR m_P; - PAIR m_SA; - PAIR m_SB; - PAIR m_B; // BU + BM + BL - - UINT8 m_C; // Carry flag - UINT8 m_FF1; // Flip-flop 1 - UINT8 m_FF2; // Flip-flop 2 - - address_space *m_program; - direct_read_data *m_direct; - address_space *m_data; - address_space *m_io; - - int m_icount; - - inline UINT8 ROP(); - inline UINT8 ARG(); - inline void DO_SKIP(); - void execute_one(int opcode); - + address_space_config m_program_config; + address_space_config m_data_config; + address_space_config m_io_config; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_data; + address_space *m_io; + int m_icount; + + UINT8 m_A; //!< Accumulator A(4:1) + UINT8 m_X; //!< X register X(4:1) + UINT16 m_P; //!< program counter P(12:1) + UINT16 m_SA; //!< Shift register SA(12:1) + UINT16 m_SB; //!< Shift register SB(12:1) + UINT16 m_SAG; //!< Special address generation mask + UINT16 m_B; //!< B register B(12:1) (BL, BM and BH) + UINT8 m_C; //!< Carry flip-flop + UINT8 m_FF1; //!< Flip-flop 1 + UINT8 m_FF2; //!< Flip-flop 2 + UINT8 m_I; //!< Most recent instruction I(8:1) + UINT8 m_I2; //!< Most recent parameter I2(8:1) + UINT8 m_Ip; //!< Previous instruction I(8:1) + + //! return the contents of B register (made of BU, BM and BL) + inline UINT16 B() const; + + //! return memory at address B(12:1) + inline UINT8 M(); + + //! write to memory at address B(12:1) + inline void W(UINT8 data); + + //! return the next opcode (also in m_I) + inline UINT8 ROP(); + + //! return the next argument (also in m_I2) + inline UINT8 ARG(); + + void iAD(); //!< Add + void iADC(); //!< Add with carry-in + void iADSK(); //!< Add and skip on carry-out + void iADCSK(); //!< Add with carry-in and skip on carry-out + void iADI(); //!< Add immediate + void iDC(); //!< Decimal correction + void iAND(); //!< Logical AND + void iOR(); //!< Logical OR + void iEOR(); //!< Logical Exclusive-OR + void iCOMP(); //!< Complement + void iSC(); //!< Set Carry flip-flop + void iRC(); //!< Reset Carry flip-flop + void iSF1(); //!< Set FF1 + void iRF1(); //!< Reset FF1 + void iSF2(); //!< Set FF2 + void iRF2(); //!< Reset FF2 + void iLD(); //!< Load accumulator from memory + void iEX(); //!< Exchange accumulator and memory + void iEXD(); //!< Exchange accumulator and memory and decrement BL + void iLDI(); //!< Load accumulator immediate + void iLAX(); //!< Load accumulator from X register + void iLXA(); //!< Load X register from accumulator + void iLABL(); //!< Load accumulator with BL + void iLBMX(); //!< Load BM with X + void iLBUA(); //!< Load BU with A + void iXABL(); //!< Exchange accumulator and BL + void iXBMX(); //!< Exchange BM and X registers + void iXAX(); //!< Exchange accumulator and X + void iXS(); //!< Eychange SA and SB registers + void iCYS(); //!< Cycle SA register and accumulaor + void iLB(); //!< Load B indirect + void iLBL(); //!< Load B long + void iINCB(); //!< Increment BL + void iDECB(); //!< Decrement BL + void iT(); //!< Transfer + void iTM(); //!< Transfer and mark indirect + void iTL(); //!< Transfer long + void iTML(); //!< Transfer and mark long + void iSKC(); //!< Skip on carry flip-flop + void iSKZ(); //!< Skip on accumulator zero + void iSKBI(); //!< Skip if BL equal to immediate + void iSKF1(); //!< Skip if FF1 equals 1 + void iSKF2(); //!< Skip if FF2 equals 1 + void iRTN(); //!< Return + void iRTNSK(); //!< Return and skip + void iIOL(); //!< Input/Output long + void iDIA(); //!< Discrete input group A + void iDIB(); //!< Discrete input group B + void iDOA(); //!< Discrete output group A + void iSAG(); //!< Special address generation + + void execute_one(); //!< execute one instruction }; - -#endif +#endif // __PPS4_H__ diff --git a/src/emu/cpu/pps4/pps4dasm.c b/src/emu/cpu/pps4/pps4dasm.c index f3cb664f0e9..35eda8e09fb 100644 --- a/src/emu/cpu/pps4/pps4dasm.c +++ b/src/emu/cpu/pps4/pps4dasm.c @@ -1,135 +1,426 @@ // license:BSD-3-Clause -// copyright-holders:Miodrag Milanovic +// copyright-holders:Juergen Buchmueller <pullmoll@t-online.de> /***************************************************************************** * * pps4dasm.c * * Rockwell PPS-4 CPU Disassembly * + * + * TODO: double verify all opcodes with t_Ixx flags + * *****************************************************************************/ - #include "emu.h" #define OP(A) oprom[(A) - PC] #define ARG(A) opram[(A) - PC] +typedef enum pps4_token_e { + t_AD, t_ADC, t_ADSK, t_ADCSK, t_ADI, + t_DC, t_AND, t_OR, t_EOR, t_COMP, + t_SC, t_RC, t_SF1, t_RF1, t_SF2, + t_RF2, t_LD, t_EX, t_EXD, t_LDI, + t_LAX, t_LXA, t_LABL, t_LBMX, t_LBUA, + t_XABL, t_XBMX, t_XAX, t_XS, t_CYS, + t_LB, t_LBL, t_INCB, t_DECB, t_T, + t_TM, t_TL, t_TML, t_SKC, t_SKZ, + t_SKBI, t_SKF1, t_SKF2, t_RTN, t_RTNSK, + t_IOL, t_DIA, t_DIB, t_DOA, t_SAG, + t_COUNT, + t_MASK = (1 << 6) - 1, + t_I3c = 1 << 6, /* immediate 3 bit constant, complemented */ + t_I4 = 1 << 7, /* immediate 4 bit constant */ + t_I4c = 1 << 8, /* immediate 4 bit constant, complemented */ + t_I4p = 1 << 9, /* immediate 4 bit offset into page 3 */ + t_I6p = 1 << 10, /* immediate 6 bit constant; address in current page */ + t_I8 = 1 << 11, /* immediate 8 bit constant (I/O port number) */ + t_I8c = 1 << 12, /* immediate 8 bit constant inverted */ +} pps4_token_e; + +static const char *token_str[t_COUNT] = { + "ad", /* add */ + "adc", /* add with carry-in */ + "adsk", /* add and skip on carry-out */ + "adcsk", /* add with carry-in and skip on carry-out */ + "adi", /* add immediate */ + "dc", /* decimal correction */ + "and", /* logical and */ + "or", /* logical or */ + "eor", /* logical exclusive-orf */ + "comp", /* complement */ + "sc", /* set C flip-flop */ + "rc", /* reset C flip-flop */ + "sf1", /* set FF1 flip-flop */ + "rf1", /* reset FF1 flip-flop */ + "sf2", /* set FF2 flip-flop */ + "rf2", /* reset FF2 flip-flop */ + "ld", /* load accumulator from memory */ + "ex", /* exchange accumulator and memory */ + "exd", /* exchange accumulator and memory and decrement BL */ + "ldi", /* load accumulator immediate */ + "lax", /* load accumulator from X register */ + "lxa", /* load X register from accumulator */ + "labl", /* load accumulator with BL */ + "lbmx", /* load BM with X */ + "lbua", /* load BU with A */ + "xabl", /* exchange accumulator and BL */ + "xbmx", /* exchange BM and X */ + "xax", /* exchange accumulator and X */ + "xs", /* exchange SA and SB */ + "cys", /* cycle SA register and accumulator */ + "lb", /* load B indirect */ + "lbl", /* load B long */ + "incb", /* increment BL */ + "decb", /* decrement BL */ + "t", /* transfer */ + "tm", /* transfer and mark indirect */ + "tl", /* transfer long */ + "tml", /* transfer and mark long */ + "skc", /* skip on C flip-flop equals 1 */ + "skz", /* skip on accumulator zero */ + "skbi", /* skip on BL equal to immediate */ + "skf1", /* skip on FF1 flip-flop equals 1 */ + "skf2", /* skip on FF2 flip-flop equals 1 */ + "rtn", /* return */ + "rtnsk", /* return and skip */ + "iol", /* input/output long */ + "dia", /* discrete input group A */ + "dib", /* discrete input group B */ + "doa", /* discrete output */ + "sag" /* special address generation */ +}; + +static const UINT16 table[] = { + t_LBL | t_I8c, /* 00 */ + t_TML | t_I4 | t_I8, /* 01 */ + t_TML | t_I4 | t_I8, /* 02 */ + t_TML | t_I4 | t_I8, /* 03 */ + t_LBUA, /* 04 */ + t_RTN, /* 05 */ + t_XS, /* 06 */ + t_RTNSK, /* 07 */ + t_ADCSK, /* 08 */ + t_ADSK, /* 09 */ + t_ADC, /* 0a */ + t_AD, /* 0b */ + t_EOR, /* 0c */ + t_AND, /* 0d */ + t_COMP, /* 0e */ + t_OR, /* 0f */ + + t_LBMX, /* 10 */ + t_LABL, /* 11 */ + t_LAX, /* 12 */ + t_SAG, /* 13 */ + t_SKF2, /* 14 */ + t_SKC, /* 15 */ + t_SKF1, /* 16 */ + t_INCB, /* 17 */ + t_XBMX, /* 18 */ + t_XABL, /* 19 */ + t_XAX, /* 1a */ + t_LXA, /* 1b */ + t_IOL | t_I8, /* 1c */ + t_DOA, /* 1d */ + t_SKZ, /* 1e */ + t_DECB, /* 1f */ + + t_SC, /* 20 */ + t_SF2, /* 21 */ + t_SF1, /* 22 */ + t_DIB, /* 23 */ + t_RC, /* 24 */ + t_RF2, /* 25 */ + t_RF1, /* 26 */ + t_DIA, /* 27 */ + t_EXD | t_I3c, /* 28 */ + t_EXD | t_I3c, /* 29 */ + t_EXD | t_I3c, /* 2a */ + t_EXD | t_I3c, /* 2b */ + t_EXD | t_I3c, /* 2c */ + t_EXD | t_I3c, /* 2d */ + t_EXD | t_I3c, /* 2e */ + t_EXD | t_I3c, /* 2f */ + + t_LD | t_I3c, /* 30 */ + t_LD | t_I3c, /* 31 */ + t_LD | t_I3c, /* 32 */ + t_LD | t_I3c, /* 33 */ + t_LD | t_I3c, /* 34 */ + t_LD | t_I3c, /* 35 */ + t_LD | t_I3c, /* 36 */ + t_LD | t_I3c, /* 37 */ + t_EX | t_I3c, /* 38 */ + t_EX | t_I3c, /* 39 */ + t_EX | t_I3c, /* 3a */ + t_EX | t_I3c, /* 3b */ + t_EX | t_I3c, /* 3c */ + t_EX | t_I3c, /* 3d */ + t_EX | t_I3c, /* 3e */ + t_EX | t_I3c, /* 3f */ + + t_SKBI | t_I4, /* 40 */ + t_SKBI | t_I4, /* 41 */ + t_SKBI | t_I4, /* 42 */ + t_SKBI | t_I4, /* 43 */ + t_SKBI | t_I4, /* 44 */ + t_SKBI | t_I4, /* 45 */ + t_SKBI | t_I4, /* 46 */ + t_SKBI | t_I4, /* 47 */ + t_SKBI | t_I4, /* 48 */ + t_SKBI | t_I4, /* 49 */ + t_SKBI | t_I4, /* 4a */ + t_SKBI | t_I4, /* 4b */ + t_SKBI | t_I4, /* 4c */ + t_SKBI | t_I4, /* 4d */ + t_SKBI | t_I4, /* 4e */ + t_SKBI | t_I4, /* 4f */ + + t_TL | t_I4 | t_I8, /* 50 */ + t_TL | t_I4 | t_I8, /* 51 */ + t_TL | t_I4 | t_I8, /* 52 */ + t_TL | t_I4 | t_I8, /* 53 */ + t_TL | t_I4 | t_I8, /* 54 */ + t_TL | t_I4 | t_I8, /* 55 */ + t_TL | t_I4 | t_I8, /* 56 */ + t_TL | t_I4 | t_I8, /* 57 */ + t_TL | t_I4 | t_I8, /* 58 */ + t_TL | t_I4 | t_I8, /* 59 */ + t_TL | t_I4 | t_I8, /* 5a */ + t_TL | t_I4 | t_I8, /* 5b */ + t_TL | t_I4 | t_I8, /* 5c */ + t_TL | t_I4 | t_I8, /* 5d */ + t_TL | t_I4 | t_I8, /* 5e */ + t_TL | t_I4 | t_I8, /* 5f */ + + t_ADI | t_I4c, /* 60 */ + t_ADI | t_I4c, /* 61 */ + t_ADI | t_I4c, /* 62 */ + t_ADI | t_I4c, /* 63 */ + t_ADI | t_I4c, /* 64 */ + t_DC, /* 65 */ + t_ADI | t_I4c, /* 66 */ + t_ADI | t_I4c, /* 67 */ + t_ADI | t_I4c, /* 68 */ + t_ADI | t_I4c, /* 69 */ + t_ADI | t_I4c, /* 6a */ + t_ADI | t_I4c, /* 6b */ + t_ADI | t_I4c, /* 6c */ + t_ADI | t_I4c, /* 6d */ + t_ADI | t_I4c, /* 6e */ + t_CYS, /* 6f */ + + t_LDI | t_I4c, /* 70 */ + t_LDI | t_I4c, /* 71 */ + t_LDI | t_I4c, /* 72 */ + t_LDI | t_I4c, /* 73 */ + t_LDI | t_I4c, /* 74 */ + t_LDI | t_I4c, /* 75 */ + t_LDI | t_I4c, /* 76 */ + t_LDI | t_I4c, /* 77 */ + t_LDI | t_I4c, /* 78 */ + t_LDI | t_I4c, /* 79 */ + t_LDI | t_I4c, /* 7a */ + t_LDI | t_I4c, /* 7b */ + t_LDI | t_I4c, /* 7c */ + t_LDI | t_I4c, /* 7d */ + t_LDI | t_I4c, /* 7e */ + t_LDI | t_I4c, /* 7f */ + + t_T | t_I6p, /* 80 */ + t_T | t_I6p, /* 81 */ + t_T | t_I6p, /* 82 */ + t_T | t_I6p, /* 83 */ + t_T | t_I6p, /* 84 */ + t_T | t_I6p, /* 85 */ + t_T | t_I6p, /* 86 */ + t_T | t_I6p, /* 87 */ + t_T | t_I6p, /* 88 */ + t_T | t_I6p, /* 89 */ + t_T | t_I6p, /* 8a */ + t_T | t_I6p, /* 8b */ + t_T | t_I6p, /* 8c */ + t_T | t_I6p, /* 8d */ + t_T | t_I6p, /* 8e */ + t_T | t_I6p, /* 8f */ + + t_T | t_I6p, /* 90 */ + t_T | t_I6p, /* 91 */ + t_T | t_I6p, /* 92 */ + t_T | t_I6p, /* 93 */ + t_T | t_I6p, /* 94 */ + t_T | t_I6p, /* 95 */ + t_T | t_I6p, /* 96 */ + t_T | t_I6p, /* 97 */ + t_T | t_I6p, /* 98 */ + t_T | t_I6p, /* 99 */ + t_T | t_I6p, /* 9a */ + t_T | t_I6p, /* 9b */ + t_T | t_I6p, /* 9c */ + t_T | t_I6p, /* 9d */ + t_T | t_I6p, /* 9e */ + t_T | t_I6p, /* 9f */ + + t_T | t_I6p, /* a0 */ + t_T | t_I6p, /* a1 */ + t_T | t_I6p, /* a2 */ + t_T | t_I6p, /* a3 */ + t_T | t_I6p, /* a4 */ + t_T | t_I6p, /* a5 */ + t_T | t_I6p, /* a6 */ + t_T | t_I6p, /* a7 */ + t_T | t_I6p, /* a8 */ + t_T | t_I6p, /* a9 */ + t_T | t_I6p, /* aa */ + t_T | t_I6p, /* ab */ + t_T | t_I6p, /* ac */ + t_T | t_I6p, /* ad */ + t_T | t_I6p, /* ae */ + t_T | t_I6p, /* af */ + + t_T | t_I6p, /* b0 */ + t_T | t_I6p, /* b1 */ + t_T | t_I6p, /* b2 */ + t_T | t_I6p, /* b3 */ + t_T | t_I6p, /* b4 */ + t_T | t_I6p, /* b5 */ + t_T | t_I6p, /* b6 */ + t_T | t_I6p, /* b7 */ + t_T | t_I6p, /* b8 */ + t_T | t_I6p, /* b9 */ + t_T | t_I6p, /* ba */ + t_T | t_I6p, /* bb */ + t_T | t_I6p, /* bc */ + t_T | t_I6p, /* bd */ + t_T | t_I6p, /* be */ + t_T | t_I6p, /* bf */ + + t_LB | t_I4p, /* c0 */ + t_LB | t_I4p, /* c1 */ + t_LB | t_I4p, /* c2 */ + t_LB | t_I4p, /* c3 */ + t_LB | t_I4p, /* c4 */ + t_LB | t_I4p, /* c5 */ + t_LB | t_I4p, /* c6 */ + t_LB | t_I4p, /* c7 */ + t_LB | t_I4p, /* c8 */ + t_LB | t_I4p, /* c9 */ + t_LB | t_I4p, /* ca */ + t_LB | t_I4p, /* cb */ + t_LB | t_I4p, /* cc */ + t_LB | t_I4p, /* cd */ + t_LB | t_I4p, /* ce */ + t_LB | t_I4p, /* cf */ + + t_TM | t_I6p, /* d0 */ + t_TM | t_I6p, /* d1 */ + t_TM | t_I6p, /* d2 */ + t_TM | t_I6p, /* d3 */ + t_TM | t_I6p, /* d4 */ + t_TM | t_I6p, /* d5 */ + t_TM | t_I6p, /* d6 */ + t_TM | t_I6p, /* d7 */ + t_TM | t_I6p, /* d8 */ + t_TM | t_I6p, /* d9 */ + t_TM | t_I6p, /* da */ + t_TM | t_I6p, /* db */ + t_TM | t_I6p, /* dc */ + t_TM | t_I6p, /* dd */ + t_TM | t_I6p, /* de */ + t_TM | t_I6p, /* df */ + + t_TM | t_I6p, /* e0 */ + t_TM | t_I6p, /* e1 */ + t_TM | t_I6p, /* e2 */ + t_TM | t_I6p, /* e3 */ + t_TM | t_I6p, /* e4 */ + t_TM | t_I6p, /* e5 */ + t_TM | t_I6p, /* e6 */ + t_TM | t_I6p, /* e7 */ + t_TM | t_I6p, /* e8 */ + t_TM | t_I6p, /* e9 */ + t_TM | t_I6p, /* ea */ + t_TM | t_I6p, /* eb */ + t_TM | t_I6p, /* ec */ + t_TM | t_I6p, /* ed */ + t_TM | t_I6p, /* ee */ + t_TM | t_I6p, /* ef */ + + t_TM | t_I6p, /* f0 */ + t_TM | t_I6p, /* f1 */ + t_TM | t_I6p, /* f2 */ + t_TM | t_I6p, /* f3 */ + t_TM | t_I6p, /* f4 */ + t_TM | t_I6p, /* f5 */ + t_TM | t_I6p, /* f6 */ + t_TM | t_I6p, /* f7 */ + t_TM | t_I6p, /* f8 */ + t_TM | t_I6p, /* f9 */ + t_TM | t_I6p, /* fa */ + t_TM | t_I6p, /* fb */ + t_TM | t_I6p, /* fc */ + t_TM | t_I6p, /* fd */ + t_TM | t_I6p, /* fe */ + t_TM | t_I6p, /* ff */ +}; + CPU_DISASSEMBLE( pps4 ) { - UINT32 flags = 0; - unsigned PC = pc; - UINT8 op; - switch (op = OP(pc++)) - { - // Arithmetic instructions - case 0x0b: sprintf (buffer,"ad"); break; - case 0x0a: sprintf (buffer,"adc"); break; - case 0x09: sprintf (buffer,"adsk"); break; - case 0x08: sprintf (buffer,"adcsk"); break; - case 0x60: case 0x61: case 0x62: case 0x63: - case 0x64: case 0x66: case 0x67: case 0x68: - case 0x69: case 0x6a: case 0x6b: case 0x6c: - case 0x6d: case 0x6e: - sprintf (buffer,"adi %01x",(op & 0x0f)); break; - case 0x65: sprintf (buffer,"dc"); break; - // Logical instructions - case 0x0d: sprintf (buffer,"and"); break; - case 0x0f: sprintf (buffer,"or"); break; - case 0x0c: sprintf (buffer,"eor"); break; - case 0x0e: sprintf (buffer,"comp"); break; - // Data transfer instructions - case 0x20: sprintf (buffer,"sc"); break; - case 0x24: sprintf (buffer,"rc"); break; - case 0x22: sprintf (buffer,"sf1"); break; - case 0x26: sprintf (buffer,"rf1"); break; - case 0x21: sprintf (buffer,"sf2"); break; - case 0x25: sprintf (buffer,"rf2"); break; - case 0x30: case 0x31: case 0x32: case 0x33: - case 0x34: case 0x35: case 0x36: case 0x37: - sprintf (buffer,"ld %01x",(op & 0x07)); break; - case 0x38: case 0x39: case 0x3a: case 0x3b: - case 0x3c: case 0x3d: case 0x3e: case 0x3f: - sprintf (buffer,"ex %01x",(op & 0x07)); break; - case 0x28: case 0x29: case 0x2a: case 0x2b: - case 0x2c: case 0x2d: case 0x2e: case 0x2f: - sprintf (buffer,"exd %01x",(op & 0x07)); break; - case 0x70: case 0x71: case 0x72: case 0x73: - case 0x74: case 0x75: case 0x76: case 0x77: - sprintf (buffer,"ldi %01x",(op & 0x0f)); break; - case 0x12: sprintf (buffer,"lax"); break; - case 0x1b: sprintf (buffer,"lxa"); break; - case 0x11: sprintf (buffer,"labl"); break; - case 0x10: sprintf (buffer,"lbmx"); break; - case 0x04: sprintf (buffer,"lbua"); break; - case 0x19: sprintf (buffer,"xabl"); break; - case 0x18: sprintf (buffer,"xbmx"); break; - case 0x1a: sprintf (buffer,"xax"); break; - case 0x06: sprintf (buffer,"xs"); break; - case 0x6f: sprintf (buffer,"cys"); break; - case 0xc0: case 0xc1: case 0xc2: case 0xc3: - case 0xc4: case 0xc5: case 0xc6: case 0xc7: - case 0xc8: case 0xc9: case 0xca: case 0xcb: - case 0xcc: case 0xcd: case 0xce: case 0xcf: - sprintf (buffer,"lb %02x",ARG(pc)); pc++; break; - case 0x00: sprintf (buffer,"lbl %02x",ARG(pc)); pc++; break; - case 0x17: sprintf (buffer,"incb"); break; - case 0x1f: sprintf (buffer,"decb"); break; - // Control transfer instructions - case 0x80: case 0x81: case 0x82: case 0x83: - case 0x84: case 0x85: case 0x86: case 0x87: - case 0x88: case 0x89: case 0x8a: case 0x8b: - case 0x8c: case 0x8d: case 0x8e: case 0x8f: - case 0x90: case 0x91: case 0x92: case 0x93: - case 0x94: case 0x95: case 0x96: case 0x97: - case 0x98: case 0x99: case 0x9a: case 0x9b: - case 0x9c: case 0x9d: case 0x9e: case 0x9f: - case 0xa0: case 0xa1: case 0xa2: case 0xa3: - case 0xa4: case 0xa5: case 0xa6: case 0xa7: - case 0xa8: case 0xa9: case 0xaa: case 0xab: - case 0xac: case 0xad: case 0xae: case 0xaf: - case 0xb0: case 0xb1: case 0xb2: case 0xb3: - case 0xb4: case 0xb5: case 0xb6: case 0xb7: - case 0xb8: case 0xb9: case 0xba: case 0xbb: - case 0xbc: case 0xbd: case 0xbe: case 0xbf: - sprintf (buffer,"t %02x",(op & 0x3f)); break; - case 0xd0: case 0xd1: case 0xd2: case 0xd3: - case 0xd4: case 0xd5: case 0xd6: case 0xd7: - case 0xd8: case 0xd9: case 0xda: case 0xdb: - case 0xdc: case 0xdd: case 0xde: case 0xdf: - case 0xe0: case 0xe1: case 0xe2: case 0xe3: - case 0xe4: case 0xe5: case 0xe6: case 0xe7: - case 0xe8: case 0xe9: case 0xea: case 0xeb: - case 0xec: case 0xed: case 0xee: case 0xef: - case 0xf0: case 0xf1: case 0xf2: case 0xf3: - case 0xf4: case 0xf5: case 0xf6: case 0xf7: - case 0xf8: case 0xf9: case 0xfa: case 0xfb: - case 0xfc: case 0xfd: case 0xfe: case 0xff: - sprintf (buffer,"tm %02x %02x",(op & 0x3f),ARG(pc)); pc++; break; - case 0x50: case 0x51: case 0x52: case 0x53: - case 0x54: case 0x55: case 0x56: case 0x57: - case 0x58: case 0x59: case 0x5a: case 0x5b: - case 0x5c: case 0x5d: case 0x5e: case 0x5f: - sprintf (buffer,"tl %01x %02x",(op & 0x0f),ARG(pc)); pc++; break; - case 0x01: case 0x02: case 0x03: - sprintf (buffer,"tml %02x",ARG(pc)); pc++; break; - case 0x15: sprintf (buffer,"skc"); break; - case 0x1e: sprintf (buffer,"skz"); break; - case 0x40: case 0x41: case 0x42: case 0x43: - case 0x44: case 0x45: case 0x46: case 0x47: - case 0x48: case 0x49: case 0x4a: case 0x4b: - case 0x4c: case 0x4d: case 0x4e: case 0x4f: - sprintf (buffer,"skbi %01x",(op & 0x0f)); break; - case 0x16: sprintf (buffer,"skf1"); break; - case 0x14: sprintf (buffer,"skf2"); break; - case 0x05: sprintf (buffer,"rtn"); break; - case 0x07: sprintf (buffer,"rtnsk"); break; - // Input/Output instructions - case 0x1c: sprintf (buffer,"iol %02x",ARG(pc)); pc++; break; - case 0x27: sprintf (buffer,"dia"); break; - case 0x23: sprintf (buffer,"dib"); break; - case 0x1d: sprintf (buffer,"doa"); break; - // Special instructions - case 0x13: sprintf (buffer,"sag"); break; - } - - return (pc - PC) | flags | DASMFLAG_SUPPORTED; + UINT32 flags = 0; + unsigned PC = pc; + UINT8 op = OP(pc++); + UINT32 tok = table[op]; + char *dst = 0; + + if (0 == (tok & t_MASK)) + sprintf(buffer, "%s", token_str[tok & t_MASK]); + else + dst = buffer + sprintf(buffer, "%-7s", token_str[tok & t_MASK]); + + if (tok & t_I3c) { + // 3 bit immediate, complemented + UINT8 i = ~op & 7; + dst += sprintf(dst, "%x", i); + } + + if (tok & t_I4) { + // 4 bit immediate + UINT8 i = op & 15; + dst += sprintf(dst, "%x", i); + } + + if (tok & t_I4c) { + // 4 bit immediate, complemented + UINT8 i = ~op & 15; + dst += sprintf(dst, "%x", i); + } + + if (tok & t_I4p) { + // 4 bit immediate offset into page 3 + UINT8 i = op & 15; + dst += sprintf(dst, "[%x]", 0x0c0 | i); + } + + if (tok & t_I6p) { + // 6 bit immediate offset into current page + UINT8 i = op & 63; + dst += sprintf(dst, "%x", (PC & ~63) | i); + } + + if (tok & t_I8) { + // 8 bit immediate I/O port address + UINT8 arg = ARG(pc++); + dst += sprintf(dst, "%02x", arg); + } + + if (tok & t_I8c) { + // 8 bit immediate offset into page + UINT16 arg = ~ARG(pc++) & 255; + dst += sprintf(dst, "%03x", arg); + } + + if (0x05 == op || 0x07 == op) // RTN or RTNSK + flags |= DASMFLAG_STEP_OUT; + + return (pc - PC) | flags | DASMFLAG_SUPPORTED; } |