diff --git a/m68k_in.c b/m68k_in.c index bcb8851..300d9ae 100644 --- a/m68k_in.c +++ b/m68k_in.c @@ -8469,7 +8469,81 @@ M68KMAKE_OP(pmove, 32, ., .) modes = m68ki_read_imm_16(); ea = M68KMAKE_GET_EA_AY_32; - fprintf(stderr,"680x0: unhandled PMOVE modes %x ea %x\n", modes, ea); + if ((modes & 0xfde0) == 0x2000) // PLOAD + { + fprintf(stderr,"680x0: unhandled PLOAD\n"); + return; + } + + if ((modes & 0xe200) == 0x2000) // PFLUSHA + { + fprintf(stderr,"680x0: unhandled PFLUSHA\n"); + return; + } + + switch ((modes>>13) & 0x7) + { + case 0: // MC68030/040 form with FD bit + case 2: // MC68881 form, FD never set + if (modes & 0x200) + { + fprintf(stderr,"680x0: PMOVE from MMU not supported\n"); + } + else + { + switch ((modes>>10) & 7) + { + case 0: // translation control register + m68ki_cpu.mmu_tc = m68k_read_memory_16( ea)<<16; + m68ki_cpu.mmu_tc |= m68k_read_memory_16( ea+2); + + if (m68ki_cpu.mmu_tc & 0x80000000) + { + m68ki_cpu.pmmu_enabled = 1; + } + else + { + m68ki_cpu.pmmu_enabled = 0; + } + break; + + case 2: // supervisor root pointer + m68ki_cpu.mmu_srp_limit = m68k_read_memory_16( ea)<<16; + m68ki_cpu.mmu_srp_limit |= m68k_read_memory_16( ea+2); + m68ki_cpu.mmu_srp_aptr = m68k_read_memory_16( ea+4)<<16; + m68ki_cpu.mmu_srp_aptr |= m68k_read_memory_16( ea+6); + break; + + case 3: // CPU root pointer + m68ki_cpu.mmu_crp_limit = m68k_read_memory_16( ea)<<16; + m68ki_cpu.mmu_crp_limit |= m68k_read_memory_16( ea+2); + m68ki_cpu.mmu_crp_aptr = m68k_read_memory_16( ea+4)<<16; + m68ki_cpu.mmu_crp_aptr |= m68k_read_memory_16( ea+6); + break; + + default: + fprintf(stderr,"680x0: PMOVE to unknown MMU register %x\n", (modes>>10) & 7); + break; + } + } + break; + + case 3: // MC68030 to/from status reg + if (modes & 0x200) + { + m68k_write_memory_16(ea, m68ki_cpu.mmu_sr); + } + else + { + m68ki_cpu.mmu_sr = m68k_read_memory_16( ea); + } + break; + + default: + fprintf(stderr,"680x0: unknown PMOVE mode %x (modes %04x) (PC %x)\n", (modes>>13) & 0x7, modes, REG_PC); + break; + } + } else { diff --git a/m68kconf.h b/m68kconf.h index 044b219..8844952 100644 --- a/m68kconf.h +++ b/m68kconf.h @@ -184,6 +184,9 @@ #define M68K_LOG_1010_1111 OPT_OFF #define M68K_LOG_FILEHANDLE some_file_handle +/* Emulate PMMU : if you enable this, there will be a test to see if the current chip has some enabled pmmu added to every memory access, + * so enable this only if it's useful */ +#define M68K_EMULATE_PMMU OPT_ON /* ----------------------------- COMPATIBILITY ---------------------------- */ diff --git a/m68kcpu.c b/m68kcpu.c index 2aecbe3..c03509e 100644 --- a/m68kcpu.c +++ b/m68kcpu.c @@ -3,7 +3,7 @@ /* ======================================================================== */ /* * MUSASHI - * Version 4.10 + * Version 4.5 * * A portable Motorola M680x0 processor emulation engine. * Copyright Karl Stenerud. All rights reserved. @@ -597,7 +597,6 @@ static void default_instr_hook_callback(unsigned int pc) jmp_buf m68ki_aerr_trap; #endif /* M68K_EMULATE_ADDRESS_ERROR */ - /* ======================================================================== */ /* ================================= API ================================== */ /* ======================================================================== */ @@ -1046,6 +1045,9 @@ void m68k_init(void) /* Pulse the RESET line on the CPU */ void m68k_pulse_reset(void) { + /* Disable the PMMU on reset */ + m68ki_cpu.pmmu_enabled = 0; + /* Clear all stop levels and eat up all remaining cycles */ CPU_STOPPED = 0; SET_CYCLES(0); @@ -1088,7 +1090,6 @@ void m68k_pulse_halt(void) CPU_STOPPED |= STOP_LEVEL_HALT; } - /* Get and set the current CPU context */ /* This is to allow for multiple CPUs */ unsigned int m68k_context_size() diff --git a/m68kcpu.h b/m68kcpu.h index 70cefbb..e86f566 100644 --- a/m68kcpu.h +++ b/m68kcpu.h @@ -3,7 +3,7 @@ /* ======================================================================== */ /* * MUSASHI - * Version 3.32 + * Version 4.5 * * A portable Motorola M680x0 processor emulation engine. * Copyright Karl Stenerud. All rights reserved. @@ -267,7 +267,11 @@ extern "C" { #endif /* M68K_INT_GT_32_BIT || M68K_USE_64_BIT */ /* Simulate address lines of 68k family */ +#if M68K_EMULATE_PMMU +#define ADDRESS_68K(A) (PMMU_ENABLED ? pmmu_translate_addr((A)&CPU_ADDRESS_MASK) : ((A)&CPU_ADDRESS_MASK)) +#else #define ADDRESS_68K(A) ((A)&CPU_ADDRESS_MASK) +#endif /* Shift & Rotate Macros. */ @@ -369,6 +373,7 @@ extern "C" { #define CYC_SHIFT m68ki_cpu.cyc_shift #define CYC_RESET m68ki_cpu.cyc_reset #define HAS_PMMU m68ki_cpu.has_pmmu +#define PMMU_ENABLED m68ki_cpu.pmmu_enabled #define RESET_CYCLES m68ki_cpu.reset_cycles @@ -945,6 +950,7 @@ typedef struct uint instr_mode; /* Stores whether we are in instruction mode or group 0/1 exception mode */ uint run_mode; /* Stores whether we are processing a reset, bus error, address error, or something else */ int has_pmmu; /* Indicates if a PMMU available (yes on 030, 040, no on EC030) */ + int pmmu_enabled; /* Indicates if the PMMU is enabled */ uint reset_cycles; /* Clocks required for instructions / exceptions */ @@ -962,6 +968,12 @@ typedef struct uint virq_state; uint nmi_pending; + /* PMMU registers */ + uint mmu_crp_aptr, mmu_crp_limit; + uint mmu_srp_aptr, mmu_srp_limit; + uint mmu_tc; + uint16 mmu_sr; + const uint8* cyc_instruction; const uint8* cyc_exception; @@ -1011,6 +1023,8 @@ char* m68ki_disassemble_quick(unsigned int pc, unsigned int cpu_type); /* ---------------------------- Read Immediate ---------------------------- */ +#include "m68kmmu.h" + /* Handles all immediate reads, does address error check, function code setting, * and prefetching if they are enabled in m68kconf.h */ diff --git a/m68kdasm.c b/m68kdasm.c index 83d9d47..c035cf0 100644 --- a/m68kdasm.c +++ b/m68kdasm.c @@ -3019,6 +3019,32 @@ static void d68030_pmove(void) // do this after fetching the second PMOVE word so we properly get the 3rd if necessary str = get_ea_mode_str_32(g_cpu_ir); + if ((modes & 0xfde0) == 0x2000) // PLOAD + { + if (modes & 0x0200) + { + sprintf(g_dasm_str, "pload #%d, %s", (modes>>10)&7, str); + } + else + { + sprintf(g_dasm_str, "pload %s, #%d", str, (modes>>10)&7); + } + return; + } + + if ((modes & 0xe200) == 0x2000) // PFLUSHA + { + if (modes & 0x0200) + { + sprintf(g_dasm_str, "pflush %s, %s", g_mmuregs[(modes>>10)&7], str); + } + else + { + sprintf(g_dasm_str, "pflush %s, %s", str, g_mmuregs[(modes>>10)&7]); + } + return; + } + switch ((modes>>13) & 0x7) { case 0: // MC68030/040 form with FD bit @@ -3767,7 +3793,7 @@ unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cp return 1; } - +// f028 2215 0008 /* ======================================================================== */ /* ============================== END OF FILE ============================= */ diff --git a/m68kfpu.c b/m68kfpu.c index e27b129..de7beb9 100644 --- a/m68kfpu.c +++ b/m68kfpu.c @@ -1,27 +1,6 @@ #include -#include -#include #include "m68kcpu.h" -extern void exit(int); - -#if defined(_MSC_VER) -# define NORETURN __declspec(noreturn) -#elif defined(__clang__) || defined(__GNUC__) -# define NORETURN __attribute__((noreturn)) -#else -# define NORETURN -#endif - -// TODO: Remove this and replace with a non-fatal signaling mechanism -static NORETURN void fatalerror(char *format, ...) { - va_list ap; - va_start(ap,format); - fprintf(stderr,format,ap); - va_end(ap); - exit(1); -} - #define FPCC_N 0x08000000 #define FPCC_Z 0x04000000 #define FPCC_I 0x02000000 diff --git a/m68kmmu.h b/m68kmmu.h new file mode 100644 index 0000000..bb1c326 --- /dev/null +++ b/m68kmmu.h @@ -0,0 +1,193 @@ +/* + m68kmmu.h - PMMU implementation for 68851/68030/68040 + + By R. Belmont + + Copyright Nicola Salmoria and the MAME Team. + Visit http://mamedev.org for licensing and usage restrictions. +*/ +#include +#include + +extern void exit(int); + +// TODO: Remove this and replace with a non-fatal signaling mechanism +inline void fatalerror(char *format, ...) { + va_list ap; + va_start(ap,format); + fprintf(stderr,format,ap); + va_end(ap); + exit(1); +} + +/* + pmmu_translate_addr: perform 68851/68030-style PMMU address translation +*/ +inline uint pmmu_translate_addr(uint addr_in) +{ + uint addr_out, tbl_entry, tbl_entry2, tamode, tbmode; + uint root_aptr, root_limit, tofs, is, abits, bbits; // , cbits; + uint resolved, tptr, shift; + + resolved = 0; + addr_out = addr_in; + + // if SRP is enabled and we're in supervisor mode, use it + if ((m68ki_cpu.mmu_tc & 0x02000000) && (m68ki_get_sr() & 0x2000)) + { + root_aptr = m68ki_cpu.mmu_srp_aptr; + root_limit = m68ki_cpu.mmu_srp_limit; + } + else // else use the CRP + { + root_aptr = m68ki_cpu.mmu_crp_aptr; + root_limit = m68ki_cpu.mmu_crp_limit; + } + + // get initial shift (# of top bits to ignore) + is = (m68ki_cpu.mmu_tc>>16) & 0xf; + abits = (m68ki_cpu.mmu_tc>>12)&0xf; + bbits = (m68ki_cpu.mmu_tc>>8)&0xf; + // cbits = (m68ki_cpu.mmu_tc>>4)&0xf; + +// fprintf(stderr,"PMMU: tcr %08x limit %08x aptr %08x is %x abits %d bbits %d cbits %d\n", m68ki_cpu.mmu_tc, root_limit, root_aptr, is, abits, bbits, cbits); + + // get table A offset + tofs = (addr_in<>(32-abits); + + // find out what format table A is + switch (root_limit & 3) + { + case 0: // invalid, should cause MMU exception + case 1: // page descriptor, should cause direct mapping + fatalerror("680x0 PMMU: Unhandled root mode\n"); + break; + + case 2: // valid 4 byte descriptors + tofs *= 4; +// fprintf(stderr,"PMMU: reading table A entry at %08x\n", tofs + (root_aptr & 0xfffffffc)); + tbl_entry = m68k_read_memory_32( tofs + (root_aptr & 0xfffffffc)); + tamode = tbl_entry & 3; +// fprintf(stderr,"PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tamode, tofs); + break; + + case 3: // valid 8 byte descriptors + tofs *= 8; +// fprintf(stderr,"PMMU: reading table A entries at %08x\n", tofs + (root_aptr & 0xfffffffc)); + tbl_entry2 = m68k_read_memory_32( tofs + (root_aptr & 0xfffffffc)); + tbl_entry = m68k_read_memory_32( tofs + (root_aptr & 0xfffffffc)+4); + tamode = tbl_entry2 & 3; +// fprintf(stderr,"PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tamode, tofs); + break; + } + + // get table B offset and pointer + tofs = (addr_in<<(is+abits))>>(32-bbits); + tptr = tbl_entry & 0xfffffff0; + + // 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)\n", tamode, addr_in); + break; + + case 2: // 4-byte table B descriptor + tofs *= 4; +// fprintf(stderr,"PMMU: reading table B entry at %08x\n", tofs + tptr); + tbl_entry = m68k_read_memory_32( tofs + tptr); + tbmode = tbl_entry & 3; +// fprintf(stderr,"PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tbmode, tofs); + break; + + case 3: // 8-byte table B descriptor + tofs *= 8; +// fprintf(stderr,"PMMU: reading table B entries at %08x\n", tofs + tptr); + tbl_entry2 = m68k_read_memory_32( tofs + tptr); + tbl_entry = m68k_read_memory_32( tofs + tptr + 4); + tbmode = tbl_entry2 & 3; +// fprintf(stderr,"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; + + shift = is+abits; + addr_out = ((addr_in<>shift) + tbl_entry; + resolved = 1; + break; + } + + // if table A wasn't early-out, continue to process table B + if (!resolved) + { + switch (tbmode) + { + case 0: // invalid, should cause MMU exception + case 2: // 4-byte table C descriptor + case 3: // 8-byte table C descriptor + fatalerror("680x0 PMMU: Unhandled Table B mode %d (addr_in %08x)\n", tbmode, addr_in); + break; + + case 1: // early termination descriptor + tbl_entry &= 0xffffff00; + + shift = is+abits+bbits; + addr_out = ((addr_in<>shift) + tbl_entry; + resolved = 1; + break; + } + } + +// if ((addr_in < 0x40000000) || (addr_in > 0x4fffffff)) printf("PMMU: [%08x] => [%08x]\n", addr_in, addr_out); + + return addr_out; +} + +/* + +maincpu at 40804366: called unimplemented instruction f000 (cpgen) +PMMU: tcr 80f05570 limit 7fff0003 aptr 043ffcc0 is 0 +PMMU: reading table A entries at 043ffce0 +PMMU: addr 4080438a entry 00000000 entry2 7ffffc18 mode 0 aofs 20 +680x0 PMMU: Unhandled Table A mode 0 + +enable, PS = f + +tblA @ 043ffcc0: + +043ffcc0 0001fc0a 043ffcb0 => 00000019 04000019 +043ffcc8 7ffffc18 00000000 +043ffcd0 7ffffc18 00000000 +043ffcd8 7ffffc18 00000000 +043ffce0 7ffffc18 00000000 +043ffce8 7ffffc18 00000000 +043ffcf0 7ffffc18 00000000 +043ffcf8 7ffffc18 00000000 +043ffd00 7ffffc19 40000000 +043ffd08 7ffffc19 48000000 +043ffd10 7ffffc59 50000000 +043ffd18 7ffffc59 58000000 +043ffd20 7ffffc59 60000000 +043ffd28 7ffffc59 68000000 +043ffd30 7ffffc59 70000000 +043ffd38 7ffffc59 78000000 +043ffd40 7ffffc59 80000000 +043ffd48 7ffffc59 88000000 +043ffd50 7ffffc59 90000000 +043ffd58 7ffffc59 98000000 +043ffd60 7ffffc59 a0000000 +043ffd68 7ffffc59 a8000000 +043ffd70 7ffffc59 b0000000 +043ffd78 7ffffc59 b8000000 +043ffd80 7ffffc59 c0000000 +043ffd88 7ffffc59 c8000000 +043ffd90 7ffffc59 d0000000 +043ffd98 7ffffc59 d8000000 +043ffda0 7ffffc59 e0000000 +043ffda8 7ffffc59 e8000000 +043ffdb0 7ffffc59 f0000000 +043ffdb8 7ffffc59 f8000000 + +*/ +