|
|
1.1.1.3 ! root 1: /* $Id: m68k-execute.c,v 1.20 2005/04/30 15:18:33 fredette Exp $ */ 1.1 root 2: 1.1.1.2 root 3: /* ic/m68k/m68k-execute.c - executes Motorola 68k instructions: */ 1.1 root 4: 1.1.1.2 root 5: /* 6: * Copyright (c) 2002, 2003 Matt Fredette 7: * All rights reserved. 8: * 9: * Redistribution and use in source and binary forms, with or without 10: * modification, are permitted provided that the following conditions 11: * are met: 12: * 1. Redistributions of source code must retain the above copyright 13: * notice, this list of conditions and the following disclaimer. 14: * 2. Redistributions in binary form must reproduce the above copyright 15: * notice, this list of conditions and the following disclaimer in the 16: * documentation and/or other materials provided with the distribution. 17: * 3. All advertising materials mentioning features or use of this software 18: * must display the following acknowledgement: 19: * This product includes software developed by Matt Fredette. 20: * 4. The name of the author may not be used to endorse or promote products 21: * derived from this software without specific prior written permission. 22: * 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33: * POSSIBILITY OF SUCH DAMAGE. 34: */ 35: 1.1.1.3 ! root 36: _TME_RCSID("$Id: m68k-execute.c,v 1.20 2005/04/30 15:18:33 fredette Exp $"); 1.1 root 37: 38: /* includes: */ 39: #include "m68k-auto.h" 40: 41: /* the m68k instruction executor: */ 42: static void 43: _TME_M68K_EXECUTE_NAME(struct tme_m68k *ic) 44: { 45: #undef _TME_M68K_SEQUENCE_RESTARTING 46: #undef _TME_M68K_INSN_FETCH_SAVE 47: #ifdef _TME_M68K_EXECUTE_FAST 48: struct tme_m68k_tlb *tlb; 1.1.1.3 ! root 49: const tme_uint8_t *emulator_load, *emulator_load_last; ! 50: const tme_uint8_t *emulator_load_start; ! 51: tme_uint16_t insn_fetch_sizes; 1.1 root 52: #define _TME_M68K_INSN_FETCH_SAVE \ 53: do { \ 54: ic->_tme_m68k_insn_buffer_fetch_total = emulator_load - emulator_load_start; \ 55: ic->_tme_m68k_insn_buffer_fetch_sizes = insn_fetch_sizes; \ 56: } while (/* CONSTCOND */ 0) 57: #define _TME_M68K_SEQUENCE_RESTARTING (FALSE) 58: #else /* !_TME_M68K_EXECUTE_FAST */ 59: unsigned int exceptions; 60: tme_uint32_t linear_pc; 61: #define _TME_M68K_INSN_FETCH_SAVE \ 62: do { \ 63: } while (/* CONSTCOND */ 0) 64: #define _TME_M68K_SEQUENCE_RESTARTING TME_M68K_SEQUENCE_RESTARTING 65: #endif /* !_TME_M68K_EXECUTE_FAST */ 66: #if (_TME_M68K_EXECUTE_CPU == TME_M68K_M68020) || (_TME_M68K_EXECUTE_CPU == TME_M68K_M68030) 67: unsigned int eai_function_code; 68: int ea_post_index; 69: unsigned int ea_i_is; 1.1.1.3 ! root 70: tme_uint32_t ea_od; ! 71: unsigned int src_specifier; 1.1 root 72: #else /* !TME_M68K_M68020 && !TME_M68K_M68030 */ 73: #define eai_function_code ea_function_code 74: #endif /* !TME_M68K_M68020 && !TME_M68K_M68030 */ 75: unsigned int function_code_program; 76: unsigned int function_code_data; 77: tme_uint16_t opw, extword; 78: void (*func) _TME_P((struct tme_m68k *, void *, void *)); 1.1.1.3 ! root 79: tme_uint32_t params; 1.1 root 80: unsigned int first_ea_extword_offset; 1.1.1.3 ! root 81: int ea_size; 1.1 root 82: int ea_reg, ea_pre_index; 83: unsigned int ea_index_long, ea_index_scale; 84: tme_uint32_t ea_address; 85: unsigned int ea_function_code; 1.1.1.3 ! root 86: tme_int32_t ea_bd; 1.1 root 87: tme_uint32_t imm32; 88: tme_uint16_t transfer_next_before; 89: int rc; 90: 1.1.1.3 ! root 91: /* silence gcc -Wuninitialized: */ ! 92: ea_size = 0; ! 93: 1.1 root 94: /* get the function codes. if the privilege ever changes as a 95: result of any instruction, we must redispatch: */ 96: if (TME_M68K_PRIV(ic)) { 97: function_code_program = TME_M68K_FC_SP; 98: function_code_data = TME_M68K_FC_SD; 99: } 100: else { 101: function_code_program = TME_M68K_FC_UP; 102: function_code_data = TME_M68K_FC_UD; 103: } 104: 1.1.1.2 root 105: /* if we have used up our burst: */ 106: if (ic->_tme_m68k_instruction_burst_remaining == 0) { 107: 108: /* start a new burst: */ 109: ic->_tme_m68k_instruction_burst_remaining 110: = ic->_tme_m68k_instruction_burst; 111: 112: /* if this is a cooperative threading system, yield: */ 113: #ifdef TME_THREADS_COOPERATIVE 114: tme_thread_yield(); 115: #endif /* TME_THREADS_COOPERATIVE */ 116: } 117: 1.1 root 118: #ifdef _TME_M68K_EXECUTE_FAST 119: 120: /* get our instruction TLB entry and reload it: */ 121: tlb = TME_ATOMIC_READ(struct tme_m68k_tlb *, ic->_tme_m68k_itlb); 122: if (!TME_M68K_TLB_OK_FAST_READ(tlb, function_code_program, ic->tme_m68k_ireg_pc, ic->tme_m68k_ireg_pc)) { 123: tme_m68k_tlb_fill(ic, tlb, 124: function_code_program, 125: ic->tme_m68k_ireg_pc, 126: TME_BUS_CYCLE_READ); 127: } 128: 129: /* if we have to go slow, run the slow executor: */ 130: if (TME_M68K_SEQUENCE_RESTARTING 131: || tme_m68k_go_slow(ic)) { 132: return (_TME_M68K_EXECUTE_SLOW(ic)); 133: } 134: 135: /* set up to do fast reads from the instruction TLB entry: */ 136: emulator_load_last = tlb->tme_m68k_tlb_emulator_off_read + TME_ATOMIC_READ(tme_bus_addr_t, tlb->tme_m68k_tlb_linear_last); 137: ic->_tme_m68k_group0_hook = tme_m68k_group0_hook_fast; 138: #else /* !_TME_M68K_EXECUTE_FAST */ 139: 140: /* set up to do slow reads from the instruction TLB entry: */ 141: ic->_tme_m68k_group0_hook = NULL; 142: #endif /* !_TME_M68K_EXECUTE_FAST */ 143: 144: /* the execution loop: */ 145: for (;;) { 146: 147: /* reset for this instruction: */ 148: #ifdef _TME_M68K_EXECUTE_FAST 149: if (__tme_predict_false(TME_ATOMIC_READ(tme_bus_addr_t, tlb->tme_m68k_tlb_linear_last) == 0)) { 150: tme_m68k_redispatch(ic); 151: } 152: emulator_load_start = emulator_load = tlb->tme_m68k_tlb_emulator_off_read + ic->tme_m68k_ireg_pc; 1.1.1.3 ! root 153: insn_fetch_sizes = 0; 1.1 root 154: assert(TME_M68K_TLB_OK_FAST_READ(tlb, function_code_program, ic->tme_m68k_ireg_pc, ic->tme_m68k_ireg_pc) 155: || (emulator_load - 1) == emulator_load_last); 156: tme_m68k_verify_begin(ic, emulator_load_start); 157: #else /* !_TME_M68K_EXECUTE_FAST */ 158: linear_pc = ic->tme_m68k_ireg_pc; 159: ic->_tme_m68k_insn_buffer_off = 0; 1.1.1.3 ! root 160: ic->_tme_m68k_insn_buffer_fetch_total = 0; ! 161: ic->_tme_m68k_insn_buffer_fetch_sizes = 0; 1.1 root 162: exceptions = 0; 1.1.1.3 ! root 163: if (__tme_predict_false((ic->tme_m68k_ireg_sr & ic->_tme_m68k_sr_mask_t) == TME_M68K_FLAG_T1)) { ! 164: ic->tme_m68k_ireg_pc_last = ic->tme_m68k_ireg_pc; ! 165: exceptions |= TME_M68K_EXCEPTION_TRACE; 1.1 root 166: } 167: tme_m68k_verify_begin(ic, NULL); 168: #endif /* _TME_M68K_EXECUTE_FAST */ 169: #ifdef _TME_M68K_VERIFY 170: if (ic->tme_m68k_ireg_pc == 0x6000) { 171: tme_m68k_verify_hook(); 172: } 173: #endif 1.1.1.3 ! root 174: #ifdef _TME_M68K_STATS ! 175: ic->tme_m68k_stats.tme_m68k_stats_insns_total++; ! 176: #ifndef _TME_M68K_EXECUTE_FAST ! 177: ic->tme_m68k_stats.tme_m68k_stats_insns_slow++; ! 178: #endif /* !_TME_M68K_EXECUTE_FAST */ ! 179: #endif /* _TME_M68K_STATS */ 1.1 root 180: first_ea_extword_offset = sizeof(opw); 1.1.1.2 root 181: ic->_tme_m68k_instruction_burst_remaining--; 1.1 root 182: 183: /* fetch and decode the first word of this instruction: */ 184: _TME_M68K_EXECUTE_FETCH_U16(opw); 185: ic->_tme_m68k_insn_opcode = opw; 1.1.1.3 ! root 186: params = _TME_M68K_EXECUTE_OPMAP[opw]; ! 187: func = tme_m68k_opcode_insns[TME_M68K_OPCODE_INSN_WHICH(params)]; ! 188: ! 189: /* now that we no longer need the insn index part of the params, ! 190: replace it with the least significant bits of the opcode, which ! 191: contain any EA mode and reg fields: */ ! 192: TME_FIELD_MASK_DEPOSITU(params, ! 193: TME_M68K_OPCODE_INSN_MASK, ! 194: (opw & (TME_M68K_OPCODE_INSN_MASK / TME_M68K_OPCODE_INSN(1)))); 1.1 root 195: 1.1.1.3 ! root 196: /* if this is a special opcode: */ ! 197: if (__tme_predict_false((params & TME_M68K_OPCODE_SPECOP) != 0)) { ! 198: 1.1 root 199: #if (_TME_M68K_EXECUTE_CPU == TME_M68K_M68020) || (_TME_M68K_EXECUTE_CPU == TME_M68K_M68030) 1.1.1.3 ! root 200: ! 201: /* a general floating-point instruction: */ ! 202: if (__tme_predict_false((opw & 0xffc0) == 0xf200)) { ! 203: ! 204: /* if there is no FPU present, or if it isn't enabled: */ ! 205: if (__tme_predict_false(!ic->tme_m68k_fpu_enabled)) { ! 206: ! 207: /* mark this instruction as illegal and use an FPgen command ! 208: word of zero: */ ! 209: func = tme_m68k_illegal; ! 210: extword = 0; 1.1 root 211: } 1.1.1.3 ! root 212: ! 213: /* otherwise, there is an FPU present and it is enabled: */ ! 214: else { ! 215: ! 216: /* fetch the FPgen command word: */ ! 217: _TME_M68K_EXECUTE_FETCH_U16(ic->_tme_m68k_insn_specop); ! 218: first_ea_extword_offset = 4; ! 219: ! 220: /* temporarily store the FPgen command word in extword: */ ! 221: extword = ic->_tme_m68k_insn_specop; ! 222: } ! 223: ! 224: /* the goal here is not to decide whether or not an FPgen ! 225: instruction is legal, although some illegal instructions ! 226: are caught. the goal is to only decide if this FPgen ! 227: instruction uses the EA field. ! 228: ! 229: we need to know this here because only the executer can ! 230: calculate all memory EAs (i.e., absolute addresses, ! 231: indirect addresses, PC-relative addresses, etc.) and fetch ! 232: immediates. ! 233: ! 234: in general, all other decisions about whether or not an ! 235: instruction is legal (including whether or not certain EAs ! 236: are legal, like data register direct or address register ! 237: direct) or how to dispatch it is done somewhere else. ! 238: ! 239: all legal FPgen instructions that use the EA field are ! 240: handled by one of the following ifs. all illegal FPgen ! 241: instructions, and all FPgen instructions that do not use ! 242: the EA field are handled by the final unconditional else ! 243: clause that cancels memory EA calculation and immediate ! 244: fetching. ! 245: ! 246: for those FPgen instructions that do use the EA field, they ! 247: either leave the EA cycles unchanged, as TME_M68K_OPCODE_EA_READ, to ! 248: indicate that they read the EA, or they change it to ! 249: TME_M68K_OPCODE_EA_WRITE to indicate that they write the EA. ! 250: additionally, they either flag any immediate operand as ! 251: illegal, fetch it themselves, or specify its size for the ! 252: normal immediate fetching code to use: */ ! 253: ! 254: /* m68k-iset.txt must assume that any EA is not written: */ ! 255: assert (!TME_M68K_OPCODE_HAS_EA(params) ! 256: || ((params ! 257: & (TME_M68K_OPCODE_EA_READ ! 258: | TME_M68K_OPCODE_EA_WRITE)) ! 259: == TME_M68K_OPCODE_EA_READ)); ! 260: ! 261: /* m68k-iset.txt must assume that any immediate is 32 bits: */ ! 262: assert (!TME_M68K_OPCODE_HAS_IMM(params) ! 263: || (params & (TME_M68K_OPCODE_IMM_16 | TME_M68K_OPCODE_IMM_32)) == TME_M68K_OPCODE_IMM_32); ! 264: ! 265: /* if this is an FMOVE or FMOVEM of floating-point control ! 266: registers (command word pattern 10dr rr00 0000 0000): */ ! 267: if ((extword & 0xc3ff) == 0x8000) { ! 268: ! 269: /* override the function: */ ! 270: func = tme_m68k_fmovemctl; ! 271: ! 272: /* if this is a register-to-memory operation: */ ! 273: if (extword & TME_BIT(13)) { ! 274: ! 275: /* any EA must be writable: */ ! 276: params |= TME_M68K_OPCODE_EA_WRITE; ! 277: } ! 278: ! 279: /* otherwise, this is a memory-to-register operation: */ ! 280: else { ! 281: ! 282: /* if this instruction has an immediate, and this ! 283: instruction is moving multiple control registers, this ! 284: is an illegal instruction: */ ! 285: /* NB the trick we use to see if multiple bits are set in ! 286: the rrr field - we subtract one from the base of the ! 287: rrr field (0x0400), binary-AND the result with extword, ! 288: and mask off all bits except the rrr field. this ! 289: result will be nonzero iff the rrr field has multiple ! 290: bits set: */ ! 291: if (__tme_predict_false(TME_M68K_OPCODE_HAS_IMM(params) ! 292: && ((extword & (extword - 0x0400)) & 0x1c00))) { ! 293: func = tme_m68k_illegal; ! 294: } ! 295: } 1.1 root 296: } 1.1.1.3 ! root 297: ! 298: /* if this is an FMOVEM ! 299: (command word pattern 11dm m000 rrrr rrrr): */ ! 300: else if ((extword & 0xc700) == 0xc000) { ! 301: ! 302: /* override the function: */ ! 303: func = tme_m68k_fmovem; ! 304: ! 305: /* if this instruction has an immediate, this is an ! 306: illegal instruction: */ ! 307: if (__tme_predict_false(TME_M68K_OPCODE_HAS_IMM(params))) { ! 308: func = tme_m68k_illegal; ! 309: } ! 310: ! 311: /* if this is a register-to-memory operation: */ ! 312: if (extword & TME_BIT(13)) { ! 313: ! 314: /* any EA must be writable: */ ! 315: params |= TME_M68K_OPCODE_EA_WRITE; ! 316: } 1.1 root 317: } 1.1.1.3 ! root 318: ! 319: /* if this is a register-to-memory FMOVE instruction ! 320: (command word pattern 011d ddss skkk kkkk): */ ! 321: else if ((extword & 0xe000) == 0x6000) { ! 322: ! 323: /* override the function: */ ! 324: func = tme_m68k_fmove_rm; ! 325: ! 326: /* any EA must be writable: */ ! 327: params |= TME_M68K_OPCODE_EA_WRITE; ! 328: } ! 329: ! 330: /* if this is a memory-to-register true FPgen instruction ! 331: (command word pattern 010s ssdd dooo oooo): */ ! 332: else if ((extword & 0xe000) == 0x4000 ! 333: && (_tme_m6888x_fpgen_opmode_bitmap[TME_FIELD_EXTRACTU(extword, 0, 7) / 8] ! 334: & (1 << (TME_FIELD_EXTRACTU(extword, 0, 7) % 8))) ! 335: && TME_FIELD_EXTRACTU(extword, 10, 3) != TME_M6888X_TYPE_INVALID) { ! 336: ! 337: /* if this instruction has an immediate: */ ! 338: if (TME_M68K_OPCODE_HAS_IMM(params)) { ! 339: ! 340: /* if the source specifier is for a size that the normal ! 341: immediate fetching code can handle, let it handle it, ! 342: otherwise we have to fetch the immediate ourselves: */ ! 343: ! 344: /* m68k-iset.txt must have specified the EA operand to be ! 345: operand one: */ ! 346: assert((void *) TME_M68K_OPCODE_OP1_WHICH(ic, params) ! 347: == (void *) &ic->tme_m68k_ireg_uint32(TME_M68K_IREG_IMM32 + 0)); ! 348: ! 349: /* dispatch on the source specifier: */ ! 350: src_specifier = TME_FIELD_EXTRACTU(extword, 10, 3); ! 351: switch (src_specifier) { ! 352: ! 353: /* we can let the normal immediate fetching code fetch ! 354: word integers, long-word integers, and ! 355: single-precision reals: */ ! 356: default: ! 357: assert (func == tme_m68k_illegal); ! 358: /* FALLTHROUGH */ ! 359: case TME_M6888X_TYPE_WORD: ! 360: /* we can simply flip TME_M68K_OPCODE_IMM_16 and ! 361: TME_M68K_OPCODE_IMM_32 to select a 16-bit immediate; ! 362: we know that only TME_M68K_OPCODE_IMM_32 is set, ! 363: thanks to the assert we did at the beginning of the ! 364: fpgen specop handling: */ ! 365: params ^= (TME_M68K_OPCODE_IMM_16 | TME_M68K_OPCODE_IMM_32); ! 366: /* FALLTHROUGH */ ! 367: case TME_M6888X_TYPE_LONG: ! 368: case TME_M6888X_TYPE_SINGLE: ! 369: break; ! 370: case TME_M6888X_TYPE_EXTENDED80: ! 371: case TME_M6888X_TYPE_PACKEDDEC: ! 372: case TME_M6888X_TYPE_DOUBLE: ! 373: _TME_M68K_EXECUTE_FETCH_U32(imm32); ! 374: ic->tme_m68k_ireg_uint32(TME_M68K_IREG_IMM32 + 0) = imm32; ! 375: _TME_M68K_EXECUTE_FETCH_U32(imm32); ! 376: ic->tme_m68k_ireg_uint32(TME_M68K_IREG_IMM32 + 1) = imm32; ! 377: if (src_specifier != TME_M6888X_TYPE_DOUBLE) { ! 378: _TME_M68K_EXECUTE_FETCH_U32(imm32); ! 379: ic->tme_m68k_ireg_uint32(TME_M68K_IREG_IMM32 + 2) = imm32; ! 380: } ! 381: /* we only need to clear TME_M68K_OPCODE_IMM_32 here to ! 382: cancel the later immediate fetching; we know that ! 383: only TME_M68K_OPCODE_IMM_32 is set, thanks to the ! 384: assert we did at the beginning of the fpgen specop ! 385: handling: */ ! 386: params &= ~TME_M68K_OPCODE_IMM_32; ! 387: break; ! 388: case TME_M6888X_TYPE_BYTE: ! 389: _TME_M68K_EXECUTE_FETCH_U16(imm32); ! 390: ic->tme_m68k_ireg_uint32(TME_M68K_IREG_IMM32 + 0) = TME_EXT_S8_U32((tme_int8_t) imm32); ! 391: /* we only need to clear TME_M68K_OPCODE_IMM_32 here to ! 392: cancel the later immediate fetching; we know that ! 393: only TME_M68K_OPCODE_IMM_32 is set, thanks to the ! 394: assert we did at the beginning of the fpgen specop ! 395: handling: */ ! 396: params &= ~TME_M68K_OPCODE_IMM_32; ! 397: break; ! 398: } ! 399: } 1.1 root 400: } 1.1.1.3 ! root 401: ! 402: /* otherwise, this FPgen instruction does not need any memory ! 403: EA or immediate. we'll decide later if this instruction is ! 404: actually legal: */ 1.1 root 405: else { 1.1.1.3 ! root 406: /* cancel immediate fetching and all EA work: */ ! 407: params &= ~(TME_M68K_OPCODE_IMM_32 ! 408: | TME_M68K_OPCODE_IMM_16 ! 409: | TME_M68K_OPCODE_EA_SIZE_MASK ! 410: | TME_M68K_OPCODE_EA_READ ! 411: | TME_M68K_OPCODE_EA_WRITE); ! 412: } ! 413: ! 414: /* if this instruction has already been marked as illegal, or ! 415: this EA must be writable, and this is a PC-relative or ! 416: immediate EA, this instruction is illegal: */ ! 417: if (__tme_predict_false(func == tme_m68k_illegal ! 418: || (params & TME_M68K_OPCODE_EA_WRITE ! 419: && (TME_M68K_OPCODE_HAS_IMM(params) ! 420: || (TME_M68K_OPCODE_EA_MODE_WHICH(params) == 7 ! 421: && (TME_M68K_OPCODE_EA_REG_WHICH(params) & 6) == 2))))) { ! 422: func = tme_m68k_illegal; ! 423: /* cancel immediate fetching and all EA work: */ ! 424: params &= ~(TME_M68K_OPCODE_IMM_32 ! 425: | TME_M68K_OPCODE_IMM_16 ! 426: | TME_M68K_OPCODE_EA_SIZE_MASK ! 427: | TME_M68K_OPCODE_EA_READ ! 428: | TME_M68K_OPCODE_EA_WRITE); ! 429: } ! 430: ! 431: /* otherwise, if this instruction has a memory EA: */ ! 432: else if (params & TME_M68K_OPCODE_EA_READ) { ! 433: ! 434: /* override any m68k-iset.txt guess about the operand ! 435: size, and cancel all memory cycles. the instruction ! 436: itself will do the actual operand reading and any address ! 437: register postincrement or predecrement: */ ! 438: params = ! 439: ((params ! 440: & ~(TME_M68K_OPCODE_EA_READ ! 441: | TME_M68K_OPCODE_EA_WRITE ! 442: | TME_M68K_OPCODE_EA_SIZE_MASK)) ! 443: | TME_M68K_OPCODE_EA_UNSIZED); 1.1 root 444: } 445: 1.1.1.3 ! root 446: /* otherwise, this instruction does not have a memory EA: */ ! 447: else { 1.1 root 448: 1.1.1.3 ! root 449: /* cancel all EA work: */ ! 450: params &= ~(TME_M68K_OPCODE_EA_SIZE_MASK ! 451: | TME_M68K_OPCODE_EA_READ ! 452: | TME_M68K_OPCODE_EA_WRITE); ! 453: } ! 454: } ! 455: else ! 456: #endif /* TME_M68K_M68020 || TME_M68K_M68030 */ 1.1 root 457: 1.1.1.3 ! root 458: /* if this is not a memory-to-memory move instruction: */ ! 459: if ((params & TME_M68K_OPCODE_EA_Y) == 0) { 1.1 root 460: 1.1.1.3 ! root 461: /* many instructions have a single special extension word: */ ! 462: _TME_M68K_EXECUTE_FETCH_U16(ic->_tme_m68k_insn_specop); ! 463: first_ea_extword_offset = 4; ! 464: } 1.1 root 465: } 1.1.1.3 ! root 466: 1.1 root 467: /* get any immediate operand: */ 1.1.1.3 ! root 468: if (__tme_predict_false(TME_M68K_OPCODE_HAS_IMM(params))) { ! 469: if (params & TME_M68K_OPCODE_IMM_16) { 1.1 root 470: _TME_M68K_EXECUTE_FETCH_S16(imm32); 471: } 1.1.1.3 ! root 472: else { ! 473: _TME_M68K_EXECUTE_FETCH_U32(imm32); ! 474: } ! 475: ic->tme_m68k_ireg_imm32 = imm32; ! 476: } 1.1 root 477: 478: /* loop over up to two effective addresses calculations. this 479: initializes for the normal, single effective address: */ 1.1.1.3 ! root 480: while (TME_M68K_OPCODE_HAS_EA(params)) { ! 481: ! 482: /* if this EA is described by the alternate EA mode and reg ! 483: fields, copy them into the EA mode and reg fields in ! 484: params: */ ! 485: if (__tme_predict_false((params ! 486: & (TME_M68K_OPCODE_EA_Y | TME_M68K_OPCODE_SPECOP)) ! 487: == TME_M68K_OPCODE_EA_Y)) { ! 488: ! 489: /* reload to write the other memory EA: */ ! 490: params ! 491: = ((params ! 492: & ~(TME_M68K_OPCODE_EA_MODE_MASK ! 493: | TME_M68K_OPCODE_EA_REG_MASK ! 494: | TME_M68K_OPCODE_EA_READ ! 495: | TME_M68K_OPCODE_EA_Y)) ! 496: | TME_M68K_OPCODE_EA_MODE(TME_FIELD_EXTRACTU(opw, 6, 3)) ! 497: | TME_M68K_OPCODE_EA_REG(TME_FIELD_EXTRACTU(opw, 9, 3)) ! 498: | TME_M68K_OPCODE_EA_WRITE); ! 499: } ! 500: ! 501: /* get the reg, size, and function code of this EA: */ ! 502: ea_reg = TME_M68K_IREG_A0 + TME_M68K_OPCODE_EA_REG_WHICH(params); ! 503: ea_size = TME_M68K_OPCODE_EA_SIZE_WHICH(params); ! 504: ea_function_code = function_code_data; 1.1 root 505: 506: /* this EA must have either no size, or be exactly one, two, or 507: four bytes: */ 508: assert(ea_size == TME_M68K_SIZE_UNSIZED 509: || ea_size == TME_M68K_SIZE_8 510: || ea_size == TME_M68K_SIZE_16 511: || ea_size == TME_M68K_SIZE_32); 512: 513: /* for the effective address predecrement and postincrement 514: modes, we require that these size macros correspond exactly 515: to the number of bytes, that the %a7 register number be 15, 516: and that the ea reg not be greater than %a7: */ 517: #if TME_M68K_SIZE_UNSIZED != 0 518: #error "TME_M68K_SIZE_UNSIZED must be 0" 519: #endif 520: #if TME_M68K_SIZE_8 != 1 521: #error "TME_M68K_SIZE_8 must be 1" 522: #endif 523: #if TME_M68K_SIZE_16 != 2 524: #error "TME_M68K_SIZE_16 must be 2" 525: #endif 526: #if TME_M68K_SIZE_32 != 4 527: #error "TME_M68K_SIZE_32 must be 4" 528: #endif 529: #if TME_M68K_IREG_A7 != 15 530: #error "TME_M68K_IREG_A7 must be 15" 531: #endif 532: assert(ea_reg <= TME_M68K_IREG_A7); 533: #define TME_M68K_AREG_INCREMENT(areg, size) \ 534: (((((areg) + 1) / (TME_M68K_IREG_A7 + 1)) & (size)) + (size)) 535: 536: /* initialize ea_address to silence -Wuninitialized: */ 537: ea_address = 0; 538: 539: /* set the EA inner function code: */ 540: eai_function_code = ea_function_code; 541: 542: /* dispatch on the mode: */ 1.1.1.3 ! root 543: switch (TME_M68K_OPCODE_EA_MODE_WHICH(params)) { 1.1 root 544: 545: /* address register indirect: */ 546: case 2: 547: ea_address = ic->tme_m68k_ireg_uint32(ea_reg); 548: break; 549: 550: /* address register indirect postincrement: */ 551: case 3: 552: /* if we are not restarting, set the effective address: */ 553: if (!_TME_M68K_SEQUENCE_RESTARTING) { 554: ea_address = ic->tme_m68k_ireg_uint32(ea_reg); 555: ic->tme_m68k_ireg_uint32(ea_reg) += TME_M68K_AREG_INCREMENT(ea_reg, ea_size); 556: } 557: break; 558: 559: /* address register indirect predecrement: */ 560: case 4: 561: /* if we are not restarting, set the effective address: */ 562: if (!_TME_M68K_SEQUENCE_RESTARTING) { 563: ic->tme_m68k_ireg_uint32(ea_reg) -= TME_M68K_AREG_INCREMENT(ea_reg, ea_size); 564: ea_address = ic->tme_m68k_ireg_uint32(ea_reg); 565: } 566: break; 567: 568: /* address register indirect with 16-bit displacement: */ 569: case 5: 570: _TME_M68K_EXECUTE_FETCH_S16(ea_bd); 571: ea_address = ic->tme_m68k_ireg_uint32(ea_reg) + ea_bd; 572: break; 573: 574: /* miscellaneous modes: */ 575: case 7: 576: 577: /* absolute short addressing: */ 578: if (ea_reg == TME_M68K_IREG_A0) { 579: _TME_M68K_EXECUTE_FETCH_S16(ea_address); 580: break; 581: } 582: 583: /* absolute long addressing: */ 584: if (ea_reg == TME_M68K_IREG_A1) { 585: _TME_M68K_EXECUTE_FETCH_S32(ea_address); 586: break; 587: } 588: 589: /* program counter indirect with 16-bit displacement: */ 590: if (ea_reg == TME_M68K_IREG_A2) { 591: _TME_M68K_EXECUTE_FETCH_S16(ea_bd); 592: /* XXX simulates preincremented pc: */ 593: ea_address = ic->tme_m68k_ireg_pc + first_ea_extword_offset + ea_bd; 594: ea_function_code = function_code_program; 595: break; 596: } 597: 598: /* everything else is just like mode 6 except with the PC as 599: the base register: */ 600: assert (ea_reg == TME_M68K_IREG_A3); 601: ea_reg = TME_M68K_IREG_PC; 602: eai_function_code = function_code_program; 603: /* FALLTHROUGH */ 604: 605: /* various indexed modes: */ 606: case 6: 607: 608: /* fetch the extension word and take it apart. the 68000 and 609: 68010 ignore the scale field in the extension word and always 610: behave as if it is zero: */ 611: _TME_M68K_EXECUTE_FETCH_U16(extword); 612: ea_pre_index = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(extword, 12, 4); 613: ea_index_long = (extword & TME_BIT(11)); 614: #if (_TME_M68K_EXECUTE_CPU == TME_M68K_M68020) || (_TME_M68K_EXECUTE_CPU == TME_M68K_M68030) 615: ea_index_scale = TME_FIELD_EXTRACTU(extword, 9, 2); 616: #else /* !TME_M68K_M68020 && !TME_M68K_M68030 */ 617: ea_index_scale = 0; 618: #endif /* !TME_M68K_M68020 && !TME_M68K_M68030 */ 619: 620: /* if this is a full extension word: */ 1.1.1.3 ! root 621: if (__tme_predict_false(extword & TME_BIT(8))) { 1.1 root 622: #if (_TME_M68K_EXECUTE_CPU == TME_M68K_M68020) || (_TME_M68K_EXECUTE_CPU == TME_M68K_M68030) 623: 624: ea_i_is = TME_FIELD_EXTRACTU(extword, 0, 3); 625: 626: /* optionally suppress the base register: */ 627: if (extword & TME_BIT(7)) { 1.1.1.3 ! root 628: ea_reg = TME_M68K_IREG_ZERO; 1.1 root 629: } 630: 631: /* fetch any base displacement: */ 1.1.1.3 ! root 632: ea_bd = 0; 1.1 root 633: switch (TME_FIELD_EXTRACTU(extword, 4, 2)) { 634: case 0: abort(); 1.1.1.3 ! root 635: case 1: break; 1.1 root 636: case 2: _TME_M68K_EXECUTE_FETCH_S16(ea_bd); break; 637: case 3: _TME_M68K_EXECUTE_FETCH_S32(ea_bd); break; 638: } 639: 640: /* optionally suppress the index register. this is also 641: where we check for combined IS-I/IS fields greater than 642: or equal to 0xc, which are reserved: */ 643: if (extword & TME_BIT(6)) { 1.1.1.3 ! root 644: ea_pre_index = TME_M68K_IREG_ZERO; 1.1 root 645: if (ea_i_is >= 0x4) { 646: abort(); 647: } 648: } 649: 650: /* fetch any outer displacement: */ 1.1.1.3 ! root 651: ea_od = 0; 1.1 root 652: switch (ea_i_is & 3) { 1.1.1.3 ! root 653: case 0: case 1: break; 1.1 root 654: case 2: _TME_M68K_EXECUTE_FETCH_S16(ea_od); break; 655: case 3: _TME_M68K_EXECUTE_FETCH_S32(ea_od); break; 656: } 657: 658: /* dispatch on the I/IS fields: */ 1.1.1.3 ! root 659: ea_post_index = TME_M68K_IREG_ZERO; 1.1 root 660: switch (ea_i_is) { 661: 662: /* no memory indirect action: */ 663: case 0x0: 664: ea_post_index = TME_M68K_IREG_UNDEF; 665: break; 666: 667: /* indirect preindexed with null outer displacement: */ 668: /* indirect preindexed with word outer displacement: */ 669: /* indirect preindexed with long outer displacement: */ 670: case 0x1: case 0x2: case 0x3: 671: break; 672: 673: /* reserved: */ 674: case 0x4: default: abort(); 675: 676: /* indirect postindexed with null outer displacement: */ 677: /* indirect postindexed with word outer displacement: */ 678: /* indirect postindexed with long outer displacement: */ 679: case 0x5: case 0x6: case 0x7: 680: ea_post_index = ea_pre_index; 1.1.1.3 ! root 681: ea_pre_index = TME_M68K_IREG_ZERO; 1.1 root 682: break; 683: } 684: 685: /* preindex and base-displace the original address register 686: to arrive at the indirect EA: */ 687: ea_address = 688: (ic->tme_m68k_ireg_uint32(ea_reg) 689: + ((ea_index_long 690: ? ic->tme_m68k_ireg_int32(ea_pre_index) 691: : ((tme_int32_t) ic->tme_m68k_ireg_int16(ea_pre_index << 1))) 692: << ea_index_scale) 693: + ea_bd 694: + (ea_reg == TME_M68K_IREG_PC 695: /* XXX simulates preincremented pc: */ 696: ? first_ea_extword_offset 697: : 0)); 698: 699: /* if this is a memory indirect, read the indirect EA. 700: don't disturb the EA in the IC state if we're restarting, 701: for two reasons: 702: 703: first, the value in the IC state may belong to some later 704: part of the instruction handling, in which case we must 705: (continue to) preserve it, and 706: 707: second, if the EA in the IC state *is* from this part of 708: the instruction handling, it's correct, while our EA may 709: *not* be correct, since it was generated from IC state 710: that may have changed since the instruction originally 711: started (i.e., address register changes by the user or by 712: our own postincrement/predecrement, or function code 713: register changes by the user): */ 714: if (ea_post_index != TME_M68K_IREG_UNDEF) { 715: if (!_TME_M68K_SEQUENCE_RESTARTING) { 716: ic->_tme_m68k_ea_address = ea_address; 717: ic->_tme_m68k_ea_function_code = eai_function_code; 718: } 719: _TME_M68K_INSN_FETCH_SAVE; 720: tme_m68k_read_mem32(ic, TME_M68K_IREG_MEMY32); 721: ea_address = 722: (ic->tme_m68k_ireg_memy32 723: + ((ea_index_long 724: ? ic->tme_m68k_ireg_int32(ea_post_index) 725: : ((tme_int32_t) ic->tme_m68k_ireg_int16(ea_post_index << 1))) 726: << ea_index_scale) 727: + ea_od); 728: } 729: else { 730: ea_function_code = eai_function_code; 731: } 732: 733: #else /* !TME_M68K_M68020 && !TME_M68K_M68030 */ 734: /* XXX - illegal instruction */ 735: abort(); 736: #endif /* !TME_M68K_M68020 && !TME_M68K_M68030 */ 737: } 738: 739: /* otherwise, this is a brief extension word: */ 740: else { 741: ea_address = 742: (ic->tme_m68k_ireg_uint32(ea_reg) 743: + ((tme_int32_t) ((tme_int8_t) (extword & 0xff))) 744: + ((ea_index_long 745: ? ic->tme_m68k_ireg_int32(ea_pre_index) 746: : ((tme_int32_t) ic->tme_m68k_ireg_int16(ea_pre_index << 1))) 747: << ea_index_scale) 748: + (ea_reg == TME_M68K_IREG_PC 749: /* XXX simulates preincremented pc: */ 750: ? first_ea_extword_offset 751: : 0)); 752: ea_function_code = eai_function_code; 753: } 754: break; 755: 756: default: assert(FALSE); 757: } 758: 759: /* we have calculated the effective address. we don't store it 760: if we're restarting, because it may have been calculated 761: using user-visible registers (address registers and even 762: function code registers!) that the user may have changed (or, 763: in the case of pre/postdecrement EAs, that *we* may have 764: changed) between the bus fault and the instruction restart. 765: when we restart an instruction we *always* want to use the 766: same effective address as before: */ 767: if (!_TME_M68K_SEQUENCE_RESTARTING) { 768: ic->_tme_m68k_ea_address = ea_address; 769: ic->_tme_m68k_ea_function_code = eai_function_code; 770: } 771: 772: /* XXX XXX XXX - if we detect a store to program space, that's an illegal: */ 773: /* XXX but maybe not for moves? */ 1.1.1.3 ! root 774: if (__tme_predict_false(ea_function_code == function_code_program ! 775: && (params & TME_M68K_OPCODE_EA_WRITE) != 0)) { 1.1 root 776: abort(); 777: } 778: 779: /* if we're loading this operand: */ 1.1.1.3 ! root 780: if (params & TME_M68K_OPCODE_EA_READ) { 1.1 root 781: _TME_M68K_INSN_FETCH_SAVE; 782: (*_tme_m68k_read_memx[ea_size])(ic); 783: } 784: 785: /* stop unless this is a memory-to-memory move: */ 1.1.1.3 ! root 786: if (__tme_predict_true(!(params & TME_M68K_OPCODE_EA_Y))) 1.1 root 787: break; 788: 1.1.1.3 ! root 789: /* loop to reload for the other memory EA at the same size: */ ! 790: params &= ~TME_M68K_OPCODE_SPECOP; 1.1 root 791: } 792: 793: /* we've fetched all of the instruction words: */ 794: _TME_M68K_INSN_FETCH_SAVE; 795: 796: /* set the next PC: */ 797: #ifdef _TME_M68K_EXECUTE_FAST 798: ic->tme_m68k_ireg_pc_next = ic->tme_m68k_ireg_pc + (emulator_load - emulator_load_start); 799: #else /* !_TME_M68K_EXECUTE_FAST */ 800: ic->tme_m68k_ireg_pc_next = linear_pc; 801: #endif /* !_TME_M68K_EXECUTE_FAST */ 802: 803: /* if we're not restarting, or if this instruction function can 804: fault, call the instruction function: */ 805: if (!_TME_M68K_SEQUENCE_RESTARTING 806: || (ic->_tme_m68k_mode_flags & TME_M68K_EXECUTION_INST_CANFAULT)) { 807: transfer_next_before = ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_next; 1.1.1.3 ! root 808: (*func)(ic, TME_M68K_OPCODE_OP0_WHICH(ic, params), TME_M68K_OPCODE_OP1_WHICH(ic, params)); 1.1 root 809: assert(!(ic->_tme_m68k_mode_flags & TME_M68K_EXECUTION_INST_CANFAULT) 810: != (ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_next 811: != transfer_next_before)); 812: ic->_tme_m68k_mode_flags &= ~TME_M68K_EXECUTION_INST_CANFAULT; 813: } 814: 815: /* store up to one EA path: */ 1.1.1.3 ! root 816: if ((params & TME_M68K_OPCODE_EA_WRITE) != 0) { 1.1 root 817: (*_tme_m68k_write_memx[ea_size])(ic); 818: } 819: 820: /* an instruction has ended: */ 821: tme_m68k_verify_end(ic, func); 822: 823: /* update the PC: */ 824: ic->tme_m68k_ireg_pc = ic->tme_m68k_ireg_pc_next; 825: TME_M68K_SEQUENCE_START; 826: 827: #ifdef _TME_M68K_EXECUTE_FAST 828: /* if we haven't finished the instruction burst yet, continue: */ 1.1.1.2 root 829: if (__tme_predict_true(ic->_tme_m68k_instruction_burst_remaining != 0)) { 1.1 root 830: continue; 831: } 832: #endif /* _TME_M68K_EXECUTE_FAST */ 833: 834: /* try to acquire the external mutex and check for external 835: resets, halts, or interrupts, and process them along 836: with any internal exceptions: */ 837: rc = tme_mutex_trylock(&ic->tme_m68k_external_mutex); 838: if (TME_THREADS_ERRNO(rc) == TME_OK) { 839: tme_m68k_external_check(ic, 840: #ifdef _TME_M68K_EXECUTE_FAST 841: 0 842: #else /* !_TME_M68K_EXECUTE_FAST */ 843: exceptions 844: #endif /* !_TME_M68K_EXECUTE_FAST */ 845: ); 846: 847: /* unlock the external mutex: */ 848: tme_mutex_unlock(&ic->tme_m68k_external_mutex); 849: } 850: 851: #ifndef _TME_M68K_EXECUTE_FAST 852: 853: /* otherwise, if we have internal exceptions, process them: */ 854: else if (exceptions) { 855: tme_m68k_exception(ic, exceptions); 856: } 857: 858: /* if we can go fast now, go fast: */ 859: if (!tme_m68k_go_slow(ic)) { 860: tme_m68k_redispatch(ic); 861: } 862: 1.1.1.2 root 863: /* otherwise, unless we've used up our burst, continue: */ 864: if (ic->_tme_m68k_instruction_burst_remaining != 0) { 865: continue; 866: } 867: 868: #endif /* !_TME_M68K_EXECUTE_FAST */ 869: 870: /* start a new burst: */ 871: ic->_tme_m68k_instruction_burst_remaining 872: = ic->_tme_m68k_instruction_burst; 1.1 root 873: 874: /* if this is a cooperative threading system, yield: */ 875: #ifdef TME_THREADS_COOPERATIVE 876: tme_thread_yield(); 877: #endif /* TME_THREADS_COOPERATIVE */ 878: 879: } 880: /* NOTREACHED */ 881: 882: #ifdef _TME_M68K_EXECUTE_FAST 883: 884: /* if we get here, we "faulted" trying to fetch an instruction word 885: from host memory. it's possibly not a "real" fault, since this 886: instruction may simply cross a page boundary, but since the fast 887: executor can't restart instructions we have to treat this like a 888: group 0 fault: */ 889: _tme_m68k_fast_fetch_failed: 890: 891: /* mimic a group 0 exception: */ 892: _TME_M68K_INSN_FETCH_SAVE; 893: ic->_tme_m68k_group0_flags = TME_M68K_BUS_CYCLE_FETCH | TME_M68K_BUS_CYCLE_READ; 894: ic->_tme_m68k_group0_function_code = function_code_program; 895: ic->_tme_m68k_group0_address = ic->tme_m68k_ireg_pc + (emulator_load - emulator_load_start); 896: ic->_tme_m68k_group0_sequence = ic->_tme_m68k_sequence; 897: ic->_tme_m68k_group0_sequence._tme_m68k_sequence_transfer_faulted_after = 0; 898: ic->_tme_m68k_group0_buffer_read_size = 0; 899: ic->_tme_m68k_group0_buffer_read_softrr = 0; 900: tme_m68k_group0_hook_fast(ic); 901: ic->_tme_m68k_group0_sequence._tme_m68k_sequence_transfer_faulted = 902: ic->_tme_m68k_group0_sequence._tme_m68k_sequence_transfer_next; 903: 904: /* mimic the rte: */ 905: ic->_tme_m68k_sequence = ic->_tme_m68k_group0_sequence; 906: ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_next = 1; 907: TME_M68K_SEQUENCE_RESTART; 908: 909: tme_m68k_redispatch(ic); 910: /* NOTREACHED */ 911: #endif /* _TME_M68K_EXECUTE_FAST */ 912: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.