summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/cpu/cosmac/cosmac.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/cpu/cosmac/cosmac.c')
-rw-r--r--trunk/src/emu/cpu/cosmac/cosmac.c1146
1 files changed, 1146 insertions, 0 deletions
diff --git a/trunk/src/emu/cpu/cosmac/cosmac.c b/trunk/src/emu/cpu/cosmac/cosmac.c
new file mode 100644
index 00000000000..89bc3423ce3
--- /dev/null
+++ b/trunk/src/emu/cpu/cosmac/cosmac.c
@@ -0,0 +1,1146 @@
+/**********************************************************************
+
+ 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:
+
+ - divide clock by 8
+ - min cycles -> 2 and 3
+
+*/
+
+// permit our enums to be saved
+ALLOW_SAVE_TYPE(cosmac_device::cosmac_mode);
+ALLOW_SAVE_TYPE(cosmac_device::cosmac_state);
+
+
+//**************************************************************************
+// 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
+};
+
+
+
+//**************************************************************************
+// DEVICE INTERFACE
+//**************************************************************************
+
+// device type definition
+const device_type COSMAC = &device_creator<cosmac_device>;
+
+
+//-------------------------------------------------
+// cosmac_device - constructor
+//-------------------------------------------------
+
+cosmac_device::cosmac_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : cpu_device(mconfig, COSMAC, "COSMAC", tag, owner, clock),
+ m_program_config("program", ENDIANNESS_LITTLE, 8, 16),
+ m_io_config("io", ENDIANNESS_LITTLE, 8, 3),
+ 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)
+{
+ for (int i = 0; i < 4; i++)
+ EF[i] = 0;
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void cosmac_device::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 error out if none provided
+ else
+ {
+ fatalerror("COSMAC_INTERFACE for cpu '%s' not defined!", tag());
+ }
+}
+
+
+//-------------------------------------------------
+// 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", m_pc).callimport().callexport().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
+ m_in_wait_func.resolve(m_in_wait_cb, *this);
+ m_in_clear_func.resolve(m_in_clear_cb, *this);
+ m_in_ef_func[0].resolve(m_in_ef1_cb, *this);
+ m_in_ef_func[1].resolve(m_in_ef2_cb, *this);
+ m_in_ef_func[2].resolve(m_in_ef3_cb, *this);
+ m_in_ef_func[3].resolve(m_in_ef4_cb, *this);
+ m_out_q_func.resolve(m_out_q_cb, *this);
+ m_in_dma_func.resolve(m_in_dma_cb, *this);
+ m_out_dma_func.resolve(m_out_dma_cb, *this);
+ m_out_sc_func = m_out_sc_cb;
+ m_out_tpa_func.resolve(m_out_tpa_cb, *this);
+ m_out_tpb_func.resolve(m_out_tpb_cb, *this);
+
+ // register our state for saving
+ save_item(NAME(m_op));
+ save_item(NAME(m_flagsio));
+ save_item(NAME(m_state));
+ save_item(NAME(m_mode));
+ save_item(NAME(m_pmode));
+ save_item(NAME(m_irq));
+ save_item(NAME(m_dmain));
+ save_item(NAME(m_dmaout));
+ save_item(NAME(m_ef));
+ save_item(NAME(m_d));
+ save_item(NAME(m_b));
+ save_item(NAME(m_r));
+ save_item(NAME(m_p));
+ save_item(NAME(m_x));
+ save_item(NAME(m_n));
+ save_item(NAME(m_i));
+ save_item(NAME(m_t));
+ save_item(NAME(m_df));
+ save_item(NAME(m_ie));
+ save_item(NAME(m_q));
+ save_item(NAME(m_icount));
+
+ // set our instruction counter
+ m_icountptr = &m_icount;
+}
+
+
+//-------------------------------------------------
+// device_reset - reset the device
+//-------------------------------------------------
+
+void cosmac_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// 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::memory_space_config(address_spacenum spacenum) const
+{
+ switch (spacenum)
+ {
+ case AS_PROGRAM:
+ return &m_program_config;
+
+ case AS_IO:
+ return &m_io_config;
+
+ default:
+ return NULL;
+ }
+}
+
+
+//-------------------------------------------------
+// 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_GENPC:
+ R[P] = m_pc;
+ break;
+
+ 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_GENPC:
+ m_pc = R[P];
+ break;
+
+ 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_min_opcode_bytes - return the length
+// of the shortest instruction, in bytes
+//-------------------------------------------------
+
+UINT32 cosmac_device::disasm_min_opcode_bytes() const
+{
+ return 1;
+}
+
+
+//-------------------------------------------------
+// disasm_max_opcode_bytes - return the length
+// of the longest instruction, in bytes
+//-------------------------------------------------
+
+UINT32 cosmac_device::disasm_max_opcode_bytes() const
+{
+ return 3;
+}
+
+
+//-------------------------------------------------
+// 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
+//**************************************************************************
+
+//-------------------------------------------------
+// get_memory_address - get current memory address
+//-------------------------------------------------
+
+offs_t cosmac_device::get_memory_address()
+{
+ // this is valid for INP/OUT opcodes
+ return R[X];
+}
+
+//-------------------------------------------------
+// execute_min_cycles - return minimum number of
+// cycles it takes for one instruction to execute
+//-------------------------------------------------
+
+UINT32 cosmac_device::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::execute_max_cycles() const
+{
+ return 8 * 3;
+}
+
+
+//-------------------------------------------------
+// execute_input_lines - return the number of
+// input/interrupt lines
+//-------------------------------------------------
+
+UINT32 cosmac_device::execute_input_lines() const
+{
+ return 7;
+}
+
+
+//-------------------------------------------------
+// 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::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 = m_in_wait_func();
+ int clear = 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].isnull())
+ {
+ EF[i] = 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;
+
+ 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], 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()
+{
+ 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); }