summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu
diff options
context:
space:
mode:
author Michael Zapf <Michael.Zapf@mizapf.de>2016-03-31 00:58:27 +0200
committer Michael Zapf <Michael.Zapf@mizapf.de>2016-03-31 00:58:27 +0200
commita444e30e281eee5a4e0d7c19ec17f7e963442276 (patch)
treee62fe44fb3249aeb25d506ac6940d82b16c463c9 /src/devices/cpu
parent2a71be55e90288b6dab33b80d4c3687db0279d70 (diff)
Logging changed; fixed HOLD handling; added synchronous RESET
Diffstat (limited to 'src/devices/cpu')
-rw-r--r--src/devices/cpu/tms9900/tms9995.cpp256
-rw-r--r--src/devices/cpu/tms9900/tms9995.h11
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,43 +1267,47 @@ 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);
}
}
}
@@ -1310,6 +1315,14 @@ void tms9995_device::execute_set_input(int irqline, int state)
}
/*
+ Triggers a RESET.
+*/
+WRITE_LINE_MEMBER( tms9995_device::reset_line )
+{
+ if (state==ASSERT_LINE) m_reset = true;
+}
+
+/*
Issue a pulse on the clock line.
*/
void tms9995_device::pulse_clock(int count)
@@ -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<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_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.