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
This commit is contained in:
R. Belmont 2009-11-14 18:28:47 +00:00 committed by Emmanuel Anne
parent 3639c27e9c
commit 530f644bd3
8 changed files with 263 additions and 193 deletions

1
m68k.h
View file

@ -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
};

114
m68k_in.c
View file

@ -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
{

View file

@ -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;
}
}

View file

@ -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

View file

@ -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 ||

134
m68kfpu.c
View file

@ -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: // #<data>
{
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: // #<data>
{
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;

View file

@ -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);
}

View file

@ -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)>>shift) + tbl_entry;
resolved = 1;
break;
}
}
// fprintf(stderr,"PMMU: [%08x] => [%08x]\n", addr_in, addr_out);
return addr_out;
}