summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/emu/cpu/pps4/pps4.c1776
-rw-r--r--src/emu/cpu/pps4/pps4.h196
-rw-r--r--src/emu/cpu/pps4/pps4dasm.c529
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;
}