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