mirror of
https://github.com/holub/mame
synced 2025-06-02 02:49:44 +03:00
494 lines
16 KiB
C++
494 lines
16 KiB
C++
// license:BSD-3-Clause
|
|
// copyright-holders:Curt Coder
|
|
/**********************************************************************
|
|
|
|
RCA COSMAC CPU emulation
|
|
|
|
**********************************************************************
|
|
_____ _____
|
|
Vcc 1 |* \_/ | 40 Vdd
|
|
_BUS 3 2 | | 39 _BUS 4
|
|
_BUS 2 3 | | 38 _BUS 5
|
|
_BUS 1 4 | | 37 _BUS 6
|
|
_BUS 0 5 | | 36 _BUS 7
|
|
_N0 6 | | 35 Vss
|
|
_N1 7 | | 34 _EF1
|
|
_N2 8 | | 33 _EF2
|
|
_N3 9 | | 32 _EF3
|
|
* 10 | CDP1801U | 31 _EF4
|
|
* 11 | | 30 _DMA OUT
|
|
* 12 | | 29 _INTERRUPT
|
|
* 13 | | 28 _DMA IN
|
|
* 14 | | 27 _CLEAR
|
|
_CLOCK 15 | | 26 _LOAD
|
|
_TPB 16 | | 25 _SC2
|
|
_TPA 17 | | 24 _SC1
|
|
* 18 | | 23 _SC0
|
|
MWR 19 | | 22 _M READ
|
|
Vss 20 |_____________| 21 *
|
|
|
|
_____ _____
|
|
Vcc 1 |* \_/ | 28 Vdd
|
|
_BUS 4 2 | | 27 _BUS 3
|
|
_BUS 5 3 | | 26 _BUS 2
|
|
_BUS 6 4 | | 25 _BUS 1
|
|
_BUS 7 5 | | 24 _BUS 0
|
|
_MA0 6 | | 23 *
|
|
_MA1 7 | CDP1801C | 22 _TPB
|
|
_MA2 8 | | 21 *
|
|
_MA3 9 | | 20 *
|
|
_MA4 10 | | 19 *
|
|
_MA5 11 | | 18 *
|
|
_MA6 12 | | 17 *
|
|
_MA7 13 | | 16 *
|
|
Vss 14 |_____________| 15 _CLEAR
|
|
|
|
_____ _____
|
|
CLOCK 1 |* \_/ | 40 Vdd
|
|
_WAIT 2 | | 39 _XTAL
|
|
_CLEAR 3 | | 38 _DMA IN
|
|
Q 4 | | 37 _DMA OUT
|
|
SC1 5 | | 36 _INTERRUPT
|
|
SC0 6 | | 35 _MWR
|
|
_MRD 7 | | 34 TPA
|
|
BUS 7 8 | | 33 TPB
|
|
BUS 6 9 | CDP1802 | 32 MA7
|
|
BUS 5 10 | CDP1803 | 31 MA6
|
|
BUS 4 11 | CDP1804 | 30 MA5
|
|
BUS 3 12 | CDP1805 | 29 MA4
|
|
BUS 2 13 | CDP1806 | 28 MA3
|
|
BUS 1 14 | | 27 MA2
|
|
BUS 0 15 | | 26 MA1
|
|
* 16 | | 25 MA0
|
|
N2 17 | | 24 _EF1
|
|
N1 18 | | 23 _EF2
|
|
N0 19 | | 22 _EF3
|
|
Vss 20 |_____________| 21 _EF4
|
|
|
|
|
|
Type Internal ROM Internal RAM Timer Pin 16 (*)
|
|
------------------------------------------------------------------
|
|
CDP1802 none none no Vcc
|
|
CDP1803 ? ? ? ?
|
|
CDP1804 2 KB 64 bytes yes ?
|
|
CDP1805 none 64 bytes yes _ME
|
|
CDP1806 none none yes Vdd
|
|
|
|
**********************************************************************/
|
|
|
|
#ifndef MAME_CPU_COSMAC_COSMAC_H
|
|
#define MAME_CPU_COSMAC_COSMAC_H
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
//**************************************************************************
|
|
// INTERFACE CONFIGURATION MACROS
|
|
//**************************************************************************
|
|
|
|
#define MCFG_COSMAC_WAIT_CALLBACK(_read) \
|
|
devcb = &cosmac_device::set_wait_rd_callback(*device, DEVCB_##_read);
|
|
|
|
#define MCFG_COSMAC_CLEAR_CALLBACK(_read) \
|
|
devcb = &cosmac_device::set_clear_rd_callback(*device, DEVCB_##_read);
|
|
|
|
#define MCFG_COSMAC_EF1_CALLBACK(_read) \
|
|
devcb = &cosmac_device::set_ef1_rd_callback(*device, DEVCB_##_read);
|
|
|
|
#define MCFG_COSMAC_EF2_CALLBACK(_read) \
|
|
devcb = &cosmac_device::set_ef2_rd_callback(*device, DEVCB_##_read);
|
|
|
|
#define MCFG_COSMAC_EF3_CALLBACK(_read) \
|
|
devcb = &cosmac_device::set_ef3_rd_callback(*device, DEVCB_##_read);
|
|
|
|
#define MCFG_COSMAC_EF4_CALLBACK(_read) \
|
|
devcb = &cosmac_device::set_ef4_rd_callback(*device, DEVCB_##_read);
|
|
|
|
#define MCFG_COSMAC_Q_CALLBACK(_write) \
|
|
devcb = &cosmac_device::set_q_wr_callback(*device, DEVCB_##_write);
|
|
|
|
#define MCFG_COSMAC_DMAR_CALLBACK(_read) \
|
|
devcb = &cosmac_device::set_dma_rd_callback(*device, DEVCB_##_read);
|
|
|
|
#define MCFG_COSMAC_DMAW_CALLBACK(_write) \
|
|
devcb = &cosmac_device::set_dma_wr_callback(*device, DEVCB_##_write);
|
|
|
|
#define MCFG_COSMAC_SC_CALLBACK(_write) \
|
|
devcb = &cosmac_device::set_sc_wr_callback(*device, DEVCB_##_write);
|
|
|
|
|
|
|
|
//**************************************************************************
|
|
// ENUMERATIONS
|
|
//**************************************************************************
|
|
|
|
// input lines
|
|
enum
|
|
{
|
|
COSMAC_INPUT_LINE_WAIT = 0,
|
|
COSMAC_INPUT_LINE_CLEAR,
|
|
COSMAC_INPUT_LINE_INT,
|
|
COSMAC_INPUT_LINE_DMAIN,
|
|
COSMAC_INPUT_LINE_DMAOUT,
|
|
COSMAC_INPUT_LINE_EF1,
|
|
COSMAC_INPUT_LINE_EF2,
|
|
COSMAC_INPUT_LINE_EF3,
|
|
COSMAC_INPUT_LINE_EF4
|
|
};
|
|
|
|
|
|
// state codes
|
|
enum cosmac_state_code
|
|
{
|
|
COSMAC_STATE_CODE_S0_FETCH = 0,
|
|
COSMAC_STATE_CODE_S1_EXECUTE,
|
|
COSMAC_STATE_CODE_S2_DMA,
|
|
COSMAC_STATE_CODE_S3_INTERRUPT
|
|
};
|
|
|
|
|
|
|
|
//**************************************************************************
|
|
// TYPE DEFINITIONS
|
|
//**************************************************************************
|
|
|
|
// ======================> cosmac_device
|
|
|
|
class cosmac_device : public cpu_device
|
|
{
|
|
public:
|
|
// registers
|
|
// public because machine/pecom.cpp accesses registers through the state interface - there should be a proper way to get address on bus for this
|
|
// drivers/microkit.cpp and drivers/eti660.cpp are even worse setting R0 through the state interface to hack around running boot code or something
|
|
enum
|
|
{
|
|
COSMAC_P,
|
|
COSMAC_X,
|
|
COSMAC_D,
|
|
COSMAC_B,
|
|
COSMAC_T,
|
|
COSMAC_R0,
|
|
COSMAC_R1,
|
|
COSMAC_R2,
|
|
COSMAC_R3,
|
|
COSMAC_R4,
|
|
COSMAC_R5,
|
|
COSMAC_R6,
|
|
COSMAC_R7,
|
|
COSMAC_R8,
|
|
COSMAC_R9,
|
|
COSMAC_Ra,
|
|
COSMAC_Rb,
|
|
COSMAC_Rc,
|
|
COSMAC_Rd,
|
|
COSMAC_Re,
|
|
COSMAC_Rf,
|
|
COSMAC_DF,
|
|
COSMAC_IE,
|
|
COSMAC_Q,
|
|
COSMAC_N,
|
|
COSMAC_I,
|
|
COSMAC_SC
|
|
};
|
|
|
|
|
|
template <class Object> static devcb_base &set_wait_rd_callback(device_t &device, Object &&cb) { return downcast<cosmac_device &>(device).m_read_wait.set_callback(std::forward<Object>(cb)); }
|
|
template <class Object> static devcb_base &set_clear_rd_callback(device_t &device, Object &&cb) { return downcast<cosmac_device &>(device).m_read_clear.set_callback(std::forward<Object>(cb)); }
|
|
template <class Object> static devcb_base &set_ef1_rd_callback(device_t &device, Object &&cb) { return downcast<cosmac_device &>(device).m_read_ef1.set_callback(std::forward<Object>(cb)); }
|
|
template <class Object> static devcb_base &set_ef2_rd_callback(device_t &device, Object &&cb) { return downcast<cosmac_device &>(device).m_read_ef2.set_callback(std::forward<Object>(cb)); }
|
|
template <class Object> static devcb_base &set_ef3_rd_callback(device_t &device, Object &&cb) { return downcast<cosmac_device &>(device).m_read_ef3.set_callback(std::forward<Object>(cb)); }
|
|
template <class Object> static devcb_base &set_ef4_rd_callback(device_t &device, Object &&cb) { return downcast<cosmac_device &>(device).m_read_ef4.set_callback(std::forward<Object>(cb)); }
|
|
template <class Object> static devcb_base &set_q_wr_callback(device_t &device, Object &&cb) { return downcast<cosmac_device &>(device).m_write_q.set_callback(std::forward<Object>(cb)); }
|
|
template <class Object> static devcb_base &set_dma_rd_callback(device_t &device, Object &&cb) { return downcast<cosmac_device &>(device).m_read_dma.set_callback(std::forward<Object>(cb)); }
|
|
template <class Object> static devcb_base &set_dma_wr_callback(device_t &device, Object &&cb) { return downcast<cosmac_device &>(device).m_write_dma.set_callback(std::forward<Object>(cb)); }
|
|
template <class Object> static devcb_base &set_sc_wr_callback(device_t &device, Object &&cb) { return downcast<cosmac_device &>(device).m_write_sc.set_callback(std::forward<Object>(cb)); }
|
|
|
|
// public interfaces
|
|
offs_t get_memory_address();
|
|
|
|
DECLARE_WRITE_LINE_MEMBER( wait_w ) { set_input_line(COSMAC_INPUT_LINE_WAIT, state); }
|
|
DECLARE_WRITE_LINE_MEMBER( clear_w ) { set_input_line(COSMAC_INPUT_LINE_CLEAR, state); }
|
|
DECLARE_WRITE_LINE_MEMBER( int_w ) { set_input_line(COSMAC_INPUT_LINE_INT, state); }
|
|
DECLARE_WRITE_LINE_MEMBER( dma_in_w ) { set_input_line(COSMAC_INPUT_LINE_DMAIN, state); }
|
|
DECLARE_WRITE_LINE_MEMBER( dma_out_w ) { set_input_line(COSMAC_INPUT_LINE_DMAOUT, state); }
|
|
DECLARE_WRITE_LINE_MEMBER( ef1_w ) { set_input_line(COSMAC_INPUT_LINE_EF1, state); }
|
|
DECLARE_WRITE_LINE_MEMBER( ef2_w ) { set_input_line(COSMAC_INPUT_LINE_EF2, state); }
|
|
DECLARE_WRITE_LINE_MEMBER( ef3_w ) { set_input_line(COSMAC_INPUT_LINE_EF3, state); }
|
|
DECLARE_WRITE_LINE_MEMBER( ef4_w ) { set_input_line(COSMAC_INPUT_LINE_EF4, state); }
|
|
|
|
protected:
|
|
// construction/destruction
|
|
cosmac_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;
|
|
|
|
// device_execute_interface overrides
|
|
virtual uint32_t execute_min_cycles() const override;
|
|
virtual uint32_t execute_max_cycles() const override;
|
|
virtual uint32_t execute_input_lines() const override;
|
|
virtual void execute_run() override;
|
|
virtual void execute_set_input(int inputnum, int state) override;
|
|
|
|
// device_memory_interface overrides
|
|
virtual space_config_vector memory_space_config() const override;
|
|
|
|
// device_state_interface overrides
|
|
virtual void state_import(const device_state_entry &entry) override;
|
|
virtual void state_export(const device_state_entry &entry) override;
|
|
virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
|
|
|
|
// device_disasm_interface overrides
|
|
virtual uint32_t disasm_min_opcode_bytes() const override;
|
|
virtual uint32_t disasm_max_opcode_bytes() const override;
|
|
|
|
// helpers
|
|
inline uint8_t read_opcode(offs_t pc);
|
|
inline uint8_t read_byte(offs_t address);
|
|
inline uint8_t read_io_byte(offs_t address);
|
|
inline void write_byte(offs_t address, uint8_t data);
|
|
inline void write_io_byte(offs_t address, uint8_t data);
|
|
|
|
// execution logic
|
|
inline void run();
|
|
inline void debug();
|
|
inline void reset();
|
|
inline void initialize();
|
|
inline void fetch_instruction();
|
|
inline void execute_instruction();
|
|
inline void dma_input();
|
|
inline void dma_output();
|
|
inline void interrupt();
|
|
inline void sample_wait_clear();
|
|
inline void sample_ef_lines();
|
|
inline void output_state_code();
|
|
inline void set_q_flag(int state);
|
|
|
|
// arithmetic handlers
|
|
void add(int left, int right);
|
|
void add_with_carry(int left, int right);
|
|
void subtract(int left, int right);
|
|
void subtract_with_borrow(int left, int right);
|
|
|
|
// condition handlers
|
|
void short_branch(int taken);
|
|
void long_branch(int taken);
|
|
void long_skip(int taken);
|
|
|
|
// control handlers
|
|
void return_from_interrupt(int ie);
|
|
|
|
// memory reference opcode handlers
|
|
void ldn();
|
|
void lda();
|
|
void ldx();
|
|
void ldxa();
|
|
void ldi();
|
|
void str();
|
|
void stxd();
|
|
|
|
// register operations opcode handlers
|
|
void inc();
|
|
void dec();
|
|
void irx();
|
|
void glo();
|
|
void plo();
|
|
void ghi();
|
|
void phi();
|
|
|
|
// logic operations opcode handlers
|
|
void _or();
|
|
void ori();
|
|
void _xor();
|
|
void xri();
|
|
void _and();
|
|
void ani();
|
|
void shr();
|
|
void shrc();
|
|
void shl();
|
|
void shlc();
|
|
|
|
// arithmetic operations opcode handlers
|
|
void add();
|
|
void adi();
|
|
void adc();
|
|
void adci();
|
|
void sd();
|
|
void sdi();
|
|
void sdb();
|
|
void sdbi();
|
|
void sm();
|
|
void smi();
|
|
void smb();
|
|
void smbi();
|
|
|
|
// short branch instructions opcode handlers
|
|
void br();
|
|
void nbr();
|
|
void bz();
|
|
void bnz();
|
|
void bdf();
|
|
void bnf();
|
|
void bq();
|
|
void bnq();
|
|
void b();
|
|
void bn();
|
|
|
|
// long branch instructions opcode handlers
|
|
void lbr();
|
|
void nlbr();
|
|
void lbz();
|
|
void lbnz();
|
|
void lbdf();
|
|
void lbnf();
|
|
void lbq();
|
|
void lbnq();
|
|
|
|
// skip instructions opcode handlers
|
|
void lsz();
|
|
void lsnz();
|
|
void lsdf();
|
|
void lsnf();
|
|
void lsq();
|
|
void lsnq();
|
|
void lsie();
|
|
|
|
// control instructions opcode handlers
|
|
void idl();
|
|
void nop();
|
|
void und();
|
|
void sep();
|
|
void sex();
|
|
void seq();
|
|
void req();
|
|
void sav();
|
|
void mark();
|
|
void ret();
|
|
void dis();
|
|
|
|
// input/output byte transfer opcode handlers
|
|
void out();
|
|
void inp();
|
|
|
|
const address_space_config m_program_config;
|
|
const address_space_config m_io_config;
|
|
|
|
// device callbacks
|
|
devcb_read_line m_read_wait;
|
|
devcb_read_line m_read_clear;
|
|
devcb_read_line m_read_ef1;
|
|
devcb_read_line m_read_ef2;
|
|
devcb_read_line m_read_ef3;
|
|
devcb_read_line m_read_ef4;
|
|
devcb_write_line m_write_q;
|
|
devcb_read8 m_read_dma;
|
|
devcb_write8 m_write_dma;
|
|
devcb_write8 m_write_sc;
|
|
|
|
// control modes
|
|
enum class cosmac_mode : u8
|
|
{
|
|
LOAD = 0,
|
|
RESET,
|
|
PAUSE,
|
|
RUN
|
|
};
|
|
|
|
// execution states
|
|
enum class cosmac_state : u8
|
|
{
|
|
STATE_0_FETCH = 0,
|
|
STATE_1_RESET,
|
|
STATE_1_INIT,
|
|
STATE_1_EXECUTE,
|
|
STATE_2_DMA_IN,
|
|
STATE_2_DMA_OUT,
|
|
STATE_3_INT
|
|
};
|
|
|
|
// internal state
|
|
uint16_t m_pc; // fake program counter
|
|
uint8_t m_op; // current opcode
|
|
uint8_t m_flagsio; // flags storage for state saving
|
|
cosmac_state m_state; // state
|
|
cosmac_mode m_mode; // control mode
|
|
cosmac_mode m_pmode; // previous control mode
|
|
bool m_wait;
|
|
bool m_clear;
|
|
int m_irq; // interrupt request
|
|
int m_dmain; // DMA input request
|
|
int m_dmaout; // DMA output request
|
|
int m_ef[4]; // external flags
|
|
|
|
// registers
|
|
uint8_t m_d; // data register (accumulator)
|
|
uint8_t m_b; // auxiliary holding register
|
|
uint16_t m_r[16]; // scratchpad registers
|
|
uint8_t m_p; // designates which register is Program Counter
|
|
uint8_t m_x; // designates which register is Data Pointer
|
|
uint8_t m_n; // low-order instruction digit
|
|
uint8_t m_i; // high-order instruction digit
|
|
uint8_t m_t; // temporary register
|
|
|
|
// flags
|
|
int m_df; // data flag (ALU carry)
|
|
int m_ie; // interrupt enable
|
|
int m_q; // output flip-flop
|
|
|
|
// internal stuff
|
|
int m_icount;
|
|
address_space * m_program;
|
|
address_space * m_io;
|
|
direct_read_data * m_direct;
|
|
|
|
// opcode/condition tables
|
|
typedef void (cosmac_device::*ophandler)();
|
|
virtual cosmac_device::ophandler get_ophandler(uint8_t opcode) = 0;
|
|
};
|
|
|
|
|
|
// ======================> cdp1801_device
|
|
|
|
class cdp1801_device : public cosmac_device
|
|
{
|
|
public:
|
|
// construction/destruction
|
|
cdp1801_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
|
|
|
protected:
|
|
// device_disasm_interface overrides
|
|
virtual offs_t disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options) override;
|
|
|
|
virtual cosmac_device::ophandler get_ophandler(uint8_t opcode) override;
|
|
|
|
static const ophandler s_opcodetable[256];
|
|
};
|
|
|
|
|
|
// ======================> cdp1802_device
|
|
|
|
class cdp1802_device : public cosmac_device
|
|
{
|
|
public:
|
|
// construction/destruction
|
|
cdp1802_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
|
|
|
protected:
|
|
// device_disasm_interface overrides
|
|
virtual offs_t disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options) override;
|
|
|
|
virtual cosmac_device::ophandler get_ophandler(uint8_t opcode) override;
|
|
|
|
static const ophandler s_opcodetable[256];
|
|
};
|
|
|
|
|
|
// device type definition
|
|
DECLARE_DEVICE_TYPE(CDP1801, cdp1801_device)
|
|
DECLARE_DEVICE_TYPE(CDP1802, cdp1802_device)
|
|
|
|
|
|
#endif // MAME_CPU_COSMAC_COSMAC_H
|