/* ======================================================================== */ /* ========================= LICENSING & COPYRIGHT ======================== */ /* ======================================================================== */ /* * MUSASHI * Version 3.4 * * A portable Motorola M680x0 processor emulation engine. * Copyright 1998-2001 Karl Stenerud. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* ======================================================================== */ /* ================================= NOTES ================================ */ /* ======================================================================== */ /* ======================================================================== */ /* ================================ INCLUDES ============================== */ /* ======================================================================== */ #include "m68kops.h" #include "m68kcpu.h" /* ======================================================================== */ /* ================================= DATA ================================= */ /* ======================================================================== */ int m68ki_initial_cycles; int m68ki_remaining_cycles = 0; /* Number of clocks remaining */ uint m68ki_tracing = 0; uint m68ki_address_space; #ifdef M68K_LOG_ENABLE char* m68ki_cpu_names[9] = { "Invalid CPU", "M68000", "M68010", "Invalid CPU", "M68EC020" "Invalid CPU", "Invalid CPU", "Invalid CPU", "M68020" }; #endif /* M68K_LOG_ENABLE */ /* The CPU core */ m68ki_cpu_core m68ki_cpu = {0}; #if M68K_EMULATE_ADDRESS_ERROR jmp_buf m68ki_aerr_trap; #endif /* M68K_EMULATE_ADDRESS_ERROR */ uint m68ki_aerr_address; uint m68ki_aerr_write_mode; uint m68ki_aerr_fc; /* Used by shift & rotate instructions */ uint8 m68ki_shift_8_table[65] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; uint16 m68ki_shift_16_table[65] = { 0x0000, 0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }; uint m68ki_shift_32_table[65] = { 0x00000000, 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000, 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; /* Number of clock cycles to use for exception processing. * I used 4 for any vectors that are undocumented for processing times. */ uint8 m68ki_exception_cycle_table[3][256] = { { /* 000 */ 4, /* 0: Reset - Initial Stack Pointer */ 4, /* 1: Reset - Initial Program Counter */ 50, /* 2: Bus Error (unemulated) */ 50, /* 3: Address Error (unemulated) */ 34, /* 4: Illegal Instruction */ 38, /* 5: Divide by Zero -- ASG: changed from 42 */ 40, /* 6: CHK -- ASG: chanaged from 44 */ 34, /* 7: TRAPV */ 34, /* 8: Privilege Violation */ 34, /* 9: Trace */ 34, /* 10: 1010 */ 34, /* 11: 1111 */ 4, /* 12: RESERVED */ 4, /* 13: Coprocessor Protocol Violation (unemulated) */ 4, /* 14: Format Error */ 44, /* 15: Uninitialized Interrupt */ 4, /* 16: RESERVED */ 4, /* 17: RESERVED */ 4, /* 18: RESERVED */ 4, /* 19: RESERVED */ 4, /* 20: RESERVED */ 4, /* 21: RESERVED */ 4, /* 22: RESERVED */ 4, /* 23: RESERVED */ 44, /* 24: Spurious Interrupt */ 44, /* 25: Level 1 Interrupt Autovector */ 44, /* 26: Level 2 Interrupt Autovector */ 44, /* 27: Level 3 Interrupt Autovector */ 44, /* 28: Level 4 Interrupt Autovector */ 44, /* 29: Level 5 Interrupt Autovector */ 44, /* 30: Level 6 Interrupt Autovector */ 44, /* 31: Level 7 Interrupt Autovector */ 34, /* 32: TRAP #0 -- ASG: chanaged from 38 */ 34, /* 33: TRAP #1 */ 34, /* 34: TRAP #2 */ 34, /* 35: TRAP #3 */ 34, /* 36: TRAP #4 */ 34, /* 37: TRAP #5 */ 34, /* 38: TRAP #6 */ 34, /* 39: TRAP #7 */ 34, /* 40: TRAP #8 */ 34, /* 41: TRAP #9 */ 34, /* 42: TRAP #10 */ 34, /* 43: TRAP #11 */ 34, /* 44: TRAP #12 */ 34, /* 45: TRAP #13 */ 34, /* 46: TRAP #14 */ 34, /* 47: TRAP #15 */ 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */ 4, /* 49: FP Inexact Result (unemulated) */ 4, /* 50: FP Divide by Zero (unemulated) */ 4, /* 51: FP Underflow (unemulated) */ 4, /* 52: FP Operand Error (unemulated) */ 4, /* 53: FP Overflow (unemulated) */ 4, /* 54: FP Signaling NAN (unemulated) */ 4, /* 55: FP Unimplemented Data Type (unemulated) */ 4, /* 56: MMU Configuration Error (unemulated) */ 4, /* 57: MMU Illegal Operation Error (unemulated) */ 4, /* 58: MMU Access Level Violation Error (unemulated) */ 4, /* 59: RESERVED */ 4, /* 60: RESERVED */ 4, /* 61: RESERVED */ 4, /* 62: RESERVED */ 4, /* 63: RESERVED */ /* 64-255: User Defined */ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 }, { /* 010 */ 4, /* 0: Reset - Initial Stack Pointer */ 4, /* 1: Reset - Initial Program Counter */ 126, /* 2: Bus Error (unemulated) */ 126, /* 3: Address Error (unemulated) */ 38, /* 4: Illegal Instruction */ 44, /* 5: Divide by Zero */ 44, /* 6: CHK */ 34, /* 7: TRAPV */ 38, /* 8: Privilege Violation */ 38, /* 9: Trace */ 4, /* 10: 1010 */ 4, /* 11: 1111 */ 4, /* 12: RESERVED */ 4, /* 13: Coprocessor Protocol Violation (unemulated) */ 4, /* 14: Format Error */ 44, /* 15: Uninitialized Interrupt */ 4, /* 16: RESERVED */ 4, /* 17: RESERVED */ 4, /* 18: RESERVED */ 4, /* 19: RESERVED */ 4, /* 20: RESERVED */ 4, /* 21: RESERVED */ 4, /* 22: RESERVED */ 4, /* 23: RESERVED */ 46, /* 24: Spurious Interrupt */ 46, /* 25: Level 1 Interrupt Autovector */ 46, /* 26: Level 2 Interrupt Autovector */ 46, /* 27: Level 3 Interrupt Autovector */ 46, /* 28: Level 4 Interrupt Autovector */ 46, /* 29: Level 5 Interrupt Autovector */ 46, /* 30: Level 6 Interrupt Autovector */ 46, /* 31: Level 7 Interrupt Autovector */ 38, /* 32: TRAP #0 */ 38, /* 33: TRAP #1 */ 38, /* 34: TRAP #2 */ 38, /* 35: TRAP #3 */ 38, /* 36: TRAP #4 */ 38, /* 37: TRAP #5 */ 38, /* 38: TRAP #6 */ 38, /* 39: TRAP #7 */ 38, /* 40: TRAP #8 */ 38, /* 41: TRAP #9 */ 38, /* 42: TRAP #10 */ 38, /* 43: TRAP #11 */ 38, /* 44: TRAP #12 */ 38, /* 45: TRAP #13 */ 38, /* 46: TRAP #14 */ 38, /* 47: TRAP #15 */ 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */ 4, /* 49: FP Inexact Result (unemulated) */ 4, /* 50: FP Divide by Zero (unemulated) */ 4, /* 51: FP Underflow (unemulated) */ 4, /* 52: FP Operand Error (unemulated) */ 4, /* 53: FP Overflow (unemulated) */ 4, /* 54: FP Signaling NAN (unemulated) */ 4, /* 55: FP Unimplemented Data Type (unemulated) */ 4, /* 56: MMU Configuration Error (unemulated) */ 4, /* 57: MMU Illegal Operation Error (unemulated) */ 4, /* 58: MMU Access Level Violation Error (unemulated) */ 4, /* 59: RESERVED */ 4, /* 60: RESERVED */ 4, /* 61: RESERVED */ 4, /* 62: RESERVED */ 4, /* 63: RESERVED */ /* 64-255: User Defined */ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 }, { /* 020 */ 4, /* 0: Reset - Initial Stack Pointer */ 4, /* 1: Reset - Initial Program Counter */ 50, /* 2: Bus Error (unemulated) */ 50, /* 3: Address Error (unemulated) */ 20, /* 4: Illegal Instruction */ 38, /* 5: Divide by Zero */ 40, /* 6: CHK */ 20, /* 7: TRAPV */ 34, /* 8: Privilege Violation */ 25, /* 9: Trace */ 20, /* 10: 1010 */ 20, /* 11: 1111 */ 4, /* 12: RESERVED */ 4, /* 13: Coprocessor Protocol Violation (unemulated) */ 4, /* 14: Format Error */ 30, /* 15: Uninitialized Interrupt */ 4, /* 16: RESERVED */ 4, /* 17: RESERVED */ 4, /* 18: RESERVED */ 4, /* 19: RESERVED */ 4, /* 20: RESERVED */ 4, /* 21: RESERVED */ 4, /* 22: RESERVED */ 4, /* 23: RESERVED */ 30, /* 24: Spurious Interrupt */ 30, /* 25: Level 1 Interrupt Autovector */ 30, /* 26: Level 2 Interrupt Autovector */ 30, /* 27: Level 3 Interrupt Autovector */ 30, /* 28: Level 4 Interrupt Autovector */ 30, /* 29: Level 5 Interrupt Autovector */ 30, /* 30: Level 6 Interrupt Autovector */ 30, /* 31: Level 7 Interrupt Autovector */ 20, /* 32: TRAP #0 */ 20, /* 33: TRAP #1 */ 20, /* 34: TRAP #2 */ 20, /* 35: TRAP #3 */ 20, /* 36: TRAP #4 */ 20, /* 37: TRAP #5 */ 20, /* 38: TRAP #6 */ 20, /* 39: TRAP #7 */ 20, /* 40: TRAP #8 */ 20, /* 41: TRAP #9 */ 20, /* 42: TRAP #10 */ 20, /* 43: TRAP #11 */ 20, /* 44: TRAP #12 */ 20, /* 45: TRAP #13 */ 20, /* 46: TRAP #14 */ 20, /* 47: TRAP #15 */ 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */ 4, /* 49: FP Inexact Result (unemulated) */ 4, /* 50: FP Divide by Zero (unemulated) */ 4, /* 51: FP Underflow (unemulated) */ 4, /* 52: FP Operand Error (unemulated) */ 4, /* 53: FP Overflow (unemulated) */ 4, /* 54: FP Signaling NAN (unemulated) */ 4, /* 55: FP Unimplemented Data Type (unemulated) */ 4, /* 56: MMU Configuration Error (unemulated) */ 4, /* 57: MMU Illegal Operation Error (unemulated) */ 4, /* 58: MMU Access Level Violation Error (unemulated) */ 4, /* 59: RESERVED */ 4, /* 60: RESERVED */ 4, /* 61: RESERVED */ 4, /* 62: RESERVED */ 4, /* 63: RESERVED */ /* 64-255: User Defined */ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 } }; uint8 m68ki_ea_idx_cycle_table[64] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ..01.000 no memory indirect, base NULL */ 5, /* ..01..01 memory indirect, base NULL, outer NULL */ 7, /* ..01..10 memory indirect, base NULL, outer 16 */ 7, /* ..01..11 memory indirect, base NULL, outer 32 */ 0, 5, 7, 7, 0, 5, 7, 7, 0, 5, 7, 7, 2, /* ..10.000 no memory indirect, base 16 */ 7, /* ..10..01 memory indirect, base 16, outer NULL */ 9, /* ..10..10 memory indirect, base 16, outer 16 */ 9, /* ..10..11 memory indirect, base 16, outer 32 */ 0, 7, 9, 9, 0, 7, 9, 9, 0, 7, 9, 9, 6, /* ..11.000 no memory indirect, base 32 */ 11, /* ..11..01 memory indirect, base 32, outer NULL */ 13, /* ..11..10 memory indirect, base 32, outer 16 */ 13, /* ..11..11 memory indirect, base 32, outer 32 */ 0, 11, 13, 13, 0, 11, 13, 13, 0, 11, 13, 13 }; /* ======================================================================== */ /* =============================== CALLBACKS ============================== */ /* ======================================================================== */ /* Default callbacks used if the callback hasn't been set yet, or if the * callback is set to NULL */ /* Interrupt acknowledge */ static int default_int_ack_callback_data; static int default_int_ack_callback(int int_level) { default_int_ack_callback_data = int_level; CPU_INT_LEVEL = 0; return M68K_INT_ACK_AUTOVECTOR; } /* Breakpoint acknowledge */ static unsigned int default_bkpt_ack_callback_data; static void default_bkpt_ack_callback(unsigned int data) { default_bkpt_ack_callback_data = data; } /* Called when a reset instruction is executed */ static void default_reset_instr_callback(void) { } /* Called when the program counter changed by a large value */ static unsigned int default_pc_changed_callback_data; static void default_pc_changed_callback(unsigned int new_pc) { default_pc_changed_callback_data = new_pc; } /* Called every time there's bus activity (read/write to/from memory */ static unsigned int default_set_fc_callback_data; static void default_set_fc_callback(unsigned int new_fc) { default_set_fc_callback_data = new_fc; } /* Called every instruction cycle prior to execution */ static void default_instr_hook_callback(void) { } #if M68K_EMULATE_ADDRESS_ERROR #include jmp_buf m68ki_aerr_trap; #endif /* M68K_EMULATE_ADDRESS_ERROR */ /* ======================================================================== */ /* ================================= API ================================== */ /* ======================================================================== */ /* Access the internals of the CPU */ unsigned int m68k_get_reg(void* context, m68k_register_t regnum) { m68ki_cpu_core* cpu = context != NULL ?(m68ki_cpu_core*)context : &m68ki_cpu; switch(regnum) { case M68K_REG_D0: return cpu->dar[0]; case M68K_REG_D1: return cpu->dar[1]; case M68K_REG_D2: return cpu->dar[2]; case M68K_REG_D3: return cpu->dar[3]; case M68K_REG_D4: return cpu->dar[4]; case M68K_REG_D5: return cpu->dar[5]; case M68K_REG_D6: return cpu->dar[6]; case M68K_REG_D7: return cpu->dar[7]; case M68K_REG_A0: return cpu->dar[8]; case M68K_REG_A1: return cpu->dar[9]; case M68K_REG_A2: return cpu->dar[10]; case M68K_REG_A3: return cpu->dar[11]; case M68K_REG_A4: return cpu->dar[12]; case M68K_REG_A5: return cpu->dar[13]; case M68K_REG_A6: return cpu->dar[14]; case M68K_REG_A7: return cpu->dar[15]; case M68K_REG_PC: return MASK_OUT_ABOVE_32(cpu->pc); case M68K_REG_SR: return cpu->t1_flag | cpu->t0_flag | (cpu->s_flag << 11) | (cpu->m_flag << 11) | cpu->int_mask | ((cpu->x_flag & XFLAG_SET) >> 4) | ((cpu->n_flag & NFLAG_SET) >> 4) | ((!cpu->not_z_flag) << 2) | ((cpu->v_flag & VFLAG_SET) >> 6) | ((cpu->c_flag & CFLAG_SET) >> 8); case M68K_REG_SP: return cpu->dar[15]; case M68K_REG_USP: return cpu->s_flag ? cpu->sp[0] : cpu->dar[15]; case M68K_REG_ISP: return cpu->s_flag && !cpu->m_flag ? cpu->dar[15] : cpu->sp[4]; case M68K_REG_MSP: return cpu->s_flag && cpu->m_flag ? cpu->dar[15] : cpu->sp[6]; case M68K_REG_SFC: return cpu->sfc; case M68K_REG_DFC: return cpu->dfc; case M68K_REG_VBR: return cpu->vbr; case M68K_REG_CACR: return cpu->cacr; case M68K_REG_CAAR: return cpu->caar; case M68K_REG_PREF_ADDR: return cpu->pref_addr; case M68K_REG_PREF_DATA: return cpu->pref_data; case M68K_REG_PPC: return MASK_OUT_ABOVE_32(cpu->ppc); case M68K_REG_IR: return cpu->ir; case M68K_REG_CPU_TYPE: switch(cpu->cpu_type) { case CPU_TYPE_000: return (unsigned int)M68K_CPU_TYPE_68000; case CPU_TYPE_010: return (unsigned int)M68K_CPU_TYPE_68010; case CPU_TYPE_EC020: return (unsigned int)M68K_CPU_TYPE_68EC020; case CPU_TYPE_020: return (unsigned int)M68K_CPU_TYPE_68020; } return M68K_CPU_TYPE_INVALID; default: return 0; } return 0; } void m68k_set_reg(m68k_register_t regnum, unsigned int value) { switch(regnum) { case M68K_REG_D0: REG_D[0] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_D1: REG_D[1] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_D2: REG_D[2] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_D3: REG_D[3] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_D4: REG_D[4] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_D5: REG_D[5] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_D6: REG_D[6] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_D7: REG_D[7] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_A0: REG_A[0] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_A1: REG_A[1] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_A2: REG_A[2] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_A3: REG_A[3] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_A4: REG_A[4] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_A5: REG_A[5] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_A6: REG_A[6] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_A7: REG_A[7] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_PC: m68ki_jump(MASK_OUT_ABOVE_32(value)); return; case M68K_REG_SR: m68ki_set_sr(value); return; case M68K_REG_SP: REG_SP = MASK_OUT_ABOVE_32(value); return; case M68K_REG_USP: if(FLAG_S) REG_USP = MASK_OUT_ABOVE_32(value); else REG_SP = MASK_OUT_ABOVE_32(value); return; case M68K_REG_ISP: if(FLAG_S && !FLAG_M) REG_SP = MASK_OUT_ABOVE_32(value); else REG_ISP = MASK_OUT_ABOVE_32(value); return; case M68K_REG_MSP: if(FLAG_S && FLAG_M) REG_SP = MASK_OUT_ABOVE_32(value); else REG_MSP = MASK_OUT_ABOVE_32(value); return; case M68K_REG_VBR: REG_VBR = MASK_OUT_ABOVE_32(value); return; case M68K_REG_SFC: REG_SFC = value & 7; return; case M68K_REG_DFC: REG_DFC = value & 7; return; case M68K_REG_CACR: REG_CACR = MASK_OUT_ABOVE_32(value); return; case M68K_REG_CAAR: REG_CAAR = MASK_OUT_ABOVE_32(value); return; case M68K_REG_PPC: REG_PPC = MASK_OUT_ABOVE_32(value); return; case M68K_REG_IR: REG_IR = MASK_OUT_ABOVE_16(value); return; case M68K_REG_CPU_TYPE: m68k_set_cpu_type(value); return; default: return; } } /* Set the callbacks */ void m68k_set_int_ack_callback(int (*callback)(int int_level)) { CALLBACK_INT_ACK = callback ? callback : default_int_ack_callback; } void m68k_set_bkpt_ack_callback(void (*callback)(unsigned int data)) { CALLBACK_BKPT_ACK = callback ? callback : default_bkpt_ack_callback; } void m68k_set_reset_instr_callback(void (*callback)(void)) { CALLBACK_RESET_INSTR = callback ? callback : default_reset_instr_callback; } void m68k_set_pc_changed_callback(void (*callback)(unsigned int new_pc)) { CALLBACK_PC_CHANGED = callback ? callback : default_pc_changed_callback; } void m68k_set_fc_callback(void (*callback)(unsigned int new_fc)) { CALLBACK_SET_FC = callback ? callback : default_set_fc_callback; } void m68k_set_instr_hook_callback(void (*callback)(void)) { CALLBACK_INSTR_HOOK = callback ? callback : default_instr_hook_callback; } /* Set the CPU type. */ void m68k_set_cpu_type(unsigned int cpu_type) { switch(cpu_type) { case M68K_CPU_TYPE_68000: CPU_TYPE = CPU_TYPE_000; CPU_ADDRESS_MASK = 0x00ffffff; CPU_SR_MASK = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */ CYC_INSTRUCTION = m68ki_cycles[0]; CYC_EXCEPTION = m68ki_exception_cycle_table[0]; CYC_BCC_NOTAKE_B = -2; CYC_BCC_NOTAKE_W = 2; CYC_DBCC_F_NOEXP = -2; CYC_DBCC_F_EXP = 2; CYC_SCC_R_TRUE = 2; CYC_MOVEM_W = 2; CYC_MOVEM_L = 3; CYC_SHIFT = 1; CYC_RESET = 132; return; case M68K_CPU_TYPE_68010: CPU_TYPE = CPU_TYPE_010; CPU_ADDRESS_MASK = 0x00ffffff; CPU_SR_MASK = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */ CYC_INSTRUCTION = m68ki_cycles[1]; CYC_EXCEPTION = m68ki_exception_cycle_table[1]; CYC_BCC_NOTAKE_B = -4; CYC_BCC_NOTAKE_W = 0; CYC_DBCC_F_NOEXP = 0; CYC_DBCC_F_EXP = 6; CYC_SCC_R_TRUE = 0; CYC_MOVEM_W = 2; CYC_MOVEM_L = 3; CYC_SHIFT = 1; CYC_RESET = 130; return; case M68K_CPU_TYPE_68EC020: CPU_TYPE = CPU_TYPE_EC020; CPU_ADDRESS_MASK = 0x00ffffff; CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */ CYC_INSTRUCTION = m68ki_cycles[2]; CYC_EXCEPTION = m68ki_exception_cycle_table[2]; 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; return; case M68K_CPU_TYPE_68020: CPU_TYPE = CPU_TYPE_020; CPU_ADDRESS_MASK = 0xffffffff; CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */ CYC_INSTRUCTION = m68ki_cycles[2]; CYC_EXCEPTION = m68ki_exception_cycle_table[2]; 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; return; } } /* Execute some instructions until we use up num_cycles clock cycles */ /* ASG: removed per-instruction interrupt checks */ int m68k_execute(int num_cycles) { /* Make sure we're not stopped */ if(!CPU_STOPPED) { /* Set our pool of clock cycles available */ SET_CYCLES(num_cycles); m68ki_initial_cycles = num_cycles; /* ASG: update cycles */ USE_CYCLES(CPU_INT_CYCLES); CPU_INT_CYCLES = 0; /* Return point if we had an address error */ m68ki_set_address_error_trap(); /* auto-disable (see m68kcpu.h) */ /* Main loop. Keep going until we run out of clock cycles */ do { /* Set tracing accodring to T1. (T0 is done inside instruction) */ m68ki_trace_t1(); /* auto-disable (see m68kcpu.h) */ /* Set the address space for reads */ m68ki_use_data_space(); /* auto-disable (see m68kcpu.h) */ /* Call external hook to peek at CPU */ m68ki_instr_hook(); /* auto-disable (see m68kcpu.h) */ /* Record previous program counter */ REG_PPC = REG_PC; /* Read an instruction and call its handler */ REG_IR = m68ki_read_imm_16(); m68ki_instruction_jump_table[REG_IR](); USE_CYCLES(CYC_INSTRUCTION[REG_IR]); /* Trace m68k_exception, if necessary */ m68ki_exception_if_trace(); /* auto-disable (see m68kcpu.h) */ } while(GET_CYCLES() > 0); /* set previous PC to current PC for the next entry into the loop */ REG_PPC = REG_PC; /* ASG: update cycles */ USE_CYCLES(CPU_INT_CYCLES); CPU_INT_CYCLES = 0; /* return how many clocks we used */ return m68ki_initial_cycles - GET_CYCLES(); } /* We get here if the CPU is stopped or halted */ SET_CYCLES(0); CPU_INT_CYCLES = 0; return num_cycles; } int m68k_cycles_run(void) { return m68ki_initial_cycles - GET_CYCLES(); } int m68k_cycles_remaining(void) { return GET_CYCLES(); } /* Change the timeslice */ void m68k_modify_timeslice(int cycles) { m68ki_initial_cycles += cycles; ADD_CYCLES(cycles); } void m68k_end_timeslice(void) { m68ki_initial_cycles = GET_CYCLES(); SET_CYCLES(0); } /* ASG: rewrote so that the int_level is a mask of the IPL0/IPL1/IPL2 bits */ /* KS: Modified so that IPL* bits match with mask positions in the SR * and cleaned out remenants of the interrupt controller. */ void m68k_set_irq(unsigned int int_level) { uint old_level = CPU_INT_LEVEL; CPU_INT_LEVEL = int_level << 8; /* A transition from < 7 to 7 always interrupts (NMI) */ /* Note: Level 7 can also level trigger like a normal IRQ */ if(old_level != 0x0700 && CPU_INT_LEVEL == 0x0700) m68ki_exception_interrupt(7); /* Edge triggered level 7 (NMI) */ else m68ki_check_interrupts(); /* Level triggered (IRQ) */ } void m68k_init(void) { static uint emulation_initialized = 0; /* The first call to this function initializes the opcode handler jump table */ if(!emulation_initialized) { m68ki_build_opcode_table(); emulation_initialized = 1; } m68k_set_int_ack_callback(NULL); m68k_set_bkpt_ack_callback(NULL); m68k_set_reset_instr_callback(NULL); m68k_set_pc_changed_callback(NULL); m68k_set_fc_callback(NULL); m68k_set_instr_hook_callback(NULL); } /* Pulse the RESET line on the CPU */ void m68k_pulse_reset(void) { /* Clear all stop levels and eat up all remaining cycles */ CPU_STOPPED = 0; SET_CYCLES(0); CPU_RUN_MODE = RUN_MODE_BERR_AERR_RESET; CPU_INSTR_MODE = INSTRUCTION_YES; /* Turn off tracing */ FLAG_T1 = FLAG_T0 = 0; m68ki_clear_trace(); /* Interrupt mask to level 7 */ FLAG_INT_MASK = 0x0700; /* Reset VBR */ REG_VBR = 0; /* Go to supervisor mode */ m68ki_set_sm_flag(SFLAG_SET | MFLAG_CLEAR); /* Invalidate the prefetch queue */ #if M68K_EMULATE_PREFETCH /* Set to arbitrary number since our first fetch is from 0 */ CPU_PREF_ADDR = 0x1000; #endif /* M68K_EMULATE_PREFETCH */ /* Read the initial stack pointer and program counter */ m68ki_jump(0); REG_SP = m68ki_read_imm_32(); REG_PC = m68ki_read_imm_32(); m68ki_jump(REG_PC); CPU_RUN_MODE = RUN_MODE_NORMAL; } /* Pulse the HALT line on the CPU */ 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() { return sizeof(m68ki_cpu_core); } unsigned int m68k_get_context(void* dst) { if(dst) *(m68ki_cpu_core*)dst = m68ki_cpu; return sizeof(m68ki_cpu_core); } void m68k_set_context(void* src) { if(src) m68ki_cpu = *(m68ki_cpu_core*)src; } /* ======================================================================== */ /* ============================== MAME STUFF ============================== */ /* ======================================================================== */ #if M68K_COMPILE_FOR_MAME == OPT_ON #include "state.h" static struct { UINT16 sr; int stopped; int halted; } m68k_substate; static void m68k_prepare_substate(void) { m68k_substate.sr = m68ki_get_sr(); m68k_substate.stopped = (CPU_STOPPED & STOP_LEVEL_STOP) != 0; m68k_substate.halted = (CPU_STOPPED & STOP_LEVEL_HALT) != 0; } static void m68k_post_load(void) { m68ki_set_sr_noint_nosp(m68k_substate.sr); CPU_STOPPED = m68k_substate.stopped ? STOP_LEVEL_STOP : 0 | m68k_substate.halted ? STOP_LEVEL_HALT : 0; m68ki_jump(REG_PC); } void m68k_state_register(const char *type) { int cpu = cpu_getactivecpu(); state_save_register_UINT32(type, cpu, "D" , REG_D, 8); state_save_register_UINT32(type, cpu, "A" , REG_A, 8); state_save_register_UINT32(type, cpu, "PPC" , ®_PPC, 1); state_save_register_UINT32(type, cpu, "PC" , ®_PC, 1); state_save_register_UINT32(type, cpu, "USP" , ®_USP, 1); state_save_register_UINT32(type, cpu, "ISP" , ®_ISP, 1); state_save_register_UINT32(type, cpu, "MSP" , ®_MSP, 1); state_save_register_UINT32(type, cpu, "VBR" , ®_VBR, 1); state_save_register_UINT32(type, cpu, "SFC" , ®_SFC, 1); state_save_register_UINT32(type, cpu, "DFC" , ®_DFC, 1); state_save_register_UINT32(type, cpu, "CACR" , ®_CACR, 1); state_save_register_UINT32(type, cpu, "CAAR" , ®_CAAR, 1); state_save_register_UINT16(type, cpu, "SR" , &m68k_substate.sr, 1); state_save_register_UINT32(type, cpu, "INT_LEVEL" , &CPU_INT_LEVEL, 1); state_save_register_UINT32(type, cpu, "INT_CYCLES", &CPU_INT_CYCLES, 1); state_save_register_int (type, cpu, "STOPPED" , &m68k_substate.stopped); state_save_register_int (type, cpu, "HALTED" , &m68k_substate.halted); state_save_register_UINT32(type, cpu, "PREF_ADDR" , &CPU_PREF_ADDR, 1); state_save_register_UINT32(type, cpu, "PREF_DATA" , &CPU_PREF_DATA, 1); state_save_register_func_presave(m68k_prepare_substate); state_save_register_func_postload(m68k_post_load); } #endif /* M68K_COMPILE_FOR_MAME */ /* ======================================================================== */ /* ============================== END OF FILE ============================= */ /* ======================================================================== */