diff --git a/src/emu/cpu/m68000/m68k_in.c b/src/emu/cpu/m68000/m68k_in.c index 64a73f7a36d..29c1b8b0883 100644 --- a/src/emu/cpu/m68000/m68k_in.c +++ b/src/emu/cpu/m68000/m68k_in.c @@ -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; diff --git a/src/emu/cpu/m68000/m68kcpu.c b/src/emu/cpu/m68000/m68kcpu.c index b15304f20fb..47318b40ffc 100644 --- a/src/emu/cpu/m68000/m68kcpu.c +++ b/src/emu/cpu/m68000/m68kcpu.c @@ -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); } diff --git a/src/emu/cpu/m68000/m68kcpu.h b/src/emu/cpu/m68000/m68kcpu.h index 6a1e4918349..21c7e31bf60 100644 --- a/src/emu/cpu/m68000/m68kcpu.h +++ b/src/emu/cpu/m68000/m68kcpu.h @@ -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); diff --git a/src/emu/cpu/m68000/m68kdasm.c b/src/emu/cpu/m68000/m68kdasm.c index 93288363577..522fd70a9a4 100644 --- a/src/emu/cpu/m68000/m68kdasm.c +++ b/src/emu/cpu/m68000/m68kdasm.c @@ -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; diff --git a/src/emu/cpu/m68000/m68kfpu.c b/src/emu/cpu/m68000/m68kfpu.c index e1afc4186fc..934ac3fa704 100644 --- a/src/emu/cpu/m68000/m68kfpu.c +++ b/src/emu/cpu/m68000/m68kfpu.c @@ -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: // # { 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: // # { 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: // # { 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: // # { 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); } diff --git a/src/emu/cpu/m68000/m68kmake.c b/src/emu/cpu/m68000/m68kmake.c index b0d27097750..72268ac5d54 100644 --- a/src/emu/cpu/m68000/m68kmake.c +++ b/src/emu/cpu/m68000/m68kmake.c @@ -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 =============================== */ diff --git a/src/emu/cpu/m68000/m68kmmu.h b/src/emu/cpu/m68000/m68kmmu.h index 97dc968f68f..dc60651a890 100644 --- a/src/emu/cpu/m68000/m68kmmu.h +++ b/src/emu/cpu/m68000/m68kmmu.h @@ -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<>(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) + 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) + 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) + 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;