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
parent e3dfa2d83e
commit fa216ba6f9
9 changed files with 422 additions and 247 deletions

View File

@ -976,7 +976,7 @@ endif
# rule to ensure we build the header before building the core CPU file
$(CPUOBJ)/m68000/m68kcpu.o: $(CPUOBJ)/m68000/m68kops.c \
$(CPUSRC)/m68000/m68kcpu.h
$(CPUSRC)/m68000/m68kcpu.h $(CPUSRC)/m68000/m68kfpu.c $(CPUSRC)/m68000/m68kmmu.h

View File

@ -29,6 +29,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
};
@ -93,6 +94,7 @@ CPU_GET_INFO( scc68070 );
#define CPU_M68EC030 CPU_GET_INFO_NAME( m68ec030 )
#define CPU_M68030 CPU_GET_INFO_NAME( m68030 )
#define CPU_M68EC040 CPU_GET_INFO_NAME( m68ec040 )
#define CPU_M68LC040 CPU_GET_INFO_NAME( m68lc040 )
#define CPU_M68040 CPU_GET_INFO_NAME( m68040 )
#define CPU_SCC68070 CPU_GET_INFO_NAME( scc68070 )

View File

@ -262,6 +262,7 @@ M68KMAKE_OPCODE_HANDLER_HEADER
#include "mame.h"
extern void m68040_fpu_op0(m68ki_cpu_core *m68k);
extern void m68040_fpu_op1(m68ki_cpu_core *m68k);
extern void m68881_mmu_ops(m68ki_cpu_core *m68k);
/* ======================================================================== */
/* ========================= INSTRUCTION HANDLERS ========================= */
@ -748,7 +749,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
@ -7994,126 +7995,21 @@ M68KMAKE_OP(pea, 32, ., .)
m68ki_push_32(m68k, ea);
}
M68KMAKE_OP(pflush, 32, ., .)
{
if ((CPU_TYPE_IS_EC020_PLUS(m68k->cpu_type)) && (m68k->has_pmmu))
{
logerror("680x0: unhandled PFLUSH\n");
logerror("68040: unhandled PFLUSH\n");
return;
}
m68ki_exception_1111(m68k);
}
M68KMAKE_OP(pmove, 32, ., .)
M68KMAKE_OP(pmmu, 32, ., .)
{
UINT16 modes;
UINT32 ea;
if ((CPU_TYPE_IS_EC020_PLUS(m68k->cpu_type)) && (m68k->has_pmmu))
{
modes = m68ki_read_imm_16(m68k);
ea = M68KMAKE_GET_EA_AY_32;
if ((modes & 0xfde0) == 0x2000) // PLOAD
{
logerror("680x0: unhandled PLOAD\n");
return;
}
if ((modes & 0xe200) == 0x2000) // PFLUSHA
{
logerror("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
memory_write_word_32be(m68k->program, ea, m68k->mmu_tc>>16);
memory_write_word_32be(m68k->program, ea+2, m68k->mmu_tc&0xffff);
break;
case 2: // supervisor root pointer
memory_write_word_32be(m68k->program, ea, m68k->mmu_srp_limit>>16);
memory_write_word_32be(m68k->program, ea+2, m68k->mmu_srp_limit&0xffff);
memory_write_word_32be(m68k->program, ea+4, m68k->mmu_srp_aptr>>16);
memory_write_word_32be(m68k->program, ea+6, m68k->mmu_srp_aptr&0xffff);
break;
case 3: // CPU root pointer
memory_write_word_32be(m68k->program, ea, m68k->mmu_crp_limit>>16);
memory_write_word_32be(m68k->program, ea+2, m68k->mmu_crp_limit&0xffff);
memory_write_word_32be(m68k->program, ea+4, m68k->mmu_crp_aptr>>16);
memory_write_word_32be(m68k->program, ea+6, m68k->mmu_crp_aptr&0xffff);
break;
default:
logerror("680x0: PMOVE from unknown MMU register %x, PC %x\n", (modes>>10) & 7, m68k->pc);
break;
}
}
else
{
switch ((modes>>10) & 7)
{
case 0: // translation control register
m68k->mmu_tc = memory_read_word_32be(m68k->program, ea)<<16;
m68k->mmu_tc |= memory_read_word_32be(m68k->program, ea+2);
if (m68k->mmu_tc & 0x80000000)
{
m68k->pmmu_enabled = 1;
}
else
{
m68k->pmmu_enabled = 0;
}
break;
case 2: // supervisor root pointer
m68k->mmu_srp_limit = memory_read_word_32be(m68k->program, ea)<<16;
m68k->mmu_srp_limit |= memory_read_word_32be(m68k->program, ea+2);
m68k->mmu_srp_aptr = memory_read_word_32be(m68k->program, ea+4)<<16;
m68k->mmu_srp_aptr |= memory_read_word_32be(m68k->program, ea+6);
break;
case 3: // CPU root pointer
m68k->mmu_crp_limit = memory_read_word_32be(m68k->program, ea)<<16;
m68k->mmu_crp_limit |= memory_read_word_32be(m68k->program, ea+2);
m68k->mmu_crp_aptr = memory_read_word_32be(m68k->program, ea+4)<<16;
m68k->mmu_crp_aptr |= memory_read_word_32be(m68k->program, ea+6);
break;
default:
logerror("680x0: PMOVE to unknown MMU register %x, PC %x\n", (modes>>10) & 7, m68k->pc);
break;
}
}
break;
case 3: // MC68030 to/from status reg
if (modes & 0x200)
{
memory_write_word_32be(m68k->program, ea, m68k->mmu_sr);
}
else
{
m68k->mmu_sr = memory_read_word_32be(m68k->program, ea);
}
break;
default:
logerror("680x0: unknown PMOVE mode %x (modes %04x) (PC %x)\n", (modes>>13) & 0x7, modes, m68k->pc);
break;
}
m68881_mmu_ops(m68k);
}
else
{

View File

@ -5,7 +5,7 @@
#if 0
static const char copyright_notice[] =
"MUSASHI\n"
"Version 4.5 (2009-10-09)\n"
"Version 4.55 (2009-10-31)\n"
"A portable Motorola M680x0 processor emulation engine.\n"
"Copyright Karl Stenerud. All rights reserved.\n"
"\n"
@ -42,6 +42,7 @@ static const char copyright_notice[] =
extern void m68040_fpu_op0(m68ki_cpu_core *m68k);
extern void m68040_fpu_op1(m68ki_cpu_core *m68k);
extern void m68881_mmu_ops(m68ki_cpu_core *m68k);
/* ======================================================================== */
/* ================================= DATA ================================= */
@ -1720,7 +1721,7 @@ CPU_GET_INFO( m68040 )
}
/****************************************************************************
* M680EC30 section
* M68EC040 section
****************************************************************************/
static CPU_INIT( m68ec040 )
@ -1762,6 +1763,49 @@ CPU_GET_INFO( m68ec040 )
}
}
/****************************************************************************
* M68LC040 section
****************************************************************************/
static CPU_INIT( m68lc040 )
{
m68ki_cpu_core *m68k = get_safe_token(device);
CPU_INIT_CALL(m68k);
m68k->cpu_type = CPU_TYPE_LC040;
m68k->state.subtypemask = m68k->cpu_type;
m68k->dasm_type = M68K_CPU_TYPE_68LC040;
m68k->memory = interface_d32;
m68k->sr_mask = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */
m68k->cyc_instruction = m68ki_cycles[4];
m68k->cyc_exception = m68ki_exception_cycle_table[4];
m68k->cyc_bcc_notake_b = -2;
m68k->cyc_bcc_notake_w = 0;
m68k->cyc_dbcc_f_noexp = 0;
m68k->cyc_dbcc_f_exp = 4;
m68k->cyc_scc_r_true = 0;
m68k->cyc_movem_w = 2;
m68k->cyc_movem_l = 2;
m68k->cyc_shift = 0;
m68k->cyc_reset = 518;
m68k->has_pmmu = 1;
}
CPU_GET_INFO( m68lc040 )
{
switch (state)
{
/* --- the following bits of info are returned as pointers to data or functions --- */
case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(m68lc040); break;
/* --- the following bits of info are returned as NULL-terminated strings --- */
case DEVINFO_STR_NAME: strcpy(info->s, "68LC040"); break;
default: CPU_GET_INFO_CALL(m68040); break;
}
}
/****************************************************************************
* SCC-68070 section
****************************************************************************/

View File

@ -81,8 +81,9 @@ typedef struct _m68ki_cpu_core m68ki_cpu_core;
#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

@ -146,6 +146,7 @@ UINT32 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(UINT32 val);
@ -230,6 +231,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 ========================== */
/* ======================================================================== */
@ -304,6 +311,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(UINT32 val)
@ -2563,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);
@ -3019,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;
UINT16 modes = read_imm_16();
@ -3040,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);
sprintf(g_dasm_str, "pflushr %x, %x, %s", modes & 0x1f, (modes>>5)&0xf, str);
return;
}
else
if (modes == 0xa000) // PFLUSHR
{
sprintf(g_dasm_str, "pflush %s, %s", str, g_mmuregs[(modes>>10)&7]);
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;
}
@ -3098,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 ====================== */
@ -3421,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}
};
@ -3551,15 +3619,16 @@ static unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned i
g_cpu_type = TYPE_68010;
break;
case M68K_CPU_TYPE_68EC020:
g_cpu_type = TYPE_68020;
break;
case M68K_CPU_TYPE_68020:
g_cpu_type = TYPE_68020;
break;
case M68K_CPU_TYPE_68EC030:
case M68K_CPU_TYPE_68030:
g_cpu_type = TYPE_68030;
break;
case M68K_CPU_TYPE_68040:
case M68K_CPU_TYPE_68EC040:
case M68K_CPU_TYPE_68LC040:
g_cpu_type = TYPE_68040;
break;
default:
@ -3752,6 +3821,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)
@ -3766,9 +3836,9 @@ 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;
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)
@ -3789,6 +3859,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 ||

View File

@ -95,6 +95,11 @@ static UINT8 READ_EA_8(m68ki_cpu_core *m68k, int ea)
{
switch (reg)
{
case 0: // (xxx).W
{
UINT32 ea = (UINT32)OPER_I_16(m68k);
return m68ki_read_8(m68k, ea);
}
case 1: // (xxx).L
{
UINT32 d1 = OPER_I_16(m68k);
@ -146,6 +151,11 @@ static UINT16 READ_EA_16(m68ki_cpu_core *m68k, int ea)
{
switch (reg)
{
case 0: // (xxx).W
{
UINT32 ea = (UINT32)OPER_I_16(m68k);
return m68ki_read_16(m68k, ea);
}
case 1: // (xxx).L
{
UINT32 d1 = OPER_I_16(m68k);
@ -203,6 +213,11 @@ static UINT32 READ_EA_32(m68ki_cpu_core *m68k, int ea)
{
switch (reg)
{
case 0: // (xxx).W
{
UINT32 ea = (UINT32)OPER_I_16(m68k);
return m68ki_read_32(m68k, ea);
}
case 1: // (xxx).L
{
UINT32 d1 = OPER_I_16(m68k);
@ -228,6 +243,63 @@ static UINT32 READ_EA_32(m68ki_cpu_core *m68k, int ea)
return 0;
}
static UINT64 READ_EA_64(m68ki_cpu_core *m68k, 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(m68k, ea+0);
h2 = m68ki_read_32(m68k, ea+4);
return (UINT64)(h1) << 32 | (UINT64)(h2);
}
case 3: // (An)+
{
UINT32 ea = REG_A[reg];
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);
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 4: // #<data>
{
h1 = OPER_I_32(m68k);
h2 = OPER_I_32(m68k);
return (UINT64)(h1) << 32 | (UINT64)(h2);
}
case 2: // (d16, PC)
{
UINT32 ea = EA_PCDI_32(m68k);
h1 = m68ki_read_32(m68k, ea+0);
h2 = m68ki_read_32(m68k, 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(m68ki_cpu_core *m68k, int ea, UINT8 data)
{
int mode = (ea >> 3) & 0x7;
@ -376,6 +448,11 @@ static void WRITE_EA_32(m68ki_cpu_core *m68k, 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];
@ -432,63 +509,6 @@ static void WRITE_EA_32(m68ki_cpu_core *m68k, int ea, UINT32 data)
}
}
static UINT64 READ_EA_64(m68ki_cpu_core *m68k, 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(m68k, ea+0);
h2 = m68ki_read_32(m68k, ea+4);
return (UINT64)(h1) << 32 | (UINT64)(h2);
}
case 3: // (An)+
{
UINT32 ea = REG_A[reg];
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);
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 4: // #<data>
{
h1 = OPER_I_32(m68k);
h2 = OPER_I_32(m68k);
return (UINT64)(h1) << 32 | (UINT64)(h2);
}
case 2: // (d16, PC)
{
UINT32 ea = EA_PCDI_32(m68k);
h1 = m68ki_read_32(m68k, ea+0);
h2 = m68ki_read_32(m68k, 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(m68ki_cpu_core *m68k, 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.
@ -55,7 +55,7 @@
*/
static const char g_version[] = "4.10";
static const char g_version[] = "4.55";
/* ======================================================================== */
/* =============================== INCLUDES =============================== */
@ -767,7 +767,7 @@ static 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

@ -12,7 +12,7 @@
*/
INLINE UINT32 pmmu_translate_addr(m68ki_cpu_core *m68k, UINT32 addr_in)
{
UINT32 addr_out, tbl_entry = 0, tbl_entry2, tamode = 0, tbmode = 0;
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;
@ -108,15 +108,34 @@ 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)
{
// 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, m68k->pc);
break;
case 1: // early termination descriptor
case 2: // 4-byte table C descriptor
tofs *= 4;
// logerror("PMMU: reading table C entry at %08x\n", tofs + tptr);
tbl_entry = memory_read_dword_32be(m68k->program, tofs + tptr);
tcmode = tbl_entry & 3;
// 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
tofs *= 8;
// logerror("PMMU: reading table C entries at %08x\n", tofs + tptr);
tbl_entry2 = memory_read_dword_32be(m68k->program, tofs + tptr);
tbl_entry = memory_read_dword_32be(m68k->program, tofs + tptr + 4);
tcmode = tbl_entry2 & 3;
// logerror("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;
@ -126,55 +145,176 @@ INLINE UINT32 pmmu_translate_addr(m68ki_cpu_core *m68k, UINT32 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, m68k->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;
}
}
// logerror("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
m68881_mmu_ops: COP 0 MMU opcode handling
*/
void m68881_mmu_ops(m68ki_cpu_core *m68k)
{
UINT16 modes;
UINT32 ea = m68k->ir & 0x3f;
UINT64 temp64;
// catch the 2 "weird" encodings up front (PBcc)
if ((m68k->ir & 0xffc0) == 0xf0c0)
{
logerror("680x0: unhandled PBcc\n");
return;
}
else if ((m68k->ir & 0xffc0) == 0xf080)
{
logerror("680x0: unhandled PBcc\n");
return;
}
else // the rest are 1111000xxxXXXXXX where xxx is the instruction family
{
switch ((m68k->ir>>9) & 0x7)
{
case 0:
modes = OPER_I_16(m68k);
if ((modes & 0xfde0) == 0x2000) // PLOAD
{
logerror("680x0: unhandled PLOAD\n");
return;
}
else if ((modes & 0xe200) == 0x2000) // PFLUSH
{
logerror("680x0: unhandled PFLUSH PC=%x\n", m68k->pc);
return;
}
else if (modes == 0xa000) // PFLUSHR
{
logerror("680x0: unhandled PFLUSHR\n");
return;
}
else if (modes == 0x2800) // PVALID (FORMAT 1)
{
logerror("680x0: unhandled PVALID1\n");
return;
}
else if ((modes & 0xfff8) == 0x2c00) // PVALID (FORMAT 2)
{
logerror("680x0: unhandled PVALID2\n");
return;
}
else if ((modes & 0xe000) == 0x8000) // PTEST
{
logerror("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(m68k, ea, 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 3: // CPU root pointer
WRITE_EA_64(m68k, ea, (UINT64)m68k->mmu_crp_limit<<32 | (UINT64)m68k->mmu_crp_aptr);
break;
default:
logerror("680x0: PMOVE from unknown MMU register %x, PC %x\n", (modes>>10) & 7, m68k->pc);
break;
}
}
else
{
switch ((modes>>10) & 7)
{
case 0: // translation control register
m68k->mmu_tc = READ_EA_32(m68k, ea);
if (m68k->mmu_tc & 0x80000000)
{
m68k->pmmu_enabled = 1;
}
else
{
m68k->pmmu_enabled = 0;
}
break;
case 2: // supervisor root pointer
temp64 = READ_EA_64(m68k, ea);
m68k->mmu_srp_limit = (temp64>>32) & 0xffffffff;
m68k->mmu_srp_aptr = temp64 & 0xffffffff;
break;
case 3: // CPU root pointer
temp64 = READ_EA_64(m68k, ea);
m68k->mmu_crp_limit = (temp64>>32) & 0xffffffff;
m68k->mmu_crp_aptr = temp64 & 0xffffffff;
break;
default:
logerror("680x0: PMOVE to unknown MMU register %x, PC %x\n", (modes>>10) & 7, m68k->pc);
break;
}
}
break;
case 3: // MC68030 to/from status reg
if (modes & 0x200)
{
WRITE_EA_32(m68k, ea, m68k->mmu_sr);
}
else
{
m68k->mmu_sr = READ_EA_32(m68k, ea);
}
break;
default:
logerror("680x0: unknown PMOVE mode %x (modes %04x) (PC %x)\n", (modes>>13) & 0x7, modes, m68k->pc);
break;
}
}
break;
default:
logerror("680x0: unknown PMMU instruction group %d\n", (m68k->ir>>9) & 0x7);
break;
}
}
}