mirror of
https://github.com/holub/mame
synced 2025-04-19 15:11:37 +03:00
nw, add skeleton and disassembler for DEC PDP-8 CPU
This commit is contained in:
parent
21b7eb47cd
commit
5d7c5fc62b
@ -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
249
src/emu/cpu/pdp8/pdp8.c
Normal 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
113
src/emu/cpu/pdp8/pdp8.h
Normal 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
183
src/emu/cpu/pdp8/pdp8dasm.c
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user