commit
710f795aaf
14 changed files with 814 additions and 119 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -24,3 +24,4 @@ Thumbs.db
|
|||
m68kmake
|
||||
m68kops.?
|
||||
sim
|
||||
tags
|
||||
|
|
|
|||
2
Makefile
2
Makefile
|
|
@ -1,7 +1,7 @@
|
|||
# Just a basic makefile to quickly test that everyting is working, it just
|
||||
# compiles the .o and the generator
|
||||
|
||||
MUSASHIFILES = m68kcpu.c m68kdasm.c m68kfpu.c
|
||||
MUSASHIFILES = m68kcpu.c m68kdasm.c
|
||||
MUSASHIGENCFILES = m68kops.c
|
||||
MUSASHIGENHFILES = m68kops.h
|
||||
MUSASHIGENERATOR = m68kmake
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ OSD_DOS = osd_dos.c
|
|||
|
||||
OSDFILES = osd_linux.c # $(OSD_DOS)
|
||||
MAINFILES = sim.c
|
||||
MUSASHIFILES = m68kcpu.c m68kdasm.c m68kfpu.c
|
||||
MUSASHIFILES = m68kcpu.c m68kdasm.c
|
||||
MUSASHIGENCFILES = m68kops.c
|
||||
MUSASHIGENHFILES = m68kops.h
|
||||
MUSASHIGENERATOR = m68kmake
|
||||
|
|
|
|||
1
example/m68kmmu.h
Symbolic link
1
example/m68kmmu.h
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../m68kmmu.h
|
||||
1
m68k.h
1
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
|
||||
};
|
||||
|
|
|
|||
20
m68k_in.c
20
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
|
||||
|
|
@ -914,7 +915,7 @@ M68KMAKE_OP(1111, 0, ., .)
|
|||
|
||||
M68KMAKE_OP(040fpu0, 32, ., .)
|
||||
{
|
||||
if(CPU_TYPE_IS_040_PLUS(CPU_TYPE))
|
||||
if(CPU_TYPE_IS_030_PLUS(CPU_TYPE))
|
||||
{
|
||||
m68040_fpu_op0();
|
||||
return;
|
||||
|
|
@ -925,7 +926,7 @@ M68KMAKE_OP(040fpu0, 32, ., .)
|
|||
|
||||
M68KMAKE_OP(040fpu1, 32, ., .)
|
||||
{
|
||||
if(CPU_TYPE_IS_040_PLUS(CPU_TYPE))
|
||||
if(CPU_TYPE_IS_030_PLUS(CPU_TYPE))
|
||||
{
|
||||
m68040_fpu_op1();
|
||||
return;
|
||||
|
|
@ -8448,28 +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;
|
||||
|
||||
fprintf(stderr,"680x0: unhandled PMOVE modes %x ea %x\n", modes, ea);
|
||||
m68881_mmu_ops();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 ---------------------------- */
|
||||
|
||||
|
|
|
|||
44
m68kcpu.c
44
m68kcpu.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.
|
||||
|
|
@ -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);
|
||||
|
|
@ -47,6 +48,9 @@ extern void m68ki_build_opcode_table(void);
|
|||
#include "m68kops.h"
|
||||
#include "m68kcpu.h"
|
||||
|
||||
#include "m68kfpu.c"
|
||||
#include "m68kmmu.h" // uses some functions from m68kfpu.c which are static !
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ================================= DATA ================================= */
|
||||
/* ======================================================================== */
|
||||
|
|
@ -599,7 +603,6 @@ static void default_instr_hook_callback(unsigned int pc)
|
|||
jmp_buf m68ki_aerr_trap;
|
||||
#endif /* M68K_EMULATE_ADDRESS_ERROR */
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ================================= API ================================== */
|
||||
/* ======================================================================== */
|
||||
|
|
@ -896,6 +899,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1062,6 +1098,9 @@ void m68k_pulse_bus_error(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);
|
||||
|
|
@ -1104,7 +1143,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()
|
||||
|
|
|
|||
79
m68kcpu.h
79
m68kcpu.h
|
|
@ -3,7 +3,7 @@
|
|||
/* ======================================================================== */
|
||||
/*
|
||||
* MUSASHI
|
||||
* Version 3.32
|
||||
* Version 4.5
|
||||
*
|
||||
* A portable Motorola M680x0 processor emulation engine.
|
||||
* Copyright Karl Stenerud. All rights reserved.
|
||||
|
|
@ -172,8 +172,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
|
||||
|
|
@ -368,6 +369,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
|
||||
|
||||
|
||||
|
|
@ -946,6 +948,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 */
|
||||
|
|
@ -963,6 +966,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;
|
||||
|
||||
|
|
@ -1012,6 +1021,8 @@ char* m68ki_disassemble_quick(unsigned int pc, unsigned int cpu_type);
|
|||
|
||||
/* ---------------------------- Read Immediate ---------------------------- */
|
||||
|
||||
extern uint pmmu_translate_addr(uint addr_in);
|
||||
|
||||
/* Handles all immediate reads, does address error check, function code setting,
|
||||
* and prefetching if they are enabled in m68kconf.h
|
||||
*/
|
||||
|
|
@ -1019,6 +1030,14 @@ static inline uint m68ki_read_imm_16(void)
|
|||
{
|
||||
m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */
|
||||
m68ki_check_address_error(REG_PC, MODE_READ, FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */
|
||||
|
||||
#if M68K_SEPARATE_READS
|
||||
#if M68K_EMULATE_PMMU
|
||||
if (PMMU_ENABLED)
|
||||
address = pmmu_translate_addr(address);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if M68K_EMULATE_PREFETCH
|
||||
{
|
||||
uint result;
|
||||
|
|
@ -1047,6 +1066,13 @@ static inline uint m68ki_read_imm_8(void)
|
|||
|
||||
static inline uint m68ki_read_imm_32(void)
|
||||
{
|
||||
#if M68K_SEPARATE_READS
|
||||
#if M68K_EMULATE_PMMU
|
||||
if (PMMU_ENABLED)
|
||||
address = pmmu_translate_addr(address);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if M68K_EMULATE_PREFETCH
|
||||
uint temp_val;
|
||||
|
||||
|
|
@ -1077,8 +1103,6 @@ static inline uint m68ki_read_imm_32(void)
|
|||
#endif /* M68K_EMULATE_PREFETCH */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------- Top level read/write ------------------------- */
|
||||
|
||||
/* Handles all memory accesses (except for immediate reads if they are
|
||||
|
|
@ -1091,6 +1115,12 @@ static inline uint m68ki_read_8_fc(uint address, uint fc)
|
|||
{
|
||||
(void)fc;
|
||||
m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */
|
||||
|
||||
#if M68K_EMULATE_PMMU
|
||||
if (PMMU_ENABLED)
|
||||
address = pmmu_translate_addr(address);
|
||||
#endif
|
||||
|
||||
return m68k_read_memory_8(ADDRESS_68K(address));
|
||||
}
|
||||
static inline uint m68ki_read_16_fc(uint address, uint fc)
|
||||
|
|
@ -1098,6 +1128,12 @@ static inline uint m68ki_read_16_fc(uint address, uint fc)
|
|||
(void)fc;
|
||||
m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */
|
||||
m68ki_check_address_error_010_less(address, MODE_READ, fc); /* auto-disable (see m68kcpu.h) */
|
||||
|
||||
#if M68K_EMULATE_PMMU
|
||||
if (PMMU_ENABLED)
|
||||
address = pmmu_translate_addr(address);
|
||||
#endif
|
||||
|
||||
return m68k_read_memory_16(ADDRESS_68K(address));
|
||||
}
|
||||
static inline uint m68ki_read_32_fc(uint address, uint fc)
|
||||
|
|
@ -1105,6 +1141,12 @@ static inline uint m68ki_read_32_fc(uint address, uint fc)
|
|||
(void)fc;
|
||||
m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */
|
||||
m68ki_check_address_error_010_less(address, MODE_READ, fc); /* auto-disable (see m68kcpu.h) */
|
||||
|
||||
#if M68K_EMULATE_PMMU
|
||||
if (PMMU_ENABLED)
|
||||
address = pmmu_translate_addr(address);
|
||||
#endif
|
||||
|
||||
return m68k_read_memory_32(ADDRESS_68K(address));
|
||||
}
|
||||
|
||||
|
|
@ -1112,6 +1154,12 @@ static inline void m68ki_write_8_fc(uint address, uint fc, uint value)
|
|||
{
|
||||
(void)fc;
|
||||
m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */
|
||||
|
||||
#if M68K_EMULATE_PMMU
|
||||
if (PMMU_ENABLED)
|
||||
address = pmmu_translate_addr(address);
|
||||
#endif
|
||||
|
||||
m68k_write_memory_8(ADDRESS_68K(address), value);
|
||||
}
|
||||
static inline void m68ki_write_16_fc(uint address, uint fc, uint value)
|
||||
|
|
@ -1119,6 +1167,12 @@ static inline void m68ki_write_16_fc(uint address, uint fc, uint value)
|
|||
(void)fc;
|
||||
m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */
|
||||
m68ki_check_address_error_010_less(address, MODE_WRITE, fc); /* auto-disable (see m68kcpu.h) */
|
||||
|
||||
#if M68K_EMULATE_PMMU
|
||||
if (PMMU_ENABLED)
|
||||
address = pmmu_translate_addr(address);
|
||||
#endif
|
||||
|
||||
m68k_write_memory_16(ADDRESS_68K(address), value);
|
||||
}
|
||||
static inline void m68ki_write_32_fc(uint address, uint fc, uint value)
|
||||
|
|
@ -1126,6 +1180,12 @@ static inline void m68ki_write_32_fc(uint address, uint fc, uint value)
|
|||
(void)fc;
|
||||
m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */
|
||||
m68ki_check_address_error_010_less(address, MODE_WRITE, fc); /* auto-disable (see m68kcpu.h) */
|
||||
|
||||
#if M68K_EMULATE_PMMU
|
||||
if (PMMU_ENABLED)
|
||||
address = pmmu_translate_addr(address);
|
||||
#endif
|
||||
|
||||
m68k_write_memory_32(ADDRESS_68K(address), value);
|
||||
}
|
||||
|
||||
|
|
@ -1135,11 +1195,16 @@ static inline void m68ki_write_32_pd_fc(uint address, uint fc, uint value)
|
|||
(void)fc;
|
||||
m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */
|
||||
m68ki_check_address_error_010_less(address, MODE_WRITE, fc); /* auto-disable (see m68kcpu.h) */
|
||||
|
||||
#if M68K_EMULATE_PMMU
|
||||
if (PMMU_ENABLED)
|
||||
address = pmmu_translate_addr(address);
|
||||
#endif
|
||||
|
||||
m68k_write_memory_32_pd(ADDRESS_68K(address), value);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* --------------------- Effective Address Calculation -------------------- */
|
||||
|
||||
/* The program counter relative addressing modes cause operands to be
|
||||
|
|
@ -1417,8 +1482,6 @@ static inline void m68ki_branch_32(uint offset)
|
|||
m68ki_pc_changed(REG_PC);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ---------------------------- Status Register --------------------------- */
|
||||
|
||||
/* Set the S flag and change the active stack pointer.
|
||||
|
|
|
|||
122
m68kdasm.c
122
m68kdasm.c
|
|
@ -38,6 +38,14 @@
|
|||
#include <string.h>
|
||||
#include "m68k.h"
|
||||
|
||||
#ifndef uint32
|
||||
#define uint32 uint
|
||||
#endif
|
||||
|
||||
#ifndef uint16
|
||||
#define uint16 unsigned short
|
||||
#endif
|
||||
|
||||
#ifndef DECL_SPEC
|
||||
#define DECL_SPEC
|
||||
#endif
|
||||
|
|
@ -156,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);
|
||||
|
|
@ -243,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 ========================== */
|
||||
/* ======================================================================== */
|
||||
|
|
@ -326,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)
|
||||
|
|
@ -1676,8 +1695,8 @@ static void d68040_fpu(void)
|
|||
};
|
||||
|
||||
char mnemonic[40];
|
||||
uint w2, src, dst_reg;
|
||||
LIMIT_CPU_TYPES(M68040_PLUS);
|
||||
uint32 w2, src, dst_reg;
|
||||
LIMIT_CPU_TYPES(M68030_PLUS);
|
||||
w2 = read_imm_16();
|
||||
|
||||
src = (w2 >> 10) & 0x7;
|
||||
|
|
@ -2555,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);
|
||||
|
|
@ -3011,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();
|
||||
|
|
@ -3019,6 +3048,48 @@ 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) // PFLUSH
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
switch ((modes>>13) & 0x7)
|
||||
{
|
||||
case 0: // MC68030/040 form with FD bit
|
||||
|
|
@ -3064,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 ====================== */
|
||||
|
|
@ -3387,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}
|
||||
};
|
||||
|
||||
|
|
@ -3523,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;
|
||||
|
|
@ -3720,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)
|
||||
|
|
@ -3734,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)
|
||||
|
|
@ -3758,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 ||
|
||||
|
|
@ -3767,7 +3875,7 @@ unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cp
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// f028 2215 0008
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ============================== END OF FILE ============================= */
|
||||
|
|
|
|||
319
m68kfpu.c
319
m68kfpu.c
|
|
@ -1,20 +1,10 @@
|
|||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "m68kcpu.h"
|
||||
#include <stdarg.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, ...) {
|
||||
static void fatalerror(char *format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap,format);
|
||||
fprintf(stderr,format,ap);
|
||||
|
|
@ -98,6 +88,11 @@ static uint8 READ_EA_8(int ea)
|
|||
{
|
||||
return REG_D[reg];
|
||||
}
|
||||
case 2: // (An)
|
||||
{
|
||||
uint32 ea = REG_A[reg];
|
||||
return m68ki_read_8(ea);
|
||||
}
|
||||
case 5: // (d16, An)
|
||||
{
|
||||
uint32 ea = EA_AY_DI_8();
|
||||
|
|
@ -112,6 +107,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();
|
||||
|
|
@ -163,6 +163,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();
|
||||
|
|
@ -220,6 +225,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();
|
||||
|
|
@ -245,74 +255,6 @@ static uint32 READ_EA_32(int ea)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void WRITE_EA_32(int ea, uint32 data)
|
||||
{
|
||||
int mode = (ea >> 3) & 0x7;
|
||||
int reg = (ea & 0x7);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case 0: // Dn
|
||||
{
|
||||
REG_D[reg] = data;
|
||||
break;
|
||||
}
|
||||
case 2: // (An)
|
||||
{
|
||||
uint32 ea = REG_A[reg];
|
||||
m68ki_write_32(ea, data);
|
||||
break;
|
||||
}
|
||||
case 3: // (An)+
|
||||
{
|
||||
uint32 ea = EA_AY_PI_32();
|
||||
m68ki_write_32(ea, data);
|
||||
break;
|
||||
}
|
||||
case 4: // -(An)
|
||||
{
|
||||
uint32 ea = EA_AY_PD_32();
|
||||
m68ki_write_32(ea, data);
|
||||
break;
|
||||
}
|
||||
case 5: // (d16, An)
|
||||
{
|
||||
uint32 ea = EA_AY_DI_32();
|
||||
m68ki_write_32(ea, data);
|
||||
break;
|
||||
}
|
||||
case 6: // (An) + (Xn) + d8
|
||||
{
|
||||
uint32 ea = EA_AY_IX_32();
|
||||
m68ki_write_32(ea, data);
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
switch (reg)
|
||||
{
|
||||
case 1: // (xxx).L
|
||||
{
|
||||
uint32 d1 = OPER_I_16();
|
||||
uint32 d2 = OPER_I_16();
|
||||
uint32 ea = (d1 << 16) | d2;
|
||||
m68ki_write_32(ea, data);
|
||||
break;
|
||||
}
|
||||
case 2: // (d16, PC)
|
||||
{
|
||||
uint32 ea = EA_PCDI_32();
|
||||
m68ki_write_32(ea, data);
|
||||
break;
|
||||
}
|
||||
default: fatalerror("MC68040: WRITE_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: fatalerror("MC68040: WRITE_EA_32: unhandled mode %d, reg %d, data %08X at %08X\n", mode, reg, data, REG_PC);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64 READ_EA_64(int ea)
|
||||
{
|
||||
int mode = (ea >> 3) & 0x7;
|
||||
|
|
@ -370,6 +312,215 @@ static uint64 READ_EA_64(int ea)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void WRITE_EA_8(int ea, uint8 data)
|
||||
{
|
||||
int mode = (ea >> 3) & 0x7;
|
||||
int reg = (ea & 0x7);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case 0: // Dn
|
||||
{
|
||||
REG_D[reg] = data;
|
||||
break;
|
||||
}
|
||||
case 2: // (An)
|
||||
{
|
||||
uint32 ea = REG_A[reg];
|
||||
m68ki_write_8(ea, data);
|
||||
break;
|
||||
}
|
||||
case 3: // (An)+
|
||||
{
|
||||
uint32 ea = EA_AY_PI_8();
|
||||
m68ki_write_8(ea, data);
|
||||
break;
|
||||
}
|
||||
case 4: // -(An)
|
||||
{
|
||||
uint32 ea = EA_AY_PD_8();
|
||||
m68ki_write_8(ea, data);
|
||||
break;
|
||||
}
|
||||
case 5: // (d16, An)
|
||||
{
|
||||
uint32 ea = EA_AY_DI_8();
|
||||
m68ki_write_8(ea, data);
|
||||
break;
|
||||
}
|
||||
case 6: // (An) + (Xn) + d8
|
||||
{
|
||||
uint32 ea = EA_AY_IX_8();
|
||||
m68ki_write_8(ea, data);
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
switch (reg)
|
||||
{
|
||||
case 1: // (xxx).B
|
||||
{
|
||||
uint32 d1 = OPER_I_16();
|
||||
uint32 d2 = OPER_I_16();
|
||||
uint32 ea = (d1 << 16) | d2;
|
||||
m68ki_write_8(ea, data);
|
||||
break;
|
||||
}
|
||||
case 2: // (d16, PC)
|
||||
{
|
||||
uint32 ea = EA_PCDI_16();
|
||||
m68ki_write_8(ea, data);
|
||||
break;
|
||||
}
|
||||
default: fatalerror("MC68040: WRITE_EA_8: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: fatalerror("MC68040: WRITE_EA_8: unhandled mode %d, reg %d, data %08X at %08X\n", mode, reg, data, REG_PC);
|
||||
}
|
||||
}
|
||||
|
||||
static void WRITE_EA_16(int ea, uint16 data)
|
||||
{
|
||||
int mode = (ea >> 3) & 0x7;
|
||||
int reg = (ea & 0x7);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case 0: // Dn
|
||||
{
|
||||
REG_D[reg] = data;
|
||||
break;
|
||||
}
|
||||
case 2: // (An)
|
||||
{
|
||||
uint32 ea = REG_A[reg];
|
||||
m68ki_write_16(ea, data);
|
||||
break;
|
||||
}
|
||||
case 3: // (An)+
|
||||
{
|
||||
uint32 ea = EA_AY_PI_16();
|
||||
m68ki_write_16(ea, data);
|
||||
break;
|
||||
}
|
||||
case 4: // -(An)
|
||||
{
|
||||
uint32 ea = EA_AY_PD_16();
|
||||
m68ki_write_16(ea, data);
|
||||
break;
|
||||
}
|
||||
case 5: // (d16, An)
|
||||
{
|
||||
uint32 ea = EA_AY_DI_16();
|
||||
m68ki_write_16(ea, data);
|
||||
break;
|
||||
}
|
||||
case 6: // (An) + (Xn) + d8
|
||||
{
|
||||
uint32 ea = EA_AY_IX_16();
|
||||
m68ki_write_16(ea, data);
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
switch (reg)
|
||||
{
|
||||
case 1: // (xxx).W
|
||||
{
|
||||
uint32 d1 = OPER_I_16();
|
||||
uint32 d2 = OPER_I_16();
|
||||
uint32 ea = (d1 << 16) | d2;
|
||||
m68ki_write_16(ea, data);
|
||||
break;
|
||||
}
|
||||
case 2: // (d16, PC)
|
||||
{
|
||||
uint32 ea = EA_PCDI_16();
|
||||
m68ki_write_16(ea, data);
|
||||
break;
|
||||
}
|
||||
default: fatalerror("MC68040: WRITE_EA_16: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: fatalerror("MC68040: WRITE_EA_16: unhandled mode %d, reg %d, data %08X at %08X\n", mode, reg, data, REG_PC);
|
||||
}
|
||||
}
|
||||
|
||||
static void WRITE_EA_32(int ea, uint32 data)
|
||||
{
|
||||
int mode = (ea >> 3) & 0x7;
|
||||
int reg = (ea & 0x7);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case 0: // Dn
|
||||
{
|
||||
REG_D[reg] = data;
|
||||
break;
|
||||
}
|
||||
case 1: // An
|
||||
{
|
||||
REG_A[reg] = data;
|
||||
break;
|
||||
}
|
||||
case 2: // (An)
|
||||
{
|
||||
uint32 ea = REG_A[reg];
|
||||
m68ki_write_32(ea, data);
|
||||
break;
|
||||
}
|
||||
case 3: // (An)+
|
||||
{
|
||||
uint32 ea = EA_AY_PI_32();
|
||||
m68ki_write_32(ea, data);
|
||||
break;
|
||||
}
|
||||
case 4: // -(An)
|
||||
{
|
||||
uint32 ea = EA_AY_PD_32();
|
||||
m68ki_write_32(ea, data);
|
||||
break;
|
||||
}
|
||||
case 5: // (d16, An)
|
||||
{
|
||||
uint32 ea = EA_AY_DI_32();
|
||||
m68ki_write_32(ea, data);
|
||||
break;
|
||||
}
|
||||
case 6: // (An) + (Xn) + d8
|
||||
{
|
||||
uint32 ea = EA_AY_IX_32();
|
||||
m68ki_write_32(ea, data);
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
switch (reg)
|
||||
{
|
||||
case 1: // (xxx).L
|
||||
{
|
||||
uint32 d1 = OPER_I_16();
|
||||
uint32 d2 = OPER_I_16();
|
||||
uint32 ea = (d1 << 16) | d2;
|
||||
m68ki_write_32(ea, data);
|
||||
break;
|
||||
}
|
||||
case 2: // (d16, PC)
|
||||
{
|
||||
uint32 ea = EA_PCDI_32();
|
||||
m68ki_write_32(ea, data);
|
||||
break;
|
||||
}
|
||||
default: fatalerror("MC68040: WRITE_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: fatalerror("MC68040: WRITE_EA_32: unhandled mode %d, reg %d, data %08X at %08X\n", mode, reg, data, REG_PC);
|
||||
}
|
||||
}
|
||||
|
||||
static void WRITE_EA_64(int ea, uint64 data)
|
||||
{
|
||||
int mode = (ea >> 3) & 0x7;
|
||||
|
|
@ -381,7 +532,7 @@ static void WRITE_EA_64(int ea, uint64 data)
|
|||
{
|
||||
uint32 ea = REG_A[reg];
|
||||
m68ki_write_32(ea, (uint32)(data >> 32));
|
||||
m68ki_write_32(ea, (uint32)(data));
|
||||
m68ki_write_32(ea+4, (uint32)(data));
|
||||
break;
|
||||
}
|
||||
case 4: // -(An)
|
||||
|
|
@ -627,7 +778,8 @@ static void fmove_reg_mem(uint16 w2)
|
|||
}
|
||||
case 4: // Word Integer
|
||||
{
|
||||
fatalerror("fmove_reg_mem: word integer store unimplemented at %08X\n", REG_PC-4);
|
||||
sint16 d = (sint16)(REG_FP[src].f);
|
||||
WRITE_EA_16(ea, d);
|
||||
break;
|
||||
}
|
||||
case 5: // Double-precision Real
|
||||
|
|
@ -638,7 +790,8 @@ static void fmove_reg_mem(uint16 w2)
|
|||
}
|
||||
case 6: // Byte Integer
|
||||
{
|
||||
fatalerror("fmove_reg_mem: byte integer store unimplemented at %08X\n", REG_PC-4);
|
||||
sint8 d = (sint16)(REG_FP[src].f);
|
||||
WRITE_EA_8(ea, d);
|
||||
break;
|
||||
}
|
||||
case 7: // Packed-decimal Real with Dynamic K-factor
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
321
m68kmmu.h
Normal file
321
m68kmmu.h
Normal file
|
|
@ -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()
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
12
readme.txt
12
readme.txt
|
|
@ -147,11 +147,23 @@ To enable separate immediate reads:
|
|||
unsigned int m68k_read_immediate_16(unsigned int address);
|
||||
unsigned int m68k_read_immediate_32(unsigned int address);
|
||||
|
||||
Now you also have the pcrelative stuff:
|
||||
unsigned int m68k_read_pcrelative_8(unsigned int address);
|
||||
unsigned int m68k_read_pcrelative_16(unsigned int address);
|
||||
unsigned int m68k_read_pcrelative_32(unsigned int address);
|
||||
|
||||
- If you need to know the current PC (for banking and such), set
|
||||
M68K_MONITOR_PC to OPT_SPECIFY_HANDLER, and set M68K_SET_PC_CALLBACK(A) to
|
||||
your routine.
|
||||
|
||||
- In the unlikely case where you need to emulate some PMMU in the immediate
|
||||
reads and/or pcrealtive stuff, you'll need to explicitely call the
|
||||
translation address mechanism from your user functions this way :
|
||||
|
||||
if (PMMU_ENABLED)
|
||||
address = pmmu_translate_addr(address);
|
||||
|
||||
(this is handled automatically by normal memory accesses).
|
||||
|
||||
ADDRESS SPACES:
|
||||
--------------
|
||||
|
|
|
|||
Loading…
Reference in a new issue