mirror of
https://github.com/holub/mame
synced 2025-06-06 21:03:47 +03:00
Merge branch 'master' of https://github.com/mamedev/mame
This commit is contained in:
commit
0894cdecd9
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
int m_instindex;
|
||||
|
||||
// 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;
|
||||
// the decoded commands. When the next instruction shall be started,
|
||||
// the contents from the pre* members are copied to the main members.
|
||||
|
||||
UINT16 IR;
|
||||
UINT16 m_command;
|
||||
int m_index;
|
||||
bool m_byteop;
|
||||
|
||||
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();
|
||||
|
Loading…
Reference in New Issue
Block a user