summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu
diff options
context:
space:
mode:
author Michael Zapf <michael.zapf@mizapf.de>2013-11-01 17:06:32 +0000
committer Michael Zapf <michael.zapf@mizapf.de>2013-11-01 17:06:32 +0000
commitf4ff52905ae2e4e875a79e937d872c5e05b23772 (patch)
treeeb50411f2cdc3c76242f58772cef6ad822c6e3d9 /src/emu
parent4d6f21861bb5c09bc356211ba66671d55ec771ff (diff)
tms9995: Cycles fine-tuned, almost complete. (nw)
Diffstat (limited to 'src/emu')
-rw-r--r--src/emu/cpu/tms9900/tms9995.c366
-rw-r--r--src/emu/cpu/tms9900/tms9995.h1
2 files changed, 196 insertions, 171 deletions
diff --git a/src/emu/cpu/tms9900/tms9995.c b/src/emu/cpu/tms9900/tms9995.c
index c2606121f7a..97291c3a29b 100644
--- a/src/emu/cpu/tms9900/tms9995.c
+++ b/src/emu/cpu/tms9900/tms9995.c
@@ -84,7 +84,6 @@
[1] Texas Instruments 9900 Microprocessor series: TMS9995 16-bit Microcomputer
TODO:
- - Fine-tune cycles
- State save
- Test HOLD
@@ -117,7 +116,18 @@ enum
PENDING_LEVEL4 = 32
};
+/*****************************************************************
+ Debugging
+ Set to 0 (disable) or 1 (enable)
+******************************************************************/
+
#define LOG logerror
+
+// Log addresses of executed opcodes
+#define TRACE_EXEC 0
+
+// old debugging approach; going to be replaced
+// VERBOSE = 0 ... 9
#define VERBOSE 1
/****************************************************************************
@@ -214,6 +224,7 @@ void tms9995_device::device_stop()
void tms9995_device::device_reset()
{
m_reset = true; // for the main loop
+ m_servicing_interrupt = false; // only for debugging
}
const char* tms9995_device::s_statename[20] =
@@ -471,7 +482,7 @@ MICROPROGRAM(add_s_sxc_mp)
MEMORY_READ, // 1 (1)
ALU_ADD_S_SXC, // 0 (see above, occurs in parallel with PREFETCH)
PREFETCH, // 1 (1)
- MEMORY_WRITE, // 1 (1) + DECODE=0
+ MEMORY_WRITE, // 1 (1) + decode in parallel (0)
END
};
@@ -530,7 +541,7 @@ MICROPROGRAM(c_mp)
MICROPROGRAM(ci_mp)
{
MEMORY_READ, // 1 (1) (reg)
- SET_IMM, // 0
+ SET_IMM, // 0 belongs to next cycle
MEMORY_READ, // 1 (1) (imm)
ALU_CI, // 0 set status
PREFETCH, // 1 (1)
@@ -540,105 +551,106 @@ MICROPROGRAM(ci_mp)
MICROPROGRAM(coc_czc_mp)
{
- OPERAND_ADDR,
- MEMORY_READ,
- ALU_F3,
- MEMORY_READ,
- ALU_F3,
- PREFETCH,
- ALU_NOP,
+ OPERAND_ADDR, // x
+ MEMORY_READ, // 1 (1)
+ ALU_F3, // 0
+ MEMORY_READ, // 1 (1)
+ ALU_F3, // 0
+ PREFETCH, // 1 (1)
+ ALU_NOP, // 1 decode
END
};
MICROPROGRAM(clr_seto_mp)
{
- OPERAND_ADDR,
- ALU_NOP,
- ALU_CLR_SETO, // (1)
- PREFETCH, // 1
- MEMORY_WRITE, // 1
+ OPERAND_ADDR, // x
+ ALU_NOP, // 1
+ ALU_CLR_SETO, // 0
+ PREFETCH, // 1 (1)
+ MEMORY_WRITE, // 1 (1)
END
};
-MICROPROGRAM(divide_mp)
-{
- OPERAND_ADDR, // Address of divisor S in Q=W1W2/S
- MEMORY_READ, // Get S
- ALU_DIV,
- MEMORY_READ, // Get W1
- ALU_DIV, // Check for overflow; skip next instruction if not
- ABORT,
- MEMORY_READ, // Get W2
- ALU_DIV, // Calculate quotient
- MEMORY_WRITE, // Write quotient to &W1
- ALU_DIV,
- PREFETCH,
- MEMORY_WRITE, // Write remainder to &W2
+MICROPROGRAM(divide_mp) // TODO: Verify cycles on the real machine
+{
+ OPERAND_ADDR, // x Address of divisor S in Q=W1W2/S
+ MEMORY_READ, // 1 (1) Get S
+ ALU_DIV, // 1
+ MEMORY_READ, // 1 (1) Get W1
+ ALU_DIV, // 1 Check for overflow; skip next instruction if not
+ ABORT, // 1
+ MEMORY_READ, // 1 (1) Get W2
+ ALU_DIV, // d Calculate quotient
+ MEMORY_WRITE, // 1 (1) Write quotient to &W1
+ ALU_DIV, // 0
+ PREFETCH, // 1 (1)
+ MEMORY_WRITE, // 1 (1) Write remainder to &W2
END
};
-MICROPROGRAM(divide_signed_mp)
-{
- OPERAND_ADDR, // Address of divisor S in Q=W1W2/S
- MEMORY_READ, // Get S
- ALU_DIVS,
- MEMORY_READ, // Get W1
- ALU_DIVS, //
- MEMORY_READ, // Get W2
- ALU_DIVS, // Check for overflow, skip next instruction if not
- ABORT,
- ALU_DIVS, // Calculate quotient
- MEMORY_WRITE, // Write quotient to &W1
- ALU_DIVS,
- PREFETCH,
- MEMORY_WRITE, // Write remainder to &W2
+MICROPROGRAM(divide_signed_mp) // TODO: Verify cycles on the real machine
+{
+ OPERAND_ADDR, // x Address of divisor S in Q=W1W2/S
+ MEMORY_READ, // 1 (1) Get S
+ ALU_DIVS, // 1
+ MEMORY_READ, // 1 (1) Get W1
+ ALU_DIVS, // 1
+ MEMORY_READ, // 1 (1) Get W2
+ ALU_DIVS, // 1 Check for overflow, skip next instruction if not
+ ABORT, // 1
+ ALU_DIVS, // d Calculate quotient
+ MEMORY_WRITE, // 1 (1) Write quotient to &W1
+ ALU_DIVS, // 0
+ PREFETCH, // 1
+ MEMORY_WRITE, // 1 (1) Write remainder to &W2
END
};
MICROPROGRAM(external_mp)
{
- ALU_NOP,
- ALU_NOP,
- ALU_NOP,
- ALU_NOP,
- ALU_NOP,
- ALU_EXTERNAL,
- PREFETCH,
- ALU_NOP,
+ ALU_NOP, // 1
+ ALU_NOP, // 1
+ ALU_NOP, // 1
+ ALU_NOP, // 1
+ ALU_NOP, // 1
+ ALU_EXTERNAL, // 0
+ PREFETCH, // 1 (1)
+ ALU_NOP, // 1
END
};
MICROPROGRAM(imm_arithm_mp)
{
- MEMORY_READ,
+ MEMORY_READ, // 1 (1)
SET_IMM, // 0
MEMORY_READ, // 1 (1)
ALU_IMM_ARITHM, // 0
PREFETCH, // 1 (1)
- MEMORY_WRITE,
+ MEMORY_WRITE, // 1 (1)
END
};
MICROPROGRAM(jump_mp)
{
- ALU_JUMP,
- PREFETCH,
- ALU_NOP,
+ ALU_NOP, // 1
+ ALU_JUMP, // 0
+ PREFETCH, // 1 (1)
+ ALU_NOP, // 1
END
};
-MICROPROGRAM(ldcr_mp)
+MICROPROGRAM(ldcr_mp) // TODO: Verify cycles
{
- ALU_LDCR,
- OPERAND_ADDR,
- MEMORY_READ, // Get source data
- ALU_LDCR, // Save it, point to R12
- WORD_READ, // Get R12
- ALU_LDCR, // Prepare CRU operation
- CRU_OUTPUT,
- ALU_NOP,
- PREFETCH,
- ALU_NOP,
+ ALU_LDCR, // 1
+ OPERAND_ADDR, // x
+ MEMORY_READ, // 1 (1) Get source data
+ ALU_LDCR, // 1 Save it, point to R12
+ WORD_READ, // 1 (1) Get R12
+ ALU_LDCR, // 1 Prepare CRU operation
+ CRU_OUTPUT, // c
+ ALU_NOP, // 0
+ PREFETCH, // 1 (1)
+ ALU_NOP, // 1
END
};
@@ -657,19 +669,19 @@ MICROPROGRAM(limi_lwpi_mp)
SET_IMM, // 0
MEMORY_READ, // 1 (1)
ALU_NOP, // 1
- ALU_LIMIWP, // (1)
- PREFETCH, // 1
+ ALU_LIMIWP, // 0 lwpi, 1 limi
+ PREFETCH, // 1 (1)
ALU_NOP, // 1
END
};
MICROPROGRAM(lst_lwp_mp)
{
- MEMORY_READ,
- ALU_NOP,
- ALU_LSTWP,
- PREFETCH,
- ALU_NOP,
+ MEMORY_READ, // 1 (1)
+ ALU_NOP, // 1
+ ALU_LSTWP, // 0 lwp, 1 lst
+ PREFETCH, // 1 (1)
+ ALU_NOP, // 1
END
};
@@ -678,146 +690,148 @@ MICROPROGRAM(mov_mp)
OPERAND_ADDR, // 0
MEMORY_READ, // 1 (1)
OPERAND_ADDR, // 0
- ALU_MOV, // 1
- PREFETCH,
+ ALU_MOV, // 0
+ PREFETCH, // 1 (1)
MEMORY_WRITE, // 1 (1)
END
};
MICROPROGRAM(multiply_mp)
{
- OPERAND_ADDR,
- MEMORY_READ,
- ALU_MPY,
- MEMORY_READ,
- ALU_MPY,
- MEMORY_WRITE,
- ALU_MPY,
- PREFETCH,
- MEMORY_WRITE,
+ OPERAND_ADDR, // x
+ MEMORY_READ, // 1 (1)
+ ALU_MPY, // 1
+ MEMORY_READ, // 1 (1)
+ ALU_MPY, // 17
+ MEMORY_WRITE, // 1 (1)
+ ALU_MPY, // 0
+ PREFETCH, // 1 (1)
+ MEMORY_WRITE, // 1 (1)
END
};
MICROPROGRAM(rtwp_mp)
{
- ALU_RTWP,
- MEMORY_READ,
- ALU_RTWP,
- MEMORY_READ,
- ALU_RTWP,
- MEMORY_READ,
- ALU_RTWP,
- PREFETCH,
- ALU_NOP,
+ ALU_RTWP, // 1
+ MEMORY_READ, // 1 (1)
+ ALU_RTWP, // 0
+ MEMORY_READ, // 1 (1)
+ ALU_RTWP, // 0
+ MEMORY_READ, // 1 (1)
+ ALU_RTWP, // 0
+ PREFETCH, // 1 (1)
+ ALU_NOP, // 1
END
};
MICROPROGRAM(sbo_sbz_mp)
{
- ALU_SBO_SBZ, // Set address = &R12
- WORD_READ, // Read R12
- ALU_SBO_SBZ, // Add offset
- CRU_OUTPUT, // output via CRU
- ALU_NOP,
- PREFETCH,
- ALU_NOP,
+ ALU_SBO_SBZ, // 1 Set address = &R12
+ WORD_READ, // 1 (1) Read R12
+ ALU_SBO_SBZ, // 1 Add offset
+ CRU_OUTPUT, // 1 output via CRU
+ PREFETCH, // 1 (1)
+ ALU_NOP, // 1
+ ALU_NOP, // 1
END
};
MICROPROGRAM(shift_mp)
{
- MEMORY_READ,
- ALU_SHIFT, // skip next operation if count != 0
- MEMORY_READ, // if count=0 we must read R0
- ALU_SHIFT, // do the shift
- PREFETCH,
- MEMORY_WRITE,
+ MEMORY_READ, // 1 (1)
+ ALU_SHIFT, // 2 skip next operation if count != 0
+ MEMORY_READ, // 1 (1) if count=0 we must read R0
+ ALU_SHIFT, // c do the shift
+ PREFETCH, // 1 (1)
+ MEMORY_WRITE, // 1 (1)
END
};
MICROPROGRAM(single_arithm_mp)
{
- OPERAND_ADDR,
- MEMORY_READ, // This one is not done for CLR/SETO
- ALU_SINGLE_ARITHM,
- PREFETCH,
- MEMORY_WRITE,
+ OPERAND_ADDR, // x
+ MEMORY_READ, // 1 (1)
+ ALU_SINGLE_ARITHM, // 0
+ PREFETCH, // 1 (1)
+ MEMORY_WRITE, // 1 (1)
END
};
-MICROPROGRAM(stcr_mp)
+MICROPROGRAM(stcr_mp) // TODO: Verify on real machine
{
- ALU_STCR, // Check for byte operation
- OPERAND_ADDR, // Source operand
- ALU_STCR, // Save, set R12
- WORD_READ, // Read R12
- ALU_STCR,
- CRU_INPUT,
- ALU_STCR,
- PREFETCH,
- MEMORY_WRITE,
+ ALU_STCR, // 1 Check for byte operation
+ OPERAND_ADDR, // x Source operand
+ ALU_STCR, // 1 Save, set R12
+ WORD_READ, // 1 (1) Read R12
+ ALU_STCR, // 1
+ CRU_INPUT, // c
+ ALU_STCR, // 13
+ PREFETCH, // 1 (1)
+ MEMORY_WRITE, // 1 (1)
END
};
MICROPROGRAM(stst_stwp_mp)
{
- ALU_STSTWP,
- ALU_NOP,
- PREFETCH,
- MEMORY_WRITE,
+ ALU_STSTWP, // 0
+ ALU_NOP, // 1
+ PREFETCH, // 1 (1)
+ MEMORY_WRITE, // 1 (1)
END
};
MICROPROGRAM(tb_mp)
{
- ALU_TB,
- WORD_READ,
- ALU_TB,
- CRU_INPUT,
- ALU_TB,
- PREFETCH,
- ALU_NOP,
+ ALU_TB, // 1
+ WORD_READ, // 1 (1)
+ ALU_TB, // 1
+ CRU_INPUT, // 2
+ ALU_TB, // 0
+ PREFETCH, // 1 (1)
+ ALU_NOP, // 1
+ ALU_NOP, // 1
END
};
MICROPROGRAM(x_mp)
{
- OPERAND_ADDR,
- MEMORY_READ,
- ALU_X,
+ OPERAND_ADDR, // x
+ MEMORY_READ, // 1 (1)
+ ALU_X, // 1
END // should not be reached
};
MICROPROGRAM(xop_mp)
{
- OPERAND_ADDR, // Determine source address
- ALU_XOP, // Save it; determine XOP number
- MEMORY_READ, // Read new WP
- ALU_XOP, //
- MEMORY_WRITE, // save source address to new R11
- ALU_XOP,
- MEMORY_WRITE, // save old ST to new R15
- ALU_XOP,
- MEMORY_WRITE, // save old PC to new R14
- ALU_XOP,
- MEMORY_WRITE, // save old WP to new R13
- ALU_XOP,
- MEMORY_READ, // Read new PC
- ALU_XOP, // set new PC, set X flag
- PREFETCH,
- ALU_NOP,
+ OPERAND_ADDR, // x Determine source address
+ ALU_XOP, // 1 Save it; determine XOP number
+ MEMORY_READ, // 1 (1) Read new WP
+ ALU_XOP, // 1
+ MEMORY_WRITE, // 1 (1) save source address to new R11
+ ALU_XOP, // 1
+ MEMORY_WRITE, // 1 (1) save old ST to new R15
+ ALU_XOP, // 1
+ MEMORY_WRITE, // 1 (1) save old PC to new R14
+ ALU_XOP, // 1
+ MEMORY_WRITE, // 1 (1) save old WP to new R13
+ ALU_XOP, // 1
+ MEMORY_READ, // 1 (1) Read new PC
+ ALU_XOP, // 0 set new PC, set X flag
+ PREFETCH, // 1 (1)
+ ALU_NOP, // 1
+ ALU_NOP, // 1
END
};
MICROPROGRAM(xor_mp)
{
- OPERAND_ADDR,
- MEMORY_READ,
- ALU_F3,
- MEMORY_READ,
- ALU_F3,
- PREFETCH,
- MEMORY_WRITE,
+ OPERAND_ADDR, // x
+ MEMORY_READ, // 1 (1)
+ ALU_F3, // 0
+ MEMORY_READ, // 1 (1)
+ ALU_F3, // 0
+ PREFETCH, // 1 (1)
+ MEMORY_WRITE, // 1 (1)
END
};
@@ -1470,6 +1484,10 @@ void tms9995_device::next_command()
m_address = WP + ((m_instruction->IR & 0x000f)<<1);
MPC = -1;
if (VERBOSE>3) LOG("tms9995: ===== Next operation %04x (%s) at %04x =====\n", m_instruction->IR, opname[m_instruction->command], PC-2);
+#if TRACE_EXEC
+ if (m_servicing_interrupt) LOG("i%04x\n", PC-2);
+ else LOG("%04x\n", PC-2);
+#endif
PC_debug = PC - 2;
debugger_instruction_hook(this, PC_debug);
m_first_cycle = m_icount;
@@ -1609,6 +1627,9 @@ void tms9995_device::service_interrupt()
if (VERBOSE>6) LOG("tms9995: ********* triggered an interrupt with vector %04x/%04x\n", vectorpos, vectorpos+2);
+ // just for debugging purposes
+ m_servicing_interrupt = true;
+
// The microinstructions will do the context switch
m_address = vectorpos;
m_instruction->program = int_mp;
@@ -2632,7 +2653,6 @@ void tms9995_device::alu_f3()
if (VERBOSE>7) LOG("tms9995: ST = %04x\n", ST);
break;
}
- pulse_clock(1);
m_instruction->state++;
}
@@ -2729,7 +2749,6 @@ void tms9995_device::alu_jump()
if (VERBOSE>7) LOG("tms9995: Jump condition true\n");
PC = (PC + (displacement<<1)) & 0xfffe;
}
- pulse_clock(1);
}
/*
@@ -2858,7 +2877,7 @@ void tms9995_device::alu_multiply()
m_current_value = (result >> 16) & 0xffff;
m_value_copy = result & 0xffff;
// m_address is still the register
- n = 16;
+ n = 17;
break;
case 2:
m_address += 2;
@@ -2901,11 +2920,11 @@ void tms9995_device::alu_multiply()
void tms9995_device::alu_rtwp()
{
- int n = 0;
switch (m_instruction->state)
{
case 0:
m_address = WP + 30; // R15
+ pulse_clock(1);
break;
case 1:
ST = m_current_value;
@@ -2917,12 +2936,14 @@ void tms9995_device::alu_rtwp()
break;
case 3:
WP = m_current_value & 0xfffe;
- n = 1;
+
+ // Just for debugging purposes
+ m_servicing_interrupt = false;
+
if (VERBOSE>4) LOG("tms9995: RTWP restored old context (WP=%04x, PC=%04x, ST=%04x)\n", WP, PC, ST);
break;
}
m_instruction->state++;
- pulse_clock(n);
}
void tms9995_device::alu_sbo_sbz()
@@ -2969,12 +2990,13 @@ void tms9995_device::alu_shift()
{
// skip the next read operation
MPC++;
- pulse_clock(1);
}
else
{
if (VERBOSE>8) LOG("tms9995: Shift operation gets count from R0\n");
}
+ pulse_clock(1);
+ pulse_clock(1);
break;
case 1:
@@ -3020,7 +3042,6 @@ void tms9995_device::alu_shift()
break;
}
m_instruction->state++;
- pulse_clock(1);
}
/*
@@ -3217,7 +3238,6 @@ void tms9995_device::alu_x()
*/
void tms9995_device::alu_xop()
{
- int n = 1;
switch (m_instruction->state)
{
case 0:
@@ -3225,6 +3245,7 @@ void tms9995_device::alu_xop()
m_address_saved = m_address;
// Format is xxxx xxnn nnxx xxxx
m_address = 0x0040 + ((m_instruction->IR & 0x03c0)>>4);
+ pulse_clock(1);
break;
case 1:
// m_current_value is new WP
@@ -3232,30 +3253,33 @@ void tms9995_device::alu_xop()
WP = m_current_value & 0xfffe;
m_address = WP + 0x0016; // Address of new R11
m_current_value = m_address_saved;
+ pulse_clock(1);
break;
case 2:
m_address = WP + 0x001e;
m_current_value = ST;
+ pulse_clock(1);
break;
case 3:
m_address = WP + 0x001c;
m_current_value = PC;
+ pulse_clock(1);
break;
case 4:
m_address = WP + 0x001a;
m_current_value = m_value_copy;
+ pulse_clock(1);
break;
case 5:
m_address = 0x0042 + ((m_instruction->IR & 0x03c0)>>4);
+ pulse_clock(1);
break;
case 6:
PC = m_current_value & 0xfffe;
set_status_bit(ST_X, true);
- n = 0;
break;
}
m_instruction->state++;
- pulse_clock(n);
}
/*
diff --git a/src/emu/cpu/tms9900/tms9995.h b/src/emu/cpu/tms9900/tms9995.h
index f18b81ccf3d..5b2abedb2ea 100644
--- a/src/emu/cpu/tms9900/tms9995.h
+++ b/src/emu/cpu/tms9900/tms9995.h
@@ -174,6 +174,7 @@ private:
bool m_mid_active;
int m_decrementer_clkdiv;
+ bool m_servicing_interrupt;
// Flag field
int m_int_pending;