m680x0 update:

- Added working PMMU address translation (not feature complete, but sufficient
  to boot several 68030 Macs in MESS)
- Fixed up disassembly of some PMMU instructions
- Added "68020 with 68851" CPU type
This commit is contained in:
R. Belmont 2009-10-12 02:50:35 +00:00 committed by Emmanuel Anne
parent 8126887721
commit d5576b3797
7 changed files with 317 additions and 27 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -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 ============================= */

View file

@ -1,27 +1,6 @@
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#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

193
m68kmmu.h Normal file
View file

@ -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 <stdio.h>
#include <stdarg.h>
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<<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)
{
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)>>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
*/