nw, add skeleton and disassembler for DEC PDP-8 CPU

This commit is contained in:
therealmogminer@gmail.com 2015-08-13 14:37:07 +02:00
parent 21b7eb47cd
commit 5d7c5fc62b
4 changed files with 561 additions and 0 deletions

View File

@ -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

249
src/emu/cpu/pdp8/pdp8.c Normal file
View File

@ -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>;
//-------------------------------------------------
// 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;
}
}

113
src/emu/cpu/pdp8/pdp8.h Normal file
View File

@ -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__ */

183
src/emu/cpu/pdp8/pdp8dasm.c Normal file
View File

@ -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);
}