diff options
author | Oxore <oxore@protonmail.com> | 2022-08-11 23:16:38 +0300 |
---|---|---|
committer | Oxore <oxore@protonmail.com> | 2022-08-25 22:33:54 +0300 |
commit | bfec175173f4e1a350729588526c4ff0be9ac949 (patch) | |
tree | 3bd10776c8c370f05bf4a81eb2e8fc07b1288569 /musashi-m68k/m68kmmu.h |
Initial commit
Diffstat (limited to 'musashi-m68k/m68kmmu.h')
-rw-r--r-- | musashi-m68k/m68kmmu.h | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/musashi-m68k/m68kmmu.h b/musashi-m68k/m68kmmu.h new file mode 100644 index 0000000..b6d9098 --- /dev/null +++ b/musashi-m68k/m68kmmu.h @@ -0,0 +1,321 @@ +/* + 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. +*/ + +/* + pmmu_translate_addr: perform 68851/68030-style PMMU address translation +*/ +uint pmmu_translate_addr(uint addr_in) +{ + 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; + 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<<is)>>(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)>>shift) + tbl_entry; + resolved = 1; + break; + } + + // 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 + fatalerror("680x0 PMMU: Unhandled Table B mode %d (addr_in %08x PC %x)\n", tbmode, addr_in, REG_PC); + break; + + 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; + addr_out = ((addr_in<<shift)>>shift) + tbl_entry; + resolved = 1; + break; + } + } + + 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)>>shift) + tbl_entry; + resolved = 1; + break; + } + } + + +// fprintf(stderr,"PMMU: [%08x] => [%08x]\n", addr_in, addr_out); + + return addr_out; +} + +/* + + m68881_mmu_ops: COP 0 MMU opcode handling + +*/ + +void m68881_mmu_ops(void) +{ + uint16 modes; + uint32 ea = m68ki_cpu.ir & 0x3f; + uint64 temp64; + + // catch the 2 "weird" encodings up front (PBcc) + if ((m68ki_cpu.ir & 0xffc0) == 0xf0c0) + { + fprintf(stderr,"680x0: unhandled PBcc\n"); + return; + } + else if ((m68ki_cpu.ir & 0xffc0) == 0xf080) + { + fprintf(stderr,"680x0: unhandled PBcc\n"); + return; + } + else // the rest are 1111000xxxXXXXXX where xxx is the instruction family + { + switch ((m68ki_cpu.ir>>9) & 0x7) + { + case 0: + modes = OPER_I_16(); + + if ((modes & 0xfde0) == 0x2000) // PLOAD + { + fprintf(stderr,"680x0: unhandled PLOAD\n"); + return; + } + else if ((modes & 0xe200) == 0x2000) // PFLUSH + { + fprintf(stderr,"680x0: unhandled PFLUSH PC=%x\n", REG_PC); + return; + } + else if (modes == 0xa000) // PFLUSHR + { + fprintf(stderr,"680x0: unhandled PFLUSHR\n"); + return; + } + else if (modes == 0x2800) // PVALID (FORMAT 1) + { + fprintf(stderr,"680x0: unhandled PVALID1\n"); + return; + } + else if ((modes & 0xfff8) == 0x2c00) // PVALID (FORMAT 2) + { + fprintf(stderr,"680x0: unhandled PVALID2\n"); + return; + } + else if ((modes & 0xe000) == 0x8000) // PTEST + { + fprintf(stderr,"680x0: unhandled PTEST\n"); + return; + } + else + { + 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 + WRITE_EA_32(ea, m68ki_cpu.mmu_tc); + break; + + case 2: // supervisor root pointer + WRITE_EA_64(ea, (uint64)m68ki_cpu.mmu_srp_limit<<32 | (uint64)m68ki_cpu.mmu_srp_aptr); + break; + + case 3: // CPU root pointer + WRITE_EA_64(ea, (uint64)m68ki_cpu.mmu_crp_limit<<32 | (uint64)m68ki_cpu.mmu_crp_aptr); + 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 = READ_EA_32(ea); + + if (m68ki_cpu.mmu_tc & 0x80000000) + { + m68ki_cpu.pmmu_enabled = 1; + } + else + { + m68ki_cpu.pmmu_enabled = 0; + } + break; + + case 2: // supervisor root pointer + temp64 = READ_EA_64(ea); + m68ki_cpu.mmu_srp_limit = (temp64>>32) & 0xffffffff; + m68ki_cpu.mmu_srp_aptr = temp64 & 0xffffffff; + break; + + case 3: // CPU root pointer + temp64 = READ_EA_64(ea); + m68ki_cpu.mmu_crp_limit = (temp64>>32) & 0xffffffff; + m68ki_cpu.mmu_crp_aptr = temp64 & 0xffffffff; + 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) + { + WRITE_EA_32(ea, m68ki_cpu.mmu_sr); + } + else + { + m68ki_cpu.mmu_sr = READ_EA_32(ea); + } + break; + + default: + fprintf(stderr,"680x0: unknown PMOVE mode %x (modes %04x) (PC %x)\n", (modes>>13) & 0x7, modes, REG_PC); + break; + } + } + break; + + default: + fprintf(stderr,"680x0: unknown PMMU instruction group %d\n", (m68ki_cpu.ir>>9) & 0x7); + break; + } + } +} + |