mirror of
https://github.com/holub/mame
synced 2025-04-23 00:39:36 +03:00
TMS99xx CPU family gone to devcb2. (nw)
This commit is contained in:
parent
a554cc79ed
commit
d1251c70f0
@ -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:
|
||||
|
@ -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<<prg_addr_bits)-1),
|
||||
m_cruaddr_mask((1<<cru_addr_bits)-1)
|
||||
m_cruaddr_mask((1<<cru_addr_bits)-1),
|
||||
m_clock_out_line(*this),
|
||||
m_wait_line(*this),
|
||||
m_holda_line(*this),
|
||||
m_iaq_line(*this),
|
||||
m_get_intlevel(*this),
|
||||
m_dbin_line(*this),
|
||||
m_external_operation(*this)
|
||||
{
|
||||
}
|
||||
|
||||
@ -238,17 +248,14 @@ void tms99xx_device::device_stop()
|
||||
*/
|
||||
void tms99xx_device::resolve_lines()
|
||||
{
|
||||
const tms99xx_config *conf = reinterpret_cast<const tms99xx_config *>(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);
|
||||
}
|
||||
|
||||
|
@ -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<class _Object> static devcb2_base &static_set_extop_callback(device_t &device, _Object object) { return downcast<tms99xx_device &>(device).m_external_operation.set_callback(object); }
|
||||
template<class _Object> static devcb2_base &static_set_intlevel_callback(device_t &device, _Object object) { return downcast<tms99xx_device &>(device).m_get_intlevel.set_callback(object); }
|
||||
template<class _Object> static devcb2_base &static_set_iaq_callback(device_t &device, _Object object) { return downcast<tms99xx_device &>(device).m_iaq_line.set_callback(object); }
|
||||
template<class _Object> static devcb2_base &static_set_clkout_callback(device_t &device, _Object object) { return downcast<tms99xx_device &>(device).m_clock_out_line.set_callback(object); }
|
||||
template<class _Object> static devcb2_base &static_set_wait_callback(device_t &device, _Object object) { return downcast<tms99xx_device &>(device).m_wait_line.set_callback(object); }
|
||||
template<class _Object> static devcb2_base &static_set_holda_callback(device_t &device, _Object object) { return downcast<tms99xx_device &>(device).m_holda_line.set_callback(object); }
|
||||
template<class _Object> static devcb2_base &static_set_dbin_callback(device_t &device, _Object object) { return downcast<tms99xx_device &>(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:
|
||||
|
@ -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<const tms9980a_config *>(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;
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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<const tms9995_config *>(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<tms9995_device>;
|
||||
const device_type TMS9995_MP9537 = &device_creator<tms9995_mp9537_device>;
|
||||
|
@ -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<tms9995_device*>(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<class _Object> static devcb2_base &static_set_extop_callback(device_t &device, _Object object) { return downcast<tms9995_device &>(device).m_external_operation.set_callback(object); }
|
||||
template<class _Object> static devcb2_base &static_set_iaq_callback(device_t &device, _Object object) { return downcast<tms9995_device &>(device).m_iaq_line.set_callback(object); }
|
||||
template<class _Object> static devcb2_base &static_set_clkout_callback(device_t &device, _Object object) { return downcast<tms9995_device &>(device).m_clock_out_line.set_callback(object); }
|
||||
template<class _Object> static devcb2_base &static_set_holda_callback(device_t &device, _Object object) { return downcast<tms9995_device &>(device).m_holda_line.set_callback(object); }
|
||||
template<class _Object> static devcb2_base &static_set_dbin_callback(device_t &device, _Object object) { return downcast<tms9995_device &>(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__ */
|
||||
|
@ -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
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user