X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=m68kcpu.h;h=b5b919745217c2837c88a73d6cd9421f4de5c1fa;hb=a2b0521dbdd754e129639bc210003cde57775cf5;hp=8cd03d6573b4bd6e5539e67f37fc36985db1382f;hpb=6c9276f882444e8f164bed4e642fbf3cbb259971;p=pistorm diff --git a/m68kcpu.h b/m68kcpu.h index 8cd03d6..b5b9197 100644 --- a/m68kcpu.h +++ b/m68kcpu.h @@ -43,6 +43,7 @@ extern "C" { #include #include +#include /* ======================================================================== */ /* ==================== ARCHITECTURE-DEPENDANT DEFINES ==================== */ @@ -144,13 +145,16 @@ typedef uint32 uint64; } #endif /* UINT_MAX == 0xffffffff */ - - - /* ======================================================================== */ /* ============================ GENERAL DEFINES =========================== */ /* ======================================================================== */ +/* MMU constants */ +#define MMU_ATC_ENTRIES 22 // 68851 has 64, 030 has 22 + +/* instruction cache constants */ +#define M68K_IC_SIZE 128 + /* Exception Vectors handled by emulation */ #define EXCEPTION_RESET 0 #define EXCEPTION_BUS_ERROR 2 /* This one is not emulated! */ @@ -168,6 +172,7 @@ typedef uint32 uint64; #define EXCEPTION_SPURIOUS_INTERRUPT 24 #define EXCEPTION_INTERRUPT_AUTOVECTOR 24 #define EXCEPTION_TRAP_BASE 32 +#define EXCEPTION_MMU_CONFIGURATION 56 // only on 020/030 /* Function codes set by CPU during data/address bus activity */ #define FUNCTION_CODE_USER_DATA 1 @@ -177,7 +182,7 @@ typedef uint32 uint64; #define FUNCTION_CODE_CPU_SPACE 7 /* CPU types for deciding what to emulate */ -#define CPU_TYPE_000 (0x00000001) +#define CPU_TYPE_000 (0x00000001) #define CPU_TYPE_008 (0x00000002) #define CPU_TYPE_010 (0x00000004) #define CPU_TYPE_EC020 (0x00000008) @@ -199,8 +204,15 @@ typedef uint32 uint64; #define MODE_READ 0x10 #define MODE_WRITE 0 -#define RUN_MODE_NORMAL 0 -#define RUN_MODE_BERR_AERR_RESET 1 +#define RUN_MODE_NORMAL 0 +#define RUN_MODE_BERR_AERR_RESET_WSF 1 // writing the stack frame +#define RUN_MODE_BERR_AERR_RESET 2 // stack frame done + +#define M68K_CACR_IBE 0x10 // Instruction Burst Enable +#define M68K_CACR_CI 0x08 // Clear Instruction Cache +#define M68K_CACR_CEI 0x04 // Clear Entry in Instruction Cache +#define M68K_CACR_FI 0x02 // Freeze Instruction Cache +#define M68K_CACR_EI 0x01 // Enable Instruction Cache #ifndef NULL #define NULL ((void*)0) @@ -328,10 +340,10 @@ typedef uint32 uint64; #define CPU_TYPE m68ki_cpu.cpu_type #define REG_DA m68ki_cpu.dar /* easy access to data and address regs */ -#define REG_DA_SAVE m68ki_cpu.dar_save +#define REG_DA_SAVE m68ki_cpu.dar_save #define REG_D m68ki_cpu.dar #define REG_A (m68ki_cpu.dar+8) -#define REG_PPC m68ki_cpu.ppc +#define REG_PPC m68ki_cpu.ppc #define REG_PC m68ki_cpu.pc #define REG_SP_BASE m68ki_cpu.sp #define REG_USP m68ki_cpu.sp[0] @@ -387,16 +399,16 @@ typedef uint32 uint64; #define RESET_CYCLES m68ki_cpu.reset_cycles -#define CALLBACK_INT_ACK m68ki_cpu.int_ack_callback -#define CALLBACK_BKPT_ACK m68ki_cpu.bkpt_ack_callback -#define CALLBACK_RESET_INSTR m68ki_cpu.reset_instr_callback +#define CALLBACK_INT_ACK m68ki_cpu.int_ack_callback +#define CALLBACK_BKPT_ACK m68ki_cpu.bkpt_ack_callback +#define CALLBACK_RESET_INSTR m68ki_cpu.reset_instr_callback #define CALLBACK_CMPILD_INSTR m68ki_cpu.cmpild_instr_callback #define CALLBACK_RTE_INSTR m68ki_cpu.rte_instr_callback #define CALLBACK_TAS_INSTR m68ki_cpu.tas_instr_callback -#define CALLBACK_ILLG_INSTR m68ki_cpu.illg_instr_callback -#define CALLBACK_PC_CHANGED m68ki_cpu.pc_changed_callback -#define CALLBACK_SET_FC m68ki_cpu.set_fc_callback -#define CALLBACK_INSTR_HOOK m68ki_cpu.instr_hook_callback +#define CALLBACK_ILLG_INSTR m68ki_cpu.illg_instr_callback +#define CALLBACK_PC_CHANGED m68ki_cpu.pc_changed_callback +#define CALLBACK_SET_FC m68ki_cpu.set_fc_callback +#define CALLBACK_INSTR_HOOK m68ki_cpu.instr_hook_callback @@ -406,7 +418,7 @@ typedef uint32 uint64; /* Disable certain comparisons if we're not using all CPU types */ #if M68K_EMULATE_040 -#define CPU_TYPE_IS_040_PLUS(A) ((A) & (CPU_TYPE_040 | CPU_TYPE_EC040)) +#define CPU_TYPE_IS_040_PLUS(A) ((A) & (CPU_TYPE_040 | CPU_TYPE_EC040 | CPU_TYPE_LC040)) #define CPU_TYPE_IS_040_LESS(A) 1 #else #define CPU_TYPE_IS_040_PLUS(A) 0 @@ -414,7 +426,7 @@ typedef uint32 uint64; #endif #if M68K_EMULATE_030 -#define CPU_TYPE_IS_030_PLUS(A) ((A) & (CPU_TYPE_030 | CPU_TYPE_EC030 | CPU_TYPE_040 | CPU_TYPE_EC040)) +#define CPU_TYPE_IS_030_PLUS(A) ((A) & (CPU_TYPE_030 | CPU_TYPE_EC030 | CPU_TYPE_040 | CPU_TYPE_EC040 | CPU_TYPE_LC040)) #define CPU_TYPE_IS_030_LESS(A) 1 #else #define CPU_TYPE_IS_030_PLUS(A) 0 @@ -422,7 +434,7 @@ typedef uint32 uint64; #endif #if M68K_EMULATE_020 -#define CPU_TYPE_IS_020_PLUS(A) ((A) & (CPU_TYPE_020 | CPU_TYPE_030 | CPU_TYPE_EC030 | CPU_TYPE_040 | CPU_TYPE_EC040)) +#define CPU_TYPE_IS_020_PLUS(A) ((A) & (CPU_TYPE_020 | CPU_TYPE_030 | CPU_TYPE_EC030 | CPU_TYPE_040 | CPU_TYPE_EC040 | CPU_TYPE_LC040)) #define CPU_TYPE_IS_020_LESS(A) 1 #else #define CPU_TYPE_IS_020_PLUS(A) 0 @@ -430,7 +442,7 @@ typedef uint32 uint64; #endif #if M68K_EMULATE_EC020 -#define CPU_TYPE_IS_EC020_PLUS(A) ((A) & (CPU_TYPE_EC020 | CPU_TYPE_020 | CPU_TYPE_030 | CPU_TYPE_EC030 | CPU_TYPE_040 | CPU_TYPE_EC040)) +#define CPU_TYPE_IS_EC020_PLUS(A) ((A) & (CPU_TYPE_EC020 | CPU_TYPE_020 | CPU_TYPE_030 | CPU_TYPE_EC030 | CPU_TYPE_040 | CPU_TYPE_EC040 | CPU_TYPE_LC040)) #define CPU_TYPE_IS_EC020_LESS(A) ((A) & (CPU_TYPE_000 | CPU_TYPE_010 | CPU_TYPE_EC020)) #else #define CPU_TYPE_IS_EC020_PLUS(A) CPU_TYPE_IS_020_PLUS(A) @@ -439,7 +451,7 @@ typedef uint32 uint64; #if M68K_EMULATE_010 #define CPU_TYPE_IS_010(A) ((A) == CPU_TYPE_010) -#define CPU_TYPE_IS_010_PLUS(A) ((A) & (CPU_TYPE_010 | CPU_TYPE_EC020 | CPU_TYPE_020 | CPU_TYPE_EC030 | CPU_TYPE_030 | CPU_TYPE_040 | CPU_TYPE_EC040)) +#define CPU_TYPE_IS_010_PLUS(A) ((A) & (CPU_TYPE_010 | CPU_TYPE_EC020 | CPU_TYPE_020 | CPU_TYPE_EC030 | CPU_TYPE_030 | CPU_TYPE_040 | CPU_TYPE_EC040 | CPU_TYPE_LC040)) #define CPU_TYPE_IS_010_LESS(A) ((A) & (CPU_TYPE_000 | CPU_TYPE_008 | CPU_TYPE_010)) #else #define CPU_TYPE_IS_010(A) 0 @@ -656,6 +668,7 @@ extern jmp_buf m68ki_aerr_trap; longjmp(m68ki_aerr_trap, 1); \ } #endif + #define m68ki_bus_error(ADDR,WRITE_MODE) m68ki_aerr_address=ADDR;m68ki_aerr_write_mode=WRITE_MODE;m68ki_exception_bus_error() #define m68ki_check_address_error_010_less(ADDR, WRITE_MODE, FC) \ if (CPU_TYPE_IS_010_LESS(CPU_TYPE)) \ @@ -671,12 +684,12 @@ extern jmp_buf m68ki_aerr_trap; /* Logging */ #if M68K_LOG_ENABLE #include - extern FILE* M68K_LOG_FILEHANDLE +// extern FILE* M68K_LOG_FILEHANDLE; extern const char *const m68ki_cpu_names[]; - #define M68K_DO_LOG(A) if(M68K_LOG_FILEHANDLE) fprintf A + #define M68K_DO_LOG(A) do{printf("*************");printf A;}while(0) //if(M68K_LOG_FILEHANDLE) fprintf A #if M68K_LOG_1010_1111 - #define M68K_DO_LOG_EMU(A) if(M68K_LOG_FILEHANDLE) fprintf A + #define M68K_DO_LOG_EMU(A) printf A //if(M68K_LOG_FILEHANDLE) fprintf A #else #define M68K_DO_LOG_EMU(A) #endif @@ -924,6 +937,15 @@ typedef union double f; } fp_reg; +typedef struct +{ + unsigned int lower; + unsigned int upper; + unsigned char *offset; +} address_translation_cache; + + + typedef struct { uint cpu_type; /* CPU Type: 68000, 68008, 68010, 68EC020, 68020, 68EC030, 68030, 68EC040, or 68040 */ @@ -988,6 +1010,32 @@ typedef struct uint mmu_tc; uint16 mmu_sr; + uint mmu_urp_aptr; /* 040 only */ + uint mmu_sr_040; + uint mmu_atc_tag[MMU_ATC_ENTRIES], mmu_atc_data[MMU_ATC_ENTRIES]; + uint mmu_atc_rr; + uint mmu_tt0, mmu_tt1; + uint mmu_itt0, mmu_itt1, mmu_dtt0, mmu_dtt1; + uint mmu_acr0, mmu_acr1, mmu_acr2, mmu_acr3; + uint mmu_last_page_entry, mmu_last_page_entry_addr; + + uint16 mmu_tmp_sr; /* temporary hack: status code for ptest and to handle write protection */ + uint16 mmu_tmp_fc; /* temporary hack: function code for the mmu (moves) */ + uint16 mmu_tmp_rw; /* temporary hack: read/write (1/0) for the mmu */ + uint8 mmu_tmp_sz; /* temporary hack: size for mmu */ + + uint mmu_tmp_buserror_address; /* temporary hack: (first) bus error address */ + uint16 mmu_tmp_buserror_occurred; /* temporary hack: flag that bus error has occurred from mmu */ + uint16 mmu_tmp_buserror_fc; /* temporary hack: (first) bus error fc */ + uint16 mmu_tmp_buserror_rw; /* temporary hack: (first) bus error rw */ + uint16 mmu_tmp_buserror_sz; /* temporary hack: (first) bus error size` */ + + uint8 mmu_tablewalk; /* set when MMU walks page tables */ + uint mmu_last_logical_addr; + uint ic_address[M68K_IC_SIZE]; /* instruction cache address data */ + uint ic_data[M68K_IC_SIZE]; /* instruction cache content data */ + uint8 ic_valid[M68K_IC_SIZE]; /* instruction cache valid flags */ + const uint8* cyc_instruction; const uint8* cyc_exception; @@ -1003,6 +1051,19 @@ typedef struct void (*set_fc_callback)(unsigned int new_fc); /* Called when the CPU function code changes */ void (*instr_hook_callback)(unsigned int pc); /* Called every instruction cycle prior to execution */ + /* address translation caches */ + + unsigned char read_ranges; + unsigned int read_addr[8]; + unsigned int read_upper[8]; + unsigned char *read_data[8]; + unsigned char write_ranges; + unsigned int write_addr[8]; + unsigned int write_upper[8]; + unsigned char *write_data[8]; + address_translation_cache code_translation_cache; + + } m68ki_cpu_core; @@ -1037,59 +1098,88 @@ char* m68ki_disassemble_quick(unsigned int pc, unsigned int cpu_type); /* ---------------------------- Read Immediate ---------------------------- */ -extern unsigned char read_ranges; -extern unsigned int read_addr[8]; -extern unsigned int read_upper[8]; -extern unsigned char *read_data[8]; -extern unsigned char write_ranges; -extern unsigned int write_addr[8]; -extern unsigned int write_upper[8]; -extern unsigned char *write_data[8]; - -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 - */ -static inline uint m68ki_read_imm_16(void) +// clear the instruction cache +inline void m68ki_ic_clear() { - 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) */ + int i; + for (i=0; i< M68K_IC_SIZE; i++) { + m68ki_cpu.ic_address[i] = ~0; + } +} -#if M68K_SEPARATE_READS -/*#if M68K_EMULATE_PMMU - if (PMMU_ENABLED) - address = pmmu_translate_addr(ADDRESS_68K(CPU_PREF_ADDR)); -#endif*/ -#endif +extern uint32 pmmu_translate_addr(uint32 addr_in, const uint16 rw); -#if M68K_EMULATE_PREFETCH +// read immediate word using the instruction cache + +static inline uint32 m68ki_ic_readimm16(uint32 address) { - uint result; - if(REG_PC != CPU_PREF_ADDR) + if (m68ki_cpu.cacr & M68K_CACR_EI) { - CPU_PREF_ADDR = REG_PC; - CPU_PREF_DATA = m68k_read_immediate_16(ADDRESS_68K(CPU_PREF_ADDR)); + // 68020 series I-cache (MC68020 User's Manual, Section 4 - On-Chip Cache Memory) + if (CPU_TYPE & (CPU_TYPE_EC020 | CPU_TYPE_020)) + { + uint32 tag = (address >> 8) | (m68ki_cpu.s_flag ? 0x1000000 : 0); + int idx = (address >> 2) & 0x3f; // 1-of-64 select + + // do a cache fill if the line is invalid or the tags don't match + if ((!m68ki_cpu.ic_valid[idx]) || (m68ki_cpu.ic_address[idx] != tag)) + { + // if the cache is frozen, don't update it + if (m68ki_cpu.cacr & M68K_CACR_FI) + { + return m68k_read_immediate_16(address); + } + + uint32 data = m68ki_read_32(address & ~3); + + //printf("m68k: doing cache fill at %08x (tag %08x idx %d)\n", address, tag, idx); + + // if no buserror occurred, validate the tag + if (!m68ki_cpu.mmu_tmp_buserror_occurred) + { + m68ki_cpu.ic_address[idx] = tag; + m68ki_cpu.ic_data[idx] = data; + m68ki_cpu.ic_valid[idx] = 1; + } + else + { + return m68k_read_immediate_16(address); + } + } + + // at this point, the cache is guaranteed to be valid, either as + // a hit or because we just filled it. + if (address & 2) + { + return m68ki_cpu.ic_data[idx] & 0xffff; + } + else + { + return m68ki_cpu.ic_data[idx] >> 16; + } + } } - result = MASK_OUT_ABOVE_16(CPU_PREF_DATA); - REG_PC += 2; - CPU_PREF_ADDR = REG_PC; - CPU_PREF_DATA = m68k_read_immediate_16(ADDRESS_68K(CPU_PREF_ADDR)); - return result; + return m68k_read_immediate_16(address); } -#else - uint32_t address = ADDRESS_68K(REG_PC); - REG_PC += 2; +/* Handles all immediate reads, does address error check, function code setting, + * and prefetching if they are enabled in m68kconf.h + */ +uint m68ki_read_imm6_addr_slowpath(uint32_t pc, address_translation_cache *cache); - for (int i = 0; i < read_ranges; i++) { - if(address >= read_addr[i] && address < read_upper[i]) { - return be16toh(((unsigned short *)(read_data[i] + (address - read_addr[i])))[0]); - } - } - return m68k_read_immediate_16(ADDRESS_68K(REG_PC-2)); -#endif /* M68K_EMULATE_PREFETCH */ + +static inline uint m68ki_read_imm_16(void) +{ + uint32_t pc = REG_PC; + + address_translation_cache *cache = &m68ki_cpu.code_translation_cache; + if(pc >= cache->lower && pc < cache->upper) + { + REG_PC += 2; + return be16toh(((unsigned short *)(cache->offset + pc))[0]); + } + return m68ki_read_imm6_addr_slowpath(pc, cache); } static inline uint m68ki_read_imm_8(void) @@ -1101,47 +1191,48 @@ 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_68K(CPU_PREF_ADDR)); -#endif*/ +#if M68K_EMULATE_PMMU +// if (PMMU_ENABLED) +// address = pmmu_translate_addr(address,1); #endif +#endif + uint32_t address = ADDRESS_68K(REG_PC); + for (int i = 0; i < m68ki_cpu.read_ranges; i++) { + if(address >= m68ki_cpu.read_addr[i] && address < m68ki_cpu.read_upper[i]) { + REG_PC += 4; + return be32toh(((unsigned int *)(m68ki_cpu.read_data[i] + (address - m68ki_cpu.read_addr[i])))[0]); + } + } #if M68K_EMULATE_PREFETCH uint temp_val; m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ + m68ki_cpu.mmu_tmp_fc = FLAG_S | FUNCTION_CODE_USER_PROGRAM; + m68ki_cpu.mmu_tmp_rw = 1; + m68ki_cpu.mmu_tmp_sz = M68K_SZ_LONG; m68ki_check_address_error(REG_PC, MODE_READ, FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ if(REG_PC != CPU_PREF_ADDR) { CPU_PREF_ADDR = REG_PC; - - CPU_PREF_DATA = m68k_read_immediate_16(ADDRESS_68K(CPU_PREF_ADDR)); + CPU_PREF_DATA = m68ki_ic_readimm16(ADDRESS_68K(CPU_PREF_ADDR)); } temp_val = MASK_OUT_ABOVE_16(CPU_PREF_DATA); REG_PC += 2; CPU_PREF_ADDR = REG_PC; - CPU_PREF_DATA = m68k_read_immediate_16(ADDRESS_68K(CPU_PREF_ADDR)); + CPU_PREF_DATA = m68ki_ic_readimm16(ADDRESS_68K(CPU_PREF_ADDR)); temp_val = MASK_OUT_ABOVE_32((temp_val << 16) | MASK_OUT_ABOVE_16(CPU_PREF_DATA)); REG_PC += 2; - CPU_PREF_ADDR = REG_PC; - CPU_PREF_DATA = m68k_read_immediate_16(ADDRESS_68K(CPU_PREF_ADDR)); + CPU_PREF_DATA = m68ki_ic_readimm16(REG_PC); + CPU_PREF_ADDR = m68ki_cpu.mmu_tmp_buserror_occurred ? ((uint32)~0) : REG_PC; return temp_val; #else - 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) */ - uint32_t address = ADDRESS_68K(REG_PC); REG_PC += 4; - for (int i = 0; i < read_ranges; i++) { - if(address >= read_addr[i] && address < read_upper[i]) { - return be32toh(((unsigned int *)(read_data[i] + (address - read_addr[i])))[0]); - } - } - return m68k_read_immediate_32(ADDRESS_68K(REG_PC-4)); + return m68k_read_immediate_32(address); #endif /* M68K_EMULATE_PREFETCH */ } @@ -1158,15 +1249,18 @@ static inline uint m68ki_read_8_fc(uint address, uint fc) { (void)fc; m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */ + m68ki_cpu.mmu_tmp_fc = fc; + m68ki_cpu.mmu_tmp_rw = 1; + m68ki_cpu.mmu_tmp_sz = M68K_SZ_BYTE; #if M68K_EMULATE_PMMU if (PMMU_ENABLED) - address = pmmu_translate_addr(address); + address = pmmu_translate_addr(address,1); #endif - for (int i = 0; i < read_ranges; i++) { - if(address >= read_addr[i] && address < read_upper[i]) { - return read_data[i][address - read_addr[i]]; + for (int i = 0; i < m68ki_cpu.read_ranges; i++) { + if(address >= m68ki_cpu.read_addr[i] && address < m68ki_cpu.read_upper[i]) { + return m68ki_cpu.read_data[i][address - m68ki_cpu.read_addr[i]]; } } @@ -1174,18 +1268,20 @@ static inline uint m68ki_read_8_fc(uint address, uint fc) } static inline uint m68ki_read_16_fc(uint address, uint fc) { - (void)fc; m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */ + m68ki_cpu.mmu_tmp_fc = fc; + m68ki_cpu.mmu_tmp_rw = 1; + m68ki_cpu.mmu_tmp_sz = M68K_SZ_WORD; 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); + address = pmmu_translate_addr(address,1); #endif - for (int i = 0; i < read_ranges; i++) { - if(address >= read_addr[i] && address < read_upper[i]) { - return be16toh(((unsigned short *)(read_data[i] + (address - read_addr[i])))[0]); + for (int i = 0; i < m68ki_cpu.read_ranges; i++) { + if(address >= m68ki_cpu.read_addr[i] && address < m68ki_cpu.read_upper[i]) { + return be16toh(((unsigned short *)(m68ki_cpu.read_data[i] + (address - m68ki_cpu.read_addr[i])))[0]); } } @@ -1193,18 +1289,20 @@ static inline uint m68ki_read_16_fc(uint address, uint fc) } static inline uint m68ki_read_32_fc(uint address, uint fc) { - (void)fc; m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */ + m68ki_cpu.mmu_tmp_fc = fc; + m68ki_cpu.mmu_tmp_rw = 1; + m68ki_cpu.mmu_tmp_sz = M68K_SZ_LONG; 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); + address = pmmu_translate_addr(address,1); #endif - for (int i = 0; i < read_ranges; i++) { - if(address >= read_addr[i] && address < read_upper[i]) { - return be32toh(((unsigned int *)(read_data[i] + (address - read_addr[i])))[0]); + for (int i = 0; i < m68ki_cpu.read_ranges; i++) { + if(address >= m68ki_cpu.read_addr[i] && address < m68ki_cpu.read_upper[i]) { + return be32toh(((unsigned int *)(m68ki_cpu.read_data[i] + (address - m68ki_cpu.read_addr[i])))[0]); } } @@ -1213,17 +1311,19 @@ static inline uint m68ki_read_32_fc(uint address, uint fc) static inline void m68ki_write_8_fc(uint address, uint fc, uint value) { - (void)fc; m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */ + m68ki_cpu.mmu_tmp_fc = fc; + m68ki_cpu.mmu_tmp_rw = 0; + m68ki_cpu.mmu_tmp_sz = M68K_SZ_BYTE; #if M68K_EMULATE_PMMU if (PMMU_ENABLED) - address = pmmu_translate_addr(address); + address = pmmu_translate_addr(address,0); #endif - for (int i = 0; i < write_ranges; i++) { - if(address >= write_addr[i] && address < write_upper[i]) { - write_data[i][address - write_addr[i]] = (unsigned char)value; + for (int i = 0; i < m68ki_cpu.write_ranges; i++) { + if(address >= m68ki_cpu.write_addr[i] && address < m68ki_cpu.write_upper[i]) { + m68ki_cpu.write_data[i][address - m68ki_cpu.write_addr[i]] = (unsigned char)value; return; } } @@ -1232,18 +1332,20 @@ static inline void m68ki_write_8_fc(uint address, uint fc, uint value) } 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_cpu.mmu_tmp_fc = fc; + m68ki_cpu.mmu_tmp_rw = 0; + m68ki_cpu.mmu_tmp_sz = M68K_SZ_WORD; 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); + address = pmmu_translate_addr(address,0); #endif - for (int i = 0; i < write_ranges; i++) { - if(address >= write_addr[i] && address < write_upper[i]) { - ((short *)(write_data[i] + (address - write_addr[i])))[0] = htobe16(value); + for (int i = 0; i < m68ki_cpu.write_ranges; i++) { + if(address >= m68ki_cpu.write_addr[i] && address < m68ki_cpu.write_upper[i]) { + ((short *)(m68ki_cpu.write_data[i] + (address - m68ki_cpu.write_addr[i])))[0] = htobe16(value); return; } } @@ -1252,18 +1354,20 @@ static inline void m68ki_write_16_fc(uint address, uint fc, uint value) } 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_cpu.mmu_tmp_fc = fc; + m68ki_cpu.mmu_tmp_rw = 0; + m68ki_cpu.mmu_tmp_sz = M68K_SZ_LONG; 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); + address = pmmu_translate_addr(address,0); #endif - for (int i = 0; i < write_ranges; i++) { - if(address >= write_addr[i] && address < write_upper[i]) { - ((int *)(write_data[i] + (address - write_addr[i])))[0] = htobe32(value); + for (int i = 0; i < m68ki_cpu.write_ranges; i++) { + if(address >= m68ki_cpu.write_addr[i] && address < m68ki_cpu.write_upper[i]) { + ((int *)(m68ki_cpu.write_data[i] + (address - m68ki_cpu.write_addr[i])))[0] = htobe32(value); return; } } @@ -1272,15 +1376,22 @@ static inline void m68ki_write_32_fc(uint address, uint fc, uint value) } #if M68K_SIMULATE_PD_WRITES +/* Special call to simulate undocumented 68k behavior when move.l with a + * predecrement destination mode is executed. + * A real 68k first writes the high word to [address+2], and then writes the + * low word to [address]. + */ 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_cpu.mmu_tmp_fc = fc; + m68ki_cpu.mmu_tmp_rw = 0; + m68ki_cpu.mmu_tmp_sz = M68K_SZ_LONG; 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); + address = pmmu_translate_addr(address,0); #endif m68k_write_memory_32_pd(ADDRESS_68K(address), value); @@ -1785,8 +1896,12 @@ static inline void m68ki_stack_frame_1000(uint pc, uint sr, uint vector) * if the error happens at an instruction boundary. * PC stacked is address of next instruction. */ -static inline void m68ki_stack_frame_1010(uint sr, uint vector, uint pc) +static inline void m68ki_stack_frame_1010(uint sr, uint vector, uint pc, uint fault_address) { + int orig_rw = m68ki_cpu.mmu_tmp_buserror_rw; // this gets splatted by the following pushes, so save it now + int orig_fc = m68ki_cpu.mmu_tmp_buserror_fc; + int orig_sz = m68ki_cpu.mmu_tmp_buserror_sz; + /* INTERNAL REGISTER */ m68ki_push_16(0); @@ -1803,7 +1918,7 @@ static inline void m68ki_stack_frame_1010(uint sr, uint vector, uint pc) m68ki_push_16(0); /* DATA CYCLE FAULT ADDRESS (2 words) */ - m68ki_push_32(0); + m68ki_push_32(fault_address); /* INSTRUCTION PIPE STAGE B */ m68ki_push_16(0); @@ -1812,7 +1927,9 @@ static inline void m68ki_stack_frame_1010(uint sr, uint vector, uint pc) m68ki_push_16(0); /* SPECIAL STATUS REGISTER */ - m68ki_push_16(0); + // set bit for: Rerun Faulted bus Cycle, or run pending prefetch + // set FC + m68ki_push_16(0x0100 | orig_fc | orig_rw<<6 | orig_sz<<4); /* INTERNAL REGISTER */ m68ki_push_16(0); @@ -1832,8 +1949,11 @@ static inline void m68ki_stack_frame_1010(uint sr, uint vector, uint pc) * if the error happens during instruction execution. * PC stacked is address of instruction in progress. */ -static inline void m68ki_stack_frame_1011(uint sr, uint vector, uint pc) +static inline void m68ki_stack_frame_1011(uint sr, uint vector, uint pc, uint fault_address) { + int orig_rw = m68ki_cpu.mmu_tmp_buserror_rw; // this gets splatted by the following pushes, so save it now + int orig_fc = m68ki_cpu.mmu_tmp_buserror_fc; + int orig_sz = m68ki_cpu.mmu_tmp_buserror_sz; /* INTERNAL REGISTERS (18 words) */ m68ki_push_32(0); m68ki_push_32(0); @@ -1875,7 +1995,7 @@ static inline void m68ki_stack_frame_1011(uint sr, uint vector, uint pc) m68ki_push_16(0); /* DATA CYCLE FAULT ADDRESS (2 words) */ - m68ki_push_32(0); + m68ki_push_32(fault_address); /* INSTRUCTION PIPE STAGE B */ m68ki_push_16(0); @@ -1884,7 +2004,7 @@ static inline void m68ki_stack_frame_1011(uint sr, uint vector, uint pc) m68ki_push_16(0); /* SPECIAL STATUS REGISTER */ - m68ki_push_16(0); + m68ki_push_16(0x0100 | orig_fc | (orig_rw<<6) | (orig_sz<<4)); /* INTERNAL REGISTER */ m68ki_push_16(0); @@ -1899,6 +2019,48 @@ static inline void m68ki_stack_frame_1011(uint sr, uint vector, uint pc) m68ki_push_16(sr); } +/* Type 7 stack frame (access fault). + * This is used by the 68040 for bus fault and mmu trap + * 30 words + */ +static inline void m68ki_stack_frame_0111(uint sr, uint vector, uint pc, uint fault_address, uint8 in_mmu) +{ + int orig_rw = m68ki_cpu.mmu_tmp_buserror_rw; // this gets splatted by the following pushes, so save it now + int orig_fc = m68ki_cpu.mmu_tmp_buserror_fc; + + /* INTERNAL REGISTERS (18 words) */ + m68ki_push_32(0); + m68ki_push_32(0); + m68ki_push_32(0); + m68ki_push_32(0); + m68ki_push_32(0); + m68ki_push_32(0); + m68ki_push_32(0); + m68ki_push_32(0); + m68ki_push_32(0); + + /* FAULT ADDRESS (2 words) */ + m68ki_push_32(fault_address); + + /* INTERNAL REGISTERS (3 words) */ + m68ki_push_32(0); + m68ki_push_16(0); + + /* SPECIAL STATUS REGISTER (1 word) */ + m68ki_push_16((in_mmu ? 0x400 : 0) | orig_fc | (orig_rw<<8)); + + /* EFFECTIVE ADDRESS (2 words) */ + m68ki_push_32(fault_address); + + /* 0111, VECTOR OFFSET (1 word) */ + m68ki_push_16(0x7000 | (vector<<2)); + + /* PROGRAM COUNTER (2 words) */ + m68ki_push_32(pc); + + /* STATUS REGISTER (1 word) */ + m68ki_push_16(sr); +} /* Used for Group 2 exceptions. * These stack a type 2 frame on the 020. @@ -1990,7 +2152,7 @@ static inline void m68ki_exception_bus_error(void) */ if(CPU_RUN_MODE == RUN_MODE_BERR_AERR_RESET) { -m68k_read_memory_8(0x00ffff01); + m68k_read_memory_8(0x00ffff01); CPU_STOPPED = STOP_LEVEL_HALT; return; } @@ -2019,7 +2181,7 @@ static inline void m68ki_exception_1010(void) #if M68K_LOG_1010_1111 == OPT_ON M68K_DO_LOG_EMU((M68K_LOG_FILEHANDLE "%s at %08x: called 1010 instruction %04x (%s)\n", m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PPC), REG_IR, - m68ki_disassemble_quick(ADDRESS_68K(REG_PPC)))); + m68ki_disassemble_quick(ADDRESS_68K(REG_PPC),CPU_TYPE))); #endif sr = m68ki_init_exception(); @@ -2038,7 +2200,7 @@ static inline void m68ki_exception_1111(void) #if M68K_LOG_1010_1111 == OPT_ON M68K_DO_LOG_EMU((M68K_LOG_FILEHANDLE "%s at %08x: called 1111 instruction %04x (%s)\n", m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PPC), REG_IR, - m68ki_disassemble_quick(ADDRESS_68K(REG_PPC)))); + m68ki_disassemble_quick(ADDRESS_68K(REG_PPC),CPU_TYPE))); #endif sr = m68ki_init_exception(); @@ -2060,7 +2222,7 @@ static inline void m68ki_exception_illegal(void) M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: illegal instruction %04x (%s)\n", m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PPC), REG_IR, - m68ki_disassemble_quick(ADDRESS_68K(REG_PPC)))); + m68ki_disassemble_quick(ADDRESS_68K(REG_PPC),CPU_TYPE))); if (m68ki_illg_callback(REG_IR)) return; @@ -2094,25 +2256,44 @@ static inline void m68ki_exception_format_error(void) /* Exception for address error */ static inline void m68ki_exception_address_error(void) { - uint sr = m68ki_init_exception(); + uint32 sr = m68ki_init_exception(); /* If we were processing a bus error, address error, or reset, * this is a catastrophic failure. * Halt the CPU */ - if(CPU_RUN_MODE == RUN_MODE_BERR_AERR_RESET) + if(CPU_RUN_MODE == RUN_MODE_BERR_AERR_RESET_WSF) { -m68k_read_memory_8(0x00ffff01); + m68k_read_memory_8(0x00ffff01); CPU_STOPPED = STOP_LEVEL_HALT; return; } - CPU_RUN_MODE = RUN_MODE_BERR_AERR_RESET; - /* Note: This is implemented for 68000 only! */ - m68ki_stack_frame_buserr(sr); + CPU_RUN_MODE = RUN_MODE_BERR_AERR_RESET_WSF; + + if (CPU_TYPE_IS_000(CPU_TYPE)) + { + /* Note: This is implemented for 68000 only! */ + m68ki_stack_frame_buserr(sr); + } + else if (CPU_TYPE_IS_010(CPU_TYPE)) + { + /* only the 68010 throws this unique type-1000 frame */ + m68ki_stack_frame_1000(REG_PPC, sr, EXCEPTION_BUS_ERROR); + } + else if (m68ki_cpu.mmu_tmp_buserror_address == REG_PPC) + { + m68ki_stack_frame_1010(sr, EXCEPTION_BUS_ERROR, REG_PPC, m68ki_cpu.mmu_tmp_buserror_address); + } + else + { + m68ki_stack_frame_1011(sr, EXCEPTION_BUS_ERROR, REG_PPC, m68ki_cpu.mmu_tmp_buserror_address); + } m68ki_jump_vector(EXCEPTION_ADDRESS_ERROR); + m68ki_cpu.run_mode = RUN_MODE_BERR_AERR_RESET; + /* Use up some clock cycles. Note that we don't need to undo the instruction's cycles here as we've longjmp:ed directly from the instruction handler without passing the part of the excecute loop