mirror of
https://github.com/holub/mame
synced 2025-06-11 07:14:07 +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"
|
#include "tms9900.h"
|
||||||
|
|
||||||
|
#define NOPRG -1
|
||||||
|
|
||||||
/* tms9900 ST register bits. */
|
/* tms9900 ST register bits. */
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@ -182,7 +184,9 @@ tms99xx_device::tms99xx_device(const machine_config &mconfig, device_type type,
|
|||||||
m_iaq_line(*this),
|
m_iaq_line(*this),
|
||||||
m_get_intlevel(*this),
|
m_get_intlevel(*this),
|
||||||
m_dbin_line(*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();
|
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()
|
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 },
|
{ 0xc000, MOV, 1, f1_mp },
|
||||||
{ 0xd000, MOVB, 1, f1_mp },
|
{ 0xd000, MOVB, 1, f1_mp },
|
||||||
{ 0xe000, SOC, 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;
|
int bitcount;
|
||||||
const tms_instruction *inst;
|
const tms_instruction *inst;
|
||||||
UINT16 opcode;
|
UINT16 opcode;
|
||||||
int k = 0;
|
|
||||||
|
|
||||||
m_command_lookup_table = new lookup_entry[16];
|
m_command_lookup_table = std::make_unique<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;
|
|
||||||
|
|
||||||
lookup_entry* table = m_command_lookup_table;
|
lookup_entry* table = m_command_lookup_table.get();
|
||||||
for (int j=0; j < 16; j++)
|
for (int j=0; j < 16; j++)
|
||||||
{
|
{
|
||||||
table[j].entry = nullptr;
|
|
||||||
table[j].next_digit = nullptr;
|
table[j].next_digit = nullptr;
|
||||||
|
table[j].index = NOPRG;
|
||||||
}
|
}
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
inst = &s_command[i];
|
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]);
|
if (TRACE_SETUP) logerror("=== opcode=%04x, len=%d\n", inst->opcode, format_mask_len[inst->format]);
|
||||||
bitcount = 4;
|
bitcount = 4;
|
||||||
opcode = inst->opcode;
|
opcode = inst->opcode;
|
||||||
@ -1072,12 +1112,11 @@ void tms99xx_device::build_command_lookup_table()
|
|||||||
if (table[cmdindex].next_digit == nullptr)
|
if (table[cmdindex].next_digit == nullptr)
|
||||||
{
|
{
|
||||||
if (TRACE_SETUP) logerror("create new table at bitcount=%d for index=%d\n", bitcount, cmdindex);
|
if (TRACE_SETUP) logerror("create new table at bitcount=%d for index=%d\n", bitcount, cmdindex);
|
||||||
table[cmdindex].next_digit = new lookup_entry[16];
|
table[cmdindex].next_digit = std::make_unique<lookup_entry[]>(16);
|
||||||
m_lotables[k++] = table[cmdindex].next_digit;
|
|
||||||
for (int j=0; j < 16; j++)
|
for (int j=0; j < 16; j++)
|
||||||
{
|
{
|
||||||
table[cmdindex].next_digit[j].next_digit = nullptr;
|
table[cmdindex].next_digit[j].next_digit = nullptr;
|
||||||
table[cmdindex].next_digit[j].entry = nullptr;
|
table[cmdindex].next_digit[j].index = NOPRG;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1085,7 +1124,7 @@ void tms99xx_device::build_command_lookup_table()
|
|||||||
if (TRACE_SETUP) logerror("found a table at bitcount=%d\n", bitcount);
|
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;
|
bitcount = bitcount+4;
|
||||||
opcode <<= 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++)
|
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);
|
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++;
|
i++;
|
||||||
} while (inst->opcode != 0xf000);
|
} while (inst->opcode != 0xf000);
|
||||||
|
|
||||||
m_lotables[k++] = nullptr;
|
m_interrupt_mp_index = i;
|
||||||
if (TRACE_SETUP) logerror("Allocated %d tables\n", k);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1155,7 +1192,7 @@ void tms99xx_device::execute_run()
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
// Only when last instruction has completed
|
// Only when last instruction has completed
|
||||||
if (m_program == nullptr)
|
if (m_program_index == NOPRG)
|
||||||
{
|
{
|
||||||
if (m_load_state)
|
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");
|
if (TRACE_WAIT) logerror("idle state\n");
|
||||||
pulse_clock(1);
|
pulse_clock(1);
|
||||||
@ -1187,14 +1224,19 @@ void tms99xx_device::execute_run()
|
|||||||
}
|
}
|
||||||
else
|
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
|
// Handle HOLD
|
||||||
// A HOLD request is signalled through the input line HOLD.
|
// A HOLD request is signalled through the input line HOLD.
|
||||||
// The hold state will be entered with the next non-memory access cycle.
|
// The hold state will be entered with the next non-memory access cycle.
|
||||||
if (m_hold_state &&
|
if (m_hold_state &&
|
||||||
(m_program==nullptr ||
|
(m_program_index == NOPRG ||
|
||||||
(m_program[MPC] != IAQ &&
|
(program[MPC] != IAQ &&
|
||||||
m_program[MPC] != MEMORY_READ && m_program[MPC] != MEMORY_WRITE &&
|
program[MPC] != MEMORY_READ && program[MPC] != MEMORY_WRITE &&
|
||||||
m_program[MPC] != REG_READ && m_program[MPC] != REG_WRITE)))
|
program[MPC] != REG_READ && program[MPC] != REG_WRITE)))
|
||||||
{
|
{
|
||||||
if (TRACE_WAIT) logerror("hold\n");
|
if (TRACE_WAIT) logerror("hold\n");
|
||||||
if (!m_hold_acknowledged) acknowledge_hold();
|
if (!m_hold_acknowledged) acknowledge_hold();
|
||||||
@ -1216,15 +1258,12 @@ void tms99xx_device::execute_run()
|
|||||||
{
|
{
|
||||||
set_wait_state(false);
|
set_wait_state(false);
|
||||||
m_check_ready = 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;
|
if (TRACE_MICRO) logerror("MPC = %d, op = %d\n", MPC, op);
|
||||||
else
|
|
||||||
{
|
|
||||||
m_op = m_program[MPC];
|
|
||||||
}
|
|
||||||
if (TRACE_MICRO) logerror("MPC = %d, m_op = %d\n", MPC, m_op);
|
|
||||||
// Call the operation of the microprogram
|
// Call the operation of the microprogram
|
||||||
(this->*s_microoperation[m_op])();
|
(this->*s_microoperation[op])();
|
||||||
// If we have multiple passes (as in the TMS9980)
|
// If we have multiple passes (as in the TMS9980)
|
||||||
m_pass--;
|
m_pass--;
|
||||||
if (m_pass<=0)
|
if (m_pass<=0)
|
||||||
@ -1287,7 +1326,8 @@ int tms99xx_device::get_intlevel(int state)
|
|||||||
|
|
||||||
void tms99xx_device::service_interrupt()
|
void tms99xx_device::service_interrupt()
|
||||||
{
|
{
|
||||||
m_program = int_mp;
|
m_program_index = m_interrupt_mp_index;
|
||||||
|
|
||||||
m_command = INTR;
|
m_command = INTR;
|
||||||
m_idle_state = false;
|
m_idle_state = false;
|
||||||
if (!m_external_operation.isnull()) m_external_operation(IDLE_OP, 0, 0xff);
|
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)
|
void tms99xx_device::decode(UINT16 inst)
|
||||||
{
|
{
|
||||||
int index = 0;
|
int ix = 0;
|
||||||
lookup_entry* table = m_command_lookup_table;
|
lookup_entry* table = m_command_lookup_table.get();
|
||||||
UINT16 opcode = inst;
|
UINT16 opcode = inst;
|
||||||
bool complete = false;
|
bool complete = false;
|
||||||
const tms_instruction *decoded;
|
|
||||||
|
|
||||||
m_state = 0;
|
m_state = 0;
|
||||||
IR = inst;
|
IR = inst;
|
||||||
@ -1415,35 +1454,34 @@ void tms99xx_device::decode(UINT16 inst)
|
|||||||
|
|
||||||
while (!complete)
|
while (!complete)
|
||||||
{
|
{
|
||||||
index = (opcode >> 12) & 0x000f;
|
ix = (opcode >> 12) & 0x000f;
|
||||||
if (TRACE_MICRO) logerror("Check next hex digit of instruction %x\n", index);
|
if (TRACE_MICRO) logerror("Check next hex digit of instruction %x\n", ix);
|
||||||
if (table[index].next_digit != nullptr)
|
if (table[ix].next_digit != nullptr)
|
||||||
{
|
{
|
||||||
table = table[index].next_digit;
|
table = table[ix].next_digit.get();
|
||||||
opcode = opcode << 4;
|
opcode = opcode << 4;
|
||||||
}
|
}
|
||||||
else complete = true;
|
else complete = true;
|
||||||
}
|
}
|
||||||
decoded = table[index].entry;
|
m_program_index = table[ix].index;
|
||||||
if (decoded == nullptr)
|
if (m_program_index == NOPRG)
|
||||||
{
|
{
|
||||||
// not found
|
// not found
|
||||||
logerror("Address %04x: Illegal opcode %04x\n", PC, inst);
|
logerror("Address %04x: Illegal opcode %04x\n", PC, inst);
|
||||||
IR = 0;
|
IR = 0;
|
||||||
// This will cause another instruction acquisition in the next machine cycle
|
// 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).
|
// with an asserted IAQ line (can be used to indicate this illegal opcode detection).
|
||||||
m_program = nullptr;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_program = decoded->prog;
|
const tms_instruction decoded = s_command[m_program_index];
|
||||||
MPC = -1;
|
MPC = -1;
|
||||||
m_command = decoded->id;
|
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);
|
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
|
// Byte operations are either format 1 with the byte flag set
|
||||||
// or format 4 (CRU multi bit operations) with 1-8 bits to transfer.
|
// or format 4 (CRU multi bit operations) with 1-8 bits to transfer.
|
||||||
m_byteop = ((decoded->format==1 && ((IR & 0x1000)!=0))
|
m_byteop = ((decoded.format==1 && ((IR & 0x1000)!=0))
|
||||||
|| (decoded->format==4 && (((IR >> 6)&0x000f) > 0) && (((IR >> 6)&0x000f) > 9)));
|
|| (decoded.format==4 && (((IR >> 6)&0x000f) > 0) && (((IR >> 6)&0x000f) > 9)));
|
||||||
}
|
}
|
||||||
m_pass = 1;
|
m_pass = 1;
|
||||||
}
|
}
|
||||||
@ -1646,7 +1684,8 @@ void tms99xx_device::return_from_subprogram()
|
|||||||
// Return from data derivation
|
// Return from data derivation
|
||||||
// The result should be in m_current_value
|
// The result should be in m_current_value
|
||||||
// and the address in m_address
|
// 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
|
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);
|
if (cycles > 0 && cycles < 10000) logerror(" %d cycles", cycles);
|
||||||
logerror("\n");
|
logerror("\n");
|
||||||
}
|
}
|
||||||
m_program = nullptr;
|
m_program_index = NOPRG;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1674,7 +1713,7 @@ void tms99xx_device::data_derivation_subprogram()
|
|||||||
UINT16 ircopy = IR;
|
UINT16 ircopy = IR;
|
||||||
|
|
||||||
// Save the return program and position
|
// Save the return program and position
|
||||||
m_caller = m_program;
|
m_caller_index = m_program_index;
|
||||||
m_caller_MPC = MPC;
|
m_caller_MPC = MPC;
|
||||||
|
|
||||||
// Source or destination argument?
|
// Source or destination argument?
|
||||||
@ -1682,7 +1721,6 @@ void tms99xx_device::data_derivation_subprogram()
|
|||||||
|
|
||||||
m_regnumber = ircopy & 0x000f;
|
m_regnumber = ircopy & 0x000f;
|
||||||
|
|
||||||
m_program = (UINT8*)data_derivation;
|
|
||||||
MPC = ircopy & 0x0030;
|
MPC = ircopy & 0x0030;
|
||||||
|
|
||||||
if (((MPC == 0x0020) && (m_regnumber != 0)) // indexed
|
if (((MPC == 0x0020) && (m_regnumber != 0)) // indexed
|
||||||
|
@ -133,9 +133,6 @@ protected:
|
|||||||
// single-bit accesses. (Needed for TMS9980)
|
// single-bit accesses. (Needed for TMS9980)
|
||||||
int m_pass;
|
int m_pass;
|
||||||
|
|
||||||
// Data bus width. Needed for TMS9980.
|
|
||||||
int m_databus_width;
|
|
||||||
|
|
||||||
// Check the READY line?
|
// Check the READY line?
|
||||||
bool m_check_ready;
|
bool m_check_ready;
|
||||||
|
|
||||||
@ -254,15 +251,12 @@ private:
|
|||||||
// Lookup table entry
|
// Lookup table entry
|
||||||
struct lookup_entry
|
struct lookup_entry
|
||||||
{
|
{
|
||||||
lookup_entry *next_digit;
|
std::unique_ptr<lookup_entry[]> next_digit;
|
||||||
const tms_instruction *entry;
|
int index; // pointing to the static instruction list
|
||||||
};
|
};
|
||||||
|
|
||||||
// Pointer to the lookup table
|
// Pointer to the lookup table
|
||||||
lookup_entry* m_command_lookup_table;
|
std::unique_ptr<lookup_entry[]> m_command_lookup_table;
|
||||||
|
|
||||||
// List of allocated tables (used for easy clean-up on exit)
|
|
||||||
lookup_entry* m_lotables[32];
|
|
||||||
|
|
||||||
// List of pointers for micro-operations
|
// List of pointers for micro-operations
|
||||||
static const tms99xx_device::ophandler s_microoperation[];
|
static const tms99xx_device::ophandler s_microoperation[];
|
||||||
@ -321,18 +315,18 @@ private:
|
|||||||
|
|
||||||
void abort_operation(void);
|
void abort_operation(void);
|
||||||
|
|
||||||
// Micro-operation
|
|
||||||
UINT8 m_op;
|
|
||||||
|
|
||||||
// Micro-operation program counter (as opposed to the program counter PC)
|
// Micro-operation program counter (as opposed to the program counter PC)
|
||||||
int MPC;
|
int MPC;
|
||||||
|
|
||||||
// Current microprogram
|
// Current microprogram
|
||||||
const UINT8* m_program;
|
int m_program_index;
|
||||||
|
|
||||||
// Calling microprogram (used when data derivation is called)
|
// Calling microprogram (used when data derivation is called)
|
||||||
const UINT8* m_caller;
|
int m_caller_index;
|
||||||
int m_caller_MPC;
|
int m_caller_MPC;
|
||||||
|
|
||||||
|
// Index of the interrupt program
|
||||||
|
int m_interrupt_mp_index;
|
||||||
|
|
||||||
// State of the micro-operation. Needed for repeated ALU calls.
|
// State of the micro-operation. Needed for repeated ALU calls.
|
||||||
int m_state;
|
int m_state;
|
||||||
|
@ -91,6 +91,8 @@
|
|||||||
|
|
||||||
#include "tms9995.h"
|
#include "tms9995.h"
|
||||||
|
|
||||||
|
#define NOPRG -1
|
||||||
|
|
||||||
/* tms9995 ST register bits. */
|
/* tms9995 ST register bits. */
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@ -269,13 +271,76 @@ void tms9995_device::device_start()
|
|||||||
build_command_lookup_table();
|
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");
|
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()
|
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;
|
ST = (UINT16)m_state_any;
|
||||||
break;
|
break;
|
||||||
case TMS9995_IR:
|
case TMS9995_IR:
|
||||||
m_instruction->IR = (UINT16)m_state_any;
|
IR = (UINT16)m_state_any;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Workspace registers
|
// Workspace registers
|
||||||
@ -359,7 +424,7 @@ void tms9995_device::state_export(const device_state_entry &entry)
|
|||||||
m_state_any = ST;
|
m_state_any = ST;
|
||||||
break;
|
break;
|
||||||
case TMS9995_IR:
|
case TMS9995_IR:
|
||||||
m_state_any = m_instruction->IR;
|
m_state_any = IR;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Workspace registers
|
// Workspace registers
|
||||||
@ -988,7 +1053,7 @@ enum
|
|||||||
LIMI, LREX, LST, LWP, LWPI, MOV, MOVB, MPY, MPYS, NEG,
|
LIMI, LREX, LST, LWP, LWPI, MOV, MOVB, MPY, MPYS, NEG,
|
||||||
ORI, RSET, RTWP, S, SB, SBO, SBZ, SETO, SLA, SOC,
|
ORI, RSET, RTWP, S, SB, SBO, SBZ, SETO, SLA, SOC,
|
||||||
SOCB, SRA, SRC, SRL, STCR, STST, STWP, SWPB, SZC, SZCB,
|
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] =
|
static const char opname[][5] =
|
||||||
@ -999,7 +1064,7 @@ static const char opname[][5] =
|
|||||||
"LIMI", "LREX", "LST ", "LWP ", "LWPI", "MOV ", "MOVB", "MPY ", "MPYS", "NEG ",
|
"LIMI", "LREX", "LST ", "LWP ", "LWPI", "MOV ", "MOVB", "MPY ", "MPYS", "NEG ",
|
||||||
"ORI ", "RSET", "RTWP", "S ", "SB ", "SBO ", "SBZ ", "SETO", "SLA ", "SOC ",
|
"ORI ", "RSET", "RTWP", "S ", "SB ", "SBO ", "SBZ ", "SETO", "SLA ", "SOC ",
|
||||||
"SOCB", "SRA ", "SRC ", "SRL ", "STCR", "STST", "STWP", "SWPB", "SZC ", "SZCB",
|
"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 },
|
{ 0xc000, MOV, 1, mov_mp },
|
||||||
{ 0xd000, MOVB, 1, mov_mp },
|
{ 0xd000, MOVB, 1, mov_mp },
|
||||||
{ 0xe000, SOC, 1, add_s_sxc_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;
|
int bitcount;
|
||||||
const tms_instruction *inst;
|
const tms_instruction *inst;
|
||||||
UINT16 opcode;
|
UINT16 opcode;
|
||||||
int k = 0;
|
|
||||||
|
|
||||||
m_command_lookup_table = new lookup_entry[16];
|
m_command_lookup_table = std::make_unique<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;
|
|
||||||
|
|
||||||
lookup_entry* table = m_command_lookup_table;
|
lookup_entry* table = m_command_lookup_table.get();
|
||||||
for (int j=0; j < 16; j++)
|
for (int j=0; j < 16; j++)
|
||||||
{
|
{
|
||||||
table[j].entry = nullptr;
|
|
||||||
table[j].next_digit = nullptr;
|
table[j].next_digit = nullptr;
|
||||||
|
table[j].index = NOPRG;
|
||||||
}
|
}
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
inst = &s_command[i];
|
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]);
|
if (TRACE_EMU) logerror("=== opcode=%04x, len=%d\n", inst->opcode, format_mask_len[inst->format]);
|
||||||
bitcount = 4;
|
bitcount = 4;
|
||||||
opcode = inst->opcode;
|
opcode = inst->opcode;
|
||||||
@ -1161,12 +1226,11 @@ void tms9995_device::build_command_lookup_table()
|
|||||||
if (table[cmdindex].next_digit == nullptr)
|
if (table[cmdindex].next_digit == nullptr)
|
||||||
{
|
{
|
||||||
if (TRACE_EMU) logerror("create new table at bitcount=%d for index=%d\n", bitcount, cmdindex);
|
if (TRACE_EMU) logerror("create new table at bitcount=%d for index=%d\n", bitcount, cmdindex);
|
||||||
table[cmdindex].next_digit = new lookup_entry[16];
|
table[cmdindex].next_digit = std::make_unique<lookup_entry[]>(16);
|
||||||
m_lotables[k++] = table[cmdindex].next_digit;
|
|
||||||
for (int j=0; j < 16; j++)
|
for (int j=0; j < 16; j++)
|
||||||
{
|
{
|
||||||
table[cmdindex].next_digit[j].next_digit = nullptr;
|
table[cmdindex].next_digit[j].next_digit = nullptr;
|
||||||
table[cmdindex].next_digit[j].entry = nullptr;
|
table[cmdindex].next_digit[j].index = NOPRG;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1174,7 +1238,7 @@ void tms9995_device::build_command_lookup_table()
|
|||||||
if (TRACE_EMU) logerror("found a table at bitcount=%d\n", bitcount);
|
if (TRACE_EMU) logerror("found a table at bitcount=%d\n", bitcount);
|
||||||
}
|
}
|
||||||
|
|
||||||
table = table[cmdindex].next_digit;
|
table = table[cmdindex].next_digit.get();
|
||||||
|
|
||||||
bitcount = bitcount+4;
|
bitcount = bitcount+4;
|
||||||
opcode <<= 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++)
|
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);
|
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++;
|
i++;
|
||||||
} while (inst->opcode != 0xf000);
|
} while (inst->opcode != 0xf000);
|
||||||
|
|
||||||
m_lotables[k++] = nullptr;
|
// Save the index to these two special microprograms
|
||||||
if (TRACE_EMU) logerror("Allocated %d tables\n", k);
|
m_interrupt_mp_index = i++;
|
||||||
|
m_operand_address_derivation_index = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1238,8 +1303,9 @@ void tms9995_device::execute_run()
|
|||||||
|
|
||||||
m_check_ready = false;
|
m_check_ready = false;
|
||||||
|
|
||||||
if (TRACE_MICRO) logerror("main loop, operation %s, MPC = %d\n", opname[m_instruction->command], MPC);
|
if (TRACE_MICRO) logerror("main loop, operation %s, MPC = %d\n", opname[m_command], MPC);
|
||||||
(this->*s_microoperation[m_instruction->program[MPC]])();
|
UINT8* program = (UINT8*)s_command[m_index].prog;
|
||||||
|
(this->*s_microoperation[program[MPC]])();
|
||||||
|
|
||||||
// For multi-pass operations where the MPC should not advance
|
// For multi-pass operations where the MPC should not advance
|
||||||
// or when we have put in a new microprogram
|
// 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)
|
void tms9995_device::decode(UINT16 inst)
|
||||||
{
|
{
|
||||||
int index = 0;
|
int ix = 0;
|
||||||
lookup_entry* table = m_command_lookup_table;
|
lookup_entry* table = m_command_lookup_table.get();
|
||||||
UINT16 opcode = inst;
|
UINT16 opcode = inst;
|
||||||
bool complete = false;
|
bool complete = false;
|
||||||
const tms_instruction *decoded;
|
|
||||||
|
|
||||||
int dindex = (m_instindex==0)? 1:0;
|
|
||||||
|
|
||||||
m_mid_active = false;
|
m_mid_active = false;
|
||||||
|
|
||||||
while (!complete)
|
while (!complete)
|
||||||
{
|
{
|
||||||
index = (opcode >> 12) & 0x000f;
|
ix = (opcode >> 12) & 0x000f;
|
||||||
if (TRACE_EMU) logerror("Check next hex digit of instruction %x\n", index);
|
if (TRACE_EMU) logerror("Check next hex digit of instruction %x\n", ix);
|
||||||
if (table[index].next_digit != nullptr)
|
if (table[ix].next_digit != nullptr)
|
||||||
{
|
{
|
||||||
table = table[index].next_digit;
|
table = table[ix].next_digit.get();
|
||||||
opcode = opcode << 4;
|
opcode = opcode << 4;
|
||||||
}
|
}
|
||||||
else complete = true;
|
else complete = true;
|
||||||
}
|
}
|
||||||
decoded = table[index].entry;
|
|
||||||
if (decoded == nullptr)
|
int program_index = table[ix].index;
|
||||||
|
if (program_index == NOPRG)
|
||||||
{
|
{
|
||||||
// not found
|
// not found
|
||||||
logerror("Undefined opcode %04x at logical address %04x, will trigger MID\n", inst, PC);
|
logerror("Undefined opcode %04x at logical address %04x, will trigger MID\n", inst, PC);
|
||||||
m_decoded[dindex].IR = 0;
|
m_pre_IR = 0;
|
||||||
m_decoded[dindex].command = MID;
|
m_pre_command = MID;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_decoded[dindex].IR = inst;
|
const tms_instruction decoded = s_command[program_index];
|
||||||
m_decoded[dindex].command = decoded->id;
|
|
||||||
m_decoded[dindex].program = decoded->prog;
|
m_pre_IR = inst;
|
||||||
m_decoded[dindex].byteop = ((decoded->format == 1) && ((inst & 0x1000)!=0));
|
m_pre_command = decoded.id;
|
||||||
m_decoded[dindex].state = 0;
|
m_pre_index = program_index;
|
||||||
if (TRACE_EMU) logerror("Command decoded as id %d, %s, base opcode %04x\n", decoded->id, opname[decoded->id], decoded->opcode);
|
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;
|
m_pass = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1453,7 +1518,6 @@ void tms9995_device::decode(UINT16 inst)
|
|||||||
*/
|
*/
|
||||||
void tms9995_device::int_prefetch_and_decode()
|
void tms9995_device::int_prefetch_and_decode()
|
||||||
{
|
{
|
||||||
bool check_int = (m_instruction->command != XOP && m_instruction->command != BLWP);
|
|
||||||
int intmask = ST & 0x000f;
|
int intmask = ST & 0x000f;
|
||||||
|
|
||||||
if (m_mem_phase == 1)
|
if (m_mem_phase == 1)
|
||||||
@ -1470,8 +1534,8 @@ void tms9995_device::int_prefetch_and_decode()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_int_pending = 0;
|
m_int_pending = 0;
|
||||||
|
// If the current command is XOP or BLWP, ignore the interrupt
|
||||||
if (check_int)
|
if (m_command != XOP && m_command != BLWP)
|
||||||
{
|
{
|
||||||
if (m_int1_active && intmask >= 1) m_int_pending |= PENDING_LEVEL1;
|
if (m_int1_active && intmask >= 1) m_int_pending |= PENDING_LEVEL1;
|
||||||
if (m_int_overflow && intmask >= 2) m_int_pending |= PENDING_OVERFLOW;
|
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()
|
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_flag = true;
|
||||||
m_mid_active = true;
|
m_mid_active = true;
|
||||||
@ -1560,13 +1630,11 @@ void tms9995_device::next_command()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_instindex = next;
|
|
||||||
m_instruction = &m_decoded[m_instindex];
|
|
||||||
m_get_destination = false;
|
m_get_destination = false;
|
||||||
// This is a preset for opcodes which do not need an opcode address derivation
|
// 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;
|
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)
|
if (TRACE_EXEC)
|
||||||
{
|
{
|
||||||
@ -1587,7 +1655,7 @@ void tms9995_device::command_completed()
|
|||||||
// Pseudo state at the end of the current instruction cycle sequence
|
// Pseudo state at the end of the current instruction cycle sequence
|
||||||
if (TRACE_CYCLES)
|
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;
|
int cycles = m_first_cycle - m_icount;
|
||||||
// Avoid nonsense values due to expired and resumed main loop
|
// Avoid nonsense values due to expired and resumed main loop
|
||||||
if (cycles > 0 && cycles < 10000) logerror(", consumed %d cycles", cycles);
|
if (cycles > 0 && cycles < 10000) logerror(", consumed %d cycles", cycles);
|
||||||
@ -1595,19 +1663,13 @@ void tms9995_device::command_completed()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_int_pending != 0)
|
if (m_int_pending != 0)
|
||||||
{
|
|
||||||
service_interrupt();
|
service_interrupt();
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((ST & ST_OE)!=0 && (ST & ST_OV)!=0 && (ST & 0x000f)>2)
|
if ((ST & ST_OE)!=0 && (ST & ST_OV)!=0 && (ST & 0x000f)>2)
|
||||||
{
|
|
||||||
service_interrupt();
|
service_interrupt();
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
next_command();
|
next_command();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1634,8 +1696,6 @@ void tms9995_device::service_interrupt()
|
|||||||
m_decrementer_clkdiv = 0;
|
m_decrementer_clkdiv = 0;
|
||||||
|
|
||||||
m_pass = 0;
|
m_pass = 0;
|
||||||
m_instindex = 0;
|
|
||||||
m_instruction = &m_decoded[m_instindex];
|
|
||||||
|
|
||||||
memset(m_flag, 0, sizeof(m_flag));
|
memset(m_flag, 0, sizeof(m_flag));
|
||||||
|
|
||||||
@ -1718,16 +1778,18 @@ void tms9995_device::service_interrupt()
|
|||||||
|
|
||||||
// The microinstructions will do the context switch
|
// The microinstructions will do the context switch
|
||||||
m_address = vectorpos;
|
m_address = vectorpos;
|
||||||
m_instruction->program = int_mp;
|
|
||||||
m_instruction->state = 0;
|
m_index = m_interrupt_mp_index;
|
||||||
m_instruction->byteop = false;
|
m_inst_state = 0;
|
||||||
m_instruction->command = INTR;
|
m_byteop = false;
|
||||||
|
m_command = INTR;
|
||||||
|
|
||||||
m_pass = m_reset? 1 : 2;
|
m_pass = m_reset? 1 : 2;
|
||||||
m_from_reset = m_reset;
|
m_from_reset = m_reset;
|
||||||
|
|
||||||
if (m_reset)
|
if (m_reset)
|
||||||
{
|
{
|
||||||
m_instruction->IR = 0x0000;
|
IR = 0x0000;
|
||||||
m_reset = false;
|
m_reset = false;
|
||||||
}
|
}
|
||||||
MPC = 0;
|
MPC = 0;
|
||||||
@ -1764,7 +1826,7 @@ void tms9995_device::mem_read()
|
|||||||
if (TRACE_DEC) logerror("read decrementer\n");
|
if (TRACE_DEC) logerror("read decrementer\n");
|
||||||
// Decrementer mapped into the address space
|
// Decrementer mapped into the address space
|
||||||
m_current_value = m_decrementer_value;
|
m_current_value = m_decrementer_value;
|
||||||
if (m_instruction->byteop)
|
if (m_byteop)
|
||||||
{
|
{
|
||||||
if ((m_address & 1)!=1) m_current_value <<= 8;
|
if ((m_address & 1)!=1) m_current_value <<= 8;
|
||||||
m_current_value &= 0xff00;
|
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
|
// If we have a word access, we have to align the address
|
||||||
// This is the case for word operations and for certain phases of
|
// This is the case for word operations and for certain phases of
|
||||||
// byte operations (e.g. when retrieving the index register)
|
// 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);
|
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;
|
m_check_ready = false;
|
||||||
// We put fffc-ffff back into the f000-f0ff area
|
// We put fffc-ffff back into the f000-f0ff area
|
||||||
m_current_value = m_onchip_memory[m_address & 0x00ff]<<8;
|
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)
|
// 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);
|
m_current_value |= (m_onchip_memory[(m_address & 0x00ff)+1] & 0xff);
|
||||||
@ -1806,7 +1868,7 @@ void tms9995_device::mem_read()
|
|||||||
// Set address
|
// Set address
|
||||||
// If this is a word access, 4 passes, else 2 passes
|
// If this is a word access, 4 passes, else 2 passes
|
||||||
if (!m_dbin_line.isnull()) m_dbin_line(ASSERT_LINE);
|
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;
|
m_pass = 4;
|
||||||
// For word accesses, we always start at the even address
|
// For word accesses, we always start at the even address
|
||||||
@ -1822,7 +1884,7 @@ void tms9995_device::mem_read()
|
|||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
// Sample the value on the data bus (high byte)
|
// 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);
|
value = m_prgspace->read_byte(address);
|
||||||
if (TRACE_MEM) logerror("memory read byte %04x -> %02x\n", m_address & ~1, value);
|
if (TRACE_MEM) logerror("memory read byte %04x -> %02x\n", m_address & ~1, value);
|
||||||
m_current_value = (value << 8) & 0xff00;
|
m_current_value = (value << 8) & 0xff00;
|
||||||
@ -1888,7 +1950,7 @@ void tms9995_device::mem_write()
|
|||||||
{
|
{
|
||||||
if ((m_address & 0xfffe)==0xfffa && !m_mp9537)
|
if ((m_address & 0xfffe)==0xfffa && !m_mp9537)
|
||||||
{
|
{
|
||||||
if (m_instruction->byteop)
|
if (m_byteop)
|
||||||
{
|
{
|
||||||
// According to [1], section 2.3.1.2.2:
|
// According to [1], section 2.3.1.2.2:
|
||||||
// "The decrementer should always be accessed as a full word. [...]
|
// "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
|
// If we have a word access, we have to align the address
|
||||||
// This is the case for word operations and for certain phases of
|
// This is the case for word operations and for certain phases of
|
||||||
// byte operations (e.g. when retrieving the index register)
|
// 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);
|
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_check_ready = false;
|
||||||
m_onchip_memory[m_address & 0x00ff] = (m_current_value >> 8) & 0xff;
|
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;
|
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 this is a word access, 4 passes, else 2 passes
|
||||||
if (!m_dbin_line.isnull()) m_dbin_line(CLEAR_LINE);
|
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;
|
m_pass = 4;
|
||||||
address &= 0xfffe;
|
address &= 0xfffe;
|
||||||
@ -2000,7 +2062,7 @@ void tms9995_device::return_with_address()
|
|||||||
{
|
{
|
||||||
// Return from operand address derivation
|
// Return from operand address derivation
|
||||||
// The result should be in m_address
|
// 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
|
MPC = m_caller_MPC; // will be increased on return
|
||||||
m_address = m_current_value + m_address_add;
|
m_address = m_current_value + m_address_add;
|
||||||
if (TRACE_DETAIL) logerror("+++ return from operand address derivation +++\n");
|
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()
|
void tms9995_device::return_with_address_copy()
|
||||||
{
|
{
|
||||||
// Return from operand address derivation
|
// Return from operand address derivation
|
||||||
m_instruction->program = m_caller;
|
m_index = m_caller_index;
|
||||||
MPC = m_caller_MPC; // will be increased on return
|
MPC = m_caller_MPC; // will be increased on return
|
||||||
m_address = m_address_saved;
|
m_address = m_address_saved;
|
||||||
if (TRACE_DETAIL) logerror("+++ return from operand address derivation (auto inc) +++\n");
|
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_read >>= offset;
|
||||||
m_cru_bits_left -= offset;
|
m_cru_bits_left -= offset;
|
||||||
m_parity = 0;
|
|
||||||
m_cru_value = 0;
|
m_cru_value = 0;
|
||||||
m_cru_first_read = false;
|
m_cru_first_read = false;
|
||||||
m_pass = m_count;
|
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);
|
if (TRACE_CRU) logerror("CRU input operation, address %04x, value %d\n", m_cru_address, (crubit & 0x8000)>>15);
|
||||||
|
|
||||||
m_cru_value |= crubit;
|
m_cru_value |= crubit;
|
||||||
if (crubit!=0) m_parity++;
|
|
||||||
|
|
||||||
m_cru_address = (m_cru_address + 2) & 0xfffe;
|
m_cru_address = (m_cru_address + 2) & 0xfffe;
|
||||||
m_cru_bits_left--;
|
m_cru_bits_left--;
|
||||||
@ -2219,7 +2279,7 @@ void tms9995_device::trigger_decrementer()
|
|||||||
|
|
||||||
input:
|
input:
|
||||||
m_get_destination
|
m_get_destination
|
||||||
m_instruction
|
m_decoded[m_instindex]
|
||||||
WP
|
WP
|
||||||
m_current_value
|
m_current_value
|
||||||
m_address
|
m_address
|
||||||
@ -2234,14 +2294,14 @@ void tms9995_device::trigger_decrementer()
|
|||||||
*/
|
*/
|
||||||
void tms9995_device::operand_address_subprogram()
|
void tms9995_device::operand_address_subprogram()
|
||||||
{
|
{
|
||||||
UINT16 ircopy = m_instruction->IR;
|
UINT16 ircopy = IR;
|
||||||
if (m_get_destination) ircopy = ircopy >> 6;
|
if (m_get_destination) ircopy = ircopy >> 6;
|
||||||
|
|
||||||
// Save the return program and position
|
// Save the return program and position
|
||||||
m_caller = m_instruction->program;
|
m_caller_index = m_index;
|
||||||
m_caller_MPC = MPC;
|
m_caller_MPC = MPC;
|
||||||
|
|
||||||
m_instruction->program = (UINT8*)operand_address_derivation;
|
m_index = m_operand_address_derivation_index;
|
||||||
MPC = (ircopy & 0x0030) >> 2;
|
MPC = (ircopy & 0x0030) >> 2;
|
||||||
m_regnumber = (ircopy & 0x000f);
|
m_regnumber = (ircopy & 0x000f);
|
||||||
m_address = (WP + (m_regnumber<<1)) & 0xffff;
|
m_address = (WP + (m_regnumber<<1)) & 0xffff;
|
||||||
@ -2278,7 +2338,7 @@ void tms9995_device::operand_address_subprogram()
|
|||||||
void tms9995_device::increment_register()
|
void tms9995_device::increment_register()
|
||||||
{
|
{
|
||||||
m_address_saved = m_current_value; // need a special return so we do not lose the value
|
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_address = (WP + (m_regnumber<<1)) & 0xffff;
|
||||||
m_mem_phase = 1;
|
m_mem_phase = 1;
|
||||||
pulse_clock(1);
|
pulse_clock(1);
|
||||||
@ -2301,7 +2361,7 @@ void tms9995_device::indexed_addressing()
|
|||||||
void tms9995_device::set_immediate()
|
void tms9995_device::set_immediate()
|
||||||
{
|
{
|
||||||
// Need to determine the register address
|
// 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_address = PC;
|
||||||
m_source_value = m_current_value; // needed for AI, ANDI, ORI
|
m_source_value = m_current_value; // needed for AI, ANDI, ORI
|
||||||
PC = (PC + 2) & 0xfffe;
|
PC = (PC + 2) & 0xfffe;
|
||||||
@ -2364,7 +2424,7 @@ void tms9995_device::alu_add_s_sxc()
|
|||||||
|
|
||||||
UINT32 dest_new = 0;
|
UINT32 dest_new = 0;
|
||||||
|
|
||||||
switch (m_instruction->command)
|
switch (m_command)
|
||||||
{
|
{
|
||||||
case A:
|
case A:
|
||||||
case AB:
|
case AB:
|
||||||
@ -2406,7 +2466,7 @@ void tms9995_device::alu_add_s_sxc()
|
|||||||
m_current_value = (UINT16)(dest_new & 0xffff);
|
m_current_value = (UINT16)(dest_new & 0xffff);
|
||||||
|
|
||||||
compare_and_set_lae((UINT16)(dest_new & 0xffff),0);
|
compare_and_set_lae((UINT16)(dest_new & 0xffff),0);
|
||||||
if (m_instruction->byteop)
|
if (m_byteop)
|
||||||
{
|
{
|
||||||
set_status_parity((UINT8)(dest_new>>8));
|
set_status_parity((UINT8)(dest_new>>8));
|
||||||
}
|
}
|
||||||
@ -2433,7 +2493,7 @@ void tms9995_device::alu_b()
|
|||||||
void tms9995_device::alu_blwp()
|
void tms9995_device::alu_blwp()
|
||||||
{
|
{
|
||||||
int n = 1;
|
int n = 1;
|
||||||
switch (m_instruction->state)
|
switch (m_inst_state)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
// new WP in m_current_value
|
// 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);
|
if (TRACE_OP) logerror("Context switch complete; WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
m_instruction->state++;
|
m_inst_state++;
|
||||||
pulse_clock(n);
|
pulse_clock(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2473,7 +2533,7 @@ void tms9995_device::alu_c()
|
|||||||
// value in m_current_value
|
// value in m_current_value
|
||||||
// The destination address is still in m_address
|
// The destination address is still in m_address
|
||||||
// Prefetch will not change m_current_value and 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));
|
set_status_parity((UINT8)(m_source_value>>8));
|
||||||
}
|
}
|
||||||
@ -2495,7 +2555,7 @@ void tms9995_device::alu_ci()
|
|||||||
void tms9995_device::alu_clr_seto()
|
void tms9995_device::alu_clr_seto()
|
||||||
{
|
{
|
||||||
if (TRACE_OP) logerror("clr/seto: Setting values for address %04x\n", m_address);
|
if (TRACE_OP) logerror("clr/seto: Setting values for address %04x\n", m_address);
|
||||||
switch (m_instruction->command)
|
switch (m_command)
|
||||||
{
|
{
|
||||||
case CLR:
|
case CLR:
|
||||||
m_current_value = 0;
|
m_current_value = 0;
|
||||||
@ -2518,12 +2578,12 @@ void tms9995_device::alu_divide()
|
|||||||
bool overflow = true;
|
bool overflow = true;
|
||||||
UINT16 value1;
|
UINT16 value1;
|
||||||
|
|
||||||
switch (m_instruction->state)
|
switch (m_inst_state)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
m_source_value = m_current_value;
|
m_source_value = m_current_value;
|
||||||
// Set address of register
|
// Set address of register
|
||||||
m_address = WP + ((m_instruction->IR >> 5) & 0x001e);
|
m_address = WP + ((IR >> 5) & 0x001e);
|
||||||
m_address_copy = m_address;
|
m_address_copy = m_address;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
@ -2569,7 +2629,7 @@ void tms9995_device::alu_divide()
|
|||||||
m_address = m_address + 2;
|
m_address = m_address + 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
m_instruction->state++;
|
m_inst_state++;
|
||||||
pulse_clock(n);
|
pulse_clock(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2588,7 +2648,7 @@ void tms9995_device::alu_divide_signed()
|
|||||||
INT16 divisor;
|
INT16 divisor;
|
||||||
INT32 dividend;
|
INT32 dividend;
|
||||||
|
|
||||||
switch (m_instruction->state)
|
switch (m_inst_state)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
// Got the source value (divisor)
|
// Got the source value (divisor)
|
||||||
@ -2671,7 +2731,7 @@ void tms9995_device::alu_divide_signed()
|
|||||||
n = 0;
|
n = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
m_instruction->state++;
|
m_inst_state++;
|
||||||
pulse_clock(n);
|
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
|
// external code on the data bus. A special line decoder could then trigger
|
||||||
// a reset from outside.
|
// a reset from outside.
|
||||||
|
|
||||||
if (m_instruction->command == IDLE)
|
if (m_command == IDLE)
|
||||||
{
|
{
|
||||||
if (TRACE_OP) logerror("Entering IDLE state\n");
|
if (TRACE_OP) logerror("Entering IDLE state\n");
|
||||||
m_idle_state = true;
|
m_idle_state = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_instruction->command == RSET)
|
if (m_command == RSET)
|
||||||
{
|
{
|
||||||
ST &= 0xfff0;
|
ST &= 0xfff0;
|
||||||
if (TRACE_OP) logerror("RSET, new ST = %04x\n", ST);
|
if (TRACE_OP) logerror("RSET, new ST = %04x\n", ST);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_external_operation.isnull()) m_external_operation((m_instruction->IR >> 5) & 0x07, 1, 0xff);
|
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()
|
void tms9995_device::alu_f3()
|
||||||
{
|
{
|
||||||
switch (m_instruction->state)
|
switch (m_inst_state)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
// We have the contents of the source in m_current_value and its address
|
// We have the contents of the source in m_current_value and its address
|
||||||
// in m_address
|
// in m_address
|
||||||
m_source_value = m_current_value;
|
m_source_value = m_current_value;
|
||||||
// Get register address
|
// Get register address
|
||||||
m_address = WP + ((m_instruction->IR >> 5) & 0x001e);
|
m_address = WP + ((IR >> 5) & 0x001e);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
// Register contents -> m_current_value
|
// Register contents -> m_current_value
|
||||||
// Source contents -> m_source_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);
|
set_status_bit(ST_EQ, (m_current_value & m_source_value) == m_source_value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_instruction->command == CZC)
|
if (m_command == CZC)
|
||||||
{
|
{
|
||||||
set_status_bit(ST_EQ, (~m_current_value & m_source_value) == m_source_value);
|
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);
|
if (TRACE_STATUS) logerror("ST = %04x\n", ST);
|
||||||
break;
|
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
|
// We have the register value in m_source_value, the register address in m_address_saved
|
||||||
// and the immediate value in m_current_value
|
// and the immediate value in m_current_value
|
||||||
switch (m_instruction->command)
|
switch (m_command)
|
||||||
{
|
{
|
||||||
case AI:
|
case AI:
|
||||||
dest_new = m_current_value + m_source_value;
|
dest_new = m_current_value + m_source_value;
|
||||||
@ -2796,9 +2857,9 @@ void tms9995_device::alu_imm_arithm()
|
|||||||
void tms9995_device::alu_jump()
|
void tms9995_device::alu_jump()
|
||||||
{
|
{
|
||||||
bool cond = false;
|
bool cond = false;
|
||||||
INT8 displacement = (m_instruction->IR & 0xff);
|
INT8 displacement = (IR & 0xff);
|
||||||
|
|
||||||
switch (m_instruction->command)
|
switch (m_command)
|
||||||
{
|
{
|
||||||
case JMP:
|
case JMP:
|
||||||
cond = true;
|
cond = true;
|
||||||
@ -2857,18 +2918,21 @@ void tms9995_device::alu_jump()
|
|||||||
*/
|
*/
|
||||||
void tms9995_device::alu_ldcr()
|
void tms9995_device::alu_ldcr()
|
||||||
{
|
{
|
||||||
switch (m_instruction->state)
|
switch (m_inst_state)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
m_count = (m_instruction->IR >> 6) & 0x000f;
|
m_count = (IR >> 6) & 0x000f;
|
||||||
if (m_count==0) m_count = 16;
|
if (m_count==0) m_count = 16;
|
||||||
m_instruction->byteop = (m_count<9);
|
m_byteop = (m_count<9);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
// We have read the byte or word into m_current_value.
|
// We have read the byte or word into m_current_value.
|
||||||
compare_and_set_lae(m_current_value, 0);
|
compare_and_set_lae(m_current_value, 0);
|
||||||
if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value);
|
if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value);
|
||||||
if (m_instruction->byteop)
|
|
||||||
|
// 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;
|
m_current_value = (m_current_value>>8) & 0xff;
|
||||||
set_status_parity((UINT8)m_current_value);
|
set_status_parity((UINT8)m_current_value);
|
||||||
@ -2881,7 +2945,7 @@ void tms9995_device::alu_ldcr()
|
|||||||
m_cru_address = m_current_value;
|
m_cru_address = m_current_value;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
m_instruction->state++;
|
m_inst_state++;
|
||||||
pulse_clock(1);
|
pulse_clock(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2902,7 +2966,7 @@ void tms9995_device::alu_li()
|
|||||||
void tms9995_device::alu_limi_lwpi()
|
void tms9995_device::alu_limi_lwpi()
|
||||||
{
|
{
|
||||||
// The immediate value is in m_current_value
|
// The immediate value is in m_current_value
|
||||||
if (m_instruction->command == LIMI)
|
if (m_command == LIMI)
|
||||||
{
|
{
|
||||||
ST = (ST & 0xfff0) | (m_current_value & 0x000f);
|
ST = (ST & 0xfff0) | (m_current_value & 0x000f);
|
||||||
if (TRACE_OP) logerror("LIMI sets ST = %04x\n", ST);
|
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()
|
void tms9995_device::alu_lst_lwp()
|
||||||
{
|
{
|
||||||
if (m_instruction->command==LST)
|
if (m_command==LST)
|
||||||
{
|
{
|
||||||
ST = m_current_value;
|
ST = m_current_value;
|
||||||
if (TRACE_OP) logerror("new ST = %04x\n", ST);
|
if (TRACE_OP) logerror("new ST = %04x\n", ST);
|
||||||
@ -2943,7 +3007,7 @@ void tms9995_device::alu_lst_lwp()
|
|||||||
void tms9995_device::alu_mov()
|
void tms9995_device::alu_mov()
|
||||||
{
|
{
|
||||||
m_current_value = m_source_value;
|
m_current_value = m_source_value;
|
||||||
if (m_instruction->byteop)
|
if (m_byteop)
|
||||||
{
|
{
|
||||||
set_status_parity((UINT8)(m_current_value>>8));
|
set_status_parity((UINT8)(m_current_value>>8));
|
||||||
}
|
}
|
||||||
@ -2961,15 +3025,15 @@ void tms9995_device::alu_multiply()
|
|||||||
UINT32 result;
|
UINT32 result;
|
||||||
INT32 results;
|
INT32 results;
|
||||||
|
|
||||||
if (m_instruction->command==MPY)
|
if (m_command==MPY)
|
||||||
{
|
{
|
||||||
switch (m_instruction->state)
|
switch (m_inst_state)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
// m_current_value <- multiplier (source)
|
// m_current_value <- multiplier (source)
|
||||||
m_source_value = m_current_value;
|
m_source_value = m_current_value;
|
||||||
// m_address is the second multiplier (in a register)
|
// 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;
|
n = 1;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
@ -2989,9 +3053,9 @@ void tms9995_device::alu_multiply()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else // MPYS
|
||||||
{
|
{
|
||||||
switch (m_instruction->state)
|
switch (m_inst_state)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
// m_current_value <- multiplier (source)
|
// m_current_value <- multiplier (source)
|
||||||
@ -3015,13 +3079,13 @@ void tms9995_device::alu_multiply()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_instruction->state++;
|
m_inst_state++;
|
||||||
pulse_clock(n);
|
pulse_clock(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tms9995_device::alu_rtwp()
|
void tms9995_device::alu_rtwp()
|
||||||
{
|
{
|
||||||
switch (m_instruction->state)
|
switch (m_inst_state)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
m_address = WP + 30; // R15
|
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);
|
if (TRACE_OP) logerror("RTWP restored old context (WP=%04x, PC=%04x, ST=%04x)\n", WP, PC, ST);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
m_instruction->state++;
|
m_inst_state++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tms9995_device::alu_sbo_sbz()
|
void tms9995_device::alu_sbo_sbz()
|
||||||
{
|
{
|
||||||
INT8 displacement;
|
INT8 displacement;
|
||||||
|
|
||||||
if (m_instruction->state==0)
|
if (m_inst_state==0)
|
||||||
{
|
{
|
||||||
m_address = WP + 24;
|
m_address = WP + 24;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_cru_value = (m_instruction->command==SBO)? 1 : 0;
|
m_cru_value = (m_command==SBO)? 1 : 0;
|
||||||
displacement = (INT8)(m_instruction->IR & 0xff);
|
displacement = (INT8)(IR & 0xff);
|
||||||
m_cru_address = m_current_value + (displacement<<1);
|
m_cru_address = m_current_value + (displacement<<1);
|
||||||
m_count = 1;
|
m_count = 1;
|
||||||
}
|
}
|
||||||
m_instruction->state++;
|
m_inst_state++;
|
||||||
pulse_clock(1);
|
pulse_clock(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3077,7 +3141,7 @@ void tms9995_device::alu_shift()
|
|||||||
UINT32 value;
|
UINT32 value;
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
switch (m_instruction->state)
|
switch (m_inst_state)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
// we have the value of the register in m_current_value
|
// 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_saved = m_address;
|
||||||
m_address = WP;
|
m_address = WP;
|
||||||
// store this in m_current_value where the R0 value will be put
|
// 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)
|
if (m_current_value != 0)
|
||||||
{
|
{
|
||||||
// skip the next read operation
|
// skip the next read operation
|
||||||
@ -3110,11 +3174,11 @@ void tms9995_device::alu_shift()
|
|||||||
// the clock at each single shift anyway.
|
// the clock at each single shift anyway.
|
||||||
// Also, it is easier to implement the status bit setting.
|
// Also, it is easier to implement the status bit setting.
|
||||||
// Note that count is never 0
|
// 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++)
|
for (int i=0; i < count; i++)
|
||||||
{
|
{
|
||||||
switch (m_instruction->command)
|
switch (m_command)
|
||||||
{
|
{
|
||||||
case SRL:
|
case SRL:
|
||||||
case SRA:
|
case SRA:
|
||||||
@ -3142,7 +3206,7 @@ void tms9995_device::alu_shift()
|
|||||||
if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value);
|
if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
m_instruction->state++;
|
m_inst_state++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3155,7 +3219,7 @@ void tms9995_device::alu_single_arithm()
|
|||||||
UINT16 sign = 0;
|
UINT16 sign = 0;
|
||||||
bool check_ov = true;
|
bool check_ov = true;
|
||||||
|
|
||||||
switch (m_instruction->command)
|
switch (m_command)
|
||||||
{
|
{
|
||||||
case ABS:
|
case ABS:
|
||||||
// LAECO (from original word!)
|
// LAECO (from original word!)
|
||||||
@ -3245,12 +3309,12 @@ void tms9995_device::alu_single_arithm()
|
|||||||
void tms9995_device::alu_stcr()
|
void tms9995_device::alu_stcr()
|
||||||
{
|
{
|
||||||
int n = 1;
|
int n = 1;
|
||||||
switch (m_instruction->state)
|
switch (m_inst_state)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
m_count = (m_instruction->IR >> 6) & 0x000f;
|
m_count = (IR >> 6) & 0x000f;
|
||||||
if (m_count == 0) m_count = 16;
|
if (m_count == 0) m_count = 16;
|
||||||
m_instruction->byteop = (m_count < 9);
|
m_byteop = (m_count < 9);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
m_address_saved = m_address;
|
m_address_saved = m_address;
|
||||||
@ -3267,7 +3331,7 @@ void tms9995_device::alu_stcr()
|
|||||||
m_address = m_address_saved;
|
m_address = m_address_saved;
|
||||||
compare_and_set_lae(m_current_value, 0);
|
compare_and_set_lae(m_current_value, 0);
|
||||||
n = 13;
|
n = 13;
|
||||||
if (m_instruction->byteop)
|
if (m_byteop)
|
||||||
{
|
{
|
||||||
set_status_parity((UINT8)m_current_value);
|
set_status_parity((UINT8)m_current_value);
|
||||||
m_current_value <<= 8;
|
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);
|
if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
m_instruction->state++;
|
m_inst_state++;
|
||||||
pulse_clock(n);
|
pulse_clock(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3287,8 +3351,8 @@ void tms9995_device::alu_stcr()
|
|||||||
*/
|
*/
|
||||||
void tms9995_device::alu_stst_stwp()
|
void tms9995_device::alu_stst_stwp()
|
||||||
{
|
{
|
||||||
m_address = WP + ((m_instruction->IR & 0x000f)<<1);
|
m_address = WP + ((IR & 0x000f)<<1);
|
||||||
m_current_value = (m_instruction->command==STST)? ST : WP;
|
m_current_value = (m_command==STST)? ST : WP;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3298,14 +3362,14 @@ void tms9995_device::alu_tb()
|
|||||||
{
|
{
|
||||||
INT8 displacement;
|
INT8 displacement;
|
||||||
|
|
||||||
switch (m_instruction->state)
|
switch (m_inst_state)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
m_address = WP + 24;
|
m_address = WP + 24;
|
||||||
pulse_clock(1);
|
pulse_clock(1);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
displacement = (INT8)(m_instruction->IR & 0xff);
|
displacement = (INT8)(IR & 0xff);
|
||||||
m_cru_address = m_current_value + (displacement<<1);
|
m_cru_address = m_current_value + (displacement<<1);
|
||||||
m_cru_first_read = true;
|
m_cru_first_read = true;
|
||||||
m_count = 1;
|
m_count = 1;
|
||||||
@ -3316,7 +3380,7 @@ void tms9995_device::alu_tb()
|
|||||||
if (TRACE_STATUS) logerror("ST = %04x\n", ST);
|
if (TRACE_STATUS) logerror("ST = %04x\n", ST);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
m_instruction->state++;
|
m_inst_state++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3339,13 +3403,13 @@ void tms9995_device::alu_x()
|
|||||||
*/
|
*/
|
||||||
void tms9995_device::alu_xop()
|
void tms9995_device::alu_xop()
|
||||||
{
|
{
|
||||||
switch (m_instruction->state)
|
switch (m_inst_state)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
// we have the source address in m_address
|
// we have the source address in m_address
|
||||||
m_address_saved = m_address;
|
m_address_saved = m_address;
|
||||||
// Format is xxxx xxnn nnxx xxxx
|
// Format is xxxx xxnn nnxx xxxx
|
||||||
m_address = 0x0040 + ((m_instruction->IR & 0x03c0)>>4);
|
m_address = 0x0040 + ((IR & 0x03c0)>>4);
|
||||||
pulse_clock(1);
|
pulse_clock(1);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
@ -3372,7 +3436,7 @@ void tms9995_device::alu_xop()
|
|||||||
pulse_clock(1);
|
pulse_clock(1);
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
m_address = 0x0042 + ((m_instruction->IR & 0x03c0)>>4);
|
m_address = 0x0042 + ((IR & 0x03c0)>>4);
|
||||||
pulse_clock(1);
|
pulse_clock(1);
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
@ -3380,7 +3444,7 @@ void tms9995_device::alu_xop()
|
|||||||
set_status_bit(ST_X, true);
|
set_status_bit(ST_X, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
m_instruction->state++;
|
m_inst_state++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3391,7 +3455,7 @@ void tms9995_device::alu_int()
|
|||||||
{
|
{
|
||||||
int pulse = 1;
|
int pulse = 1;
|
||||||
|
|
||||||
switch (m_instruction->state)
|
switch (m_inst_state)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
PC = (PC - 2) & 0xfffe;
|
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
|
// If next instruction is MID opcode we will detect this in command_completed
|
||||||
}
|
}
|
||||||
m_instruction->state++;
|
m_inst_state++;
|
||||||
pulse_clock(pulse);
|
pulse_clock(pulse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,11 +131,9 @@ private:
|
|||||||
address_space* m_prgspace;
|
address_space* m_prgspace;
|
||||||
address_space* m_cru;
|
address_space* m_cru;
|
||||||
|
|
||||||
|
|
||||||
// Processor states
|
// Processor states
|
||||||
bool m_idle_state;
|
bool m_idle_state;
|
||||||
bool m_nmi_state;
|
bool m_nmi_state;
|
||||||
// bool m_irq_state;
|
|
||||||
bool m_hold_state;
|
bool m_hold_state;
|
||||||
bool m_hold_requested;
|
bool m_hold_requested;
|
||||||
|
|
||||||
@ -166,9 +164,6 @@ private:
|
|||||||
// single-bit accesses.
|
// single-bit accesses.
|
||||||
int m_pass;
|
int m_pass;
|
||||||
|
|
||||||
// For parity operations
|
|
||||||
int m_parity;
|
|
||||||
|
|
||||||
// For Format 1 instruction; determines whether the next operand address
|
// For Format 1 instruction; determines whether the next operand address
|
||||||
// derivation is for the source or address operand
|
// derivation is for the source or address operand
|
||||||
bool m_get_destination;
|
bool m_get_destination;
|
||||||
@ -276,22 +271,22 @@ private:
|
|||||||
|
|
||||||
// ============== Prefetch support =====================
|
// ============== 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
|
// We implement the prefetch mechanism by two separate datasets for
|
||||||
// the decoded commands. When the previous command has completed, the
|
// the decoded commands. When the next instruction shall be started,
|
||||||
// pointer is just switched to the other one.
|
// the contents from the pre* members are copied to the main members.
|
||||||
tms9995_device::decoded_instruction m_decoded[2];
|
|
||||||
tms9995_device::decoded_instruction* m_instruction;
|
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 ========================
|
// ================ Microprogram support ========================
|
||||||
|
|
||||||
@ -316,27 +311,30 @@ private:
|
|||||||
// Lookup table entry
|
// Lookup table entry
|
||||||
struct lookup_entry
|
struct lookup_entry
|
||||||
{
|
{
|
||||||
lookup_entry *next_digit;
|
std::unique_ptr<lookup_entry[]> next_digit;
|
||||||
const tms_instruction *entry;
|
int index; // pointing to the static instruction list
|
||||||
};
|
};
|
||||||
|
|
||||||
// Pointer to the lookup table; the entry point for searching the command
|
// Pointer to the lookup table; the entry point for searching the command
|
||||||
lookup_entry* m_command_lookup_table;
|
std::unique_ptr<lookup_entry[]> m_command_lookup_table;
|
||||||
|
|
||||||
// List of allocated tables (used for easy clean-up on exit)
|
|
||||||
lookup_entry* m_lotables[32];
|
|
||||||
|
|
||||||
// List of pointers for micro-operations
|
// List of pointers for micro-operations
|
||||||
static const tms9995_device::ophandler s_microoperation[];
|
static const tms9995_device::ophandler s_microoperation[];
|
||||||
|
|
||||||
static const tms9995_device::tms_instruction s_command[];
|
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)
|
// Micro-operation program counter (as opposed to the program counter PC)
|
||||||
int MPC;
|
int MPC;
|
||||||
|
|
||||||
// Calling microprogram (used when data derivation is called)
|
// Calling microprogram (used when data derivation is called)
|
||||||
const UINT8* m_caller;
|
int m_caller_index;
|
||||||
int m_caller_MPC;
|
int m_caller_MPC;
|
||||||
|
|
||||||
// Table of microprograms
|
// Table of microprograms
|
||||||
static const microprogram mp_table[];
|
static const microprogram mp_table[];
|
||||||
@ -387,7 +385,6 @@ private:
|
|||||||
void alu_lst_lwp();
|
void alu_lst_lwp();
|
||||||
void alu_mov();
|
void alu_mov();
|
||||||
void alu_multiply();
|
void alu_multiply();
|
||||||
// void alu_multiply_signed();
|
|
||||||
void alu_rtwp();
|
void alu_rtwp();
|
||||||
void alu_sbo_sbz();
|
void alu_sbo_sbz();
|
||||||
void alu_shift();
|
void alu_shift();
|
||||||
|
Loading…
Reference in New Issue
Block a user