diff options
author | 2010-10-18 12:13:58 +0000 | |
---|---|---|
committer | 2010-10-18 12:13:58 +0000 | |
commit | 3c3f26a66ff25f34487261cfa67a79788881af8d (patch) | |
tree | 2e8586bd8d91d8e7fefecb0f618b7632b3b9a418 /src/emu | |
parent | 40910ec4a6b3a725f65699765e9f0a0c9a85c125 (diff) |
Converted the RCA CDP1802 CPU into a C++ device. Refactored cidelsa.c to use the new RCA COSMAC CPU. [Curt Coder]
Diffstat (limited to 'src/emu')
-rw-r--r-- | src/emu/cpu/cosmac/cosdasm.c | 173 | ||||
-rw-r--r-- | src/emu/cpu/cosmac/cosmac.c | 1173 | ||||
-rw-r--r-- | src/emu/cpu/cosmac/cosmac.h | 414 | ||||
-rw-r--r-- | src/emu/cpu/cpu.mak | 15 | ||||
-rw-r--r-- | src/emu/sound/cdp1869.c | 23 | ||||
-rw-r--r-- | src/emu/sound/cdp1869.h | 3 |
6 files changed, 1795 insertions, 6 deletions
diff --git a/src/emu/cpu/cosmac/cosdasm.c b/src/emu/cpu/cosmac/cosdasm.c new file mode 100644 index 00000000000..aa5dbe4a8fd --- /dev/null +++ b/src/emu/cpu/cosmac/cosdasm.c @@ -0,0 +1,173 @@ +/***************************************************************************** + * + * disasm.c + * portable cosmac cdp1802 emulator interface + * + * Copyright Peter Trauner, all rights reserved. + * + * - This source code is released as freeware for non-commercial purposes. + * - You are free to use and redistribute this code in modified or + * unmodified form, provided you list me in the credits. + * - If you modify this source code, you must add a notice to each modified + * source file that it has been changed. If you're a nice person, you + * will clearly mark each change too. :) + * - If you wish to use this for commercial purposes, please contact me at + * peter.trauner@jk.uni-linz.ac.at + * - The author of this copywritten work reserves the right to change the + * terms of its usage and license at any time, including retroactively + * - This entire notice must remain in the source code. + * + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" + +#include "cosmac.h" + +typedef enum +{ + Ill, + Imm, + Imp, + Imp2, // lownibble contains register number + Imp3, // bit 0,1,2 1..7 contains n0,n1,n2 level + Low, // only low byte of address specified + Abs +} Adr; + +static const struct { const char *mnemonic; Adr adr; } table[]={ + { "IDL", Imp }, { "LDN", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { "INC", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { "DEC", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + + { "BR", Low }, { "BQ", Low }, { "BZ", Low }, { "BDF", Low }, + { "B1", Low }, { "B2", Low }, { "B3", Low }, { "B4", Low }, + { "SKP", Low }, { "BNQ", Low }, { "BNZ", Low }, { "BNF", Low }, + { "BN1", Low }, { "BN2", Low }, { "BN3", Low }, { "BN4", Low }, + + { "LDA", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { "STR", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { "IRX", Imp } ,{ "OUT", Imp3},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 } ,{ "INP", Imp3},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { "RET", Imp }, { "DIS", Imp }, { "LDXA", Imp }, { "STXD", Imp }, + { "ADC", Imp }, { "SDB", Imp }, { "SHRC", Imp }, { "SMB", Imp }, + { "SAV", Imp }, { "MARK", Imp }, { "REQ", Imp }, { "SEQ", Imp }, + { "ADCI", Imm }, { "SDBI", Imm }, { "SHLC", Imp }, { "SMBI", Imm }, + + + { "GLO", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { "GHI", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { "PLO", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { "PHI", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { "LBR", Abs }, { "LBQ", Abs }, { "LBZ", Abs }, { "LBDF", Abs }, + { "NOP", Imp }, { "LSNQ", Imp }, { "LSNZ", Imp }, { "LSNF", Imp }, + { "LSKP", Imp }, { "LBNQ", Abs }, { "LBNZ", Abs }, { "LBNF", Abs }, + { "LSIE", Imp }, { "LSQ", Imp }, { "LSZ", Imp }, { "LSDF", Imp }, + + { "SEP", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { "SEX", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { "LDX", Imp }, { "OR", Imp }, { "AND", Imp }, { "XOR", Imp }, + { "ADD", Imp }, { "SD", Imp }, { "SHR", Imp }, { "SM", Imp }, + { "LDI", Imm }, { "ORI", Imm }, { "ANI", Imm }, { "XRI", Imm }, + { "ADI", Imm }, { "SDI", Imm }, { "SHL", Imp }, { "SMI", Imm }, + +}; + +CPU_DISASSEMBLE( cosmac ) +{ + UINT32 flags = 0; + int oldpc = pc; + int oper; + UINT16 absolut; + oldpc&=0xffff; + pc=oldpc; + oper=oprom[pc++ - oldpc]; + + switch(oper&0xf0) { + case 0: + if (oper==0) { + sprintf(buffer,"%-5s",table[oper].mnemonic); + } else { + sprintf(buffer,"%-5sR%.1x",table[(oper&0xf0)|1].mnemonic, oper&0x0f); + } + break; + case 0xd0: + flags = DASMFLAG_STEP_OVER; + /* fall through */ + case 0x10: + case 0x20: + case 0x40: + case 0x50: + case 0x80: + case 0x90: + case 0xa0: + case 0xb0: + case 0xe0: + sprintf(buffer,"%-5sR%.1x",table[oper&0xf0].mnemonic, oper&0x0f); + break; + default: + switch(oper&0xf8) { + case 0x60: + if (oper==0x60) { + sprintf(buffer,"%-5s",table[oper].mnemonic); + } else { + sprintf(buffer,"%-5s%d",table[(oper&0xf8)|1].mnemonic, oper&0x7); + } + break; + case 0x68: + sprintf(buffer,"%-5s%d",table[(oper&0xf8)|1].mnemonic, oper&0x7); + break; + default: + switch (table[oper].adr) { + case Imp: + sprintf(buffer,"%-5s",table[oper].mnemonic); + if (oper == 0x70 || oper == 0x71) + flags = DASMFLAG_STEP_OUT; + break; + case Imm: + sprintf(buffer,"%-5s#%.2x",table[oper].mnemonic,oprom[pc++ - oldpc]); + break; + case Low: + absolut=oprom[pc++ - oldpc]; + absolut|=pc&0xff00; + sprintf(buffer,"%-5s%.4x",table[oper].mnemonic,absolut); + break; + case Abs: + absolut=oprom[pc++ - oldpc]<<8; + absolut|=oprom[pc++ - oldpc]; + sprintf(buffer,"%-5s%.4x",table[oper].mnemonic,absolut); + break; + default: + sprintf(buffer,"%-5s%.2x","ill",oper); + break; + } + break; + } + break; + } + + return (pc-oldpc) | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/emu/cpu/cosmac/cosmac.c b/src/emu/cpu/cosmac/cosmac.c new file mode 100644 index 00000000000..bd8d1b21bba --- /dev/null +++ b/src/emu/cpu/cosmac/cosmac.c @@ -0,0 +1,1173 @@ +/********************************************************************** + + RCA "COSMAC" CPU emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "cosmac.h" + + +/* + + TODO: + + - debugger cursor is not on R(P) + - divide clock by 8 + - min cycles -> 2 and 3 + +*/ + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type COSMAC = cosmac_device_config::static_alloc_device_config; + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define CLOCKS_RESET 8 +#define CLOCKS_INIT 8 // really 9, but needs to be 8 to synchronize cdp1861 video timings +#define CLOCKS_FETCH 8 +#define CLOCKS_EXECUTE 8 +#define CLOCKS_DMA 8 +#define CLOCKS_INTERRUPT 8 + +const cosmac_state_code COSMAC_STATE_CODE[] = +{ + COSMAC_STATE_CODE_S0_FETCH, // COSMAC_STATE_0_FETCH + COSMAC_STATE_CODE_S1_EXECUTE, // COSMAC_STATE_1_RESET + COSMAC_STATE_CODE_S1_EXECUTE, // COSMAC_STATE_1_INIT + COSMAC_STATE_CODE_S1_EXECUTE, // COSMAC_STATE_1_EXECUTE + COSMAC_STATE_CODE_S2_DMA, // COSMAC_STATE_2_DMA_IN + COSMAC_STATE_CODE_S2_DMA, // COSMAC_STATE_2_DMA_OUT + COSMAC_STATE_CODE_S3_INTERRUPT // COSMAC_STATE_3_INT +}; + + + +//************************************************************************** +// MACROS +//************************************************************************** + +#define OPCODE_R(addr) read_opcode(addr) +#define RAM_R(addr) read_byte(addr) +#define RAM_W(addr, data) write_byte(addr, data) +#define IO_R(addr) read_io_byte(addr) +#define IO_W(addr, data) write_io_byte(addr, data) + +#define P m_p +#define X m_x +#define D m_d +#define B m_b +#define T m_t +#define R m_r +#define DF m_df +#define IE m_ie +#define Q m_q +#define N m_n +#define I m_i +#define EF m_ef + +#define GET_FLAGS() ((m_df << 2) | (m_ie << 1) | m_q) + +#define SET_FLAGS(v) do { \ + m_df = BIT(v, 2); \ + m_ie = BIT(v, 1); \ + m_q = BIT(v, 0); \ + } while (0); + + + +//************************************************************************** +// STATIC OPCODE TABLES +//************************************************************************** + +const cosmac_device::ophandler cosmac_device::s_opcodetable[256] = +{ + &cosmac_device::idl, &cosmac_device::ldn, &cosmac_device::ldn, &cosmac_device::ldn, + &cosmac_device::ldn, &cosmac_device::ldn, &cosmac_device::ldn, &cosmac_device::ldn, + &cosmac_device::ldn, &cosmac_device::ldn, &cosmac_device::ldn, &cosmac_device::ldn, + &cosmac_device::ldn, &cosmac_device::ldn, &cosmac_device::ldn, &cosmac_device::ldn, + + &cosmac_device::inc, &cosmac_device::inc, &cosmac_device::inc, &cosmac_device::inc, + &cosmac_device::inc, &cosmac_device::inc, &cosmac_device::inc, &cosmac_device::inc, + &cosmac_device::inc, &cosmac_device::inc, &cosmac_device::inc, &cosmac_device::inc, + &cosmac_device::inc, &cosmac_device::inc, &cosmac_device::inc, &cosmac_device::inc, + + &cosmac_device::dec, &cosmac_device::dec, &cosmac_device::dec, &cosmac_device::dec, + &cosmac_device::dec, &cosmac_device::dec, &cosmac_device::dec, &cosmac_device::dec, + &cosmac_device::dec, &cosmac_device::dec, &cosmac_device::dec, &cosmac_device::dec, + &cosmac_device::dec, &cosmac_device::dec, &cosmac_device::dec, &cosmac_device::dec, + + &cosmac_device::br, &cosmac_device::bq, &cosmac_device::bz, &cosmac_device::bdf, + &cosmac_device::b, &cosmac_device::b, &cosmac_device::b, &cosmac_device::b, + &cosmac_device::nbr, &cosmac_device::bnq, &cosmac_device::bnz, &cosmac_device::bnf, + &cosmac_device::bn, &cosmac_device::bn, &cosmac_device::bn, &cosmac_device::bn, + + &cosmac_device::lda, &cosmac_device::lda, &cosmac_device::lda, &cosmac_device::lda, + &cosmac_device::lda, &cosmac_device::lda, &cosmac_device::lda, &cosmac_device::lda, + &cosmac_device::lda, &cosmac_device::lda, &cosmac_device::lda, &cosmac_device::lda, + &cosmac_device::lda, &cosmac_device::lda, &cosmac_device::lda, &cosmac_device::lda, + + &cosmac_device::str, &cosmac_device::str, &cosmac_device::str, &cosmac_device::str, + &cosmac_device::str, &cosmac_device::str, &cosmac_device::str, &cosmac_device::str, + &cosmac_device::str, &cosmac_device::str, &cosmac_device::str, &cosmac_device::str, + &cosmac_device::str, &cosmac_device::str, &cosmac_device::str, &cosmac_device::str, + + &cosmac_device::irx, &cosmac_device::out, &cosmac_device::out, &cosmac_device::out, + &cosmac_device::out, &cosmac_device::out, &cosmac_device::out, &cosmac_device::out, + &cosmac_device::inp, &cosmac_device::inp, &cosmac_device::inp, &cosmac_device::inp, + &cosmac_device::inp, &cosmac_device::inp, &cosmac_device::inp, &cosmac_device::inp, + + &cosmac_device::ret, &cosmac_device::dis, &cosmac_device::ldxa, &cosmac_device::stxd, + &cosmac_device::adc, &cosmac_device::sdb, &cosmac_device::shrc, &cosmac_device::smb, + &cosmac_device::sav, &cosmac_device::mark, &cosmac_device::req, &cosmac_device::seq, + &cosmac_device::adci, &cosmac_device::sdbi, &cosmac_device::shlc, &cosmac_device::smbi, + + &cosmac_device::glo, &cosmac_device::glo, &cosmac_device::glo, &cosmac_device::glo, + &cosmac_device::glo, &cosmac_device::glo, &cosmac_device::glo, &cosmac_device::glo, + &cosmac_device::glo, &cosmac_device::glo, &cosmac_device::glo, &cosmac_device::glo, + &cosmac_device::glo, &cosmac_device::glo, &cosmac_device::glo, &cosmac_device::glo, + + &cosmac_device::ghi, &cosmac_device::ghi, &cosmac_device::ghi, &cosmac_device::ghi, + &cosmac_device::ghi, &cosmac_device::ghi, &cosmac_device::ghi, &cosmac_device::ghi, + &cosmac_device::ghi, &cosmac_device::ghi, &cosmac_device::ghi, &cosmac_device::ghi, + &cosmac_device::ghi, &cosmac_device::ghi, &cosmac_device::ghi, &cosmac_device::ghi, + + &cosmac_device::plo, &cosmac_device::plo, &cosmac_device::plo, &cosmac_device::plo, + &cosmac_device::plo, &cosmac_device::plo, &cosmac_device::plo, &cosmac_device::plo, + &cosmac_device::plo, &cosmac_device::plo, &cosmac_device::plo, &cosmac_device::plo, + &cosmac_device::plo, &cosmac_device::plo, &cosmac_device::plo, &cosmac_device::plo, + + &cosmac_device::phi, &cosmac_device::phi, &cosmac_device::phi, &cosmac_device::phi, + &cosmac_device::phi, &cosmac_device::phi, &cosmac_device::phi, &cosmac_device::phi, + &cosmac_device::phi, &cosmac_device::phi, &cosmac_device::phi, &cosmac_device::phi, + &cosmac_device::phi, &cosmac_device::phi, &cosmac_device::phi, &cosmac_device::phi, + + &cosmac_device::lbr, &cosmac_device::lbq, &cosmac_device::lbz, &cosmac_device::lbdf, + &cosmac_device::nop, &cosmac_device::lsnq, &cosmac_device::lsnz, &cosmac_device::lsnf, + &cosmac_device::nlbr, &cosmac_device::lbnq, &cosmac_device::lbnz, &cosmac_device::lbnf, + &cosmac_device::lsie, &cosmac_device::lsq, &cosmac_device::lsz, &cosmac_device::lsdf, + + &cosmac_device::sep, &cosmac_device::sep, &cosmac_device::sep, &cosmac_device::sep, + &cosmac_device::sep, &cosmac_device::sep, &cosmac_device::sep, &cosmac_device::sep, + &cosmac_device::sep, &cosmac_device::sep, &cosmac_device::sep, &cosmac_device::sep, + &cosmac_device::sep, &cosmac_device::sep, &cosmac_device::sep, &cosmac_device::sep, + + &cosmac_device::sex, &cosmac_device::sex, &cosmac_device::sex, &cosmac_device::sex, + &cosmac_device::sex, &cosmac_device::sex, &cosmac_device::sex, &cosmac_device::sex, + &cosmac_device::sex, &cosmac_device::sex, &cosmac_device::sex, &cosmac_device::sex, + &cosmac_device::sex, &cosmac_device::sex, &cosmac_device::sex, &cosmac_device::sex, + + &cosmac_device::ldx, &cosmac_device::_or, &cosmac_device::_and, &cosmac_device::_xor, + &cosmac_device::add, &cosmac_device::sd, &cosmac_device::shr, &cosmac_device::sm, + &cosmac_device::ldi, &cosmac_device::ori, &cosmac_device::ani, &cosmac_device::xri, + &cosmac_device::adi, &cosmac_device::sdi, &cosmac_device::shl, &cosmac_device::smi +}; + + + +//************************************************************************** +// COSMAC DEVICE CONFIG +//************************************************************************** + +//------------------------------------------------- +// cosmac_device_config - constructor +//------------------------------------------------- + +cosmac_device_config::cosmac_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) + : cpu_device_config(mconfig, static_alloc_device_config, "COSMAC", tag, owner, clock), + m_program_config("program", ENDIANNESS_LITTLE, 8, 16), + m_io_config("io", ENDIANNESS_LITTLE, 8, 3) +{ +} + + +//------------------------------------------------- +// static_alloc_device_config - allocate a new +// configuration object +//------------------------------------------------- + +device_config *cosmac_device_config::static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) +{ + return global_alloc(cosmac_device_config(mconfig, tag, owner, clock)); +} + + +//------------------------------------------------- +// alloc_device - allocate a new device object +//------------------------------------------------- + +device_t *cosmac_device_config::alloc_device(running_machine &machine) const +{ + return auto_alloc(&machine, cosmac_device(machine, *this)); +} + + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 cosmac_device_config::execute_min_cycles() const +{ + return 8 * 2; +} + + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 cosmac_device_config::execute_max_cycles() const +{ + return 8 * 3; +} + + +//------------------------------------------------- +// execute_input_lines - return the number of +// input/interrupt lines +//------------------------------------------------- + +UINT32 cosmac_device_config::execute_input_lines() const +{ + return 7; +} + + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config *cosmac_device_config::memory_space_config(int spacenum) const +{ + switch (spacenum) + { + case AS_PROGRAM: + return &m_program_config; + + case AS_IO: + return &m_io_config; + + default: + return NULL; + } +} + + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 cosmac_device_config::disasm_min_opcode_bytes() const +{ + return 1; +} + + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 cosmac_device_config::disasm_max_opcode_bytes() const +{ + return 3; +} + + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void cosmac_device_config::device_config_complete() +{ + // inherit a copy of the static data + const cosmac_interface *intf = reinterpret_cast<const cosmac_interface *>(static_config()); + if (intf != NULL) + *static_cast<cosmac_interface *>(this) = *intf; + + // or initialize to defaults if none provided + else + { + memset(&m_in_wait_func, 0, sizeof(m_in_wait_func)); + memset(&m_in_clear_func, 0, sizeof(m_in_clear_func)); + // TODO: clear ef1-4 + memset(&m_out_q_func, 0, sizeof(m_out_q_func)); + memset(&m_in_dma_func, 0, sizeof(m_in_dma_func)); + memset(&m_out_dma_func, 0, sizeof(m_out_dma_func)); + m_out_sc_func = NULL; + memset(&m_out_tpa_func, 0, sizeof(m_out_tpa_func)); + memset(&m_out_tpb_func, 0, sizeof(m_out_tpb_func)); + } +} + + + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// cosmac_device - constructor +//------------------------------------------------- + +cosmac_device::cosmac_device(running_machine &_machine, const cosmac_device_config &config) + : cpu_device(_machine, config), + m_op(0), + m_state(COSMAC_STATE_1_RESET), + m_mode(COSMAC_MODE_RESET), + m_irq(0), + m_dmain(0), + m_dmaout(0), + m_program(NULL), + m_io(NULL), + m_direct(NULL), + m_config(config) +{ + for (int i = 0; i < 4; i++) + EF[i] = 0; +} + + +//------------------------------------------------- +// device_start - start up the device +//------------------------------------------------- + +void cosmac_device::device_start() +{ + // get our address spaces + m_program = space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = space(AS_IO); + + // register our state for the debugger + state_add(STATE_GENPC, "GENPC", R[P]).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_flagsio).mask(0x7).callimport().callexport().noshow().formatstr("%3s"); + + state_add(COSMAC_P, "P", m_p).mask(0xf); + state_add(COSMAC_X, "X", m_x).mask(0xf); + state_add(COSMAC_D, "D", m_d); + state_add(COSMAC_B, "B", m_b); + state_add(COSMAC_T, "T", m_t); + + state_add(COSMAC_I, "I", m_i).mask(0xf); + state_add(COSMAC_N, "N", m_n).mask(0xf); + + astring tempstr; + for (int regnum = 0; regnum < 16; regnum++) + state_add(COSMAC_R0 + regnum, tempstr.format("R%x", regnum), m_r[regnum]); + + state_add(COSMAC_DF, "DF", m_df).mask(0x1).noshow(); + state_add(COSMAC_IE, "IE", m_ie).mask(0x1).noshow(); + state_add(COSMAC_Q, "Q", m_q).mask(0x1).noshow(); + + // resolve callbacks + devcb_resolve_read_line(&m_in_wait_func, &m_config.m_in_wait_func, this); + devcb_resolve_read_line(&m_in_clear_func, &m_config.m_in_clear_func, this); + devcb_resolve_read_line(&m_in_ef_func[0], &m_config.m_in_ef1_func, this); + devcb_resolve_read_line(&m_in_ef_func[1], &m_config.m_in_ef2_func, this); + devcb_resolve_read_line(&m_in_ef_func[2], &m_config.m_in_ef3_func, this); + devcb_resolve_read_line(&m_in_ef_func[3], &m_config.m_in_ef4_func, this); + devcb_resolve_write_line(&m_out_q_func, &m_config.m_out_q_func, this); + devcb_resolve_read8(&m_in_dma_func, &m_config.m_in_dma_func, this); + devcb_resolve_write8(&m_out_dma_func, &m_config.m_out_dma_func, this); + m_out_sc_func = m_config.m_out_sc_func; + devcb_resolve_write_line(&m_out_tpa_func, &m_config.m_out_tpa_func, this); + devcb_resolve_write_line(&m_out_tpb_func, &m_config.m_out_tpb_func, this); + + // register our state for saving + state_save_register_device_item(this, 0, m_op); + state_save_register_device_item(this, 0, m_flagsio); + state_save_register_device_item(this, 0, m_state); + state_save_register_device_item(this, 0, m_mode); + state_save_register_device_item(this, 0, m_pmode); + state_save_register_device_item(this, 0, m_irq); + state_save_register_device_item(this, 0, m_dmain); + state_save_register_device_item(this, 0, m_dmaout); + state_save_register_device_item_array(this, 0, m_ef); + state_save_register_device_item(this, 0, m_d); + state_save_register_device_item(this, 0, m_b); + state_save_register_device_item_array(this, 0, m_r); + state_save_register_device_item(this, 0, m_p); + state_save_register_device_item(this, 0, m_x); + state_save_register_device_item(this, 0, m_n); + state_save_register_device_item(this, 0, m_i); + state_save_register_device_item(this, 0, m_t); + state_save_register_device_item(this, 0, m_df); + state_save_register_device_item(this, 0, m_ie); + state_save_register_device_item(this, 0, m_q); + state_save_register_device_item(this, 0, m_icount); + + // set our instruction counter + m_icountptr = &m_icount; +} + + +//------------------------------------------------- +// device_reset - reset the device +//------------------------------------------------- + +void cosmac_device::device_reset() +{ +} + + +//------------------------------------------------- +// state_import - import state into the device, +// after it has been set +//------------------------------------------------- + +void cosmac_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + SET_FLAGS(m_flagsio); + break; + } +} + + +//------------------------------------------------- +// state_export - export state from the device, +// to a known location where it can be read +//------------------------------------------------- + +void cosmac_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + m_flagsio = GET_FLAGS(); + break; + } +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void cosmac_device::state_string_export(const device_state_entry &entry, astring &string) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + string.printf("%c%c%c", + m_df ? 'D' : '.', + m_ie ? 'I' : '.', + m_q ? 'Q' : '.'); + break; + } +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t cosmac_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( cosmac ); + return CPU_DISASSEMBLE_NAME(cosmac)(NULL, buffer, pc, oprom, opram, 0); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// read_opcode - read an opcode at the given address +//------------------------------------------------- + +inline UINT8 cosmac_device::read_opcode(offs_t pc) +{ + return m_direct->read_decrypted_byte(pc); +} + + +//------------------------------------------------- +// read_byte - read a byte at the given address +//------------------------------------------------- + +inline UINT8 cosmac_device::read_byte(offs_t address) +{ + return m_program->read_byte(address); +} + + +//------------------------------------------------- +// read_io_byte - read an I/O byte at the given +// address +//------------------------------------------------- + +inline UINT8 cosmac_device::read_io_byte(offs_t address) +{ + return m_io->read_byte(address); +} + + +//------------------------------------------------- +// write_byte - write a byte at the given address +//------------------------------------------------- + +inline void cosmac_device::write_byte(offs_t address, UINT8 data) +{ + m_program->write_byte(address, data); +} + + +//------------------------------------------------- +// write_io_byte - write an I/O byte at the given +// address +//------------------------------------------------- + +inline void cosmac_device::write_io_byte(offs_t address, UINT8 data) +{ + m_io->write_byte(address, data); +} + + + +//************************************************************************** +// CORE EXECUTION +//************************************************************************** + +//------------------------------------------------- +// execute_set_input - +//------------------------------------------------- + +void cosmac_device::execute_set_input(int inputnum, int state) +{ + switch (inputnum) + { + case COSMAC_INPUT_LINE_INT: + m_irq = state; + break; + + case COSMAC_INPUT_LINE_DMAIN: + m_dmain = state; + break; + + case COSMAC_INPUT_LINE_DMAOUT: + m_dmaout = state; + break; + + case COSMAC_INPUT_LINE_EF1: + case COSMAC_INPUT_LINE_EF2: + case COSMAC_INPUT_LINE_EF3: + case COSMAC_INPUT_LINE_EF4: + EF[inputnum - COSMAC_INPUT_LINE_EF1] = state; + break; + } +} + + +//------------------------------------------------- +// execute_run - +//------------------------------------------------- + +void cosmac_device::execute_run() +{ + do + { + sample_wait_clear(); + + switch (m_mode) + { + case COSMAC_MODE_LOAD: + if (m_pmode == COSMAC_MODE_RESET) + { + m_pmode = COSMAC_MODE_LOAD; + + // execute initialization cycle + m_state = COSMAC_STATE_1_INIT; + run(); + + // next state is IDLE + m_state = COSMAC_STATE_1_EXECUTE; + } + else + { + // idle + m_op = 0; + I = 0; + N = 0; + run(); + } + break; + + case COSMAC_MODE_RESET: + m_state = COSMAC_STATE_1_RESET; + run(); + break; + + case COSMAC_MODE_PAUSE: + m_icount--; + break; + + case COSMAC_MODE_RUN: + switch (m_pmode) + { + case COSMAC_MODE_LOAD: + // RUN mode cannot be initiated from LOAD mode + logerror("COSMAC '%s' Tried to initiate RUN mode from LOAD mode\n", tag()); + m_mode = COSMAC_MODE_LOAD; + break; + + case COSMAC_MODE_RESET: + m_pmode = COSMAC_MODE_RUN; + m_state = COSMAC_STATE_1_INIT; + run(); + break; + + case COSMAC_MODE_PAUSE: + m_pmode = COSMAC_MODE_RUN; + m_state = COSMAC_STATE_0_FETCH; + run(); + break; + + case COSMAC_MODE_RUN: + run(); + break; + } + break; + } + } + while (m_icount > 0); +} + + +//------------------------------------------------- +// run - run the CPU state machine +//------------------------------------------------- + +inline void cosmac_device::run() +{ + output_state_code(); + + switch (m_state) + { + case COSMAC_STATE_0_FETCH: + fetch_instruction(); + break; + + case COSMAC_STATE_1_RESET: + reset(); + debug(); + break; + + case COSMAC_STATE_1_INIT: + initialize(); + debug(); + break; + + case COSMAC_STATE_1_EXECUTE: + sample_ef_lines(); + execute_instruction(); + debug(); + break; + + case COSMAC_STATE_2_DMA_IN: + dma_input(); + break; + + case COSMAC_STATE_2_DMA_OUT: + dma_output(); + break; + + case COSMAC_STATE_3_INT: + interrupt(); + debug(); + break; + } +} + + +//------------------------------------------------- +// debug - hook into debugger +//------------------------------------------------- + +inline void cosmac_device::debug() +{ + if (device_t::m_machine.debug_flags & DEBUG_FLAG_ENABLED) + { + debugger_instruction_hook(this, R[P]); + } +} + + +//------------------------------------------------- +// sample_wait_clear - sample wait/clear lines +//------------------------------------------------- + +inline void cosmac_device::sample_wait_clear() +{ + int wait = devcb_call_read_line(&m_in_wait_func); + int clear = devcb_call_read_line(&m_in_clear_func); + + m_pmode = m_mode; + m_mode = (cosmac_mode) ((clear << 1) | wait); +} + + +//------------------------------------------------- +// sample_ef_lines - sample EF input lines +//------------------------------------------------- + +inline void cosmac_device::sample_ef_lines() +{ + for (int i = 0; i < 4; i++) + { + if (m_in_ef_func[i].target != NULL) + { + EF[i] = devcb_call_read_line(&m_in_ef_func[i]); + } + } +} + + +//------------------------------------------------- +// output_state_code - output state code +//------------------------------------------------- + +inline void cosmac_device::output_state_code() +{ + if (m_out_sc_func != NULL) + { + m_out_sc_func(this, COSMAC_STATE_CODE[m_state]); + } +} + + +//------------------------------------------------- +// set_q_flag - set Q flag state and output it +//------------------------------------------------- + +inline void cosmac_device::set_q_flag(int state) +{ + Q = state; + + devcb_call_write_line(&m_out_q_func, Q); +} + + +//------------------------------------------------- +// fetch_instruction - fetch instruction from +// the program memory +//------------------------------------------------- + +inline void cosmac_device::fetch_instruction() +{ + // instruction fetch + m_op = read_opcode(R[P]); + R[P]++; + + I = m_op >> 4; + N = m_op & 0x0f; + + m_icount -= CLOCKS_FETCH; + + m_state = COSMAC_STATE_1_EXECUTE; +} + + +//------------------------------------------------- +// reset - handle reset state +//------------------------------------------------- + +inline void cosmac_device::reset() +{ + m_op = 0; + I = 0; + N = 0; + Q = 0; + IE = 1; + + m_icount -= CLOCKS_RESET; +} + + +//------------------------------------------------- +// initialize - handle initialization state +//------------------------------------------------- + +inline void cosmac_device::initialize() +{ + X = 0; + P = 0; + R[0] = 0; + + m_icount -= CLOCKS_INIT; + + if (m_dmain) + { + m_state = COSMAC_STATE_2_DMA_IN; + } + else if (m_dmaout) + { + m_state = COSMAC_STATE_2_DMA_OUT; + } + else + { + m_state = COSMAC_STATE_0_FETCH; + } +} + + +//------------------------------------------------- +// execute_instruction - execute instruction +//------------------------------------------------- + +inline void cosmac_device::execute_instruction() +{ + // parse the instruction + (this->*s_opcodetable[m_op])(); + + m_icount -= CLOCKS_EXECUTE; + + if (m_dmain) + { + m_state = COSMAC_STATE_2_DMA_IN; + } + else if (m_dmaout) + { + m_state = COSMAC_STATE_2_DMA_OUT; + } + else if (IE && m_irq) + { + m_state = COSMAC_STATE_3_INT; + } + else if ((I > 0) || (N > 0)) // not idling + { + m_state = COSMAC_STATE_0_FETCH; + } +} + + +//------------------------------------------------- +// dma_input - handle DMA input state +//------------------------------------------------- + +inline void cosmac_device::dma_input() +{ + RAM_W(R[0], devcb_call_read8(&m_in_dma_func, R[0])); + + R[0]++; + + m_icount -= CLOCKS_DMA; + + if (m_dmain) + { + m_state = COSMAC_STATE_2_DMA_IN; + } + else if (m_dmaout) + { + m_state = COSMAC_STATE_2_DMA_OUT; + } + else if (IE && m_irq) + { + m_state = COSMAC_STATE_3_INT; + } + else if (m_mode == COSMAC_MODE_LOAD) + { + m_state = COSMAC_STATE_1_EXECUTE; + } + else + { + m_state = COSMAC_STATE_0_FETCH; + } +} + + +//------------------------------------------------- +// dma_output - handle DMA output state +//------------------------------------------------- + +inline void cosmac_device::dma_output() +{ + devcb_call_write8(&m_out_dma_func, R[0], RAM_R(R[0])); + + R[0]++; + + m_icount -= CLOCKS_DMA; + + if (m_dmain) + { + m_state = COSMAC_STATE_2_DMA_IN; + } + else if (m_dmaout) + { + m_state = COSMAC_STATE_2_DMA_OUT; + } + else if (IE && m_irq) + { + m_state = COSMAC_STATE_3_INT; + } + else + { + m_state = COSMAC_STATE_0_FETCH; + } +} + + +//------------------------------------------------- +// interrupt - handle interrupt state +//------------------------------------------------- + +inline void cosmac_device::interrupt() +{ + T = (X << 4) | P; + X = 2; + P = 1; + IE = 0; + + m_icount -= CLOCKS_INTERRUPT; + + if (m_dmain) + { + m_state = COSMAC_STATE_2_DMA_IN; + } + else if (m_dmaout) + { + m_state = COSMAC_STATE_2_DMA_OUT; + } + else + { + m_state = COSMAC_STATE_0_FETCH; + } +} + + + +//************************************************************************** +// OPCODE IMPLEMENTATIONS +//************************************************************************** + +// memory reference opcode handlers +void cosmac_device::ldn() { D = RAM_R(R[N]); } +void cosmac_device::lda() { D = RAM_R(R[N]); R[N]++; } +void cosmac_device::ldx() { D = RAM_R(R[X]); } +void cosmac_device::ldxa() { D = RAM_R(R[X]); R[X]++; } +void cosmac_device::ldi() { D = RAM_R(R[P]); R[P]++; } +void cosmac_device::str() { RAM_W(R[N], D); } +void cosmac_device::stxd() { RAM_W(R[X], D); R[X]--; } + +// register operations opcode handlers +void cosmac_device::inc() { R[N]++; } +void cosmac_device::dec() { R[N]--; } +void cosmac_device::irx() { R[X]++; } +void cosmac_device::glo() { D = R[N] & 0xff; } +void cosmac_device::plo() { R[N] = (R[N] & 0xff00) | D; } +void cosmac_device::ghi() { D = R[N] >> 8; } +void cosmac_device::phi() { R[N] = (D << 8) | (R[N] & 0xff); } + +// logic operations opcode handlers +void cosmac_device::_or() { D = RAM_R(R[X]) | D; } +void cosmac_device::ori() { D = RAM_R(R[P]) | D; R[P]++; } +void cosmac_device::_xor() { D = RAM_R(R[X]) ^ D; } +void cosmac_device::xri() { D = RAM_R(R[P]) ^ D; R[P]++; } +void cosmac_device::_and() { D = RAM_R(R[X]) & D; } +void cosmac_device::ani() { D = RAM_R(R[P]) & D; R[P]++; } +void cosmac_device::shr() { DF = BIT(D, 0); D >>= 1; } +void cosmac_device::shrc() { int b = DF; DF = BIT(D, 0); D >>= 1; D |= b << 7; } +void cosmac_device::shl() { DF = BIT(D, 7); D <<= 1; } +void cosmac_device::shlc() { int b = DF; DF = BIT(D, 7); D <<= 1; D |= b; } + +// arithmetic operations opcode handlers +void cosmac_device::add(int left, int right) +{ + int result = left + right; + + D = result & 0xff; + DF = result > 0xff; +} + +void cosmac_device::add_with_carry(int left, int right) +{ + int result = left + right + DF; + + D = result & 0xff; + DF = result > 0xff; +} + +void cosmac_device::subtract(int left, int right) +{ + int result = left + (right ^ 0xff) + 1; + + D = result & 0xff; + DF = result > 0xff; +} + +void cosmac_device::subtract_with_borrow(int left, int right) +{ + int result = left + (right ^ 0xff) + DF; + + D = result & 0xff; + DF = result > 0xff; +} + +void cosmac_device::add() { add(RAM_R(R[X]), D); } +void cosmac_device::adi() { add(RAM_R(R[P]), D); R[P]++; } +void cosmac_device::adc() { add_with_carry(RAM_R(R[X]), D); } +void cosmac_device::adci() { add_with_carry(RAM_R(R[P]), D); R[P]++; } +void cosmac_device::sd() { subtract(RAM_R(R[X]), D); } +void cosmac_device::sdi() { subtract(RAM_R(R[P]), D); R[P]++; } +void cosmac_device::sdb() { subtract_with_borrow(RAM_R(R[X]), D); } +void cosmac_device::sdbi() { subtract_with_borrow(RAM_R(R[P]), D); R[P]++; } +void cosmac_device::sm() { subtract(D, RAM_R(R[X])); } +void cosmac_device::smi() { subtract(D, RAM_R(R[P])); R[P]++; } +void cosmac_device::smb() { subtract_with_borrow(D, RAM_R(R[X])); } +void cosmac_device::smbi() { subtract_with_borrow(D, RAM_R(R[P])); R[P]++; } + +// short branch instructions opcode handlers +void cosmac_device::short_branch(int taken) +{ + if (taken) + { + R[P] = (R[P] & 0xff00) | OPCODE_R(R[P]); + } + else + { + R[P]++; + } +} + +void cosmac_device::br() { short_branch(1); } +void cosmac_device::nbr() { short_branch(0); } +void cosmac_device::bz() { short_branch(D == 0); } +void cosmac_device::bnz() { short_branch(D != 0); } +void cosmac_device::bdf() { short_branch(DF); } +void cosmac_device::bnf() { short_branch(!DF); } +void cosmac_device::bq() { short_branch(Q); } +void cosmac_device::bnq() { short_branch(!Q); } +void cosmac_device::b() { short_branch(EF[N & 0x03]); } +void cosmac_device::bn() { short_branch(!EF[N & 0x03]); } + +// long branch instructions opcode handlers +void cosmac_device::long_branch(int taken) +{ + if (taken) + { + // S1#1 + B = OPCODE_R(R[P]++); + + // S1#2 + R[P] = (B << 8) | OPCODE_R(R[P]); + } + else + { + // S1#1 + R[P]++; + + // S1#2 + R[P]++; + } + + m_icount -= CLOCKS_EXECUTE; +} + +void cosmac_device::lbr() { long_branch(1); } +void cosmac_device::nlbr() { long_skip(1); } +void cosmac_device::lbz() { long_branch(D == 0); } +void cosmac_device::lbnz() { long_branch(D != 0); } +void cosmac_device::lbdf() { long_branch(DF); } +void cosmac_device::lbnf() { long_branch(!DF); } +void cosmac_device::lbq() { long_branch(Q); } +void cosmac_device::lbnq() { long_branch(!Q); } + +// skip instructions opcode handlers +void cosmac_device::long_skip(int taken) +{ + if (taken) + { + // S1#1 + R[P]++; + + // S1#2 + R[P]++; + } + + m_icount -= CLOCKS_EXECUTE; +} + +void cosmac_device::lsz() { long_skip(D == 0); } +void cosmac_device::lsnz() { long_skip(D != 0); } +void cosmac_device::lsdf() { long_skip(DF); } +void cosmac_device::lsnf() { long_skip(!DF); } +void cosmac_device::lsq() { long_skip(Q); } +void cosmac_device::lsnq() { long_skip(!Q); } +void cosmac_device::lsie() { long_skip(IE); } + +// control instructions opcode handlers +void cosmac_device::idl() { /* idle */ } +void cosmac_device::nop() { m_icount -= CLOCKS_EXECUTE; } +void cosmac_device::sep() { P = N; } +void cosmac_device::sex() { X = N; } +void cosmac_device::seq() { set_q_flag(1); } +void cosmac_device::req() { set_q_flag(0); } +void cosmac_device::sav() { RAM_W(R[X], T); } + +void cosmac_device::mark() +{ + T = (X << 4) | P; + RAM_W(R[2], T); + X = P; + R[2]--; +} + +void cosmac_device::return_from_interrupt(int ie) +{ + UINT8 data = RAM_R(R[X]); + R[X]++; + P = data & 0xf; + X = data >> 4; + IE = ie; +} + +void cosmac_device::ret() { return_from_interrupt(1); } +void cosmac_device::dis() { return_from_interrupt(0); } + +// input/output byte transfer opcode handlers +void cosmac_device::out() { IO_W(N, RAM_R(R[X])); R[X]++; } + +/* + + A note about INP 0 (0x68) from Tom Pittman's "A Short Course in Programming": + + If you look carefully, you will notice that we never studied the opcode "68". + That's because it is not a defined 1802 instruction. It has the form of an INP + instruction, but 0 is not a defined input port, so if you execute it (try it!) + nothing is input. "Nothing" is the answer to a question; it is data, and something + will be put in the accumulator and memory (so now you know what the computer uses + to mean "nothing"). + + However, since the result of the "68" opcode is unpredictable, it should not be + used in your programs. In fact, "68" is the first byte of a series of additional + instructions for the 1804 and 1805 microprocessors. + + http://www.ittybittycomputers.com/IttyBitty/ShortCor.htm + +*/ +void cosmac_device::inp() { D = IO_R(N & 0x07); RAM_W(R[X], D); } diff --git a/src/emu/cpu/cosmac/cosmac.h b/src/emu/cpu/cosmac/cosmac.h new file mode 100644 index 00000000000..a057f43990e --- /dev/null +++ b/src/emu/cpu/cosmac/cosmac.h @@ -0,0 +1,414 @@ +/********************************************************************** + + RCA "COSMAC" CPU emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +********************************************************************** + _____ _____ + 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 + +**********************************************************************/ + +#pragma once + +#ifndef __COSMAC_H__ +#define __COSMAC_H__ + + +//************************************************************************** +// ENUMERATIONS +//************************************************************************** + +// registers +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 +}; + + +// input lines +enum +{ + COSMAC_INPUT_LINE_INT = 0, + 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 +}; + + +// device type definition +extern const device_type COSMAC; + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +typedef void (*cosmac_out_sc_func)(running_device *device, cosmac_state_code sc); +#define COSMAC_SC_WRITE(name) void name(running_device *device, cosmac_state_code sc) + + +// ======================> cosmac_interface + +struct cosmac_interface +{ + devcb_read_line m_in_wait_func; + devcb_read_line m_in_clear_func; + devcb_read_line m_in_ef1_func; + devcb_read_line m_in_ef2_func; + devcb_read_line m_in_ef3_func; + devcb_read_line m_in_ef4_func; + devcb_write_line m_out_q_func; + devcb_read8 m_in_dma_func; + devcb_write8 m_out_dma_func; + cosmac_out_sc_func m_out_sc_func; + devcb_write_line m_out_tpa_func; + devcb_write_line m_out_tpb_func; +}; + +#define COSMAC_INTERFACE(name) \ + const cosmac_interface (name) = + + +// ======================> cosmac_device_config + +class cosmac_device_config : public cpu_device_config, + public cosmac_interface +{ + friend class cosmac_device; + + // construction/destruction + cosmac_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + +public: + // allocators + static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + virtual device_t *alloc_device(running_machine &machine) const; + +protected: + // device_config overrides + virtual void device_config_complete(); + + // device_config_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + + // device_config_memory_interface overrides + virtual const address_space_config *memory_space_config(int spacenum = 0) const; + + // device_config_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + + // inline data + const address_space_config m_program_config; + const address_space_config m_io_config; +}; + + + +// ======================> cosmac_device + +class cosmac_device : public cpu_device +{ + friend class cosmac_device_config; + + // construction/destruction + cosmac_device(running_machine &_machine, const cosmac_device_config &config); + +public: + // public interfaces + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, astring &string); + + // device_disasm_interface overrides + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // helpers + inline UINT8 read_opcode(offs_t pc); + inline UINT8 read_byte(offs_t address); + inline UINT8 read_io_byte(offs_t address); + inline void write_byte(offs_t address, UINT8 data); + inline void write_io_byte(offs_t address, UINT8 data); + + // execution logic + inline void run(); + inline void debug(); + inline void reset(); + inline void initialize(); + inline void fetch_instruction(); + inline void fetch_instruction_debug(); + 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 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(); + + // device callbacks + devcb_resolved_read_line m_in_wait_func; + devcb_resolved_read_line m_in_clear_func; + devcb_resolved_read_line m_in_ef_func[4]; + devcb_resolved_write_line m_out_q_func; + devcb_resolved_read8 m_in_dma_func; + devcb_resolved_write8 m_out_dma_func; + cosmac_out_sc_func m_out_sc_func; + devcb_resolved_write_line m_out_tpa_func; + devcb_resolved_write_line m_out_tpb_func; + + // control modes + enum _cosmac_mode + { + COSMAC_MODE_LOAD = 0, + COSMAC_MODE_RESET, + COSMAC_MODE_PAUSE, + COSMAC_MODE_RUN + }; + typedef enum _cosmac_mode cosmac_mode; + + // execution states + enum _cosmac_state + { + COSMAC_STATE_0_FETCH = 0, + COSMAC_STATE_1_RESET, + COSMAC_STATE_1_INIT, + COSMAC_STATE_1_EXECUTE, + COSMAC_STATE_2_DMA_IN, + COSMAC_STATE_2_DMA_OUT, + COSMAC_STATE_3_INT + }; + typedef enum _cosmac_state cosmac_state; + + // internal state + UINT8 m_op; // current opcode + UINT8 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 + 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 m_d; // data register (accumulator) + UINT8 m_b; // auxiliary holding register + UINT16 m_r[16]; // scratchpad registers + UINT8 m_p; // designates which register is Program Counter + UINT8 m_x; // designates which register is Data Pointer + UINT8 m_n; // low-order instruction digit + UINT8 m_i; // high-order instruction digit + UINT8 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)(); + + static const ophandler s_opcodetable[256]; + + const cosmac_device_config &m_config; +}; + + + +#endif /* __COSMAC_H__ */ diff --git a/src/emu/cpu/cpu.mak b/src/emu/cpu/cpu.mak index 984197051bc..123961fc99b 100644 --- a/src/emu/cpu/cpu.mak +++ b/src/emu/cpu/cpu.mak @@ -291,6 +291,21 @@ $(CPUOBJ)/cdp1802/cdp1802.o: $(CPUSRC)/cdp1802/cdp1802.c \ #------------------------------------------------- +# RCA COSMAC +#------------------------------------------------- + +ifneq ($(filter COSMAC,$(CPUS)),) +OBJDIRS += $(CPUOBJ)/cosmac +CPUOBJS += $(CPUOBJ)/cosmac/cosmac.o +DASMOBJS += $(CPUOBJ)/cosmac/cosdasm.o +endif + +$(CPUOBJ)/cosmac/cosmac.o: $(CPUSRC)/cosmac/cosmac.c \ + $(CPUSRC)/cosmac/cosmac.h + + + +#------------------------------------------------- # National Semiconductor COP400 family #------------------------------------------------- diff --git a/src/emu/sound/cdp1869.c b/src/emu/sound/cdp1869.c index ae2a95682a8..21108cf0576 100644 --- a/src/emu/sound/cdp1869.c +++ b/src/emu/sound/cdp1869.c @@ -1,6 +1,6 @@ #include "emu.h" #include "streams.h" -#include "cpu/cdp1802/cdp1802.h" +#include "cpu/cosmac/cosmac.h" #include "sound/cdp1869.h" /* @@ -135,22 +135,22 @@ static void update_prd_changed_timer(cdp1869_t *cdp1869) if (scanline < start) { next_scanline = start; - level = 0; + level = ASSERT_LINE; } else if (scanline < end) { next_scanline = end; - level = 1; + level = CLEAR_LINE; } else { next_scanline = start; - level = 0; + level = ASSERT_LINE; } if (cdp1869->dispoff) { - level = 1; + level = CLEAR_LINE; } duration = cdp1869->screen->time_until_pos(next_scanline); @@ -188,7 +188,7 @@ static STATE_POSTLOAD( cdp1869_state_save_postload ) static UINT16 cdp1802_get_r_x(cdp1869_t *cdp1869) { - return cpu_get_reg(cdp1869->cpu, CDP1802_R0 + cpu_get_reg(cdp1869->cpu, CDP1802_X)); + return cpu_get_reg(cdp1869->cpu, COSMAC_R0 + cpu_get_reg(cdp1869->cpu, COSMAC_X)); } /*------------------------------------------------- @@ -713,6 +713,17 @@ READ_LINE_DEVICE_HANDLER( cdp1869_predisplay_r ) } /*------------------------------------------------- + cdp1869_pal_ntsc_r - PAL/NTSC read +-------------------------------------------------*/ + +READ_LINE_DEVICE_HANDLER( cdp1869_pal_ntsc_r ) +{ + cdp1869_t *cdp1869 = get_safe_token(device); + + return devcb_call_read_line(&cdp1869->in_pal_ntsc_func); +} + +/*------------------------------------------------- cdp1869_update - screen update -------------------------------------------------*/ diff --git a/src/emu/sound/cdp1869.h b/src/emu/sound/cdp1869.h index afcfb6e59d9..1f4d05c3a55 100644 --- a/src/emu/sound/cdp1869.h +++ b/src/emu/sound/cdp1869.h @@ -183,6 +183,9 @@ WRITE8_DEVICE_HANDLER ( cdp1869_pageram_w ); /* predisplay */ READ_LINE_DEVICE_HANDLER( cdp1869_predisplay_r ); +/* PAL/NTSC */ +READ_LINE_DEVICE_HANDLER( cdp1869_pal_ntsc_r ); + /* screen update */ void cdp1869_update(running_device *device, bitmap_t *bitmap, const rectangle *cliprect); |