Logging changed; fixed HOLD handling; added synchronous RESET

This commit is contained in:
Michael Zapf 2016-03-31 00:58:27 +02:00
parent 2a71be55e9
commit a444e30e28
2 changed files with 150 additions and 117 deletions

View File

@ -85,7 +85,6 @@
TODO: TODO:
- State save - State save
- Test HOLD
Michael Zapf, June 2012 Michael Zapf, June 2012
*/ */
@ -275,7 +274,7 @@ void tms9995_device::device_start()
void tms9995_device::device_stop() void tms9995_device::device_stop()
{ {
int k = 0; int k = 0;
if (TRACE_CONFIG) logerror("%s: Deleting lookup tables\n", tag()); if (TRACE_EMU) logerror("%s: Deleting lookup tables\n", tag());
while (m_lotables[k]!=nullptr) delete[] m_lotables[k++]; while (m_lotables[k]!=nullptr) delete[] m_lotables[k++];
} }
@ -292,6 +291,7 @@ void tms9995_device::device_reset()
m_reset = true; // for the main loop m_reset = true; // for the main loop
m_servicing_interrupt = false; // only for debugging m_servicing_interrupt = false; // only for debugging
m_request_auto_wait_state = false; m_request_auto_wait_state = false;
m_hold_requested = false;
memset(m_flag, 0, sizeof(m_flag)); memset(m_flag, 0, sizeof(m_flag));
} }
@ -1150,7 +1150,7 @@ void tms9995_device::build_command_lookup_table()
{ {
inst = &s_command[i]; inst = &s_command[i];
table = m_command_lookup_table; table = m_command_lookup_table;
if (TRACE_EMU) logerror("tms9995: === opcode=%04x, len=%d\n", inst->opcode, format_mask_len[inst->format]); if (TRACE_EMU) logerror("=== opcode=%04x, len=%d\n", inst->opcode, format_mask_len[inst->format]);
bitcount = 4; bitcount = 4;
opcode = inst->opcode; opcode = inst->opcode;
cmdindex = (opcode>>12) & 0x000f; cmdindex = (opcode>>12) & 0x000f;
@ -1160,7 +1160,7 @@ void tms9995_device::build_command_lookup_table()
// Descend // Descend
if (table[cmdindex].next_digit == nullptr) if (table[cmdindex].next_digit == nullptr)
{ {
if (TRACE_EMU) logerror("tms9995: create new table at bitcount=%d for index=%d\n", bitcount, cmdindex); if (TRACE_EMU) logerror("create new table at bitcount=%d for index=%d\n", bitcount, cmdindex);
table[cmdindex].next_digit = new lookup_entry[16]; table[cmdindex].next_digit = new lookup_entry[16];
m_lotables[k++] = table[cmdindex].next_digit; m_lotables[k++] = table[cmdindex].next_digit;
for (int j=0; j < 16; j++) for (int j=0; j < 16; j++)
@ -1171,7 +1171,7 @@ void tms9995_device::build_command_lookup_table()
} }
else else
{ {
if (TRACE_EMU) logerror("tms9995: found a table at bitcount=%d\n", bitcount); if (TRACE_EMU) logerror("found a table at bitcount=%d\n", bitcount);
} }
table = table[cmdindex].next_digit; table = table[cmdindex].next_digit;
@ -1179,17 +1179,17 @@ void tms9995_device::build_command_lookup_table()
bitcount = bitcount+4; bitcount = bitcount+4;
opcode <<= 4; opcode <<= 4;
cmdindex = (opcode>>12) & 0x000f; cmdindex = (opcode>>12) & 0x000f;
if (TRACE_EMU) logerror("tms9995: next index=%x\n", cmdindex); if (TRACE_EMU) logerror("next index=%x\n", cmdindex);
} }
if (TRACE_EMU) logerror("tms9995: bitcount=%d\n", bitcount); if (TRACE_EMU) logerror("bitcount=%d\n", bitcount);
// We are at the target level // We are at the target level
// Need to fill in the same entry for all values in the bitcount // 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 // (if a command needs 10 bits we have to copy it four
// times for all combinations with 12 bits) // times for all combinations with 12 bits)
for (int j=0; j < (1<<(bitcount-format_mask_len[inst->format])); j++) for (int j=0; j < (1<<(bitcount-format_mask_len[inst->format])); j++)
{ {
if (TRACE_EMU) logerror("tms9995: opcode=%04x at position %d\n", inst->opcode, cmdindex+j); if (TRACE_EMU) logerror("opcode=%04x at position %d\n", inst->opcode, cmdindex+j);
table[cmdindex+j].entry = inst; table[cmdindex+j].entry = inst;
} }
@ -1197,7 +1197,7 @@ void tms9995_device::build_command_lookup_table()
} while (inst->opcode != 0xf000); } while (inst->opcode != 0xf000);
m_lotables[k++] = nullptr; m_lotables[k++] = nullptr;
if (TRACE_EMU) logerror("tms9995: Allocated %d tables\n", k); if (TRACE_EMU) logerror("Allocated %d tables\n", k);
} }
/* /*
@ -1212,24 +1212,24 @@ void tms9995_device::execute_run()
{ {
if (m_reset) service_interrupt(); if (m_reset) service_interrupt();
if (TRACE_EMU) logerror("tms9995: calling execute_run for %d cycles\n", m_icount); if (TRACE_EMU) logerror("calling execute_run for %d cycles\n", m_icount);
do do
{ {
// Normal operation // Normal operation
if (m_check_ready && m_ready == false) if (m_check_ready && m_ready == false)
{ {
// We are in a wait state // We are in a wait state
if (TRACE_WAITHOLD) logerror("tms9995: wait state\n"); if (TRACE_WAITHOLD) logerror("wait state\n");
// The clock output should be used to change the state of an outer // The clock output should be used to change the state of an outer
// device which operates the READY line // device which operates the READY line
pulse_clock(1); pulse_clock(1);
} }
else else
{ {
if (m_check_hold && m_hold_state) if (m_check_hold && m_hold_requested)
{ {
set_hold_state(true); set_hold_state(true);
if (TRACE_WAITHOLD) logerror("tms9995: hold state\n"); if (TRACE_WAITHOLD) logerror("HOLD state\n");
pulse_clock(1); pulse_clock(1);
} }
else else
@ -1238,7 +1238,7 @@ void tms9995_device::execute_run()
m_check_ready = false; m_check_ready = false;
if (TRACE_MICRO) logerror("tms9995: main loop, operation %s, MPC = %d\n", opname[m_instruction->command], MPC); if (TRACE_MICRO) logerror("main loop, operation %s, MPC = %d\n", opname[m_instruction->command], MPC);
(this->*s_microoperation[m_instruction->program[MPC]])(); (this->*s_microoperation[m_instruction->program[MPC]])();
// For multi-pass operations where the MPC should not advance // For multi-pass operations where the MPC should not advance
@ -1252,7 +1252,8 @@ void tms9995_device::execute_run()
} }
} }
} while (m_icount>0 && !m_reset); } while (m_icount>0 && !m_reset);
if (TRACE_EMU) logerror("tms9995: cycles expired; will return soon.\n");
if (TRACE_EMU) logerror("cycles expired; will return soon.\n");
} }
/**************************************************************************/ /**************************************************************************/
@ -1266,49 +1267,61 @@ void tms9995_device::execute_run()
*/ */
void tms9995_device::execute_set_input(int irqline, int state) void tms9995_device::execute_set_input(int irqline, int state)
{ {
if (irqline==INT_9995_RESET && state==ASSERT_LINE) if (irqline == INT_9995_RESET)
{ {
m_reset = true; if (state == ASSERT_LINE)
{
logerror("RESET interrupt line; READY=%d\n", m_ready_bufd);
m_reset = true;
}
} }
else else
{ {
if (irqline == INPUT_LINE_NMI) if (irqline == INPUT_LINE_NMI)
{ {
m_nmi_active = (state==ASSERT_LINE); m_nmi_active = (state==ASSERT_LINE);
if (TRACE_INT) logerror("tms9995: NMI interrupt line state=%d\n", state); if (TRACE_INT) logerror("NMI interrupt line state=%d\n", state);
} }
else else
{ {
if (irqline == INT_9995_INT1) if (irqline == INT_9995_INT1)
{ {
m_int1_active = m_flag[2] = (state==ASSERT_LINE); m_int1_active = m_flag[2] = (state==ASSERT_LINE);
if (TRACE_INT) logerror("tms9995: Line INT1 state=%d\n", state); if (TRACE_INT) logerror("Line INT1 state=%d\n", state);
} }
else else
{ {
if (irqline == INT_9995_INT4) if (irqline == INT_9995_INT4)
{ {
if (TRACE_INT) logerror("tms9995: Line INT4/EC state=%d\n", state); if (TRACE_INT) logerror("Line INT4/EC state=%d\n", state);
if (m_flag[0]==false) if (m_flag[0]==false)
{ {
if (TRACE_INT) logerror("tms9995: set as interrupt\n"); if (TRACE_INT) logerror("set as interrupt\n");
m_int4_active = m_flag[4] = (state==ASSERT_LINE); m_int4_active = m_flag[4] = (state==ASSERT_LINE);
} }
else else
{ {
if (TRACE_INT) logerror("tms9995: set as event count\n"); if (TRACE_INT) logerror("set as event count\n");
trigger_decrementer(); trigger_decrementer();
} }
} }
else else
{ {
logerror("tms9995: Accessed invalid interrupt line %d\n", irqline); logerror("Accessed invalid interrupt line %d\n", irqline);
} }
} }
} }
} }
} }
/*
Triggers a RESET.
*/
WRITE_LINE_MEMBER( tms9995_device::reset_line )
{
if (state==ASSERT_LINE) m_reset = true;
}
/* /*
Issue a pulse on the clock line. Issue a pulse on the clock line.
*/ */
@ -1322,8 +1335,8 @@ void tms9995_device::pulse_clock(int count)
m_icount--; // This is the only location where we count down the cycles. m_icount--; // This is the only location where we count down the cycles.
if (TRACE_CLOCK) if (TRACE_CLOCK)
{ {
if (m_check_ready) logerror("tms9995: pulse_clock, READY=%d, auto_wait=%d\n", m_ready_bufd? 1:0, m_auto_wait? 1:0); if (m_check_ready) logerror("pulse_clock, READY=%d, auto_wait=%d\n", m_ready_bufd? 1:0, m_auto_wait? 1:0);
else logerror("tms9995: pulse_clock\n"); else logerror("pulse_clock\n");
} }
m_request_auto_wait_state = false; m_request_auto_wait_state = false;
if (m_flag[0] == false && m_flag[1] == true) if (m_flag[0] == false && m_flag[1] == true)
@ -1339,11 +1352,11 @@ void tms9995_device::pulse_clock(int count)
/* /*
Enter the hold state. Enter the hold state.
*/ */
void tms9995_device::set_hold(int state) WRITE_LINE_MEMBER( tms9995_device::set_hold )
{ {
m_hold_state = (state==ASSERT_LINE); m_hold_requested = (state==ASSERT_LINE);
if (TRACE_WAITHOLD) logerror("tms9995: set HOLD = %d\n", state); if (TRACE_WAITHOLD) logerror("set HOLD = %d\n", state);
if (!m_hold_state) if (!m_hold_requested)
{ {
if (!m_holda_line.isnull()) m_holda_line(CLEAR_LINE); if (!m_holda_line.isnull()) m_holda_line(CLEAR_LINE);
} }
@ -1353,10 +1366,14 @@ void tms9995_device::set_hold(int state)
Signal READY to the CPU. When cleared, the CPU enters wait states. This Signal READY to the CPU. When cleared, the CPU enters wait states. This
becomes effective on a clock pulse. becomes effective on a clock pulse.
*/ */
void tms9995_device::set_ready(int state) WRITE_LINE_MEMBER( tms9995_device::set_ready )
{ {
m_ready_bufd = (state==ASSERT_LINE); if (m_reset && (m_ready_bufd != state)) logerror("Ignoring READY=%d change due to pending RESET\n", state);
if (TRACE_READY) logerror("tms9995: set READY = %d\n", m_ready_bufd? 1 : 0); else
{
m_ready_bufd = (state==ASSERT_LINE);
if (TRACE_READY) logerror("set READY = %d\n", m_ready_bufd? 1 : 0);
}
} }
/* /*
@ -1374,7 +1391,7 @@ void tms9995_device::abort_operation()
/* /*
Enter or leave the hold state. We only operate the HOLDA line when there is a change. Enter or leave the hold state. We only operate the HOLDA line when there is a change.
*/ */
inline void tms9995_device::set_hold_state(bool state) void tms9995_device::set_hold_state(bool state)
{ {
if (m_hold_state != state) if (m_hold_state != state)
if (!m_holda_line.isnull()) m_holda_line(state? ASSERT_LINE : CLEAR_LINE); if (!m_holda_line.isnull()) m_holda_line(state? ASSERT_LINE : CLEAR_LINE);
@ -1400,7 +1417,7 @@ void tms9995_device::decode(UINT16 inst)
while (!complete) while (!complete)
{ {
index = (opcode >> 12) & 0x000f; index = (opcode >> 12) & 0x000f;
if (TRACE_EMU) logerror("tms9995: Check next hex digit of instruction %x\n", index); if (TRACE_EMU) logerror("Check next hex digit of instruction %x\n", index);
if (table[index].next_digit != nullptr) if (table[index].next_digit != nullptr)
{ {
table = table[index].next_digit; table = table[index].next_digit;
@ -1412,7 +1429,7 @@ void tms9995_device::decode(UINT16 inst)
if (decoded == nullptr) if (decoded == nullptr)
{ {
// not found // not found
logerror("tms9995: Undefined opcode %04x at logical address %04x, will trigger MID\n", inst, PC); logerror("Undefined opcode %04x at logical address %04x, will trigger MID\n", inst, PC);
m_decoded[dindex].IR = 0; m_decoded[dindex].IR = 0;
m_decoded[dindex].command = MID; m_decoded[dindex].command = MID;
} }
@ -1423,7 +1440,7 @@ void tms9995_device::decode(UINT16 inst)
m_decoded[dindex].program = decoded->prog; m_decoded[dindex].program = decoded->prog;
m_decoded[dindex].byteop = ((decoded->format == 1) && ((inst & 0x1000)!=0)); m_decoded[dindex].byteop = ((decoded->format == 1) && ((inst & 0x1000)!=0));
m_decoded[dindex].state = 0; m_decoded[dindex].state = 0;
if (TRACE_EMU) logerror("tms9995: Command decoded as id %d, %s, base opcode %04x\n", decoded->id, opname[decoded->id], decoded->opcode); if (TRACE_EMU) logerror("Command decoded as id %d, %s, base opcode %04x\n", decoded->id, opname[decoded->id], decoded->opcode);
m_pass = 1; m_pass = 1;
} }
} }
@ -1444,7 +1461,7 @@ void tms9995_device::int_prefetch_and_decode()
// Check interrupt lines // Check interrupt lines
if (m_nmi_active) if (m_nmi_active)
{ {
if (TRACE_INT) logerror("tms9995: Checking interrupts ... NMI active\n"); if (TRACE_INT) logerror("Checking interrupts ... NMI active\n");
m_int_pending |= PENDING_NMI; m_int_pending |= PENDING_NMI;
m_idle_state = false; m_idle_state = false;
PC = (PC + 2) & 0xfffe; // we have not prefetched the next instruction PC = (PC + 2) & 0xfffe; // we have not prefetched the next instruction
@ -1467,19 +1484,19 @@ void tms9995_device::int_prefetch_and_decode()
if (m_idle_state) if (m_idle_state)
{ {
m_idle_state = false; m_idle_state = false;
if (TRACE_INT) logerror("tms9995: Interrupt occurred, terminate IDLE state\n"); if (TRACE_INT) logerror("Interrupt occurred, terminate IDLE state\n");
} }
PC = PC + 2; // PC must be advanced (see flow chart), but no prefetch PC = PC + 2; // PC must be advanced (see flow chart), but no prefetch
if (TRACE_INT) logerror("tms9995: Interrupts pending; no prefetch; advance PC to %04x\n", PC); if (TRACE_INT) logerror("Interrupts pending; no prefetch; advance PC to %04x\n", PC);
return; return;
} }
else else
{ {
if (TRACE_INT) logerror("tms9995: Checking interrupts ... none pending\n"); if (TRACE_INT) logerror("Checking interrupts ... none pending\n");
// No pending interrupts // No pending interrupts
if (m_idle_state) if (m_idle_state)
{ {
if (TRACE_WAITHOLD) logerror("tms9995: IDLE state\n"); if (TRACE_WAITHOLD) logerror("IDLE state\n");
// We are IDLE, stay in the loop and do not advance the PC // We are IDLE, stay in the loop and do not advance the PC
m_pass = 2; m_pass = 2;
pulse_clock(1); pulse_clock(1);
@ -1509,7 +1526,7 @@ void tms9995_device::prefetch_and_decode()
m_value_copy = m_current_value; m_value_copy = m_current_value;
if (!m_iaq_line.isnull()) m_iaq_line(ASSERT_LINE); if (!m_iaq_line.isnull()) m_iaq_line(ASSERT_LINE);
m_address = PC; m_address = PC;
if (TRACE_OP) logerror("tms9995: **** Prefetching new instruction at %04x ****\n", PC); if (TRACE_OP) logerror("**** Prefetching new instruction at %04x ****\n", PC);
} }
word_read(); // changes m_mem_phase word_read(); // changes m_mem_phase
@ -1522,7 +1539,7 @@ void tms9995_device::prefetch_and_decode()
m_current_value = m_value_copy; // restore m_current_value m_current_value = m_value_copy; // restore m_current_value
PC = (PC + 2) & 0xfffe; // advance PC PC = (PC + 2) & 0xfffe; // advance PC
if (!m_iaq_line.isnull()) m_iaq_line(CLEAR_LINE); if (!m_iaq_line.isnull()) m_iaq_line(CLEAR_LINE);
if (TRACE_OP) logerror("tms9995: ++++ Prefetch done ++++\n"); if (TRACE_OP) logerror("++++ Prefetch done ++++\n");
} }
} }
@ -1549,7 +1566,7 @@ void tms9995_device::next_command()
// This is a preset for opcodes which do not need an opcode address derivation // This is a preset for opcodes which do not need an opcode address derivation
m_address = WP + ((m_instruction->IR & 0x000f)<<1); m_address = WP + ((m_instruction->IR & 0x000f)<<1);
MPC = -1; MPC = -1;
if (TRACE_OP) logerror("tms9995: ===== Next operation %04x (%s) at %04x =====\n", m_instruction->IR, opname[m_instruction->command], PC-2); if (TRACE_OP) logerror("===== Next operation %04x (%s) at %04x =====\n", m_instruction->IR, opname[m_instruction->command], PC-2);
if (TRACE_EXEC) if (TRACE_EXEC)
{ {
@ -1570,7 +1587,7 @@ void tms9995_device::command_completed()
// Pseudo state at the end of the current instruction cycle sequence // Pseudo state at the end of the current instruction cycle sequence
if (TRACE_CYCLES) if (TRACE_CYCLES)
{ {
logerror("tms9995: +++++ Instruction %04x (%s) completed", m_instruction->IR, opname[m_instruction->command]); logerror("+++++ Instruction %04x (%s) completed", m_instruction->IR, opname[m_instruction->command]);
int cycles = m_first_cycle - m_icount; int cycles = m_first_cycle - m_icount;
// Avoid nonsense values due to expired and resumed main loop // Avoid nonsense values due to expired and resumed main loop
if (cycles > 0 && cycles < 10000) logerror(", consumed %d cycles", cycles); if (cycles > 0 && cycles < 10000) logerror(", consumed %d cycles", cycles);
@ -1607,9 +1624,10 @@ void tms9995_device::service_interrupt()
m_intmask = 0; // clear interrupt mask m_intmask = 0; // clear interrupt mask
m_nmi_state = false; m_nmi_state = false;
m_hold_requested = false;
m_hold_state = false; m_hold_state = false;
m_mem_phase = 1; m_mem_phase = 1;
m_check_hold = false; m_check_hold = true;
m_word_access = false; m_word_access = false;
m_int1_active = false; m_int1_active = false;
m_int4_active = false; m_int4_active = false;
@ -1626,7 +1644,7 @@ void tms9995_device::service_interrupt()
// The auto-wait state generation is turned on when the READY line is cleared // The auto-wait state generation is turned on when the READY line is cleared
// on RESET. // on RESET.
m_auto_wait = !m_ready_bufd; m_auto_wait = !m_ready_bufd;
if (TRACE_CONFIG) logerror("tms9995: RESET; automatic wait state creation is %s\n", m_auto_wait? "enabled":"disabled"); logerror("RESET; automatic wait state creation is %s\n", m_auto_wait? "enabled":"disabled");
// We reset the READY flag, or the CPU will not start // We reset the READY flag, or the CPU will not start
m_ready_bufd = true; m_ready_bufd = true;
} }
@ -1637,7 +1655,7 @@ void tms9995_device::service_interrupt()
vectorpos = 0x0008; vectorpos = 0x0008;
m_intmask = 0x0001; m_intmask = 0x0001;
PC = (PC + 2) & 0xfffe; PC = (PC + 2) & 0xfffe;
if (TRACE_INT) logerror("tms9995: ***** MID pending\n"); if (TRACE_INT) logerror("***** MID pending\n");
m_mid_active = false; m_mid_active = false;
} }
else else
@ -1647,7 +1665,7 @@ void tms9995_device::service_interrupt()
vectorpos = 0xfffc; vectorpos = 0xfffc;
m_int_pending &= ~PENDING_NMI; m_int_pending &= ~PENDING_NMI;
m_intmask = 0; m_intmask = 0;
if (TRACE_INT) logerror("tms9995: ***** NMI pending\n"); if (TRACE_INT) logerror("***** NMI pending\n");
} }
else else
{ {
@ -1657,7 +1675,7 @@ void tms9995_device::service_interrupt()
m_int_pending &= ~PENDING_LEVEL1; m_int_pending &= ~PENDING_LEVEL1;
m_flag[2] = false; m_flag[2] = false;
m_intmask = 0; m_intmask = 0;
if (TRACE_INT) logerror("tms9995: ***** INT1 pending\n"); if (TRACE_INT) logerror("***** INT1 pending\n");
} }
else else
{ {
@ -1666,7 +1684,7 @@ void tms9995_device::service_interrupt()
vectorpos = 0x0008; vectorpos = 0x0008;
m_int_pending &= ~PENDING_OVERFLOW; m_int_pending &= ~PENDING_OVERFLOW;
m_intmask = 0x0001; m_intmask = 0x0001;
if (TRACE_INT) logerror("tms9995: ***** OVERFL pending\n"); if (TRACE_INT) logerror("***** OVERFL pending\n");
} }
else else
{ {
@ -1677,7 +1695,7 @@ void tms9995_device::service_interrupt()
m_int_pending &= ~PENDING_DECR; m_int_pending &= ~PENDING_DECR;
m_flag[3] = false; m_flag[3] = false;
m_int_decrementer = false; m_int_decrementer = false;
if (TRACE_DEC) logerror("tms9995: ***** DECR pending\n"); if (TRACE_DEC) logerror("***** DECR pending\n");
} }
else else
{ {
@ -1685,7 +1703,7 @@ void tms9995_device::service_interrupt()
m_intmask = 0x0003; m_intmask = 0x0003;
m_int_pending &= ~PENDING_LEVEL4; m_int_pending &= ~PENDING_LEVEL4;
m_flag[4] = false; m_flag[4] = false;
if (TRACE_INT) logerror("tms9995: ***** INT4 pending\n"); if (TRACE_INT) logerror("***** INT4 pending\n");
} }
} }
} }
@ -1693,10 +1711,10 @@ void tms9995_device::service_interrupt()
} }
} }
if (TRACE_INT) logerror("tms9995: ********* triggered an interrupt with vector %04x/%04x\n", vectorpos, vectorpos+2); if (TRACE_INT) logerror("********* triggered an interrupt with vector %04x/%04x\n", vectorpos, vectorpos+2);
// just for debugging purposes // just for debugging purposes
m_servicing_interrupt = true; if (!m_reset) m_servicing_interrupt = true;
// The microinstructions will do the context switch // The microinstructions will do the context switch
m_address = vectorpos; m_address = vectorpos;
@ -1743,7 +1761,7 @@ void tms9995_device::mem_read()
if ((m_address & 0xfffe)==0xfffa && !m_mp9537) if ((m_address & 0xfffe)==0xfffa && !m_mp9537)
{ {
if (TRACE_DEC) logerror("tms9995: read decrementer\n"); if (TRACE_DEC) logerror("read decrementer\n");
// Decrementer mapped into the address space // Decrementer mapped into the address space
m_current_value = m_decrementer_value; m_current_value = m_decrementer_value;
if (m_instruction->byteop) if (m_instruction->byteop)
@ -1762,7 +1780,7 @@ void tms9995_device::mem_read()
// byte operations (e.g. when retrieving the index register) // byte operations (e.g. when retrieving the index register)
if (m_word_access || !m_instruction->byteop) m_address &= 0xfffe; if (m_word_access || !m_instruction->byteop) m_address &= 0xfffe;
if (TRACE_MEM) logerror("tms9995: read onchip memory (single pass, address %04x)\n", m_address); if (TRACE_MEM) logerror("read onchip memory (single pass, address %04x)\n", m_address);
// Ignore the READY state // Ignore the READY state
m_check_ready = false; m_check_ready = false;
@ -1797,7 +1815,7 @@ void tms9995_device::mem_read()
else m_pass = 2; else m_pass = 2;
m_check_hold = false; m_check_hold = false;
if (TRACE_ADDRESSBUS) logerror("tms9995: set address bus %04x\n", m_address & ~1); if (TRACE_ADDRESSBUS) logerror("set address bus %04x\n", m_address & ~1);
m_prgspace->set_address(address); m_prgspace->set_address(address);
m_request_auto_wait_state = m_auto_wait; m_request_auto_wait_state = m_auto_wait;
pulse_clock(1); pulse_clock(1);
@ -1806,20 +1824,21 @@ void tms9995_device::mem_read()
// Sample the value on the data bus (high byte) // Sample the value on the data bus (high byte)
if (m_word_access || !m_instruction->byteop) address &= 0xfffe; if (m_word_access || !m_instruction->byteop) address &= 0xfffe;
value = m_prgspace->read_byte(address); value = m_prgspace->read_byte(address);
if (TRACE_MEM) logerror("tms9995: memory read byte %04x -> %02x\n", m_address & ~1, value); if (TRACE_MEM) logerror("memory read byte %04x -> %02x\n", m_address & ~1, value);
m_current_value = (value << 8) & 0xff00; m_current_value = (value << 8) & 0xff00;
break; break;
case 3: case 3:
// Set address + 1 (unless byte command) // Set address + 1 (unless byte command)
if (TRACE_ADDRESSBUS) logerror("tms9995: set address bus %04x\n", m_address | 1); if (TRACE_ADDRESSBUS) logerror("set address bus %04x\n", m_address | 1);
m_prgspace->set_address(m_address | 1); m_prgspace->set_address(m_address | 1);
m_request_auto_wait_state = m_auto_wait;
pulse_clock(1); pulse_clock(1);
break; break;
case 4: case 4:
// Read low byte // Read low byte
value = m_prgspace->read_byte(m_address | 1); value = m_prgspace->read_byte(m_address | 1);
m_current_value |= value; m_current_value |= value;
if (TRACE_MEM) logerror("tms9995: memory read byte %04x -> %02x, complete word = %04x\n", m_address | 1, value, m_current_value); if (TRACE_MEM) logerror("memory read byte %04x -> %02x, complete word = %04x\n", m_address | 1, value, m_current_value);
m_check_hold = true; m_check_hold = true;
break; break;
} }
@ -1827,7 +1846,11 @@ void tms9995_device::mem_read()
m_mem_phase = (m_mem_phase % 4) +1; m_mem_phase = (m_mem_phase % 4) +1;
// Reset to 1 when we are done // Reset to 1 when we are done
if (m_pass==1) m_mem_phase = 1; if (m_pass==1)
{
m_mem_phase = 1;
m_check_hold = true;
}
} }
} }
@ -1883,7 +1906,7 @@ void tms9995_device::mem_write()
{ {
m_starting_count_storage_register = m_decrementer_value = m_current_value; m_starting_count_storage_register = m_decrementer_value = m_current_value;
} }
if (TRACE_DEC) logerror("tms9995: Setting decrementer to %04x, PC=%04x\n", m_current_value, PC); if (TRACE_DEC) logerror("Setting decrementer to %04x, PC=%04x\n", m_current_value, PC);
pulse_clock(1); pulse_clock(1);
return; return;
} }
@ -1895,7 +1918,7 @@ void tms9995_device::mem_write()
// byte operations (e.g. when retrieving the index register) // byte operations (e.g. when retrieving the index register)
if (m_word_access || !m_instruction->byteop) m_address &= 0xfffe; if (m_word_access || !m_instruction->byteop) m_address &= 0xfffe;
if (TRACE_MEM) logerror("tms9995: write to onchip memory (single pass, address %04x, value=%04x)\n", m_address, m_current_value); if (TRACE_MEM) logerror("write to onchip memory (single pass, address %04x, value=%04x)\n", m_address, m_current_value);
m_check_ready = false; m_check_ready = false;
m_onchip_memory[m_address & 0x00ff] = (m_current_value >> 8) & 0xff; m_onchip_memory[m_address & 0x00ff] = (m_current_value >> 8) & 0xff;
if (m_word_access || !m_instruction->byteop) if (m_word_access || !m_instruction->byteop)
@ -1924,10 +1947,11 @@ void tms9995_device::mem_write()
else m_pass = 2; else m_pass = 2;
m_check_hold = false; m_check_hold = false;
if (TRACE_ADDRESSBUS) logerror("tms9995: set address bus %04x\n", address); if (TRACE_ADDRESSBUS) logerror("set address bus %04x\n", address);
m_prgspace->set_address(address); m_prgspace->set_address(address);
if (TRACE_MEM) logerror("tms9995: memory write byte %04x <- %02x\n", address, (m_current_value >> 8)&0xff); if (TRACE_MEM) logerror("memory write byte %04x <- %02x\n", address, (m_current_value >> 8)&0xff);
m_prgspace->write_byte(address, (m_current_value >> 8)&0xff); m_prgspace->write_byte(address, (m_current_value >> 8)&0xff);
m_request_auto_wait_state = m_auto_wait;
pulse_clock(1); pulse_clock(1);
break; break;
@ -1936,22 +1960,26 @@ void tms9995_device::mem_write()
break; break;
case 3: case 3:
// Set address + 1 (unless byte command) // Set address + 1 (unless byte command)
if (TRACE_ADDRESSBUS) logerror("tms9995: set address bus %04x\n", m_address | 1); if (TRACE_ADDRESSBUS) logerror("set address bus %04x\n", m_address | 1);
m_prgspace->set_address(m_address | 1); m_prgspace->set_address(m_address | 1);
if (TRACE_MEM) logerror("tms9995: memory write byte %04x <- %02x\n", m_address | 1, m_current_value & 0xff); if (TRACE_MEM) logerror("memory write byte %04x <- %02x\n", m_address | 1, m_current_value & 0xff);
m_prgspace->write_byte(m_address | 1, m_current_value & 0xff); m_prgspace->write_byte(m_address | 1, m_current_value & 0xff);
m_request_auto_wait_state = m_auto_wait;
pulse_clock(1); pulse_clock(1);
break; break;
case 4: case 4:
// no action here, just wait for READY // no action here, just wait for READY
m_check_hold = true;
break; break;
} }
m_mem_phase = (m_mem_phase % 4) +1; m_mem_phase = (m_mem_phase % 4) +1;
// Reset to 1 when we are done // Reset to 1 when we are done
if (m_pass==1) m_mem_phase = 1; if (m_pass==1)
{
m_mem_phase = 1;
m_check_hold = true;
}
} }
} }
@ -1975,7 +2003,7 @@ void tms9995_device::return_with_address()
m_instruction->program = m_caller; m_instruction->program = m_caller;
MPC = m_caller_MPC; // will be increased on return MPC = m_caller_MPC; // will be increased on return
m_address = m_current_value + m_address_add; m_address = m_current_value + m_address_add;
if (TRACE_DETAIL) logerror("tms9995: +++ return from operand address derivation +++\n"); if (TRACE_DETAIL) logerror("+++ return from operand address derivation +++\n");
// no clock pulse // no clock pulse
} }
@ -1989,7 +2017,7 @@ void tms9995_device::return_with_address_copy()
m_instruction->program = m_caller; m_instruction->program = m_caller;
MPC = m_caller_MPC; // will be increased on return MPC = m_caller_MPC; // will be increased on return
m_address = m_address_saved; m_address = m_address_saved;
if (TRACE_DETAIL) logerror("tms9995: +++ return from operand address derivation (auto inc) +++\n"); if (TRACE_DETAIL) logerror("+++ return from operand address derivation (auto inc) +++\n");
// no clock pulse // no clock pulse
} }
@ -2030,7 +2058,7 @@ void tms9995_device::return_with_address_copy()
void tms9995_device::cru_output_operation() void tms9995_device::cru_output_operation()
{ {
if (TRACE_CRU) logerror("tms9995: CRU output operation, address %04x, value %d\n", m_cru_address, m_cru_value & 0x01); if (TRACE_CRU) logerror("CRU output operation, address %04x, value %d\n", m_cru_address, m_cru_value & 0x01);
if (m_cru_address == 0x1fda) if (m_cru_address == 0x1fda)
{ {
@ -2045,7 +2073,7 @@ void tms9995_device::cru_output_operation()
{ {
m_check_ready = false; m_check_ready = false;
// FLAG2, FLAG3, and FLAG4 are read-only // FLAG2, FLAG3, and FLAG4 are read-only
if (TRACE_CRU) logerror("tms9995: set CRU address %04x to %d\n", m_cru_address, m_cru_value&1); if (TRACE_CRU) logerror("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)) if ((m_cru_address != 0x1ee4) && (m_cru_address != 0x1ee6) && (m_cru_address != 0x1ee8))
m_flag[(m_cru_address>>1)&0x000f] = (m_cru_value & 0x01); m_flag[(m_cru_address>>1)&0x000f] = (m_cru_value & 0x01);
} }
@ -2102,7 +2130,7 @@ void tms9995_device::cru_input_operation()
// ........ ........ X....... ........ // ........ ........ X....... ........
// //
crubyte = m_cru->read_byte((m_cru_address >> 4)& CRUREADMASK); crubyte = m_cru->read_byte((m_cru_address >> 4)& CRUREADMASK);
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); if (TRACE_DETAIL) logerror("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_read = crubyte << 15;
m_cru_bits_left = 8; m_cru_bits_left = 8;
@ -2115,7 +2143,7 @@ void tms9995_device::cru_input_operation()
m_cru_first_read = false; m_cru_first_read = false;
m_pass = m_count; m_pass = m_count;
} }
if (TRACE_DETAIL) logerror("tms9995: adjusted value for shift: %06x\n", m_cru_read); if (TRACE_DETAIL) logerror("adjusted value for shift: %06x\n", m_cru_read);
} }
crubit = (m_cru_read & 0x8000); crubit = (m_cru_read & 0x8000);
@ -2141,7 +2169,7 @@ void tms9995_device::cru_input_operation()
} }
} }
if (TRACE_CRU) logerror("tms9995: CRU input operation, address %04x, value %d\n", m_cru_address, (crubit & 0x8000)>>15); if (TRACE_CRU) logerror("CRU input operation, address %04x, value %d\n", m_cru_address, (crubit & 0x8000)>>15);
m_cru_value |= crubit; m_cru_value |= crubit;
if (crubit!=0) m_parity++; if (crubit!=0) m_parity++;
@ -2172,11 +2200,11 @@ void tms9995_device::trigger_decrementer()
m_decrementer_value--; m_decrementer_value--;
if (m_decrementer_value==0) if (m_decrementer_value==0)
{ {
if (TRACE_DEC) logerror("tms9995: decrementer reached 0\n"); if (TRACE_DEC) logerror("decrementer reached 0\n");
m_decrementer_value = m_starting_count_storage_register; m_decrementer_value = m_starting_count_storage_register;
if (m_flag[1]==true) if (m_flag[1]==true)
{ {
if (TRACE_DEC) logerror("tms9995: decrementer flags interrupt\n"); if (TRACE_DEC) logerror("decrementer flags interrupt\n");
m_flag[3] = true; m_flag[3] = true;
m_int_decrementer = true; m_int_decrementer = true;
} }
@ -2225,12 +2253,12 @@ void tms9995_device::operand_address_subprogram()
{ {
if (m_regnumber != 0) if (m_regnumber != 0)
{ {
if (TRACE_DETAIL) logerror("tms9995: indexed addressing\n"); if (TRACE_DETAIL) logerror("indexed addressing\n");
MPC = 16; // indexed MPC = 16; // indexed
} }
else else
{ {
if (TRACE_DETAIL) logerror("tms9995: symbolic addressing\n"); if (TRACE_DETAIL) logerror("symbolic addressing\n");
m_address = PC; m_address = PC;
PC = (PC + 2) & 0xfffe; PC = (PC + 2) & 0xfffe;
} }
@ -2240,7 +2268,7 @@ void tms9995_device::operand_address_subprogram()
m_mem_phase = 1; m_mem_phase = 1;
m_address_add = 0; m_address_add = 0;
MPC--; // will be increased in the mail loop MPC--; // will be increased in the mail loop
if (TRACE_DETAIL) logerror("tms9995: *** Operand address derivation; address=%04x; index=%d\n", m_address, MPC+1); if (TRACE_DETAIL) logerror("*** Operand address derivation; address=%04x; index=%d\n", m_address, MPC+1);
} }
/* /*
@ -2382,7 +2410,7 @@ void tms9995_device::alu_add_s_sxc()
{ {
set_status_parity((UINT8)(dest_new>>8)); set_status_parity((UINT8)(dest_new>>8));
} }
if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value);
// No clock pulse (will be done by prefetch) // No clock pulse (will be done by prefetch)
} }
@ -2429,7 +2457,7 @@ void tms9995_device::alu_blwp()
case 4: case 4:
PC = m_current_value & 0xfffe; PC = m_current_value & 0xfffe;
n = 0; n = 0;
if (TRACE_OP) logerror("tms9995: Context switch complete; WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST); if (TRACE_OP) logerror("Context switch complete; WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST);
break; break;
} }
m_instruction->state++; m_instruction->state++;
@ -2450,7 +2478,7 @@ void tms9995_device::alu_c()
set_status_parity((UINT8)(m_source_value>>8)); set_status_parity((UINT8)(m_source_value>>8));
} }
compare_and_set_lae(m_source_value, m_current_value); compare_and_set_lae(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); if (TRACE_STATUS) logerror("ST = %04x (val1=%04x, val2=%04x)\n", ST, m_source_value, m_current_value);
} }
/* /*
@ -2461,12 +2489,12 @@ void tms9995_device::alu_ci()
// We have the register value in m_source_value, the register address in m_address_saved // We have the register value in m_source_value, the register address in m_address_saved
// and the immediate value in m_current_value // and the immediate value in m_current_value
compare_and_set_lae(m_source_value, m_current_value); compare_and_set_lae(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); if (TRACE_STATUS) logerror("ST = %04x (val1=%04x, val2=%04x)\n", ST, m_source_value, m_current_value);
} }
void tms9995_device::alu_clr_seto() void tms9995_device::alu_clr_seto()
{ {
if (TRACE_OP) logerror("tms9995: clr/seto: Setting values for address %04x\n", m_address); if (TRACE_OP) logerror("clr/seto: Setting values for address %04x\n", m_address);
switch (m_instruction->command) switch (m_instruction->command)
{ {
case CLR: case CLR:
@ -2675,14 +2703,14 @@ void tms9995_device::alu_external()
if (m_instruction->command == IDLE) if (m_instruction->command == IDLE)
{ {
if (TRACE_OP) logerror("tms9995: Entering IDLE state\n"); if (TRACE_OP) logerror("Entering IDLE state\n");
m_idle_state = true; m_idle_state = true;
} }
if (m_instruction->command == RSET) if (m_instruction->command == RSET)
{ {
ST &= 0xfff0; ST &= 0xfff0;
if (TRACE_OP) logerror("tms9995: RSET, new ST = %04x\n", ST); if (TRACE_OP) logerror("RSET, new ST = %04x\n", ST);
} }
if (!m_external_operation.isnull()) m_external_operation((m_instruction->IR >> 5) & 0x07, 1, 0xff); if (!m_external_operation.isnull()) m_external_operation((m_instruction->IR >> 5) & 0x07, 1, 0xff);
@ -2723,7 +2751,7 @@ void tms9995_device::alu_f3()
compare_and_set_lae(m_current_value, 0); compare_and_set_lae(m_current_value, 0);
} }
} }
if (TRACE_STATUS) logerror("tms9995: ST = %04x\n", ST); if (TRACE_STATUS) logerror("ST = %04x\n", ST);
break; break;
} }
m_instruction->state++; m_instruction->state++;
@ -2759,7 +2787,7 @@ void tms9995_device::alu_imm_arithm()
m_current_value = (UINT16)(dest_new & 0xffff); m_current_value = (UINT16)(dest_new & 0xffff);
compare_and_set_lae(m_current_value, 0); compare_and_set_lae(m_current_value, 0);
m_address = m_address_saved; m_address = m_address_saved;
if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value);
} }
/* /*
@ -2815,11 +2843,11 @@ void tms9995_device::alu_jump()
if (!cond) if (!cond)
{ {
if (TRACE_OP) logerror("tms9995: Jump condition false\n"); if (TRACE_OP) logerror("Jump condition false\n");
} }
else else
{ {
if (TRACE_OP) logerror("tms9995: Jump condition true\n"); if (TRACE_OP) logerror("Jump condition true\n");
PC = (PC + (displacement<<1)) & 0xfffe; PC = (PC + (displacement<<1)) & 0xfffe;
} }
} }
@ -2839,7 +2867,7 @@ void tms9995_device::alu_ldcr()
case 1: case 1:
// We have read the byte or word into m_current_value. // We have read the byte or word into m_current_value.
compare_and_set_lae(m_current_value, 0); compare_and_set_lae(m_current_value, 0);
if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value);
if (m_instruction->byteop) if (m_instruction->byteop)
{ {
m_current_value = (m_current_value>>8) & 0xff; m_current_value = (m_current_value>>8) & 0xff;
@ -2868,7 +2896,7 @@ void tms9995_device::alu_li()
// The immediate value is still in m_current_value // The immediate value is still in m_current_value
m_address = m_address_saved; m_address = m_address_saved;
compare_and_set_lae(m_current_value, 0); compare_and_set_lae(m_current_value, 0);
if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value);
} }
void tms9995_device::alu_limi_lwpi() void tms9995_device::alu_limi_lwpi()
@ -2877,13 +2905,13 @@ void tms9995_device::alu_limi_lwpi()
if (m_instruction->command == LIMI) if (m_instruction->command == LIMI)
{ {
ST = (ST & 0xfff0) | (m_current_value & 0x000f); ST = (ST & 0xfff0) | (m_current_value & 0x000f);
if (TRACE_OP) logerror("tms9995: LIMI sets ST = %04x\n", ST); if (TRACE_OP) logerror("LIMI sets ST = %04x\n", ST);
pulse_clock(1); // needs one more than LWPI pulse_clock(1); // needs one more than LWPI
} }
else else
{ {
WP = m_current_value & 0xfffe; WP = m_current_value & 0xfffe;
if (TRACE_OP) logerror("tms9995: LWPI sets new WP = %04x\n", WP); if (TRACE_OP) logerror("LWPI sets new WP = %04x\n", WP);
} }
} }
@ -2896,13 +2924,13 @@ void tms9995_device::alu_lst_lwp()
if (m_instruction->command==LST) if (m_instruction->command==LST)
{ {
ST = m_current_value; ST = m_current_value;
if (TRACE_OP) logerror("tms9995: new ST = %04x\n", ST); if (TRACE_OP) logerror("new ST = %04x\n", ST);
pulse_clock(1); pulse_clock(1);
} }
else else
{ {
WP = m_current_value & 0xfffe; WP = m_current_value & 0xfffe;
if (TRACE_OP) logerror("tms9995: new WP = %04x\n", WP); if (TRACE_OP) logerror("new WP = %04x\n", WP);
} }
} }
@ -2920,7 +2948,7 @@ void tms9995_device::alu_mov()
set_status_parity((UINT8)(m_current_value>>8)); set_status_parity((UINT8)(m_current_value>>8));
} }
compare_and_set_lae(m_current_value, 0); compare_and_set_lae(m_current_value, 0);
if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value);
// No clock pulse, as next instruction is prefetch // No clock pulse, as next instruction is prefetch
} }
@ -3013,7 +3041,7 @@ void tms9995_device::alu_rtwp()
// Just for debugging purposes // Just for debugging purposes
m_servicing_interrupt = false; m_servicing_interrupt = false;
if (TRACE_OP) logerror("tms9995: RTWP restored old context (WP=%04x, PC=%04x, ST=%04x)\n", WP, PC, ST); if (TRACE_OP) logerror("RTWP restored old context (WP=%04x, PC=%04x, ST=%04x)\n", WP, PC, ST);
break; break;
} }
m_instruction->state++; m_instruction->state++;
@ -3066,7 +3094,7 @@ void tms9995_device::alu_shift()
} }
else else
{ {
if (TRACE_DETAIL) logerror("tms9995: Shift operation gets count from R0\n"); if (TRACE_DETAIL) logerror("Shift operation gets count from R0\n");
} }
pulse_clock(1); pulse_clock(1);
pulse_clock(1); pulse_clock(1);
@ -3111,7 +3139,7 @@ void tms9995_device::alu_shift()
set_status_bit(ST_OV, overflow); set_status_bit(ST_OV, overflow);
compare_and_set_lae(m_current_value, 0); compare_and_set_lae(m_current_value, 0);
m_address = m_address_saved; // Register address m_address = m_address_saved; // Register address
if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value);
break; break;
} }
m_instruction->state++; m_instruction->state++;
@ -3207,7 +3235,7 @@ void tms9995_device::alu_single_arithm()
m_current_value = dest_new & 0xffff; m_current_value = dest_new & 0xffff;
compare_and_set_lae(m_current_value, 0); compare_and_set_lae(m_current_value, 0);
if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value);
// No clock pulse, as next instruction is prefetch // No clock pulse, as next instruction is prefetch
} }
@ -3245,7 +3273,7 @@ void tms9995_device::alu_stcr()
m_current_value <<= 8; m_current_value <<= 8;
} }
else n += 8; else n += 8;
if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value);
break; break;
} }
m_instruction->state++; m_instruction->state++;
@ -3285,7 +3313,7 @@ void tms9995_device::alu_tb()
break; break;
case 2: case 2:
set_status_bit(ST_EQ, m_cru_value!=0); set_status_bit(ST_EQ, m_cru_value!=0);
if (TRACE_STATUS) logerror("tms9995: ST = %04x\n", ST); if (TRACE_STATUS) logerror("ST = %04x\n", ST);
break; break;
} }
m_instruction->state++; m_instruction->state++;
@ -3368,7 +3396,7 @@ void tms9995_device::alu_int()
case 0: case 0:
PC = (PC - 2) & 0xfffe; PC = (PC - 2) & 0xfffe;
m_address_saved = m_address; m_address_saved = m_address;
if (TRACE_INTD) logerror("tms9995: interrupt service (0): Prepare to read vector\n"); if (TRACE_INTD) logerror("interrupt service (0): Prepare to read vector\n");
break; break;
case 1: case 1:
pulse = 2; // two cycles (with the one at the end) pulse = 2; // two cycles (with the one at the end)
@ -3376,30 +3404,30 @@ void tms9995_device::alu_int()
WP = m_current_value & 0xfffe; // new WP WP = m_current_value & 0xfffe; // new WP
m_current_value = ST; m_current_value = ST;
m_address = (WP + 30)&0xfffe; m_address = (WP + 30)&0xfffe;
if (TRACE_INTD) logerror("tms9995: interrupt service (1): Read new WP = %04x, save ST to %04x\n", WP, m_address); if (TRACE_INTD) logerror("interrupt service (1): Read new WP = %04x, save ST to %04x\n", WP, m_address);
break; break;
case 2: case 2:
m_address = (WP + 28)&0xfffe; m_address = (WP + 28)&0xfffe;
m_current_value = PC; m_current_value = PC;
if (TRACE_INTD) logerror("tms9995: interrupt service (2): Save PC to %04x\n", m_address); if (TRACE_INTD) logerror("interrupt service (2): Save PC to %04x\n", m_address);
break; break;
case 3: case 3:
m_address = (WP + 26)&0xfffe; m_address = (WP + 26)&0xfffe;
m_current_value = m_source_value; // old WP m_current_value = m_source_value; // old WP
if (TRACE_INTD) logerror("tms9995: interrupt service (3): Save WP to %04x\n", m_address); if (TRACE_INTD) logerror("interrupt service (3): Save WP to %04x\n", m_address);
break; break;
case 4: case 4:
m_address = (m_address_saved + 2) & 0xfffe; m_address = (m_address_saved + 2) & 0xfffe;
if (TRACE_INTD) logerror("tms9995: interrupt service (4): Read PC from %04x\n", m_address); if (TRACE_INTD) logerror("interrupt service (4): Read PC from %04x\n", m_address);
break; break;
case 5: case 5:
PC = m_current_value & 0xfffe; PC = m_current_value & 0xfffe;
ST = (ST & 0xfe00) | m_intmask; ST = (ST & 0xfe00) | m_intmask;
if (TRACE_INTD) logerror("tms9995: interrupt service (5): Context switch complete; WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST); if (TRACE_INTD) logerror("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 (((m_int_pending & PENDING_MID)!=0) && m_nmi_active)
{ {
if (TRACE_INTD) logerror("tms9995: interrupt service (6): NMI active after context switch\n"); if (TRACE_INTD) logerror("interrupt service (6): NMI active after context switch\n");
m_int_pending &= ~PENDING_MID; m_int_pending &= ~PENDING_MID;
m_address = 0xfffc; m_address = 0xfffc;
m_intmask = 0; m_intmask = 0;
@ -3409,7 +3437,7 @@ void tms9995_device::alu_int()
{ {
if (m_from_reset) if (m_from_reset)
{ {
if (TRACE_INTD) logerror("tms9995: interrupt service (6): RESET completed\n"); if (TRACE_INTD) logerror("interrupt service (6): RESET completed\n");
// We came from the RESET interrupt // We came from the RESET interrupt
m_from_reset = false; m_from_reset = false;
ST &= 0x01ff; ST &= 0x01ff;

View File

@ -54,12 +54,16 @@ public:
// READY input line. When asserted (high), the memory is ready for data exchange. // 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 // We chose to use a direct method instead of a delegate to keep performance
// footprint low; this method may be called very frequently. // footprint low; this method may be called very frequently.
void set_ready(int state); DECLARE_WRITE_LINE_MEMBER( set_ready );
// HOLD input line. When asserted (low), the CPU is requested to release the // HOLD input line. When asserted (low), the CPU is requested to release the
// data and address bus and enter the HOLD state. The entrance of this state // data and address bus and enter the HOLD state. The entrance of this state
// is acknowledged by the HOLDA output line. // is acknowledged by the HOLDA output line.
void set_hold(int state); DECLARE_WRITE_LINE_MEMBER( set_hold );
// RESET input line. Unlike the standard set_input_line, this input method
// is synchronous and will immediately lead to a reset of the CPU.
DECLARE_WRITE_LINE_MEMBER( reset_line );
// Callbacks // Callbacks
template<class _Object> static devcb_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 devcb_base &static_set_extop_callback(device_t &device, _Object object) { return downcast<tms9995_device &>(device).m_external_operation.set_callback(object); }
@ -133,6 +137,7 @@ private:
bool m_nmi_state; bool m_nmi_state;
// bool m_irq_state; // bool m_irq_state;
bool m_hold_state; bool m_hold_state;
bool m_hold_requested;
// READY handling. The READY line is operated before the clock // READY handling. The READY line is operated before the clock
// pulse falls. As the ready line is only set once in this emulation we // pulse falls. As the ready line is only set once in this emulation we
@ -205,7 +210,7 @@ private:
inline void pulse_clock(int count); inline void pulse_clock(int count);
// Signal the hold state via the external line // Signal the hold state via the external line
inline void set_hold_state(bool state); void set_hold_state(bool state);
// Only used for the DIV(S) operations. It seems sufficient to let the // Only used for the DIV(S) operations. It seems sufficient to let the
// command terminate at this point, so this method just calls command_terminated. // command terminate at this point, so this method just calls command_terminated.