From 530f644bd3deb672b7bfefb5f0cba4118baf3b5e Mon Sep 17 00:00:00 2001 From: "R. Belmont" Date: Sat, 14 Nov 2009 18:28:47 +0000 Subject: [PATCH] MC680x0 update - Reworked PMMU/core interface so PMMU now sees all cop 0 instructions - Improved disassembly of PMMU instructions - Preliminary 68LC040 support - Fixed disassembly for EC/LC variants of '030/'040 --- m68k.h | 1 + m68k_in.c | 114 ++------------------------------------------- m68kcpu.c | 36 +++++++++++++- m68kcpu.h | 5 +- m68kdasm.c | 104 +++++++++++++++++++++++++++++++++++------ m68kfpu.c | 134 ++++++++++++++++++++++++++++++----------------------- m68kmake.c | 6 +-- m68kmmu.h | 56 ++++++++++++++++++---- 8 files changed, 263 insertions(+), 193 deletions(-) diff --git a/m68k.h b/m68k.h index bb56378..86bb75b 100644 --- a/m68k.h +++ b/m68k.h @@ -101,6 +101,7 @@ enum M68K_CPU_TYPE_68EC030, M68K_CPU_TYPE_68030, M68K_CPU_TYPE_68EC040, + M68K_CPU_TYPE_68LC040, M68K_CPU_TYPE_68040, M68K_CPU_TYPE_SCC68070 }; diff --git a/m68k_in.c b/m68k_in.c index aeaef47..38d8118 100644 --- a/m68k_in.c +++ b/m68k_in.c @@ -283,6 +283,7 @@ M68KMAKE_OPCODE_HANDLER_HEADER #include "m68kcpu.h" extern void m68040_fpu_op0(void); extern void m68040_fpu_op1(void); +extern void m68881_mmu_ops(); /* ======================================================================== */ /* ========================= INSTRUCTION HANDLERS ========================= */ @@ -769,7 +770,7 @@ pack 16 mm axy7 1000111101001111 .......... . . U U U . . 13 1 pack 16 mm . 1000...101001... .......... . . U U U . . 13 13 13 pea 32 . . 0100100001...... A..DXWLdx. U U U U U 6 6 5 5 5 pflush 32 . . 1111010100011000 .......... . . . . S . . . . 4 TODO: correct timing -pmove 32 . . 1111000000...... A..DXWLdx. . . S S S . . 8 8 8 +pmmu 32 . . 1111000......... .......... . . S S S . . 8 8 8 reset 0 . . 0100111001110000 .......... S S S S S 0 0 0 0 0 ror 8 s . 1110...000011... .......... U U U U U 6 6 8 8 8 ror 16 s . 1110...001011... .......... U U U U U 6 6 8 8 8 @@ -8448,126 +8449,21 @@ M68KMAKE_OP(pea, 32, ., .) m68ki_push_32(ea); } - M68KMAKE_OP(pflush, 32, ., .) { if ((CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) && (HAS_PMMU)) { - fprintf(stderr,"680x0: unhandled PFLUSH\n"); + fprintf(stderr,"68040: unhandled PFLUSH\n"); return; } m68ki_exception_1111(); } -M68KMAKE_OP(pmove, 32, ., .) +M68KMAKE_OP(pmmu, 32, ., .) { - uint16 modes; - uint32 ea; - if ((CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) && (HAS_PMMU)) { - modes = m68ki_read_imm_16(); - ea = M68KMAKE_GET_EA_AY_32; - - 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) - { - switch ((modes>>10) & 7) - { - case 0: // translation control register - m68k_write_memory_16( ea, m68ki_cpu.mmu_tc>>16); - m68k_write_memory_16( ea+2, m68ki_cpu.mmu_tc&0xffff); - break; - - case 2: // supervisor root pointer - m68k_write_memory_16( ea, m68ki_cpu.mmu_srp_limit>>16); - m68k_write_memory_16( ea+2, m68ki_cpu.mmu_srp_limit&0xffff); - m68k_write_memory_16( ea+4, m68ki_cpu.mmu_srp_aptr>>16); - m68k_write_memory_16( ea+6, m68ki_cpu.mmu_srp_aptr&0xffff); - break; - - case 3: // CPU root pointer - m68k_write_memory_16( ea, m68ki_cpu.mmu_crp_limit>>16); - m68k_write_memory_16( ea+2, m68ki_cpu.mmu_crp_limit&0xffff); - m68k_write_memory_16( ea+4, m68ki_cpu.mmu_crp_aptr>>16); - m68k_write_memory_16( ea+6, m68ki_cpu.mmu_crp_aptr&0xffff); - break; - - default: - fprintf(stderr,"680x0: PMOVE from unknown MMU register %x, PC %x\n", (modes>>10) & 7, REG_PC); - break; - } - } - 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, PC %x\n", (modes>>10) & 7, REG_PC); - 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; - } - + m68881_mmu_ops(); } else { diff --git a/m68kcpu.c b/m68kcpu.c index c03509e..1c355ce 100644 --- a/m68kcpu.c +++ b/m68kcpu.c @@ -3,7 +3,7 @@ /* ======================================================================== */ /* * MUSASHI - * Version 4.5 + * Version 4.55 * * A portable Motorola M680x0 processor emulation engine. * Copyright Karl Stenerud. All rights reserved. @@ -40,6 +40,7 @@ extern void m68040_fpu_op0(void); extern void m68040_fpu_op1(void); +extern void m68881_mmu_ops(); extern unsigned char m68ki_cycles[][0x10000]; extern void (*m68ki_instruction_jump_table[0x10000])(void); /* opcode handler jump table */ extern void m68ki_build_opcode_table(void); @@ -893,6 +894,39 @@ void m68k_set_cpu_type(unsigned int cpu_type) CYC_RESET = 518; HAS_PMMU = 1; return; + case M68K_CPU_TYPE_68EC040: // Just a 68040 without pmmu apparently... + CPU_TYPE = CPU_TYPE_EC040; + CPU_ADDRESS_MASK = 0xffffffff; + CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */ + CYC_INSTRUCTION = m68ki_cycles[4]; + CYC_EXCEPTION = m68ki_exception_cycle_table[4]; + CYC_BCC_NOTAKE_B = -2; + CYC_BCC_NOTAKE_W = 0; + CYC_DBCC_F_NOEXP = 0; + CYC_DBCC_F_EXP = 4; + CYC_SCC_R_TRUE = 0; + CYC_MOVEM_W = 2; + CYC_MOVEM_L = 2; + CYC_SHIFT = 0; + CYC_RESET = 518; + HAS_PMMU = 0; + return; + case M68K_CPU_TYPE_68LC040: + CPU_TYPE = CPU_TYPE_LC040; + m68ki_cpu.sr_mask = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */ + m68ki_cpu.cyc_instruction = m68ki_cycles[4]; + m68ki_cpu.cyc_exception = m68ki_exception_cycle_table[4]; + m68ki_cpu.cyc_bcc_notake_b = -2; + m68ki_cpu.cyc_bcc_notake_w = 0; + m68ki_cpu.cyc_dbcc_f_noexp = 0; + m68ki_cpu.cyc_dbcc_f_exp = 4; + m68ki_cpu.cyc_scc_r_true = 0; + m68ki_cpu.cyc_movem_w = 2; + m68ki_cpu.cyc_movem_l = 2; + m68ki_cpu.cyc_shift = 0; + m68ki_cpu.cyc_reset = 518; + HAS_PMMU = 1; + return; } } diff --git a/m68kcpu.h b/m68kcpu.h index 8c3be99..04448b9 100644 --- a/m68kcpu.h +++ b/m68kcpu.h @@ -174,8 +174,9 @@ extern "C" { #define CPU_TYPE_EC030 (0x00000020) #define CPU_TYPE_030 (0x00000040) #define CPU_TYPE_EC040 (0x00000080) -#define CPU_TYPE_040 (0x00000100) -#define CPU_TYPE_SCC070 (0x00000200) +#define CPU_TYPE_LC040 (0x00000100) +#define CPU_TYPE_040 (0x00000200) +#define CPU_TYPE_SCC070 (0x00000400) /* Different ways to stop the CPU */ #define STOP_LEVEL_STOP 1 diff --git a/m68kdasm.c b/m68kdasm.c index 504cd7c..b452b96 100644 --- a/m68kdasm.c +++ b/m68kdasm.c @@ -42,6 +42,10 @@ #define uint32 uint #endif +#ifndef uint16 +#define uint16 unsigned short +#endif + #ifndef DECL_SPEC #define DECL_SPEC #endif @@ -160,6 +164,7 @@ uint peek_imm_32(void); /* make signed integers 100% portably */ static int make_int_8(int value); static int make_int_16(int value); +static int make_int_32(int value); /* make a string of a hex value */ static char* make_signed_hex_str_8(uint val); @@ -247,6 +252,12 @@ static const char *const g_mmuregs[8] = "tc", "drp", "srp", "crp", "cal", "val", "sccr", "acr" }; +static const char *const g_mmucond[16] = +{ + "bs", "bc", "ls", "lc", "ss", "sc", "as", "ac", + "ws", "wc", "is", "ic", "gs", "gc", "cs", "cc" +}; + /* ======================================================================== */ /* =========================== UTILITY FUNCTIONS ========================== */ /* ======================================================================== */ @@ -330,6 +341,10 @@ static int make_int_16(int value) return (value & 0x8000) ? value | ~0xffff : value & 0xffff; } +static int make_int_32(int value) +{ + return (value & 0x80000000) ? value | ~0xffffffff : value & 0xffffffff; +} /* Get string representation of hex values */ static char* make_signed_hex_str_8(uint val) @@ -2559,6 +2574,7 @@ static void d68000_pea(void) sprintf(g_dasm_str, "pea %s", get_ea_mode_str_32(g_cpu_ir)); } +// this is a 68040-specific form of PFLUSH static void d68040_pflush(void) { LIMIT_CPU_TYPES(M68040_PLUS); @@ -3015,7 +3031,16 @@ static void d68020_unpk_mm(void) } -static void d68030_pmove(void) +// PFLUSH: 001xxx0xxxxxxxxx +// PLOAD: 001000x0000xxxxx +// PVALID1: 0010100000000000 +// PVALID2: 0010110000000xxx +// PMOVE 1: 010xxxx000000000 +// PMOVE 2: 011xxxx0000xxx00 +// PMOVE 3: 011xxxx000000000 +// PTEST: 100xxxxxxxxxxxxx +// PFLUSHR: 1010000000000000 +static void d68851_p000(void) { char* str; uint modes = read_imm_16(); @@ -3036,16 +3061,32 @@ static void d68030_pmove(void) return; } - if ((modes & 0xe200) == 0x2000) // PFLUSHA + if ((modes & 0xe200) == 0x2000) // PFLUSH { - 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]); - } + sprintf(g_dasm_str, "pflushr %x, %x, %s", modes & 0x1f, (modes>>5)&0xf, str); + return; + } + + if (modes == 0xa000) // PFLUSHR + { + sprintf(g_dasm_str, "pflushr %s", str); + } + + if (modes == 0x2800) // PVALID (FORMAT 1) + { + sprintf(g_dasm_str, "pvalid VAL, %s", str); + return; + } + + if ((modes & 0xfff8) == 0x2c00) // PVALID (FORMAT 2) + { + sprintf(g_dasm_str, "pvalid A%d, %s", modes & 0xf, str); + return; + } + + if ((modes & 0xe000) == 0x8000) // PTEST + { + sprintf(g_dasm_str, "ptest #%d, %s", modes & 0x1f, str); return; } @@ -3094,6 +3135,33 @@ static void d68030_pmove(void) } } +static void d68851_pbcc16(void) +{ + uint32 temp_pc = g_cpu_pc; + + sprintf(g_dasm_str, "pb%s %x", g_mmucond[g_cpu_ir&0xf], temp_pc + make_int_16(read_imm_16())); +} + +static void d68851_pbcc32(void) +{ + uint32 temp_pc = g_cpu_pc; + + sprintf(g_dasm_str, "pb%s %x", g_mmucond[g_cpu_ir&0xf], temp_pc + make_int_32(read_imm_32())); +} + +static void d68851_pdbcc(void) +{ + uint32 temp_pc = g_cpu_pc; + uint16 modes = read_imm_16(); + + sprintf(g_dasm_str, "pb%s %x", g_mmucond[modes&0xf], temp_pc + make_int_16(read_imm_16())); +} + +// PScc: 0000000000xxxxxx +static void d68851_p001(void) +{ + sprintf(g_dasm_str, "MMU 001 group"); +} /* ======================================================================== */ /* ======================= INSTRUCTION TABLE BUILDER ====================== */ @@ -3417,7 +3485,11 @@ static const opcode_struct g_opcode_info[] = {d68000_unlk , 0xfff8, 0x4e58, 0x000}, {d68020_unpk_rr , 0xf1f8, 0x8180, 0x000}, {d68020_unpk_mm , 0xf1f8, 0x8188, 0x000}, - {d68030_pmove , 0xffc0, 0xf000, 0x278}, + {d68851_p000 , 0xffc0, 0xf000, 0x000}, + {d68851_pbcc16 , 0xffc0, 0xf080, 0x000}, + {d68851_pbcc32 , 0xffc0, 0xf0c0, 0x000}, + {d68851_pdbcc , 0xfff8, 0xf048, 0x000}, + {d68851_p001 , 0xffc0, 0xf040, 0x000}, {0, 0, 0, 0} }; @@ -3553,11 +3625,14 @@ unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned int cpu_ g_cpu_type = TYPE_68020; g_address_mask = 0xffffffff; break; + case M68K_CPU_TYPE_68EC030: case M68K_CPU_TYPE_68030: g_cpu_type = TYPE_68030; g_address_mask = 0xffffffff; break; case M68K_CPU_TYPE_68040: + case M68K_CPU_TYPE_68EC040: + case M68K_CPU_TYPE_68LC040: g_cpu_type = TYPE_68040; g_address_mask = 0xffffffff; break; @@ -3750,6 +3825,7 @@ unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cp case M68K_CPU_TYPE_68EC020: case M68K_CPU_TYPE_68020: case M68K_CPU_TYPE_68030: + case M68K_CPU_TYPE_68EC030: if(g_instruction_table[instruction] == d68040_cinv) return 0; if(g_instruction_table[instruction] == d68040_cpush) @@ -3764,10 +3840,10 @@ unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cp return 0; if(g_instruction_table[instruction] == d68040_move16_al_ai) return 0; - if(g_instruction_table[instruction] == d68040_pflush) - return 0; // Fallthrough case M68K_CPU_TYPE_68040: + case M68K_CPU_TYPE_68EC040: + case M68K_CPU_TYPE_68LC040: if(g_instruction_table[instruction] == d68020_cpbcc_16) return 0; if(g_instruction_table[instruction] == d68020_cpbcc_32) @@ -3788,6 +3864,8 @@ unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cp return 0; if(g_instruction_table[instruction] == d68020_cptrapcc_32) return 0; + if(g_instruction_table[instruction] == d68040_pflush) + return 0; } if(cpu_type != M68K_CPU_TYPE_68020 && cpu_type != M68K_CPU_TYPE_68EC020 && (g_instruction_table[instruction] == d68020_callm || diff --git a/m68kfpu.c b/m68kfpu.c index 5cd6719..bc7208a 100644 --- a/m68kfpu.c +++ b/m68kfpu.c @@ -96,6 +96,11 @@ static uint8 READ_EA_8(int ea) { switch (reg) { + case 0: // (xxx).W + { + uint32 ea = (uint32)OPER_I_16(); + return m68ki_read_8(ea); + } case 1: // (xxx).L { uint32 d1 = OPER_I_16(); @@ -147,6 +152,11 @@ static uint16 READ_EA_16(int ea) { switch (reg) { + case 0: // (xxx).W + { + uint32 ea = (uint32)OPER_I_16(); + return m68ki_read_16(ea); + } case 1: // (xxx).L { uint32 d1 = OPER_I_16(); @@ -204,6 +214,11 @@ static uint32 READ_EA_32(int ea) { switch (reg) { + case 0: // (xxx).W + { + uint32 ea = (uint32)OPER_I_16(); + return m68ki_read_32(ea); + } case 1: // (xxx).L { uint32 d1 = OPER_I_16(); @@ -229,6 +244,63 @@ static uint32 READ_EA_32(int ea) return 0; } +static uint64 READ_EA_64(int ea) +{ + int mode = (ea >> 3) & 0x7; + int reg = (ea & 0x7); + uint32 h1, h2; + + switch (mode) + { + case 2: // (An) + { + uint32 ea = REG_A[reg]; + h1 = m68ki_read_32(ea+0); + h2 = m68ki_read_32(ea+4); + return (uint64)(h1) << 32 | (uint64)(h2); + } + case 3: // (An)+ + { + uint32 ea = REG_A[reg]; + REG_A[reg] += 8; + h1 = m68ki_read_32(ea+0); + h2 = m68ki_read_32(ea+4); + return (uint64)(h1) << 32 | (uint64)(h2); + } + case 5: // (d16, An) + { + uint32 ea = EA_AY_DI_32(); + h1 = m68ki_read_32(ea+0); + h2 = m68ki_read_32(ea+4); + return (uint64)(h1) << 32 | (uint64)(h2); + } + case 7: + { + switch (reg) + { + case 4: // # + { + h1 = OPER_I_32(); + h2 = OPER_I_32(); + return (uint64)(h1) << 32 | (uint64)(h2); + } + case 2: // (d16, PC) + { + uint32 ea = EA_PCDI_32(); + h1 = m68ki_read_32(ea+0); + h2 = m68ki_read_32(ea+4); + return (uint64)(h1) << 32 | (uint64)(h2); + } + default: fatalerror("MC68040: READ_EA_64: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC); + } + break; + } + default: fatalerror("MC68040: READ_EA_64: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC); + } + + return 0; +} + static void WRITE_EA_8(int ea, uint8 data) { int mode = (ea >> 3) & 0x7; @@ -377,6 +449,11 @@ static void WRITE_EA_32(int ea, uint32 data) REG_D[reg] = data; break; } + case 1: // An + { + REG_A[reg] = data; + break; + } case 2: // (An) { uint32 ea = REG_A[reg]; @@ -433,63 +510,6 @@ static void WRITE_EA_32(int ea, uint32 data) } } -static uint64 READ_EA_64(int ea) -{ - int mode = (ea >> 3) & 0x7; - int reg = (ea & 0x7); - uint32 h1, h2; - - switch (mode) - { - case 2: // (An) - { - uint32 ea = REG_A[reg]; - h1 = m68ki_read_32(ea+0); - h2 = m68ki_read_32(ea+4); - return (uint64)(h1) << 32 | (uint64)(h2); - } - case 3: // (An)+ - { - uint32 ea = REG_A[reg]; - REG_A[reg] += 8; - h1 = m68ki_read_32(ea+0); - h2 = m68ki_read_32(ea+4); - return (uint64)(h1) << 32 | (uint64)(h2); - } - case 5: // (d16, An) - { - uint32 ea = EA_AY_DI_32(); - h1 = m68ki_read_32(ea+0); - h2 = m68ki_read_32(ea+4); - return (uint64)(h1) << 32 | (uint64)(h2); - } - case 7: - { - switch (reg) - { - case 4: // # - { - h1 = OPER_I_32(); - h2 = OPER_I_32(); - return (uint64)(h1) << 32 | (uint64)(h2); - } - case 2: // (d16, PC) - { - uint32 ea = EA_PCDI_32(); - h1 = m68ki_read_32(ea+0); - h2 = m68ki_read_32(ea+4); - return (uint64)(h1) << 32 | (uint64)(h2); - } - default: fatalerror("MC68040: READ_EA_64: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC); - } - break; - } - default: fatalerror("MC68040: READ_EA_64: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC); - } - - return 0; -} - static void WRITE_EA_64(int ea, uint64 data) { int mode = (ea >> 3) & 0x7; diff --git a/m68kmake.c b/m68kmake.c index cee5809..fe30855 100644 --- a/m68kmake.c +++ b/m68kmake.c @@ -3,7 +3,7 @@ /* ======================================================================== */ /* * MUSASHI - * Version 4.10 + * Version 4.55 * * A portable Motorola M680x0 processor emulation engine. * Copyright Karl Stenerud. All rights reserved. @@ -56,7 +56,7 @@ */ -static const char g_version[] = "4.10"; +static const char g_version[] = "4.55"; /* ======================================================================== */ /* =============================== INCLUDES =============================== */ @@ -762,7 +762,7 @@ void write_body(FILE* filep, body_struct* body, replace_struct* replace) } /* Found a directive with no matching replace string */ if(!found) - error_exit("Unknown " ID_BASE " directive"); + error_exit("Unknown " ID_BASE " directive [%s]", output); } fprintf(filep, "%s\n", output); } diff --git a/m68kmmu.h b/m68kmmu.h index bb1c326..ff7e6e6 100644 --- a/m68kmmu.h +++ b/m68kmmu.h @@ -25,8 +25,8 @@ inline void fatalerror(char *format, ...) { */ 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; + uint32 addr_out, tbl_entry = 0, tbl_entry2, tamode = 0, tbmode = 0, tcmode = 0; + uint root_aptr, root_limit, tofs, is, abits, bbits, cbits; uint resolved, tptr, shift; resolved = 0; @@ -48,7 +48,7 @@ inline uint pmmu_translate_addr(uint addr_in) 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; + 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); @@ -121,15 +121,34 @@ inline uint pmmu_translate_addr(uint addr_in) // if table A wasn't early-out, continue to process table B if (!resolved) { + // 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 - 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); + fatalerror("680x0 PMMU: Unhandled Table B mode %d (addr_in %08x PC %x)\n", tbmode, addr_in, REG_PC); break; - case 1: // early termination descriptor + case 2: // 4-byte table C descriptor + tofs *= 4; +// fprintf(stderr,"PMMU: reading table C entry at %08x\n", tofs + tptr); + tbl_entry = m68k_read_memory_32(tofs + tptr); + tcmode = 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 C descriptor + tofs *= 8; +// fprintf(stderr,"PMMU: reading table C entries at %08x\n", tofs + tptr); + tbl_entry2 = m68k_read_memory_32(tofs + tptr); + tbl_entry = m68k_read_memory_32(tofs + tptr + 4); + tcmode = 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: // termination descriptor tbl_entry &= 0xffffff00; shift = is+abits+bbits; @@ -139,7 +158,28 @@ inline uint pmmu_translate_addr(uint addr_in) } } -// if ((addr_in < 0x40000000) || (addr_in > 0x4fffffff)) printf("PMMU: [%08x] => [%08x]\n", addr_in, addr_out); + if (!resolved) + { + switch (tcmode) + { + case 0: // invalid, should cause MMU exception + case 2: // 4-byte ??? descriptor + case 3: // 8-byte ??? descriptor + fatalerror("680x0 PMMU: Unhandled Table B mode %d (addr_in %08x PC %x)\n", tbmode, addr_in, REG_PC); + break; + + case 1: // termination descriptor + tbl_entry &= 0xffffff00; + + shift = is+abits+bbits+cbits; + addr_out = ((addr_in<>shift) + tbl_entry; + resolved = 1; + break; + } + } + + +// fprintf(stderr,"PMMU: [%08x] => [%08x]\n", addr_in, addr_out); return addr_out; }