summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/tms9900
diff options
context:
space:
mode:
author Michael Zapf <Michael.Zapf@mizapf.de>2016-09-23 14:35:27 +0200
committer Michael Zapf <Michael.Zapf@mizapf.de>2016-09-23 14:36:38 +0200
commit72e7a9489f0475d049f940460994e3a90e8e36d6 (patch)
tree5ac90ef4cfd2c2d66dc3a92c0ef9dc98ea392e32 /src/devices/cpu/tms9900
parenta69576ee1892bbcdb327e7bace6802d591c7f3ae (diff)
Added save state support to tms99xx; replaced new/delete by unique_ptr.
Diffstat (limited to 'src/devices/cpu/tms9900')
-rw-r--r--src/devices/cpu/tms9900/tms9900.cpp148
-rw-r--r--src/devices/cpu/tms9900/tms9900.h24
-rw-r--r--src/devices/cpu/tms9900/tms9995.cpp364
-rw-r--r--src/devices/cpu/tms9900/tms9995.h53
4 files changed, 341 insertions, 248 deletions
diff --git a/src/devices/cpu/tms9900/tms9900.cpp b/src/devices/cpu/tms9900/tms9900.cpp
index 098af362040..eab6ffc8007 100644
--- a/src/devices/cpu/tms9900/tms9900.cpp
+++ b/src/devices/cpu/tms9900/tms9900.cpp
@@ -106,6 +106,8 @@
#include "tms9900.h"
+#define NOPRG -1
+
/* tms9900 ST register bits. */
enum
{
@@ -182,7 +184,9 @@ tms99xx_device::tms99xx_device(const machine_config &mconfig, device_type type,
m_iaq_line(*this),
m_get_intlevel(*this),
m_dbin_line(*this),
- m_external_operation(*this)
+ m_external_operation(*this),
+ m_program_index(NOPRG),
+ m_caller_index(NOPRG)
{
}
@@ -234,14 +238,53 @@ void tms99xx_device::device_start()
build_command_lookup_table();
- m_program = nullptr;
+ // Register persistable state variables
+ save_item(NAME(m_icount));
+ save_item(NAME(WP));
+ save_item(NAME(PC));
+ save_item(NAME(ST));
+ save_item(NAME(IR));
+ save_item(NAME(m_address));
+ save_item(NAME(m_current_value));
+ save_item(NAME(m_command));
+ save_item(NAME(m_byteop));
+ save_item(NAME(m_pass));
+ save_item(NAME(m_check_ready));
+ save_item(NAME(m_mem_phase));
+ save_item(NAME(m_load_state));
+ save_item(NAME(m_irq_state));
+ save_item(NAME(m_reset));
+ save_item(NAME(m_irq_level));
+ // save_item(NAME(m_first_cycle)); // only for log output
+ save_item(NAME(m_idle_state));
+ save_item(NAME(m_ready_bufd));
+ save_item(NAME(m_ready));
+ save_item(NAME(m_wait_state));
+ save_item(NAME(m_hold_state));
+ // save_item(NAME(m_state_any)); // only for debugger output
+ save_item(NAME(MPC));
+ save_item(NAME(m_program_index));
+ save_item(NAME(m_caller_index));
+ save_item(NAME(m_caller_MPC));
+ save_item(NAME(m_state));
+ save_item(NAME(m_hold_acknowledged));
+ save_item(NAME(m_source_even));
+ save_item(NAME(m_destination_even));
+ save_item(NAME(m_source_address));
+ save_item(NAME(m_source_value));
+ save_item(NAME(m_address_saved));
+ save_item(NAME(m_address_copy));
+ save_item(NAME(m_register_contents));
+ save_item(NAME(m_regnumber));
+ save_item(NAME(m_cru_address));
+ save_item(NAME(m_count));
+ save_item(NAME(m_value_copy));
+ save_item(NAME(m_value));
+ save_item(NAME(m_get_destination));
}
void tms99xx_device::device_stop()
{
- int k = 0;
- if (TRACE_SETUP) logerror("Deleting lookup tables\n");
- while (m_lotables[k]!=nullptr) delete[] m_lotables[k++];
}
/*
@@ -998,7 +1041,8 @@ const tms99xx_device::tms_instruction tms99xx_device::s_command[] =
{ 0xc000, MOV, 1, f1_mp },
{ 0xd000, MOVB, 1, f1_mp },
{ 0xe000, SOC, 1, f1_mp },
- { 0xf000, SOCB, 1, f1_mp }
+ { 0xf000, SOCB, 1, f1_mp },
+ { 0x0000, INTR, 1, int_mp} // special entry for the interrupt microprogram, not in lookup table
};
/*
@@ -1043,24 +1087,20 @@ void tms99xx_device::build_command_lookup_table()
int bitcount;
const tms_instruction *inst;
UINT16 opcode;
- int k = 0;
- m_command_lookup_table = new lookup_entry[16];
- // We use lotables as a list of allocated tables - to be able to delete them
- // at the end.
- m_lotables[k++] = m_command_lookup_table;
+ m_command_lookup_table = std::make_unique<lookup_entry[]>(16);
- lookup_entry* table = m_command_lookup_table;
+ lookup_entry* table = m_command_lookup_table.get();
for (int j=0; j < 16; j++)
{
- table[j].entry = nullptr;
table[j].next_digit = nullptr;
+ table[j].index = NOPRG;
}
do
{
inst = &s_command[i];
- table = m_command_lookup_table;
+ table = m_command_lookup_table.get();
if (TRACE_SETUP) logerror("=== opcode=%04x, len=%d\n", inst->opcode, format_mask_len[inst->format]);
bitcount = 4;
opcode = inst->opcode;
@@ -1072,12 +1112,11 @@ void tms99xx_device::build_command_lookup_table()
if (table[cmdindex].next_digit == nullptr)
{
if (TRACE_SETUP) 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;
+ table[cmdindex].next_digit = std::make_unique<lookup_entry[]>(16);
for (int j=0; j < 16; j++)
{
table[cmdindex].next_digit[j].next_digit = nullptr;
- table[cmdindex].next_digit[j].entry = nullptr;
+ table[cmdindex].next_digit[j].index = NOPRG;
}
}
else
@@ -1085,7 +1124,7 @@ void tms99xx_device::build_command_lookup_table()
if (TRACE_SETUP) logerror("found a table at bitcount=%d\n", bitcount);
}
- table = table[cmdindex].next_digit;
+ table = table[cmdindex].next_digit.get();
bitcount = bitcount+4;
opcode <<= 4;
@@ -1101,14 +1140,12 @@ void tms99xx_device::build_command_lookup_table()
for (int j=0; j < (1<<(bitcount-format_mask_len[inst->format])); j++)
{
if (TRACE_SETUP) logerror("opcode=%04x at position %d\n", inst->opcode, cmdindex+j);
- table[cmdindex+j].entry = inst;
+ table[cmdindex+j].index = i;
}
-
i++;
} while (inst->opcode != 0xf000);
- m_lotables[k++] = nullptr;
- if (TRACE_SETUP) logerror("Allocated %d tables\n", k);
+ m_interrupt_mp_index = i;
}
/*
@@ -1155,7 +1192,7 @@ void tms99xx_device::execute_run()
do
{
// Only when last instruction has completed
- if (m_program == nullptr)
+ if (m_program_index == NOPRG)
{
if (m_load_state)
{
@@ -1175,7 +1212,7 @@ void tms99xx_device::execute_run()
}
}
- if (m_program == nullptr && m_idle_state)
+ if (m_program_index == NOPRG && m_idle_state)
{
if (TRACE_WAIT) logerror("idle state\n");
pulse_clock(1);
@@ -1187,14 +1224,19 @@ void tms99xx_device::execute_run()
}
else
{
+ const UINT8* program = nullptr;
+ // When we are in the data derivation sequence, the caller_index is set
+ if (m_program_index != NOPRG)
+ program = (m_caller_index == NOPRG)? (UINT8*)s_command[m_program_index].prog : data_derivation;
+
// Handle HOLD
// A HOLD request is signalled through the input line HOLD.
// The hold state will be entered with the next non-memory access cycle.
if (m_hold_state &&
- (m_program==nullptr ||
- (m_program[MPC] != IAQ &&
- m_program[MPC] != MEMORY_READ && m_program[MPC] != MEMORY_WRITE &&
- m_program[MPC] != REG_READ && m_program[MPC] != REG_WRITE)))
+ (m_program_index == NOPRG ||
+ (program[MPC] != IAQ &&
+ program[MPC] != MEMORY_READ && program[MPC] != MEMORY_WRITE &&
+ program[MPC] != REG_READ && program[MPC] != REG_WRITE)))
{
if (TRACE_WAIT) logerror("hold\n");
if (!m_hold_acknowledged) acknowledge_hold();
@@ -1216,15 +1258,12 @@ void tms99xx_device::execute_run()
{
set_wait_state(false);
m_check_ready = false;
+ // If we don't have a microprogram, acquire the next instruction
+ UINT8 op = (m_program_index==NOPRG)? IAQ : program[MPC];
- if (m_program==nullptr) m_op = IAQ;
- else
- {
- m_op = m_program[MPC];
- }
- if (TRACE_MICRO) logerror("MPC = %d, m_op = %d\n", MPC, m_op);
+ if (TRACE_MICRO) logerror("MPC = %d, op = %d\n", MPC, op);
// Call the operation of the microprogram
- (this->*s_microoperation[m_op])();
+ (this->*s_microoperation[op])();
// If we have multiple passes (as in the TMS9980)
m_pass--;
if (m_pass<=0)
@@ -1287,7 +1326,8 @@ int tms99xx_device::get_intlevel(int state)
void tms99xx_device::service_interrupt()
{
- m_program = int_mp;
+ m_program_index = m_interrupt_mp_index;
+
m_command = INTR;
m_idle_state = false;
if (!m_external_operation.isnull()) m_external_operation(IDLE_OP, 0, 0xff);
@@ -1402,11 +1442,10 @@ inline void tms99xx_device::set_wait_state(bool state)
*/
void tms99xx_device::decode(UINT16 inst)
{
- int index = 0;
- lookup_entry* table = m_command_lookup_table;
+ int ix = 0;
+ lookup_entry* table = m_command_lookup_table.get();
UINT16 opcode = inst;
bool complete = false;
- const tms_instruction *decoded;
m_state = 0;
IR = inst;
@@ -1415,35 +1454,34 @@ void tms99xx_device::decode(UINT16 inst)
while (!complete)
{
- index = (opcode >> 12) & 0x000f;
- if (TRACE_MICRO) logerror("Check next hex digit of instruction %x\n", index);
- if (table[index].next_digit != nullptr)
+ ix = (opcode >> 12) & 0x000f;
+ if (TRACE_MICRO) logerror("Check next hex digit of instruction %x\n", ix);
+ if (table[ix].next_digit != nullptr)
{
- table = table[index].next_digit;
+ table = table[ix].next_digit.get();
opcode = opcode << 4;
}
else complete = true;
}
- decoded = table[index].entry;
- if (decoded == nullptr)
+ m_program_index = table[ix].index;
+ if (m_program_index == NOPRG)
{
// not found
logerror("Address %04x: Illegal opcode %04x\n", PC, inst);
IR = 0;
// This will cause another instruction acquisition in the next machine cycle
// with an asserted IAQ line (can be used to indicate this illegal opcode detection).
- m_program = nullptr;
}
else
{
- m_program = decoded->prog;
+ const tms_instruction decoded = s_command[m_program_index];
MPC = -1;
- m_command = decoded->id;
- if (TRACE_MICRO) logerror("Command decoded as id %d, %s, base opcode %04x\n", m_command, opname[m_command], decoded->opcode);
+ m_command = decoded.id;
+ if (TRACE_MICRO) logerror("Command decoded as id %d, %s, base opcode %04x\n", m_command, opname[m_command], decoded.opcode);
// Byte operations are either format 1 with the byte flag set
// or format 4 (CRU multi bit operations) with 1-8 bits to transfer.
- m_byteop = ((decoded->format==1 && ((IR & 0x1000)!=0))
- || (decoded->format==4 && (((IR >> 6)&0x000f) > 0) && (((IR >> 6)&0x000f) > 9)));
+ m_byteop = ((decoded.format==1 && ((IR & 0x1000)!=0))
+ || (decoded.format==4 && (((IR >> 6)&0x000f) > 0) && (((IR >> 6)&0x000f) > 9)));
}
m_pass = 1;
}
@@ -1646,7 +1684,8 @@ void tms99xx_device::return_from_subprogram()
// Return from data derivation
// The result should be in m_current_value
// and the address in m_address
- m_program = m_caller;
+ m_program_index = m_caller_index;
+ m_caller_index = NOPRG;
MPC = m_caller_MPC; // will be increased on return
}
@@ -1661,7 +1700,7 @@ void tms99xx_device::command_completed()
if (cycles > 0 && cycles < 10000) logerror(" %d cycles", cycles);
logerror("\n");
}
- m_program = nullptr;
+ m_program_index = NOPRG;
}
/*
@@ -1674,7 +1713,7 @@ void tms99xx_device::data_derivation_subprogram()
UINT16 ircopy = IR;
// Save the return program and position
- m_caller = m_program;
+ m_caller_index = m_program_index;
m_caller_MPC = MPC;
// Source or destination argument?
@@ -1682,7 +1721,6 @@ void tms99xx_device::data_derivation_subprogram()
m_regnumber = ircopy & 0x000f;
- m_program = (UINT8*)data_derivation;
MPC = ircopy & 0x0030;
if (((MPC == 0x0020) && (m_regnumber != 0)) // indexed
diff --git a/src/devices/cpu/tms9900/tms9900.h b/src/devices/cpu/tms9900/tms9900.h
index 4669eeb439a..1104a29e4d4 100644
--- a/src/devices/cpu/tms9900/tms9900.h
+++ b/src/devices/cpu/tms9900/tms9900.h
@@ -133,9 +133,6 @@ protected:
// single-bit accesses. (Needed for TMS9980)
int m_pass;
- // Data bus width. Needed for TMS9980.
- int m_databus_width;
-
// Check the READY line?
bool m_check_ready;
@@ -254,15 +251,12 @@ private:
// Lookup table entry
struct lookup_entry
{
- lookup_entry *next_digit;
- const tms_instruction *entry;
+ std::unique_ptr<lookup_entry[]> next_digit;
+ int index; // pointing to the static instruction list
};
// Pointer to the lookup table
- lookup_entry* m_command_lookup_table;
-
- // List of allocated tables (used for easy clean-up on exit)
- lookup_entry* m_lotables[32];
+ std::unique_ptr<lookup_entry[]> m_command_lookup_table;
// List of pointers for micro-operations
static const tms99xx_device::ophandler s_microoperation[];
@@ -321,18 +315,18 @@ private:
void abort_operation(void);
- // Micro-operation
- UINT8 m_op;
-
// Micro-operation program counter (as opposed to the program counter PC)
int MPC;
// Current microprogram
- const UINT8* m_program;
+ int m_program_index;
// Calling microprogram (used when data derivation is called)
- const UINT8* m_caller;
- int m_caller_MPC;
+ int m_caller_index;
+ int m_caller_MPC;
+
+ // Index of the interrupt program
+ int m_interrupt_mp_index;
// State of the micro-operation. Needed for repeated ALU calls.
int m_state;
diff --git a/src/devices/cpu/tms9900/tms9995.cpp b/src/devices/cpu/tms9900/tms9995.cpp
index 0e175663473..52e482efaa5 100644
--- a/src/devices/cpu/tms9900/tms9995.cpp
+++ b/src/devices/cpu/tms9900/tms9995.cpp
@@ -91,6 +91,8 @@
#include "tms9995.h"
+#define NOPRG -1
+
/* tms9995 ST register bits. */
enum
{
@@ -269,13 +271,76 @@ void tms9995_device::device_start()
build_command_lookup_table();
if (TRACE_CONFIG) logerror("%s: Variant = %s, Overflow int = %s\n", tag(), m_mp9537? "MP9537 (no on-chip RAM)" : "with on-chip RAM", m_check_overflow? "check" : "no check");
+
+ // Register persistable state variables
+ // save_item(NAME(m_state_any)); // only for debugger output
+ save_item(NAME(WP));
+ save_item(NAME(PC));
+ save_item(NAME(ST));
+ // save_item(NAME(PC_debug)); // only for debugger output
+ save_pointer(NAME(m_onchip_memory),256);
+ save_item(NAME(m_idle_state));
+ save_item(NAME(m_nmi_state));
+ save_item(NAME(m_hold_state));
+ save_item(NAME(m_hold_requested));
+ save_item(NAME(m_ready_bufd));
+ save_item(NAME(m_ready));
+ save_item(NAME(m_request_auto_wait_state));
+ save_item(NAME(m_auto_wait));
+ save_item(NAME(m_icount));
+ save_item(NAME(m_mem_phase));
+ save_item(NAME(m_check_ready));
+ save_item(NAME(m_check_hold));
+ save_item(NAME(m_pass));
+ save_item(NAME(m_get_destination));
+ save_item(NAME(m_word_access));
+ save_item(NAME(m_nmi_active));
+ save_item(NAME(m_int1_active));
+ save_item(NAME(m_int4_active));
+ save_item(NAME(m_int_decrementer));
+ save_item(NAME(m_int_overflow));
+ save_item(NAME(m_reset));
+ save_item(NAME(m_from_reset));
+ save_item(NAME(m_mid_flag));
+ save_item(NAME(m_mid_active));
+ save_item(NAME(m_decrementer_clkdiv));
+ save_item(NAME(m_servicing_interrupt));
+ save_item(NAME(m_int_pending));
+ save_item(NAME(m_check_overflow));
+ save_item(NAME(m_intmask));
+ save_item(NAME(m_address));
+ save_item(NAME(m_current_value));
+ save_item(NAME(m_source_value));
+ save_item(NAME(m_address_add));
+ save_item(NAME(m_address_saved));
+ save_item(NAME(m_address_copy));
+ save_item(NAME(m_value_copy));
+ save_item(NAME(m_regnumber));
+ save_item(NAME(m_count));
+ save_item(NAME(m_starting_count_storage_register));
+ save_item(NAME(m_decrementer_value));
+ save_item(NAME(m_cru_address));
+ save_item(NAME(m_cru_value));
+ save_item(NAME(m_cru_first_read));
+ save_item(NAME(m_cru_bits_left));
+ save_item(NAME(m_cru_read));
+ save_pointer(NAME(m_flag),16);
+ save_item(NAME(IR));
+ save_item(NAME(m_pre_IR));
+ save_item(NAME(m_command));
+ save_item(NAME(m_pre_command));
+ save_item(NAME(m_index));
+ save_item(NAME(m_pre_index));
+ save_item(NAME(m_byteop));
+ save_item(NAME(m_pre_byteop));
+ save_item(NAME(m_inst_state));
+ save_item(NAME(MPC));
+ save_item(NAME(m_caller_MPC));
+ // save_item(NAME(m_first_cycle)); // only for log output
}
void tms9995_device::device_stop()
{
- int k = 0;
- if (TRACE_EMU) logerror("%s: Deleting lookup tables\n", tag());
- while (m_lotables[k]!=nullptr) delete[] m_lotables[k++];
}
/*
@@ -328,7 +393,7 @@ void tms9995_device::state_import(const device_state_entry &entry)
ST = (UINT16)m_state_any;
break;
case TMS9995_IR:
- m_instruction->IR = (UINT16)m_state_any;
+ IR = (UINT16)m_state_any;
break;
default:
// Workspace registers
@@ -359,7 +424,7 @@ void tms9995_device::state_export(const device_state_entry &entry)
m_state_any = ST;
break;
case TMS9995_IR:
- m_state_any = m_instruction->IR;
+ m_state_any = IR;
break;
default:
// Workspace registers
@@ -988,7 +1053,7 @@ enum
LIMI, LREX, LST, LWP, LWPI, MOV, MOVB, MPY, MPYS, NEG,
ORI, RSET, RTWP, S, SB, SBO, SBZ, SETO, SLA, SOC,
SOCB, SRA, SRC, SRL, STCR, STST, STWP, SWPB, SZC, SZCB,
- TB, X, XOP, XOR, INTR
+ TB, X, XOP, XOR, INTR, OPAD
};
static const char opname[][5] =
@@ -999,7 +1064,7 @@ static const char opname[][5] =
"LIMI", "LREX", "LST ", "LWP ", "LWPI", "MOV ", "MOVB", "MPY ", "MPYS", "NEG ",
"ORI ", "RSET", "RTWP", "S ", "SB ", "SBO ", "SBZ ", "SETO", "SLA ", "SOC ",
"SOCB", "SRA ", "SRC ", "SRL ", "STCR", "STST", "STWP", "SWPB", "SZC ", "SZCB",
- "TB ", "X ", "XOP ", "XOR ", "*int"
+ "TB ", "X ", "XOP ", "XOR ", "*int", "*oad"
};
/*
@@ -1116,7 +1181,11 @@ const tms9995_device::tms_instruction tms9995_device::s_command[] =
{ 0xc000, MOV, 1, mov_mp },
{ 0xd000, MOVB, 1, mov_mp },
{ 0xe000, SOC, 1, add_s_sxc_mp },
- { 0xf000, SOCB, 1, add_s_sxc_mp }
+ { 0xf000, SOCB, 1, add_s_sxc_mp },
+
+// Special entries for interrupt and the address derivation subprogram; not in lookup table
+ { 0x0000, INTR, 1, int_mp},
+ { 0x0000, OPAD, 1, operand_address_derivation }
};
/*
@@ -1132,24 +1201,20 @@ void tms9995_device::build_command_lookup_table()
int bitcount;
const tms_instruction *inst;
UINT16 opcode;
- int k = 0;
- m_command_lookup_table = new lookup_entry[16];
- // We use lotables as a list of allocated tables - to be able to delete them
- // at the end.
- m_lotables[k++] = m_command_lookup_table;
+ m_command_lookup_table = std::make_unique<lookup_entry[]>(16);
- lookup_entry* table = m_command_lookup_table;
+ lookup_entry* table = m_command_lookup_table.get();
for (int j=0; j < 16; j++)
{
- table[j].entry = nullptr;
table[j].next_digit = nullptr;
+ table[j].index = NOPRG;
}
do
{
inst = &s_command[i];
- table = m_command_lookup_table;
+ table = m_command_lookup_table.get();
if (TRACE_EMU) logerror("=== opcode=%04x, len=%d\n", inst->opcode, format_mask_len[inst->format]);
bitcount = 4;
opcode = inst->opcode;
@@ -1161,12 +1226,11 @@ void tms9995_device::build_command_lookup_table()
if (table[cmdindex].next_digit == nullptr)
{
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;
+ table[cmdindex].next_digit = std::make_unique<lookup_entry[]>(16);
for (int j=0; j < 16; j++)
{
table[cmdindex].next_digit[j].next_digit = nullptr;
- table[cmdindex].next_digit[j].entry = nullptr;
+ table[cmdindex].next_digit[j].index = NOPRG;
}
}
else
@@ -1174,7 +1238,7 @@ void tms9995_device::build_command_lookup_table()
if (TRACE_EMU) logerror("found a table at bitcount=%d\n", bitcount);
}
- table = table[cmdindex].next_digit;
+ table = table[cmdindex].next_digit.get();
bitcount = bitcount+4;
opcode <<= 4;
@@ -1190,14 +1254,15 @@ void tms9995_device::build_command_lookup_table()
for (int j=0; j < (1<<(bitcount-format_mask_len[inst->format])); j++)
{
if (TRACE_EMU) logerror("opcode=%04x at position %d\n", inst->opcode, cmdindex+j);
- table[cmdindex+j].entry = inst;
+ table[cmdindex+j].index = i;
}
i++;
} while (inst->opcode != 0xf000);
- m_lotables[k++] = nullptr;
- if (TRACE_EMU) logerror("Allocated %d tables\n", k);
+ // Save the index to these two special microprograms
+ m_interrupt_mp_index = i++;
+ m_operand_address_derivation_index = i;
}
/*
@@ -1238,8 +1303,9 @@ void tms9995_device::execute_run()
m_check_ready = false;
- if (TRACE_MICRO) logerror("main loop, operation %s, MPC = %d\n", opname[m_instruction->command], MPC);
- (this->*s_microoperation[m_instruction->program[MPC]])();
+ if (TRACE_MICRO) logerror("main loop, operation %s, MPC = %d\n", opname[m_command], MPC);
+ UINT8* program = (UINT8*)s_command[m_index].prog;
+ (this->*s_microoperation[program[MPC]])();
// For multi-pass operations where the MPC should not advance
// or when we have put in a new microprogram
@@ -1404,43 +1470,42 @@ void tms9995_device::set_hold_state(bool state)
*/
void tms9995_device::decode(UINT16 inst)
{
- int index = 0;
- lookup_entry* table = m_command_lookup_table;
+ int ix = 0;
+ lookup_entry* table = m_command_lookup_table.get();
UINT16 opcode = inst;
bool complete = false;
- const tms_instruction *decoded;
-
- int dindex = (m_instindex==0)? 1:0;
m_mid_active = false;
while (!complete)
{
- index = (opcode >> 12) & 0x000f;
- if (TRACE_EMU) logerror("Check next hex digit of instruction %x\n", index);
- if (table[index].next_digit != nullptr)
+ ix = (opcode >> 12) & 0x000f;
+ if (TRACE_EMU) logerror("Check next hex digit of instruction %x\n", ix);
+ if (table[ix].next_digit != nullptr)
{
- table = table[index].next_digit;
+ table = table[ix].next_digit.get();
opcode = opcode << 4;
}
else complete = true;
}
- decoded = table[index].entry;
- if (decoded == nullptr)
+
+ int program_index = table[ix].index;
+ if (program_index == NOPRG)
{
// not found
logerror("Undefined opcode %04x at logical address %04x, will trigger MID\n", inst, PC);
- m_decoded[dindex].IR = 0;
- m_decoded[dindex].command = MID;
+ m_pre_IR = 0;
+ m_pre_command = MID;
}
else
{
- m_decoded[dindex].IR = inst;
- m_decoded[dindex].command = decoded->id;
- 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("Command decoded as id %d, %s, base opcode %04x\n", decoded->id, opname[decoded->id], decoded->opcode);
+ const tms_instruction decoded = s_command[program_index];
+
+ m_pre_IR = inst;
+ m_pre_command = decoded.id;
+ m_pre_index = program_index;
+ m_pre_byteop = ((decoded.format == 1) && ((inst & 0x1000)!=0));
+ if (TRACE_EMU) logerror("Command decoded as id %d, %s, base opcode %04x\n", decoded.id, opname[decoded.id], decoded.opcode);
m_pass = 1;
}
}
@@ -1453,7 +1518,6 @@ void tms9995_device::decode(UINT16 inst)
*/
void tms9995_device::int_prefetch_and_decode()
{
- bool check_int = (m_instruction->command != XOP && m_instruction->command != BLWP);
int intmask = ST & 0x000f;
if (m_mem_phase == 1)
@@ -1470,8 +1534,8 @@ void tms9995_device::int_prefetch_and_decode()
else
{
m_int_pending = 0;
-
- if (check_int)
+ // If the current command is XOP or BLWP, ignore the interrupt
+ if (m_command != XOP && m_command != BLWP)
{
if (m_int1_active && intmask >= 1) m_int_pending |= PENDING_LEVEL1;
if (m_int_overflow && intmask >= 2) m_int_pending |= PENDING_OVERFLOW;
@@ -1550,9 +1614,15 @@ void tms9995_device::prefetch_and_decode()
*/
void tms9995_device::next_command()
{
- int next = (m_instindex==0)? 1:0;
+ // Copy the prefetched results
+ IR = m_pre_IR;
+ m_command = m_pre_command;
+ m_index = m_pre_index;
+ m_byteop = m_pre_byteop;
- if (m_decoded[next].command == MID)
+ m_inst_state = 0;
+
+ if (m_command == MID)
{
m_mid_flag = true;
m_mid_active = true;
@@ -1560,13 +1630,11 @@ void tms9995_device::next_command()
}
else
{
- m_instindex = next;
- m_instruction = &m_decoded[m_instindex];
m_get_destination = false;
// 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 + ((IR & 0x000f)<<1);
MPC = -1;
- if (TRACE_OP) logerror("===== 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", IR, opname[m_command], PC-2);
if (TRACE_EXEC)
{
@@ -1587,7 +1655,7 @@ void tms9995_device::command_completed()
// Pseudo state at the end of the current instruction cycle sequence
if (TRACE_CYCLES)
{
- logerror("+++++ Instruction %04x (%s) completed", m_instruction->IR, opname[m_instruction->command]);
+ logerror("+++++ Instruction %04x (%s) completed", IR, opname[m_command]);
int cycles = m_first_cycle - m_icount;
// Avoid nonsense values due to expired and resumed main loop
if (cycles > 0 && cycles < 10000) logerror(", consumed %d cycles", cycles);
@@ -1595,19 +1663,13 @@ void tms9995_device::command_completed()
}
if (m_int_pending != 0)
- {
service_interrupt();
- }
else
{
if ((ST & ST_OE)!=0 && (ST & ST_OV)!=0 && (ST & 0x000f)>2)
- {
service_interrupt();
- }
else
- {
next_command();
- }
}
}
@@ -1634,8 +1696,6 @@ void tms9995_device::service_interrupt()
m_decrementer_clkdiv = 0;
m_pass = 0;
- m_instindex = 0;
- m_instruction = &m_decoded[m_instindex];
memset(m_flag, 0, sizeof(m_flag));
@@ -1718,16 +1778,18 @@ void tms9995_device::service_interrupt()
// The microinstructions will do the context switch
m_address = vectorpos;
- m_instruction->program = int_mp;
- m_instruction->state = 0;
- m_instruction->byteop = false;
- m_instruction->command = INTR;
+
+ m_index = m_interrupt_mp_index;
+ m_inst_state = 0;
+ m_byteop = false;
+ m_command = INTR;
+
m_pass = m_reset? 1 : 2;
m_from_reset = m_reset;
if (m_reset)
{
- m_instruction->IR = 0x0000;
+ IR = 0x0000;
m_reset = false;
}
MPC = 0;
@@ -1764,7 +1826,7 @@ void tms9995_device::mem_read()
if (TRACE_DEC) logerror("read decrementer\n");
// Decrementer mapped into the address space
m_current_value = m_decrementer_value;
- if (m_instruction->byteop)
+ if (m_byteop)
{
if ((m_address & 1)!=1) m_current_value <<= 8;
m_current_value &= 0xff00;
@@ -1778,7 +1840,7 @@ void tms9995_device::mem_read()
// If we have a word access, we have to align the address
// This is the case for word operations and for certain phases of
// byte operations (e.g. when retrieving the index register)
- if (m_word_access || !m_instruction->byteop) m_address &= 0xfffe;
+ if (m_word_access || !m_byteop) m_address &= 0xfffe;
if (TRACE_MEM) logerror("read onchip memory (single pass, address %04x)\n", m_address);
@@ -1786,7 +1848,7 @@ void tms9995_device::mem_read()
m_check_ready = false;
// We put fffc-ffff back into the f000-f0ff area
m_current_value = m_onchip_memory[m_address & 0x00ff]<<8;
- if (m_word_access || !m_instruction->byteop)
+ if (m_word_access || !m_byteop)
{
// We have a word operation; add the low byte right here (just 1 cycle)
m_current_value |= (m_onchip_memory[(m_address & 0x00ff)+1] & 0xff);
@@ -1806,7 +1868,7 @@ void tms9995_device::mem_read()
// Set address
// If this is a word access, 4 passes, else 2 passes
if (!m_dbin_line.isnull()) m_dbin_line(ASSERT_LINE);
- if (m_word_access || !m_instruction->byteop)
+ if (m_word_access || !m_byteop)
{
m_pass = 4;
// For word accesses, we always start at the even address
@@ -1822,7 +1884,7 @@ void tms9995_device::mem_read()
break;
case 2:
// Sample the value on the data bus (high byte)
- if (m_word_access || !m_instruction->byteop) address &= 0xfffe;
+ if (m_word_access || !m_byteop) address &= 0xfffe;
value = m_prgspace->read_byte(address);
if (TRACE_MEM) logerror("memory read byte %04x -> %02x\n", m_address & ~1, value);
m_current_value = (value << 8) & 0xff00;
@@ -1888,7 +1950,7 @@ void tms9995_device::mem_write()
{
if ((m_address & 0xfffe)==0xfffa && !m_mp9537)
{
- if (m_instruction->byteop)
+ if (m_byteop)
{
// According to [1], section 2.3.1.2.2:
// "The decrementer should always be accessed as a full word. [...]
@@ -1916,12 +1978,12 @@ void tms9995_device::mem_write()
// If we have a word access, we have to align the address
// This is the case for word operations and for certain phases of
// byte operations (e.g. when retrieving the index register)
- if (m_word_access || !m_instruction->byteop) m_address &= 0xfffe;
+ if (m_word_access || !m_byteop) m_address &= 0xfffe;
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)
+ if (m_word_access || !m_byteop)
{
m_onchip_memory[(m_address & 0x00ff)+1] = m_current_value & 0xff;
}
@@ -1939,7 +2001,7 @@ void tms9995_device::mem_write()
// If this is a word access, 4 passes, else 2 passes
if (!m_dbin_line.isnull()) m_dbin_line(CLEAR_LINE);
- if (m_word_access || !m_instruction->byteop)
+ if (m_word_access || !m_byteop)
{
m_pass = 4;
address &= 0xfffe;
@@ -2000,7 +2062,7 @@ void tms9995_device::return_with_address()
{
// Return from operand address derivation
// The result should be in m_address
- m_instruction->program = m_caller;
+ m_index = m_caller_index;
MPC = m_caller_MPC; // will be increased on return
m_address = m_current_value + m_address_add;
if (TRACE_DETAIL) logerror("+++ return from operand address derivation +++\n");
@@ -2014,7 +2076,7 @@ void tms9995_device::return_with_address()
void tms9995_device::return_with_address_copy()
{
// Return from operand address derivation
- m_instruction->program = m_caller;
+ m_index = m_caller_index;
MPC = m_caller_MPC; // will be increased on return
m_address = m_address_saved;
if (TRACE_DETAIL) logerror("+++ return from operand address derivation (auto inc) +++\n");
@@ -2138,7 +2200,6 @@ void tms9995_device::cru_input_operation()
{
m_cru_read >>= offset;
m_cru_bits_left -= offset;
- m_parity = 0;
m_cru_value = 0;
m_cru_first_read = false;
m_pass = m_count;
@@ -2172,7 +2233,6 @@ void tms9995_device::cru_input_operation()
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++;
m_cru_address = (m_cru_address + 2) & 0xfffe;
m_cru_bits_left--;
@@ -2219,7 +2279,7 @@ void tms9995_device::trigger_decrementer()
input:
m_get_destination
- m_instruction
+ m_decoded[m_instindex]
WP
m_current_value
m_address
@@ -2234,14 +2294,14 @@ void tms9995_device::trigger_decrementer()
*/
void tms9995_device::operand_address_subprogram()
{
- UINT16 ircopy = m_instruction->IR;
+ UINT16 ircopy = IR;
if (m_get_destination) ircopy = ircopy >> 6;
// Save the return program and position
- m_caller = m_instruction->program;
+ m_caller_index = m_index;
m_caller_MPC = MPC;
- m_instruction->program = (UINT8*)operand_address_derivation;
+ m_index = m_operand_address_derivation_index;
MPC = (ircopy & 0x0030) >> 2;
m_regnumber = (ircopy & 0x000f);
m_address = (WP + (m_regnumber<<1)) & 0xffff;
@@ -2278,7 +2338,7 @@ void tms9995_device::operand_address_subprogram()
void tms9995_device::increment_register()
{
m_address_saved = m_current_value; // need a special return so we do not lose the value
- m_current_value += m_instruction->byteop? 1 : 2;
+ m_current_value += m_byteop? 1 : 2;
m_address = (WP + (m_regnumber<<1)) & 0xffff;
m_mem_phase = 1;
pulse_clock(1);
@@ -2301,7 +2361,7 @@ void tms9995_device::indexed_addressing()
void tms9995_device::set_immediate()
{
// Need to determine the register address
- m_address_saved = WP + ((m_instruction->IR & 0x000f)<<1);
+ m_address_saved = WP + ((IR & 0x000f)<<1);
m_address = PC;
m_source_value = m_current_value; // needed for AI, ANDI, ORI
PC = (PC + 2) & 0xfffe;
@@ -2364,7 +2424,7 @@ void tms9995_device::alu_add_s_sxc()
UINT32 dest_new = 0;
- switch (m_instruction->command)
+ switch (m_command)
{
case A:
case AB:
@@ -2406,7 +2466,7 @@ void tms9995_device::alu_add_s_sxc()
m_current_value = (UINT16)(dest_new & 0xffff);
compare_and_set_lae((UINT16)(dest_new & 0xffff),0);
- if (m_instruction->byteop)
+ if (m_byteop)
{
set_status_parity((UINT8)(dest_new>>8));
}
@@ -2433,7 +2493,7 @@ void tms9995_device::alu_b()
void tms9995_device::alu_blwp()
{
int n = 1;
- switch (m_instruction->state)
+ switch (m_inst_state)
{
case 0:
// new WP in m_current_value
@@ -2460,7 +2520,7 @@ void tms9995_device::alu_blwp()
if (TRACE_OP) logerror("Context switch complete; WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST);
break;
}
- m_instruction->state++;
+ m_inst_state++;
pulse_clock(n);
}
@@ -2473,7 +2533,7 @@ void tms9995_device::alu_c()
// value in m_current_value
// The destination address is still in m_address
// Prefetch will not change m_current_value and m_address
- if (m_instruction->byteop)
+ if (m_byteop)
{
set_status_parity((UINT8)(m_source_value>>8));
}
@@ -2495,7 +2555,7 @@ void tms9995_device::alu_ci()
void tms9995_device::alu_clr_seto()
{
if (TRACE_OP) logerror("clr/seto: Setting values for address %04x\n", m_address);
- switch (m_instruction->command)
+ switch (m_command)
{
case CLR:
m_current_value = 0;
@@ -2518,12 +2578,12 @@ void tms9995_device::alu_divide()
bool overflow = true;
UINT16 value1;
- switch (m_instruction->state)
+ switch (m_inst_state)
{
case 0:
m_source_value = m_current_value;
// Set address of register
- m_address = WP + ((m_instruction->IR >> 5) & 0x001e);
+ m_address = WP + ((IR >> 5) & 0x001e);
m_address_copy = m_address;
break;
case 1:
@@ -2569,7 +2629,7 @@ void tms9995_device::alu_divide()
m_address = m_address + 2;
break;
}
- m_instruction->state++;
+ m_inst_state++;
pulse_clock(n);
}
@@ -2588,7 +2648,7 @@ void tms9995_device::alu_divide_signed()
INT16 divisor;
INT32 dividend;
- switch (m_instruction->state)
+ switch (m_inst_state)
{
case 0:
// Got the source value (divisor)
@@ -2671,7 +2731,7 @@ void tms9995_device::alu_divide_signed()
n = 0;
break;
}
- m_instruction->state++;
+ m_inst_state++;
pulse_clock(n);
}
@@ -2701,19 +2761,20 @@ void tms9995_device::alu_external()
// external code on the data bus. A special line decoder could then trigger
// a reset from outside.
- if (m_instruction->command == IDLE)
+ if (m_command == IDLE)
{
if (TRACE_OP) logerror("Entering IDLE state\n");
m_idle_state = true;
}
- if (m_instruction->command == RSET)
+ if (m_command == RSET)
{
ST &= 0xfff0;
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((IR >> 5) & 0x07, 1, 0xff);
}
/*
@@ -2721,25 +2782,25 @@ void tms9995_device::alu_external()
*/
void tms9995_device::alu_f3()
{
- switch (m_instruction->state)
+ switch (m_inst_state)
{
case 0:
// We have the contents of the source in m_current_value and its address
// in m_address
m_source_value = m_current_value;
// Get register address
- m_address = WP + ((m_instruction->IR >> 5) & 0x001e);
+ m_address = WP + ((IR >> 5) & 0x001e);
break;
case 1:
// Register contents -> m_current_value
// Source contents -> m_source_value
- if (m_instruction->command == COC)
+ if (m_command == COC)
{
set_status_bit(ST_EQ, (m_current_value & m_source_value) == m_source_value);
}
else
{
- if (m_instruction->command == CZC)
+ if (m_command == CZC)
{
set_status_bit(ST_EQ, (~m_current_value & m_source_value) == m_source_value);
}
@@ -2754,7 +2815,7 @@ void tms9995_device::alu_f3()
if (TRACE_STATUS) logerror("ST = %04x\n", ST);
break;
}
- m_instruction->state++;
+ m_inst_state++;
}
/*
@@ -2766,7 +2827,7 @@ void tms9995_device::alu_imm_arithm()
// We have the register value in m_source_value, the register address in m_address_saved
// and the immediate value in m_current_value
- switch (m_instruction->command)
+ switch (m_command)
{
case AI:
dest_new = m_current_value + m_source_value;
@@ -2796,9 +2857,9 @@ void tms9995_device::alu_imm_arithm()
void tms9995_device::alu_jump()
{
bool cond = false;
- INT8 displacement = (m_instruction->IR & 0xff);
+ INT8 displacement = (IR & 0xff);
- switch (m_instruction->command)
+ switch (m_command)
{
case JMP:
cond = true;
@@ -2857,18 +2918,21 @@ void tms9995_device::alu_jump()
*/
void tms9995_device::alu_ldcr()
{
- switch (m_instruction->state)
+ switch (m_inst_state)
{
case 0:
- m_count = (m_instruction->IR >> 6) & 0x000f;
+ m_count = (IR >> 6) & 0x000f;
if (m_count==0) m_count = 16;
- m_instruction->byteop = (m_count<9);
+ m_byteop = (m_count<9);
break;
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("ST = %04x (val=%04x)\n", ST, m_current_value);
- if (m_instruction->byteop)
+
+ // Parity is computed from the complete byte, even when less than
+ // 8 bits are transferred (see [1]).
+ if (m_byteop)
{
m_current_value = (m_current_value>>8) & 0xff;
set_status_parity((UINT8)m_current_value);
@@ -2881,7 +2945,7 @@ void tms9995_device::alu_ldcr()
m_cru_address = m_current_value;
break;
}
- m_instruction->state++;
+ m_inst_state++;
pulse_clock(1);
}
@@ -2902,7 +2966,7 @@ void tms9995_device::alu_li()
void tms9995_device::alu_limi_lwpi()
{
// The immediate value is in m_current_value
- if (m_instruction->command == LIMI)
+ if (m_command == LIMI)
{
ST = (ST & 0xfff0) | (m_current_value & 0x000f);
if (TRACE_OP) logerror("LIMI sets ST = %04x\n", ST);
@@ -2921,7 +2985,7 @@ void tms9995_device::alu_limi_lwpi()
*/
void tms9995_device::alu_lst_lwp()
{
- if (m_instruction->command==LST)
+ if (m_command==LST)
{
ST = m_current_value;
if (TRACE_OP) logerror("new ST = %04x\n", ST);
@@ -2943,7 +3007,7 @@ void tms9995_device::alu_lst_lwp()
void tms9995_device::alu_mov()
{
m_current_value = m_source_value;
- if (m_instruction->byteop)
+ if (m_byteop)
{
set_status_parity((UINT8)(m_current_value>>8));
}
@@ -2961,15 +3025,15 @@ void tms9995_device::alu_multiply()
UINT32 result;
INT32 results;
- if (m_instruction->command==MPY)
+ if (m_command==MPY)
{
- switch (m_instruction->state)
+ switch (m_inst_state)
{
case 0:
// m_current_value <- multiplier (source)
m_source_value = m_current_value;
// m_address is the second multiplier (in a register)
- m_address = ((m_instruction->IR >> 5) & 0x001e) + WP;
+ m_address = ((IR >> 5) & 0x001e) + WP;
n = 1;
break;
case 1:
@@ -2989,9 +3053,9 @@ void tms9995_device::alu_multiply()
break;
}
}
- else
+ else // MPYS
{
- switch (m_instruction->state)
+ switch (m_inst_state)
{
case 0:
// m_current_value <- multiplier (source)
@@ -3015,13 +3079,13 @@ void tms9995_device::alu_multiply()
break;
}
}
- m_instruction->state++;
+ m_inst_state++;
pulse_clock(n);
}
void tms9995_device::alu_rtwp()
{
- switch (m_instruction->state)
+ switch (m_inst_state)
{
case 0:
m_address = WP + 30; // R15
@@ -3044,25 +3108,25 @@ void tms9995_device::alu_rtwp()
if (TRACE_OP) logerror("RTWP restored old context (WP=%04x, PC=%04x, ST=%04x)\n", WP, PC, ST);
break;
}
- m_instruction->state++;
+ m_inst_state++;
}
void tms9995_device::alu_sbo_sbz()
{
INT8 displacement;
- if (m_instruction->state==0)
+ if (m_inst_state==0)
{
m_address = WP + 24;
}
else
{
- m_cru_value = (m_instruction->command==SBO)? 1 : 0;
- displacement = (INT8)(m_instruction->IR & 0xff);
+ m_cru_value = (m_command==SBO)? 1 : 0;
+ displacement = (INT8)(IR & 0xff);
m_cru_address = m_current_value + (displacement<<1);
m_count = 1;
}
- m_instruction->state++;
+ m_inst_state++;
pulse_clock(1);
}
@@ -3077,7 +3141,7 @@ void tms9995_device::alu_shift()
UINT32 value;
int count;
- switch (m_instruction->state)
+ switch (m_inst_state)
{
case 0:
// we have the value of the register in m_current_value
@@ -3086,7 +3150,7 @@ void tms9995_device::alu_shift()
m_address_saved = m_address;
m_address = WP;
// store this in m_current_value where the R0 value will be put
- m_current_value = (m_instruction->IR >> 4)& 0x000f;
+ m_current_value = (IR >> 4)& 0x000f;
if (m_current_value != 0)
{
// skip the next read operation
@@ -3110,11 +3174,11 @@ void tms9995_device::alu_shift()
// the clock at each single shift anyway.
// Also, it is easier to implement the status bit setting.
// Note that count is never 0
- if (m_instruction->command == SRA) sign = value & 0x8000;
+ if (m_command == SRA) sign = value & 0x8000;
for (int i=0; i < count; i++)
{
- switch (m_instruction->command)
+ switch (m_command)
{
case SRL:
case SRA:
@@ -3142,7 +3206,7 @@ void tms9995_device::alu_shift()
if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value);
break;
}
- m_instruction->state++;
+ m_inst_state++;
}
/*
@@ -3155,7 +3219,7 @@ void tms9995_device::alu_single_arithm()
UINT16 sign = 0;
bool check_ov = true;
- switch (m_instruction->command)
+ switch (m_command)
{
case ABS:
// LAECO (from original word!)
@@ -3245,12 +3309,12 @@ void tms9995_device::alu_single_arithm()
void tms9995_device::alu_stcr()
{
int n = 1;
- switch (m_instruction->state)
+ switch (m_inst_state)
{
case 0:
- m_count = (m_instruction->IR >> 6) & 0x000f;
+ m_count = (IR >> 6) & 0x000f;
if (m_count == 0) m_count = 16;
- m_instruction->byteop = (m_count < 9);
+ m_byteop = (m_count < 9);
break;
case 1:
m_address_saved = m_address;
@@ -3267,7 +3331,7 @@ void tms9995_device::alu_stcr()
m_address = m_address_saved;
compare_and_set_lae(m_current_value, 0);
n = 13;
- if (m_instruction->byteop)
+ if (m_byteop)
{
set_status_parity((UINT8)m_current_value);
m_current_value <<= 8;
@@ -3276,7 +3340,7 @@ void tms9995_device::alu_stcr()
if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value);
break;
}
- m_instruction->state++;
+ m_inst_state++;
pulse_clock(n);
}
@@ -3287,8 +3351,8 @@ void tms9995_device::alu_stcr()
*/
void tms9995_device::alu_stst_stwp()
{
- m_address = WP + ((m_instruction->IR & 0x000f)<<1);
- m_current_value = (m_instruction->command==STST)? ST : WP;
+ m_address = WP + ((IR & 0x000f)<<1);
+ m_current_value = (m_command==STST)? ST : WP;
}
/*
@@ -3298,14 +3362,14 @@ void tms9995_device::alu_tb()
{
INT8 displacement;
- switch (m_instruction->state)
+ switch (m_inst_state)
{
case 0:
m_address = WP + 24;
pulse_clock(1);
break;
case 1:
- displacement = (INT8)(m_instruction->IR & 0xff);
+ displacement = (INT8)(IR & 0xff);
m_cru_address = m_current_value + (displacement<<1);
m_cru_first_read = true;
m_count = 1;
@@ -3316,7 +3380,7 @@ void tms9995_device::alu_tb()
if (TRACE_STATUS) logerror("ST = %04x\n", ST);
break;
}
- m_instruction->state++;
+ m_inst_state++;
}
/*
@@ -3339,13 +3403,13 @@ void tms9995_device::alu_x()
*/
void tms9995_device::alu_xop()
{
- switch (m_instruction->state)
+ switch (m_inst_state)
{
case 0:
// we have the source address in m_address
m_address_saved = m_address;
// Format is xxxx xxnn nnxx xxxx
- m_address = 0x0040 + ((m_instruction->IR & 0x03c0)>>4);
+ m_address = 0x0040 + ((IR & 0x03c0)>>4);
pulse_clock(1);
break;
case 1:
@@ -3372,7 +3436,7 @@ void tms9995_device::alu_xop()
pulse_clock(1);
break;
case 5:
- m_address = 0x0042 + ((m_instruction->IR & 0x03c0)>>4);
+ m_address = 0x0042 + ((IR & 0x03c0)>>4);
pulse_clock(1);
break;
case 6:
@@ -3380,7 +3444,7 @@ void tms9995_device::alu_xop()
set_status_bit(ST_X, true);
break;
}
- m_instruction->state++;
+ m_inst_state++;
}
/*
@@ -3391,7 +3455,7 @@ void tms9995_device::alu_int()
{
int pulse = 1;
- switch (m_instruction->state)
+ switch (m_inst_state)
{
case 0:
PC = (PC - 2) & 0xfffe;
@@ -3453,7 +3517,7 @@ void tms9995_device::alu_int()
// If next instruction is MID opcode we will detect this in command_completed
}
- m_instruction->state++;
+ m_inst_state++;
pulse_clock(pulse);
}
diff --git a/src/devices/cpu/tms9900/tms9995.h b/src/devices/cpu/tms9900/tms9995.h
index 1e5dfdf3594..1231de40196 100644
--- a/src/devices/cpu/tms9900/tms9995.h
+++ b/src/devices/cpu/tms9900/tms9995.h
@@ -131,11 +131,9 @@ private:
address_space* m_prgspace;
address_space* m_cru;
-
// Processor states
bool m_idle_state;
bool m_nmi_state;
-// bool m_irq_state;
bool m_hold_state;
bool m_hold_requested;
@@ -166,9 +164,6 @@ private:
// single-bit accesses.
int m_pass;
- // For parity operations
- int m_parity;
-
// For Format 1 instruction; determines whether the next operand address
// derivation is for the source or address operand
bool m_get_destination;
@@ -276,22 +271,22 @@ private:
// ============== Prefetch support =====================
- struct decoded_instruction
- {
- UINT16 IR;
- UINT16 command;
- const UINT8* program;
- bool byteop;
- int state;
- };
+ // We implement the prefetch mechanism by two separate datasets for
+ // the decoded commands. When the next instruction shall be started,
+ // the contents from the pre* members are copied to the main members.
- int m_instindex;
+ UINT16 IR;
+ UINT16 m_command;
+ int m_index;
+ bool m_byteop;
- // We implement the prefetch mechanism by two separate datasets for
- // the decoded commands. When the previous command has completed, the
- // pointer is just switched to the other one.
- tms9995_device::decoded_instruction m_decoded[2];
- tms9995_device::decoded_instruction* m_instruction;
+ UINT16 m_pre_IR;
+ UINT16 m_pre_command;
+ int m_pre_index;
+ bool m_pre_byteop;
+
+ // State of the currently executed instruction
+ int m_inst_state;
// ================ Microprogram support ========================
@@ -316,27 +311,30 @@ private:
// Lookup table entry
struct lookup_entry
{
- lookup_entry *next_digit;
- const tms_instruction *entry;
+ std::unique_ptr<lookup_entry[]> next_digit;
+ int index; // pointing to the static instruction list
};
// Pointer to the lookup table; the entry point for searching the command
- lookup_entry* m_command_lookup_table;
-
- // List of allocated tables (used for easy clean-up on exit)
- lookup_entry* m_lotables[32];
+ std::unique_ptr<lookup_entry[]> m_command_lookup_table;
// List of pointers for micro-operations
static const tms9995_device::ophandler s_microoperation[];
static const tms9995_device::tms_instruction s_command[];
+ // Index of the interrupt program
+ int m_interrupt_mp_index;
+
+ // Index of the operand address derivation subprogram
+ int m_operand_address_derivation_index;
+
// Micro-operation program counter (as opposed to the program counter PC)
int MPC;
// Calling microprogram (used when data derivation is called)
- const UINT8* m_caller;
- int m_caller_MPC;
+ int m_caller_index;
+ int m_caller_MPC;
// Table of microprograms
static const microprogram mp_table[];
@@ -387,7 +385,6 @@ private:
void alu_lst_lwp();
void alu_mov();
void alu_multiply();
-// void alu_multiply_signed();
void alu_rtwp();
void alu_sbo_sbz();
void alu_shift();