From a444e30e281eee5a4e0d7c19ec17f7e963442276 Mon Sep 17 00:00:00 2001 From: Michael Zapf Date: Thu, 31 Mar 2016 00:58:27 +0200 Subject: [PATCH] Logging changed; fixed HOLD handling; added synchronous RESET --- src/devices/cpu/tms9900/tms9995.cpp | 256 +++++++++++++++------------- src/devices/cpu/tms9900/tms9995.h | 11 +- 2 files changed, 150 insertions(+), 117 deletions(-) diff --git a/src/devices/cpu/tms9900/tms9995.cpp b/src/devices/cpu/tms9900/tms9995.cpp index 855f00499a0..bdd530d7cc7 100644 --- a/src/devices/cpu/tms9900/tms9995.cpp +++ b/src/devices/cpu/tms9900/tms9995.cpp @@ -85,7 +85,6 @@ TODO: - State save - - Test HOLD Michael Zapf, June 2012 */ @@ -275,7 +274,7 @@ void tms9995_device::device_start() void tms9995_device::device_stop() { 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++]; } @@ -292,6 +291,7 @@ void tms9995_device::device_reset() m_reset = true; // for the main loop m_servicing_interrupt = false; // only for debugging m_request_auto_wait_state = false; + m_hold_requested = false; memset(m_flag, 0, sizeof(m_flag)); } @@ -1150,7 +1150,7 @@ void tms9995_device::build_command_lookup_table() { inst = &s_command[i]; 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; opcode = inst->opcode; cmdindex = (opcode>>12) & 0x000f; @@ -1160,7 +1160,7 @@ void tms9995_device::build_command_lookup_table() // Descend 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]; m_lotables[k++] = table[cmdindex].next_digit; for (int j=0; j < 16; j++) @@ -1171,7 +1171,7 @@ void tms9995_device::build_command_lookup_table() } 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; @@ -1179,17 +1179,17 @@ void tms9995_device::build_command_lookup_table() bitcount = bitcount+4; opcode <<= 4; 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 // 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 (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; } @@ -1197,7 +1197,7 @@ void tms9995_device::build_command_lookup_table() } while (inst->opcode != 0xf000); 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 (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 { // Normal operation if (m_check_ready && m_ready == false) { // 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 // device which operates the READY line pulse_clock(1); } else { - if (m_check_hold && m_hold_state) + if (m_check_hold && m_hold_requested) { set_hold_state(true); - if (TRACE_WAITHOLD) logerror("tms9995: hold state\n"); + if (TRACE_WAITHOLD) logerror("HOLD state\n"); pulse_clock(1); } else @@ -1238,7 +1238,7 @@ void tms9995_device::execute_run() 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]])(); // 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); - 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) { - 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 { if (irqline == INPUT_LINE_NMI) { 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 { if (irqline == INT_9995_INT1) { 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 { 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 (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); } else { - if (TRACE_INT) logerror("tms9995: set as event count\n"); + if (TRACE_INT) logerror("set as event count\n"); trigger_decrementer(); } } 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. */ @@ -1322,8 +1335,8 @@ void tms9995_device::pulse_clock(int count) m_icount--; // This is the only location where we count down the cycles. 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); - else logerror("tms9995: pulse_clock\n"); + 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("pulse_clock\n"); } m_request_auto_wait_state = false; if (m_flag[0] == false && m_flag[1] == true) @@ -1339,11 +1352,11 @@ void tms9995_device::pulse_clock(int count) /* Enter the hold state. */ -void tms9995_device::set_hold(int state) +WRITE_LINE_MEMBER( tms9995_device::set_hold ) { - m_hold_state = (state==ASSERT_LINE); - if (TRACE_WAITHOLD) logerror("tms9995: set HOLD = %d\n", state); - if (!m_hold_state) + m_hold_requested = (state==ASSERT_LINE); + if (TRACE_WAITHOLD) logerror("set HOLD = %d\n", state); + if (!m_hold_requested) { 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 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 (TRACE_READY) logerror("tms9995: set READY = %d\n", m_ready_bufd? 1 : 0); + if (m_reset && (m_ready_bufd != state)) logerror("Ignoring READY=%d change due to pending RESET\n", state); + 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. */ -inline void tms9995_device::set_hold_state(bool state) +void tms9995_device::set_hold_state(bool state) { if (m_hold_state != state) 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) { 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) { table = table[index].next_digit; @@ -1412,7 +1429,7 @@ void tms9995_device::decode(UINT16 inst) if (decoded == nullptr) { // 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].command = MID; } @@ -1423,7 +1440,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 (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; } } @@ -1444,7 +1461,7 @@ void tms9995_device::int_prefetch_and_decode() // Check interrupt lines 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_idle_state = false; 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) { 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 - 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; } else { - if (TRACE_INT) logerror("tms9995: Checking interrupts ... none pending\n"); + if (TRACE_INT) logerror("Checking interrupts ... none pending\n"); // No pending interrupts 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 m_pass = 2; pulse_clock(1); @@ -1509,7 +1526,7 @@ void tms9995_device::prefetch_and_decode() m_value_copy = m_current_value; if (!m_iaq_line.isnull()) m_iaq_line(ASSERT_LINE); 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 @@ -1522,7 +1539,7 @@ void tms9995_device::prefetch_and_decode() m_current_value = m_value_copy; // restore m_current_value PC = (PC + 2) & 0xfffe; // advance PC 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 m_address = WP + ((m_instruction->IR & 0x000f)<<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) { @@ -1570,7 +1587,7 @@ void tms9995_device::command_completed() // Pseudo state at the end of the current instruction cycle sequence 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; // Avoid nonsense values due to expired and resumed main loop 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_nmi_state = false; + m_hold_requested = false; m_hold_state = false; m_mem_phase = 1; - m_check_hold = false; + m_check_hold = true; m_word_access = false; m_int1_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 // on RESET. 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 m_ready_bufd = true; } @@ -1637,7 +1655,7 @@ void tms9995_device::service_interrupt() vectorpos = 0x0008; m_intmask = 0x0001; PC = (PC + 2) & 0xfffe; - if (TRACE_INT) logerror("tms9995: ***** MID pending\n"); + if (TRACE_INT) logerror("***** MID pending\n"); m_mid_active = false; } else @@ -1647,7 +1665,7 @@ void tms9995_device::service_interrupt() vectorpos = 0xfffc; m_int_pending &= ~PENDING_NMI; m_intmask = 0; - if (TRACE_INT) logerror("tms9995: ***** NMI pending\n"); + if (TRACE_INT) logerror("***** NMI pending\n"); } else { @@ -1657,7 +1675,7 @@ void tms9995_device::service_interrupt() m_int_pending &= ~PENDING_LEVEL1; m_flag[2] = false; m_intmask = 0; - if (TRACE_INT) logerror("tms9995: ***** INT1 pending\n"); + if (TRACE_INT) logerror("***** INT1 pending\n"); } else { @@ -1666,7 +1684,7 @@ void tms9995_device::service_interrupt() vectorpos = 0x0008; m_int_pending &= ~PENDING_OVERFLOW; m_intmask = 0x0001; - if (TRACE_INT) logerror("tms9995: ***** OVERFL pending\n"); + if (TRACE_INT) logerror("***** OVERFL pending\n"); } else { @@ -1677,7 +1695,7 @@ void tms9995_device::service_interrupt() m_int_pending &= ~PENDING_DECR; m_flag[3] = false; m_int_decrementer = false; - if (TRACE_DEC) logerror("tms9995: ***** DECR pending\n"); + if (TRACE_DEC) logerror("***** DECR pending\n"); } else { @@ -1685,7 +1703,7 @@ void tms9995_device::service_interrupt() m_intmask = 0x0003; m_int_pending &= ~PENDING_LEVEL4; 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 - m_servicing_interrupt = true; + if (!m_reset) m_servicing_interrupt = true; // The microinstructions will do the context switch m_address = vectorpos; @@ -1743,7 +1761,7 @@ void tms9995_device::mem_read() 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 m_current_value = m_decrementer_value; if (m_instruction->byteop) @@ -1762,7 +1780,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 (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 m_check_ready = false; @@ -1797,7 +1815,7 @@ void tms9995_device::mem_read() else m_pass = 2; 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_request_auto_wait_state = m_auto_wait; pulse_clock(1); @@ -1806,20 +1824,21 @@ 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 (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; break; case 3: // 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_request_auto_wait_state = m_auto_wait; pulse_clock(1); break; case 4: // Read low byte value = m_prgspace->read_byte(m_address | 1); 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; break; } @@ -1827,7 +1846,11 @@ void tms9995_device::mem_read() m_mem_phase = (m_mem_phase % 4) +1; // 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; } - 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); return; } @@ -1895,7 +1918,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 (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_onchip_memory[m_address & 0x00ff] = (m_current_value >> 8) & 0xff; if (m_word_access || !m_instruction->byteop) @@ -1924,10 +1947,11 @@ void tms9995_device::mem_write() else m_pass = 2; 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); - 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_request_auto_wait_state = m_auto_wait; pulse_clock(1); break; @@ -1936,22 +1960,26 @@ void tms9995_device::mem_write() break; case 3: // 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); - 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_request_auto_wait_state = m_auto_wait; pulse_clock(1); break; case 4: // no action here, just wait for READY - m_check_hold = true; break; } m_mem_phase = (m_mem_phase % 4) +1; // 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; MPC = m_caller_MPC; // will be increased on return 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 } @@ -1989,7 +2017,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 (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 } @@ -2030,7 +2058,7 @@ void tms9995_device::return_with_address_copy() 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) { @@ -2045,7 +2073,7 @@ void tms9995_device::cru_output_operation() { m_check_ready = false; // 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)) m_flag[(m_cru_address>>1)&0x000f] = (m_cru_value & 0x01); } @@ -2102,7 +2130,7 @@ void tms9995_device::cru_input_operation() // ........ ........ X....... ........ // 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_bits_left = 8; @@ -2115,7 +2143,7 @@ void tms9995_device::cru_input_operation() m_cru_first_read = false; 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); @@ -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; if (crubit!=0) m_parity++; @@ -2172,11 +2200,11 @@ void tms9995_device::trigger_decrementer() m_decrementer_value--; 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; 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_int_decrementer = true; } @@ -2225,12 +2253,12 @@ void tms9995_device::operand_address_subprogram() { if (m_regnumber != 0) { - if (TRACE_DETAIL) logerror("tms9995: indexed addressing\n"); + if (TRACE_DETAIL) logerror("indexed addressing\n"); MPC = 16; // indexed } else { - if (TRACE_DETAIL) logerror("tms9995: symbolic addressing\n"); + if (TRACE_DETAIL) logerror("symbolic addressing\n"); m_address = PC; PC = (PC + 2) & 0xfffe; } @@ -2240,7 +2268,7 @@ void tms9995_device::operand_address_subprogram() m_mem_phase = 1; m_address_add = 0; 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)); } - 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) } @@ -2429,7 +2457,7 @@ void tms9995_device::alu_blwp() case 4: PC = m_current_value & 0xfffe; 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; } m_instruction->state++; @@ -2450,7 +2478,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 (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 // and the immediate value in 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() { - 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) { case CLR: @@ -2675,14 +2703,14 @@ void tms9995_device::alu_external() 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; } if (m_instruction->command == RSET) { 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); @@ -2723,7 +2751,7 @@ void tms9995_device::alu_f3() 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; } m_instruction->state++; @@ -2759,7 +2787,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 (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 (TRACE_OP) logerror("tms9995: Jump condition false\n"); + if (TRACE_OP) logerror("Jump condition false\n"); } else { - if (TRACE_OP) logerror("tms9995: Jump condition true\n"); + if (TRACE_OP) logerror("Jump condition true\n"); PC = (PC + (displacement<<1)) & 0xfffe; } } @@ -2839,7 +2867,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 (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) { 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 m_address = m_address_saved; 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() @@ -2877,13 +2905,13 @@ void tms9995_device::alu_limi_lwpi() if (m_instruction->command == LIMI) { 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 } else { 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) { 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); } else { 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)); } 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 } @@ -3013,7 +3041,7 @@ void tms9995_device::alu_rtwp() // Just for debugging purposes 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; } m_instruction->state++; @@ -3066,7 +3094,7 @@ void tms9995_device::alu_shift() } 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); @@ -3111,7 +3139,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 (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; } m_instruction->state++; @@ -3207,7 +3235,7 @@ void tms9995_device::alu_single_arithm() m_current_value = dest_new & 0xffff; 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 } @@ -3245,7 +3273,7 @@ void tms9995_device::alu_stcr() m_current_value <<= 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; } m_instruction->state++; @@ -3285,7 +3313,7 @@ void tms9995_device::alu_tb() break; case 2: 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; } m_instruction->state++; @@ -3368,7 +3396,7 @@ void tms9995_device::alu_int() case 0: PC = (PC - 2) & 0xfffe; 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; case 1: 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 m_current_value = ST; 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; case 2: m_address = (WP + 28)&0xfffe; 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; case 3: m_address = (WP + 26)&0xfffe; 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; case 4: 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; case 5: PC = m_current_value & 0xfffe; 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 (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_address = 0xfffc; m_intmask = 0; @@ -3409,7 +3437,7 @@ void tms9995_device::alu_int() { 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 m_from_reset = false; ST &= 0x01ff; diff --git a/src/devices/cpu/tms9900/tms9995.h b/src/devices/cpu/tms9900/tms9995.h index e5dc055f36f..96f5c7b1cb8 100644 --- a/src/devices/cpu/tms9900/tms9995.h +++ b/src/devices/cpu/tms9900/tms9995.h @@ -54,12 +54,16 @@ public: // 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 // 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 // data and address bus and enter the HOLD state. The entrance of this state // 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 template static devcb_base &static_set_extop_callback(device_t &device, _Object object) { return downcast(device).m_external_operation.set_callback(object); } @@ -133,6 +137,7 @@ private: bool m_nmi_state; // bool m_irq_state; bool m_hold_state; + bool m_hold_requested; // READY handling. The READY line is operated before the clock // 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); // 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 // command terminate at this point, so this method just calls command_terminated.