diff options
Diffstat (limited to 'src/devices/cpu/scmp')
-rw-r--r-- | src/devices/cpu/scmp/scmp.cpp | 88 | ||||
-rw-r--r-- | src/devices/cpu/scmp/scmp.h | 26 | ||||
-rw-r--r-- | src/devices/cpu/scmp/scmpdasm.cpp | 318 | ||||
-rw-r--r-- | src/devices/cpu/scmp/scmpdasm.h | 21 |
4 files changed, 243 insertions, 210 deletions
diff --git a/src/devices/cpu/scmp/scmp.cpp b/src/devices/cpu/scmp/scmp.cpp index bb19aef3536..efd89f31469 100644 --- a/src/devices/cpu/scmp/scmp.cpp +++ b/src/devices/cpu/scmp/scmp.cpp @@ -2,9 +2,10 @@ // copyright-holders:Miodrag Milanovic /***************************************************************************** * - * scmp.c + * scmp.cpp * - * National Semiconductor SC/MP CPU Disassembly + * National Semiconductor SC/MP CPU emulation + * (SC/MP = Simple-to-use, Cost-effective MicroProcessor) * *****************************************************************************/ @@ -12,13 +13,11 @@ #include "scmp.h" #include "scmpdasm.h" -#include "debugger.h" - //#define VERBOSE 1 #include "logmacro.h" -DEFINE_DEVICE_TYPE(SCMP, scmp_device, "ins8050", "National Semiconductor INS 8050 SC/MP") +DEFINE_DEVICE_TYPE(SCMP, scmp_device, "ins8050", "National Semiconductor ISP-8A/500D SC/MP") DEFINE_DEVICE_TYPE(INS8060, ins8060_device, "ins8060", "National Semiconductor INS 8060 SC/MP II") @@ -30,13 +29,13 @@ scmp_device::scmp_device(const machine_config &mconfig, const char *tag, device_ scmp_device::scmp_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : cpu_device(mconfig, type, tag, owner, clock) - , m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0) - , m_AC(0), m_ER(0), m_SR(0), m_program(nullptr), m_cache(nullptr), m_icount(0) + , m_program_config("program", ENDIANNESS_BIG, 8, 16, 0) + , m_AC(0), m_ER(0), m_SR(0) , m_flag_out_func(*this) , m_sout_func(*this) - , m_sin_func(*this) - , m_sensea_func(*this) - , m_senseb_func(*this) + , m_sin_func(*this, 0) + , m_sensea_func(*this, 0) + , m_senseb_func(*this, 0) , m_halt_func(*this) { } @@ -70,24 +69,24 @@ uint8_t scmp_device::ROP() { uint16_t pc = m_PC.w.l; m_PC.w.l = ADD12(m_PC.w.l,1); - return m_cache->read_byte( pc); + return m_cache.read_byte( pc); } uint8_t scmp_device::ARG() { uint16_t pc = m_PC.w.l; m_PC.w.l = ADD12(m_PC.w.l,1); - return m_cache->read_byte(pc); + return m_cache.read_byte(pc); } uint8_t scmp_device::RM(uint32_t a) { - return m_program->read_byte(a); + return m_program.read_byte(a); } void scmp_device::WM(uint32_t a, uint8_t v) { - m_program->write_byte(a, v); + m_program.write_byte(a, v); } void scmp_device::illegal(uint8_t opcode) @@ -134,15 +133,10 @@ uint16_t scmp_device::GET_ADDR(uint8_t code) uint16_t ptr = GET_PTR_REG(code & 0x03)->w.l; uint8_t arg = ARG(); - if (arg == 0x80) { + if (arg == 0x80) offset = m_ER; - } else { - if (arg & 0x80) { - offset = (int8_t)arg; - } else { - offset = arg; - } - } + else + offset = (int8_t)arg; addr = ADD12(ptr,offset); @@ -276,7 +270,8 @@ void scmp_device::execute_one(int opcode) // Transfer Instructions case 0x90 : case 0x91 : case 0x92 : case 0x93 :// JMP m_icount -= 11; - m_PC.w.l = ADD12(GET_PTR_REG(ptr)->w.l,(int8_t)ARG()); + tmp = ARG(); // PC must be updated before the destination address is calculated + m_PC.w.l = ADD12(GET_PTR_REG(ptr)->w.l,(int8_t)tmp); break; case 0x94 : case 0x95 : case 0x96 : case 0x97 : // JP @@ -312,7 +307,7 @@ void scmp_device::execute_one(int opcode) m_AC = 0xff; break; // Others are illegal - default : m_icount -= 1; + default : m_icount -= 5; illegal (opcode); break; } @@ -444,7 +439,7 @@ void scmp_device::execute_one(int opcode) m_icount -= 5; break; // Others are illegal - default : m_icount -= 1; + default : m_icount -= 5; illegal (opcode); break; } @@ -455,6 +450,7 @@ void scmp_device::execute_one(int opcode) /*************************************************************************** COMMON EXECUTION ***************************************************************************/ + void scmp_device::take_interrupt() { uint16_t tmp = ADD12(m_PC.w.l,-1); // We fix PC so at return it goes to current location @@ -487,31 +483,23 @@ void scmp_device::execute_run() void scmp_device::device_start() { - /* set up the state table */ - { - state_add(SCMP_PC, "PC", m_PC.w.l); - state_add(STATE_GENPC, "GENPC", m_PC.w.l).noshow(); - state_add(STATE_GENPCBASE, "CURPC", m_PC.w.l).noshow(); - state_add(STATE_GENFLAGS, "GENFLAGS", m_SR).noshow().formatstr("%8s"); - state_add(SCMP_P1, "P1", m_P1.w.l); - state_add(SCMP_P2, "P2", m_P2.w.l); - state_add(SCMP_P3, "P3", m_P3.w.l); - state_add(SCMP_AC, "AC", m_AC); - state_add(SCMP_ER, "ER", m_ER); - state_add(SCMP_SR, "SR", m_SR); - } - - m_program = &space(AS_PROGRAM); - m_cache = m_program->cache<0, 0, ENDIANNESS_LITTLE>(); - - /* resolve callbacks */ - m_flag_out_func.resolve_safe(); - m_sout_func.resolve_safe(); - m_sin_func.resolve_safe(0); - m_sensea_func.resolve_safe(0); - m_senseb_func.resolve_safe(0); - m_halt_func.resolve_safe(); - + space(AS_PROGRAM).cache(m_cache); + space(AS_PROGRAM).specific(m_program); + + // set up the state table + state_add(SCMP_PC, "PC", m_PC.w.l); + state_add(STATE_GENPC, "GENPC", m_PC.w.l).noshow(); + state_add(STATE_GENPCBASE, "CURPC", m_PC.w.l).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_SR).noshow().formatstr("%8s"); + + state_add(SCMP_P1, "P1", m_P1.w.l); + state_add(SCMP_P2, "P2", m_P2.w.l); + state_add(SCMP_P3, "P3", m_P3.w.l); + state_add(SCMP_AC, "AC", m_AC); + state_add(SCMP_ER, "ER", m_ER); + state_add(SCMP_SR, "SR", m_SR); + + // register for savestates save_item(NAME(m_PC)); save_item(NAME(m_P1)); save_item(NAME(m_P2)); diff --git a/src/devices/cpu/scmp/scmp.h b/src/devices/cpu/scmp/scmp.h index 83577285a85..9c102d240f2 100644 --- a/src/devices/cpu/scmp/scmp.h +++ b/src/devices/cpu/scmp/scmp.h @@ -29,13 +29,12 @@ protected: scmp_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); // device-level overrides - virtual void device_start() override; - virtual void device_reset() override; + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; // device_execute_interface overrides - virtual uint32_t execute_min_cycles() const override { return 5; } - virtual uint32_t execute_max_cycles() const override { return 131593; } - virtual uint32_t execute_input_lines() const override { return 0; } + virtual uint32_t execute_min_cycles() const noexcept override { return 5; } + virtual uint32_t execute_max_cycles() const noexcept override { return 23+8; } // max opcode + interrupt virtual void execute_run() override; // device_memory_interface overrides @@ -54,13 +53,14 @@ private: PAIR m_P1; PAIR m_P2; PAIR m_P3; - uint8_t m_AC; - uint8_t m_ER; - uint8_t m_SR; + uint8_t m_AC; + uint8_t m_ER; + uint8_t m_SR; - address_space *m_program; - memory_access_cache<0, 0, ENDIANNESS_LITTLE> *m_cache; - int m_icount; + memory_access<16, 0, 0, ENDIANNESS_BIG>::cache m_cache; + memory_access<16, 0, 0, ENDIANNESS_BIG>::specific m_program; + + int m_icount; devcb_write8 m_flag_out_func; devcb_write_line m_sout_func; @@ -91,8 +91,8 @@ public: ins8060_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); protected: - virtual uint64_t execute_clocks_to_cycles(uint64_t clocks) const override { return (clocks + 2 - 1) / 2; } - virtual uint64_t execute_cycles_to_clocks(uint64_t cycles) const override { return (cycles * 2); } + virtual uint64_t execute_clocks_to_cycles(uint64_t clocks) const noexcept override { return (clocks + 2 - 1) / 2; } + virtual uint64_t execute_cycles_to_clocks(uint64_t cycles) const noexcept override { return (cycles * 2); } }; diff --git a/src/devices/cpu/scmp/scmpdasm.cpp b/src/devices/cpu/scmp/scmpdasm.cpp index 1a906218a38..3a6fbbbfda4 100644 --- a/src/devices/cpu/scmp/scmpdasm.cpp +++ b/src/devices/cpu/scmp/scmpdasm.cpp @@ -1,156 +1,202 @@ // license:BSD-3-Clause -// copyright-holders:Miodrag Milanovic -/***************************************************************************** - * - * scmpdasm.c - * - * National Semiconductor SC/MP CPU Disassembly - * - *****************************************************************************/ +// copyright-holders:AJR +/*************************************************************************** + + National Semiconductor SC/MP disassembler + + The pseudo-instruction "JS Pn, dest" (not handled by this disassembler) + awkwardly effects a subroutine call by the following sequence of five + instructions: + + LDI H(dest-1) + XPAH Pn + LDI L(dest-1) + XPAL Pn + XPPC Pn + + The Programming and Assembler manual also mentions stacks, which are + only supported as a software convention. The .DBYTE directive stores + 16-bit data in big-endian format, though no single instruction loads + more than 8 bits. + + All address arithmetic operates within 4 KB pages, passing bits 15-12 + of pointer registers unchanged. + +***************************************************************************/ #include "emu.h" #include "scmpdasm.h" +scmp_disassembler::scmp_disassembler() + : util::disasm_interface() +{ +} + u32 scmp_disassembler::opcode_alignment() const { return 1; } -offs_t scmp_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) +u32 scmp_disassembler::interface_flags() const +{ + return PAGED; +} + +u32 scmp_disassembler::page_address_bits() const +{ + return 12; +} + +namespace { + +const char *const s_mref_insts[8] = +{ + "LD", "ST", "AND", "OR", "XOR", "DAD", "ADD", "CAD" +}; + +const char *const s_alu_ops[8] = +{ + "LD", "ST", "AN", "OR", "XR", "DA", "AD", "CA" +}; + +const char *const s_xfer_insts[4] = +{ + "JMP", "JP", "JZ", "JNZ" +}; + +const char *const s_ptr_regs[4] = +{ + "PC", "P1", "P2", "P3" +}; + +} // anonymous namespace + +void scmp_disassembler::format_disp(std::ostream &stream, offs_t pc, u8 op, u8 disp) { - unsigned PC = pc; - uint8_t op = opcodes.r8(pc++); - uint8_t ptr = op & 3; - - if (BIT(op,7)) { - // two bytes instructions - char as[10]; - char aspr[10]; - uint8_t arg = params.r8(pc); pc++; - if (arg==0x80) { - sprintf(as,"E"); - } else { - if (arg & 0x80) { - sprintf(as,"-$%02x",0x100-arg); - } else { - sprintf(as,"+$%02x",arg); - } + if (disp == 0x80) + util::stream_format(stream, "E(%s)", s_ptr_regs[BIT(op, 0, 2)]); + else if (BIT(op, 0, 2) == 0) + util::stream_format(stream, "X'%04X", (pc & 0xf000) | ((pc + ((op & 0xf0) == 0x90 ? 2 : 1) + s8(disp)) & 0x0fff)); + else + { + if (s8(disp) < 0) + { + stream << '-'; + disp = -disp; } - sprintf(aspr,"%s(%d)",as,ptr); + if (disp > 9) + stream << "X'"; + util::stream_format(stream, "%X(%s)", disp, s_ptr_regs[BIT(op, 0, 2)]); + } +} - switch (op) +offs_t scmp_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) +{ + u8 op = opcodes.r8(pc); + if (op >= 0xc0 && op != 0xcc) + { + if (BIT(op, 0, 3) == 4) { - // Memory Reference Instructions - case 0xc0 : util::stream_format(stream, "ld %s",as); break; - case 0xc1 : case 0xc2 : case 0xc3 : - util::stream_format(stream, "ld %s",aspr);break; - case 0xc5 : case 0xc6 : case 0xc7 : - util::stream_format(stream, "ld @%s",aspr); break; - case 0xc8 : util::stream_format(stream, "st %s",as); break; - case 0xc9 : case 0xca : case 0xcb : - util::stream_format(stream, "st %s",aspr);break; - case 0xcd : case 0xce : case 0xcf : - util::stream_format(stream, "st @%s",aspr); break; - case 0xd0 : util::stream_format(stream, "and %s",as); break; - case 0xd1 : case 0xd2 : case 0xd3 : - util::stream_format(stream, "and %s",aspr);break; - case 0xd5 : case 0xd6 : case 0xd7 : - util::stream_format(stream, "and @%s",aspr); break; - case 0xd8 : util::stream_format(stream, "or %s",as); break; - case 0xd9 : case 0xda : case 0xdb : - util::stream_format(stream, "or %s",aspr);break; - case 0xdd : case 0xde : case 0xdf : - util::stream_format(stream, "or @%s",aspr); break; - case 0xe0 : util::stream_format(stream, "xor %s",as); break; - case 0xe1 : case 0xe2 : case 0xe3 : - util::stream_format(stream, "xor %s",aspr);break; - case 0xe5 : case 0xe6 : case 0xe7 : - util::stream_format(stream, "xor @%s",aspr); break; - case 0xe8 : util::stream_format(stream, "dad %s",as); break; - case 0xe9 : case 0xea : case 0xeb : - util::stream_format(stream, "dad %s",aspr);break; - case 0xed : case 0xee : case 0xef : - util::stream_format(stream, "dad @%s",aspr); break; - case 0xf0 : util::stream_format(stream, "add %s",as); break; - case 0xf1 : case 0xf2 : case 0xf3 : - util::stream_format(stream, "add %s",aspr);break; - case 0xf5 : case 0xf6 : case 0xf7 : - util::stream_format(stream, "add @%s",aspr); break; - case 0xf8 : util::stream_format(stream, "cad %s",as); break; - case 0xf9 : case 0xfa : case 0xfb : - util::stream_format(stream, "cad %s",aspr);break; - case 0xfd : case 0xfe : case 0xff : - util::stream_format(stream, "cad @%s",aspr); break; - // Memory Increment/Decrement Instructions - case 0xa8 : case 0xa9 : case 0xaa : case 0xab : - util::stream_format(stream, "ild %s",aspr); break; - case 0xb8 : case 0xb9 : case 0xba : case 0xbb : - util::stream_format(stream, "dld %s",aspr); break; - // Immediate Instructions - case 0xc4 : util::stream_format(stream, "ldi $%02x",arg); break; - case 0xd4 : util::stream_format(stream, "ani $%02x",arg); break; - case 0xdc : util::stream_format(stream, "ori $%02x",arg); break; - case 0xe4 : util::stream_format(stream, "xri $%02x",arg); break; - case 0xec : util::stream_format(stream, "dai $%02x",arg); break; - case 0xf4 : util::stream_format(stream, "adi $%02x",arg); break; - case 0xfc : util::stream_format(stream, "cai $%02x",arg); break; - // Transfer Instructions - case 0x90 : util::stream_format(stream, "jmp %s",as);break; - case 0x91 : case 0x92 : case 0x93 : - util::stream_format(stream, "jmp %s",aspr);break; - case 0x94 : util::stream_format(stream, "jp %s",as); break; - case 0x95 : case 0x96 : case 0x97 : - util::stream_format(stream, "jp %s",aspr); break; - case 0x98 : util::stream_format(stream, "jz %s",as); break; - case 0x99 : case 0x9a : case 0x9b : - util::stream_format(stream, "jz %s",aspr); break; - case 0x9c : util::stream_format(stream, "jnz %s",as); break; - case 0x9d : case 0x9e : case 0x9f : - util::stream_format(stream, "jnz %s",aspr); break; - // Double-Byte Miscellaneous Instructions - case 0x8f: util::stream_format(stream, "dly $%02x",arg); break; - // Others are illegal - default : util::stream_format(stream, "illegal"); pc--; break; // Illegal we consider without param + // Immediate instructions + util::stream_format(stream, "%s%-6cX'%02X", s_alu_ops[BIT(op, 3, 3)], 'I', opcodes.r8(pc + 1)); } - } else { - // one byte instructions - switch (op) + else { - // Extension Register Instructions - case 0x40: util::stream_format(stream, "lde"); break; - case 0x01: util::stream_format(stream, "xae"); break; - case 0x50: util::stream_format(stream, "ane"); break; - case 0x58: util::stream_format(stream, "ore"); break; - case 0x60: util::stream_format(stream, "xre"); break; - case 0x68: util::stream_format(stream, "dae"); break; - case 0x70: util::stream_format(stream, "ade"); break; - case 0x78: util::stream_format(stream, "cae"); break; - // Pointer Register Move Instructions - case 0x30: case 0x31 :case 0x32: case 0x33: - util::stream_format(stream, "xpal %d",ptr); break; - case 0x34: case 0x35 :case 0x36: case 0x37: - util::stream_format(stream, "xpah %d",ptr); break; - case 0x3c: case 0x3d :case 0x3e: case 0x3f: - util::stream_format(stream, "xppc %d",ptr); break; - // Shift, Rotate, Serial I/O Instructions - case 0x19: util::stream_format(stream, "sio"); break; - case 0x1c: util::stream_format(stream, "sr"); break; - case 0x1d: util::stream_format(stream, "srl"); break; - case 0x1e: util::stream_format(stream, "rr"); break; - case 0x1f: util::stream_format(stream, "rrl"); break; - // Single Byte Miscellaneous Instructions - case 0x00: util::stream_format(stream, "halt"); break; - case 0x02: util::stream_format(stream, "ccl"); break; - case 0x03: util::stream_format(stream, "scl"); break; - case 0x04: util::stream_format(stream, "dint"); break; - case 0x05: util::stream_format(stream, "ien"); break; - case 0x06: util::stream_format(stream, "csa"); break; - case 0x07: util::stream_format(stream, "cas"); break; - case 0x08: util::stream_format(stream, "nop"); break; - // Others are illegal - default : util::stream_format(stream, "illegal"); break; + // Memory reference instructions + util::stream_format(stream, "%-8s", s_mref_insts[BIT(op, 3, 3)]); + if (BIT(op, 2)) + stream << '@'; // "Auto-indexed" (post-increment or pre-decrement) + format_disp(stream, pc, op, opcodes.r8(pc + 1)); } + return 2 | SUPPORTED; } + else if ((op & 0xec) == 0xa8) + { + // Memory increment/decrement instructions + util::stream_format(stream, "%-8s", BIT(op, 4) ? "DLD" : "ILD"); + format_disp(stream, pc, op, opcodes.r8(pc + 1)); + return 2 | SUPPORTED; + } + else if ((op & 0xf0) == 0x90) + { + // Transfer instructions (effective address is off by 1) + util::stream_format(stream, "%-8s", s_xfer_insts[BIT(op, 2, 2)]); + format_disp(stream, pc, op, opcodes.r8(pc + 1)); + return 2 | (BIT(op, 2, 2) != 0 ? STEP_COND : 0) | SUPPORTED; + } + else if (op == 0x8f) + { + util::stream_format(stream, "%-8s%d", "DLY", opcodes.r8(pc + 1)); + return 2 | SUPPORTED; + } + else + { + // Single-byte instructions + switch (op) + { + case 0x00: + stream << "HALT"; + break; + + case 0x01: + stream << "XAE"; + break; - return (pc - PC); + case 0x02: case 0x03: + util::stream_format(stream, "%cCL", BIT(op, 0) ? 'S' : 'C'); + break; + + case 0x04: + stream << "DINT"; + break; + + case 0x05: + stream << "IEN"; + break; + + case 0x06: + stream << "CSA"; + break; + + case 0x07: + stream << "CAS"; + break; + + case 0x08: + stream << "NOP"; + break; + + case 0x19: + stream << "SIO"; + break; + + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + // Shift and rotate instructions + util::stream_format(stream, "%cR", BIT(op, 1) ? 'R' : 'S'); + if (BIT(op, 0)) + stream << 'L'; + break; + + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + // Exchange pointer with AC + util::stream_format(stream, "%-8s%s", BIT(op, 2) ? "XPAH" : "XPAL", s_ptr_regs[BIT(op, 0, 2)]); + break; + + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + // Exchange pointer with PC + util::stream_format(stream, "%-8s%s", "XPPC", s_ptr_regs[BIT(op, 0, 2)]); + return 1 | STEP_OUT | SUPPORTED; + + case 0x40: case 0x50: case 0x58: case 0x60: case 0x68: case 0x70: case 0x78: + // Extension register instructions + util::stream_format(stream, "%sE", s_alu_ops[BIT(op, 3, 3)]); + break; + + default: + util::stream_format(stream, "%-8sX'%02X", ".BYTE", op); + break; + } + return 1 | SUPPORTED; + } } diff --git a/src/devices/cpu/scmp/scmpdasm.h b/src/devices/cpu/scmp/scmpdasm.h index 915f74ee848..2e45224933e 100644 --- a/src/devices/cpu/scmp/scmpdasm.h +++ b/src/devices/cpu/scmp/scmpdasm.h @@ -1,12 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Miodrag Milanovic -/***************************************************************************** - * - * scmpdasm.c - * - * National Semiconductor SC/MP CPU Disassembly - * - *****************************************************************************/ +// copyright-holders:AJR #ifndef MAME_CPU_SCMP_SCMPDASM_H #define MAME_CPU_SCMP_SCMPDASM_H @@ -16,11 +9,17 @@ class scmp_disassembler : public util::disasm_interface { public: - scmp_disassembler() = default; - virtual ~scmp_disassembler() = default; + scmp_disassembler(); + // util::disasm_interface overrides virtual u32 opcode_alignment() const override; + virtual u32 interface_flags() const override; + virtual u32 page_address_bits() const override; virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override; + +private: + // internal helpers + static void format_disp(std::ostream &stream, offs_t pc, u8 op, u8 disp); }; -#endif +#endif // MAME_CPU_SCMP_SCMPDASM_H |