mirror of
https://github.com/holub/mame
synced 2025-05-20 20:58:51 +03:00
m680x0: Many FPU and PMMU fixes and enhancements [Hans Ostermeyer]
This commit is contained in:
parent
aecc1c8512
commit
de0dabd29f
@ -894,7 +894,7 @@ M68KMAKE_OP(1111, 0, ., .)
|
||||
|
||||
M68KMAKE_OP(040fpu0, 32, ., .)
|
||||
{
|
||||
if(CPU_TYPE_IS_030_PLUS(m68k->cpu_type))
|
||||
if(m68k->has_fpu)
|
||||
{
|
||||
m68040_fpu_op0(m68k);
|
||||
return;
|
||||
@ -905,7 +905,7 @@ M68KMAKE_OP(040fpu0, 32, ., .)
|
||||
|
||||
M68KMAKE_OP(040fpu1, 32, ., .)
|
||||
{
|
||||
if(CPU_TYPE_IS_030_PLUS(m68k->cpu_type))
|
||||
if(m68k->has_fpu)
|
||||
{
|
||||
m68040_fpu_op1(m68k);
|
||||
return;
|
||||
@ -8790,6 +8790,58 @@ rte_loop:
|
||||
new_pc = m68ki_pull_32(m68k);
|
||||
m68ki_fake_pull_16(m68k); /* format word */
|
||||
m68ki_fake_pull_32(m68k); /* address */
|
||||
m68ki_jump(m68k, new_pc);
|
||||
m68ki_set_sr(m68k, new_sr);
|
||||
m68k->instr_mode = INSTRUCTION_YES;
|
||||
m68k->run_mode = RUN_MODE_NORMAL;
|
||||
return;
|
||||
case 0x0a: /* Bus Error at instruction boundary */
|
||||
new_sr = m68ki_pull_16(m68k);
|
||||
new_pc = m68ki_pull_32(m68k);
|
||||
m68ki_fake_pull_16(m68k); /* $06: format word */
|
||||
m68ki_fake_pull_16(m68k); /* $08: internal register */
|
||||
m68ki_fake_pull_16(m68k); /* $0a: special status word */
|
||||
m68ki_fake_pull_16(m68k); /* $0c: instruction pipe stage c */
|
||||
m68ki_fake_pull_16(m68k); /* $0e: instruction pipe stage b */
|
||||
m68ki_fake_pull_32(m68k); /* $10: data fault address */
|
||||
m68ki_fake_pull_32(m68k); /* $14: internal registers */
|
||||
m68ki_fake_pull_32(m68k); /* $18: data output buffer */
|
||||
m68ki_fake_pull_32(m68k); /* $1c: internal registers */
|
||||
|
||||
m68ki_jump(m68k, new_pc);
|
||||
m68ki_set_sr(m68k, new_sr);
|
||||
m68k->instr_mode = INSTRUCTION_YES;
|
||||
m68k->run_mode = RUN_MODE_NORMAL;
|
||||
return;
|
||||
case 0x0b: /* Bus Error - Instruction Execution in Progress */
|
||||
new_sr = m68ki_pull_16(m68k);
|
||||
new_pc = m68ki_pull_32(m68k);
|
||||
m68ki_fake_pull_16(m68k); /* $06: format word */
|
||||
m68ki_fake_pull_16(m68k); /* $08: internal register */
|
||||
m68ki_fake_pull_16(m68k); /* $0a: special status word */
|
||||
m68ki_fake_pull_16(m68k); /* $0c: instruction pipe stage c */
|
||||
m68ki_fake_pull_16(m68k); /* $0e: instruction pipe stage b */
|
||||
m68ki_fake_pull_32(m68k); /* $10: data fault address */
|
||||
m68ki_fake_pull_32(m68k); /* $14: internal registers */
|
||||
m68ki_fake_pull_32(m68k); /* $18: data output buffer */
|
||||
m68ki_fake_pull_32(m68k); /* $1c: internal registers */
|
||||
m68ki_fake_pull_32(m68k); /* $20: */
|
||||
m68ki_fake_pull_32(m68k); /* $24: stage B address */
|
||||
m68ki_fake_pull_32(m68k); /* $28: */
|
||||
m68ki_fake_pull_32(m68k); /* $2c: data input buffer */
|
||||
m68ki_fake_pull_32(m68k); /* $30: */
|
||||
m68ki_fake_pull_16(m68k); /* $34: */
|
||||
m68ki_fake_pull_16(m68k); /* $36: version #, internal information */
|
||||
m68ki_fake_pull_32(m68k); /* $38: */
|
||||
m68ki_fake_pull_32(m68k); /* $3c: */
|
||||
m68ki_fake_pull_32(m68k); /* $40: */
|
||||
m68ki_fake_pull_32(m68k); /* $44: */
|
||||
m68ki_fake_pull_32(m68k); /* $48: */
|
||||
m68ki_fake_pull_32(m68k); /* $4c: */
|
||||
m68ki_fake_pull_32(m68k); /* $50: */
|
||||
m68ki_fake_pull_32(m68k); /* $54: */
|
||||
m68ki_fake_pull_32(m68k); /* $58: */
|
||||
|
||||
m68ki_jump(m68k, new_pc);
|
||||
m68ki_set_sr(m68k, new_sr);
|
||||
m68k->instr_mode = INSTRUCTION_YES;
|
||||
|
@ -5,7 +5,7 @@
|
||||
#if 0
|
||||
static const char copyright_notice[] =
|
||||
"MUSASHI\n"
|
||||
"Version 4.60 (2010-03-12)\n"
|
||||
"Version 4.70 (2010-11-06)\n"
|
||||
"A portable Motorola M680x0 processor emulation engine.\n"
|
||||
"Copyright Karl Stenerud. All rights reserved.\n"
|
||||
"\n"
|
||||
@ -565,7 +565,18 @@ static CPU_TRANSLATE( m68k )
|
||||
{
|
||||
if ((space == ADDRESS_SPACE_PROGRAM) && (m68k->pmmu_enabled))
|
||||
{
|
||||
*address = pmmu_translate_addr(m68k, *address);
|
||||
// FIXME: mmu_tmp_sr will be overwritten in pmmu_translate_addr_with_fc
|
||||
UINT16 mmu_tmp_sr = m68k->mmu_tmp_sr;
|
||||
// UINT32 va=*address;
|
||||
|
||||
*address = pmmu_translate_addr_with_fc(m68k, *address, 4, 1);
|
||||
|
||||
if ((m68k->mmu_tmp_sr & M68K_MMU_SR_INVALID) != 0) {
|
||||
// logerror("cpu_translate_m68k failed with mmu_sr=%04x va=%08x pa=%08x\n",m68k->mmu_tmp_sr,va ,*address);
|
||||
*address = 0;
|
||||
}
|
||||
|
||||
m68k->mmu_tmp_sr= mmu_tmp_sr;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
@ -621,13 +632,91 @@ static CPU_EXECUTE( m68k )
|
||||
/* Call external hook to peek at CPU */
|
||||
debugger_instruction_hook(device, REG_PC);
|
||||
|
||||
// FIXME: remove this
|
||||
// void apollo_debug_instruction(running_device *device);
|
||||
// apollo_debug_instruction(device);
|
||||
|
||||
/* Record previous program counter */
|
||||
REG_PPC = REG_PC;
|
||||
|
||||
/* Read an instruction and call its handler */
|
||||
m68k->ir = m68ki_read_imm_16(m68k);
|
||||
m68ki_instruction_jump_table[m68k->ir](m68k);
|
||||
m68k->remaining_cycles -= m68k->cyc_instruction[m68k->ir];
|
||||
if (!m68k->pmmu_enabled)
|
||||
{
|
||||
/* Read an instruction and call its handler */
|
||||
m68k->ir = m68ki_read_imm_16(m68k);
|
||||
m68ki_instruction_jump_table[m68k->ir](m68k);
|
||||
m68k->remaining_cycles -= m68k->cyc_instruction[m68k->ir];
|
||||
}
|
||||
else
|
||||
{
|
||||
// save CPU address registers values at start of instruction
|
||||
int i;
|
||||
UINT32 tmp_dar[16];
|
||||
|
||||
for (i = 15; i >= 0; i--)
|
||||
{
|
||||
tmp_dar[i] = REG_DA[i];
|
||||
}
|
||||
|
||||
m68k->mmu_tmp_buserror_occurred = 0;
|
||||
|
||||
/* Read an instruction and call its handler */
|
||||
m68k->ir = m68ki_read_imm_16(m68k);
|
||||
|
||||
if (!m68k->mmu_tmp_buserror_occurred)
|
||||
{
|
||||
m68ki_instruction_jump_table[m68k->ir](m68k);
|
||||
m68k->remaining_cycles -= m68k->cyc_instruction[m68k->ir];
|
||||
}
|
||||
|
||||
if (m68k->mmu_tmp_buserror_occurred)
|
||||
{
|
||||
UINT32 sr;
|
||||
|
||||
// const char * disassemble(m68ki_cpu_core *m68k, offs_t pc);
|
||||
// logerror(
|
||||
// "PMMU: pc=%08x sp=%08x va=%08x bus error: %s\n",
|
||||
// REG_PPC, REG_A[7], m68k->mmu_tmp_buserror_address,
|
||||
// (m68k->mmu_tmp_buserror_address == REG_PPC) ? "-"
|
||||
// : disassemble(m68k, REG_PPC));
|
||||
|
||||
m68k->mmu_tmp_buserror_occurred = 0;
|
||||
|
||||
// restore cpu address registers to value at start of instruction
|
||||
for (i = 15; i >= 0; i--)
|
||||
{
|
||||
if (REG_DA[i] != tmp_dar[i])
|
||||
{
|
||||
// logerror("PMMU: pc=%08x sp=%08x bus error: fixed %s[%d]: %08x -> %08x\n",
|
||||
// REG_PPC, REG_A[7], i < 8 ? "D" : "A", i & 7, REG_DA[i], tmp_dar[i]);
|
||||
REG_DA[i] = tmp_dar[i];
|
||||
}
|
||||
}
|
||||
|
||||
sr = m68ki_init_exception(m68k);
|
||||
|
||||
m68k->run_mode = RUN_MODE_BERR_AERR_RESET;
|
||||
|
||||
if (!CPU_TYPE_IS_020_PLUS(m68k->cpu_type))
|
||||
{
|
||||
/* Note: This is implemented for 68000 only! */
|
||||
m68ki_stack_frame_buserr(m68k, sr);
|
||||
}
|
||||
else if (m68k->mmu_tmp_buserror_address == REG_PPC)
|
||||
{
|
||||
m68ki_stack_frame_1010(m68k, sr, EXCEPTION_BUS_ERROR, REG_PPC, m68k->mmu_tmp_buserror_address);
|
||||
}
|
||||
else
|
||||
{
|
||||
m68ki_stack_frame_1011(m68k, sr, EXCEPTION_BUS_ERROR, REG_PPC, m68k->mmu_tmp_buserror_address);
|
||||
}
|
||||
|
||||
m68ki_jump_vector(m68k, EXCEPTION_BUS_ERROR);
|
||||
|
||||
// TODO:
|
||||
/* Use up some clock cycles and undo the instruction's cycles */
|
||||
// m68k->remaining_cycles -= m68k->cyc_exception[EXCEPTION_BUS_ERROR] - m68k->cyc_instruction[m68k->ir];
|
||||
}
|
||||
}
|
||||
|
||||
/* Trace m68k_exception, if necessary */
|
||||
m68ki_exception_if_trace(); /* auto-disable (see m68kcpu.h) */
|
||||
@ -693,6 +782,10 @@ static CPU_RESET( m68k )
|
||||
m68k->pmmu_enabled = 0;
|
||||
m68k->hmmu_enabled = 0;
|
||||
|
||||
m68k->mmu_tc = 0;
|
||||
m68k->mmu_tt0 = 0;
|
||||
m68k->mmu_tt1 = 0;
|
||||
|
||||
/* Clear all stop levels and eat up all remaining cycles */
|
||||
m68k->stopped = 0;
|
||||
if (m68k->remaining_cycles > 0)
|
||||
@ -952,7 +1045,7 @@ static CPU_GET_INFO( m68k )
|
||||
case DEVINFO_STR_FAMILY: strcpy(info->s, "Motorola 68K"); break;
|
||||
case DEVINFO_STR_VERSION: strcpy(info->s, "4.60"); break;
|
||||
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
|
||||
case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Karl Stenerud. All rights reserved. (2.1 fixes HJB, FPU+MMU by RB)"); break;
|
||||
case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Karl Stenerud. All rights reserved. (2.1 fixes HJB, FPU+MMU by RB+HO)"); break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1055,6 +1148,9 @@ UINT8 m68k_memory_interface::read_byte_32_mmu(offs_t address)
|
||||
if (m_cpustate->pmmu_enabled)
|
||||
{
|
||||
address = pmmu_translate_addr(m_cpustate, address);
|
||||
if (m_cpustate->mmu_tmp_buserror_occurred) {
|
||||
return ~0;
|
||||
}
|
||||
}
|
||||
|
||||
return m_space->read_byte(address);
|
||||
@ -1065,6 +1161,9 @@ void m68k_memory_interface::write_byte_32_mmu(offs_t address, UINT8 data)
|
||||
if (m_cpustate->pmmu_enabled)
|
||||
{
|
||||
address = pmmu_translate_addr(m_cpustate, address);
|
||||
if (m_cpustate->mmu_tmp_buserror_occurred) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_space->write_byte(address, data);
|
||||
@ -1075,6 +1174,9 @@ UINT16 m68k_memory_interface::read_immediate_16_mmu(offs_t address)
|
||||
if (m_cpustate->pmmu_enabled)
|
||||
{
|
||||
address = pmmu_translate_addr(m_cpustate, address);
|
||||
if (m_cpustate->mmu_tmp_buserror_occurred) {
|
||||
return ~0;
|
||||
}
|
||||
}
|
||||
|
||||
return m_direct->read_decrypted_word((address) ^ m_cpustate->memory.opcode_xor);
|
||||
@ -1087,7 +1189,20 @@ UINT16 m68k_memory_interface::readword_d32_mmu(offs_t address)
|
||||
|
||||
if (m_cpustate->pmmu_enabled)
|
||||
{
|
||||
address = pmmu_translate_addr(m_cpustate, address);
|
||||
UINT32 address0 = pmmu_translate_addr(m_cpustate, address);
|
||||
if (m_cpustate->mmu_tmp_buserror_occurred) {
|
||||
return ~0;
|
||||
} else if (!(address & 1)) {
|
||||
return m_space->read_word(address0);
|
||||
} else {
|
||||
UINT32 address1 = pmmu_translate_addr(m_cpustate, address + 1);
|
||||
if (m_cpustate->mmu_tmp_buserror_occurred) {
|
||||
return ~0;
|
||||
} else {
|
||||
result = m_space->read_byte(address0) << 8;
|
||||
return result | m_space->read_byte(address1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(address & 1))
|
||||
@ -1101,7 +1216,22 @@ void m68k_memory_interface::writeword_d32_mmu(offs_t address, UINT16 data)
|
||||
{
|
||||
if (m_cpustate->pmmu_enabled)
|
||||
{
|
||||
address = pmmu_translate_addr(m_cpustate, address);
|
||||
UINT32 address0 = pmmu_translate_addr(m_cpustate, address);
|
||||
if (m_cpustate->mmu_tmp_buserror_occurred) {
|
||||
return;
|
||||
} else if (!(address & 1)) {
|
||||
m_space->write_word(address0, data);
|
||||
return;
|
||||
} else {
|
||||
UINT32 address1 = pmmu_translate_addr(m_cpustate, address + 1);
|
||||
if (m_cpustate->mmu_tmp_buserror_occurred) {
|
||||
return;
|
||||
} else {
|
||||
m_space->write_byte(address0, data >> 8);
|
||||
m_space->write_byte(address1, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(address & 1))
|
||||
@ -1120,7 +1250,33 @@ UINT32 m68k_memory_interface::readlong_d32_mmu(offs_t address)
|
||||
|
||||
if (m_cpustate->pmmu_enabled)
|
||||
{
|
||||
address = pmmu_translate_addr(m_cpustate, address);
|
||||
UINT32 address0 = pmmu_translate_addr(m_cpustate, address);
|
||||
if (m_cpustate->mmu_tmp_buserror_occurred) {
|
||||
return ~0;
|
||||
} else if ((address +3) & 0xfc) {
|
||||
// not at page boundary; use default code
|
||||
address = address0;
|
||||
} else if (!(address & 3)) { // 0
|
||||
return m_space->read_dword(address0);
|
||||
} else {
|
||||
UINT32 address2 = pmmu_translate_addr(m_cpustate, address+2);
|
||||
if (m_cpustate->mmu_tmp_buserror_occurred) {
|
||||
return ~0;
|
||||
} else if (!(address & 1)) { // 2
|
||||
result = m_space->read_word(address0) << 16;
|
||||
return result | m_space->read_word(address2);
|
||||
} else {
|
||||
UINT32 address1 = pmmu_translate_addr(m_cpustate, address+1);
|
||||
UINT32 address3 = pmmu_translate_addr(m_cpustate, address+3);
|
||||
if (m_cpustate->mmu_tmp_buserror_occurred) {
|
||||
return ~0;
|
||||
} else {
|
||||
result = m_space->read_byte(address0) << 24;
|
||||
result |= m_space->read_word(address1) << 8;
|
||||
return result | m_space->read_byte(address3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(address & 3))
|
||||
@ -1140,7 +1296,36 @@ void m68k_memory_interface::writelong_d32_mmu(offs_t address, UINT32 data)
|
||||
{
|
||||
if (m_cpustate->pmmu_enabled)
|
||||
{
|
||||
address = pmmu_translate_addr(m_cpustate, address);
|
||||
UINT32 address0 = pmmu_translate_addr(m_cpustate, address);
|
||||
if (m_cpustate->mmu_tmp_buserror_occurred) {
|
||||
return;
|
||||
} else if ((address +3) & 0xfc) {
|
||||
// not at page boundary; use default code
|
||||
address = address0;
|
||||
} else if (!(address & 3)) { // 0
|
||||
m_space->write_dword(address0, data);
|
||||
return;
|
||||
} else {
|
||||
UINT32 address2 = pmmu_translate_addr(m_cpustate, address+2);
|
||||
if (m_cpustate->mmu_tmp_buserror_occurred) {
|
||||
return;
|
||||
} else if (!(address & 1)) { // 2
|
||||
m_space->write_word(address0, data >> 16);
|
||||
m_space->write_word(address2, data);
|
||||
return;
|
||||
} else {
|
||||
UINT32 address1 = pmmu_translate_addr(m_cpustate, address+1);
|
||||
UINT32 address3 = pmmu_translate_addr(m_cpustate, address+3);
|
||||
if (m_cpustate->mmu_tmp_buserror_occurred) {
|
||||
return;
|
||||
} else {
|
||||
m_space->write_byte(address0, data >> 24);
|
||||
m_space->write_word(address1, data >> 8);
|
||||
m_space->write_byte(address3, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(address & 3))
|
||||
@ -1413,6 +1598,7 @@ static CPU_INIT( m68000 )
|
||||
m68k->cyc_reset = 132;
|
||||
m68k->has_pmmu = 0;
|
||||
m68k->has_hmmu = 0;
|
||||
m68k->has_fpu = 0;
|
||||
|
||||
define_state(device);
|
||||
}
|
||||
@ -1462,6 +1648,7 @@ static CPU_INIT( m68008 )
|
||||
m68k->cyc_shift = 1;
|
||||
m68k->cyc_reset = 132;
|
||||
m68k->has_pmmu = 0;
|
||||
m68k->has_fpu = 0;
|
||||
|
||||
define_state(device);
|
||||
}
|
||||
@ -1515,6 +1702,7 @@ static CPU_INIT( m68010 )
|
||||
m68k->cyc_shift = 1;
|
||||
m68k->cyc_reset = 130;
|
||||
m68k->has_pmmu = 0;
|
||||
m68k->has_fpu = 0;
|
||||
|
||||
define_state(device);
|
||||
}
|
||||
@ -1597,6 +1785,8 @@ static CPU_INIT( m68020pmmu )
|
||||
CPU_INIT_CALL(m68020);
|
||||
|
||||
m68k->has_pmmu = 1;
|
||||
m68k->has_fpu = 1;
|
||||
|
||||
// hack alert: we use placement new to ensure we are properly initialized
|
||||
// because we live in the device state which is allocated as bytes
|
||||
// remove me when we have a real C++ device
|
||||
@ -1678,6 +1868,7 @@ static CPU_INIT( m68ec020 )
|
||||
m68k->cyc_shift = 0;
|
||||
m68k->cyc_reset = 518;
|
||||
m68k->has_pmmu = 0;
|
||||
m68k->has_fpu = 0;
|
||||
|
||||
define_state(device);
|
||||
}
|
||||
@ -1729,6 +1920,7 @@ static CPU_INIT( m68030 )
|
||||
m68k->cyc_shift = 0;
|
||||
m68k->cyc_reset = 518;
|
||||
m68k->has_pmmu = 1;
|
||||
m68k->has_fpu = 1;
|
||||
|
||||
define_state(device);
|
||||
}
|
||||
@ -1786,6 +1978,7 @@ static CPU_INIT( m68ec030 )
|
||||
m68k->cyc_shift = 0;
|
||||
m68k->cyc_reset = 518;
|
||||
m68k->has_pmmu = 0; /* EC030 lacks the PMMU and is effectively a die-shrink 68020 */
|
||||
m68k->has_fpu = 1;
|
||||
|
||||
define_state(device);
|
||||
}
|
||||
@ -1834,6 +2027,7 @@ static CPU_INIT( m68040 )
|
||||
m68k->cyc_shift = 0;
|
||||
m68k->cyc_reset = 518;
|
||||
m68k->has_pmmu = 1;
|
||||
m68k->has_fpu = 1;
|
||||
|
||||
define_state(device);
|
||||
}
|
||||
@ -1890,6 +2084,7 @@ static CPU_INIT( m68ec040 )
|
||||
m68k->cyc_shift = 0;
|
||||
m68k->cyc_reset = 518;
|
||||
m68k->has_pmmu = 0;
|
||||
m68k->has_fpu = 0;
|
||||
|
||||
define_state(device);
|
||||
}
|
||||
@ -1938,6 +2133,7 @@ static CPU_INIT( m68lc040 )
|
||||
m68k->cyc_shift = 0;
|
||||
m68k->cyc_reset = 518;
|
||||
m68k->has_pmmu = 1;
|
||||
m68k->has_fpu = 0;
|
||||
|
||||
define_state(device);
|
||||
}
|
||||
|
@ -636,6 +636,7 @@ struct _m68ki_cpu_core
|
||||
int has_hmmu; /* Indicates if an Apple HMMU is available in place of the 68851 (020 only) */
|
||||
int pmmu_enabled; /* Indicates if the PMMU is enabled */
|
||||
int hmmu_enabled; /* Indicates if the HMMU is enabled */
|
||||
int has_fpu; /* Indicates if a FPU is available (yes on 030, 040, may be on 020) */
|
||||
int fpu_just_reset; /* Indicates the FPU was just reset */
|
||||
|
||||
/* Clocks required for instructions / exceptions */
|
||||
@ -699,6 +700,12 @@ struct _m68ki_cpu_core
|
||||
UINT32 mmu_atc_tag[MMU_ATC_ENTRIES], mmu_atc_data[MMU_ATC_ENTRIES];
|
||||
UINT32 mmu_atc_rr;
|
||||
UINT32 mmu_tt0, mmu_tt1;
|
||||
|
||||
UINT16 mmu_tmp_sr; /* temporary hack: status code for ptest and to handle write protection */
|
||||
UINT16 mmu_tmp_fc; /* temporary hack: function code for the mmu (moves) */
|
||||
UINT16 mmu_tmp_rw; /* temporary hack: read/write (1/0) for the mmu */
|
||||
UINT32 mmu_tmp_buserror_address; /* temporary hack: (first) bus error address */
|
||||
UINT16 mmu_tmp_buserror_occurred; /* temporary hack: flag that bus error has occurred from mmu */
|
||||
};
|
||||
|
||||
|
||||
@ -807,8 +814,8 @@ INLINE void m68ki_stack_frame_0000(m68ki_cpu_core *m68k, UINT32 pc, UINT32 sr, U
|
||||
INLINE void m68ki_stack_frame_0001(m68ki_cpu_core *m68k, UINT32 pc, UINT32 sr, UINT32 vector);
|
||||
INLINE void m68ki_stack_frame_0010(m68ki_cpu_core *m68k, UINT32 sr, UINT32 vector);
|
||||
INLINE void m68ki_stack_frame_1000(m68ki_cpu_core *m68k, UINT32 pc, UINT32 sr, UINT32 vector);
|
||||
INLINE void m68ki_stack_frame_1010(m68ki_cpu_core *m68k, UINT32 sr, UINT32 vector, UINT32 pc);
|
||||
INLINE void m68ki_stack_frame_1011(m68ki_cpu_core *m68k, UINT32 sr, UINT32 vector, UINT32 pc);
|
||||
INLINE void m68ki_stack_frame_1010(m68ki_cpu_core *m68k, UINT32 sr, UINT32 vector, UINT32 pc, UINT32 fault_address);
|
||||
INLINE void m68ki_stack_frame_1011(m68ki_cpu_core *m68k, UINT32 sr, UINT32 vector, UINT32 pc, UINT32 fault_address);
|
||||
|
||||
INLINE void m68ki_exception_trap(m68ki_cpu_core *m68k, UINT32 vector);
|
||||
INLINE void m68ki_exception_trapN(m68ki_cpu_core *m68k, UINT32 vector);
|
||||
@ -882,17 +889,26 @@ INLINE UINT32 m68ki_read_imm_16(m68ki_cpu_core *m68k)
|
||||
{
|
||||
UINT32 result;
|
||||
|
||||
m68k->mmu_tmp_fc = m68k->s_flag | FUNCTION_CODE_USER_PROGRAM;
|
||||
m68k->mmu_tmp_rw = 1;
|
||||
|
||||
m68ki_check_address_error(m68k, REG_PC, MODE_READ, m68k->s_flag | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */
|
||||
|
||||
if(REG_PC != m68k->pref_addr)
|
||||
{
|
||||
m68k->pref_addr = REG_PC;
|
||||
m68k->pref_data = m68k->memory.readimm16(m68k->pref_addr);
|
||||
m68k->pref_data = m68k->memory.readimm16(REG_PC);
|
||||
m68k->pref_addr = m68k->mmu_tmp_buserror_occurred ? ~0 : REG_PC;
|
||||
}
|
||||
result = MASK_OUT_ABOVE_16(m68k->pref_data);
|
||||
REG_PC += 2;
|
||||
m68k->pref_addr = REG_PC;
|
||||
m68k->pref_data = m68k->memory.readimm16(m68k->pref_addr);
|
||||
if (!m68k->mmu_tmp_buserror_occurred) {
|
||||
// prefetch only if no bus error occurred in opcode fetch
|
||||
m68k->pref_data = m68k->memory.readimm16(REG_PC);
|
||||
m68k->pref_addr = m68k->mmu_tmp_buserror_occurred ? ~0 : REG_PC;
|
||||
// ignore bus error on prefetch
|
||||
m68k->mmu_tmp_buserror_occurred = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -900,6 +916,9 @@ INLINE UINT32 m68ki_read_imm_32(m68ki_cpu_core *m68k)
|
||||
{
|
||||
UINT32 temp_val;
|
||||
|
||||
m68k->mmu_tmp_fc = m68k->s_flag | FUNCTION_CODE_USER_PROGRAM;
|
||||
m68k->mmu_tmp_rw = 1;
|
||||
|
||||
m68ki_check_address_error(m68k, REG_PC, MODE_READ, m68k->s_flag | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */
|
||||
|
||||
if(REG_PC != m68k->pref_addr)
|
||||
@ -914,8 +933,8 @@ INLINE UINT32 m68ki_read_imm_32(m68ki_cpu_core *m68k)
|
||||
|
||||
temp_val = MASK_OUT_ABOVE_32((temp_val << 16) | MASK_OUT_ABOVE_16(m68k->pref_data));
|
||||
REG_PC += 2;
|
||||
m68k->pref_addr = REG_PC;
|
||||
m68k->pref_data = m68k->memory.readimm16(m68k->pref_addr);
|
||||
m68k->pref_data = m68k->memory.readimm16(REG_PC);
|
||||
m68k->pref_addr = m68k->mmu_tmp_buserror_occurred ? ~0 : REG_PC;
|
||||
|
||||
return temp_val;
|
||||
}
|
||||
@ -932,6 +951,8 @@ INLINE UINT32 m68ki_read_imm_32(m68ki_cpu_core *m68k)
|
||||
*/
|
||||
INLINE UINT32 m68ki_read_8_fc(m68ki_cpu_core *m68k, UINT32 address, UINT32 fc)
|
||||
{
|
||||
m68k->mmu_tmp_fc = fc;
|
||||
m68k->mmu_tmp_rw = 1;
|
||||
return m68k->memory.read8(address);
|
||||
}
|
||||
INLINE UINT32 m68ki_read_16_fc(m68ki_cpu_core *m68k, UINT32 address, UINT32 fc)
|
||||
@ -940,6 +961,8 @@ INLINE UINT32 m68ki_read_16_fc(m68ki_cpu_core *m68k, UINT32 address, UINT32 fc)
|
||||
{
|
||||
m68ki_check_address_error(m68k, address, MODE_READ, fc);
|
||||
}
|
||||
m68k->mmu_tmp_fc = fc;
|
||||
m68k->mmu_tmp_rw = 1;
|
||||
return m68k->memory.read16(address);
|
||||
}
|
||||
INLINE UINT32 m68ki_read_32_fc(m68ki_cpu_core *m68k, UINT32 address, UINT32 fc)
|
||||
@ -948,11 +971,15 @@ INLINE UINT32 m68ki_read_32_fc(m68ki_cpu_core *m68k, UINT32 address, UINT32 fc)
|
||||
{
|
||||
m68ki_check_address_error(m68k, address, MODE_READ, fc);
|
||||
}
|
||||
m68k->mmu_tmp_fc = fc;
|
||||
m68k->mmu_tmp_rw = 1;
|
||||
return m68k->memory.read32(address);
|
||||
}
|
||||
|
||||
INLINE void m68ki_write_8_fc(m68ki_cpu_core *m68k, UINT32 address, UINT32 fc, UINT32 value)
|
||||
{
|
||||
m68k->mmu_tmp_fc = fc;
|
||||
m68k->mmu_tmp_rw = 0;
|
||||
m68k->memory.write8(address, value);
|
||||
}
|
||||
INLINE void m68ki_write_16_fc(m68ki_cpu_core *m68k, UINT32 address, UINT32 fc, UINT32 value)
|
||||
@ -961,6 +988,8 @@ INLINE void m68ki_write_16_fc(m68ki_cpu_core *m68k, UINT32 address, UINT32 fc, U
|
||||
{
|
||||
m68ki_check_address_error(m68k, address, MODE_WRITE, fc);
|
||||
}
|
||||
m68k->mmu_tmp_fc = fc;
|
||||
m68k->mmu_tmp_rw = 0;
|
||||
m68k->memory.write16(address, value);
|
||||
}
|
||||
INLINE void m68ki_write_32_fc(m68ki_cpu_core *m68k, UINT32 address, UINT32 fc, UINT32 value)
|
||||
@ -969,6 +998,8 @@ INLINE void m68ki_write_32_fc(m68ki_cpu_core *m68k, UINT32 address, UINT32 fc, U
|
||||
{
|
||||
m68ki_check_address_error(m68k, address, MODE_WRITE, fc);
|
||||
}
|
||||
m68k->mmu_tmp_fc = fc;
|
||||
m68k->mmu_tmp_rw = 0;
|
||||
m68k->memory.write32(address, value);
|
||||
}
|
||||
|
||||
@ -983,6 +1014,8 @@ INLINE void m68ki_write_32_pd_fc(m68ki_cpu_core *m68k, UINT32 address, UINT32 fc
|
||||
{
|
||||
m68ki_check_address_error(m68k, address, MODE_WRITE, fc);
|
||||
}
|
||||
m68k->mmu_tmp_fc = fc;
|
||||
m68k->mmu_tmp_rw = 0;
|
||||
m68k->memory.write16(address+2, value>>16);
|
||||
m68k->memory.write16(address, value&0xffff);
|
||||
}
|
||||
@ -1483,7 +1516,7 @@ void m68ki_stack_frame_1000(m68ki_cpu_core *m68k, UINT32 pc, UINT32 sr, UINT32 v
|
||||
* if the error happens at an instruction boundary.
|
||||
* PC stacked is address of next instruction.
|
||||
*/
|
||||
void m68ki_stack_frame_1010(m68ki_cpu_core *m68k, UINT32 sr, UINT32 vector, UINT32 pc)
|
||||
void m68ki_stack_frame_1010(m68ki_cpu_core *m68k, UINT32 sr, UINT32 vector, UINT32 pc, UINT32 fault_address)
|
||||
{
|
||||
/* INTERNAL REGISTER */
|
||||
m68ki_push_16(m68k, 0);
|
||||
@ -1501,7 +1534,7 @@ void m68ki_stack_frame_1010(m68ki_cpu_core *m68k, UINT32 sr, UINT32 vector, UINT
|
||||
m68ki_push_16(m68k, 0);
|
||||
|
||||
/* DATA CYCLE FAULT ADDRESS (2 words) */
|
||||
m68ki_push_32(m68k, 0);
|
||||
m68ki_push_32(m68k, fault_address);
|
||||
|
||||
/* INSTRUCTION PIPE STAGE B */
|
||||
m68ki_push_16(m68k, 0);
|
||||
@ -1530,7 +1563,7 @@ void m68ki_stack_frame_1010(m68ki_cpu_core *m68k, UINT32 sr, UINT32 vector, UINT
|
||||
* if the error happens during instruction execution.
|
||||
* PC stacked is address of instruction in progress.
|
||||
*/
|
||||
void m68ki_stack_frame_1011(m68ki_cpu_core *m68k, UINT32 sr, UINT32 vector, UINT32 pc)
|
||||
void m68ki_stack_frame_1011(m68ki_cpu_core *m68k, UINT32 sr, UINT32 vector, UINT32 pc, UINT32 fault_address)
|
||||
{
|
||||
/* INTERNAL REGISTERS (18 words) */
|
||||
m68ki_push_32(m68k, 0);
|
||||
@ -1557,7 +1590,7 @@ void m68ki_stack_frame_1011(m68ki_cpu_core *m68k, UINT32 sr, UINT32 vector, UINT
|
||||
m68ki_push_32(m68k, 0);
|
||||
|
||||
/* STAGE B ADDRESS (2 words) */
|
||||
m68ki_push_32(m68k, 0);
|
||||
m68ki_push_32(m68k, fault_address);
|
||||
|
||||
/* INTERNAL REGISTER (4 words) */
|
||||
m68ki_push_32(m68k, 0);
|
||||
|
@ -1719,7 +1719,7 @@ static void d68040_fpu(void)
|
||||
|
||||
char mnemonic[40];
|
||||
UINT32 w2, src, dst_reg;
|
||||
LIMIT_CPU_TYPES(M68030_PLUS);
|
||||
LIMIT_CPU_TYPES(M68020_PLUS);
|
||||
w2 = read_imm_16();
|
||||
|
||||
src = (w2 >> 10) & 0x7;
|
||||
|
@ -366,6 +366,16 @@ static UINT8 READ_EA_8(m68ki_cpu_core *m68k, int ea)
|
||||
UINT32 ea = REG_A[reg];
|
||||
return m68ki_read_8(m68k, ea);
|
||||
}
|
||||
case 3: // (An)+
|
||||
{
|
||||
UINT32 ea = EA_AY_PI_8(m68k);
|
||||
return m68ki_read_8(m68k, ea);
|
||||
}
|
||||
case 4: // -(An)
|
||||
{
|
||||
UINT32 ea = EA_AY_PD_8(m68k);
|
||||
return m68ki_read_8(m68k, ea);
|
||||
}
|
||||
case 5: // (d16, An)
|
||||
{
|
||||
UINT32 ea = EA_AY_DI_8(m68k);
|
||||
@ -392,6 +402,16 @@ static UINT8 READ_EA_8(m68ki_cpu_core *m68k, int ea)
|
||||
UINT32 ea = (d1 << 16) | d2;
|
||||
return m68ki_read_8(m68k, ea);
|
||||
}
|
||||
case 2: // (d16, PC)
|
||||
{
|
||||
UINT32 ea = EA_PCDI_8(m68k);
|
||||
return m68ki_read_8(m68k, ea);
|
||||
}
|
||||
case 3: // (PC) + (Xn) + d8
|
||||
{
|
||||
UINT32 ea = EA_PCIX_8(m68k);
|
||||
return m68ki_read_8(m68k, ea);
|
||||
}
|
||||
case 4: // #<data>
|
||||
{
|
||||
return OPER_I_8(m68k);
|
||||
@ -422,6 +442,16 @@ static UINT16 READ_EA_16(m68ki_cpu_core *m68k, int ea)
|
||||
UINT32 ea = REG_A[reg];
|
||||
return m68ki_read_16(m68k, ea);
|
||||
}
|
||||
case 3: // (An)+
|
||||
{
|
||||
UINT32 ea = EA_AY_PI_16(m68k);
|
||||
return m68ki_read_16(m68k, ea);
|
||||
}
|
||||
case 4: // -(An)
|
||||
{
|
||||
UINT32 ea = EA_AY_PD_16(m68k);
|
||||
return m68ki_read_16(m68k, ea);
|
||||
}
|
||||
case 5: // (d16, An)
|
||||
{
|
||||
UINT32 ea = EA_AY_DI_16(m68k);
|
||||
@ -448,6 +478,16 @@ static UINT16 READ_EA_16(m68ki_cpu_core *m68k, int ea)
|
||||
UINT32 ea = (d1 << 16) | d2;
|
||||
return m68ki_read_16(m68k, ea);
|
||||
}
|
||||
case 2: // (d16, PC)
|
||||
{
|
||||
UINT32 ea = EA_PCDI_16(m68k);
|
||||
return m68ki_read_16(m68k, ea);
|
||||
}
|
||||
case 3: // (PC) + (Xn) + d8
|
||||
{
|
||||
UINT32 ea = EA_PCIX_16(m68k);
|
||||
return m68ki_read_16(m68k, ea);
|
||||
}
|
||||
case 4: // #<data>
|
||||
{
|
||||
return OPER_I_16(m68k);
|
||||
@ -484,6 +524,11 @@ static UINT32 READ_EA_32(m68ki_cpu_core *m68k, int ea)
|
||||
UINT32 ea = EA_AY_PI_32(m68k);
|
||||
return m68ki_read_32(m68k, ea);
|
||||
}
|
||||
case 4: // -(An)
|
||||
{
|
||||
UINT32 ea = EA_AY_PD_32(m68k);
|
||||
return m68ki_read_32(m68k, ea);
|
||||
}
|
||||
case 5: // (d16, An)
|
||||
{
|
||||
UINT32 ea = EA_AY_DI_32(m68k);
|
||||
@ -515,6 +560,11 @@ static UINT32 READ_EA_32(m68ki_cpu_core *m68k, int ea)
|
||||
UINT32 ea = EA_PCDI_32(m68k);
|
||||
return m68ki_read_32(m68k, ea);
|
||||
}
|
||||
case 3: // (PC) + (Xn) + d8
|
||||
{
|
||||
UINT32 ea = EA_PCIX_32(m68k);
|
||||
return m68ki_read_32(m68k, ea);
|
||||
}
|
||||
case 4: // #<data>
|
||||
{
|
||||
return OPER_I_32(m68k);
|
||||
@ -551,6 +601,14 @@ static UINT64 READ_EA_64(m68ki_cpu_core *m68k, int ea)
|
||||
h2 = m68ki_read_32(m68k, ea+4);
|
||||
return (UINT64)(h1) << 32 | (UINT64)(h2);
|
||||
}
|
||||
case 4: // -(An)
|
||||
{
|
||||
UINT32 ea = REG_A[reg]-8;
|
||||
REG_A[reg] -= 8;
|
||||
h1 = m68ki_read_32(m68k, ea+0);
|
||||
h2 = m68ki_read_32(m68k, ea+4);
|
||||
return (UINT64)(h1) << 32 | (UINT64)(h2);
|
||||
}
|
||||
case 5: // (d16, An)
|
||||
{
|
||||
UINT32 ea = EA_AY_DI_32(m68k);
|
||||
@ -558,10 +616,31 @@ static UINT64 READ_EA_64(m68ki_cpu_core *m68k, int ea)
|
||||
h2 = m68ki_read_32(m68k, ea+4);
|
||||
return (UINT64)(h1) << 32 | (UINT64)(h2);
|
||||
}
|
||||
case 6: // (An) + (Xn) + d8
|
||||
{
|
||||
UINT32 ea = EA_AY_IX_32(m68k);
|
||||
h1 = m68ki_read_32(m68k, ea+0);
|
||||
h2 = m68ki_read_32(m68k, ea+4);
|
||||
return (UINT64)(h1) << 32 | (UINT64)(h2);
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
switch (reg)
|
||||
{
|
||||
case 1: // (xxx).L
|
||||
{
|
||||
UINT32 d1 = OPER_I_16(m68k);
|
||||
UINT32 d2 = OPER_I_16(m68k);
|
||||
UINT32 ea = (d1 << 16) | d2;
|
||||
return (UINT64)(m68ki_read_32(m68k, ea)) << 32 | (UINT64)(m68ki_read_32(m68k, ea+4));
|
||||
}
|
||||
case 3: // (PC) + (Xn) + d8
|
||||
{
|
||||
UINT32 ea = EA_PCIX_32(m68k);
|
||||
h1 = m68ki_read_32(m68k, ea+0);
|
||||
h2 = m68ki_read_32(m68k, ea+4);
|
||||
return (UINT64)(h1) << 32 | (UINT64)(h2);
|
||||
}
|
||||
case 4: // #<data>
|
||||
{
|
||||
h1 = OPER_I_32(m68k);
|
||||
@ -608,6 +687,27 @@ static floatx80 READ_EA_FPE(m68ki_cpu_core *m68k, int ea)
|
||||
fpr = load_extended_float80(m68k, ea);
|
||||
break;
|
||||
}
|
||||
case 4: // -(An)
|
||||
{
|
||||
UINT32 ea = REG_A[reg]-12;
|
||||
REG_A[reg] -= 12;
|
||||
fpr = load_extended_float80(m68k, ea);
|
||||
break;
|
||||
}
|
||||
case 5: // (d16, An)
|
||||
{
|
||||
// FIXME: will fail for fmovem
|
||||
UINT32 ea = EA_AY_DI_32(m68k);
|
||||
fpr = load_extended_float80(m68k, ea);
|
||||
break;
|
||||
}
|
||||
case 6: // (An) + (Xn) + d8
|
||||
{
|
||||
// FIXME: will fail for fmovem
|
||||
UINT32 ea = EA_AY_IX_32(m68k);
|
||||
fpr = load_extended_float80(m68k, ea);
|
||||
break;
|
||||
}
|
||||
|
||||
case 7: // extended modes
|
||||
{
|
||||
@ -910,6 +1010,14 @@ static void WRITE_EA_64(m68ki_cpu_core *m68k, int ea, UINT64 data)
|
||||
m68ki_write_32(m68k, ea+4, (UINT32)(data));
|
||||
break;
|
||||
}
|
||||
case 3: // (An)+
|
||||
{
|
||||
UINT32 ea = REG_A[reg];
|
||||
REG_A[reg] += 8;
|
||||
m68ki_write_32(m68k, ea+0, (UINT32)(data >> 32));
|
||||
m68ki_write_32(m68k, ea+4, (UINT32)(data));
|
||||
break;
|
||||
}
|
||||
case 4: // -(An)
|
||||
{
|
||||
UINT32 ea;
|
||||
@ -926,6 +1034,37 @@ static void WRITE_EA_64(m68ki_cpu_core *m68k, int ea, UINT64 data)
|
||||
m68ki_write_32(m68k, ea+4, (UINT32)(data));
|
||||
break;
|
||||
}
|
||||
case 6: // (An) + (Xn) + d8
|
||||
{
|
||||
UINT32 ea = EA_AY_IX_32(m68k);
|
||||
m68ki_write_32(m68k, ea+0, (UINT32)(data >> 32));
|
||||
m68ki_write_32(m68k, ea+4, (UINT32)(data));
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
switch (reg)
|
||||
{
|
||||
case 1: // (xxx).L
|
||||
{
|
||||
UINT32 d1 = OPER_I_16(m68k);
|
||||
UINT32 d2 = OPER_I_16(m68k);
|
||||
UINT32 ea = (d1 << 16) | d2;
|
||||
m68ki_write_32(m68k, ea+0, (UINT32)(data >> 32));
|
||||
m68ki_write_32(m68k, ea+4, (UINT32)(data));
|
||||
break;
|
||||
}
|
||||
case 2: // (d16, PC)
|
||||
{
|
||||
UINT32 ea = EA_PCDI_32(m68k);
|
||||
m68ki_write_32(m68k, ea+0, (UINT32)(data >> 32));
|
||||
m68ki_write_32(m68k, ea+4, (UINT32)(data));
|
||||
break;
|
||||
}
|
||||
default: fatalerror("M68kFPU: WRITE_EA_64: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: fatalerror("M68kFPU: WRITE_EA_64: unhandled mode %d, reg %d, data %08X%08X at %08X\n", mode, reg, (UINT32)(data >> 32), (UINT32)(data), REG_PC);
|
||||
}
|
||||
}
|
||||
@ -1154,6 +1293,7 @@ static void fpgen_rm_reg(m68ki_cpu_core *m68k, UINT16 w2)
|
||||
case 0x00: // FMOVE
|
||||
{
|
||||
REG_FP[dst] = source;
|
||||
SET_CONDITION_CODES(m68k, REG_FP[dst]);
|
||||
m68k->remaining_cycles -= 4;
|
||||
break;
|
||||
}
|
||||
@ -1352,17 +1492,39 @@ static void fmovem(m68ki_cpu_core *m68k, UINT16 w2)
|
||||
int mode = (w2 >> 11) & 0x3;
|
||||
int reglist = w2 & 0xff;
|
||||
|
||||
UINT32 mem_addr = 0;
|
||||
switch (ea >> 3)
|
||||
{
|
||||
case 5: // (d16, An)
|
||||
mem_addr= EA_AY_DI_32(m68k);
|
||||
break;
|
||||
case 6: // (An) + (Xn) + d8
|
||||
mem_addr= EA_AY_IX_32(m68k);
|
||||
break;
|
||||
}
|
||||
|
||||
if (dir) // From FP regs to mem
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case 0: // Static register list, predecrement addressing mode
|
||||
case 0: // Static register list, predecrement or control addressing mode
|
||||
{
|
||||
for (i=0; i < 8; i++)
|
||||
{
|
||||
if (reglist & (1 << i))
|
||||
{
|
||||
WRITE_EA_FPE(m68k, ea, REG_FP[i]);
|
||||
switch (ea >> 3)
|
||||
{
|
||||
case 5: // (d16, An)
|
||||
case 6: // (An) + (Xn) + d8
|
||||
store_extended_float80(m68k, mem_addr, REG_FP[i]);
|
||||
mem_addr += 12;
|
||||
break;
|
||||
default:
|
||||
WRITE_EA_FPE(m68k, ea, REG_FP[i]);
|
||||
break;
|
||||
}
|
||||
|
||||
m68k->remaining_cycles -= 2;
|
||||
}
|
||||
}
|
||||
@ -1376,13 +1538,23 @@ static void fmovem(m68ki_cpu_core *m68k, UINT16 w2)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case 2: // Static register list, postincrement addressing mode
|
||||
case 2: // Static register list, postincrement or control addressing mode
|
||||
{
|
||||
for (i=0; i < 8; i++)
|
||||
{
|
||||
if (reglist & (1 << i))
|
||||
{
|
||||
REG_FP[7-i] = READ_EA_FPE(m68k, ea);
|
||||
switch (ea >> 3)
|
||||
{
|
||||
case 5: // (d16, An)
|
||||
case 6: // (An) + (Xn) + d8
|
||||
REG_FP[7-i] = load_extended_float80(m68k, mem_addr);
|
||||
mem_addr += 12;
|
||||
break;
|
||||
default:
|
||||
REG_FP[7-i] = READ_EA_FPE(m68k, ea);
|
||||
break;
|
||||
}
|
||||
m68k->remaining_cycles -= 2;
|
||||
}
|
||||
}
|
||||
@ -1472,6 +1644,19 @@ void m68040_fpu_op0(m68ki_cpu_core *m68k)
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: // FBcc disp16
|
||||
{
|
||||
switch ((m68k->ir >> 3) & 0x3) {
|
||||
case 1: // FDBcc
|
||||
// TODO:
|
||||
break;
|
||||
default: // FScc (?)
|
||||
// TODO:
|
||||
break;
|
||||
}
|
||||
fatalerror("M68kFPU: unimplemented main op %d with mode %d\n", (m68k->ir >> 6) & 0x3, (m68k->ir >> 3) & 0x7);
|
||||
}
|
||||
|
||||
case 2: // FBcc disp16
|
||||
{
|
||||
fbcc16(m68k);
|
||||
@ -1630,6 +1815,48 @@ void m68040_fpu_op1(m68ki_cpu_core *m68k)
|
||||
}
|
||||
break;
|
||||
|
||||
case 5: // (D16, An)
|
||||
addr = EA_AY_DI_16(m68k);
|
||||
temp = m68ki_read_32(m68k, addr);
|
||||
|
||||
// check for NULL frame
|
||||
if (temp & 0xff000000)
|
||||
{
|
||||
// we don't handle non-NULL frames and there's no pre/post inc/dec to do here
|
||||
m68k->fpu_just_reset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
do_frestore_null(m68k);
|
||||
}
|
||||
break;
|
||||
|
||||
case 7: //
|
||||
switch (reg)
|
||||
{
|
||||
case 2: // (d16, PC)
|
||||
{
|
||||
addr = EA_PCDI_16(m68k);;
|
||||
temp = m68ki_read_32(m68k, addr);
|
||||
|
||||
// check for NULL frame
|
||||
if (temp & 0xff000000)
|
||||
{
|
||||
// we don't handle non-NULL frames and there's no pre/post inc/dec to do here
|
||||
m68k->fpu_just_reset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
do_frestore_null(m68k);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fatalerror("M68kFPU: FRESTORE unhandled mode %d reg %d at %x\n", mode, reg, REG_PC);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
fatalerror("M68kFPU: FRESTORE unhandled mode %d reg %d at %x\n", mode, reg, REG_PC);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
/* ======================================================================== */
|
||||
/*
|
||||
* MUSASHI
|
||||
* Version 4.60
|
||||
* Version 4.70
|
||||
*
|
||||
* A portable Motorola M680x0 processor emulation engine.
|
||||
* Copyright Karl Stenerud. All rights reserved.
|
||||
@ -24,8 +24,8 @@
|
||||
* Modified For OpenVMS By: Robert Alan Byer
|
||||
* byer@mail.ourservers.net
|
||||
*
|
||||
* 68030 and PMMU by R. Belmont
|
||||
* 68040 and FPU by Ville Linde
|
||||
* 68030 and PMMU by R. Belmont and Hans Ostermeyer
|
||||
* 68040 and FPU by Ville Linde, R. Belmont, and Hans Ostermeyer
|
||||
*/
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@
|
||||
*/
|
||||
|
||||
|
||||
static const char g_version[] = "4.60";
|
||||
static const char g_version[] = "4.70";
|
||||
|
||||
/* ======================================================================== */
|
||||
/* =============================== INCLUDES =============================== */
|
||||
|
@ -8,6 +8,44 @@
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
*/
|
||||
|
||||
// MMU status register bit definitions
|
||||
|
||||
#define M68K_MMU_SR_BUS_ERROR 0x8000
|
||||
#define M68K_MMU_SR_SUPERVISOR_ONLY 0x2000
|
||||
#define M68K_MMU_SR_WRITE_PROTECT 0x0800
|
||||
#define M68K_MMU_SR_INVALID 0x0400
|
||||
#define M68K_MMU_SR_MODIFIED 0x0200
|
||||
#define M68K_MMU_SR_LEVEL_0 0x0000
|
||||
#define M68K_MMU_SR_LEVEL_1 0x0001
|
||||
#define M68K_MMU_SR_LEVEL_2 0x0002
|
||||
#define M68K_MMU_SR_LEVEL_3 0x0003
|
||||
|
||||
// MMU translation table descriptor field definitions
|
||||
|
||||
#define M68K_MMU_DF_DT 0x0003
|
||||
#define M68K_MMU_DF_DT0 0x0000
|
||||
#define M68K_MMU_DF_DT1 0x0001
|
||||
#define M68K_MMU_DF_DT2 0x0002
|
||||
#define M68K_MMU_DF_DT3 0x0003
|
||||
#define M68K_MMU_DF_WP 0x0004
|
||||
#define M68K_MMU_DF_USED 0x0008
|
||||
#define M68K_MMU_DF_MODIFIED 0x0010
|
||||
#define M68K_MMU_DF_CI 0x0040
|
||||
#define M68K_MMU_DF_SUPERVISOR 0x0100
|
||||
|
||||
// MMU ATC Fields
|
||||
|
||||
#define M68K_MMU_ATC_BUSERROR 0x08000000
|
||||
#define M68K_MMU_ATC_CACHE_IN 0x04000000
|
||||
#define M68K_MMU_ATC_WRITE_PR 0x02000000
|
||||
#define M68K_MMU_ATC_MODIFIED 0x01000000
|
||||
#define M68K_MMU_ATC_MASK 0x00ffffff
|
||||
#define M68K_MMU_ATC_SHIFT 8
|
||||
#define M68K_MMU_ATC_VALID 0x08000000
|
||||
|
||||
// MMU Translation Control register
|
||||
#define M68K_MMU_TC_SRE 0x02000000
|
||||
|
||||
/* decodes the effective address */
|
||||
static UINT32 DECODE_EA_32(m68ki_cpu_core *m68k, int ea)
|
||||
{
|
||||
@ -68,18 +106,20 @@ static UINT32 DECODE_EA_32(m68ki_cpu_core *m68k, int ea)
|
||||
/*
|
||||
pmmu_atc_add: adds this address to the ATC
|
||||
*/
|
||||
void pmmu_atc_add(m68ki_cpu_core *m68k, UINT32 logical, UINT32 physical)
|
||||
void pmmu_atc_add(m68ki_cpu_core *m68k, UINT32 logical, UINT32 physical, int fc)
|
||||
{
|
||||
int i, found, curfc;
|
||||
int i, found;
|
||||
|
||||
curfc = (m68ki_get_sr(m68k) & 0x2000) ? 4 : 0;
|
||||
curfc |= 1; // program vs. data space is not implemented
|
||||
// get page size (i.e. # of bits to ignore); is 10 for Apollo
|
||||
int ps = (m68k->mmu_tc >> 20) & 0xf;
|
||||
// Note: exact emulation would use (logical >> ps) << (ps-8)
|
||||
UINT32 atc_tag = M68K_MMU_ATC_VALID | ((fc &7) << 24)| logical >> ps;
|
||||
|
||||
// first see if this is already in the cache
|
||||
for (i = 0; i < MMU_ATC_ENTRIES; i++)
|
||||
{
|
||||
// if tag bits and function code match, don't add
|
||||
if (((m68k->mmu_atc_tag[i] & 0xffffff) == (logical>>8)) && (((m68k->mmu_atc_tag[i]>>24) & 7) == curfc))
|
||||
if (m68k->mmu_atc_tag[i] == atc_tag)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -89,7 +129,7 @@ void pmmu_atc_add(m68ki_cpu_core *m68k, UINT32 logical, UINT32 physical)
|
||||
found = -1;
|
||||
for (i = 0; i < MMU_ATC_ENTRIES; i++)
|
||||
{
|
||||
if (!(m68k->mmu_atc_tag[i] & 0x80000000))
|
||||
if (!(m68k->mmu_atc_tag[i] & M68K_MMU_ATC_VALID))
|
||||
{
|
||||
found = i;
|
||||
break;
|
||||
@ -108,9 +148,14 @@ void pmmu_atc_add(m68ki_cpu_core *m68k, UINT32 logical, UINT32 physical)
|
||||
}
|
||||
|
||||
// add the entry
|
||||
// logerror("ATC[%d] add: log %08x -> phys %08x\n", found, logical, physical);
|
||||
m68k->mmu_atc_tag[found] = (logical>>8) | (curfc<<24) | 0x80000000;
|
||||
m68k->mmu_atc_data[found] = (physical>>8);
|
||||
// logerror("ATC[%2d] add: log %08x -> phys %08x (fc=%d)\n", found, (logical>>ps) << ps, (physical >> ps) << ps, fc);
|
||||
m68k->mmu_atc_tag[found] = atc_tag;
|
||||
m68k->mmu_atc_data[found] = (physical >> ps) << (ps-8);
|
||||
|
||||
if (m68k->mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT)
|
||||
{
|
||||
m68k->mmu_atc_data[found] |= M68K_MMU_ATC_WRITE_PR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -121,6 +166,7 @@ void pmmu_atc_add(m68ki_cpu_core *m68k, UINT32 logical, UINT32 physical)
|
||||
void pmmu_atc_flush(m68ki_cpu_core *m68k)
|
||||
{
|
||||
int i;
|
||||
// logerror("ATC flush: pc=%08x\n", REG_PPC);
|
||||
|
||||
for (i = 0; i < MMU_ATC_ENTRIES; i++)
|
||||
{
|
||||
@ -130,39 +176,128 @@ void pmmu_atc_flush(m68ki_cpu_core *m68k)
|
||||
m68k->mmu_atc_rr = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
pmmu_translate_addr: perform 68851/68030-style PMMU address translation
|
||||
*/
|
||||
INLINE UINT32 pmmu_translate_addr(m68ki_cpu_core *m68k, UINT32 addr_in)
|
||||
|
||||
INLINE UINT32 get_dt2_table_entry(m68ki_cpu_core *m68k, UINT32 tptr, UINT8 ptest)
|
||||
{
|
||||
UINT32 addr_out, tbl_entry = 0, tbl_entry2, tamode = 0, tbmode = 0, tcmode = 0;
|
||||
UINT32 root_aptr, root_limit, tofs, is, abits, bbits, cbits;
|
||||
UINT32 resolved, tptr, shift;
|
||||
int curfc, i;
|
||||
UINT32 tbl_entry = m68k->program->read_dword(tptr);
|
||||
UINT32 dt = tbl_entry & M68K_MMU_DF_DT;
|
||||
|
||||
m68k->mmu_tmp_sr |= tbl_entry & 0x0004 ? M68K_MMU_SR_WRITE_PROTECT : 0;
|
||||
|
||||
if (!ptest && dt != M68K_MMU_DF_DT0)
|
||||
{
|
||||
if (dt == M68K_MMU_DF_DT1 && !m68k->mmu_tmp_rw && !(m68k->mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT))
|
||||
{
|
||||
// set used and modified
|
||||
m68k->program->write_dword( tptr, tbl_entry | M68K_MMU_DF_USED | M68K_MMU_DF_MODIFIED);
|
||||
}
|
||||
else if (!(tbl_entry & M68K_MMU_DF_USED))
|
||||
{
|
||||
m68k->program->write_dword( tptr, tbl_entry | M68K_MMU_DF_USED);
|
||||
}
|
||||
}
|
||||
return tbl_entry;
|
||||
}
|
||||
|
||||
INLINE UINT32 get_dt3_table_entry(m68ki_cpu_core *m68k, UINT32 tptr, UINT8 ptest)
|
||||
{
|
||||
UINT32 tbl_entry2 = m68k->program->read_dword(tptr);
|
||||
UINT32 tbl_entry = m68k->program->read_dword(tptr + 4);
|
||||
UINT32 dt = tbl_entry2 & M68K_MMU_DF_DT;
|
||||
|
||||
m68k->mmu_tmp_sr |= tbl_entry2 & 0x0100 ? M68K_MMU_SR_SUPERVISOR_ONLY : 0;
|
||||
m68k->mmu_tmp_sr |= tbl_entry2 & 0x0004 ? M68K_MMU_SR_WRITE_PROTECT : 0;
|
||||
|
||||
if (!ptest)
|
||||
{
|
||||
if (dt == M68K_MMU_DF_DT1 && !m68k->mmu_tmp_rw && !(m68k->mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT))
|
||||
{
|
||||
// set modified
|
||||
m68k->program->write_dword( tptr, tbl_entry2 | M68K_MMU_DF_USED | M68K_MMU_DF_MODIFIED);
|
||||
}
|
||||
else if (!(tbl_entry2 & M68K_MMU_DF_USED))
|
||||
{
|
||||
m68k->program->write_dword( tptr, tbl_entry2 | M68K_MMU_DF_USED);
|
||||
}
|
||||
}
|
||||
|
||||
return (tbl_entry & ~M68K_MMU_DF_DT) | dt;
|
||||
}
|
||||
|
||||
/*
|
||||
pmmu_translate_addr_with_fc: perform 68851/68030-style PMMU address translation
|
||||
*/
|
||||
/*INLINE*/ static UINT32 pmmu_translate_addr_with_fc(m68ki_cpu_core *m68k, UINT32 addr_in, UINT8 fc, UINT8 ptest)
|
||||
{
|
||||
UINT32 addr_out, tbl_entry = 0, tamode = 0, tbmode = 0, tcmode = 0;
|
||||
UINT32 root_aptr, root_limit, tofs, ps, is, abits, bbits, cbits;
|
||||
UINT32 resolved, tptr, shift, last_entry_ptr;
|
||||
int i;
|
||||
UINT32 atc_tag;
|
||||
// int verbose = 0;
|
||||
|
||||
// static UINT32 pmmu_access_count = 0;
|
||||
// static UINT32 pmmu_atc_count = 0;
|
||||
|
||||
resolved = 0;
|
||||
addr_out = addr_in;
|
||||
m68k->mmu_tmp_sr = 0;
|
||||
|
||||
curfc = (m68ki_get_sr(m68k) & 0x2000) ? 4 : 0;
|
||||
curfc |= 1; // program vs. data space is not implemented
|
||||
if (fc == 7)
|
||||
{
|
||||
return addr_in;
|
||||
}
|
||||
|
||||
if (m68k->mmu_tt0 & 0x8000)
|
||||
{
|
||||
// transparent translation register 0 enabled
|
||||
UINT32 address_base = m68k->mmu_tt0 & 0xff000000;
|
||||
UINT32 address_mask = ((m68k->mmu_tt0 << 8) & 0xff000000) ^ 0xff000000;
|
||||
if ((addr_in & address_mask) == address_base)
|
||||
{
|
||||
// logerror("PMMU: pc=%x TT0 fc=%x addr_in=%08x address_mask=%08x address_base=%08x\n", m68k->ppc, fc, addr_in, address_mask, address_base);
|
||||
return addr_in;
|
||||
}
|
||||
}
|
||||
|
||||
// if ((++pmmu_access_count % 10000000) == 0) {
|
||||
// logerror("pmmu_translate_addr_with_fc: atc usage = %d%%\n", pmmu_atc_count*100/pmmu_access_count);
|
||||
// pmmu_atc_count = pmmu_access_count = 0;
|
||||
// }
|
||||
|
||||
// get page size (i.e. # of bits to ignore); ps is 10 or 12 for Apollo, 8 otherwise
|
||||
ps = (m68k->mmu_tc >> 20) & 0xf;
|
||||
atc_tag = M68K_MMU_ATC_VALID | ((fc &7) << 24) | addr_in >> ps;
|
||||
|
||||
// first see if this is already in the ATC
|
||||
for (i = 0; i < MMU_ATC_ENTRIES; i++)
|
||||
{
|
||||
// if tag bits and function code match, we've got it
|
||||
if (((m68k->mmu_atc_tag[i] & 0xffffff) == (addr_in>>8)) && (((m68k->mmu_atc_tag[i]>>24) & 7) == curfc))
|
||||
if (m68k->mmu_atc_tag[i] == atc_tag)
|
||||
{
|
||||
addr_out = (m68k->mmu_atc_data[i]<<8) | (addr_in & 0xff);
|
||||
// logerror("ATC[%d] hit: log %08x -> phys %08x\n", i, addr_in, addr_out);
|
||||
return addr_out;
|
||||
if (m68k->mmu_tmp_rw || !(m68k->mmu_atc_data[i] & M68K_MMU_ATC_WRITE_PR))
|
||||
{
|
||||
// read access or write access and not write protected
|
||||
if (!m68k->mmu_tmp_rw && !ptest)
|
||||
{
|
||||
// FIXME: must set modified in PMMU tables as well
|
||||
m68k->mmu_atc_data[i] |= M68K_MMU_ATC_MODIFIED;
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: supervisor mode?
|
||||
m68k->mmu_tmp_sr = M68K_MMU_SR_MODIFIED;
|
||||
}
|
||||
addr_out = (m68k->mmu_atc_data[i]<<8) | (addr_in & ~(~0 << ps));
|
||||
// logerror("ATC[%2d] hit: log %08x -> phys %08x pc=%08x fc=%d\n", i, addr_in, addr_out, REG_PPC, fc);
|
||||
// pmmu_atc_count++;
|
||||
return addr_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if (addr_in == 0x5fa04c) verbose = 1;
|
||||
|
||||
// if SRP is enabled and we're in supervisor mode, use it
|
||||
if ((m68k->mmu_tc & 0x02000000) && (m68ki_get_sr(m68k) & 0x2000))
|
||||
if ((m68k->mmu_tc & M68K_MMU_TC_SRE) && (fc & 4))
|
||||
{
|
||||
root_aptr = m68k->mmu_srp_aptr;
|
||||
root_limit = m68k->mmu_srp_limit;
|
||||
@ -173,45 +308,50 @@ INLINE UINT32 pmmu_translate_addr(m68ki_cpu_core *m68k, UINT32 addr_in)
|
||||
root_limit = m68k->mmu_crp_limit;
|
||||
}
|
||||
|
||||
// get initial shift (# of top bits to ignore)
|
||||
is = (m68k->mmu_tc>>16) & 0xf;
|
||||
abits = (m68k->mmu_tc>>12)&0xf;
|
||||
bbits = (m68k->mmu_tc>>8)&0xf;
|
||||
cbits = (m68k->mmu_tc>>4)&0xf;
|
||||
// get initial shift (# of top bits to ignore)
|
||||
is = (m68k->mmu_tc >> 16) & 0xf;
|
||||
ps = (m68k->mmu_tc >> 20) & 0xf;
|
||||
abits = (m68k->mmu_tc >> 12) & 0xf;
|
||||
bbits = (m68k->mmu_tc >> 8) & 0xf;
|
||||
cbits = (m68k->mmu_tc >> 4) & 0xf;
|
||||
|
||||
//logerror("PMMU: tcr %08x limit %08x aptr %08x is %x abits %d bbits %d cbits %d\n", m68k->mmu_tc, root_limit, root_aptr, is, abits, bbits, cbits);
|
||||
// logerror("PMMU: tcr %08x limit %08x aptr %08x is %x abits %d bbits %d cbits %d\n", m68k->mmu_tc, root_limit, root_aptr, is, abits, bbits, cbits);
|
||||
|
||||
// get table A offset
|
||||
tofs = (addr_in<<is)>>(32-abits);
|
||||
tptr = root_aptr & 0xfffffff0;
|
||||
|
||||
// find out what format table A is
|
||||
switch (root_limit & 3)
|
||||
switch (root_limit & M68K_MMU_DF_DT)
|
||||
{
|
||||
case 0: // invalid, should cause MMU exception
|
||||
case 1: // page descriptor, should cause direct mapping
|
||||
logerror("680x0 PMMU: Unhandled root mode %d, not translating (addr_in %x)\n", root_limit & 3, addr_in);
|
||||
logerror(" : aptr %08x limit %08x\n", root_aptr, root_limit);
|
||||
return addr_in;
|
||||
break;
|
||||
case M68K_MMU_DF_DT0: // invalid, will cause MMU exception
|
||||
m68k->mmu_tmp_sr |= M68K_MMU_SR_INVALID;
|
||||
return root_aptr;
|
||||
|
||||
case 2: // valid 4 byte descriptors
|
||||
case M68K_MMU_DF_DT1: // page descriptor, will cause direct mapping
|
||||
addr_out = tptr + addr_in;
|
||||
// logerror("PMMU: PC=%x root mode %d (addr_in %08x -> %08x)\n", m68k->ppc, M68K_MMU_DF_DT1, addr_in, addr_out);
|
||||
return addr_out;
|
||||
|
||||
case M68K_MMU_DF_DT2: // valid 4 byte descriptors
|
||||
tofs *= 4;
|
||||
// if (verbose) logerror("PMMU: reading table A entry at %08x\n", tofs + (root_aptr & 0xfffffffc));
|
||||
tbl_entry = m68k->program->read_dword(tofs + (root_aptr & 0xfffffffc));
|
||||
tamode = tbl_entry & 3;
|
||||
// if (verbose) logerror("PMMU: reading table A entry at %08x\n", tofs + tptr);
|
||||
tbl_entry = get_dt2_table_entry(m68k, tptr + tofs, ptest);
|
||||
tamode = tbl_entry & M68K_MMU_DF_DT;
|
||||
// if (verbose) logerror("PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tamode, tofs);
|
||||
break;
|
||||
|
||||
case 3: // valid 8 byte descriptors
|
||||
case M68K_MMU_DF_DT3: // valid 8 byte descriptors
|
||||
tofs *= 8;
|
||||
// if (verbose) logerror("PMMU: reading table A entries at %08x\n", tofs + (root_aptr & 0xfffffffc));
|
||||
tbl_entry2 = m68k->program->read_dword(tofs + (root_aptr & 0xfffffffc));
|
||||
tbl_entry = m68k->program->read_dword(tofs + (root_aptr & 0xfffffffc)+4);
|
||||
tamode = tbl_entry2 & 3;
|
||||
// if (verbose) logerror("PMMU: reading table A entries at %08x\n", tofs + tptr);
|
||||
tbl_entry = get_dt3_table_entry(m68k, tofs + tptr, ptest);
|
||||
tamode = tbl_entry & M68K_MMU_DF_DT;
|
||||
// if (verbose) logerror("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tamode, tofs);
|
||||
break;
|
||||
}
|
||||
|
||||
last_entry_ptr = tptr + tofs;
|
||||
|
||||
// get table B offset and pointer
|
||||
tofs = (addr_in<<(is+abits))>>(32-bbits);
|
||||
tptr = tbl_entry & 0xfffffff0;
|
||||
@ -219,29 +359,32 @@ INLINE UINT32 pmmu_translate_addr(m68ki_cpu_core *m68k, UINT32 addr_in)
|
||||
// find out what format table B is, if any
|
||||
switch (tamode)
|
||||
{
|
||||
case 0: // invalid, should cause MMU exception
|
||||
fatalerror("680x0 PMMU: Unhandled Table A mode %d (addr_in %08x PC %x)\n", tamode, addr_in, m68k->pc);
|
||||
case M68K_MMU_DF_DT0: // invalid, will cause MMU exception (but not for ptest)
|
||||
m68k->mmu_tmp_sr |= (M68K_MMU_SR_INVALID | M68K_MMU_SR_LEVEL_1);
|
||||
// last valid pointer (for ptest)
|
||||
addr_out = last_entry_ptr;
|
||||
resolved = 1;
|
||||
break;
|
||||
|
||||
case 2: // 4-byte table B descriptor
|
||||
case M68K_MMU_DF_DT2: // 4-byte table B descriptor
|
||||
tofs *= 4;
|
||||
// if (verbose) logerror("PMMU: reading table B entry at %08x\n", tofs + tptr);
|
||||
tbl_entry = m68k->program->read_dword(tofs + tptr);
|
||||
tbmode = tbl_entry & 3;
|
||||
tbl_entry = get_dt2_table_entry(m68k, tptr + tofs, ptest);
|
||||
tbmode = tbl_entry & M68K_MMU_DF_DT;
|
||||
// if (verbose) logerror("PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tbmode, tofs);
|
||||
break;
|
||||
|
||||
case 3: // 8-byte table B descriptor
|
||||
case M68K_MMU_DF_DT3: // 8-byte table B descriptor
|
||||
tofs *= 8;
|
||||
// if (verbose) logerror("PMMU: reading table B entries at %08x\n", tofs + tptr);
|
||||
tbl_entry2 = m68k->program->read_dword(tofs + tptr);
|
||||
tbl_entry = m68k->program->read_dword(tofs + tptr + 4);
|
||||
tbmode = tbl_entry2 & 3;
|
||||
tbl_entry = get_dt3_table_entry(m68k, tptr + tofs, ptest);
|
||||
tbmode = tbl_entry & M68K_MMU_DF_DT;
|
||||
tbl_entry &= ~M68K_MMU_DF_DT;
|
||||
// if (verbose) logerror("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tbmode, tofs);
|
||||
break;
|
||||
|
||||
case 1: // early termination descriptor
|
||||
tbl_entry &= 0xffffff00;
|
||||
case M68K_MMU_DF_DT1: // early termination descriptor
|
||||
tbl_entry &= (~0 << ps);
|
||||
|
||||
shift = is+abits;
|
||||
addr_out = ((addr_in<<shift)>>shift) + tbl_entry;
|
||||
@ -252,35 +395,39 @@ INLINE UINT32 pmmu_translate_addr(m68ki_cpu_core *m68k, UINT32 addr_in)
|
||||
// if table A wasn't early-out, continue to process table B
|
||||
if (!resolved)
|
||||
{
|
||||
last_entry_ptr = tptr + tofs;
|
||||
|
||||
// get table C offset and pointer
|
||||
tofs = (addr_in<<(is+abits+bbits))>>(32-cbits);
|
||||
tptr = tbl_entry & 0xfffffff0;
|
||||
|
||||
switch (tbmode)
|
||||
{
|
||||
case 0: // invalid, should cause MMU exception
|
||||
fatalerror("680x0 PMMU: Unhandled Table B mode %d (addr_in %08x PC %x)\n", tbmode, addr_in, m68k->pc);
|
||||
case M68K_MMU_DF_DT0: // invalid, will cause MMU exception (but not for ptest)
|
||||
m68k->mmu_tmp_sr |= (M68K_MMU_SR_INVALID | M68K_MMU_SR_LEVEL_2);
|
||||
// last valid pointer (for ptest)
|
||||
addr_out = last_entry_ptr;
|
||||
resolved = 1;
|
||||
break;
|
||||
|
||||
case 2: // 4-byte table C descriptor
|
||||
case M68K_MMU_DF_DT2: // 4-byte table C descriptor
|
||||
tofs *= 4;
|
||||
// if (verbose) logerror("PMMU: reading table C entry at %08x\n", tofs + tptr);
|
||||
tbl_entry = m68k->program->read_dword(tofs + tptr);
|
||||
tcmode = tbl_entry & 3;
|
||||
tbl_entry = get_dt2_table_entry(m68k, tptr + tofs, ptest);
|
||||
tcmode = tbl_entry & M68K_MMU_DF_DT;
|
||||
// if (verbose) logerror("PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tbmode, tofs);
|
||||
break;
|
||||
|
||||
case 3: // 8-byte table C descriptor
|
||||
case M68K_MMU_DF_DT3: // 8-byte table C descriptor
|
||||
tofs *= 8;
|
||||
// if (verbose) logerror("PMMU: reading table C entries at %08x\n", tofs + tptr);
|
||||
tbl_entry2 = m68k->program->read_dword(tofs + tptr);
|
||||
tbl_entry = m68k->program->read_dword(tofs + tptr + 4);
|
||||
tcmode = tbl_entry2 & 3;
|
||||
// if (verbose) logerror("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tbmode, tofs);
|
||||
tbl_entry = get_dt3_table_entry(m68k, tptr+ tofs, ptest);
|
||||
tcmode = tbl_entry & M68K_MMU_DF_DT;
|
||||
// if (verbose) logerror("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tcmode, tofs);
|
||||
break;
|
||||
|
||||
case 1: // termination descriptor
|
||||
tbl_entry &= 0xffffff00;
|
||||
case M68K_MMU_DF_DT1: // termination descriptor
|
||||
tbl_entry &= (~0 << ps);
|
||||
|
||||
shift = is+abits+bbits;
|
||||
addr_out = ((addr_in<<shift)>>shift) + tbl_entry;
|
||||
@ -293,14 +440,19 @@ INLINE UINT32 pmmu_translate_addr(m68ki_cpu_core *m68k, UINT32 addr_in)
|
||||
{
|
||||
switch (tcmode)
|
||||
{
|
||||
case 0: // invalid, should cause MMU exception
|
||||
case 2: // 4-byte table D descriptor
|
||||
case 3: // 8-byte table D descriptor
|
||||
fatalerror("680x0 PMMU: Unhandled Table C mode %d (addr_in %08x PC %x)\n", tbmode, addr_in, m68k->pc);
|
||||
case M68K_MMU_DF_DT0: // invalid, will cause MMU exception (unless ptest)
|
||||
m68k->mmu_tmp_sr |= (M68K_MMU_SR_INVALID | M68K_MMU_SR_LEVEL_3);
|
||||
addr_out = tptr + tofs;
|
||||
resolved = 1;
|
||||
break;
|
||||
|
||||
case 1: // termination descriptor
|
||||
tbl_entry &= 0xffffff00;
|
||||
case M68K_MMU_DF_DT2: // 4-byte (short-form) indirect descriptor
|
||||
case M68K_MMU_DF_DT3: // 8-byte (long-form) indirect descriptor
|
||||
fatalerror("PMMU: pc=%08x Unhandled Table C mode %d (addr_in %08x)\n", m68k->ppc, tcmode, addr_in);
|
||||
break;
|
||||
|
||||
case M68K_MMU_DF_DT1: // termination descriptor
|
||||
tbl_entry &= (~0 << ps);
|
||||
|
||||
shift = is+abits+bbits+cbits;
|
||||
addr_out = ((addr_in<<shift)>>shift) + tbl_entry;
|
||||
@ -309,13 +461,58 @@ INLINE UINT32 pmmu_translate_addr(m68ki_cpu_core *m68k, UINT32 addr_in)
|
||||
}
|
||||
}
|
||||
|
||||
pmmu_atc_add(m68k, addr_in, addr_out);
|
||||
if (!ptest)
|
||||
{
|
||||
if (m68k->mmu_tmp_sr & M68K_MMU_SR_INVALID)
|
||||
{
|
||||
if (++m68k->mmu_tmp_buserror_occurred == 1)
|
||||
{
|
||||
m68k->mmu_tmp_buserror_address = addr_in;
|
||||
}
|
||||
}
|
||||
else if ((m68k->mmu_tmp_sr & M68K_MMU_SR_SUPERVISOR_ONLY) && !(fc & 4))
|
||||
{
|
||||
if (++m68k->mmu_tmp_buserror_occurred == 1)
|
||||
{
|
||||
m68k->mmu_tmp_buserror_address = addr_in;
|
||||
}
|
||||
}
|
||||
else if ((m68k->mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT) && !m68k->mmu_tmp_rw)
|
||||
{
|
||||
if (++m68k->mmu_tmp_buserror_occurred == 1)
|
||||
{
|
||||
m68k->mmu_tmp_buserror_address = addr_in;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m68k->mmu_tmp_buserror_occurred)
|
||||
{
|
||||
// we add only valid entries
|
||||
pmmu_atc_add(m68k, addr_in, addr_out, fc);
|
||||
}
|
||||
}
|
||||
|
||||
//logerror("PMMU: [%08x] => [%08x]\n", addr_in, addr_out);
|
||||
|
||||
return addr_out;
|
||||
}
|
||||
|
||||
/*
|
||||
pmmu_translate_addr: perform 68851/68030-style PMMU address translation
|
||||
*/
|
||||
/*INLINE*/ static UINT32 pmmu_translate_addr(m68ki_cpu_core *m68k, UINT32 addr_in)
|
||||
{
|
||||
UINT32 addr_out = pmmu_translate_addr_with_fc(m68k, addr_in, m68k->mmu_tmp_fc, 0);
|
||||
|
||||
// if (m68k->mmu_tmp_buserror_occurred > 0) {
|
||||
// logerror("PMMU: pc=%08x sp=%08x va=%08x pa=%08x - invalid Table mode for level=%d (buserror %d)\n",
|
||||
// REG_PPC, REG_A[7], addr_in, addr_out, m68k->mmu_tmp_sr & M68K_MMU_SR_LEVEL_3,
|
||||
// m68k->mmu_tmp_buserror_occurred);
|
||||
// }
|
||||
|
||||
return addr_out;
|
||||
}
|
||||
|
||||
/*
|
||||
m68881_mmu_ops: COP 0 MMU opcode handling
|
||||
|
||||
@ -327,6 +524,7 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
|
||||
UINT32 ea = m68k->ir & 0x3f;
|
||||
UINT64 temp64;
|
||||
|
||||
|
||||
// catch the 2 "weird" encodings up front (PBcc)
|
||||
if ((m68k->ir & 0xffc0) == 0xf0c0)
|
||||
{
|
||||
@ -353,12 +551,12 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
|
||||
ptmp = ltmp;
|
||||
if (m68k->pmmu_enabled)
|
||||
{
|
||||
ptmp = pmmu_translate_addr(m68k, ltmp);
|
||||
ptmp = pmmu_translate_addr_with_fc(m68k, ltmp, modes & 0x07, 0);
|
||||
}
|
||||
|
||||
// logerror("680x0: PLOADing ATC with logical %08x => phys %08x\n", ltmp, ptmp);
|
||||
|
||||
pmmu_atc_add(m68k, ltmp, ptmp);
|
||||
logerror("680x0: PLOADing ATC with logical %08x => phys %08x\n", ltmp, ptmp);
|
||||
// FIXME: rw bit?
|
||||
pmmu_atc_add(m68k, ltmp, ptmp, modes & 0x07);
|
||||
return;
|
||||
}
|
||||
else if ((modes & 0xe200) == 0x2000) // PFLUSH
|
||||
@ -383,7 +581,32 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
|
||||
}
|
||||
else if ((modes & 0xe000) == 0x8000) // PTEST
|
||||
{
|
||||
logerror("680x0: unhandled PTEST\n");
|
||||
UINT32 v_addr = DECODE_EA_32(m68k, ea);
|
||||
UINT32 p_addr;
|
||||
UINT32 fc = modes & 0x1f;
|
||||
switch (fc >> 3) {
|
||||
case 0:
|
||||
fc = fc == 0 ? m68k->sfc : m68k->dfc;
|
||||
break;
|
||||
case 1:
|
||||
fc = REG_D[fc &7] &7;
|
||||
break;
|
||||
case 2:
|
||||
fc &=7;
|
||||
break;
|
||||
}
|
||||
|
||||
p_addr = pmmu_translate_addr_with_fc(m68k, v_addr, fc, 1);
|
||||
m68k->mmu_sr = m68k->mmu_tmp_sr;
|
||||
|
||||
// logerror("PMMU: pc=%08x sp=%08x va=%08x pa=%08x PTEST fc=%x level=%x mmu_sr=%04x\n",
|
||||
// m68k->ppc, REG_A[7], v_addr, p_addr, fc, (modes >> 10) & 0x07, m68k->mmu_sr);
|
||||
|
||||
if (modes & 0x100)
|
||||
{
|
||||
int areg = (modes >> 5) & 7;
|
||||
WRITE_EA_32(m68k, 0x08 | areg, p_addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
@ -394,24 +617,36 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
|
||||
case 2: // MC68881 form, FD never set
|
||||
if (modes & 0x200)
|
||||
{
|
||||
switch ((modes>>10) & 7)
|
||||
{
|
||||
case 0: // translation control register
|
||||
WRITE_EA_32(m68k, ea, m68k->mmu_tc);
|
||||
break;
|
||||
switch ((modes>>10) & 0x3f)
|
||||
{
|
||||
case 0x02: // transparent translation register 0
|
||||
WRITE_EA_32(m68k, ea, m68k->mmu_tt0);
|
||||
// logerror("PMMU: pc=%x PMOVE from mmu_tt0=%08x\n", m68k->ppc, m68k->mmu_tt0);
|
||||
break;
|
||||
case 0x03: // transparent translation register 1
|
||||
WRITE_EA_32(m68k, ea, m68k->mmu_tt1);
|
||||
// logerror("PMMU: pc=%x PMOVE from mmu_tt1=%08x\n", m68k->ppc, m68k->mmu_tt1);
|
||||
break;
|
||||
case 0x10: // translation control register
|
||||
WRITE_EA_32(m68k, ea, m68k->mmu_tc);
|
||||
// logerror("PMMU: pc=%x PMOVE from mmu_tc=%08x\n", m68k->ppc, m68k->mmu_tc);
|
||||
break;
|
||||
|
||||
case 2: // supervisor root pointer
|
||||
WRITE_EA_64(m68k, ea, (UINT64)m68k->mmu_srp_limit<<32 | (UINT64)m68k->mmu_srp_aptr);
|
||||
break;
|
||||
case 0x12: // supervisor root pointer
|
||||
WRITE_EA_64(m68k, ea, (UINT64)m68k->mmu_srp_limit<<32 | (UINT64)m68k->mmu_srp_aptr);
|
||||
// logerror("PMMU: pc=%x PMOVE from SRP limit = %08x, aptr = %08x\n", REG_PPC, m68k->mmu_srp_limit, m68k->mmu_srp_aptr);
|
||||
break;
|
||||
|
||||
case 3: // CPU root pointer
|
||||
WRITE_EA_64(m68k, ea, (UINT64)m68k->mmu_crp_limit<<32 | (UINT64)m68k->mmu_crp_aptr);
|
||||
break;
|
||||
case 0x13: // CPU root pointer
|
||||
WRITE_EA_64(m68k, ea, (UINT64)m68k->mmu_crp_limit<<32 | (UINT64)m68k->mmu_crp_aptr);
|
||||
// logerror("PMMU: pc=%x PMOVE from CRP limit = %08x, aptr = %08x\n", REG_PPC, m68k->mmu_crp_limit, m68k->mmu_crp_aptr);
|
||||
break;
|
||||
|
||||
default:
|
||||
logerror("680x0: PMOVE from unknown MMU register %x, PC %x\n", (modes>>10) & 7, m68k->pc);
|
||||
break;
|
||||
default:
|
||||
logerror("680x0: PMOVE from unknown MMU register %x, PC %x\n", (modes>>10) & 7, m68k->pc);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
else // top 3 bits of modes: 010 for this, 011 for status, 000 for transparent translation regs
|
||||
{
|
||||
@ -464,7 +699,7 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
|
||||
temp64 = READ_EA_64(m68k, ea);
|
||||
m68k->mmu_srp_limit = (temp64>>32) & 0xffffffff;
|
||||
m68k->mmu_srp_aptr = temp64 & 0xffffffff;
|
||||
// logerror("PMMU: SRP limit = %08x aptr = %08x\n", m68k->mmu_srp_limit, m68k->mmu_srp_aptr);
|
||||
// logerror("PMMU: SRP limit = %08x aptr = %08x\n", m68k->mmu_srp_limit, m68k->mmu_srp_aptr);
|
||||
if (!(modes & 0x100))
|
||||
{
|
||||
pmmu_atc_flush(m68k);
|
||||
@ -475,7 +710,7 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
|
||||
temp64 = READ_EA_64(m68k, ea);
|
||||
m68k->mmu_crp_limit = (temp64>>32) & 0xffffffff;
|
||||
m68k->mmu_crp_aptr = temp64 & 0xffffffff;
|
||||
// logerror("PMMU: CRP limit = %08x aptr = %08x\n", m68k->mmu_crp_limit, m68k->mmu_crp_aptr);
|
||||
// logerror("PMMU: CRP limit = %08x aptr = %08x\n", m68k->mmu_crp_limit, m68k->mmu_crp_aptr);
|
||||
if (!(modes & 0x100))
|
||||
{
|
||||
pmmu_atc_flush(m68k);
|
||||
@ -501,11 +736,11 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
|
||||
case 3: // MC68030 to/from status reg
|
||||
if (modes & 0x200)
|
||||
{
|
||||
WRITE_EA_32(m68k, ea, m68k->mmu_sr);
|
||||
WRITE_EA_16(m68k, ea, m68k->mmu_sr);
|
||||
}
|
||||
else
|
||||
{
|
||||
m68k->mmu_sr = READ_EA_32(m68k, ea);
|
||||
m68k->mmu_sr = READ_EA_16(m68k, ea);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -532,25 +767,30 @@ INLINE UINT32 hmmu_translate_addr(m68ki_cpu_core *m68k, UINT32 addr_in)
|
||||
|
||||
addr_out = addr_in;
|
||||
|
||||
// check if LC mode is enabled
|
||||
// check if LC 24-bit mode is enabled - this simply blanks out A31, the V8 ignores A30-24 always
|
||||
if (m68k->hmmu_enabled == M68K_HMMU_ENABLE_LC)
|
||||
{
|
||||
addr_in &= 0xffffff;
|
||||
addr_out &= 0xffffff;
|
||||
addr_out = addr_in & 0xffffff;
|
||||
}
|
||||
else if (m68k->hmmu_enabled == M68K_HMMU_ENABLE_II) // the original II does a more complex translation
|
||||
{
|
||||
addr_out = addr_in & 0xffffff;
|
||||
|
||||
if ((addr_in >= 0xa00000) && (addr_in <= 0xdfffff))
|
||||
if ((addr_in >= 0x800000) && (addr_in <= 0x8fffff))
|
||||
{
|
||||
addr_out |= 0x40000000;
|
||||
addr_out |= 0x40000000; // ROM
|
||||
}
|
||||
if ((addr_in >= 0xe00000) && (addr_in <= 0xefffff))
|
||||
else if ((addr_in >= 0x900000) && (addr_in <= 0xefffff))
|
||||
{
|
||||
addr_out &= 0xfffff;
|
||||
addr_out |= 0xfe000000;
|
||||
addr_out |= 0xf0ff0000; // NuBus
|
||||
addr_out |= ((addr_in & 0xf00000)<<4);
|
||||
}
|
||||
else if (addr_in >= 0xf00000)
|
||||
{
|
||||
addr_out |= 0x50000000;
|
||||
addr_out |= 0x50000000; // I/O
|
||||
}
|
||||
|
||||
// (RAM is at 0 and doesn't need special massaging)
|
||||
}
|
||||
|
||||
return addr_out;
|
||||
|
Loading…
Reference in New Issue
Block a user