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