src/musashi/m68kcpu.h

Wed, 16 Apr 2014 02:20:43 -0600

author
andrew@localhost
date
Wed, 16 Apr 2014 02:20:43 -0600
changeset 147
ad888290cdff
parent 110
acea4b2f396f
permissions
-rw-r--r--

fixed bus error handling for real this time (save registers before every instruction and push the saved registers if a bus error occurs, since the instruction may have changed registers before the bus error, and also stop the instruction immediately with longjmp so it won't change memory after the bus error)

This isn't actually what a real 68k does, but it is a good enough approximation. A real 68k will jump back into the middle of the faulted instruction and resume it from the memory access that faulted as opposed to restarting from the beginning like this CPU emulation does. It would be a lot harder to do that with the way this CPU library is designed. Newer versions of MESS basically do the same thing (they use a newer version of this library).

philpem@0 1 #include <stdio.h>
philpem@0 2 /* ======================================================================== */
philpem@0 3 /* ========================= LICENSING & COPYRIGHT ======================== */
philpem@0 4 /* ======================================================================== */
philpem@0 5 /*
philpem@0 6 * MUSASHI
philpem@0 7 * Version 3.3
philpem@0 8 *
philpem@0 9 * A portable Motorola M680x0 processor emulation engine.
philpem@0 10 * Copyright 1998-2001 Karl Stenerud. All rights reserved.
philpem@0 11 *
philpem@0 12 * This code may be freely used for non-commercial purposes as long as this
philpem@0 13 * copyright notice remains unaltered in the source code and any binary files
philpem@0 14 * containing this code in compiled form.
philpem@0 15 *
philpem@0 16 * All other lisencing terms must be negotiated with the author
philpem@0 17 * (Karl Stenerud).
philpem@0 18 *
philpem@0 19 * The latest version of this code can be obtained at:
philpem@0 20 * http://kstenerud.cjb.net
philpem@0 21 */
philpem@0 22
philpem@0 23
philpem@0 24
philpem@0 25
philpem@0 26 #ifndef M68KCPU__HEADER
philpem@0 27 #define M68KCPU__HEADER
philpem@0 28
philpem@0 29 #include "m68k.h"
philpem@0 30 #include <limits.h>
andrew@147 31 #include <string.h>
philpem@0 32
philpem@0 33 #include <setjmp.h>
philpem@0 34
philpem@0 35 /* ======================================================================== */
philpem@0 36 /* ==================== ARCHITECTURE-DEPENDANT DEFINES ==================== */
philpem@0 37 /* ======================================================================== */
philpem@0 38
philpem@0 39 /* Check for > 32bit sizes */
philpem@0 40 #if UINT_MAX > 0xffffffff
philpem@0 41 #define M68K_INT_GT_32_BIT 1
philpem@0 42 #endif
philpem@0 43
philpem@0 44 /* Data types used in this emulation core */
philpem@0 45 #undef sint8
philpem@0 46 #undef sint16
philpem@0 47 #undef sint32
philpem@0 48 #undef sint64
philpem@0 49 #undef uint8
philpem@0 50 #undef uint16
philpem@0 51 #undef uint32
philpem@0 52 #undef uint64
philpem@0 53 #undef sint
philpem@0 54 #undef uint
philpem@0 55
philpem@0 56 #define sint8 signed char /* ASG: changed from char to signed char */
philpem@0 57 #define sint16 signed short
philpem@0 58 #define sint32 signed long
philpem@0 59 #define uint8 unsigned char
philpem@0 60 #define uint16 unsigned short
philpem@0 61 #define uint32 unsigned long
philpem@0 62
philpem@0 63 /* signed and unsigned int must be at least 32 bits wide */
philpem@0 64 #define sint signed int
philpem@0 65 #define uint unsigned int
philpem@0 66
philpem@0 67
philpem@0 68 #if M68K_USE_64_BIT
philpem@0 69 #define sint64 signed long long
philpem@0 70 #define uint64 unsigned long long
philpem@0 71 #else
philpem@0 72 #define sint64 sint32
philpem@0 73 #define uint64 uint32
philpem@0 74 #endif /* M68K_USE_64_BIT */
philpem@0 75
philpem@0 76
philpem@0 77
philpem@0 78 /* Allow for architectures that don't have 8-bit sizes */
philpem@0 79 #if UCHAR_MAX == 0xff
philpem@0 80 #define MAKE_INT_8(A) (sint8)(A)
philpem@0 81 #else
philpem@0 82 #undef sint8
philpem@0 83 #define sint8 signed int
philpem@0 84 #undef uint8
philpem@0 85 #define uint8 unsigned int
philpem@0 86 INLINE sint MAKE_INT_8(uint value)
philpem@0 87 {
philpem@0 88 return (value & 0x80) ? value | ~0xff : value & 0xff;
philpem@0 89 }
philpem@0 90 #endif /* UCHAR_MAX == 0xff */
philpem@0 91
philpem@0 92
philpem@0 93 /* Allow for architectures that don't have 16-bit sizes */
philpem@0 94 #if USHRT_MAX == 0xffff
philpem@0 95 #define MAKE_INT_16(A) (sint16)(A)
philpem@0 96 #else
philpem@0 97 #undef sint16
philpem@0 98 #define sint16 signed int
philpem@0 99 #undef uint16
philpem@0 100 #define uint16 unsigned int
philpem@0 101 INLINE sint MAKE_INT_16(uint value)
philpem@0 102 {
philpem@0 103 return (value & 0x8000) ? value | ~0xffff : value & 0xffff;
philpem@0 104 }
philpem@0 105 #endif /* USHRT_MAX == 0xffff */
philpem@0 106
philpem@0 107
philpem@0 108 /* Allow for architectures that don't have 32-bit sizes */
philpem@0 109 #if ULONG_MAX == 0xffffffff
philpem@0 110 #define MAKE_INT_32(A) (sint32)(A)
philpem@0 111 #else
philpem@0 112 #undef sint32
philpem@0 113 #define sint32 signed int
philpem@0 114 #undef uint32
philpem@0 115 #define uint32 unsigned int
philpem@0 116 INLINE sint MAKE_INT_32(uint value)
philpem@0 117 {
philpem@0 118 return (value & 0x80000000) ? value | ~0xffffffff : value & 0xffffffff;
philpem@0 119 }
philpem@0 120 #endif /* ULONG_MAX == 0xffffffff */
philpem@0 121
philpem@0 122
philpem@0 123
philpem@0 124
philpem@0 125 /* ======================================================================== */
philpem@0 126 /* ============================ GENERAL DEFINES =========================== */
philpem@0 127 /* ======================================================================== */
philpem@0 128
philpem@0 129 /* Exception Vectors handled by emulation */
philpem@0 130 #define EXCEPTION_BUS_ERROR 2 /* This one is not emulated! */
philpem@0 131 #define EXCEPTION_ADDRESS_ERROR 3 /* This one is partially emulated (doesn't stack a proper frame yet) */
philpem@0 132 #define EXCEPTION_ILLEGAL_INSTRUCTION 4
philpem@0 133 #define EXCEPTION_ZERO_DIVIDE 5
philpem@0 134 #define EXCEPTION_CHK 6
philpem@0 135 #define EXCEPTION_TRAPV 7
philpem@0 136 #define EXCEPTION_PRIVILEGE_VIOLATION 8
philpem@0 137 #define EXCEPTION_TRACE 9
philpem@0 138 #define EXCEPTION_1010 10
philpem@0 139 #define EXCEPTION_1111 11
philpem@0 140 #define EXCEPTION_FORMAT_ERROR 14
philpem@0 141 #define EXCEPTION_UNINITIALIZED_INTERRUPT 15
philpem@0 142 #define EXCEPTION_SPURIOUS_INTERRUPT 24
philpem@0 143 #define EXCEPTION_INTERRUPT_AUTOVECTOR 24
philpem@0 144 #define EXCEPTION_TRAP_BASE 32
philpem@0 145
philpem@0 146 /* Function codes set by CPU during data/address bus activity */
philpem@0 147 #define FUNCTION_CODE_USER_DATA 1
philpem@0 148 #define FUNCTION_CODE_USER_PROGRAM 2
philpem@0 149 #define FUNCTION_CODE_SUPERVISOR_DATA 5
philpem@0 150 #define FUNCTION_CODE_SUPERVISOR_PROGRAM 6
philpem@0 151 #define FUNCTION_CODE_CPU_SPACE 7
philpem@0 152
philpem@0 153 /* CPU types for deciding what to emulate */
philpem@0 154 #define CPU_TYPE_000 1
philpem@0 155 #define CPU_TYPE_010 2
philpem@0 156 #define CPU_TYPE_EC020 4
philpem@0 157 #define CPU_TYPE_020 8
philpem@0 158
philpem@0 159 /* Different ways to stop the CPU */
philpem@0 160 #define STOP_LEVEL_STOP 1
philpem@0 161 #define STOP_LEVEL_HALT 2
philpem@0 162
philpem@0 163 #ifndef NULL
philpem@0 164 #define NULL ((void*)0)
philpem@0 165 #endif
philpem@0 166
philpem@0 167 /* ======================================================================== */
philpem@0 168 /* ================================ MACROS ================================ */
philpem@0 169 /* ======================================================================== */
philpem@0 170
philpem@0 171
philpem@0 172 /* ---------------------------- General Macros ---------------------------- */
philpem@0 173
philpem@0 174 /* Bit Isolation Macros */
philpem@0 175 #define BIT_0(A) ((A) & 0x00000001)
philpem@0 176 #define BIT_1(A) ((A) & 0x00000002)
philpem@0 177 #define BIT_2(A) ((A) & 0x00000004)
philpem@0 178 #define BIT_3(A) ((A) & 0x00000008)
philpem@0 179 #define BIT_4(A) ((A) & 0x00000010)
philpem@0 180 #define BIT_5(A) ((A) & 0x00000020)
philpem@0 181 #define BIT_6(A) ((A) & 0x00000040)
philpem@0 182 #define BIT_7(A) ((A) & 0x00000080)
philpem@0 183 #define BIT_8(A) ((A) & 0x00000100)
philpem@0 184 #define BIT_9(A) ((A) & 0x00000200)
philpem@0 185 #define BIT_A(A) ((A) & 0x00000400)
philpem@0 186 #define BIT_B(A) ((A) & 0x00000800)
philpem@0 187 #define BIT_C(A) ((A) & 0x00001000)
philpem@0 188 #define BIT_D(A) ((A) & 0x00002000)
philpem@0 189 #define BIT_E(A) ((A) & 0x00004000)
philpem@0 190 #define BIT_F(A) ((A) & 0x00008000)
philpem@0 191 #define BIT_10(A) ((A) & 0x00010000)
philpem@0 192 #define BIT_11(A) ((A) & 0x00020000)
philpem@0 193 #define BIT_12(A) ((A) & 0x00040000)
philpem@0 194 #define BIT_13(A) ((A) & 0x00080000)
philpem@0 195 #define BIT_14(A) ((A) & 0x00100000)
philpem@0 196 #define BIT_15(A) ((A) & 0x00200000)
philpem@0 197 #define BIT_16(A) ((A) & 0x00400000)
philpem@0 198 #define BIT_17(A) ((A) & 0x00800000)
philpem@0 199 #define BIT_18(A) ((A) & 0x01000000)
philpem@0 200 #define BIT_19(A) ((A) & 0x02000000)
philpem@0 201 #define BIT_1A(A) ((A) & 0x04000000)
philpem@0 202 #define BIT_1B(A) ((A) & 0x08000000)
philpem@0 203 #define BIT_1C(A) ((A) & 0x10000000)
philpem@0 204 #define BIT_1D(A) ((A) & 0x20000000)
philpem@0 205 #define BIT_1E(A) ((A) & 0x40000000)
philpem@0 206 #define BIT_1F(A) ((A) & 0x80000000)
philpem@0 207
philpem@0 208 /* Get the most significant bit for specific sizes */
philpem@0 209 #define GET_MSB_8(A) ((A) & 0x80)
philpem@0 210 #define GET_MSB_9(A) ((A) & 0x100)
philpem@0 211 #define GET_MSB_16(A) ((A) & 0x8000)
philpem@0 212 #define GET_MSB_17(A) ((A) & 0x10000)
philpem@0 213 #define GET_MSB_32(A) ((A) & 0x80000000)
philpem@0 214 #if M68K_USE_64_BIT
philpem@0 215 #define GET_MSB_33(A) ((A) & 0x100000000)
philpem@0 216 #endif /* M68K_USE_64_BIT */
philpem@0 217
philpem@0 218 /* Isolate nibbles */
philpem@0 219 #define LOW_NIBBLE(A) ((A) & 0x0f)
philpem@0 220 #define HIGH_NIBBLE(A) ((A) & 0xf0)
philpem@0 221
philpem@0 222 /* These are used to isolate 8, 16, and 32 bit sizes */
philpem@0 223 #define MASK_OUT_ABOVE_2(A) ((A) & 3)
philpem@0 224 #define MASK_OUT_ABOVE_8(A) ((A) & 0xff)
philpem@0 225 #define MASK_OUT_ABOVE_16(A) ((A) & 0xffff)
philpem@0 226 #define MASK_OUT_BELOW_2(A) ((A) & ~3)
philpem@0 227 #define MASK_OUT_BELOW_8(A) ((A) & ~0xff)
philpem@0 228 #define MASK_OUT_BELOW_16(A) ((A) & ~0xffff)
philpem@0 229
philpem@0 230 /* No need to mask if we are 32 bit */
philpem@0 231 #if M68K_INT_GT_32BIT || M68K_USE_64_BIT
philpem@0 232 #define MASK_OUT_ABOVE_32(A) ((A) & 0xffffffff)
philpem@0 233 #define MASK_OUT_BELOW_32(A) ((A) & ~0xffffffff)
philpem@0 234 #else
philpem@0 235 #define MASK_OUT_ABOVE_32(A) (A)
philpem@0 236 #define MASK_OUT_BELOW_32(A) 0
philpem@0 237 #endif /* M68K_INT_GT_32BIT || M68K_USE_64_BIT */
philpem@0 238
philpem@0 239 /* Simulate address lines of 68k family */
philpem@0 240 #define ADDRESS_68K(A) ((A)&CPU_ADDRESS_MASK)
philpem@0 241
philpem@0 242
philpem@0 243 /* Shift & Rotate Macros. */
philpem@0 244 #define LSL(A, C) ((A) << (C))
philpem@0 245 #define LSR(A, C) ((A) >> (C))
philpem@0 246
philpem@0 247 /* Some > 32-bit optimizations */
philpem@0 248 #if M68K_INT_GT_32BIT
philpem@0 249 /* Shift left and right */
philpem@0 250 #define LSR_32(A, C) ((A) >> (C))
philpem@0 251 #define LSL_32(A, C) ((A) << (C))
philpem@0 252 #else
philpem@0 253 /* We have to do this because the morons at ANSI decided that shifts
philpem@0 254 * by >= data size are undefined.
philpem@0 255 */
philpem@0 256 #define LSR_32(A, C) ((C) < 32 ? (A) >> (C) : 0)
philpem@0 257 #define LSL_32(A, C) ((C) < 32 ? (A) << (C) : 0)
philpem@0 258 #endif /* M68K_INT_GT_32BIT */
philpem@0 259
philpem@0 260 #if M68K_USE_64_BIT
philpem@0 261 #define LSL_32_64(A, C) ((A) << (C))
philpem@0 262 #define LSR_32_64(A, C) ((A) >> (C))
philpem@0 263 #define ROL_33_64(A, C) (LSL_32_64(A, C) | LSR_32_64(A, 33-(C)))
philpem@0 264 #define ROR_33_64(A, C) (LSR_32_64(A, C) | LSL_32_64(A, 33-(C)))
philpem@0 265 #endif /* M68K_USE_64_BIT */
philpem@0 266
philpem@0 267 #define ROL_8(A, C) MASK_OUT_ABOVE_8(LSL(A, C) | LSR(A, 8-(C)))
philpem@0 268 #define ROL_9(A, C) (LSL(A, C) | LSR(A, 9-(C)))
philpem@0 269 #define ROL_16(A, C) MASK_OUT_ABOVE_16(LSL(A, C) | LSR(A, 16-(C)))
philpem@0 270 #define ROL_17(A, C) (LSL(A, C) | LSR(A, 17-(C)))
philpem@0 271 #define ROL_32(A, C) MASK_OUT_ABOVE_32(LSL_32(A, C) | LSR_32(A, 32-(C)))
philpem@0 272 #define ROL_33(A, C) (LSL_32(A, C) | LSR_32(A, 33-(C)))
philpem@0 273
philpem@0 274 #define ROR_8(A, C) MASK_OUT_ABOVE_8(LSR(A, C) | LSL(A, 8-(C)))
philpem@0 275 #define ROR_9(A, C) (LSR(A, C) | LSL(A, 9-(C)))
philpem@0 276 #define ROR_16(A, C) MASK_OUT_ABOVE_16(LSR(A, C) | LSL(A, 16-(C)))
philpem@0 277 #define ROR_17(A, C) (LSR(A, C) | LSL(A, 17-(C)))
philpem@0 278 #define ROR_32(A, C) MASK_OUT_ABOVE_32(LSR_32(A, C) | LSL_32(A, 32-(C)))
philpem@0 279 #define ROR_33(A, C) (LSR_32(A, C) | LSL_32(A, 33-(C)))
philpem@0 280
philpem@0 281
philpem@0 282
philpem@0 283 /* ------------------------------ CPU Access ------------------------------ */
philpem@0 284
philpem@0 285 /* Access the CPU registers */
philpem@0 286 #define CPU_TYPE m68ki_cpu.cpu_type
philpem@0 287
philpem@0 288 #define REG_DA m68ki_cpu.dar /* easy access to data and address regs */
andrew@147 289 #define REG_DA_SAVE m68ki_cpu.dar_save
philpem@0 290 #define REG_D m68ki_cpu.dar
philpem@0 291 #define REG_A (m68ki_cpu.dar+8)
philpem@0 292 #define REG_PPC m68ki_cpu.ppc
philpem@0 293 #define REG_PC m68ki_cpu.pc
philpem@0 294 #define REG_SP_BASE m68ki_cpu.sp
philpem@0 295 #define REG_USP m68ki_cpu.sp[0]
philpem@0 296 #define REG_ISP m68ki_cpu.sp[4]
philpem@0 297 #define REG_MSP m68ki_cpu.sp[6]
philpem@0 298 #define REG_SP m68ki_cpu.dar[15]
philpem@0 299 #define REG_VBR m68ki_cpu.vbr
philpem@0 300 #define REG_SFC m68ki_cpu.sfc
philpem@0 301 #define REG_DFC m68ki_cpu.dfc
philpem@0 302 #define REG_CACR m68ki_cpu.cacr
philpem@0 303 #define REG_CAAR m68ki_cpu.caar
philpem@0 304 #define REG_IR m68ki_cpu.ir
philpem@0 305
philpem@0 306 #define FLAG_T1 m68ki_cpu.t1_flag
philpem@0 307 #define FLAG_T0 m68ki_cpu.t0_flag
philpem@0 308 #define FLAG_S m68ki_cpu.s_flag
philpem@0 309 #define FLAG_M m68ki_cpu.m_flag
philpem@0 310 #define FLAG_X m68ki_cpu.x_flag
philpem@0 311 #define FLAG_N m68ki_cpu.n_flag
philpem@0 312 #define FLAG_Z m68ki_cpu.not_z_flag
philpem@0 313 #define FLAG_V m68ki_cpu.v_flag
philpem@0 314 #define FLAG_C m68ki_cpu.c_flag
philpem@0 315 #define FLAG_INT_MASK m68ki_cpu.int_mask
philpem@0 316
philpem@0 317 #define CPU_INT_LEVEL m68ki_cpu.int_level /* ASG: changed from CPU_INTS_PENDING */
philpem@0 318 #define CPU_INT_CYCLES m68ki_cpu.int_cycles /* ASG */
philpem@0 319 #define CPU_STOPPED m68ki_cpu.stopped
philpem@0 320 #define CPU_PREF_ADDR m68ki_cpu.pref_addr
philpem@0 321 #define CPU_PREF_DATA m68ki_cpu.pref_data
philpem@0 322 #define CPU_ADDRESS_MASK m68ki_cpu.address_mask
philpem@0 323 #define CPU_SR_MASK m68ki_cpu.sr_mask
philpem@0 324
philpem@109 325 #define BUS_ERROR_OCCURRED m68ki_cpu.bus_error_occurred
philpem@109 326
philpem@0 327 #define CYC_INSTRUCTION m68ki_cpu.cyc_instruction
philpem@0 328 #define CYC_EXCEPTION m68ki_cpu.cyc_exception
philpem@0 329 #define CYC_BCC_NOTAKE_B m68ki_cpu.cyc_bcc_notake_b
philpem@0 330 #define CYC_BCC_NOTAKE_W m68ki_cpu.cyc_bcc_notake_w
philpem@0 331 #define CYC_DBCC_F_NOEXP m68ki_cpu.cyc_dbcc_f_noexp
philpem@0 332 #define CYC_DBCC_F_EXP m68ki_cpu.cyc_dbcc_f_exp
philpem@0 333 #define CYC_SCC_R_FALSE m68ki_cpu.cyc_scc_r_false
philpem@0 334 #define CYC_MOVEM_W m68ki_cpu.cyc_movem_w
philpem@0 335 #define CYC_MOVEM_L m68ki_cpu.cyc_movem_l
philpem@0 336 #define CYC_SHIFT m68ki_cpu.cyc_shift
philpem@0 337 #define CYC_RESET m68ki_cpu.cyc_reset
philpem@0 338
philpem@0 339
philpem@0 340 #define CALLBACK_INT_ACK m68ki_cpu.int_ack_callback
philpem@0 341 #define CALLBACK_BKPT_ACK m68ki_cpu.bkpt_ack_callback
philpem@0 342 #define CALLBACK_RESET_INSTR m68ki_cpu.reset_instr_callback
philpem@0 343 #define CALLBACK_PC_CHANGED m68ki_cpu.pc_changed_callback
philpem@0 344 #define CALLBACK_SET_FC m68ki_cpu.set_fc_callback
philpem@0 345 #define CALLBACK_INSTR_HOOK m68ki_cpu.instr_hook_callback
philpem@0 346
philpem@0 347
philpem@0 348
philpem@0 349 /* ----------------------------- Configuration ---------------------------- */
philpem@0 350
philpem@0 351 /* These defines are dependant on the configuration defines in m68kconf.h */
philpem@0 352
philpem@0 353 /* Disable certain comparisons if we're not using all CPU types */
philpem@0 354 #if M68K_EMULATE_020
philpem@0 355 #define CPU_TYPE_IS_020_PLUS(A) ((A) & CPU_TYPE_020)
philpem@0 356 #define CPU_TYPE_IS_020_LESS(A) 1
philpem@0 357 #else
philpem@0 358 #define CPU_TYPE_IS_020_PLUS(A) 0
philpem@0 359 #define CPU_TYPE_IS_020_LESS(A) 1
philpem@0 360 #endif
philpem@0 361
philpem@0 362 #if M68K_EMULATE_EC020
philpem@0 363 #define CPU_TYPE_IS_EC020_PLUS(A) ((A) & (CPU_TYPE_EC020 | CPU_TYPE_020))
philpem@0 364 #define CPU_TYPE_IS_EC020_LESS(A) ((A) & (CPU_TYPE_000 | CPU_TYPE_010 | CPU_TYPE_EC020))
philpem@0 365 #else
philpem@0 366 #define CPU_TYPE_IS_EC020_PLUS(A) CPU_TYPE_IS_020_PLUS(A)
philpem@0 367 #define CPU_TYPE_IS_EC020_LESS(A) CPU_TYPE_IS_020_LESS(A)
philpem@0 368 #endif
philpem@0 369
philpem@0 370 #if M68K_EMULATE_010
philpem@0 371 #define CPU_TYPE_IS_010(A) ((A) == CPU_TYPE_010)
philpem@0 372 #define CPU_TYPE_IS_010_PLUS(A) ((A) & (CPU_TYPE_010 | CPU_TYPE_EC020 | CPU_TYPE_020))
philpem@0 373 #define CPU_TYPE_IS_010_LESS(A) ((A) & (CPU_TYPE_000 | CPU_TYPE_010))
philpem@0 374 #else
philpem@0 375 #define CPU_TYPE_IS_010(A) 0
philpem@0 376 #define CPU_TYPE_IS_010_PLUS(A) CPU_TYPE_IS_EC020_PLUS(A)
philpem@0 377 #define CPU_TYPE_IS_010_LESS(A) CPU_TYPE_IS_EC020_LESS(A)
philpem@0 378 #endif
philpem@0 379
philpem@0 380 #if M68K_EMULATE_020 || M68K_EMULATE_EC020
philpem@0 381 #define CPU_TYPE_IS_020_VARIANT(A) ((A) & (CPU_TYPE_EC020 | CPU_TYPE_020))
philpem@0 382 #else
philpem@0 383 #define CPU_TYPE_IS_020_VARIANT(A) 0
philpem@0 384 #endif
philpem@0 385
philpem@0 386 #if M68K_EMULATE_020 || M68K_EMULATE_EC020 || M68K_EMULATE_010
philpem@0 387 #define CPU_TYPE_IS_000(A) ((A) == CPU_TYPE_000)
philpem@0 388 #else
philpem@0 389 #define CPU_TYPE_IS_000(A) 1
philpem@0 390 #endif
philpem@0 391
philpem@0 392
philpem@0 393 #if !M68K_SEPARATE_READS
philpem@0 394 #define m68k_read_immediate_16(A) m68ki_read_program_16(A)
philpem@0 395 #define m68k_read_immediate_32(A) m68ki_read_program_32(A)
philpem@0 396
philpem@0 397 #define m68k_read_pcrelative_8(A) m68ki_read_program_8(A)
philpem@0 398 #define m68k_read_pcrelative_16(A) m68ki_read_program_16(A)
philpem@0 399 #define m68k_read_pcrelative_32(A) m68ki_read_program_32(A)
philpem@0 400 #endif /* M68K_SEPARATE_READS */
philpem@0 401
philpem@0 402
philpem@0 403 /* Enable or disable callback functions */
philpem@0 404 #if M68K_EMULATE_INT_ACK
philpem@0 405 #if M68K_EMULATE_INT_ACK == OPT_SPECIFY_HANDLER
philpem@0 406 #define m68ki_int_ack(A) M68K_INT_ACK_CALLBACK(A)
philpem@0 407 #else
philpem@0 408 #define m68ki_int_ack(A) CALLBACK_INT_ACK(A)
philpem@0 409 #endif
philpem@0 410 #else
philpem@0 411 /* Default action is to used autovector mode, which is most common */
philpem@0 412 #define m68ki_int_ack(A) M68K_INT_ACK_AUTOVECTOR
philpem@0 413 #endif /* M68K_EMULATE_INT_ACK */
philpem@0 414
philpem@0 415 #if M68K_EMULATE_BKPT_ACK
philpem@0 416 #if M68K_EMULATE_BKPT_ACK == OPT_SPECIFY_HANDLER
philpem@0 417 #define m68ki_bkpt_ack(A) M68K_BKPT_ACK_CALLBACK(A)
philpem@0 418 #else
philpem@0 419 #define m68ki_bkpt_ack(A) CALLBACK_BKPT_ACK(A)
philpem@0 420 #endif
philpem@0 421 #else
philpem@0 422 #define m68ki_bkpt_ack(A)
philpem@0 423 #endif /* M68K_EMULATE_BKPT_ACK */
philpem@0 424
philpem@0 425 #if M68K_EMULATE_RESET
philpem@0 426 #if M68K_EMULATE_RESET == OPT_SPECIFY_HANDLER
philpem@0 427 #define m68ki_output_reset() M68K_RESET_CALLBACK()
philpem@0 428 #else
philpem@0 429 #define m68ki_output_reset() CALLBACK_RESET_INSTR()
philpem@0 430 #endif
philpem@0 431 #else
philpem@0 432 #define m68ki_output_reset()
philpem@0 433 #endif /* M68K_EMULATE_RESET */
philpem@0 434
philpem@0 435 #if M68K_INSTRUCTION_HOOK
philpem@0 436 #if M68K_INSTRUCTION_HOOK == OPT_SPECIFY_HANDLER
philpem@0 437 #define m68ki_instr_hook() M68K_INSTRUCTION_CALLBACK()
philpem@0 438 #else
philpem@0 439 #define m68ki_instr_hook() CALLBACK_INSTR_HOOK()
philpem@0 440 #endif
philpem@0 441 #else
philpem@0 442 #define m68ki_instr_hook()
philpem@0 443 #endif /* M68K_INSTRUCTION_HOOK */
philpem@0 444
philpem@0 445 #if M68K_MONITOR_PC
philpem@0 446 #if M68K_MONITOR_PC == OPT_SPECIFY_HANDLER
philpem@0 447 #define m68ki_pc_changed(A) M68K_SET_PC_CALLBACK(ADDRESS_68K(A))
philpem@0 448 #else
philpem@0 449 #define m68ki_pc_changed(A) CALLBACK_PC_CHANGED(ADDRESS_68K(A))
philpem@0 450 #endif
philpem@0 451 #else
philpem@0 452 #define m68ki_pc_changed(A)
philpem@0 453 #endif /* M68K_MONITOR_PC */
philpem@0 454
philpem@0 455
philpem@0 456 /* Enable or disable function code emulation */
philpem@0 457 #if M68K_EMULATE_FC
philpem@0 458 #if M68K_EMULATE_FC == OPT_SPECIFY_HANDLER
philpem@0 459 #define m68ki_set_fc(A) M68K_SET_FC_CALLBACK(A)
philpem@0 460 #else
philpem@0 461 #define m68ki_set_fc(A) CALLBACK_SET_FC(A)
philpem@0 462 #endif
philpem@0 463 #define m68ki_use_data_space() m68ki_address_space = FUNCTION_CODE_USER_DATA
philpem@0 464 #define m68ki_use_program_space() m68ki_address_space = FUNCTION_CODE_USER_PROGRAM
philpem@0 465 #define m68ki_get_address_space() m68ki_address_space
philpem@0 466 #else
philpem@0 467 #define m68ki_set_fc(A)
philpem@0 468 #define m68ki_use_data_space()
philpem@0 469 #define m68ki_use_program_space()
philpem@0 470 #define m68ki_get_address_space() FUNCTION_CODE_USER_DATA
philpem@0 471 #endif /* M68K_EMULATE_FC */
philpem@0 472
philpem@0 473
philpem@0 474 /* Enable or disable trace emulation */
philpem@0 475 #if M68K_EMULATE_TRACE
philpem@0 476 /* Initiates trace checking before each instruction (t1) */
philpem@0 477 #define m68ki_trace_t1() m68ki_tracing = FLAG_T1
philpem@0 478 /* adds t0 to trace checking if we encounter change of flow */
philpem@0 479 #define m68ki_trace_t0() m68ki_tracing |= FLAG_T0
philpem@0 480 /* Clear all tracing */
philpem@0 481 #define m68ki_clear_trace() m68ki_tracing = 0
philpem@0 482 /* Cause a trace exception if we are tracing */
philpem@0 483 #define m68ki_exception_if_trace() if(m68ki_tracing) m68ki_exception_trace()
philpem@0 484 #else
philpem@0 485 #define m68ki_trace_t1()
philpem@0 486 #define m68ki_trace_t0()
philpem@0 487 #define m68ki_clear_trace()
philpem@0 488 #define m68ki_exception_if_trace()
philpem@0 489 #endif /* M68K_EMULATE_TRACE */
philpem@0 490
philpem@0 491
philpem@0 492
philpem@0 493 /* Address error */
philpem@0 494 #if M68K_EMULATE_ADDRESS_ERROR
philpem@0 495 extern jmp_buf m68ki_address_error_trap;
philpem@0 496 #define m68ki_set_address_error_trap() if(setjmp(m68ki_address_error_trap)) m68ki_exception_address_error();
philpem@0 497 #define m68ki_check_address_error(A) if((A)&1) longjmp(m68ki_address_error_jump, 1);
philpem@0 498 #else
philpem@0 499 #define m68ki_set_address_error_trap()
philpem@0 500 #define m68ki_check_address_error(A)
philpem@0 501 #endif /* M68K_ADDRESS_ERROR */
philpem@0 502
philpem@0 503 /* Logging */
philpem@0 504 #if M68K_LOG_ENABLE
philpem@0 505 #include <stdio.h>
philpem@0 506 extern FILE* M68K_LOG_FILEHANDLE
philpem@0 507 extern char* m68ki_cpu_names[];
philpem@0 508
philpem@0 509 #define M68K_DO_LOG(A) if(M68K_LOG_FILEHANDLE) fprintf A
philpem@0 510 #if M68K_LOG_1010_1111
philpem@0 511 #define M68K_DO_LOG_EMU(A) if(M68K_LOG_FILEHANDLE) fprintf A
philpem@0 512 #else
philpem@0 513 #define M68K_DO_LOG_EMU(A)
philpem@0 514 #endif
philpem@0 515 #else
philpem@0 516 #define M68K_DO_LOG(A)
philpem@0 517 #define M68K_DO_LOG_EMU(A)
philpem@0 518 #endif
philpem@0 519
philpem@0 520
philpem@0 521
philpem@0 522 /* -------------------------- EA / Operand Access ------------------------- */
philpem@0 523
philpem@0 524 /*
philpem@0 525 * The general instruction format follows this pattern:
philpem@0 526 * .... XXX. .... .YYY
philpem@0 527 * where XXX is register X and YYY is register Y
philpem@0 528 */
philpem@0 529 /* Data Register Isolation */
philpem@0 530 #define DX (REG_D[(REG_IR >> 9) & 7])
philpem@0 531 #define DY (REG_D[REG_IR & 7])
philpem@0 532 /* Address Register Isolation */
philpem@0 533 #define AX (REG_A[(REG_IR >> 9) & 7])
philpem@0 534 #define AY (REG_A[REG_IR & 7])
philpem@0 535
philpem@0 536
philpem@0 537 /* Effective Address Calculations */
philpem@0 538 #define EA_AY_AI_8() AY /* address register indirect */
philpem@0 539 #define EA_AY_AI_16() EA_AY_AI_8()
philpem@0 540 #define EA_AY_AI_32() EA_AY_AI_8()
philpem@0 541 #define EA_AY_PI_8() (AY++) /* postincrement (size = byte) */
philpem@0 542 #define EA_AY_PI_16() ((AY+=2)-2) /* postincrement (size = word) */
philpem@0 543 #define EA_AY_PI_32() ((AY+=4)-4) /* postincrement (size = long) */
philpem@0 544 #define EA_AY_PD_8() (--AY) /* predecrement (size = byte) */
philpem@0 545 #define EA_AY_PD_16() (AY-=2) /* predecrement (size = word) */
philpem@0 546 #define EA_AY_PD_32() (AY-=4) /* predecrement (size = long) */
philpem@0 547 #define EA_AY_DI_8() (AY+MAKE_INT_16(m68ki_read_imm_16())) /* displacement */
philpem@0 548 #define EA_AY_DI_16() EA_AY_DI_8()
philpem@0 549 #define EA_AY_DI_32() EA_AY_DI_8()
philpem@0 550 #define EA_AY_IX_8() m68ki_get_ea_ix(AY) /* indirect + index */
philpem@0 551 #define EA_AY_IX_16() EA_AY_IX_8()
philpem@0 552 #define EA_AY_IX_32() EA_AY_IX_8()
philpem@0 553
philpem@0 554 #define EA_AX_AI_8() AX
philpem@0 555 #define EA_AX_AI_16() EA_AX_AI_8()
philpem@0 556 #define EA_AX_AI_32() EA_AX_AI_8()
philpem@0 557 #define EA_AX_PI_8() (AX++)
philpem@0 558 #define EA_AX_PI_16() ((AX+=2)-2)
philpem@0 559 #define EA_AX_PI_32() ((AX+=4)-4)
philpem@0 560 #define EA_AX_PD_8() (--AX)
philpem@0 561 #define EA_AX_PD_16() (AX-=2)
philpem@0 562 #define EA_AX_PD_32() (AX-=4)
philpem@0 563 #define EA_AX_DI_8() (AX+MAKE_INT_16(m68ki_read_imm_16()))
philpem@0 564 #define EA_AX_DI_16() EA_AX_DI_8()
philpem@0 565 #define EA_AX_DI_32() EA_AX_DI_8()
philpem@0 566 #define EA_AX_IX_8() m68ki_get_ea_ix(AX)
philpem@0 567 #define EA_AX_IX_16() EA_AX_IX_8()
philpem@0 568 #define EA_AX_IX_32() EA_AX_IX_8()
philpem@0 569
philpem@0 570 #define EA_A7_PI_8() ((REG_A[7]+=2)-2)
philpem@0 571 #define EA_A7_PD_8() (REG_A[7]-=2)
philpem@0 572
philpem@0 573 #define EA_AW_8() MAKE_INT_16(m68ki_read_imm_16()) /* absolute word */
philpem@0 574 #define EA_AW_16() EA_AW_8()
philpem@0 575 #define EA_AW_32() EA_AW_8()
philpem@0 576 #define EA_AL_8() m68ki_read_imm_32() /* absolute long */
philpem@0 577 #define EA_AL_16() EA_AL_8()
philpem@0 578 #define EA_AL_32() EA_AL_8()
philpem@0 579 #define EA_PCDI_8() m68ki_get_ea_pcdi() /* pc indirect + displacement */
philpem@0 580 #define EA_PCDI_16() EA_PCDI_8()
philpem@0 581 #define EA_PCDI_32() EA_PCDI_8()
philpem@0 582 #define EA_PCIX_8() m68ki_get_ea_pcix() /* pc indirect + index */
philpem@0 583 #define EA_PCIX_16() EA_PCIX_8()
philpem@0 584 #define EA_PCIX_32() EA_PCIX_8()
philpem@0 585
philpem@0 586
philpem@0 587 #define OPER_I_8() m68ki_read_imm_8()
philpem@0 588 #define OPER_I_16() m68ki_read_imm_16()
philpem@0 589 #define OPER_I_32() m68ki_read_imm_32()
philpem@0 590
philpem@0 591
philpem@0 592
philpem@0 593 /* --------------------------- Status Register ---------------------------- */
philpem@0 594
philpem@0 595 /* Flag Calculation Macros */
philpem@0 596 #define CFLAG_8(A) (A)
philpem@0 597 #define CFLAG_16(A) ((A)>>8)
philpem@0 598
philpem@0 599 #if M68K_INT_GT_32_BIT
philpem@0 600 #define CFLAG_ADD_32(S, D, R) ((R)>>24)
philpem@0 601 #define CFLAG_SUB_32(S, D, R) ((R)>>24)
philpem@0 602 #else
philpem@0 603 #define CFLAG_ADD_32(S, D, R) (((S & D) | (~R & (S | D)))>>23)
philpem@0 604 #define CFLAG_SUB_32(S, D, R) (((S & R) | (~D & (S | R)))>>23)
philpem@0 605 #endif /* M68K_INT_GT_32_BIT */
philpem@0 606
philpem@0 607 #define VFLAG_ADD_8(S, D, R) ((S^R) & (D^R))
philpem@0 608 #define VFLAG_ADD_16(S, D, R) (((S^R) & (D^R))>>8)
philpem@0 609 #define VFLAG_ADD_32(S, D, R) (((S^R) & (D^R))>>24)
philpem@0 610
philpem@0 611 #define VFLAG_SUB_8(S, D, R) ((S^D) & (R^D))
philpem@0 612 #define VFLAG_SUB_16(S, D, R) (((S^D) & (R^D))>>8)
philpem@0 613 #define VFLAG_SUB_32(S, D, R) (((S^D) & (R^D))>>24)
philpem@0 614
philpem@0 615 #define NFLAG_8(A) (A)
philpem@0 616 #define NFLAG_16(A) ((A)>>8)
philpem@0 617 #define NFLAG_32(A) ((A)>>24)
philpem@0 618 #define NFLAG_64(A) ((A)>>56)
philpem@0 619
philpem@0 620 #define ZFLAG_8(A) MASK_OUT_ABOVE_8(A)
philpem@0 621 #define ZFLAG_16(A) MASK_OUT_ABOVE_16(A)
philpem@0 622 #define ZFLAG_32(A) MASK_OUT_ABOVE_32(A)
philpem@0 623
philpem@0 624
philpem@0 625 /* Flag values */
philpem@0 626 #define NFLAG_SET 0x80
philpem@0 627 #define NFLAG_CLEAR 0
philpem@0 628 #define CFLAG_SET 0x100
philpem@0 629 #define CFLAG_CLEAR 0
philpem@0 630 #define XFLAG_SET 0x100
philpem@0 631 #define XFLAG_CLEAR 0
philpem@0 632 #define VFLAG_SET 0x80
philpem@0 633 #define VFLAG_CLEAR 0
philpem@0 634 #define ZFLAG_SET 0
philpem@0 635 #define ZFLAG_CLEAR 0xffffffff
philpem@0 636
philpem@0 637 #define SFLAG_SET 4
philpem@0 638 #define SFLAG_CLEAR 0
philpem@0 639 #define MFLAG_SET 2
philpem@0 640 #define MFLAG_CLEAR 0
philpem@0 641
philpem@0 642 /* Turn flag values into 1 or 0 */
philpem@0 643 #define XFLAG_AS_1() ((FLAG_X>>8)&1)
philpem@0 644 #define NFLAG_AS_1() ((FLAG_N>>7)&1)
philpem@0 645 #define VFLAG_AS_1() ((FLAG_V>>7)&1)
philpem@0 646 #define ZFLAG_AS_1() (!FLAG_Z)
philpem@0 647 #define CFLAG_AS_1() ((FLAG_C>>8)&1)
philpem@0 648
philpem@0 649
philpem@0 650 /* Conditions */
philpem@0 651 #define COND_CS() (FLAG_C&0x100)
philpem@0 652 #define COND_CC() (!COND_CS())
philpem@0 653 #define COND_VS() (FLAG_V&0x80)
philpem@0 654 #define COND_VC() (!COND_VS())
philpem@0 655 #define COND_NE() FLAG_Z
philpem@0 656 #define COND_EQ() (!COND_NE())
philpem@0 657 #define COND_MI() (FLAG_N&0x80)
philpem@0 658 #define COND_PL() (!COND_MI())
philpem@0 659 #define COND_LT() ((FLAG_N^FLAG_V)&0x80)
philpem@0 660 #define COND_GE() (!COND_LT())
philpem@0 661 #define COND_HI() (COND_CC() && COND_NE())
philpem@0 662 #define COND_LS() (COND_CS() || COND_EQ())
philpem@0 663 #define COND_GT() (COND_GE() && COND_NE())
philpem@0 664 #define COND_LE() (COND_LT() || COND_EQ())
philpem@0 665
philpem@0 666 /* Reversed conditions */
philpem@0 667 #define COND_NOT_CS() COND_CC()
philpem@0 668 #define COND_NOT_CC() COND_CS()
philpem@0 669 #define COND_NOT_VS() COND_VC()
philpem@0 670 #define COND_NOT_VC() COND_VS()
philpem@0 671 #define COND_NOT_NE() COND_EQ()
philpem@0 672 #define COND_NOT_EQ() COND_NE()
philpem@0 673 #define COND_NOT_MI() COND_PL()
philpem@0 674 #define COND_NOT_PL() COND_MI()
philpem@0 675 #define COND_NOT_LT() COND_GE()
philpem@0 676 #define COND_NOT_GE() COND_LT()
philpem@0 677 #define COND_NOT_HI() COND_LS()
philpem@0 678 #define COND_NOT_LS() COND_HI()
philpem@0 679 #define COND_NOT_GT() COND_LE()
philpem@0 680 #define COND_NOT_LE() COND_GT()
philpem@0 681
philpem@0 682 /* Not real conditions, but here for convenience */
philpem@0 683 #define COND_XS() (FLAG_X&0x100)
philpem@0 684 #define COND_XC() (!COND_XS)
philpem@0 685
philpem@0 686
philpem@0 687 /* Get the condition code register */
philpem@0 688 #define m68ki_get_ccr() ((COND_XS() >> 4) | \
philpem@0 689 (COND_MI() >> 4) | \
philpem@0 690 (COND_EQ() << 2) | \
philpem@0 691 (COND_VS() >> 6) | \
philpem@0 692 (COND_CS() >> 8))
philpem@0 693
philpem@0 694 /* Get the status register */
philpem@0 695 #define m68ki_get_sr() ( FLAG_T1 | \
philpem@0 696 FLAG_T0 | \
philpem@0 697 (FLAG_S << 11) | \
philpem@0 698 (FLAG_M << 11) | \
philpem@0 699 FLAG_INT_MASK | \
philpem@0 700 m68ki_get_ccr())
philpem@0 701
philpem@0 702
philpem@0 703
philpem@0 704 /* ---------------------------- Cycle Counting ---------------------------- */
philpem@0 705
philpem@0 706 #define ADD_CYCLES(A) m68ki_remaining_cycles += (A)
philpem@0 707 #define USE_CYCLES(A) m68ki_remaining_cycles -= (A)
philpem@0 708 #define SET_CYCLES(A) m68ki_remaining_cycles = A
philpem@0 709 #define GET_CYCLES() m68ki_remaining_cycles
philpem@0 710 #define USE_ALL_CYCLES() m68ki_remaining_cycles = 0
philpem@0 711
philpem@0 712
philpem@0 713
philpem@0 714 /* ----------------------------- Read / Write ----------------------------- */
philpem@0 715
philpem@0 716 /* Read from the current address space */
philpem@0 717 #define m68ki_read_8(A) m68ki_read_8_fc (A, FLAG_S | m68ki_get_address_space())
philpem@0 718 #define m68ki_read_16(A) m68ki_read_16_fc(A, FLAG_S | m68ki_get_address_space())
philpem@0 719 #define m68ki_read_32(A) m68ki_read_32_fc(A, FLAG_S | m68ki_get_address_space())
philpem@0 720
philpem@0 721 /* Write to the current data space */
philpem@0 722 #define m68ki_write_8(A, V) m68ki_write_8_fc (A, FLAG_S | FUNCTION_CODE_USER_DATA, V)
philpem@0 723 #define m68ki_write_16(A, V) m68ki_write_16_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA, V)
philpem@0 724 #define m68ki_write_32(A, V) m68ki_write_32_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA, V)
philpem@0 725
philpem@0 726 /* map read immediate 8 to read immediate 16 */
philpem@0 727 #define m68ki_read_imm_8() MASK_OUT_ABOVE_8(m68ki_read_imm_16())
philpem@0 728
philpem@0 729 /* Map PC-relative reads */
philpem@0 730 #define m68ki_read_pcrel_8(A) m68k_read_pcrelative_8(A)
philpem@0 731 #define m68ki_read_pcrel_16(A) m68k_read_pcrelative_16(A)
philpem@0 732 #define m68ki_read_pcrel_32(A) m68k_read_pcrelative_32(A)
philpem@0 733
philpem@0 734 /* Read from the program space */
philpem@0 735 #define m68ki_read_program_8(A) m68ki_read_8_fc(A, FLAG_S | FUNCTION_CODE_USER_PROGRAM)
philpem@0 736 #define m68ki_read_program_16(A) m68ki_read_16_fc(A, FLAG_S | FUNCTION_CODE_USER_PROGRAM)
philpem@0 737 #define m68ki_read_program_32(A) m68ki_read_32_fc(A, FLAG_S | FUNCTION_CODE_USER_PROGRAM)
philpem@0 738
philpem@0 739 /* Read from the data space */
philpem@0 740 #define m68ki_read_data_8(A) m68ki_read_8_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA)
philpem@0 741 #define m68ki_read_data_16(A) m68ki_read_16_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA)
philpem@0 742 #define m68ki_read_data_32(A) m68ki_read_32_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA)
philpem@0 743
philpem@0 744
philpem@0 745
philpem@0 746 /* ======================================================================== */
philpem@0 747 /* =============================== PROTOTYPES ============================= */
philpem@0 748 /* ======================================================================== */
philpem@0 749
philpem@0 750 typedef struct
philpem@0 751 {
philpem@0 752 uint cpu_type; /* CPU Type: 68000, 68010, 68EC020, or 68020 */
philpem@0 753 uint dar[16]; /* Data and Address Registers */
andrew@147 754 uint dar_save[16]; /* Saved Data and Address Registers (pushed onto the
andrew@147 755 stack when a bus error occurs)*/
philpem@0 756 uint ppc; /* Previous program counter */
philpem@0 757 uint pc; /* Program Counter */
philpem@0 758 uint sp[7]; /* User, Interrupt, and Master Stack Pointers */
philpem@0 759 uint vbr; /* Vector Base Register (m68010+) */
philpem@0 760 uint sfc; /* Source Function Code Register (m68010+) */
philpem@0 761 uint dfc; /* Destination Function Code Register (m68010+) */
philpem@0 762 uint cacr; /* Cache Control Register (m68020, unemulated) */
philpem@0 763 uint caar; /* Cache Address Register (m68020, unemulated) */
philpem@0 764 uint ir; /* Instruction Register */
philpem@0 765 uint t1_flag; /* Trace 1 */
philpem@0 766 uint t0_flag; /* Trace 0 */
philpem@0 767 uint s_flag; /* Supervisor */
philpem@0 768 uint m_flag; /* Master/Interrupt state */
philpem@0 769 uint x_flag; /* Extend */
philpem@0 770 uint n_flag; /* Negative */
philpem@0 771 uint not_z_flag; /* Zero, inverted for speedups */
philpem@0 772 uint v_flag; /* Overflow */
philpem@0 773 uint c_flag; /* Carry */
philpem@0 774 uint int_mask; /* I0-I2 */
philpem@0 775 uint int_level; /* State of interrupt pins IPL0-IPL2 -- ASG: changed from ints_pending */
philpem@0 776 uint int_cycles; /* ASG: extra cycles from generated interrupts */
philpem@0 777 uint stopped; /* Stopped state */
philpem@0 778 uint pref_addr; /* Last prefetch address */
philpem@0 779 uint pref_data; /* Data in the prefetch queue */
philpem@0 780 uint address_mask; /* Available address pins */
philpem@0 781 uint sr_mask; /* Implemented status register bits */
philpem@0 782
philpem@109 783 uint bus_error_occurred;
philpem@109 784
philpem@0 785 /* Clocks required for instructions / exceptions */
philpem@0 786 uint cyc_bcc_notake_b;
philpem@0 787 uint cyc_bcc_notake_w;
philpem@0 788 uint cyc_dbcc_f_noexp;
philpem@0 789 uint cyc_dbcc_f_exp;
philpem@0 790 uint cyc_scc_r_false;
philpem@0 791 uint cyc_movem_w;
philpem@0 792 uint cyc_movem_l;
philpem@0 793 uint cyc_shift;
philpem@0 794 uint cyc_reset;
philpem@0 795 uint8* cyc_instruction;
philpem@0 796 uint8* cyc_exception;
philpem@0 797
philpem@0 798 /* Callbacks to host */
philpem@0 799 int (*int_ack_callback)(int int_line); /* Interrupt Acknowledge */
philpem@0 800 void (*bkpt_ack_callback)(unsigned int data); /* Breakpoint Acknowledge */
philpem@0 801 void (*reset_instr_callback)(void); /* Called when a RESET instruction is encountered */
philpem@0 802 void (*pc_changed_callback)(unsigned int new_pc); /* Called when the PC changes by a large amount */
philpem@0 803 void (*set_fc_callback)(unsigned int new_fc); /* Called when the CPU function code changes */
philpem@0 804 void (*instr_hook_callback)(void); /* Called every instruction cycle prior to execution */
philpem@0 805
philpem@0 806 } m68ki_cpu_core;
philpem@0 807
philpem@0 808
philpem@0 809 extern m68ki_cpu_core m68ki_cpu;
philpem@0 810 extern sint m68ki_remaining_cycles;
philpem@0 811 extern uint m68ki_tracing;
philpem@0 812 extern uint8 m68ki_shift_8_table[];
philpem@0 813 extern uint16 m68ki_shift_16_table[];
philpem@0 814 extern uint m68ki_shift_32_table[];
philpem@0 815 extern uint8 m68ki_exception_cycle_table[][256];
philpem@0 816 extern uint m68ki_address_space;
philpem@0 817 extern uint8 m68ki_ea_idx_cycle_table[];
philpem@0 818
philpem@0 819
philpem@0 820 /* Read data immediately after the program counter */
philpem@0 821 INLINE uint m68ki_read_imm_16(void);
philpem@0 822 INLINE uint m68ki_read_imm_32(void);
philpem@0 823
philpem@0 824 /* Read data with specific function code */
philpem@0 825 INLINE uint m68ki_read_8_fc (uint address, uint fc);
philpem@0 826 INLINE uint m68ki_read_16_fc (uint address, uint fc);
philpem@0 827 INLINE uint m68ki_read_32_fc (uint address, uint fc);
philpem@0 828
philpem@0 829 /* Write data with specific function code */
philpem@0 830 INLINE void m68ki_write_8_fc (uint address, uint fc, uint value);
philpem@0 831 INLINE void m68ki_write_16_fc(uint address, uint fc, uint value);
philpem@0 832 INLINE void m68ki_write_32_fc(uint address, uint fc, uint value);
philpem@0 833
philpem@0 834 /* Indexed and PC-relative ea fetching */
philpem@0 835 INLINE uint m68ki_get_ea_pcdi(void);
philpem@0 836 INLINE uint m68ki_get_ea_pcix(void);
philpem@0 837 INLINE uint m68ki_get_ea_ix(uint An);
philpem@0 838
philpem@0 839 /* Operand fetching */
philpem@0 840 INLINE uint OPER_AY_AI_8(void);
philpem@0 841 INLINE uint OPER_AY_AI_16(void);
philpem@0 842 INLINE uint OPER_AY_AI_32(void);
philpem@0 843 INLINE uint OPER_AY_PI_8(void);
philpem@0 844 INLINE uint OPER_AY_PI_16(void);
philpem@0 845 INLINE uint OPER_AY_PI_32(void);
philpem@0 846 INLINE uint OPER_AY_PD_8(void);
philpem@0 847 INLINE uint OPER_AY_PD_16(void);
philpem@0 848 INLINE uint OPER_AY_PD_32(void);
philpem@0 849 INLINE uint OPER_AY_DI_8(void);
philpem@0 850 INLINE uint OPER_AY_DI_16(void);
philpem@0 851 INLINE uint OPER_AY_DI_32(void);
philpem@0 852 INLINE uint OPER_AY_IX_8(void);
philpem@0 853 INLINE uint OPER_AY_IX_16(void);
philpem@0 854 INLINE uint OPER_AY_IX_32(void);
philpem@0 855
philpem@0 856 INLINE uint OPER_AX_AI_8(void);
philpem@0 857 INLINE uint OPER_AX_AI_16(void);
philpem@0 858 INLINE uint OPER_AX_AI_32(void);
philpem@0 859 INLINE uint OPER_AX_PI_8(void);
philpem@0 860 INLINE uint OPER_AX_PI_16(void);
philpem@0 861 INLINE uint OPER_AX_PI_32(void);
philpem@0 862 INLINE uint OPER_AX_PD_8(void);
philpem@0 863 INLINE uint OPER_AX_PD_16(void);
philpem@0 864 INLINE uint OPER_AX_PD_32(void);
philpem@0 865 INLINE uint OPER_AX_DI_8(void);
philpem@0 866 INLINE uint OPER_AX_DI_16(void);
philpem@0 867 INLINE uint OPER_AX_DI_32(void);
philpem@0 868 INLINE uint OPER_AX_IX_8(void);
philpem@0 869 INLINE uint OPER_AX_IX_16(void);
philpem@0 870 INLINE uint OPER_AX_IX_32(void);
philpem@0 871
philpem@0 872 INLINE uint OPER_A7_PI_8(void);
philpem@0 873 INLINE uint OPER_A7_PD_8(void);
philpem@0 874
philpem@0 875 INLINE uint OPER_AW_8(void);
philpem@0 876 INLINE uint OPER_AW_16(void);
philpem@0 877 INLINE uint OPER_AW_32(void);
philpem@0 878 INLINE uint OPER_AL_8(void);
philpem@0 879 INLINE uint OPER_AL_16(void);
philpem@0 880 INLINE uint OPER_AL_32(void);
philpem@0 881 INLINE uint OPER_PCDI_8(void);
philpem@0 882 INLINE uint OPER_PCDI_16(void);
philpem@0 883 INLINE uint OPER_PCDI_32(void);
philpem@0 884 INLINE uint OPER_PCIX_8(void);
philpem@0 885 INLINE uint OPER_PCIX_16(void);
philpem@0 886 INLINE uint OPER_PCIX_32(void);
philpem@0 887
philpem@0 888 /* Stack operations */
philpem@0 889 INLINE void m68ki_push_16(uint value);
philpem@0 890 INLINE void m68ki_push_32(uint value);
philpem@0 891 INLINE uint m68ki_pull_16(void);
philpem@0 892 INLINE uint m68ki_pull_32(void);
philpem@0 893
philpem@0 894 /* Program flow operations */
philpem@0 895 INLINE void m68ki_jump(uint new_pc);
philpem@0 896 INLINE void m68ki_jump_vector(uint vector);
philpem@0 897 INLINE void m68ki_branch_8(uint offset);
philpem@0 898 INLINE void m68ki_branch_16(uint offset);
philpem@0 899 INLINE void m68ki_branch_32(uint offset);
philpem@0 900
philpem@0 901 /* Status register operations. */
philpem@0 902 INLINE void m68ki_set_s_flag(uint value); /* Only bit 2 of value should be set (i.e. 4 or 0) */
philpem@0 903 INLINE void m68ki_set_sm_flag(uint value); /* only bits 1 and 2 of value should be set */
philpem@0 904 INLINE void m68ki_set_ccr(uint value); /* set the condition code register */
philpem@0 905 INLINE void m68ki_set_sr(uint value); /* set the status register */
philpem@0 906 INLINE void m68ki_set_sr_noint(uint value); /* set the status register */
philpem@0 907
philpem@0 908 /* Exception processing */
philpem@0 909 INLINE uint m68ki_init_exception(void); /* Initial exception processing */
philpem@0 910
philpem@0 911 INLINE void m68ki_stack_frame_3word(uint pc, uint sr); /* Stack various frame types */
philpem@0 912 INLINE void m68ki_stack_frame_buserr(uint pc, uint sr, uint address, uint write, uint instruction, uint fc);
philpem@0 913
philpem@0 914 INLINE void m68ki_stack_frame_0000(uint pc, uint sr, uint vector);
philpem@0 915 INLINE void m68ki_stack_frame_0001(uint pc, uint sr, uint vector);
philpem@0 916 INLINE void m68ki_stack_frame_0010(uint sr, uint vector);
philpem@0 917 INLINE void m68ki_stack_frame_1000(uint pc, uint sr, uint vector);
philpem@0 918 INLINE void m68ki_stack_frame_1010(uint sr, uint vector, uint pc);
philpem@0 919 INLINE void m68ki_stack_frame_1011(uint sr, uint vector, uint pc);
philpem@0 920
philpem@0 921 INLINE void m68ki_exception_trap(uint vector);
philpem@0 922 INLINE void m68ki_exception_trapN(uint vector);
philpem@0 923 INLINE void m68ki_exception_trace(void);
philpem@0 924 INLINE void m68ki_exception_privilege_violation(void);
philpem@19 925 INLINE void m68ki_exception_bus_error(void);
philpem@0 926 INLINE void m68ki_exception_1010(void);
philpem@0 927 INLINE void m68ki_exception_1111(void);
philpem@0 928 INLINE void m68ki_exception_illegal(void);
philpem@0 929 INLINE void m68ki_exception_format_error(void);
philpem@0 930 INLINE void m68ki_exception_address_error(void);
philpem@0 931 INLINE void m68ki_exception_interrupt(uint int_level);
philpem@0 932 INLINE void m68ki_check_interrupts(void); /* ASG: check for interrupts */
philpem@0 933
philpem@0 934 /* quick disassembly (used for logging) */
philpem@0 935 char* m68ki_disassemble_quick(unsigned int pc, unsigned int cpu_type);
philpem@0 936
philpem@0 937
philpem@0 938 /* ======================================================================== */
philpem@0 939 /* =========================== UTILITY FUNCTIONS ========================== */
philpem@0 940 /* ======================================================================== */
philpem@0 941
philpem@0 942
philpem@0 943 /* ---------------------------- Read Immediate ---------------------------- */
philpem@0 944
philpem@0 945 /* Handles all immediate reads, does address error check, function code setting,
philpem@0 946 * and prefetching if they are enabled in m68kconf.h
philpem@0 947 */
philpem@0 948 INLINE uint m68ki_read_imm_16(void)
philpem@0 949 {
philpem@0 950 m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */
philpem@0 951 m68ki_check_address_error(REG_PC); /* auto-disable (see m68kcpu.h) */
philpem@0 952 #if M68K_EMULATE_PREFETCH
philpem@0 953 if(MASK_OUT_BELOW_2(REG_PC) != CPU_PREF_ADDR)
philpem@0 954 {
philpem@0 955 CPU_PREF_ADDR = MASK_OUT_BELOW_2(REG_PC);
philpem@0 956 CPU_PREF_DATA = m68k_read_immediate_32(ADDRESS_68K(CPU_PREF_ADDR));
philpem@0 957 }
philpem@0 958 REG_PC += 2;
philpem@0 959 return MASK_OUT_ABOVE_16(CPU_PREF_DATA >> ((2-((REG_PC-2)&2))<<3));
philpem@0 960 #else
philpem@0 961 REG_PC += 2;
philpem@0 962 return m68k_read_immediate_16(ADDRESS_68K(REG_PC-2));
philpem@0 963 #endif /* M68K_EMULATE_PREFETCH */
philpem@0 964 }
philpem@0 965 INLINE uint m68ki_read_imm_32(void)
philpem@0 966 {
philpem@0 967 #if M68K_EMULATE_PREFETCH
philpem@0 968 uint temp_val;
philpem@0 969
philpem@0 970 m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */
philpem@0 971 m68ki_check_address_error(REG_PC); /* auto-disable (see m68kcpu.h) */
philpem@0 972 if(MASK_OUT_BELOW_2(REG_PC) != CPU_PREF_ADDR)
philpem@0 973 {
philpem@0 974 CPU_PREF_ADDR = MASK_OUT_BELOW_2(REG_PC);
philpem@0 975 CPU_PREF_DATA = m68k_read_immediate_32(ADDRESS_68K(CPU_PREF_ADDR));
philpem@0 976 }
philpem@0 977 temp_val = CPU_PREF_DATA;
philpem@0 978 REG_PC += 2;
philpem@0 979 if(MASK_OUT_BELOW_2(REG_PC) != CPU_PREF_ADDR)
philpem@0 980 {
philpem@0 981 CPU_PREF_ADDR = MASK_OUT_BELOW_2(REG_PC);
philpem@0 982 CPU_PREF_DATA = m68k_read_immediate_32(ADDRESS_68K(CPU_PREF_ADDR));
philpem@0 983 temp_val = MASK_OUT_ABOVE_32((temp_val << 16) | (CPU_PREF_DATA >> 16));
philpem@0 984 }
philpem@0 985 REG_PC += 2;
philpem@0 986
philpem@0 987 return temp_val;
philpem@0 988 #else
philpem@0 989 m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */
philpem@0 990 m68ki_check_address_error(REG_PC); /* auto-disable (see m68kcpu.h) */
philpem@0 991 REG_PC += 4;
philpem@0 992 return m68k_read_immediate_32(ADDRESS_68K(REG_PC-4));
philpem@0 993 #endif /* M68K_EMULATE_PREFETCH */
philpem@0 994 }
philpem@0 995
philpem@0 996
philpem@0 997
philpem@0 998 /* ------------------------- Top level read/write ------------------------- */
philpem@0 999
philpem@0 1000 /* Handles all memory accesses (except for immediate reads if they are
philpem@0 1001 * configured to use separate functions in m68kconf.h).
philpem@0 1002 * All memory accesses must go through these top level functions.
philpem@0 1003 * These functions will also check for address error and set the function
philpem@0 1004 * code if they are enabled in m68kconf.h.
philpem@0 1005 */
philpem@0 1006 INLINE uint m68ki_read_8_fc(uint address, uint fc)
philpem@0 1007 {
philpem@0 1008 m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */
philpem@0 1009 return m68k_read_memory_8(ADDRESS_68K(address));
philpem@0 1010 }
philpem@0 1011 INLINE uint m68ki_read_16_fc(uint address, uint fc)
philpem@0 1012 {
philpem@0 1013 m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */
philpem@0 1014 m68ki_check_address_error(address); /* auto-disable (see m68kcpu.h) */
philpem@0 1015 return m68k_read_memory_16(ADDRESS_68K(address));
philpem@0 1016 }
philpem@0 1017 INLINE uint m68ki_read_32_fc(uint address, uint fc)
philpem@0 1018 {
philpem@0 1019 m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */
philpem@0 1020 m68ki_check_address_error(address); /* auto-disable (see m68kcpu.h) */
philpem@0 1021 return m68k_read_memory_32(ADDRESS_68K(address));
philpem@0 1022 }
philpem@0 1023
philpem@0 1024 INLINE void m68ki_write_8_fc(uint address, uint fc, uint value)
philpem@0 1025 {
philpem@0 1026 m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */
philpem@0 1027 m68k_write_memory_8(ADDRESS_68K(address), value);
philpem@0 1028 }
philpem@0 1029 INLINE void m68ki_write_16_fc(uint address, uint fc, uint value)
philpem@0 1030 {
philpem@0 1031 m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */
philpem@0 1032 m68ki_check_address_error(address); /* auto-disable (see m68kcpu.h) */
philpem@0 1033 m68k_write_memory_16(ADDRESS_68K(address), value);
philpem@0 1034 }
philpem@0 1035 INLINE void m68ki_write_32_fc(uint address, uint fc, uint value)
philpem@0 1036 {
philpem@0 1037 m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */
philpem@0 1038 m68ki_check_address_error(address); /* auto-disable (see m68kcpu.h) */
philpem@0 1039 m68k_write_memory_32(ADDRESS_68K(address), value);
philpem@0 1040 }
philpem@0 1041
philpem@0 1042
philpem@0 1043
philpem@0 1044 /* --------------------- Effective Address Calculation -------------------- */
philpem@0 1045
philpem@0 1046 /* The program counter relative addressing modes cause operands to be
philpem@0 1047 * retrieved from program space, not data space.
philpem@0 1048 */
philpem@0 1049 INLINE uint m68ki_get_ea_pcdi(void)
philpem@0 1050 {
philpem@0 1051 uint old_pc = REG_PC;
philpem@0 1052 m68ki_use_program_space(); /* auto-disable */
philpem@0 1053 return old_pc + MAKE_INT_16(m68ki_read_imm_16());
philpem@0 1054 }
philpem@0 1055
philpem@0 1056
philpem@0 1057 INLINE uint m68ki_get_ea_pcix(void)
philpem@0 1058 {
philpem@0 1059 m68ki_use_program_space(); /* auto-disable */
philpem@0 1060 return m68ki_get_ea_ix(REG_PC);
philpem@0 1061 }
philpem@0 1062
philpem@0 1063 /* Indexed addressing modes are encoded as follows:
philpem@0 1064 *
philpem@0 1065 * Base instruction format:
philpem@0 1066 * F E D C B A 9 8 7 6 | 5 4 3 | 2 1 0
philpem@0 1067 * x x x x x x x x x x | 1 1 0 | BASE REGISTER (An)
philpem@0 1068 *
philpem@0 1069 * Base instruction format for destination EA in move instructions:
philpem@0 1070 * F E D C | B A 9 | 8 7 6 | 5 4 3 2 1 0
philpem@0 1071 * x x x x | BASE REG | 1 1 0 | X X X X X X (An)
philpem@0 1072 *
philpem@0 1073 * Brief extension format:
philpem@0 1074 * F | E D C | B | A 9 | 8 | 7 6 5 4 3 2 1 0
philpem@0 1075 * D/A | REGISTER | W/L | SCALE | 0 | DISPLACEMENT
philpem@0 1076 *
philpem@0 1077 * Full extension format:
philpem@0 1078 * F E D C B A 9 8 7 6 5 4 3 2 1 0
philpem@0 1079 * D/A | REGISTER | W/L | SCALE | 1 | BS | IS | BD SIZE | 0 | I/IS
philpem@0 1080 * BASE DISPLACEMENT (0, 16, 32 bit) (bd)
philpem@0 1081 * OUTER DISPLACEMENT (0, 16, 32 bit) (od)
philpem@0 1082 *
philpem@0 1083 * D/A: 0 = Dn, 1 = An (Xn)
philpem@0 1084 * W/L: 0 = W (sign extend), 1 = L (.SIZE)
philpem@0 1085 * SCALE: 00=1, 01=2, 10=4, 11=8 (*SCALE)
philpem@0 1086 * BS: 0=add base reg, 1=suppress base reg (An suppressed)
philpem@0 1087 * IS: 0=add index, 1=suppress index (Xn suppressed)
philpem@0 1088 * BD SIZE: 00=reserved, 01=NULL, 10=Word, 11=Long (size of bd)
philpem@0 1089 *
philpem@0 1090 * IS I/IS Operation
philpem@0 1091 * 0 000 No Memory Indirect
philpem@0 1092 * 0 001 indir prex with null outer
philpem@0 1093 * 0 010 indir prex with word outer
philpem@0 1094 * 0 011 indir prex with long outer
philpem@0 1095 * 0 100 reserved
philpem@0 1096 * 0 101 indir postx with null outer
philpem@0 1097 * 0 110 indir postx with word outer
philpem@0 1098 * 0 111 indir postx with long outer
philpem@0 1099 * 1 000 no memory indirect
philpem@0 1100 * 1 001 mem indir with null outer
philpem@0 1101 * 1 010 mem indir with word outer
philpem@0 1102 * 1 011 mem indir with long outer
philpem@0 1103 * 1 100-111 reserved
philpem@0 1104 */
philpem@0 1105 INLINE uint m68ki_get_ea_ix(uint An)
philpem@0 1106 {
philpem@0 1107 /* An = base register */
philpem@0 1108 uint extension = m68ki_read_imm_16();
philpem@0 1109 uint Xn = 0; /* Index register */
philpem@0 1110 uint bd = 0; /* Base Displacement */
philpem@0 1111 uint od = 0; /* Outer Displacement */
philpem@0 1112
philpem@0 1113 if(CPU_TYPE_IS_010_LESS(CPU_TYPE))
philpem@0 1114 {
philpem@0 1115 /* Calculate index */
philpem@0 1116 Xn = REG_DA[extension>>12]; /* Xn */
philpem@0 1117 if(!BIT_B(extension)) /* W/L */
philpem@0 1118 Xn = MAKE_INT_16(Xn);
philpem@0 1119
philpem@0 1120 /* Add base register and displacement and return */
philpem@0 1121 return An + Xn + MAKE_INT_8(extension);
philpem@0 1122 }
philpem@0 1123
philpem@0 1124 /* Brief extension format */
philpem@0 1125 if(!BIT_8(extension))
philpem@0 1126 {
philpem@0 1127 /* Calculate index */
philpem@0 1128 Xn = REG_DA[extension>>12]; /* Xn */
philpem@0 1129 if(!BIT_B(extension)) /* W/L */
philpem@0 1130 Xn = MAKE_INT_16(Xn);
philpem@0 1131 /* Add scale if proper CPU type */
philpem@0 1132 if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
philpem@0 1133 Xn <<= (extension>>9) & 3; /* SCALE */
philpem@0 1134
philpem@0 1135 /* Add base register and displacement and return */
philpem@0 1136 return An + Xn + MAKE_INT_8(extension);
philpem@0 1137 }
philpem@0 1138
philpem@0 1139 /* Full extension format */
philpem@0 1140
philpem@0 1141 USE_CYCLES(m68ki_ea_idx_cycle_table[extension&0x3f]);
philpem@0 1142
philpem@0 1143 /* Check if base register is present */
philpem@0 1144 if(BIT_7(extension)) /* BS */
philpem@0 1145 An = 0; /* An */
philpem@0 1146
philpem@0 1147 /* Check if index is present */
philpem@0 1148 if(!BIT_6(extension)) /* IS */
philpem@0 1149 {
philpem@0 1150 Xn = REG_DA[extension>>12]; /* Xn */
philpem@0 1151 if(!BIT_B(extension)) /* W/L */
philpem@0 1152 Xn = MAKE_INT_16(Xn);
philpem@0 1153 Xn <<= (extension>>9) & 3; /* SCALE */
philpem@0 1154 }
philpem@0 1155
philpem@0 1156 /* Check if base displacement is present */
philpem@0 1157 if(BIT_5(extension)) /* BD SIZE */
philpem@0 1158 bd = BIT_4(extension) ? m68ki_read_imm_32() : MAKE_INT_16(m68ki_read_imm_16());
philpem@0 1159
philpem@0 1160 /* If no indirect action, we are done */
philpem@0 1161 if(!(extension&7)) /* No Memory Indirect */
philpem@0 1162 return An + bd + Xn;
philpem@0 1163
philpem@0 1164 /* Check if outer displacement is present */
philpem@0 1165 if(BIT_1(extension)) /* I/IS: od */
philpem@0 1166 od = BIT_0(extension) ? m68ki_read_imm_32() : MAKE_INT_16(m68ki_read_imm_16());
philpem@0 1167
philpem@0 1168 /* Postindex */
philpem@0 1169 if(BIT_2(extension)) /* I/IS: 0 = preindex, 1 = postindex */
philpem@0 1170 return m68ki_read_32(An + bd) + Xn + od;
philpem@0 1171
philpem@0 1172 /* Preindex */
philpem@0 1173 return m68ki_read_32(An + bd + Xn) + od;
philpem@0 1174 }
philpem@0 1175
philpem@0 1176
philpem@0 1177 /* Fetch operands */
philpem@0 1178 INLINE uint OPER_AY_AI_8(void) {uint ea = EA_AY_AI_8(); return m68ki_read_8(ea); }
philpem@0 1179 INLINE uint OPER_AY_AI_16(void) {uint ea = EA_AY_AI_16(); return m68ki_read_16(ea);}
philpem@0 1180 INLINE uint OPER_AY_AI_32(void) {uint ea = EA_AY_AI_32(); return m68ki_read_32(ea);}
philpem@0 1181 INLINE uint OPER_AY_PI_8(void) {uint ea = EA_AY_PI_8(); return m68ki_read_8(ea); }
philpem@0 1182 INLINE uint OPER_AY_PI_16(void) {uint ea = EA_AY_PI_16(); return m68ki_read_16(ea);}
philpem@0 1183 INLINE uint OPER_AY_PI_32(void) {uint ea = EA_AY_PI_32(); return m68ki_read_32(ea);}
philpem@0 1184 INLINE uint OPER_AY_PD_8(void) {uint ea = EA_AY_PD_8(); return m68ki_read_8(ea); }
philpem@0 1185 INLINE uint OPER_AY_PD_16(void) {uint ea = EA_AY_PD_16(); return m68ki_read_16(ea);}
philpem@0 1186 INLINE uint OPER_AY_PD_32(void) {uint ea = EA_AY_PD_32(); return m68ki_read_32(ea);}
philpem@0 1187 INLINE uint OPER_AY_DI_8(void) {uint ea = EA_AY_DI_8(); return m68ki_read_8(ea); }
philpem@0 1188 INLINE uint OPER_AY_DI_16(void) {uint ea = EA_AY_DI_16(); return m68ki_read_16(ea);}
philpem@0 1189 INLINE uint OPER_AY_DI_32(void) {uint ea = EA_AY_DI_32(); return m68ki_read_32(ea);}
philpem@0 1190 INLINE uint OPER_AY_IX_8(void) {uint ea = EA_AY_IX_8(); return m68ki_read_8(ea); }
philpem@0 1191 INLINE uint OPER_AY_IX_16(void) {uint ea = EA_AY_IX_16(); return m68ki_read_16(ea);}
philpem@0 1192 INLINE uint OPER_AY_IX_32(void) {uint ea = EA_AY_IX_32(); return m68ki_read_32(ea);}
philpem@0 1193
philpem@0 1194 INLINE uint OPER_AX_AI_8(void) {uint ea = EA_AX_AI_8(); return m68ki_read_8(ea); }
philpem@0 1195 INLINE uint OPER_AX_AI_16(void) {uint ea = EA_AX_AI_16(); return m68ki_read_16(ea);}
philpem@0 1196 INLINE uint OPER_AX_AI_32(void) {uint ea = EA_AX_AI_32(); return m68ki_read_32(ea);}
philpem@0 1197 INLINE uint OPER_AX_PI_8(void) {uint ea = EA_AX_PI_8(); return m68ki_read_8(ea); }
philpem@0 1198 INLINE uint OPER_AX_PI_16(void) {uint ea = EA_AX_PI_16(); return m68ki_read_16(ea);}
philpem@0 1199 INLINE uint OPER_AX_PI_32(void) {uint ea = EA_AX_PI_32(); return m68ki_read_32(ea);}
philpem@0 1200 INLINE uint OPER_AX_PD_8(void) {uint ea = EA_AX_PD_8(); return m68ki_read_8(ea); }
philpem@0 1201 INLINE uint OPER_AX_PD_16(void) {uint ea = EA_AX_PD_16(); return m68ki_read_16(ea);}
philpem@0 1202 INLINE uint OPER_AX_PD_32(void) {uint ea = EA_AX_PD_32(); return m68ki_read_32(ea);}
philpem@0 1203 INLINE uint OPER_AX_DI_8(void) {uint ea = EA_AX_DI_8(); return m68ki_read_8(ea); }
philpem@0 1204 INLINE uint OPER_AX_DI_16(void) {uint ea = EA_AX_DI_16(); return m68ki_read_16(ea);}
philpem@0 1205 INLINE uint OPER_AX_DI_32(void) {uint ea = EA_AX_DI_32(); return m68ki_read_32(ea);}
philpem@0 1206 INLINE uint OPER_AX_IX_8(void) {uint ea = EA_AX_IX_8(); return m68ki_read_8(ea); }
philpem@0 1207 INLINE uint OPER_AX_IX_16(void) {uint ea = EA_AX_IX_16(); return m68ki_read_16(ea);}
philpem@0 1208 INLINE uint OPER_AX_IX_32(void) {uint ea = EA_AX_IX_32(); return m68ki_read_32(ea);}
philpem@0 1209
philpem@0 1210 INLINE uint OPER_A7_PI_8(void) {uint ea = EA_A7_PI_8(); return m68ki_read_8(ea); }
philpem@0 1211 INLINE uint OPER_A7_PD_8(void) {uint ea = EA_A7_PD_8(); return m68ki_read_8(ea); }
philpem@0 1212
philpem@0 1213 INLINE uint OPER_AW_8(void) {uint ea = EA_AW_8(); return m68ki_read_8(ea); }
philpem@0 1214 INLINE uint OPER_AW_16(void) {uint ea = EA_AW_16(); return m68ki_read_16(ea);}
philpem@0 1215 INLINE uint OPER_AW_32(void) {uint ea = EA_AW_32(); return m68ki_read_32(ea);}
philpem@0 1216 INLINE uint OPER_AL_8(void) {uint ea = EA_AL_8(); return m68ki_read_8(ea); }
philpem@0 1217 INLINE uint OPER_AL_16(void) {uint ea = EA_AL_16(); return m68ki_read_16(ea);}
philpem@0 1218 INLINE uint OPER_AL_32(void) {uint ea = EA_AL_32(); return m68ki_read_32(ea);}
philpem@0 1219 INLINE uint OPER_PCDI_8(void) {uint ea = EA_PCDI_8(); return m68ki_read_pcrel_8(ea); }
philpem@0 1220 INLINE uint OPER_PCDI_16(void) {uint ea = EA_PCDI_16(); return m68ki_read_pcrel_16(ea);}
philpem@0 1221 INLINE uint OPER_PCDI_32(void) {uint ea = EA_PCDI_32(); return m68ki_read_pcrel_32(ea);}
philpem@0 1222 INLINE uint OPER_PCIX_8(void) {uint ea = EA_PCIX_8(); return m68ki_read_pcrel_8(ea); }
philpem@0 1223 INLINE uint OPER_PCIX_16(void) {uint ea = EA_PCIX_16(); return m68ki_read_pcrel_16(ea);}
philpem@0 1224 INLINE uint OPER_PCIX_32(void) {uint ea = EA_PCIX_32(); return m68ki_read_pcrel_32(ea);}
philpem@0 1225
philpem@0 1226
philpem@0 1227
philpem@0 1228 /* ---------------------------- Stack Functions --------------------------- */
philpem@0 1229
philpem@0 1230 /* Push/pull data from the stack */
philpem@0 1231 INLINE void m68ki_push_16(uint value)
philpem@0 1232 {
philpem@0 1233 REG_SP = MASK_OUT_ABOVE_32(REG_SP - 2);
philpem@0 1234 m68ki_write_16(REG_SP, value);
philpem@0 1235 }
philpem@0 1236
philpem@0 1237 INLINE void m68ki_push_32(uint value)
philpem@0 1238 {
philpem@0 1239 REG_SP = MASK_OUT_ABOVE_32(REG_SP - 4);
philpem@0 1240 m68ki_write_32(REG_SP, value);
philpem@0 1241 }
philpem@0 1242
philpem@0 1243 INLINE uint m68ki_pull_16(void)
philpem@0 1244 {
philpem@0 1245 REG_SP = MASK_OUT_ABOVE_32(REG_SP + 2);
philpem@0 1246 return m68ki_read_16(REG_SP-2);
philpem@0 1247 }
philpem@0 1248
philpem@0 1249 INLINE uint m68ki_pull_32(void)
philpem@0 1250 {
philpem@0 1251 REG_SP = MASK_OUT_ABOVE_32(REG_SP + 4);
philpem@0 1252 return m68ki_read_32(REG_SP-4);
philpem@0 1253 }
philpem@0 1254
philpem@0 1255
philpem@0 1256 /* Increment/decrement the stack as if doing a push/pull but
philpem@0 1257 * don't do any memory access.
philpem@0 1258 */
philpem@0 1259 INLINE void m68ki_fake_push_16(void)
philpem@0 1260 {
philpem@0 1261 REG_SP = MASK_OUT_ABOVE_32(REG_SP - 2);
philpem@0 1262 }
philpem@0 1263
philpem@0 1264 INLINE void m68ki_fake_push_32(void)
philpem@0 1265 {
philpem@0 1266 REG_SP = MASK_OUT_ABOVE_32(REG_SP - 4);
philpem@0 1267 }
philpem@0 1268
philpem@0 1269 INLINE void m68ki_fake_pull_16(void)
philpem@0 1270 {
philpem@0 1271 REG_SP = MASK_OUT_ABOVE_32(REG_SP + 2);
philpem@0 1272 }
philpem@0 1273
philpem@0 1274 INLINE void m68ki_fake_pull_32(void)
philpem@0 1275 {
philpem@0 1276 REG_SP = MASK_OUT_ABOVE_32(REG_SP + 4);
philpem@0 1277 }
philpem@0 1278
philpem@0 1279
philpem@0 1280 /* ----------------------------- Program Flow ----------------------------- */
philpem@0 1281
philpem@0 1282 /* Jump to a new program location or vector.
philpem@0 1283 * These functions will also call the pc_changed callback if it was enabled
philpem@0 1284 * in m68kconf.h.
philpem@0 1285 */
philpem@0 1286 INLINE void m68ki_jump(uint new_pc)
philpem@0 1287 {
philpem@0 1288 REG_PC = new_pc;
philpem@0 1289 m68ki_pc_changed(REG_PC);
philpem@0 1290 }
philpem@0 1291
philpem@0 1292 INLINE void m68ki_jump_vector(uint vector)
philpem@0 1293 {
philpem@0 1294 REG_PC = (vector<<2) + REG_VBR;
philpem@0 1295 REG_PC = m68ki_read_data_32(REG_PC);
philpem@0 1296 m68ki_pc_changed(REG_PC);
philpem@0 1297 }
philpem@0 1298
philpem@0 1299
philpem@0 1300 /* Branch to a new memory location.
philpem@0 1301 * The 32-bit branch will call pc_changed if it was enabled in m68kconf.h.
philpem@0 1302 * So far I've found no problems with not calling pc_changed for 8 or 16
philpem@0 1303 * bit branches.
philpem@0 1304 */
philpem@0 1305 INLINE void m68ki_branch_8(uint offset)
philpem@0 1306 {
philpem@0 1307 REG_PC += MAKE_INT_8(offset);
philpem@0 1308 }
philpem@0 1309
philpem@0 1310 INLINE void m68ki_branch_16(uint offset)
philpem@0 1311 {
philpem@0 1312 REG_PC += MAKE_INT_16(offset);
philpem@0 1313 }
philpem@0 1314
philpem@0 1315 INLINE void m68ki_branch_32(uint offset)
philpem@0 1316 {
philpem@0 1317 REG_PC += offset;
philpem@0 1318 m68ki_pc_changed(REG_PC);
philpem@0 1319 }
philpem@0 1320
philpem@0 1321
philpem@0 1322
philpem@0 1323 /* ---------------------------- Status Register --------------------------- */
philpem@0 1324
philpem@0 1325 /* Set the S flag and change the active stack pointer.
philpem@0 1326 * Note that value MUST be 4 or 0.
philpem@0 1327 */
philpem@0 1328 INLINE void m68ki_set_s_flag(uint value)
philpem@0 1329 {
philpem@0 1330 /* Backup the old stack pointer */
philpem@0 1331 REG_SP_BASE[FLAG_S | ((FLAG_S>>1) & FLAG_M)] = REG_SP;
philpem@0 1332 /* Set the S flag */
philpem@0 1333 FLAG_S = value;
philpem@0 1334 /* Set the new stack pointer */
philpem@0 1335 REG_SP = REG_SP_BASE[FLAG_S | ((FLAG_S>>1) & FLAG_M)];
philpem@0 1336 }
philpem@0 1337
philpem@0 1338 /* Set the S and M flags and change the active stack pointer.
philpem@0 1339 * Note that value MUST be 0, 2, 4, or 6 (bit2 = S, bit1 = M).
philpem@0 1340 */
philpem@0 1341 INLINE void m68ki_set_sm_flag(uint value)
philpem@0 1342 {
philpem@0 1343 /* Backup the old stack pointer */
philpem@0 1344 REG_SP_BASE[FLAG_S | ((FLAG_S>>1) & FLAG_M)] = REG_SP;
philpem@0 1345 /* Set the S and M flags */
philpem@0 1346 FLAG_S = value & SFLAG_SET;
philpem@0 1347 FLAG_M = value & MFLAG_SET;
philpem@0 1348 /* Set the new stack pointer */
philpem@0 1349 REG_SP = REG_SP_BASE[FLAG_S | ((FLAG_S>>1) & FLAG_M)];
philpem@0 1350 }
philpem@0 1351
philpem@0 1352
philpem@0 1353 /* Set the condition code register */
philpem@0 1354 INLINE void m68ki_set_ccr(uint value)
philpem@0 1355 {
philpem@0 1356 FLAG_X = BIT_4(value) << 4;
philpem@0 1357 FLAG_N = BIT_3(value) << 4;
philpem@0 1358 FLAG_Z = !BIT_2(value);
philpem@0 1359 FLAG_V = BIT_1(value) << 6;
philpem@0 1360 FLAG_C = BIT_0(value) << 8;
philpem@0 1361 }
philpem@0 1362
philpem@0 1363 /* Set the status register but don't check for interrupts */
philpem@0 1364 INLINE void m68ki_set_sr_noint(uint value)
philpem@0 1365 {
philpem@0 1366 /* Mask out the "unimplemented" bits */
philpem@0 1367 value &= CPU_SR_MASK;
philpem@0 1368
philpem@0 1369 /* Now set the status register */
philpem@0 1370 FLAG_T1 = BIT_F(value);
philpem@0 1371 FLAG_T0 = BIT_E(value);
philpem@0 1372 FLAG_INT_MASK = value & 0x0700;
philpem@0 1373 m68ki_set_ccr(value);
philpem@0 1374 m68ki_set_sm_flag((value >> 11) & 6);
philpem@0 1375 }
philpem@0 1376
philpem@0 1377 /* Set the status register and check for interrupts */
philpem@0 1378 INLINE void m68ki_set_sr(uint value)
philpem@0 1379 {
philpem@0 1380 m68ki_set_sr_noint(value);
philpem@0 1381 m68ki_check_interrupts();
philpem@0 1382 }
philpem@0 1383
philpem@0 1384
philpem@0 1385 /* ------------------------- Exception Processing ------------------------- */
philpem@0 1386
philpem@0 1387 /* Initiate exception processing */
philpem@0 1388 INLINE uint m68ki_init_exception(void)
philpem@0 1389 {
philpem@0 1390 /* Save the old status register */
philpem@0 1391 uint sr = m68ki_get_sr();
philpem@0 1392
philpem@0 1393 /* Turn off trace flag, clear pending traces */
philpem@0 1394 FLAG_T1 = FLAG_T0 = 0;
philpem@0 1395 m68ki_clear_trace();
philpem@0 1396 /* Enter supervisor mode */
philpem@0 1397 m68ki_set_s_flag(SFLAG_SET);
philpem@0 1398
philpem@0 1399 return sr;
philpem@0 1400 }
philpem@0 1401
philpem@0 1402 /* 3 word stack frame (68000 only) */
philpem@0 1403 INLINE void m68ki_stack_frame_3word(uint pc, uint sr)
philpem@0 1404 {
philpem@0 1405 m68ki_push_32(pc);
philpem@0 1406 m68ki_push_16(sr);
philpem@0 1407 }
philpem@0 1408
philpem@0 1409 /* Format 0 stack frame.
philpem@0 1410 * This is the standard stack frame for 68010+.
philpem@0 1411 */
philpem@0 1412 INLINE void m68ki_stack_frame_0000(uint pc, uint sr, uint vector)
philpem@0 1413 {
philpem@0 1414 /* Stack a 3-word frame if we are 68000 */
philpem@0 1415 if(CPU_TYPE == CPU_TYPE_000)
philpem@0 1416 {
philpem@0 1417 m68ki_stack_frame_3word(pc, sr);
philpem@0 1418 return;
philpem@0 1419 }
philpem@0 1420 m68ki_push_16(vector<<2);
philpem@0 1421 m68ki_push_32(pc);
philpem@0 1422 m68ki_push_16(sr);
philpem@0 1423 }
philpem@0 1424
philpem@0 1425 /* Format 1 stack frame (68020).
philpem@0 1426 * For 68020, this is the 4 word throwaway frame.
philpem@0 1427 */
philpem@0 1428 INLINE void m68ki_stack_frame_0001(uint pc, uint sr, uint vector)
philpem@0 1429 {
philpem@0 1430 m68ki_push_16(0x1000 | (vector<<2));
philpem@0 1431 m68ki_push_32(pc);
philpem@0 1432 m68ki_push_16(sr);
philpem@0 1433 }
philpem@0 1434
philpem@0 1435 /* Format 2 stack frame.
philpem@0 1436 * This is used only by 68020 for trap exceptions.
philpem@0 1437 */
philpem@0 1438 INLINE void m68ki_stack_frame_0010(uint sr, uint vector)
philpem@0 1439 {
philpem@0 1440 m68ki_push_32(REG_PPC);
philpem@0 1441 m68ki_push_16(0x2000 | (vector<<2));
philpem@0 1442 m68ki_push_32(REG_PC);
philpem@0 1443 m68ki_push_16(sr);
philpem@0 1444 }
philpem@0 1445
philpem@0 1446
philpem@0 1447 /* Bus error stack frame (68000 only).
philpem@0 1448 */
philpem@0 1449 INLINE void m68ki_stack_frame_buserr(uint pc, uint sr, uint address, uint write, uint instruction, uint fc)
philpem@0 1450 {
philpem@0 1451 m68ki_push_32(pc);
philpem@0 1452 m68ki_push_16(sr);
philpem@0 1453 m68ki_push_16(REG_IR);
philpem@0 1454 m68ki_push_32(address); /* access address */
philpem@0 1455 /* 0 0 0 0 0 0 0 0 0 0 0 R/W I/N FC
philpem@0 1456 * R/W 0 = write, 1 = read
philpem@0 1457 * I/N 0 = instruction, 1 = not
philpem@0 1458 * FC 3-bit function code
philpem@0 1459 */
philpem@0 1460 m68ki_push_16(((!write)<<4) | ((!instruction)<<3) | fc);
philpem@0 1461 }
philpem@0 1462
philpem@0 1463 /* Format 8 stack frame (68010).
philpem@0 1464 * 68010 only. This is the 29 word bus/address error frame.
philpem@0 1465 */
philpem@0 1466 void m68ki_stack_frame_1000(uint pc, uint sr, uint vector)
philpem@0 1467 {
philpem@0 1468 /* VERSION
philpem@0 1469 * NUMBER
philpem@0 1470 * INTERNAL INFORMATION, 16 WORDS
philpem@0 1471 */
philpem@0 1472 m68ki_fake_push_32();
philpem@0 1473 m68ki_fake_push_32();
philpem@0 1474 m68ki_fake_push_32();
philpem@0 1475 m68ki_fake_push_32();
philpem@0 1476 m68ki_fake_push_32();
philpem@0 1477 m68ki_fake_push_32();
philpem@0 1478 m68ki_fake_push_32();
philpem@0 1479 m68ki_fake_push_32();
philpem@0 1480
philpem@0 1481 /* INSTRUCTION INPUT BUFFER */
philpem@0 1482 m68ki_push_16(0);
philpem@0 1483
philpem@0 1484 /* UNUSED, RESERVED (not written) */
philpem@0 1485 m68ki_fake_push_16();
philpem@0 1486
philpem@0 1487 /* DATA INPUT BUFFER */
philpem@0 1488 m68ki_push_16(0);
philpem@0 1489
philpem@0 1490 /* UNUSED, RESERVED (not written) */
philpem@0 1491 m68ki_fake_push_16();
philpem@0 1492
philpem@0 1493 /* DATA OUTPUT BUFFER */
philpem@0 1494 m68ki_push_16(0);
philpem@0 1495
philpem@0 1496 /* UNUSED, RESERVED (not written) */
philpem@0 1497 m68ki_fake_push_16();
philpem@0 1498
philpem@0 1499 /* FAULT ADDRESS */
philpem@0 1500 m68ki_push_32(0);
philpem@0 1501
philpem@0 1502 /* SPECIAL STATUS WORD */
philpem@0 1503 m68ki_push_16(0);
philpem@0 1504
philpem@0 1505 /* 1000, VECTOR OFFSET */
philpem@0 1506 m68ki_push_16(0x8000 | (vector<<2));
philpem@0 1507
philpem@0 1508 /* PROGRAM COUNTER */
philpem@0 1509 m68ki_push_32(pc);
philpem@0 1510
philpem@0 1511 /* STATUS REGISTER */
philpem@0 1512 m68ki_push_16(sr);
philpem@0 1513 }
philpem@0 1514
philpem@0 1515 /* Format A stack frame (short bus fault).
philpem@0 1516 * This is used only by 68020 for bus fault and address error
philpem@0 1517 * if the error happens at an instruction boundary.
philpem@0 1518 * PC stacked is address of next instruction.
philpem@0 1519 */
philpem@0 1520 void m68ki_stack_frame_1010(uint sr, uint vector, uint pc)
philpem@0 1521 {
philpem@0 1522 /* INTERNAL REGISTER */
philpem@0 1523 m68ki_push_16(0);
philpem@0 1524
philpem@0 1525 /* INTERNAL REGISTER */
philpem@0 1526 m68ki_push_16(0);
philpem@0 1527
philpem@0 1528 /* DATA OUTPUT BUFFER (2 words) */
philpem@0 1529 m68ki_push_32(0);
philpem@0 1530
philpem@0 1531 /* INTERNAL REGISTER */
philpem@0 1532 m68ki_push_16(0);
philpem@0 1533
philpem@0 1534 /* INTERNAL REGISTER */
philpem@0 1535 m68ki_push_16(0);
philpem@0 1536
philpem@0 1537 /* DATA CYCLE FAULT ADDRESS (2 words) */
philpem@0 1538 m68ki_push_32(0);
philpem@0 1539
philpem@0 1540 /* INSTRUCTION PIPE STAGE B */
philpem@0 1541 m68ki_push_16(0);
philpem@0 1542
philpem@0 1543 /* INSTRUCTION PIPE STAGE C */
philpem@0 1544 m68ki_push_16(0);
philpem@0 1545
philpem@0 1546 /* SPECIAL STATUS REGISTER */
philpem@0 1547 m68ki_push_16(0);
philpem@0 1548
philpem@0 1549 /* INTERNAL REGISTER */
philpem@0 1550 m68ki_push_16(0);
philpem@0 1551
philpem@0 1552 /* 1010, VECTOR OFFSET */
philpem@0 1553 m68ki_push_16(0xa000 | (vector<<2));
philpem@0 1554
philpem@0 1555 /* PROGRAM COUNTER */
philpem@0 1556 m68ki_push_32(pc);
philpem@0 1557
philpem@0 1558 /* STATUS REGISTER */
philpem@0 1559 m68ki_push_16(sr);
philpem@0 1560 }
philpem@0 1561
philpem@0 1562 /* Format B stack frame (long bus fault).
philpem@0 1563 * This is used only by 68020 for bus fault and address error
philpem@0 1564 * if the error happens during instruction execution.
philpem@0 1565 * PC stacked is address of instruction in progress.
philpem@0 1566 */
philpem@0 1567 void m68ki_stack_frame_1011(uint sr, uint vector, uint pc)
philpem@0 1568 {
philpem@0 1569 /* INTERNAL REGISTERS (18 words) */
philpem@0 1570 m68ki_push_32(0);
philpem@0 1571 m68ki_push_32(0);
philpem@0 1572 m68ki_push_32(0);
philpem@0 1573 m68ki_push_32(0);
philpem@0 1574 m68ki_push_32(0);
philpem@0 1575 m68ki_push_32(0);
philpem@0 1576 m68ki_push_32(0);
philpem@0 1577 m68ki_push_32(0);
philpem@0 1578 m68ki_push_32(0);
philpem@0 1579
philpem@0 1580 /* VERSION# (4 bits), INTERNAL INFORMATION */
philpem@0 1581 m68ki_push_16(0);
philpem@0 1582
philpem@0 1583 /* INTERNAL REGISTERS (3 words) */
philpem@0 1584 m68ki_push_32(0);
philpem@0 1585 m68ki_push_16(0);
philpem@0 1586
philpem@0 1587 /* DATA INTPUT BUFFER (2 words) */
philpem@0 1588 m68ki_push_32(0);
philpem@0 1589
philpem@0 1590 /* INTERNAL REGISTERS (2 words) */
philpem@0 1591 m68ki_push_32(0);
philpem@0 1592
philpem@0 1593 /* STAGE B ADDRESS (2 words) */
philpem@0 1594 m68ki_push_32(0);
philpem@0 1595
philpem@0 1596 /* INTERNAL REGISTER (4 words) */
philpem@0 1597 m68ki_push_32(0);
philpem@0 1598 m68ki_push_32(0);
philpem@0 1599
philpem@0 1600 /* DATA OUTPUT BUFFER (2 words) */
philpem@0 1601 m68ki_push_32(0);
philpem@0 1602
philpem@0 1603 /* INTERNAL REGISTER */
philpem@0 1604 m68ki_push_16(0);
philpem@0 1605
philpem@0 1606 /* INTERNAL REGISTER */
philpem@0 1607 m68ki_push_16(0);
philpem@0 1608
philpem@0 1609 /* DATA CYCLE FAULT ADDRESS (2 words) */
philpem@0 1610 m68ki_push_32(0);
philpem@0 1611
philpem@0 1612 /* INSTRUCTION PIPE STAGE B */
philpem@0 1613 m68ki_push_16(0);
philpem@0 1614
philpem@0 1615 /* INSTRUCTION PIPE STAGE C */
philpem@0 1616 m68ki_push_16(0);
philpem@0 1617
philpem@0 1618 /* SPECIAL STATUS REGISTER */
philpem@0 1619 m68ki_push_16(0);
philpem@0 1620
philpem@0 1621 /* INTERNAL REGISTER */
philpem@0 1622 m68ki_push_16(0);
philpem@0 1623
philpem@0 1624 /* 1011, VECTOR OFFSET */
philpem@0 1625 m68ki_push_16(0xb000 | (vector<<2));
philpem@0 1626
philpem@0 1627 /* PROGRAM COUNTER */
philpem@0 1628 m68ki_push_32(pc);
philpem@0 1629
philpem@0 1630 /* STATUS REGISTER */
philpem@0 1631 m68ki_push_16(sr);
philpem@0 1632 }
philpem@0 1633
philpem@0 1634
philpem@0 1635 /* Used for Group 2 exceptions.
philpem@0 1636 * These stack a type 2 frame on the 020.
philpem@0 1637 */
philpem@0 1638 INLINE void m68ki_exception_trap(uint vector)
philpem@0 1639 {
philpem@0 1640 uint sr = m68ki_init_exception();
philpem@0 1641
philpem@0 1642 if(CPU_TYPE_IS_010_LESS(CPU_TYPE))
philpem@0 1643 m68ki_stack_frame_0000(REG_PC, sr, vector);
philpem@0 1644 else
philpem@0 1645 m68ki_stack_frame_0010(sr, vector);
philpem@0 1646
philpem@0 1647 m68ki_jump_vector(vector);
philpem@0 1648
philpem@0 1649 /* Use up some clock cycles */
philpem@0 1650 USE_CYCLES(CYC_EXCEPTION[vector]);
philpem@0 1651 }
philpem@0 1652
philpem@0 1653 /* Trap#n stacks a 0 frame but behaves like group2 otherwise */
philpem@0 1654 INLINE void m68ki_exception_trapN(uint vector)
philpem@0 1655 {
philpem@0 1656 uint sr = m68ki_init_exception();
philpem@0 1657 m68ki_stack_frame_0000(REG_PC, sr, vector);
philpem@0 1658 m68ki_jump_vector(vector);
philpem@0 1659
philpem@0 1660 /* Use up some clock cycles */
philpem@0 1661 USE_CYCLES(CYC_EXCEPTION[vector]);
philpem@0 1662 }
philpem@0 1663
philpem@0 1664 /* Exception for trace mode */
philpem@0 1665 INLINE void m68ki_exception_trace(void)
philpem@0 1666 {
philpem@0 1667 uint sr = m68ki_init_exception();
philpem@0 1668
philpem@0 1669 if(CPU_TYPE_IS_010_LESS(CPU_TYPE))
philpem@0 1670 m68ki_stack_frame_0000(REG_PC, sr, EXCEPTION_TRACE);
philpem@0 1671 else
philpem@0 1672 m68ki_stack_frame_0010(sr, EXCEPTION_TRACE);
philpem@0 1673
philpem@0 1674 m68ki_jump_vector(EXCEPTION_TRACE);
philpem@0 1675
philpem@0 1676 /* Trace nullifies a STOP instruction */
philpem@0 1677 CPU_STOPPED &= ~STOP_LEVEL_STOP;
philpem@0 1678
philpem@0 1679 /* Use up some clock cycles */
philpem@0 1680 USE_CYCLES(CYC_EXCEPTION[EXCEPTION_TRACE]);
philpem@0 1681 }
philpem@0 1682
philpem@0 1683 /* Exception for privilege violation */
philpem@0 1684 INLINE void m68ki_exception_privilege_violation(void)
philpem@0 1685 {
philpem@0 1686 uint sr = m68ki_init_exception();
philpem@0 1687 m68ki_stack_frame_0000(REG_PC, sr, EXCEPTION_PRIVILEGE_VIOLATION);
philpem@0 1688 m68ki_jump_vector(EXCEPTION_PRIVILEGE_VIOLATION);
philpem@0 1689
philpem@0 1690 /* Use up some clock cycles and undo the instruction's cycles */
philpem@0 1691 USE_CYCLES(CYC_EXCEPTION[EXCEPTION_PRIVILEGE_VIOLATION] - CYC_INSTRUCTION[REG_IR]);
philpem@0 1692 }
philpem@0 1693
andrew@147 1694 extern jmp_buf m68ki_bus_error_jmp_buf;
andrew@147 1695 extern jmp_buf m68ki_bus_error_return_jmp_buf;
andrew@147 1696
andrew@147 1697 #define m68ki_check_bus_error_trap() setjmp(m68ki_bus_error_jmp_buf)
andrew@147 1698
philpem@19 1699 /* Exception for bus error */
philpem@19 1700 INLINE void m68ki_exception_bus_error(void)
philpem@19 1701 {
andrew@147 1702 int i;
philpem@109 1703 BUS_ERROR_OCCURRED = 1;
philpem@19 1704 /* Use up some clock cycles and undo the instruction's cycles */
philpem@19 1705 USE_CYCLES(CYC_EXCEPTION[EXCEPTION_BUS_ERROR] - CYC_INSTRUCTION[REG_IR]);
andrew@147 1706
andrew@147 1707 for (i = 15; i >= 0; i--){
andrew@147 1708 REG_DA[i] = REG_DA_SAVE[i];
andrew@147 1709 }
andrew@147 1710
andrew@147 1711 uint sr = m68ki_init_exception();
andrew@147 1712 m68ki_stack_frame_1000(REG_PPC, sr, EXCEPTION_BUS_ERROR);
andrew@147 1713
andrew@147 1714 m68ki_jump_vector(EXCEPTION_BUS_ERROR);
andrew@147 1715 longjmp(m68ki_bus_error_jmp_buf, 1);
philpem@19 1716 }
philpem@19 1717
andrew@147 1718 extern int cpu_log_enabled;
philpem@19 1719
philpem@0 1720 /* Exception for A-Line instructions */
philpem@0 1721 INLINE void m68ki_exception_1010(void)
philpem@0 1722 {
philpem@0 1723 uint sr;
philpem@0 1724 #if M68K_LOG_1010_1111 == OPT_ON
philpem@0 1725 M68K_DO_LOG_EMU((M68K_LOG_FILEHANDLE "%s at %08x: called 1010 instruction %04x (%s)\n",
philpem@0 1726 m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PPC), REG_IR,
philpem@0 1727 m68ki_disassemble_quick(ADDRESS_68K(REG_PPC))));
philpem@0 1728 #endif
philpem@0 1729
philpem@0 1730 sr = m68ki_init_exception();
philpem@0 1731 m68ki_stack_frame_0000(REG_PC-2, sr, EXCEPTION_1010);
philpem@0 1732 m68ki_jump_vector(EXCEPTION_1010);
philpem@0 1733
philpem@0 1734 /* Use up some clock cycles and undo the instruction's cycles */
philpem@0 1735 USE_CYCLES(CYC_EXCEPTION[EXCEPTION_1010] - CYC_INSTRUCTION[REG_IR]);
philpem@0 1736 }
philpem@0 1737
philpem@0 1738 /* Exception for F-Line instructions */
philpem@0 1739 INLINE void m68ki_exception_1111(void)
philpem@0 1740 {
philpem@0 1741 uint sr;
philpem@0 1742
philpem@0 1743 #if M68K_LOG_1010_1111 == OPT_ON
philpem@0 1744 M68K_DO_LOG_EMU((M68K_LOG_FILEHANDLE "%s at %08x: called 1111 instruction %04x (%s)\n",
philpem@0 1745 m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PPC), REG_IR,
philpem@0 1746 m68ki_disassemble_quick(ADDRESS_68K(REG_PPC))));
philpem@0 1747 #endif
philpem@0 1748
philpem@0 1749 sr = m68ki_init_exception();
philpem@0 1750 m68ki_stack_frame_0000(REG_PC-2, sr, EXCEPTION_1111);
philpem@0 1751 m68ki_jump_vector(EXCEPTION_1111);
philpem@0 1752
philpem@0 1753 /* Use up some clock cycles and undo the instruction's cycles */
philpem@0 1754 USE_CYCLES(CYC_EXCEPTION[EXCEPTION_1111] - CYC_INSTRUCTION[REG_IR]);
philpem@0 1755 }
philpem@0 1756
philpem@0 1757 /* Exception for illegal instructions */
philpem@0 1758 INLINE void m68ki_exception_illegal(void)
philpem@0 1759 {
philpem@0 1760 uint sr;
philpem@0 1761
philpem@0 1762 M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: illegal instruction %04x (%s)\n",
philpem@0 1763 m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PPC), REG_IR,
philpem@0 1764 m68ki_disassemble_quick(ADDRESS_68K(REG_PPC))));
philpem@0 1765
philpem@0 1766 sr = m68ki_init_exception();
philpem@0 1767 m68ki_stack_frame_0000(REG_PC, sr, EXCEPTION_ILLEGAL_INSTRUCTION);
philpem@0 1768 m68ki_jump_vector(EXCEPTION_ILLEGAL_INSTRUCTION);
philpem@0 1769
philpem@0 1770 /* Use up some clock cycles and undo the instruction's cycles */
philpem@0 1771 USE_CYCLES(CYC_EXCEPTION[EXCEPTION_ILLEGAL_INSTRUCTION] - CYC_INSTRUCTION[REG_IR]);
philpem@0 1772 }
philpem@0 1773
philpem@0 1774 /* Exception for format errror in RTE */
philpem@0 1775 INLINE void m68ki_exception_format_error(void)
philpem@0 1776 {
philpem@0 1777 uint sr = m68ki_init_exception();
philpem@0 1778 m68ki_stack_frame_0000(REG_PC, sr, EXCEPTION_FORMAT_ERROR);
philpem@0 1779 m68ki_jump_vector(EXCEPTION_FORMAT_ERROR);
philpem@0 1780
philpem@0 1781 /* Use up some clock cycles and undo the instruction's cycles */
philpem@0 1782 USE_CYCLES(CYC_EXCEPTION[EXCEPTION_FORMAT_ERROR] - CYC_INSTRUCTION[REG_IR]);
philpem@0 1783 }
philpem@0 1784
philpem@0 1785 /* Exception for address error */
philpem@0 1786 INLINE void m68ki_exception_address_error(void)
philpem@0 1787 {
philpem@0 1788 /* Not emulated yet */
philpem@0 1789 }
philpem@0 1790
philpem@0 1791
philpem@0 1792 /* Service an interrupt request and start exception processing */
philpem@0 1793 void m68ki_exception_interrupt(uint int_level)
philpem@0 1794 {
philpem@0 1795 uint vector;
philpem@0 1796 uint sr;
philpem@0 1797 uint new_pc;
philpem@0 1798
philpem@0 1799 /* Turn off the stopped state */
philpem@0 1800 CPU_STOPPED &= ~STOP_LEVEL_STOP;
philpem@0 1801
philpem@0 1802 /* If we are halted, don't do anything */
philpem@0 1803 if(CPU_STOPPED)
philpem@0 1804 return;
philpem@0 1805
philpem@0 1806 /* Acknowledge the interrupt */
philpem@0 1807 vector = m68ki_int_ack(int_level);
philpem@0 1808
philpem@0 1809 /* Get the interrupt vector */
philpem@0 1810 if(vector == M68K_INT_ACK_AUTOVECTOR)
philpem@0 1811 /* Use the autovectors. This is the most commonly used implementation */
philpem@0 1812 vector = EXCEPTION_INTERRUPT_AUTOVECTOR+int_level;
philpem@0 1813 else if(vector == M68K_INT_ACK_SPURIOUS)
philpem@0 1814 /* Called if no devices respond to the interrupt acknowledge */
philpem@0 1815 vector = EXCEPTION_SPURIOUS_INTERRUPT;
philpem@0 1816 else if(vector > 255)
philpem@0 1817 {
philpem@0 1818 M68K_DO_LOG_EMU((M68K_LOG_FILEHANDLE "%s at %08x: Interrupt acknowledge returned invalid vector $%x\n",
philpem@0 1819 m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC), vector));
philpem@0 1820 return;
philpem@0 1821 }
philpem@0 1822
philpem@0 1823 /* Start exception processing */
philpem@0 1824 sr = m68ki_init_exception();
philpem@0 1825
philpem@0 1826 /* Set the interrupt mask to the level of the one being serviced */
philpem@0 1827 FLAG_INT_MASK = int_level<<8;
philpem@0 1828
philpem@0 1829 /* Get the new PC */
philpem@0 1830 new_pc = m68ki_read_data_32((vector<<2) + REG_VBR);
philpem@0 1831
philpem@0 1832 /* If vector is uninitialized, call the uninitialized interrupt vector */
philpem@0 1833 if(new_pc == 0)
philpem@0 1834 new_pc = m68ki_read_data_32((EXCEPTION_UNINITIALIZED_INTERRUPT<<2) + REG_VBR);
philpem@0 1835
philpem@0 1836 /* Generate a stack frame */
philpem@0 1837 m68ki_stack_frame_0000(REG_PC, sr, vector);
philpem@0 1838 if(FLAG_M && CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
philpem@0 1839 {
philpem@0 1840 /* Create throwaway frame */
philpem@0 1841 m68ki_set_sm_flag(FLAG_S); /* clear M */
philpem@0 1842 sr |= 0x2000; /* Same as SR in master stack frame except S is forced high */
philpem@0 1843 m68ki_stack_frame_0001(REG_PC, sr, vector);
philpem@0 1844 }
philpem@0 1845
philpem@0 1846 m68ki_jump(new_pc);
philpem@0 1847
philpem@0 1848 /* Defer cycle counting until later */
philpem@0 1849 CPU_INT_CYCLES += CYC_EXCEPTION[vector];
philpem@0 1850
philpem@0 1851 #if !M68K_EMULATE_INT_ACK
philpem@0 1852 /* Automatically clear IRQ if we are not using an acknowledge scheme */
philpem@0 1853 CPU_INT_LEVEL = 0;
philpem@0 1854 #endif /* M68K_EMULATE_INT_ACK */
philpem@0 1855 }
philpem@0 1856
philpem@0 1857
philpem@0 1858 /* ASG: Check for interrupts */
philpem@0 1859 INLINE void m68ki_check_interrupts(void)
philpem@0 1860 {
philpem@0 1861 if(CPU_INT_LEVEL > FLAG_INT_MASK)
philpem@0 1862 m68ki_exception_interrupt(CPU_INT_LEVEL>>8);
philpem@0 1863 }
philpem@0 1864
philpem@0 1865
philpem@0 1866
philpem@0 1867 /* ======================================================================== */
philpem@0 1868 /* ============================== END OF FILE ============================= */
philpem@0 1869 /* ======================================================================== */
philpem@0 1870
philpem@0 1871 #endif /* M68KCPU__HEADER */