mirror of
https://github.com/holub/mame
synced 2025-04-27 10:43:07 +03:00
CPUs now utilizing split addressing (setaddress ... read/write)
This commit is contained in:
parent
32a57a15b4
commit
6c863c2d56
@ -177,6 +177,7 @@ void tms99xx_device::device_start()
|
||||
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
|
||||
|
||||
// set our instruction counter
|
||||
m_icountptr = &m_icount;
|
||||
@ -202,7 +203,7 @@ void tms99xx_device::device_start()
|
||||
void tms99xx_device::device_stop()
|
||||
{
|
||||
int k = 0;
|
||||
if (VERBOSE>8) LOG("tms99xx: Deleting lookup tables\n");
|
||||
if (VERBOSE>3) LOG("tms99xx: Deleting lookup tables\n");
|
||||
while (m_lotables[k]!=NULL) delete[] m_lotables[k++];
|
||||
}
|
||||
|
||||
@ -1122,18 +1123,18 @@ void tms99xx_device::execute_run()
|
||||
m_program[MPC] != MEMORY_READ && m_program[MPC] != MEMORY_WRITE &&
|
||||
m_program[MPC] != REG_READ && m_program[MPC] != REG_WRITE)))
|
||||
{
|
||||
if (VERBOSE>5) LOG("tms99xx: hold state\n");
|
||||
if (VERBOSE>2) LOG("tms99xx: hold state\n");
|
||||
if (!m_hold_acknowledged) acknowledge_hold();
|
||||
pulse_clock(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal operation
|
||||
if (m_check_ready && m_ready_state == false)
|
||||
if (m_check_ready && m_ready == false)
|
||||
{
|
||||
// We are in a wait state
|
||||
set_wait_state(true);
|
||||
if (VERBOSE>5) LOG("tms99xx: wait state\n");
|
||||
if (VERBOSE>2) LOG("tms99xx: 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);
|
||||
@ -1157,6 +1158,7 @@ void tms99xx_device::execute_run()
|
||||
{
|
||||
m_pass = 1;
|
||||
MPC++;
|
||||
m_mem_phase = 1;
|
||||
m_iaq_line(CLEAR_LINE);
|
||||
}
|
||||
}
|
||||
@ -1214,10 +1216,11 @@ void tms99xx_device::service_interrupt()
|
||||
m_command = INTR;
|
||||
m_idle_state = false;
|
||||
m_external_operation(IDLE_OP, 0);
|
||||
m_lowbyte = false;
|
||||
|
||||
m_state = 0;
|
||||
|
||||
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
|
||||
// leave it where it is. So we pretend we have another pass to do.
|
||||
@ -1227,13 +1230,15 @@ void tms99xx_device::service_interrupt()
|
||||
{
|
||||
m_irq_level = RESET_INT;
|
||||
|
||||
m_ready_state = true;
|
||||
m_ready_bufd = true;
|
||||
m_ready = true;
|
||||
m_load_state = false;
|
||||
m_hold_state = false;
|
||||
m_hold_acknowledged = false;
|
||||
m_wait_state = false;
|
||||
IR = 0;
|
||||
ST = 0;
|
||||
m_mem_phase = 1;
|
||||
|
||||
m_reset = false;
|
||||
}
|
||||
@ -1251,9 +1256,14 @@ void tms99xx_device::pulse_clock(int count)
|
||||
for (int i=0; i < count; i++)
|
||||
{
|
||||
m_clock_out_line(ASSERT_LINE);
|
||||
m_ready = m_ready_bufd; // get the latched READY state
|
||||
m_clock_out_line(CLEAR_LINE);
|
||||
m_icount--; // This is the only location where we count down the cycles.
|
||||
if (VERBOSE>7) LOG("tms99xx: pulse_clock\n");
|
||||
if (VERBOSE>7)
|
||||
{
|
||||
if (m_check_ready) LOG("tms99xx: pulse_clock, READY=%d\n", m_ready? 1:0);
|
||||
else LOG("tms99xx: pulse_clock\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1280,11 +1290,12 @@ inline void tms99xx_device::acknowledge_hold()
|
||||
}
|
||||
|
||||
/*
|
||||
Signal READY to the CPU. When cleared, the CPU enters wait states.
|
||||
Signal READY to the CPU. When cleared, the CPU enters wait states. This
|
||||
becomes effective on a clock pulse.
|
||||
*/
|
||||
void tms99xx_device::set_ready(int state)
|
||||
{
|
||||
m_ready_state = (state==ASSERT_LINE);
|
||||
m_ready_bufd = (state==ASSERT_LINE);
|
||||
}
|
||||
|
||||
void tms99xx_device::abort_operation()
|
||||
@ -1344,7 +1355,7 @@ void tms99xx_device::decode(UINT16 inst)
|
||||
m_program = decoded->prog;
|
||||
MPC = -1;
|
||||
m_command = decoded->id;
|
||||
if (VERBOSE>7) LOG("tms99xx: Command decoded as id %d, %s, base opcode %04x\n", m_command, opname[m_command], decoded->opcode);
|
||||
if (VERBOSE>8) LOG("tms99xx: Command decoded as id %d, %s, base opcode %04x\n", m_command, opname[m_command], decoded->opcode);
|
||||
// Byte operations are either format 1 with the byte flag set
|
||||
// or format 4 (CRU multi bit operations) with 1-8 bits to transfer.
|
||||
m_byteop = ((decoded->format==1 && ((IR & 0x1000)!=0))
|
||||
@ -1360,77 +1371,107 @@ inline bool tms99xx_device::byte_operation()
|
||||
|
||||
void tms99xx_device::acquire_instruction()
|
||||
{
|
||||
m_iaq_line(ASSERT_LINE);
|
||||
m_address = PC;
|
||||
m_first_cycle = m_icount;
|
||||
if (m_mem_phase == 1)
|
||||
{
|
||||
m_iaq_line(ASSERT_LINE);
|
||||
m_address = PC;
|
||||
m_first_cycle = m_icount;
|
||||
}
|
||||
|
||||
mem_read();
|
||||
decode(m_current_value);
|
||||
if (VERBOSE>3) LOG("tms99xx: ===== Next operation %04x (%s) at %04x =====\n", IR, opname[m_command], PC);
|
||||
debugger_instruction_hook(this, PC);
|
||||
PC = (PC + 2) & 0xfffe & m_prgaddr_mask;
|
||||
// IAQ will be cleared in the main loop
|
||||
|
||||
if (m_mem_phase == 1)
|
||||
{
|
||||
decode(m_current_value);
|
||||
if (VERBOSE>3) LOG("tms99xx: ===== Next operation %04x (%s) at %04x =====\n", IR, opname[m_command], PC);
|
||||
debugger_instruction_hook(this, PC);
|
||||
PC = (PC + 2) & 0xfffe & m_prgaddr_mask;
|
||||
// IAQ will be cleared in the main loop
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Memory read:
|
||||
1) Pulse clock (done above)
|
||||
2) Set address (we also get the value right here)
|
||||
3) Pulse clock
|
||||
4) If READY=L (WAIT=H, GOTO 3) else (WAIT=L, STOP)
|
||||
|
||||
Memory read
|
||||
Clock cycles: 2 + W, W = number of wait states
|
||||
*/
|
||||
void tms99xx_device::mem_read()
|
||||
{
|
||||
// The following line will be taken out of this method and
|
||||
// be executed at an earlier microprogram clock tick
|
||||
// After set_address, any device attached to the address bus may pull down
|
||||
// READY in order to put the CPU into wait state before the read_word
|
||||
// operation will be performed
|
||||
// set_address and read_word should pass the same address as argument
|
||||
m_prgspace->set_address(m_address & m_prgaddr_mask & 0xfffe);
|
||||
if (m_mem_phase==1)
|
||||
{
|
||||
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 (VERBOSE>7) LOG("tms99xx: set address bus %04x\n", m_address);
|
||||
|
||||
m_current_value = m_prgspace->read_word(m_address & m_prgaddr_mask & 0xfffe);
|
||||
pulse_clock(2);
|
||||
m_check_ready = true;
|
||||
if (VERBOSE>7) LOG("tms99xx: memory read %04x -> %04x\n", m_address, m_current_value);
|
||||
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
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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);
|
||||
m_mem_phase = 1; // reset to phase 1
|
||||
if (VERBOSE>7) LOG("tms99xx: memory read %04x -> %04x\n", m_address, m_current_value);
|
||||
}
|
||||
}
|
||||
|
||||
void tms99xx_device::mem_write()
|
||||
{
|
||||
// see mem_read
|
||||
m_prgspace->set_address(m_address & m_prgaddr_mask & 0xfffe);
|
||||
|
||||
m_prgspace->write_word(m_address & m_prgaddr_mask & 0xfffe, m_current_value);
|
||||
pulse_clock(2);
|
||||
m_check_ready = true;
|
||||
if (VERBOSE>7) LOG("tms99xx: memory write %04x <- %04x\n", m_address, m_current_value);
|
||||
if (m_mem_phase==1)
|
||||
{
|
||||
m_dbin_line(CLEAR_LINE);
|
||||
// When writing, the data bus is asserted immediately after the address bus
|
||||
if (VERBOSE>7) LOG("tms99xx: set address bus %04x\n", m_address);
|
||||
m_prgspace->set_address(m_address & m_prgaddr_mask & 0xfffe);
|
||||
if (VERBOSE>7) LOG("tms99xx: memory write %04x <- %04x\n", m_address, m_current_value);
|
||||
m_prgspace->write_word(m_address & m_prgaddr_mask & 0xfffe, m_current_value);
|
||||
m_check_ready = true;
|
||||
m_mem_phase = 2;
|
||||
m_pass = 2;
|
||||
pulse_clock(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Second phase (we arrive here when the wait states are over)
|
||||
pulse_clock(1);
|
||||
}
|
||||
}
|
||||
|
||||
void tms99xx_device::register_read()
|
||||
{
|
||||
// Need to set m_address for F1/F3 (we don't know what the data_derive did)
|
||||
m_address = WP + (m_regnumber<<1);
|
||||
if (m_mem_phase==1)
|
||||
{
|
||||
m_address = WP + (m_regnumber<<1);
|
||||
}
|
||||
|
||||
mem_read();
|
||||
m_check_ready = true;
|
||||
m_register_contents = m_current_value;
|
||||
|
||||
if (m_mem_phase==1)
|
||||
{
|
||||
m_register_contents = m_current_value;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Memory write:
|
||||
1) Pulse clock
|
||||
2) Set address and write (as in the real system)
|
||||
3) Pulse clock
|
||||
4) If READY=L (WAIT=H, GOTO 3) else (WAIT=L, STOP)
|
||||
|
||||
Clock cycles: 2 + W, W = number of wait states
|
||||
*/
|
||||
void tms99xx_device::register_write()
|
||||
{
|
||||
// This will be called twice; m_pass is set by the embedded mem_write
|
||||
UINT16 addr_save = m_address;
|
||||
m_address = (WP + (m_regnumber<<1)) & m_prgaddr_mask & 0xfffe;
|
||||
mem_write();
|
||||
m_check_ready = true;
|
||||
m_address = addr_save;
|
||||
}
|
||||
|
||||
@ -1530,13 +1571,13 @@ void tms99xx_device::command_completed()
|
||||
// Pseudo state at the end of the current instruction cycle sequence
|
||||
if (VERBOSE>4)
|
||||
{
|
||||
LOG("tms99xx: +++++ Instruction %04x (%s) completed +++++\n", IR, opname[m_command]);
|
||||
LOG("tms99xx: +++++ Instruction %04x (%s) completed", IR, opname[m_command]);
|
||||
int cycles = m_first_cycle - m_icount;
|
||||
// Avoid nonsense values due to expired and resumed main loop
|
||||
if (cycles > 0 && cycles < 10000) LOG("tms99xx: Consumed %d cycles\n", cycles);
|
||||
if (cycles > 0 && cycles < 10000) LOG(", consumed %d cycles", cycles);
|
||||
LOG(" +++++\n");
|
||||
}
|
||||
m_program = NULL;
|
||||
m_lowbyte = false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -117,6 +117,7 @@ struct tms99xx_config
|
||||
devcb_write_line clock_out;
|
||||
devcb_write_line wait_line;
|
||||
devcb_write_line holda_line;
|
||||
devcb_write_line dbin_line;
|
||||
};
|
||||
|
||||
#define TMS99xx_CONFIG(name) \
|
||||
@ -208,12 +209,12 @@ protected:
|
||||
// Data bus width. Needed for TMS9980.
|
||||
int m_databus_width;
|
||||
|
||||
// Needed for TMS9980
|
||||
bool m_lowbyte;
|
||||
|
||||
// Check the READY line?
|
||||
bool m_check_ready;
|
||||
|
||||
// Phase of the memory access
|
||||
int m_mem_phase;
|
||||
|
||||
// Max address
|
||||
const UINT16 m_prgaddr_mask;
|
||||
const UINT16 m_cruaddr_mask;
|
||||
@ -238,13 +239,22 @@ protected:
|
||||
// Get the value of the interrupt level lines
|
||||
devcb_resolved_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;
|
||||
|
||||
private:
|
||||
// Indicates if this is a byte-oriented command
|
||||
inline bool byte_operation();
|
||||
|
||||
// Processor states
|
||||
bool m_idle_state;
|
||||
bool m_ready_state;
|
||||
|
||||
// READY handling. The READY line is operated before the phi1 clock
|
||||
// pulse rises. As the ready line is only set once in this emulation we
|
||||
// keep the level in a buffer (like a latch)
|
||||
bool m_ready_bufd; // buffered state
|
||||
bool m_ready; // sampled value
|
||||
|
||||
bool m_wait_state;
|
||||
bool m_hold_state;
|
||||
|
||||
|
@ -147,56 +147,79 @@ int tms9980a_device::get_intlevel(int state)
|
||||
void tms9980a_device::mem_read()
|
||||
{
|
||||
UINT8 value;
|
||||
if (m_lowbyte)
|
||||
switch (m_mem_phase)
|
||||
{
|
||||
case 1:
|
||||
m_pass = 4; // make the CPU visit this method more than once
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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 -> complete word %04x\n", (m_address & m_prgaddr_mask) | 1, m_current_value);
|
||||
m_lowbyte = false;
|
||||
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);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = m_prgspace->read_byte(m_address & 0x3ffe);
|
||||
if (VERBOSE>7) LOG("tms9980a: memory read high byte %04x -> %02x\n", m_address & m_prgaddr_mask, value);
|
||||
m_current_value = (value << 8) & 0xff00;
|
||||
m_lowbyte = true;
|
||||
m_pass = 2; // make the CPU visit this method once more
|
||||
}
|
||||
pulse_clock(2);
|
||||
m_check_ready = true;
|
||||
pulse_clock(1);
|
||||
m_mem_phase = (m_mem_phase % 4) +1;
|
||||
}
|
||||
|
||||
|
||||
void tms9980a_device::mem_write()
|
||||
{
|
||||
if (m_lowbyte)
|
||||
switch (m_mem_phase)
|
||||
{
|
||||
m_prgspace->write_byte((m_address & 0x3ffe) | 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);
|
||||
m_lowbyte = false;
|
||||
case 1:
|
||||
m_pass = 4; // make the CPU visit this method once more
|
||||
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);
|
||||
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);
|
||||
m_check_ready = true;
|
||||
break;
|
||||
case 2:
|
||||
// no action here, just wait for READY
|
||||
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);
|
||||
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);
|
||||
break;
|
||||
case 4:
|
||||
// no action here, just wait for READY
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_prgspace->write_byte(m_address & 0x3ffe, (m_current_value >> 8)&0xff);
|
||||
if (VERBOSE>7) LOG("tms9980a: memory write high byte %04x <- %02x\n", m_address & m_prgaddr_mask, (m_current_value >> 8)&0xff);
|
||||
m_lowbyte = true;
|
||||
m_pass = 2; // make the CPU visit this method once more
|
||||
}
|
||||
pulse_clock(2);
|
||||
m_check_ready = true;
|
||||
pulse_clock(1);
|
||||
m_mem_phase = (m_mem_phase % 4) +1;
|
||||
}
|
||||
|
||||
void tms9980a_device::acquire_instruction()
|
||||
{
|
||||
if (!m_lowbyte)
|
||||
if (m_mem_phase == 1)
|
||||
{
|
||||
m_iaq_line(ASSERT_LINE);
|
||||
m_address = PC;
|
||||
m_first_cycle = m_icount;
|
||||
mem_read();
|
||||
}
|
||||
else
|
||||
mem_read();
|
||||
|
||||
if (m_mem_phase == 1) // changed by mem_read and wrapped
|
||||
{
|
||||
mem_read();
|
||||
decode(m_current_value);
|
||||
if (VERBOSE>3) LOG("tms9980a: ===== Next operation %04x (%s) at %04x =====\n", IR, opname[m_command], PC);
|
||||
debugger_instruction_hook(this, PC);
|
||||
@ -205,6 +228,8 @@ void tms9980a_device::acquire_instruction()
|
||||
// IAQ will be cleared in the main loop
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
UINT32 tms9980a_device::execute_min_cycles() const
|
||||
{
|
||||
|
@ -158,8 +158,8 @@ void tms9995_device::device_start()
|
||||
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_wait_line.resolve(conf->wait_line, *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);
|
||||
@ -1086,10 +1086,9 @@ void tms9995_device::execute_run()
|
||||
do
|
||||
{
|
||||
// Normal operation
|
||||
if (m_check_ready && m_ready_state == false)
|
||||
if (m_check_ready && m_ready == false)
|
||||
{
|
||||
// We are in a wait state
|
||||
set_wait_state(true);
|
||||
if (VERBOSE>2) LOG("tms9995: wait state\n");
|
||||
// The clock output should be used to change the state of an outer
|
||||
// device which operates the READY line
|
||||
@ -1105,7 +1104,6 @@ void tms9995_device::execute_run()
|
||||
}
|
||||
else
|
||||
{
|
||||
set_wait_state(false);
|
||||
set_hold_state(false);
|
||||
|
||||
m_check_ready = false;
|
||||
@ -1189,9 +1187,15 @@ inline void tms9995_device::pulse_clock(int count)
|
||||
for (int i=0; i < count; i++)
|
||||
{
|
||||
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);
|
||||
m_icount--; // This is the only location where we count down the cycles.
|
||||
if (VERBOSE>7) LOG("tms9995: pulse_clock\n");
|
||||
if (VERBOSE>7)
|
||||
{
|
||||
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");
|
||||
}
|
||||
m_request_auto_wait_state = false;
|
||||
if (m_flag[0] == false && m_flag[1] == true) trigger_decrementer();
|
||||
}
|
||||
}
|
||||
@ -1210,12 +1214,13 @@ void tms9995_device::set_hold(int state)
|
||||
}
|
||||
|
||||
/*
|
||||
Signal READY to the CPU. When cleared, the CPU enters wait states.
|
||||
Signal READY to the CPU. When cleared, the CPU enters wait states. This
|
||||
becomes effective on a clock pulse.
|
||||
*/
|
||||
void tms9995_device::set_ready(int state)
|
||||
{
|
||||
if (VERBOSE>5) LOG("tms9995: set READY = %d\n", state);
|
||||
m_ready_state = (state==ASSERT_LINE);
|
||||
m_ready_bufd = (state==ASSERT_LINE);
|
||||
if (VERBOSE>7) LOG("tms9995: set READY = %d\n", m_ready_bufd? 1 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1227,16 +1232,7 @@ void tms9995_device::abort_operation()
|
||||
// And don't forget that prefetch is a 2-pass operation, so this method
|
||||
// will be called a second time. Only when the lowbyte has been fetched,
|
||||
// continue with the next step
|
||||
if (!m_lowbyte) command_completed();
|
||||
}
|
||||
|
||||
/*
|
||||
Enter or leave the wait state. We only operate the WAIT line when there is a change.
|
||||
*/
|
||||
inline void tms9995_device::set_wait_state(bool state)
|
||||
{
|
||||
if (m_wait_state != state) m_wait_line(state? ASSERT_LINE : CLEAR_LINE);
|
||||
m_wait_state = state;
|
||||
if (m_mem_phase==1) command_completed();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1307,56 +1303,55 @@ void tms9995_device::int_prefetch_and_decode()
|
||||
bool check_int = (m_instruction->command != XOP && m_instruction->command != BLWP);
|
||||
int intmask = ST & 0x000f;
|
||||
|
||||
if (m_lowbyte)
|
||||
if (m_mem_phase == 1)
|
||||
{
|
||||
prefetch_and_decode();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check interrupt lines
|
||||
if (m_nmi_active)
|
||||
{
|
||||
if (VERBOSE>7) LOG("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
|
||||
}
|
||||
else
|
||||
{
|
||||
m_int_pending = 0;
|
||||
|
||||
if (m_int1_active && intmask >= 1 && check_int) m_int_pending |= PENDING_LEVEL1;
|
||||
if (m_int_overflow && intmask >= 2 && check_int) m_int_pending |= PENDING_OVERFLOW;
|
||||
if (m_int_decrementer && intmask >= 3 && check_int) m_int_pending |= PENDING_DECR;
|
||||
if (m_int4_active && intmask >= 4 && check_int) m_int_pending |= PENDING_LEVEL4;
|
||||
|
||||
if (m_int_pending!=0)
|
||||
// Check interrupt lines
|
||||
if (m_nmi_active)
|
||||
{
|
||||
if (m_idle_state)
|
||||
{
|
||||
m_idle_state = false;
|
||||
if (VERBOSE>7) LOG("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 (VERBOSE>7) LOG("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
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (VERBOSE>7) LOG("tms9995: Checking interrupts ... none pending\n");
|
||||
// No pending interrupts
|
||||
if (check_idle && m_idle_state)
|
||||
m_int_pending = 0;
|
||||
|
||||
if (m_int1_active && intmask >= 1 && check_int) m_int_pending |= PENDING_LEVEL1;
|
||||
if (m_int_overflow && intmask >= 2 && check_int) m_int_pending |= PENDING_OVERFLOW;
|
||||
if (m_int_decrementer && intmask >= 3 && check_int) m_int_pending |= PENDING_DECR;
|
||||
if (m_int4_active && intmask >= 4 && check_int) m_int_pending |= PENDING_LEVEL4;
|
||||
|
||||
if (m_int_pending!=0)
|
||||
{
|
||||
if (VERBOSE>7) LOG("tms9995: IDLE state\n");
|
||||
// We are IDLE, stay in the loop and do not advance the PC
|
||||
m_pass = 2;
|
||||
pulse_clock(1);
|
||||
if (m_idle_state)
|
||||
{
|
||||
m_idle_state = false;
|
||||
if (VERBOSE>7) LOG("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);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
prefetch_and_decode();
|
||||
if (VERBOSE>7) LOG("tms9995: Checking interrupts ... none pending\n");
|
||||
// No pending interrupts
|
||||
if (check_idle && m_idle_state)
|
||||
{
|
||||
if (VERBOSE>7) LOG("tms9995: IDLE state\n");
|
||||
// We are IDLE, stay in the loop and do not advance the PC
|
||||
m_pass = 2;
|
||||
pulse_clock(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We reach this point in phase 1 if there is no interrupt and in all other phases
|
||||
prefetch_and_decode();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1367,46 +1362,28 @@ void tms9995_device::int_prefetch_and_decode()
|
||||
*/
|
||||
void tms9995_device::prefetch_and_decode()
|
||||
{
|
||||
if (m_lowbyte)
|
||||
{
|
||||
// Second pass for getting the instruction
|
||||
if (VERBOSE>6) LOG("tms9995: Prefetch memory access (second pass)\n");
|
||||
word_read();
|
||||
decode(m_current_value); // This is for free; in reality it is in parallel with the next memory operation
|
||||
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");
|
||||
m_lowbyte = false;
|
||||
}
|
||||
else
|
||||
if (m_mem_phase==1)
|
||||
{
|
||||
// Fetch next instruction
|
||||
// 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);
|
||||
|
||||
m_address = PC;
|
||||
|
||||
if (VERBOSE>5) LOG("tms9995: **** Prefetching new instruction at %04x ****\n", PC);
|
||||
}
|
||||
|
||||
m_lowbyte = false; // for mem_read
|
||||
word_read(); // this is where the clock pulses occur
|
||||
word_read();
|
||||
|
||||
if (!m_lowbyte)
|
||||
{
|
||||
// Only if we got the word in one pass
|
||||
decode(m_current_value); // This is for free; in reality it is in parallel with the next memory operation
|
||||
|
||||
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 (m_mem_phase==1)
|
||||
{
|
||||
// We're back in phase 1, i.e. the whole prefetch is done
|
||||
decode(m_current_value); // This is for free; in reality it is in parallel with the next memory operation
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1447,10 +1424,11 @@ void tms9995_device::command_completed()
|
||||
// Pseudo state at the end of the current instruction cycle sequence
|
||||
if (VERBOSE>4)
|
||||
{
|
||||
LOG("tms9995: +++++ Instruction %04x (%s) completed +++++\n", m_instruction->IR, opname[m_instruction->command]);
|
||||
LOG("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("tms9995: Consumed %d cycles\n", cycles);
|
||||
if (cycles > 0 && cycles < 10000) LOG(", consumed %d cycles", cycles);
|
||||
LOG(" +++++\n");
|
||||
}
|
||||
|
||||
if (m_int_pending != 0)
|
||||
@ -1484,8 +1462,7 @@ void tms9995_device::service_interrupt()
|
||||
|
||||
m_nmi_state = false;
|
||||
m_hold_state = false;
|
||||
m_wait_state = false;
|
||||
m_lowbyte = false;
|
||||
m_mem_phase = 1;
|
||||
m_check_hold = false;
|
||||
m_word_access = false;
|
||||
m_int4_active = false;
|
||||
@ -1500,9 +1477,10 @@ void tms9995_device::service_interrupt()
|
||||
|
||||
// The auto-wait state generation is turned on when the READY line is cleared
|
||||
// on RESET.
|
||||
m_auto_wait_state = !m_ready_state;
|
||||
if (VERBOSE>0) LOG("tms9995: RESET; automatic wait state creation is %s\n", m_auto_wait_state? "enabled":"disabled");
|
||||
m_ready_state = true;
|
||||
m_auto_wait = !m_ready_bufd;
|
||||
if (VERBOSE>0) LOG("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;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1574,6 +1552,7 @@ void tms9995_device::service_interrupt()
|
||||
m_instruction->byteop = false;
|
||||
m_instruction->command = INTR;
|
||||
m_pass = m_reset? 1 : 2;
|
||||
m_from_reset = m_reset;
|
||||
|
||||
if (m_reset)
|
||||
{
|
||||
@ -1604,7 +1583,7 @@ void tms9995_device::service_interrupt()
|
||||
void tms9995_device::mem_read()
|
||||
{
|
||||
// First determine whether the memory is inside the CPU
|
||||
// On-chip memory is F000 ... F0F9, F0FC-FFF9 = off-chip, FFFA/B = Decrementer
|
||||
// On-chip memory is F000 ... F0F9, F0FA-FFF9 = off-chip, FFFA/B = Decrementer
|
||||
// FFFC-FFFF = NMI vector (on-chip)
|
||||
// There is a variant of the TMS9995 with no on-chip RAM which was used
|
||||
// for the TI-99/8 (9537).
|
||||
@ -1641,42 +1620,55 @@ void tms9995_device::mem_read()
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a off-chip access
|
||||
// This is an off-chip access
|
||||
m_check_ready = true;
|
||||
if (m_lowbyte)
|
||||
UINT8 value;
|
||||
UINT16 address = m_address;
|
||||
|
||||
switch (m_mem_phase)
|
||||
{
|
||||
// This is always the odd address
|
||||
// With the OR we can ensure that we do not skip to an even address
|
||||
// when we try to read a word from an odd address
|
||||
m_current_value |= m_prgspace->read_byte(m_address | 0x0001);
|
||||
m_lowbyte = false;
|
||||
if (VERBOSE>3) LOG("tms9995: read external memory, second pass (address %04x, complete word = %04x)\n", m_address | 1, m_current_value);
|
||||
m_check_hold = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT16 address = m_address;
|
||||
case 1:
|
||||
// Set address
|
||||
// If this is a word access, 4 passes, else 2 passes
|
||||
m_dbin_line(ASSERT_LINE);
|
||||
if (m_word_access || !m_instruction->byteop)
|
||||
{
|
||||
// We have to come here a second time; do not advance the MPC
|
||||
// if the address value is even
|
||||
m_lowbyte = true;
|
||||
m_pass = 2;
|
||||
m_pass = 4;
|
||||
// For word accesses, we always start at the even address
|
||||
address &= 0xfffe;
|
||||
m_check_hold = false;
|
||||
}
|
||||
m_current_value = m_prgspace->read_byte(address) << 8;
|
||||
if (VERBOSE>3)
|
||||
{
|
||||
if (m_pass==2) LOG("tms9995: read external memory, first pass (address %04x, value %02x)\n", address, (m_current_value>>8)&0xff);
|
||||
else LOG("tms9995: read external memory (single pass), address %04x, value=%04x)\n", address, m_current_value);
|
||||
}
|
||||
else m_pass = 2;
|
||||
|
||||
m_check_hold = false;
|
||||
if (VERBOSE>7) LOG("tms9995: set address bus %04x\n", m_address & ~1);
|
||||
m_prgspace->set_address(address);
|
||||
m_request_auto_wait_state = m_auto_wait;
|
||||
break;
|
||||
case 2:
|
||||
// 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>7) LOG("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>7) LOG("tms9995: set address bus %04x\n", m_address | 1);
|
||||
m_prgspace->set_address(m_address | 1);
|
||||
break;
|
||||
case 4:
|
||||
// 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);
|
||||
m_check_hold = true;
|
||||
break;
|
||||
}
|
||||
if (m_auto_wait_state)
|
||||
{
|
||||
if (VERBOSE>7) LOG("tms9995: Next pulse is auto wait\n");
|
||||
pulse_clock(1);
|
||||
}
|
||||
|
||||
m_mem_phase = (m_mem_phase % 4) +1;
|
||||
|
||||
// Reset to 1 when we are done
|
||||
if (m_pass==1) m_mem_phase = 1;
|
||||
}
|
||||
pulse_clock(1);
|
||||
}
|
||||
@ -1738,7 +1730,6 @@ void tms9995_device::mem_write()
|
||||
pulse_clock(1);
|
||||
return;
|
||||
}
|
||||
|
||||
bool onchip = (((m_address & 0xff00)==0xf000 && (m_address < 0xf0fc)) || ((m_address & 0xfffc)==0xfffc)) && !m_mp9537;
|
||||
|
||||
if (onchip)
|
||||
@ -1753,41 +1744,50 @@ void tms9995_device::mem_write()
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is an off-chip access
|
||||
m_check_ready = true;
|
||||
UINT16 address = m_address;
|
||||
switch (m_mem_phase)
|
||||
{
|
||||
case 1:
|
||||
// Set address
|
||||
// If this is a word access, 4 passes, else 2 passes
|
||||
m_dbin_line(CLEAR_LINE);
|
||||
|
||||
if (m_lowbyte)
|
||||
{
|
||||
// see above in mem_read
|
||||
m_prgspace->write_byte(m_address | 0x0001, m_current_value & 0xff);
|
||||
m_lowbyte = false;
|
||||
if (VERBOSE>3) LOG("tms9995: write second pass (address %04x, value %02x)\n", m_address | 0x0001, m_current_value & 0xff);
|
||||
m_check_hold = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT16 address = m_address;
|
||||
if (m_word_access || !m_instruction->byteop)
|
||||
{
|
||||
// We have to come here a second time; do not advance the MPC
|
||||
// if the address value is even
|
||||
m_lowbyte = true;
|
||||
m_pass = 2;
|
||||
m_pass = 4;
|
||||
address &= 0xfffe;
|
||||
m_check_hold = false;
|
||||
}
|
||||
if (VERBOSE>3)
|
||||
{
|
||||
if (m_pass==2) LOG("tms9995: write external memory, first pass (address %04x, value %02x)\n", address, (m_current_value>>8)&0xff);
|
||||
else LOG("tms9995: write external memory (single pass), address %04x, value=%02x\n", address, (m_current_value>>8)&0xff);
|
||||
}
|
||||
m_prgspace->write_byte(address, (m_current_value >> 8)& 0xff);
|
||||
else m_pass = 2;
|
||||
|
||||
m_check_hold = false;
|
||||
if (VERBOSE>7) LOG("tms9995: set address bus %04x\n", address);
|
||||
m_prgspace->set_address(address);
|
||||
if (VERBOSE>7) LOG("tms9995: memory write byte %04x <- %02x\n", address, (m_current_value >> 8)&0xff);
|
||||
m_prgspace->write_byte(address, (m_current_value >> 8)&0xff);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// no action here, just wait for READY
|
||||
break;
|
||||
case 3:
|
||||
// Set address + 1 (unless byte command)
|
||||
if (VERBOSE>7) LOG("tms9995: set address bus %04x\n", m_address | 1);
|
||||
m_prgspace->set_address(m_address | 1);
|
||||
if (VERBOSE>7) LOG("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);
|
||||
break;
|
||||
case 4:
|
||||
// no action here, just wait for READY
|
||||
m_check_hold = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_auto_wait_state)
|
||||
{
|
||||
if (VERBOSE>7) LOG("tms9995: Next pulse is auto wait\n");
|
||||
pulse_clock(1);
|
||||
}
|
||||
m_mem_phase = (m_mem_phase % 4) +1;
|
||||
|
||||
// Reset to 1 when we are done
|
||||
if (m_pass==1) m_mem_phase = 1;
|
||||
}
|
||||
pulse_clock(1);
|
||||
}
|
||||
@ -2072,7 +2072,7 @@ void tms9995_device::operand_address_subprogram()
|
||||
}
|
||||
|
||||
m_get_destination = true;
|
||||
m_lowbyte = false;
|
||||
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);
|
||||
@ -2087,7 +2087,7 @@ void tms9995_device::increment_register()
|
||||
m_address_saved = m_current_value; // need a special return so we do not lose the value
|
||||
m_current_value += m_instruction->byteop? 1 : 2;
|
||||
m_address = (WP + (m_regnumber<<1)) & 0xffff;
|
||||
m_lowbyte = false;
|
||||
m_mem_phase = 1;
|
||||
pulse_clock(1);
|
||||
}
|
||||
|
||||
@ -2101,7 +2101,7 @@ void tms9995_device::indexed_addressing()
|
||||
m_address_add = m_current_value;
|
||||
m_address = PC;
|
||||
PC = (PC + 2) & 0xfffe;
|
||||
m_lowbyte = false;
|
||||
m_mem_phase = 1;
|
||||
pulse_clock(1);
|
||||
}
|
||||
|
||||
@ -2112,7 +2112,7 @@ void tms9995_device::set_immediate()
|
||||
m_address = PC;
|
||||
m_source_value = m_current_value; // needed for AI, ANDI, ORI
|
||||
PC = (PC + 2) & 0xfffe;
|
||||
m_lowbyte = false;
|
||||
m_mem_phase = 1;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
@ -3227,7 +3227,7 @@ void tms9995_device::alu_int()
|
||||
|
||||
if (((m_int_pending & PENDING_MID)!=0) && m_nmi_active)
|
||||
{
|
||||
if (VERBOSE>5) LOG("tms9995: interrupt service (5): NMI active after context switch\n");
|
||||
if (VERBOSE>5) LOG("tms9995: interrupt service (6): NMI active after context switch\n");
|
||||
m_int_pending &= ~PENDING_MID;
|
||||
m_address = 0xfffc;
|
||||
m_intmask = 0;
|
||||
@ -3235,11 +3235,11 @@ void tms9995_device::alu_int()
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_reset)
|
||||
if (m_from_reset)
|
||||
{
|
||||
if (VERBOSE>5) LOG("tms9995: interrupt service (5): RESET completed\n");
|
||||
if (VERBOSE>5) LOG("tms9995: interrupt service (6): RESET completed\n");
|
||||
// We came from the RESET interrupt
|
||||
m_reset = false;
|
||||
m_from_reset = false;
|
||||
ST &= 0x01ff;
|
||||
m_mid_flag = false;
|
||||
// FLAG0 and FLAG1 are also set to zero after RESET ([1], sect. 2.3.1.2.2)
|
||||
|
@ -65,8 +65,8 @@ struct tms9995_config
|
||||
devcb_write8 external_callback;
|
||||
devcb_write_line iaq_line;
|
||||
devcb_write_line clock_out;
|
||||
devcb_write_line wait_line;
|
||||
devcb_write_line holda_line;
|
||||
devcb_write_line dbin_line;
|
||||
int mode;
|
||||
int overflow;
|
||||
};
|
||||
@ -151,18 +151,23 @@ private:
|
||||
bool m_idle_state;
|
||||
bool m_nmi_state;
|
||||
bool m_irq_state;
|
||||
bool m_ready_state;
|
||||
bool m_wait_state;
|
||||
bool m_hold_state;
|
||||
|
||||
// READY handling. The READY line is operated before the clock
|
||||
// pulse falls. As the ready line is only set once in this emulation we
|
||||
// keep the level in a buffer (like a latch)
|
||||
bool m_ready_bufd; // buffered state
|
||||
bool m_ready; // sampled value
|
||||
|
||||
// Auto-wait state generation
|
||||
bool m_auto_wait_state;
|
||||
bool m_request_auto_wait_state;
|
||||
bool m_auto_wait;
|
||||
|
||||
// Cycle counter
|
||||
int m_icount;
|
||||
|
||||
// The next memory access will address the low byte
|
||||
bool m_lowbyte;
|
||||
// Phase of the memory access
|
||||
int m_mem_phase;
|
||||
|
||||
// Check the READY line?
|
||||
bool m_check_ready;
|
||||
@ -195,6 +200,7 @@ private:
|
||||
bool m_int_overflow;
|
||||
|
||||
bool m_reset;
|
||||
bool m_from_reset;
|
||||
bool m_mid_flag;
|
||||
|
||||
// Flag field
|
||||
@ -213,10 +219,7 @@ private:
|
||||
// Issue clock pulses. The TMS9995 uses one (output) clock cycle per machine cycle.
|
||||
inline void pulse_clock(int count);
|
||||
|
||||
// Signal the wait state via the external line
|
||||
inline void set_wait_state(bool state);
|
||||
|
||||
// Signal the wait state via the external line
|
||||
// Signal the hold state via the external line
|
||||
inline void set_hold_state(bool state);
|
||||
|
||||
// Only used for the DIV(S) operations. It seems sufficient to let the
|
||||
@ -434,11 +437,11 @@ private:
|
||||
// Clock output.
|
||||
devcb_resolved_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;
|
||||
|
||||
// Asserted when the CPU is in a HOLD state
|
||||
devcb_resolved_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;
|
||||
};
|
||||
|
||||
// device type definition
|
||||
|
Loading…
Reference in New Issue
Block a user