From d1251c70f0753a465c929f4cae73bb856f67e9c3 Mon Sep 17 00:00:00 2001 From: Michael Zapf Date: Fri, 21 Mar 2014 13:22:47 +0000 Subject: [PATCH] TMS99xx CPU family gone to devcb2. (nw) --- src/emu/cpu/tms9900/ti990_10.h | 14 -- src/emu/cpu/tms9900/tms9900.c | 70 ++++--- src/emu/cpu/tms9900/tms9900.h | 37 ++-- src/emu/cpu/tms9900/tms9980a.c | 59 +++--- src/emu/cpu/tms9900/tms9980a.h | 12 -- src/emu/cpu/tms9900/tms9995.c | 346 +++++++++++++++++++-------------- src/emu/cpu/tms9900/tms9995.h | 85 ++++---- src/emu/cpu/tms9900/tms99com.h | 26 ++- 8 files changed, 372 insertions(+), 277 deletions(-) diff --git a/src/emu/cpu/tms9900/ti990_10.h b/src/emu/cpu/tms9900/ti990_10.h index 91c0493717d..f9e5a06f809 100644 --- a/src/emu/cpu/tms9900/ti990_10.h +++ b/src/emu/cpu/tms9900/ti990_10.h @@ -12,20 +12,6 @@ #include "debugger.h" #include "tms99com.h" -struct tms99xx_config -{ - devcb_write8 external_callback; - devcb_read8 irq_level; - devcb_write_line instruction_acquisition; - devcb_write_line clock_out; - devcb_write_line wait_line; - devcb_write_line holda_line; - devcb_write_line dbin_line; -}; - -#define TMS99xx_CONFIG(name) \ - const tms99xx_config(name) = - class ti990_10_device : public cpu_device { public: diff --git a/src/emu/cpu/tms9900/tms9900.c b/src/emu/cpu/tms9900/tms9900.c index c44abded0c9..c39180a7eb7 100644 --- a/src/emu/cpu/tms9900/tms9900.c +++ b/src/emu/cpu/tms9900/tms9900.c @@ -135,6 +135,9 @@ enum // Memory operation #define TRACE_MEM 0 +// Address bus operation +#define TRACE_ADDRESSBUS 0 + // Cycle count #define TRACE_CYCLES 0 @@ -172,7 +175,14 @@ tms99xx_device::tms99xx_device(const machine_config &mconfig, device_type type, m_prgspace(NULL), m_cru(NULL), m_prgaddr_mask((1<(static_config()); - assert (conf != NULL); - // Resolve our external connections - m_external_operation.resolve(conf->external_callback, *this); - m_get_intlevel.resolve(conf->irq_level, *this); - m_iaq_line.resolve(conf->instruction_acquisition, *this); - m_clock_out_line.resolve(conf->clock_out, *this); - m_wait_line.resolve(conf->wait_line, *this); - m_holda_line.resolve(conf->holda_line, *this); - m_dbin_line.resolve(conf->dbin_line, *this); // we need this for the set_address operation + m_external_operation.resolve(); + m_get_intlevel.resolve(); + m_iaq_line.resolve(); + m_clock_out_line.resolve(); + m_wait_line.resolve(); + m_holda_line.resolve(); + m_dbin_line.resolve(); // we need this for the set_address operation } /* @@ -1171,8 +1178,11 @@ void tms99xx_device::execute_run() { if (TRACE_WAIT) logerror("tms99xx: idle state\n"); pulse_clock(1); - m_external_operation(IDLE_OP, 0); - m_external_operation(IDLE_OP, 1); + if (!m_external_operation.isnull()) + { + m_external_operation(IDLE_OP, 0, 0xff); + m_external_operation(IDLE_OP, 1, 0xff); + } } else { @@ -1221,7 +1231,7 @@ void tms99xx_device::execute_run() m_pass = 1; MPC++; m_mem_phase = 1; - m_iaq_line(CLEAR_LINE); + if (!m_iaq_line.isnull()) m_iaq_line(CLEAR_LINE); } } } @@ -1270,7 +1280,8 @@ void tms99xx_device::execute_set_input(int irqline, int state) */ int tms99xx_device::get_intlevel(int state) { - return m_get_intlevel(0); + if (!m_get_intlevel.isnull()) return m_get_intlevel(0); + return 0; } void tms99xx_device::service_interrupt() @@ -1278,11 +1289,11 @@ void tms99xx_device::service_interrupt() m_program = int_mp; m_command = INTR; m_idle_state = false; - m_external_operation(IDLE_OP, 0); + if (!m_external_operation.isnull()) m_external_operation(IDLE_OP, 0, 0xff); m_state = 0; - m_dbin_line(ASSERT_LINE); + if (!m_dbin_line.isnull()) m_dbin_line(ASSERT_LINE); // If reset, we just start with execution, otherwise we put the MPC // on the first microinstruction, which also means that the main loop shall @@ -1326,9 +1337,9 @@ void tms99xx_device::pulse_clock(int count) { for (int i=0; i < count; i++) { - m_clock_out_line(ASSERT_LINE); + if (!m_clock_out_line.isnull()) m_clock_out_line(ASSERT_LINE); m_ready = m_ready_bufd; // get the latched READY state - m_clock_out_line(CLEAR_LINE); + if (!m_clock_out_line.isnull()) m_clock_out_line(CLEAR_LINE); m_icount--; // This is the only location where we count down the cycles. if (TRACE_CLOCK) { @@ -1347,7 +1358,7 @@ void tms99xx_device::set_hold(int state) if (!m_hold_state) { m_hold_acknowledged = false; - m_holda_line(CLEAR_LINE); + if (!m_holda_line.isnull()) m_holda_line(CLEAR_LINE); } } @@ -1357,7 +1368,7 @@ void tms99xx_device::set_hold(int state) inline void tms99xx_device::acknowledge_hold() { m_hold_acknowledged = true; - m_holda_line(ASSERT_LINE); + if (!m_holda_line.isnull()) m_holda_line(ASSERT_LINE); } /* @@ -1379,7 +1390,8 @@ void tms99xx_device::abort_operation() */ inline void tms99xx_device::set_wait_state(bool state) { - if (m_wait_state != state) m_wait_line(state? ASSERT_LINE : CLEAR_LINE); + if (m_wait_state != state) + if (!m_wait_line.isnull()) m_wait_line(state? ASSERT_LINE : CLEAR_LINE); m_wait_state = state; } @@ -1444,7 +1456,7 @@ void tms99xx_device::acquire_instruction() { if (m_mem_phase == 1) { - m_iaq_line(ASSERT_LINE); + if (!m_iaq_line.isnull()) m_iaq_line(ASSERT_LINE); m_address = PC; m_first_cycle = m_icount; } @@ -1473,12 +1485,12 @@ void tms99xx_device::mem_read() // set_address and read_word should pass the same address as argument if (m_mem_phase==1) { - m_dbin_line(ASSERT_LINE); + if (!m_dbin_line.isnull()) m_dbin_line(ASSERT_LINE); m_prgspace->set_address(m_address & m_prgaddr_mask & 0xfffe); m_check_ready = true; m_mem_phase = 2; m_pass = 2; - if (TRACE_MEM) logerror("tms99xx: set address (r) %04x\n", m_address); + if (TRACE_ADDRESSBUS) logerror("tms99xx: set address (r) %04x\n", m_address); pulse_clock(1); // Concludes the first cycle // If READY has been found to be low, the CPU will now stay in the wait state loop @@ -1488,7 +1500,7 @@ void tms99xx_device::mem_read() // Second phase (after READY was raised again) m_current_value = m_prgspace->read_word(m_address & m_prgaddr_mask & 0xfffe); pulse_clock(1); - m_dbin_line(CLEAR_LINE); + if (!m_dbin_line.isnull()) m_dbin_line(CLEAR_LINE); m_mem_phase = 1; // reset to phase 1 if (TRACE_MEM) logerror("tms99xx: mem r %04x -> %04x\n", m_address, m_current_value); } @@ -1498,9 +1510,9 @@ void tms99xx_device::mem_write() { if (m_mem_phase==1) { - m_dbin_line(CLEAR_LINE); + if (!m_dbin_line.isnull()) m_dbin_line(CLEAR_LINE); // When writing, the data bus is asserted immediately after the address bus - if (TRACE_MEM) logerror("tms99xx: set address (w) %04x\n", m_address); + if (TRACE_ADDRESSBUS) logerror("tms99xx: set address (w) %04x\n", m_address); m_prgspace->set_address(m_address & m_prgaddr_mask & 0xfffe); if (TRACE_MEM) logerror("tms99xx: mem w %04x <- %04x\n", m_address, m_current_value); m_prgspace->write_word(m_address & m_prgaddr_mask & 0xfffe, m_current_value); @@ -2601,7 +2613,7 @@ void tms99xx_device::alu_external() if (m_command == IDLE) m_idle_state = true; - m_external_operation((IR >> 5) & 0x07, 1); + if (!m_external_operation.isnull()) m_external_operation((IR >> 5) & 0x07, 1, 0xff); pulse_clock(2); } diff --git a/src/emu/cpu/tms9900/tms9900.h b/src/emu/cpu/tms9900/tms9900.h index 0ed5a2ec6bb..98c600420bc 100644 --- a/src/emu/cpu/tms9900/tms9900.h +++ b/src/emu/cpu/tms9900/tms9900.h @@ -39,20 +39,6 @@ static const char opname[][5] = "*int" }; -struct tms99xx_config -{ - devcb_write8 external_callback; - devcb_read8 irq_level; - devcb_write_line instruction_acquisition; - devcb_write_line clock_out; - devcb_write_line wait_line; - devcb_write_line holda_line; - devcb_write_line dbin_line; -}; - -#define TMS99xx_CONFIG(name) \ - const tms99xx_config(name) = - class tms99xx_device : public cpu_device { public: @@ -70,6 +56,15 @@ public: // is acknowledged by the HOLDA output line. void set_hold(int state); + // Callbacks + template static devcb2_base &static_set_extop_callback(device_t &device, _Object object) { return downcast(device).m_external_operation.set_callback(object); } + template static devcb2_base &static_set_intlevel_callback(device_t &device, _Object object) { return downcast(device).m_get_intlevel.set_callback(object); } + template static devcb2_base &static_set_iaq_callback(device_t &device, _Object object) { return downcast(device).m_iaq_line.set_callback(object); } + template static devcb2_base &static_set_clkout_callback(device_t &device, _Object object) { return downcast(device).m_clock_out_line.set_callback(object); } + template static devcb2_base &static_set_wait_callback(device_t &device, _Object object) { return downcast(device).m_wait_line.set_callback(object); } + template static devcb2_base &static_set_holda_callback(device_t &device, _Object object) { return downcast(device).m_holda_line.set_callback(object); } + template static devcb2_base &static_set_dbin_callback(device_t &device, _Object object) { return downcast(device).m_dbin_line.set_callback(object); } + protected: // device-level overrides virtual void device_start(); @@ -170,22 +165,22 @@ protected: // Clock output. This is not a pin of the TMS9900 because the TMS9900 // needs an external clock, and usually one of those external lines is // used for this purpose. - devcb_resolved_write_line m_clock_out_line; + devcb2_write_line m_clock_out_line; // Wait output. When asserted (high), the CPU is in a wait state. - devcb_resolved_write_line m_wait_line; + devcb2_write_line m_wait_line; // HOLD Acknowledge line. When asserted (high), the CPU is in HOLD state. - devcb_resolved_write_line m_holda_line; + devcb2_write_line m_holda_line; // Signal to the outside world that we are now getting an instruction - devcb_resolved_write_line m_iaq_line; + devcb2_write_line m_iaq_line; // Get the value of the interrupt level lines - devcb_resolved_read8 m_get_intlevel; + devcb2_read8 m_get_intlevel; // DBIN line. When asserted (high), the CPU has disabled the data bus output buffers. - devcb_resolved_write_line m_dbin_line; + devcb2_write_line m_dbin_line; // Trigger external operation. This is achieved by putting a special value in // the most significant three bits of the address bus (TMS9995: data bus) and @@ -207,7 +202,7 @@ protected: // We could realize this via the CRU access as well, but the data bus access // is not that simple to emulate. For the sake of homogenity between the // chip emulations we use a dedicated callback. - devcb_resolved_write8 m_external_operation; + devcb2_write8 m_external_operation; private: diff --git a/src/emu/cpu/tms9900/tms9980a.c b/src/emu/cpu/tms9900/tms9980a.c index 6e68814b12c..054a293a403 100644 --- a/src/emu/cpu/tms9900/tms9980a.c +++ b/src/emu/cpu/tms9900/tms9980a.c @@ -53,8 +53,22 @@ #include "tms9980a.h" -#define LOG logerror -#define VERBOSE 1 +/* + The following defines can be set to 0 or 1 to disable or enable certain + output in the log. +*/ + +// Memory operation +#define TRACE_MEM 0 + +// Address bus operation +#define TRACE_ADDRESSBUS 0 + +// Log operation +#define TRACE_OP 0 + +// Interrupts +#define TRACE_INT 0 /**************************************************************************** Constructor @@ -70,15 +84,12 @@ tms9980a_device::tms9980a_device(const machine_config &mconfig, const char *tag, */ void tms9980a_device::resolve_lines() { - const tms9980a_config *conf = reinterpret_cast(static_config()); - assert (conf != NULL); - // Resolve our external connections - m_external_operation.resolve(conf->external_callback, *this); - m_iaq_line.resolve(conf->instruction_acquisition, *this); - m_clock_out_line.resolve(conf->clock_out, *this); - m_holda_line.resolve(conf->holda_line, *this); - m_dbin_line.resolve(conf->dbin_line, *this); + m_external_operation.resolve(); + m_iaq_line.resolve(); + m_clock_out_line.resolve(); + m_holda_line.resolve(); + m_dbin_line.resolve(); } UINT16 tms9980a_device::read_workspace_register_debug(int reg) @@ -137,7 +148,7 @@ void tms9980a_device::execute_set_input(int irqline, int state) // Clear all interrupts m_load_state = false; m_irq_state = false; - if (VERBOSE>6) LOG("tms9980a: clear interrupts\n"); + if (TRACE_INT) logerror("tms9980a: clear interrupts\n"); break; } @@ -152,7 +163,7 @@ void tms9980a_device::execute_set_input(int irqline, int state) m_load_state = true; } else m_irq_state = true; - if (VERBOSE>6) LOG("tms9980a: interrupt level=%d, ST=%04x\n", m_irq_level, ST); + if (TRACE_INT) logerror("tms9980a: interrupt level=%d, ST=%04x\n", m_irq_level, ST); } } @@ -169,26 +180,26 @@ void tms9980a_device::mem_read() { case 1: m_pass = 4; // make the CPU visit this method more than once - m_dbin_line(ASSERT_LINE); + if (!m_dbin_line.isnull()) m_dbin_line(ASSERT_LINE); m_prgspace->set_address(m_address & m_prgaddr_mask & ~1); - if (VERBOSE>7) LOG("tms9980a: set address bus %04x\n", m_address & m_prgaddr_mask & ~1); + if (TRACE_ADDRESSBUS) logerror("tms9980a: set address bus %04x\n", m_address & m_prgaddr_mask & ~1); m_check_ready = true; break; case 2: // Sample the value on the data bus (high byte) value = m_prgspace->read_byte(m_address & m_prgaddr_mask & ~1); - if (VERBOSE>7) LOG("tms9980a: memory read high byte %04x -> %02x\n", m_address & m_prgaddr_mask & ~1, value); + if (TRACE_MEM) logerror("tms9980a: memory read high byte %04x -> %02x\n", m_address & m_prgaddr_mask & ~1, value); m_current_value = (value << 8) & 0xff00; break; case 3: m_prgspace->set_address((m_address & m_prgaddr_mask) | 1); - if (VERBOSE>7) LOG("tms9980a: set address bus %04x\n", (m_address & m_prgaddr_mask) | 1); + if (TRACE_ADDRESSBUS) logerror("tms9980a: set address bus %04x\n", (m_address & m_prgaddr_mask) | 1); break; case 4: // Sample the value on the data bus (low byte) value = m_prgspace->read_byte((m_address & m_prgaddr_mask) | 1); m_current_value = m_current_value | (value & 0x00ff); - if (VERBOSE>7) LOG("tms9980a: memory read low byte %04x -> %02x -> complete word %04x\n", (m_address & m_prgaddr_mask) | 1, value, m_current_value); + if (TRACE_MEM) logerror("tms9980a: memory read low byte %04x -> %02x -> complete word %04x\n", (m_address & m_prgaddr_mask) | 1, value, m_current_value); break; } pulse_clock(1); @@ -202,11 +213,11 @@ void tms9980a_device::mem_write() { case 1: m_pass = 4; // make the CPU visit this method once more - m_dbin_line(CLEAR_LINE); + if (!m_dbin_line.isnull()) m_dbin_line(CLEAR_LINE); m_prgspace->set_address(m_address & m_prgaddr_mask & ~1); - if (VERBOSE>7) LOG("tms9980a: set address bus %04x\n", m_address & m_prgaddr_mask & ~1); + if (TRACE_ADDRESSBUS) logerror("tms9980a: set address bus %04x\n", m_address & m_prgaddr_mask & ~1); m_prgspace->write_byte(m_address & 0x3ffe & ~1, (m_current_value >> 8)&0xff); - if (VERBOSE>7) LOG("tms9980a: memory write high byte %04x <- %02x\n", m_address & m_prgaddr_mask & ~1, (m_current_value >> 8)&0xff); + if (TRACE_MEM) logerror("tms9980a: memory write high byte %04x <- %02x\n", m_address & m_prgaddr_mask & ~1, (m_current_value >> 8)&0xff); m_check_ready = true; break; case 2: @@ -214,9 +225,9 @@ void tms9980a_device::mem_write() break; case 3: m_prgspace->set_address((m_address & m_prgaddr_mask) | 1); - if (VERBOSE>7) LOG("tms9980a: set address bus %04x\n", (m_address & m_prgaddr_mask) | 1); + if (TRACE_ADDRESSBUS) logerror("tms9980a: set address bus %04x\n", (m_address & m_prgaddr_mask) | 1); m_prgspace->write_byte((m_address & m_prgaddr_mask) | 1, m_current_value & 0xff); - if (VERBOSE>7) LOG("tms9980a: memory write low byte %04x <- %02x\n", (m_address & m_prgaddr_mask) | 1, m_current_value & 0xff); + if (TRACE_MEM) logerror("tms9980a: memory write low byte %04x <- %02x\n", (m_address & m_prgaddr_mask) | 1, m_current_value & 0xff); break; case 4: // no action here, just wait for READY @@ -230,7 +241,7 @@ void tms9980a_device::acquire_instruction() { if (m_mem_phase == 1) { - m_iaq_line(ASSERT_LINE); + if (!m_iaq_line.isnull()) m_iaq_line(ASSERT_LINE); m_address = PC; m_first_cycle = m_icount; } @@ -239,7 +250,7 @@ void tms9980a_device::acquire_instruction() if (m_mem_phase == 1) // changed by mem_read and wrapped { decode(m_current_value); - if (VERBOSE>3) LOG("tms9980a: ===== Next operation %04x (%s) at %04x =====\n", IR, opname[m_command], PC); + if (TRACE_OP) logerror("tms9980a: ===== Next operation %04x (%s) at %04x =====\n", IR, opname[m_command], PC); debugger_instruction_hook(this, PC); PC = (PC + 2) & 0xfffe & m_prgaddr_mask; } diff --git a/src/emu/cpu/tms9900/tms9980a.h b/src/emu/cpu/tms9900/tms9980a.h index c5bb7820827..82492d6073a 100644 --- a/src/emu/cpu/tms9900/tms9980a.h +++ b/src/emu/cpu/tms9900/tms9980a.h @@ -23,18 +23,6 @@ enum INT_9980A_CLEAR= 7 }; -struct tms9980a_config -{ - devcb_write8 external_callback; - devcb_write_line instruction_acquisition; - devcb_write_line clock_out; - devcb_write_line holda_line; - devcb_write_line dbin_line; -}; - -#define TMS9980A_CONFIG(name) \ - const tms9980a_config(name) = - class tms9980a_device : public tms99xx_device { public: diff --git a/src/emu/cpu/tms9900/tms9995.c b/src/emu/cpu/tms9900/tms9995.c index 8521580e901..052525788cc 100644 --- a/src/emu/cpu/tms9900/tms9995.c +++ b/src/emu/cpu/tms9900/tms9995.c @@ -13,7 +13,7 @@ D4 | 7 34| A9 D3 | 8 33| A8 D2 | 9 32| A7 - V_CC |10 31| V_SS + Vcc |10 31| Vss D1 |11 30| A6 D0 |12 29| A5 CRUIN |13 28| A4 @@ -44,8 +44,8 @@ READY in Memory/External CRU device ready for access CRUOUT out Communication register unit data output - V_CC +5V supply - V_SS 0V Ground reference + Vcc +5V supply + Vss 0V Ground reference A0-A15 out Address bus D0-D7 in/out Data bus @@ -121,16 +121,56 @@ enum Set to 0 (disable) or 1 (enable) ******************************************************************/ -#define LOG logerror - // Log addresses of executed opcodes #define TRACE_EXEC 0 + +// Log cycles #define TRACE_CYCLES 0 -// This is the previous debugging approach which will be replaced by the -// specific switches above -// VERBOSE = 0 ... 9 -#define VERBOSE 1 +// Log configuration +#define TRACE_CONFIG 1 + +// Log emulation details +#define TRACE_EMU 0 + +// Log wait/hold states +#define TRACE_WAITHOLD 0 + +// Log microinstruction processing +#define TRACE_MICRO 0 + +// Log interrupts +#define TRACE_INT 0 + +// Log interrupts (detailed phases) +#define TRACE_INTD 0 + +// Log clock pulses +#define TRACE_CLOCK 0 + +// Log READY line input +#define TRACE_READY 0 + +// Log memory access +#define TRACE_MEM 0 + +// Log address bus operation +#define TRACE_ADDRESSBUS 0 + +// Log CRU operations +#define TRACE_CRU 0 + +// Log status register +#define TRACE_STATUS 0 + +// Log operation +#define TRACE_OP 0 + +// Log decrementer operation +#define TRACE_DEC 0 + +// Log with max detail +#define TRACE_DETAIL 0 /**************************************************************************** Constructor @@ -144,10 +184,39 @@ tms9995_device::tms9995_device(const machine_config &mconfig, const char *tag, d m_program_config("program", ENDIANNESS_BIG, 8, 16), m_io_config("cru", ENDIANNESS_BIG, 8, 16), m_prgspace(NULL), - m_cru(NULL) + m_cru(NULL), + m_external_operation(*this), + m_iaq_line(*this), + m_clock_out_line(*this), + m_holda_line(*this), + m_dbin_line(*this) { + m_mp9537 = false; + m_check_overflow = false; } +/* + Called from subclass. +*/ +tms9995_device::tms9995_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : cpu_device(mconfig, TMS9995, name, tag, owner, clock, shortname, source), + m_state_any(0), + PC(0), + PC_debug(0), + m_program_config("program", ENDIANNESS_BIG, 8, 16), + m_io_config("cru", ENDIANNESS_BIG, 8, 16), + m_prgspace(NULL), + m_cru(NULL), + m_external_operation(*this), + m_iaq_line(*this), + m_clock_out_line(*this), + m_holda_line(*this), + m_dbin_line(*this) +{ + m_check_overflow = false; +} + + enum { TMS9995_PC=0, TMS9995_WP, TMS9995_STATUS, TMS9995_IR, @@ -159,26 +228,17 @@ enum void tms9995_device::device_start() { - const tms9995_config *conf = reinterpret_cast(static_config()); - - assert (conf != NULL); - // TODO: Restore save state suport m_prgspace = &space(AS_PROGRAM); // dimemory.h m_cru = &space(AS_IO); // Resolve our external connections - m_external_operation.resolve(conf->external_callback, *this); - m_iaq_line.resolve(conf->iaq_line, *this); - m_clock_out_line.resolve(conf->clock_out, *this); - m_holda_line.resolve(conf->holda_line, *this); - m_dbin_line.resolve(conf->dbin_line, *this); - - m_mp9537 = (conf->mode==NO_INTERNAL_RAM); - m_check_overflow = (conf->overflow==OVERFLOW_INT); - - if (VERBOSE>0) LOG("tms9995: Configured with%s internal memory and%s overflow interrupt\n", m_mp9537? " no" : "", m_check_overflow? "" : " no"); + m_external_operation.resolve(); + m_iaq_line.resolve(); + m_clock_out_line.resolve(); + m_holda_line.resolve(); + m_dbin_line.resolve(); // set our instruction counter m_icountptr = &m_icount; @@ -206,12 +266,14 @@ void tms9995_device::device_start() // Set up the lookup table for command decoding build_command_lookup_table(); + + if (TRACE_CONFIG) logerror("%s: Variant = %s, Overflow int = %s\n", tag(), m_mp9537? "MP9537 (no on-chip RAM)" : "with on-chip RAM", m_check_overflow? "check" : "no check"); } void tms9995_device::device_stop() { int k = 0; - if (VERBOSE>8) LOG("tms9995: Deleting lookup tables\n"); + if (TRACE_CONFIG) logerror("%s: Deleting lookup tables\n", tag()); while (m_lotables[k]!=NULL) delete[] m_lotables[k++]; } @@ -1086,7 +1148,7 @@ void tms9995_device::build_command_lookup_table() { inst = &s_command[i]; table = m_command_lookup_table; - if (VERBOSE>8) LOG("tms9995: === opcode=%04x, len=%d\n", inst->opcode, format_mask_len[inst->format]); + if (TRACE_EMU) logerror("tms9995: === opcode=%04x, len=%d\n", inst->opcode, format_mask_len[inst->format]); bitcount = 4; opcode = inst->opcode; cmdindex = (opcode>>12) & 0x000f; @@ -1096,7 +1158,7 @@ void tms9995_device::build_command_lookup_table() // Descend if (table[cmdindex].next_digit == NULL) { - if (VERBOSE>8) LOG("tms9995: create new table at bitcount=%d for index=%d\n", bitcount, cmdindex); + if (TRACE_EMU) logerror("tms9995: create new table at bitcount=%d for index=%d\n", bitcount, cmdindex); table[cmdindex].next_digit = new lookup_entry[16]; m_lotables[k++] = table[cmdindex].next_digit; for (int j=0; j < 16; j++) @@ -1107,7 +1169,7 @@ void tms9995_device::build_command_lookup_table() } else { - if (VERBOSE>8) LOG("tms9995: found a table at bitcount=%d\n", bitcount); + if (TRACE_EMU) logerror("tms9995: found a table at bitcount=%d\n", bitcount); } table = table[cmdindex].next_digit; @@ -1115,17 +1177,17 @@ void tms9995_device::build_command_lookup_table() bitcount = bitcount+4; opcode <<= 4; cmdindex = (opcode>>12) & 0x000f; - if (VERBOSE>8) LOG("tms9995: next index=%x\n", cmdindex); + if (TRACE_EMU) logerror("tms9995: next index=%x\n", cmdindex); } - if (VERBOSE>8) LOG("tms9995: bitcount=%d\n", bitcount); + if (TRACE_EMU) logerror("tms9995: bitcount=%d\n", bitcount); // We are at the target level // Need to fill in the same entry for all values in the bitcount // (if a command needs 10 bits we have to copy it four // times for all combinations with 12 bits) for (int j=0; j < (1<<(bitcount-format_mask_len[inst->format])); j++) { - if (VERBOSE>8) LOG("tms9995: opcode=%04x at position %d\n", inst->opcode, cmdindex+j); + if (TRACE_EMU) logerror("tms9995: opcode=%04x at position %d\n", inst->opcode, cmdindex+j); table[cmdindex+j].entry = inst; } @@ -1133,7 +1195,7 @@ void tms9995_device::build_command_lookup_table() } while (inst->opcode != 0xf000); m_lotables[k++] = NULL; - if (VERBOSE>8) LOG("tms9995: Allocated %d tables\n", k); + if (TRACE_EMU) logerror("tms9995: Allocated %d tables\n", k); } /* @@ -1148,14 +1210,14 @@ void tms9995_device::execute_run() { if (m_reset) service_interrupt(); - if (VERBOSE>5) LOG("tms9995: calling execute_run for %d cycles\n", m_icount); + if (TRACE_EMU) logerror("tms9995: calling execute_run for %d cycles\n", m_icount); do { // Normal operation if (m_check_ready && m_ready == false) { // We are in a wait state - if (VERBOSE>2) LOG("tms9995: wait state\n"); + if (TRACE_WAITHOLD) logerror("tms9995: wait state\n"); // The clock output should be used to change the state of an outer // device which operates the READY line pulse_clock(1); @@ -1165,7 +1227,7 @@ void tms9995_device::execute_run() if (m_check_hold && m_hold_state) { set_hold_state(true); - if (VERBOSE>6) LOG("tms9995: hold state\n"); + if (TRACE_WAITHOLD) logerror("tms9995: hold state\n"); pulse_clock(1); } else @@ -1174,7 +1236,7 @@ void tms9995_device::execute_run() m_check_ready = false; - if (VERBOSE>8) LOG("tms9995: main loop, operation %s, MPC = %d\n", opname[m_instruction->command], MPC); + if (TRACE_MICRO) logerror("tms9995: main loop, operation %s, MPC = %d\n", opname[m_instruction->command], MPC); (this->*s_microoperation[m_instruction->program[MPC]])(); // For multi-pass operations where the MPC should not advance @@ -1188,7 +1250,7 @@ void tms9995_device::execute_run() } } } while (m_icount>0 && !m_reset); - if (VERBOSE>5) LOG("tms9995: cycles expired; will return soon.\n"); + if (TRACE_EMU) logerror("tms9995: cycles expired; will return soon.\n"); } /**************************************************************************/ @@ -1211,34 +1273,34 @@ void tms9995_device::execute_set_input(int irqline, int state) if (irqline == INPUT_LINE_NMI) { m_nmi_active = (state==ASSERT_LINE); - if (VERBOSE>3) LOG("tms9995: NMI interrupt line state=%d\n", state); + if (TRACE_INT) logerror("tms9995: NMI interrupt line state=%d\n", state); } else { if (irqline == INT_9995_INT1) { m_int1_active = m_flag[2] = (state==ASSERT_LINE); - if (VERBOSE>3) LOG("tms9995: Line INT1 state=%d\n", state); + if (TRACE_INT) logerror("tms9995: Line INT1 state=%d\n", state); } else { if (irqline == INT_9995_INT4) { - if (VERBOSE>3) LOG("tms9995: Line INT4/EC state=%d\n", state); + if (TRACE_INT) logerror("tms9995: Line INT4/EC state=%d\n", state); if (m_flag[0]==false) { - if (VERBOSE>7) LOG("tms9995: set as interrupt\n"); + if (TRACE_INT) logerror("tms9995: set as interrupt\n"); m_int4_active = m_flag[4] = (state==ASSERT_LINE); } else { - if (VERBOSE>7) LOG("tms9995: set as event count\n"); + if (TRACE_INT) logerror("tms9995: set as event count\n"); trigger_decrementer(); } } else { - if (VERBOSE>0) LOG("tms9995: Accessed invalid interrupt line %d\n", irqline); + logerror("tms9995: Accessed invalid interrupt line %d\n", irqline); } } } @@ -1252,14 +1314,14 @@ void tms9995_device::pulse_clock(int count) { for (int i=0; i < count; i++) { - m_clock_out_line(ASSERT_LINE); + if (!m_clock_out_line.isnull()) m_clock_out_line(ASSERT_LINE); m_ready = m_ready_bufd && !m_request_auto_wait_state; // get the latched READY state - m_clock_out_line(CLEAR_LINE); + if (!m_clock_out_line.isnull()) m_clock_out_line(CLEAR_LINE); m_icount--; // This is the only location where we count down the cycles. - if (VERBOSE>6) + if (TRACE_CLOCK) { - if (m_check_ready) LOG("tms9995: pulse_clock, READY=%d, auto_wait=%d\n", m_ready_bufd? 1:0, m_auto_wait? 1:0); - else LOG("tms9995: pulse_clock\n"); + if (m_check_ready) logerror("tms9995: pulse_clock, READY=%d, auto_wait=%d\n", m_ready_bufd? 1:0, m_auto_wait? 1:0); + else logerror("tms9995: pulse_clock\n"); } m_request_auto_wait_state = false; if (m_flag[0] == false && m_flag[1] == true) @@ -1278,10 +1340,10 @@ void tms9995_device::pulse_clock(int count) void tms9995_device::set_hold(int state) { m_hold_state = (state==ASSERT_LINE); - if (VERBOSE>7) LOG("tms9995: set HOLD = %d\n", state); + if (TRACE_WAITHOLD) logerror("tms9995: set HOLD = %d\n", state); if (!m_hold_state) { - m_holda_line(CLEAR_LINE); + if (!m_holda_line.isnull()) m_holda_line(CLEAR_LINE); } } @@ -1292,7 +1354,7 @@ void tms9995_device::set_hold(int state) void tms9995_device::set_ready(int state) { m_ready_bufd = (state==ASSERT_LINE); - if (VERBOSE>7) LOG("tms9995: set READY = %d\n", m_ready_bufd? 1 : 0); + if (TRACE_READY) logerror("tms9995: set READY = %d\n", m_ready_bufd? 1 : 0); } /* @@ -1312,7 +1374,8 @@ void tms9995_device::abort_operation() */ inline void tms9995_device::set_hold_state(bool state) { - if (m_hold_state != state) m_holda_line(state? ASSERT_LINE : CLEAR_LINE); + if (m_hold_state != state) + if (!m_holda_line.isnull()) m_holda_line(state? ASSERT_LINE : CLEAR_LINE); m_hold_state = state; } @@ -1335,7 +1398,7 @@ void tms9995_device::decode(UINT16 inst) while (!complete) { index = (opcode >> 12) & 0x000f; - if (VERBOSE>8) LOG("tms9995: Check next hex digit of instruction %x\n", index); + if (TRACE_EMU) logerror("tms9995: Check next hex digit of instruction %x\n", index); if (table[index].next_digit != NULL) { table = table[index].next_digit; @@ -1347,7 +1410,7 @@ void tms9995_device::decode(UINT16 inst) if (decoded == NULL) { // not found - if (VERBOSE>0) LOG("tms9995: Unknown opcode %04x, will trigger MID\n", inst); + logerror("tms9995: Unknown opcode %04x, will trigger MID\n", inst); m_decoded[dindex].IR = 0; m_decoded[dindex].command = MID; } @@ -1358,7 +1421,7 @@ void tms9995_device::decode(UINT16 inst) m_decoded[dindex].program = decoded->prog; m_decoded[dindex].byteop = ((decoded->format == 1) && ((inst & 0x1000)!=0)); m_decoded[dindex].state = 0; - if (VERBOSE>7) LOG("tms9995: Command decoded as id %d, %s, base opcode %04x\n", decoded->id, opname[decoded->id], decoded->opcode); + if (TRACE_EMU) logerror("tms9995: Command decoded as id %d, %s, base opcode %04x\n", decoded->id, opname[decoded->id], decoded->opcode); m_pass = 1; } } @@ -1379,7 +1442,7 @@ void tms9995_device::int_prefetch_and_decode() // Check interrupt lines if (m_nmi_active) { - if (VERBOSE>7) LOG("tms9995: Checking interrupts ... NMI active\n"); + if (TRACE_INT) logerror("tms9995: Checking interrupts ... NMI active\n"); m_int_pending |= PENDING_NMI; m_idle_state = false; PC = (PC + 2) & 0xfffe; // we have not prefetched the next instruction @@ -1402,19 +1465,19 @@ void tms9995_device::int_prefetch_and_decode() if (m_idle_state) { m_idle_state = false; - if (VERBOSE>3) LOG("tms9995: Interrupt occured, terminate IDLE state\n"); + if (TRACE_INT) logerror("tms9995: Interrupt occured, terminate IDLE state\n"); } PC = PC + 2; // PC must be advanced (see flow chart), but no prefetch - if (VERBOSE>7) LOG("tms9995: Interrupts pending; no prefetch; advance PC to %04x\n", PC); + if (TRACE_INT) logerror("tms9995: Interrupts pending; no prefetch; advance PC to %04x\n", PC); return; } else { - if (VERBOSE>7) LOG("tms9995: Checking interrupts ... none pending\n"); + if (TRACE_INT) logerror("tms9995: Checking interrupts ... none pending\n"); // No pending interrupts if (m_idle_state) { - if (VERBOSE>7) LOG("tms9995: IDLE state\n"); + if (TRACE_WAITHOLD) logerror("tms9995: IDLE state\n"); // We are IDLE, stay in the loop and do not advance the PC m_pass = 2; pulse_clock(1); @@ -1442,9 +1505,9 @@ void tms9995_device::prefetch_and_decode() // Save these values; they have been computed during the current instruction execution m_address_copy = m_address; m_value_copy = m_current_value; - m_iaq_line(ASSERT_LINE); + if (!m_iaq_line.isnull()) m_iaq_line(ASSERT_LINE); m_address = PC; - if (VERBOSE>5) LOG("tms9995: **** Prefetching new instruction at %04x ****\n", PC); + if (TRACE_OP) logerror("tms9995: **** Prefetching new instruction at %04x ****\n", PC); } word_read(); // changes m_mem_phase @@ -1456,8 +1519,8 @@ void tms9995_device::prefetch_and_decode() m_address = m_address_copy; // restore m_address m_current_value = m_value_copy; // restore m_current_value PC = (PC + 2) & 0xfffe; // advance PC - m_iaq_line(CLEAR_LINE); - if (VERBOSE>5) LOG("tms9995: ++++ Prefetch done ++++\n"); + if (!m_iaq_line.isnull()) m_iaq_line(CLEAR_LINE); + if (TRACE_OP) logerror("tms9995: ++++ Prefetch done ++++\n"); } } @@ -1484,11 +1547,13 @@ void tms9995_device::next_command() // This is a preset for opcodes which do not need an opcode address derivation m_address = WP + ((m_instruction->IR & 0x000f)<<1); MPC = -1; - if (VERBOSE>3) LOG("tms9995: ===== Next operation %04x (%s) at %04x =====\n", m_instruction->IR, opname[m_instruction->command], PC-2); -#if TRACE_EXEC - if (m_servicing_interrupt) LOG("i%04x\n", PC-2); - else LOG("%04x\n", PC-2); -#endif + if (TRACE_OP) logerror("tms9995: ===== Next operation %04x (%s) at %04x =====\n", m_instruction->IR, opname[m_instruction->command], PC-2); + + if (TRACE_EXEC) + { + if (m_servicing_interrupt) logerror("i%04x\n", PC-2); + else logerror("%04x\n", PC-2); + } PC_debug = PC - 2; debugger_instruction_hook(this, PC_debug); m_first_cycle = m_icount; @@ -1503,11 +1568,11 @@ void tms9995_device::command_completed() // Pseudo state at the end of the current instruction cycle sequence if (TRACE_CYCLES) { - LOG("tms9995: +++++ Instruction %04x (%s) completed", m_instruction->IR, opname[m_instruction->command]); + logerror("tms9995: +++++ Instruction %04x (%s) completed", m_instruction->IR, opname[m_instruction->command]); int cycles = m_first_cycle - m_icount; // Avoid nonsense values due to expired and resumed main loop - if (cycles > 0 && cycles < 10000) LOG(", consumed %d cycles", cycles); - LOG(" +++++\n"); + if (cycles > 0 && cycles < 10000) logerror(", consumed %d cycles", cycles); + logerror(" +++++\n"); } if (m_int_pending != 0) @@ -1559,7 +1624,7 @@ void tms9995_device::service_interrupt() // The auto-wait state generation is turned on when the READY line is cleared // on RESET. m_auto_wait = !m_ready_bufd; - if (VERBOSE>0) LOG("tms9995: RESET; automatic wait state creation is %s\n", m_auto_wait? "enabled":"disabled"); + if (TRACE_CONFIG) logerror("tms9995: RESET; automatic wait state creation is %s\n", m_auto_wait? "enabled":"disabled"); // We reset the READY flag, or the CPU will not start m_ready_bufd = true; } @@ -1570,7 +1635,7 @@ void tms9995_device::service_interrupt() vectorpos = 0x0008; m_intmask = 0x0001; PC = (PC + 2) & 0xfffe; - if (VERBOSE>7) LOG("tms9995: ***** MID pending\n"); + if (TRACE_INT) logerror("tms9995: ***** MID pending\n"); m_mid_active = false; } else @@ -1580,7 +1645,7 @@ void tms9995_device::service_interrupt() vectorpos = 0xfffc; m_int_pending &= ~PENDING_NMI; m_intmask = 0; - if (VERBOSE>7) LOG("tms9995: ***** NMI pending\n"); + if (TRACE_INT) logerror("tms9995: ***** NMI pending\n"); } else { @@ -1590,7 +1655,7 @@ void tms9995_device::service_interrupt() m_int_pending &= ~PENDING_LEVEL1; m_flag[2] = false; m_intmask = 0; - if (VERBOSE>7) LOG("tms9995: ***** INT1 pending\n"); + if (TRACE_INT) logerror("tms9995: ***** INT1 pending\n"); } else { @@ -1599,7 +1664,7 @@ void tms9995_device::service_interrupt() vectorpos = 0x0008; m_int_pending &= ~PENDING_OVERFLOW; m_intmask = 0x0001; - if (VERBOSE>7) LOG("tms9995: ***** OVERFL pending\n"); + if (TRACE_INT) logerror("tms9995: ***** OVERFL pending\n"); } else { @@ -1610,7 +1675,7 @@ void tms9995_device::service_interrupt() m_int_pending &= ~PENDING_DECR; m_flag[3] = false; m_int_decrementer = false; - if (VERBOSE>7) LOG("tms9995: ***** DECR pending\n"); + if (TRACE_DEC) logerror("tms9995: ***** DECR pending\n"); } else { @@ -1618,7 +1683,7 @@ void tms9995_device::service_interrupt() m_intmask = 0x0003; m_int_pending &= ~PENDING_LEVEL4; m_flag[4] = false; - if (VERBOSE>7) LOG("tms9995: ***** INT4 pending\n"); + if (TRACE_INT) logerror("tms9995: ***** INT4 pending\n"); } } } @@ -1626,7 +1691,7 @@ void tms9995_device::service_interrupt() } } - if (VERBOSE>6) LOG("tms9995: ********* triggered an interrupt with vector %04x/%04x\n", vectorpos, vectorpos+2); + if (TRACE_INT) logerror("tms9995: ********* triggered an interrupt with vector %04x/%04x\n", vectorpos, vectorpos+2); // just for debugging purposes m_servicing_interrupt = true; @@ -1676,7 +1741,7 @@ void tms9995_device::mem_read() if ((m_address & 0xfffe)==0xfffa && !m_mp9537) { - if (VERBOSE>5) LOG("tms9995: read decrementer\n"); + if (TRACE_DEC) logerror("tms9995: read decrementer\n"); // Decrementer mapped into the address space m_current_value = m_decrementer_value; if (m_instruction->byteop) @@ -1695,7 +1760,7 @@ void tms9995_device::mem_read() // byte operations (e.g. when retrieving the index register) if (m_word_access || !m_instruction->byteop) m_address &= 0xfffe; - if (VERBOSE>5) LOG("tms9995: read onchip memory (single pass, address %04x)\n", m_address); + if (TRACE_MEM) logerror("tms9995: read onchip memory (single pass, address %04x)\n", m_address); // Ignore the READY state m_check_ready = false; @@ -1720,7 +1785,7 @@ void tms9995_device::mem_read() case 1: // Set address // If this is a word access, 4 passes, else 2 passes - m_dbin_line(ASSERT_LINE); + if (!m_dbin_line.isnull()) m_dbin_line(ASSERT_LINE); if (m_word_access || !m_instruction->byteop) { m_pass = 4; @@ -1730,7 +1795,7 @@ void tms9995_device::mem_read() else m_pass = 2; m_check_hold = false; - if (VERBOSE>6) LOG("tms9995: set address bus %04x\n", m_address & ~1); + if (TRACE_ADDRESSBUS) logerror("tms9995: set address bus %04x\n", m_address & ~1); m_prgspace->set_address(address); m_request_auto_wait_state = m_auto_wait; pulse_clock(1); @@ -1739,12 +1804,12 @@ void tms9995_device::mem_read() // Sample the value on the data bus (high byte) if (m_word_access || !m_instruction->byteop) address &= 0xfffe; value = m_prgspace->read_byte(address); - if (VERBOSE>3) LOG("tms9995: memory read byte %04x -> %02x\n", m_address & ~1, value); + if (TRACE_MEM) logerror("tms9995: memory read byte %04x -> %02x\n", m_address & ~1, value); m_current_value = (value << 8) & 0xff00; break; case 3: // Set address + 1 (unless byte command) - if (VERBOSE>6) LOG("tms9995: set address bus %04x\n", m_address | 1); + if (TRACE_ADDRESSBUS) logerror("tms9995: set address bus %04x\n", m_address | 1); m_prgspace->set_address(m_address | 1); pulse_clock(1); break; @@ -1752,7 +1817,7 @@ void tms9995_device::mem_read() // Read low byte value = m_prgspace->read_byte(m_address | 1); m_current_value |= value; - if (VERBOSE>3) LOG("tms9995: memory read byte %04x -> %02x, complete word = %04x\n", m_address | 1, value, m_current_value); + if (TRACE_MEM) logerror("tms9995: memory read byte %04x -> %02x, complete word = %04x\n", m_address | 1, value, m_current_value); m_check_hold = true; break; } @@ -1798,8 +1863,6 @@ void tms9995_device::mem_write() { if ((m_address & 0xfffe)==0xfffa && !m_mp9537) { - if (VERBOSE>5) LOG("tms9995: setting decrementer\n"); - if (m_instruction->byteop) { // According to [1], section 2.3.1.2.2: @@ -1818,7 +1881,7 @@ void tms9995_device::mem_write() { m_starting_count_storage_register = m_decrementer_value = m_current_value; } - if (VERBOSE>2) LOG("tms9995: Setting decrementer to %04x, PC=%04x\n", m_current_value, PC); + if (TRACE_DEC) logerror("tms9995: Setting decrementer to %04x, PC=%04x\n", m_current_value, PC); pulse_clock(1); return; } @@ -1830,7 +1893,7 @@ void tms9995_device::mem_write() // byte operations (e.g. when retrieving the index register) if (m_word_access || !m_instruction->byteop) m_address &= 0xfffe; - if (VERBOSE>3) LOG("tms9995: write to onchip memory (single pass, address %04x, value=%04x)\n", m_address, m_current_value); + if (TRACE_MEM) logerror("tms9995: write to onchip memory (single pass, address %04x, value=%04x)\n", m_address, m_current_value); m_check_ready = false; m_onchip_memory[m_address & 0x00ff] = (m_current_value >> 8) & 0xff; if (m_word_access || !m_instruction->byteop) @@ -1849,7 +1912,7 @@ void tms9995_device::mem_write() case 1: // Set address // If this is a word access, 4 passes, else 2 passes - m_dbin_line(CLEAR_LINE); + if (!m_dbin_line.isnull()) m_dbin_line(CLEAR_LINE); if (m_word_access || !m_instruction->byteop) { @@ -1859,9 +1922,9 @@ void tms9995_device::mem_write() else m_pass = 2; m_check_hold = false; - if (VERBOSE>6) LOG("tms9995: set address bus %04x\n", address); + if (TRACE_ADDRESSBUS) logerror("tms9995: set address bus %04x\n", address); m_prgspace->set_address(address); - if (VERBOSE>6) LOG("tms9995: memory write byte %04x <- %02x\n", address, (m_current_value >> 8)&0xff); + if (TRACE_MEM) logerror("tms9995: memory write byte %04x <- %02x\n", address, (m_current_value >> 8)&0xff); m_prgspace->write_byte(address, (m_current_value >> 8)&0xff); pulse_clock(1); break; @@ -1871,9 +1934,9 @@ void tms9995_device::mem_write() break; case 3: // Set address + 1 (unless byte command) - if (VERBOSE>6) LOG("tms9995: set address bus %04x\n", m_address | 1); + if (TRACE_ADDRESSBUS) logerror("tms9995: set address bus %04x\n", m_address | 1); m_prgspace->set_address(m_address | 1); - if (VERBOSE>6) LOG("tms9995: memory write byte %04x <- %02x\n", m_address | 1, m_current_value & 0xff); + if (TRACE_MEM) logerror("tms9995: memory write byte %04x <- %02x\n", m_address | 1, m_current_value & 0xff); m_prgspace->write_byte(m_address | 1, m_current_value & 0xff); pulse_clock(1); break; @@ -1910,7 +1973,7 @@ void tms9995_device::return_with_address() m_instruction->program = m_caller; MPC = m_caller_MPC; // will be increased on return m_address = m_current_value + m_address_add; - if (VERBOSE>7) LOG("tms9995: +++ return from operand address derivation +++\n"); + if (TRACE_DETAIL) logerror("tms9995: +++ return from operand address derivation +++\n"); // no clock pulse } @@ -1924,7 +1987,7 @@ void tms9995_device::return_with_address_copy() m_instruction->program = m_caller; MPC = m_caller_MPC; // will be increased on return m_address = m_address_saved; - if (VERBOSE>7) LOG("tms9995: +++ return from operand address derivation (auto inc) +++\n"); + if (TRACE_DETAIL) logerror("tms9995: +++ return from operand address derivation (auto inc) +++\n"); // no clock pulse } @@ -1965,7 +2028,7 @@ void tms9995_device::return_with_address_copy() void tms9995_device::cru_output_operation() { - if (VERBOSE>5) LOG("tms9995: CRU output operation, address %04x, value %d\n", m_cru_address, m_cru_value & 0x01); + if (TRACE_CRU) logerror("tms9995: CRU output operation, address %04x, value %d\n", m_cru_address, m_cru_value & 0x01); if (m_cru_address == 0x1fda) { @@ -1980,7 +2043,7 @@ void tms9995_device::cru_output_operation() { m_check_ready = false; // FLAG2, FLAG3, and FLAG4 are read-only - if (VERBOSE>2) LOG("tms9995: set CRU address %04x to %d\n", m_cru_address, m_cru_value&1); + if (TRACE_CRU) logerror("tms9995: set CRU address %04x to %d\n", m_cru_address, m_cru_value&1); if ((m_cru_address != 0x1ee4) && (m_cru_address != 0x1ee6) && (m_cru_address != 0x1ee8)) m_flag[(m_cru_address>>1)&0x000f] = (m_cru_value & 0x01); } @@ -2037,7 +2100,7 @@ void tms9995_device::cru_input_operation() // ........ ........ X....... ........ // crubyte = m_cru->read_byte((m_cru_address >> 4)& CRUREADMASK); - if (VERBOSE>8) LOG("tms9995: Need to get next 8 bits (addresses %04x-%04x): %02x\n", (m_cru_address&0xfff0)+14, m_cru_address&0xfff0, crubyte); + if (TRACE_DETAIL) logerror("tms9995: Need to get next 8 bits (addresses %04x-%04x): %02x\n", (m_cru_address&0xfff0)+14, m_cru_address&0xfff0, crubyte); m_cru_read = crubyte << 15; m_cru_bits_left = 8; @@ -2050,7 +2113,7 @@ void tms9995_device::cru_input_operation() m_cru_first_read = false; m_pass = m_count; } - if (VERBOSE>8) LOG("tms9995: adjusted value for shift: %06x\n", m_cru_read); + if (TRACE_DETAIL) logerror("tms9995: adjusted value for shift: %06x\n", m_cru_read); } crubit = (m_cru_read & 0x8000); @@ -2076,7 +2139,7 @@ void tms9995_device::cru_input_operation() } } - if (VERBOSE>5) LOG("tms9995: CRU input operation, address %04x, value %d\n", m_cru_address, (crubit & 0x8000)>>15); + if (TRACE_CRU) logerror("tms9995: CRU input operation, address %04x, value %d\n", m_cru_address, (crubit & 0x8000)>>15); m_cru_value |= crubit; if (crubit!=0) m_parity++; @@ -2107,11 +2170,11 @@ void tms9995_device::trigger_decrementer() m_decrementer_value--; if (m_decrementer_value==0) { - if (VERBOSE>4) LOG("tms9995: decrementer reached 0\n"); + if (TRACE_DEC) logerror("tms9995: decrementer reached 0\n"); m_decrementer_value = m_starting_count_storage_register; if (m_flag[1]==true) { - if (VERBOSE>4) LOG("tms9995: decrementer flags interrupt\n"); + if (TRACE_DEC) logerror("tms9995: decrementer flags interrupt\n"); m_flag[3] = true; m_int_decrementer = true; } @@ -2160,12 +2223,12 @@ void tms9995_device::operand_address_subprogram() { if (m_regnumber != 0) { - if (VERBOSE>8) LOG("tms9995: indexed addressing\n"); + if (TRACE_DETAIL) logerror("tms9995: indexed addressing\n"); MPC = 16; // indexed } else { - if (VERBOSE>8) LOG("tms9995: symbolic addressing\n"); + if (TRACE_DETAIL) logerror("tms9995: symbolic addressing\n"); m_address = PC; PC = (PC + 2) & 0xfffe; } @@ -2175,7 +2238,7 @@ void tms9995_device::operand_address_subprogram() m_mem_phase = 1; m_address_add = 0; MPC--; // will be increased in the mail loop - if (VERBOSE>8) LOG("tms9995: *** Operand address derivation; address=%04x; index=%d\n", m_address, MPC+1); + if (TRACE_DETAIL) logerror("tms9995: *** Operand address derivation; address=%04x; index=%d\n", m_address, MPC+1); } /* @@ -2317,7 +2380,7 @@ void tms9995_device::alu_add_s_sxc() { set_status_parity((UINT8)(dest_new>>8)); } - if (VERBOSE>7) LOG("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); + if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); // No clock pulse (will be done by prefetch) } @@ -2364,7 +2427,7 @@ void tms9995_device::alu_blwp() case 4: PC = m_current_value & 0xfffe; n = 0; - if (VERBOSE>5) LOG("tms9995: Context switch complete; WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST); + if (TRACE_OP) logerror("tms9995: Context switch complete; WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST); break; } m_instruction->state++; @@ -2385,7 +2448,7 @@ void tms9995_device::alu_c() set_status_parity((UINT8)(m_source_value>>8)); } compare_and_set_lae(m_source_value, m_current_value); - if (VERBOSE>7) LOG("tms9995: ST = %04x (val1=%04x, val2=%04x)\n", ST, m_source_value, m_current_value); + if (TRACE_STATUS) logerror("tms9995: ST = %04x (val1=%04x, val2=%04x)\n", ST, m_source_value, m_current_value); } /* @@ -2396,12 +2459,12 @@ void tms9995_device::alu_ci() // We have the register value in m_source_value, the register address in m_address_saved // and the immediate value in m_current_value compare_and_set_lae(m_source_value, m_current_value); - if (VERBOSE>7) LOG("tms9995: ST = %04x (val1=%04x, val2=%04x)\n", ST, m_source_value, m_current_value); + if (TRACE_STATUS) logerror("tms9995: ST = %04x (val1=%04x, val2=%04x)\n", ST, m_source_value, m_current_value); } void tms9995_device::alu_clr_seto() { - if (VERBOSE>7) LOG("tms9995: clr/seto: Setting values for address %04x\n", m_address); + if (TRACE_OP) logerror("tms9995: clr/seto: Setting values for address %04x\n", m_address); switch (m_instruction->command) { case CLR: @@ -2610,17 +2673,17 @@ void tms9995_device::alu_external() if (m_instruction->command == IDLE) { - if (VERBOSE>4) LOG("tms9995: Entering IDLE state\n"); + if (TRACE_OP) logerror("tms9995: Entering IDLE state\n"); m_idle_state = true; } if (m_instruction->command == RSET) { ST &= 0xfff0; - if (VERBOSE>3) LOG("tms9995: New ST = %04x\n", ST); + if (TRACE_OP) logerror("tms9995: RSET, new ST = %04x\n", ST); } - m_external_operation((m_instruction->IR >> 5) & 0x07, 1); + if (!m_external_operation.isnull()) m_external_operation((m_instruction->IR >> 5) & 0x07, 1, 0xff); } /* @@ -2658,7 +2721,7 @@ void tms9995_device::alu_f3() compare_and_set_lae(m_current_value, 0); } } - if (VERBOSE>7) LOG("tms9995: ST = %04x\n", ST); + if (TRACE_STATUS) logerror("tms9995: ST = %04x\n", ST); break; } m_instruction->state++; @@ -2694,7 +2757,7 @@ void tms9995_device::alu_imm_arithm() m_current_value = (UINT16)(dest_new & 0xffff); compare_and_set_lae(m_current_value, 0); m_address = m_address_saved; - if (VERBOSE>7) LOG("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); + if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); } /* @@ -2750,11 +2813,11 @@ void tms9995_device::alu_jump() if (!cond) { - if (VERBOSE>7) LOG("tms9995: Jump condition false\n"); + if (TRACE_OP) logerror("tms9995: Jump condition false\n"); } else { - if (VERBOSE>7) LOG("tms9995: Jump condition true\n"); + if (TRACE_OP) logerror("tms9995: Jump condition true\n"); PC = (PC + (displacement<<1)) & 0xfffe; } } @@ -2774,7 +2837,7 @@ void tms9995_device::alu_ldcr() case 1: // We have read the byte or word into m_current_value. compare_and_set_lae(m_current_value, 0); - if (VERBOSE>7) LOG("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); + if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); if (m_instruction->byteop) { m_current_value = (m_current_value>>8) & 0xff; @@ -2803,7 +2866,7 @@ void tms9995_device::alu_li() // The immediate value is still in m_current_value m_address = m_address_saved; compare_and_set_lae(m_current_value, 0); - if (VERBOSE>7) LOG("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); + if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); } void tms9995_device::alu_limi_lwpi() @@ -2812,13 +2875,13 @@ void tms9995_device::alu_limi_lwpi() if (m_instruction->command == LIMI) { ST = (ST & 0xfff0) | (m_current_value & 0x000f); - if (VERBOSE>4) LOG("tms9995: LIMI sets ST = %04x\n", ST); + if (TRACE_OP) logerror("tms9995: LIMI sets ST = %04x\n", ST); pulse_clock(1); // needs one more than LWPI } else { WP = m_current_value & 0xfffe; - if (VERBOSE>4) LOG("tms9995: LWPI sets new WP = %04x\n", WP); + if (TRACE_OP) logerror("tms9995: LWPI sets new WP = %04x\n", WP); } } @@ -2831,13 +2894,13 @@ void tms9995_device::alu_lst_lwp() if (m_instruction->command==LST) { ST = m_current_value; - if (VERBOSE>7) LOG("tms9995: new ST = %04x\n", ST); + if (TRACE_OP) logerror("tms9995: new ST = %04x\n", ST); pulse_clock(1); } else { WP = m_current_value & 0xfffe; - if (VERBOSE>7) LOG("tms9995: new WP = %04x\n", WP); + if (TRACE_OP) logerror("tms9995: new WP = %04x\n", WP); } } @@ -2855,7 +2918,7 @@ void tms9995_device::alu_mov() set_status_parity((UINT8)(m_current_value>>8)); } compare_and_set_lae(m_current_value, 0); - if (VERBOSE>7) LOG("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); + if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); // No clock pulse, as next instruction is prefetch } @@ -2948,7 +3011,7 @@ void tms9995_device::alu_rtwp() // Just for debugging purposes m_servicing_interrupt = false; - if (VERBOSE>4) LOG("tms9995: RTWP restored old context (WP=%04x, PC=%04x, ST=%04x)\n", WP, PC, ST); + if (TRACE_OP) logerror("tms9995: RTWP restored old context (WP=%04x, PC=%04x, ST=%04x)\n", WP, PC, ST); break; } m_instruction->state++; @@ -3001,7 +3064,7 @@ void tms9995_device::alu_shift() } else { - if (VERBOSE>8) LOG("tms9995: Shift operation gets count from R0\n"); + if (TRACE_DETAIL) logerror("tms9995: Shift operation gets count from R0\n"); } pulse_clock(1); pulse_clock(1); @@ -3046,7 +3109,7 @@ void tms9995_device::alu_shift() set_status_bit(ST_OV, overflow); compare_and_set_lae(m_current_value, 0); m_address = m_address_saved; // Register address - if (VERBOSE>7) LOG("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); + if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); break; } m_instruction->state++; @@ -3142,7 +3205,7 @@ void tms9995_device::alu_single_arithm() m_current_value = dest_new & 0xffff; compare_and_set_lae(m_current_value, 0); - if (VERBOSE>7) LOG("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); + if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); // No clock pulse, as next instruction is prefetch } @@ -3180,7 +3243,7 @@ void tms9995_device::alu_stcr() m_current_value <<= 8; } else n += 8; - if (VERBOSE>7) LOG("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); + if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); break; } m_instruction->state++; @@ -3220,7 +3283,7 @@ void tms9995_device::alu_tb() break; case 2: set_status_bit(ST_EQ, m_cru_value!=0); - if (VERBOSE>7) LOG("tms9995: ST = %04x\n", ST); + if (TRACE_STATUS) logerror("tms9995: ST = %04x\n", ST); break; } m_instruction->state++; @@ -3303,7 +3366,7 @@ void tms9995_device::alu_int() case 0: PC = (PC - 2) & 0xfffe; m_address_saved = m_address; - if (VERBOSE>7) LOG("tms9995: interrupt service (0): Prepare to read vector\n"); + if (TRACE_INTD) logerror("tms9995: interrupt service (0): Prepare to read vector\n"); break; case 1: pulse = 2; // two cycles (with the one at the end) @@ -3311,30 +3374,30 @@ void tms9995_device::alu_int() WP = m_current_value & 0xfffe; // new WP m_current_value = ST; m_address = (WP + 30)&0xfffe; - if (VERBOSE>7) LOG("tms9995: interrupt service (1): Read new WP = %04x, save ST to %04x\n", WP, m_address); + if (TRACE_INTD) logerror("tms9995: interrupt service (1): Read new WP = %04x, save ST to %04x\n", WP, m_address); break; case 2: m_address = (WP + 28)&0xfffe; m_current_value = PC; - if (VERBOSE>7) LOG("tms9995: interrupt service (2): Save PC to %04x\n", m_address); + if (TRACE_INTD) logerror("tms9995: interrupt service (2): Save PC to %04x\n", m_address); break; case 3: m_address = (WP + 26)&0xfffe; m_current_value = m_source_value; // old WP - if (VERBOSE>7) LOG("tms9995: interrupt service (3): Save WP to %04x\n", m_address); + if (TRACE_INTD) logerror("tms9995: interrupt service (3): Save WP to %04x\n", m_address); break; case 4: m_address = (m_address_saved + 2) & 0xfffe; - if (VERBOSE>7) LOG("tms9995: interrupt service (4): Read PC from %04x\n", m_address); + if (TRACE_INTD) logerror("tms9995: interrupt service (4): Read PC from %04x\n", m_address); break; case 5: PC = m_current_value & 0xfffe; ST = (ST & 0xfe00) | m_intmask; - if (VERBOSE>5) LOG("tms9995: interrupt service (5): Context switch complete; WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST); + if (TRACE_INTD) logerror("tms9995: interrupt service (5): Context switch complete; WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST); if (((m_int_pending & PENDING_MID)!=0) && m_nmi_active) { - if (VERBOSE>5) LOG("tms9995: interrupt service (6): NMI active after context switch\n"); + if (TRACE_INTD) logerror("tms9995: interrupt service (6): NMI active after context switch\n"); m_int_pending &= ~PENDING_MID; m_address = 0xfffc; m_intmask = 0; @@ -3344,7 +3407,7 @@ void tms9995_device::alu_int() { if (m_from_reset) { - if (VERBOSE>5) LOG("tms9995: interrupt service (6): RESET completed\n"); + if (TRACE_INTD) logerror("tms9995: interrupt service (6): RESET completed\n"); // We came from the RESET interrupt m_from_reset = false; ST &= 0x01ff; @@ -3398,3 +3461,4 @@ offs_t tms9995_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 * const device_type TMS9995 = &device_creator; +const device_type TMS9995_MP9537 = &device_creator; diff --git a/src/emu/cpu/tms9900/tms9995.h b/src/emu/cpu/tms9900/tms9995.h index bfb26cfb619..7517934b588 100644 --- a/src/emu/cpu/tms9900/tms9995.h +++ b/src/emu/cpu/tms9900/tms9995.h @@ -4,7 +4,7 @@ tms9995.h See tms9995.c for documentation - Also see tms9900.h for types of TMS9xxx processors. + Also see tms9900.h for types of TMS99xx processors. */ #ifndef __TMS9995_H__ @@ -14,6 +14,10 @@ #include "debugger.h" #include "tms99com.h" +// device type definition +extern const device_type TMS9995; +extern const device_type TMS9995_MP9537; + enum { INT_9995_RESET = 0, @@ -22,36 +26,30 @@ enum INT_9995_INT4 = 3 }; -/* - Configuration for the TMS9995. The connections are provided by the - main board which contains the processor. -*/ -struct tms9995_config -{ - devcb_write8 external_callback; - devcb_write_line iaq_line; - devcb_write_line clock_out; - devcb_write_line holda_line; - devcb_write_line dbin_line; - int mode; - int overflow; -}; +#define MCFG_TMS9995_EXTOP_HANDLER( _extop) \ + devcb = &tms9995_device::static_set_extop_callback( *device, DEVCB2_##_extop ); -#define TMS9995_CONFIG(name) \ - const tms9995_config(name) = +#define MCFG_TMS9995_IAQ_HANDLER( _iaq ) \ + devcb = &tms9995_device::static_set_iaq_callback( *device, DEVCB2_##_iaq ); + +#define MCFG_TMS9995_CLKOUT_HANDLER( _clkout ) \ + devcb = &tms9995_device::static_set_clkout_callback( *device, DEVCB2_##_clkout ); + +#define MCFG_TMS9995_HOLDA_HANDLER( _holda ) \ + devcb = &tms9995_device::static_set_holda_callback( *device, DEVCB2_##_holda ); + +#define MCFG_TMS9995_DBIN_HANDLER( _dbin ) \ + devcb = &tms9995_device::static_set_dbin_callback( *device, DEVCB2_##_dbin ); + +#define MCFG_TMS9995_ENABLE_OVINT( _ovint ) \ + downcast(device)->set_overflow_interrupt( _ovint ); -enum -{ - NO_INTERNAL_RAM = 0, - INTERNAL_RAM, - NO_OVERFLOW_INT = 0, - OVERFLOW_INT -}; class tms9995_device : public cpu_device { public: tms9995_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + tms9995_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); // READY input line. When asserted (high), the memory is ready for data exchange. // We chose to use a direct method instead of a delegate to keep performance @@ -63,10 +61,19 @@ public: // is acknowledged by the HOLDA output line. void set_hold(int state); + // Callbacks + template static devcb2_base &static_set_extop_callback(device_t &device, _Object object) { return downcast(device).m_external_operation.set_callback(object); } + template static devcb2_base &static_set_iaq_callback(device_t &device, _Object object) { return downcast(device).m_iaq_line.set_callback(object); } + template static devcb2_base &static_set_clkout_callback(device_t &device, _Object object) { return downcast(device).m_clock_out_line.set_callback(object); } + template static devcb2_base &static_set_holda_callback(device_t &device, _Object object) { return downcast(device).m_holda_line.set_callback(object); } + template static devcb2_base &static_set_dbin_callback(device_t &device, _Object object) { return downcast(device).m_dbin_line.set_callback(object); } + // For debugger access UINT8 debug_read_onchip_memory(offs_t addr) { return m_onchip_memory[addr & 0xff]; }; bool is_onchip(offs_t addrb) { return (((addrb & 0xff00)==0xf000 && (addrb < 0xf0fc)) || ((addrb & 0xfffc)==0xfffc)) && !m_mp9537; } + void set_overflow_interrupt( int enable ) { m_check_overflow = (enable!=0); } + protected: // device-level overrides virtual void device_start(); @@ -90,6 +97,9 @@ protected: UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return clocks / 4.0; } UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return cycles * 4.0; } + // Variant of the TMS9995 without internal RAM and decrementer + bool m_mp9537; + private: // State / debug management UINT16 m_state_any; @@ -117,8 +127,6 @@ private: address_space* m_prgspace; address_space* m_cru; - // Variant of the TMS9995 without internal RAM and decrementer - bool m_mp9537; // Processor states bool m_idle_state; @@ -403,25 +411,36 @@ private: // We could realize this via the CRU access as well, but the data bus access // is not that simple to emulate. For the sake of homogenity between the // chip emulations we use a dedicated callback. - devcb_resolved_write8 m_external_operation; + devcb2_write8 m_external_operation; // Signal to the outside world that we are now getting an instruction (IAQ). // In the real hardware this line is shared with the HOLDA line, and the // /MEMEN line is used to decide which signal we have on the line. We do not // emulate the /MEMEN line, so we have to use two separate lines. - devcb_resolved_write_line m_iaq_line; + devcb2_write_line m_iaq_line; // Clock output. - devcb_resolved_write_line m_clock_out_line; + devcb2_write_line m_clock_out_line; // Asserted when the CPU is in a HOLD state - devcb_resolved_write_line m_holda_line; + devcb2_write_line m_holda_line; // DBIN line. When asserted (high), the CPU has disabled the data bus output buffers. - devcb_resolved_write_line m_dbin_line; + devcb2_write_line m_dbin_line; }; -// device type definition -extern const device_type TMS9995; + +/* + Variant of the TMS9995 without on-chip RAM; used in the TI-99/8 console +*/ +class tms9995_mp9537_device : public tms9995_device +{ +public: + tms9995_mp9537_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms9995_device(mconfig, TMS9995_MP9537, "TMS9995-MP9537", tag, owner, clock, "tms9995_mp9537", __FILE__) + { + m_mp9537 = true; + } +}; #endif /* __TMS9995_H__ */ diff --git a/src/emu/cpu/tms9900/tms99com.h b/src/emu/cpu/tms9900/tms99com.h index 928413a98ee..2d300936b25 100644 --- a/src/emu/cpu/tms9900/tms99com.h +++ b/src/emu/cpu/tms9900/tms99com.h @@ -41,11 +41,31 @@ #ifndef __TMS99COMMON_H__ #define __TMS99COMMON_H__ -#define MCFG_TMS99xx_ADD(_tag, _device, _clock, _prgmap, _iomap, _config) \ +#define MCFG_TMS99xx_ADD(_tag, _device, _clock, _prgmap, _iomap ) \ MCFG_DEVICE_ADD(_tag, _device, _clock) \ MCFG_DEVICE_PROGRAM_MAP(_prgmap) \ - MCFG_DEVICE_IO_MAP(_iomap) \ - MCFG_DEVICE_CONFIG(_config) + MCFG_DEVICE_IO_MAP(_iomap) + +#define MCFG_TMS99xx_EXTOP_HANDLER( _extop) \ + devcb = &tms99xx_device::static_set_extop_callback( *device, DEVCB2_##_extop ); + +#define MCFG_TMS99xx_INTLEVEL_HANDLER( _intlevel ) \ + devcb = &tms99xx_device::static_set_intlevel_callback( *device, DEVCB2_##_intlevel ); + +#define MCFG_TMS99xx_IAQ_HANDLER( _iaq ) \ + devcb = &tms99xx_device::static_set_iaq_callback( *device, DEVCB2_##_iaq ); + +#define MCFG_TMS99xx_CLKOUT_HANDLER( _clkout ) \ + devcb = &tms99xx_device::static_set_clkout_callback( *device, DEVCB2_##_clkout ); + +#define MCFG_TMS99xx_WAIT_HANDLER( _wait ) \ + devcb = &tms99xx_device::static_set_wait_callback( *device, DEVCB2_##_wait ); + +#define MCFG_TMS99xx_HOLDA_HANDLER( _holda ) \ + devcb = &tms99xx_device::static_set_holda_callback( *device, DEVCB2_##_holda ); + +#define MCFG_TMS99xx_DBIN_HANDLER( _dbin ) \ + devcb = &tms99xx_device::static_set_dbin_callback( *device, DEVCB2_##_dbin ); enum {