src/musashi/m68kcpu.h

Fri, 12 Apr 2013 16:26:25 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Fri, 12 Apr 2013 16:26:25 +0100
branch
experimental_memory_mapper_v2
changeset 144
609707511166
parent 128
3246b74d96bc
permissions
-rw-r--r--

Don't set PS1 if there is a level-7 interrupt or bus error

PS1 should only be set if the page was originally present (PS1 or PS0 set). If
PS0 and PS1 are clear (page not present) then do NOT set PS1.

Once again the TRM is blatantly and spectacularly wrong...

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