From 5d7c5fc62becc90d7b0eb9d04548cc2f587b0e19 Mon Sep 17 00:00:00 2001 From: "therealmogminer@gmail.com" Date: Thu, 13 Aug 2015 14:37:07 +0200 Subject: [PATCH] nw, add skeleton and disassembler for DEC PDP-8 CPU --- scripts/src/cpu.lua | 16 +++ src/emu/cpu/pdp8/pdp8.c | 249 ++++++++++++++++++++++++++++++++++++ src/emu/cpu/pdp8/pdp8.h | 113 ++++++++++++++++ src/emu/cpu/pdp8/pdp8dasm.c | 183 ++++++++++++++++++++++++++ 4 files changed, 561 insertions(+) create mode 100644 src/emu/cpu/pdp8/pdp8.c create mode 100644 src/emu/cpu/pdp8/pdp8.h create mode 100644 src/emu/cpu/pdp8/pdp8dasm.c diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index 5092c86044d..23cbfc8ff52 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -460,6 +460,22 @@ if (CPUS["T11"]~=null or _OPTIONS["with-tools"]) then table.insert(disasm_files , MAME_DIR .. "src/emu/cpu/t11/t11dasm.c") end +-------------------------------------------------- +-- DEC PDP-8 +--@src/emu/cpu/pdp8/pdp8.h,CPUS["PDP8"] = true +-------------------------------------------------- + +if (CPUS["PDP8"]~=null) then + files { + MAME_DIR .. "src/emu/cpu/pdp8/pdp8.c", + MAME_DIR .. "src/emu/cpu/pdp8/pdp8.h", + } +end + +if (CPUS["PDP8"]~=null or _OPTIONS["with-tools"]) then + table.insert(disasm_files , MAME_DIR .. "src/emu/cpu/pdp8/pdp8dasm.c") +end + -------------------------------------------------- -- F8 --@src/emu/cpu/f8/f8.h,CPUS["F8"] = true diff --git a/src/emu/cpu/pdp8/pdp8.c b/src/emu/cpu/pdp8/pdp8.c new file mode 100644 index 00000000000..dd2fd6fc6b3 --- /dev/null +++ b/src/emu/cpu/pdp8/pdp8.c @@ -0,0 +1,249 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/* + First-gen DEC PDP-8 emulator skeleton + + Written by MooglyGuy +*/ + +#include "emu.h" +#include "debugger.h" +#include "pdp8.h" + +CPU_DISASSEMBLE( pdp8 ); + +#define OP ((op >> 011) & 07) + +#define MR_IND ((op >> 010) & 01) +#define MR_PAGE ((op >> 07) & 01) +#define MR_ADDR (op & 0177) + +#define IOT_DEVICE ((op >> 03) & 077) +#define IOT_IOP1 (op & 01) +#define IOT_IOP2 ((op >> 01) & 01) +#define IOT_IOP4 ((op >> 02) & 01) + +#define OPR_GROUP ((op >> 010) & 01) +#define OPR_CLA ((op >> 07) & 01) +#define OPR_CLL ((op >> 06) & 01) +#define OPR_CMA ((op >> 05) & 01) +#define OPR_CML ((op >> 04) & 01) +#define OPR_ROR ((op >> 03) & 01) +#define OPR_ROL ((op >> 02) & 01) +#define OPR_ROT2 ((op >> 01) & 01) +#define OPR_IAC (op & 01) + +#define OPR_SMA OPR_CLL +#define OPR_SZA OPR_CMA +#define OPR_SNL OPR_CML +#define OPR_REVSKIP OPR_ROR +#define OPR_OSR OPR_ROL +#define OPR_HLT OPR_ROT2 + +#define OPR_GROUP_MASK 0401 +#define OPR_GROUP1_VAL 0000 +#define OPR_GROUP2_VAL 0400 + +const device_type PDP8CPU = &device_creator; + +//------------------------------------------------- +// pdp8_device - constructor +//------------------------------------------------- + +pdp8_device::pdp8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, PDP8CPU, "PDP8CPU", tag, owner, clock, "pdp8_cpu", __FILE__), + m_program_config("program", ENDIANNESS_BIG, 12, 12), + m_pc(0), + m_ac(0), + m_mb(0), + m_ma(0), + m_sr(0), + m_l(0), + m_ir(0), + m_halt(true), + m_icount(0) +{ + // Allocate & setup +} + + +void pdp8_device::device_start() +{ + m_program = &space(AS_PROGRAM); + + // register our state for the debugger + std::string tempstr; + state_add(STATE_GENPC, "GENPC", m_pc).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_l).callimport().callexport().formatstr("%1s").noshow(); + state_add(PDP8_PC, "PC", m_pc).mask(0xfff); + state_add(PDP8_AC, "AC", m_ac).mask(0xfff); + state_add(PDP8_MB, "MB", m_mb).mask(0xfff); + state_add(PDP8_MA, "MA", m_ma).mask(0xfff); + state_add(PDP8_SR, "SR", m_sr).mask(0xfff); + state_add(PDP8_L, "L", m_l).mask(0xf); + state_add(PDP8_IR, "IR", m_ir).mask(0xff); + state_add(PDP8_HALT, "HLT", m_halt).mask(0xf); + + // setup regtable + save_item(NAME(m_pc)); + save_item(NAME(m_ac)); + save_item(NAME(m_mb)); + save_item(NAME(m_ma)); + save_item(NAME(m_sr)); + save_item(NAME(m_l)); + save_item(NAME(m_ir)); + save_item(NAME(m_halt)); + + // set our instruction counter + m_icountptr = &m_icount; +} + +void pdp8_device::device_stop() +{ +} + +void pdp8_device::device_reset() +{ + m_pc = 0; + m_ac = 0; + m_mb = 0; + m_ma = 0; + m_sr = 0; + m_l = 0; + m_ir = 0; + m_halt = true; +} + + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config *pdp8_device::memory_space_config(address_spacenum spacenum) const +{ + if (spacenum == AS_PROGRAM) + { + return &m_program_config; + } + return NULL; +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void pdp8_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c", m_halt ? 'H' : '.'); + break; + } +} + + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 pdp8_device::disasm_min_opcode_bytes() const +{ + return 2; +} + + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 pdp8_device::disasm_max_opcode_bytes() const +{ + return 2; +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t pdp8_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( pdp8 ); + return CPU_DISASSEMBLE_NAME(pdp8)(this, buffer, pc, oprom, opram, options); +} + + +//************************************************************************** +// CORE EXECUTION LOOP +//************************************************************************** + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 pdp8_device::execute_min_cycles() const +{ + return 1; // TODO +} + + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 pdp8_device::execute_max_cycles() const +{ + return 3; // TODO +} + + +//------------------------------------------------- +// execute_input_lines - return the number of +// input/interrupt lines +//------------------------------------------------- + +UINT32 pdp8_device::execute_input_lines() const +{ + return 0; // TODO +} + + +//------------------------------------------------- +// execute_set_input - set the state of an input +// line during execution +//------------------------------------------------- + +void pdp8_device::execute_set_input(int inputnum, int state) +{ + // TODO +} + + +//------------------------------------------------- +// execute_run - execute a timeslice's worth of +// opcodes +//------------------------------------------------- + +void pdp8_device::execute_run() +{ + while (m_icount > 0) + { + m_pc &= 07777; + + debugger_instruction_hook(this, m_pc); + + UINT16 op = m_program->read_word(m_pc); + + --m_icount; + } +} diff --git a/src/emu/cpu/pdp8/pdp8.h b/src/emu/cpu/pdp8/pdp8.h new file mode 100644 index 00000000000..58332770dad --- /dev/null +++ b/src/emu/cpu/pdp8/pdp8.h @@ -0,0 +1,113 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/* + First-gen DEC PDP-8 CPU emulator + + Written by MooglyGuy +*/ + +#pragma once + +#ifndef __PDP8_H__ +#define __PDP8_H__ + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> pdp8_device + +// Used by core CPU interface +class pdp8_device : public cpu_device +{ +public: + // construction/destruction + pdp8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_stop(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // device_state_interface overrides + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // address spaces + const address_space_config m_program_config; + + enum state + { + FETCH, + DEFER, + EXECUTE, + WORD_COUNT, + CURRENT_ADDR, + BREAK + } + + enum opcode + { + AND = 0, + TAD, + ISZ, + DCA, + JMS, + JMP, + IOT, + OPR + } +private: + // CPU registers + UINT16 m_pc; + UINT16 m_ac; + UINT16 m_mb; + UINT16 m_ma; + UINT16 m_sr; + UINT8 m_l; + UINT8 m_ir; + bool m_halt; + + // other internal states + int m_icount; + + // address spaces + address_space *m_program; +}; + +// device type definition +extern const device_type PDP8CPU; + +/*************************************************************************** + REGISTER ENUMERATION +***************************************************************************/ + +enum +{ + PDP8_PC = 1, + PDP8_AC, + PDP8_MB, + PDP8_MA, + PDP8_SR, + PDP8_L, + PDP8_IR, + PDP8_HALT +}; + +CPU_DISASSEMBLE( pdp8 ); + +#endif /* __PDP8_H__ */ diff --git a/src/emu/cpu/pdp8/pdp8dasm.c b/src/emu/cpu/pdp8/pdp8dasm.c new file mode 100644 index 00000000000..5ed4e73ebbb --- /dev/null +++ b/src/emu/cpu/pdp8/pdp8dasm.c @@ -0,0 +1,183 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/* + First-gen DEC PDP-8 disassembler + + Written by MooglyGuy +*/ + +#include "emu.h" + +static char *output; + +static void ATTR_PRINTF(1,2) print(const char *fmt, ...) +{ + va_list vl; + + va_start(vl, fmt); + output += vsprintf(output, fmt, vl); + va_end(vl); +} + +offs_t pdp8_dasm_one(char *buffer, offs_t pc, UINT16 op) +{ + UINT8 opcode = (op >> 011) & 07; + UINT16 current_page = pc & 07600; + UINT16 zero_addr = op & 0177; + UINT16 current_addr = current_page | zero_addr; + bool indirect = (op & 0400) ? true : false; + bool zero_page = (op & 0200) ? false : true; + + output = buffer; + + switch (opcode) + { + case 0: + output += sprintf(buffer, "AND %c %05o", indirect ? 'I' : ' ', zero_page ? zero_addr : current_addr); + break; + case 1: + output += sprintf(buffer, "TAD %c %05o", indirect ? 'I' : ' ', zero_page ? zero_addr : current_addr); + break; + case 2: + output += sprintf(buffer, "ISZ %c %05o", indirect ? 'I' : ' ', zero_page ? zero_addr : current_addr); + break; + case 3: + output += sprintf(buffer, "DCA %c %05o", indirect ? 'I' : ' ', zero_page ? zero_addr : current_addr); + break; + case 4: + output += sprintf(buffer, "JMS %c %05o", indirect ? 'I' : ' ', zero_page ? zero_addr : current_addr); + break; + case 5: + output += sprintf(buffer, "JMP %c %05o", indirect ? 'I' : ' ', zero_page ? zero_addr : current_addr); + break; + case 6: + output += sprintf(buffer, "IOT %03o %01o", (op >> 03) & 077, op & 07); + break; + case 7: + { + bool group2 = ((op & 0401) == 0400); + if (!group2) + { + if (!(op & 0377)) + { + output += sprintf(buffer, "NOP "); + } + else + { + if (op & 0200) + { + output += sprintf(buffer, "CLA "); + } + if (op & 0100) + { + output += sprintf(buffer, "CLL "); + } + if (op & 040) + { + output += sprintf(buffer, "CMA "); + } + if (op & 020) + { + output += sprintf(buffer, "CML "); + } + if (op & 01) + { + output += sprintf(buffer, "IAC "); + } + if (op & 010) + { + if (op & 02) + { + output += sprintf(buffer, "RTR "); + } + else + { + output += sprintf(buffer, "RAR "); + } + } + if (op & 04) + { + if (op & 02) + { + output += sprintf(buffer, "RTL "); + } + else + { + output += sprintf(buffer, "RAL "); + } + } + } + } + else + { + if (!(op & 0377)) + { + output += sprintf(buffer, "NOP "); + } + else + { + if (op & 010) + { + if (!(op & 0160)) + { + output += sprintf(buffer, "SKP "); + } + else + { + if (op & 0100) + { + output += sprintf(buffer, "SPA "); + } + if (op & 040) + { + output += sprintf(buffer, "SNA "); + } + if (op & 020) + { + output += sprintf(buffer, "SZL "); + } + } + } + else + { + if (op & 0100) + { + output += sprintf(buffer, "SMA "); + } + if (op & 040) + { + output += sprintf(buffer, "SZA "); + } + if (op & 020) + { + output += sprintf(buffer, "SNL "); + } + } + if (op & 0200) + { + output += sprintf(buffer, "CLA "); + } + if (op & 04) + { + output += sprintf(buffer, "OSR "); + } + if (op & 02) + { + output += sprintf(buffer, "HLT "); + } + } + } + } + } + + return 2 | DASMFLAG_SUPPORTED; +} + +/*****************************************************************************/ + +CPU_DISASSEMBLE( pdp8 ) +{ + UINT16 op = (*(UINT8 *)(opram + 0) << 8) | + (*(UINT8 *)(opram + 1) << 0); + return pdp8_dasm_one(buffer, pc, op); +}