|
|
1.1.1.3 root 1: /* $Id: m68010.c,v 1.9 2007/02/16 01:40:44 fredette Exp $ */
1.1 root 2:
3: /* ic/m68k/m68010.c - implementation of Motorola 68010 emulation: */
4:
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:
36: #include <tme/common.h>
1.1.1.3 root 37: _TME_RCSID("$Id: m68010.c,v 1.9 2007/02/16 01:40:44 fredette Exp $");
1.1 root 38:
39: /* includes: */
40: #include "m68k-impl.h"
41:
42: /* macros: */
43: #define TME_M68K_SSW8_RR 0x8000
44: #define TME_M68K_SSW8_IF 0x2000
45: #define TME_M68K_SSW8_DF 0x1000
46: #define TME_M68K_SSW8_RM 0x0800
47: #define TME_M68K_SSW8_HI 0x0400
48: #define TME_M68K_SSW8_BX 0x0200
49: #define TME_M68K_SSW8_RW 0x0100
50:
51: /* structures: */
52:
53: /* the format 8 stack frame: */
54: /* XXX we assume that this will pack: */
55: struct tme_m68k_fmt8 {
56:
57: /* the special status word: */
58: tme_uint16_t tme_m68k_fmt8_ssw;
59:
60: /* the faulting address: */
61: tme_uint16_t tme_m68k_fmt8_addr_high;
62: tme_uint16_t tme_m68k_fmt8_addr_low;
63:
64: /* the first unused word: */
65: tme_uint8_t tme_m68k_fmt8_state0[2];
66:
67: /* the data output buffer: */
68: tme_uint8_t tme_m68k_fmt8_dob[2];
69:
70: /* the second unused word: */
71: tme_uint8_t tme_m68k_fmt8_state1[2];
72:
73: /* the data input buffer: */
74: tme_uint8_t tme_m68k_fmt8_dib[2];
75:
76: /* the third unused word: */
77: tme_uint8_t tme_m68k_fmt8_state2[2];
78:
79: /* the instruction input buffer: */
80: tme_uint8_t tme_m68k_fmt8_iib[2];
81:
82: /* the internal information: */
83: tme_uint8_t tme_m68k_fmt8_state3[32];
84: };
85:
86: /* both executors are for the 68010: */
87: #define _TME_M68K_EXECUTE_CPU TME_M68K_M68010
1.1.1.2 root 88: #define _TME_M68K_EXECUTE_OPMAP tme_m68k_opcodes_m68010
1.1 root 89:
90: /* create the slow executor: */
91: #define _TME_M68K_EXECUTE_NAME _tme_m68010_execute_slow
92: #undef _TME_M68K_EXECUTE_FAST
93: #undef _TME_M68K_EXECUTE_SLOW
94: #include "m68k-execute.c"
95: #undef _TME_M68K_EXECUTE_NAME
96: #undef _TME_M68K_EXECUTE_FAST
97: #undef _TME_M68K_EXECUTE_SLOW
98:
99: /* create the fast executor: */
100: #define _TME_M68K_EXECUTE_NAME _tme_m68010_execute
101: #define _TME_M68K_EXECUTE_FAST
102: #define _TME_M68K_EXECUTE_SLOW _tme_m68010_execute_slow
103: #include "m68k-execute.c"
104: #undef _TME_M68K_EXECUTE_NAME
105: #undef _TME_M68K_EXECUTE_FAST
106: #undef _TME_M68K_EXECUTE_SLOW
107:
108: #undef _TME_M68K_EXECUTE_CPU
109:
110: /* m68010 exception processing: */
111: static void
112: _tme_m68010_exception(struct tme_m68k *ic)
113: {
114: tme_uint32_t exceptions;
115: tme_uint8_t raw_state[19 * sizeof(tme_uint16_t)], *raw;
116: unsigned int raw_avail, raw_used;
117: struct tme_m68k_fmt8 fmt8;
118: unsigned int flags;
119: tme_uint8_t function_code;
120: tme_uint16_t ssw;
121:
122: /* get the set of exceptions: */
123: exceptions = ic->_tme_m68k_exceptions;
124:
125: /* a reset exception: */
1.1.1.2 root 126: if (exceptions & TME_M68K_EXCEPTION_RESET) {
1.1 root 127:
128: /* do the common reset processing: */
129: tme_m68k_do_reset(ic);
130: /* NOTREACHED */
131: }
132:
133: /* an address or bus error: */
1.1.1.2 root 134: else if (exceptions & (TME_M68K_EXCEPTION_AERR
135: | TME_M68K_EXCEPTION_BERR)) {
1.1 root 136:
137: /* start the exception processing: */
138: tme_m68k_exception_process_start(ic, 0);
139:
140: /* start assembling the raw data: */
141: raw = raw_state;
142: raw_avail = sizeof(raw_state);
143: #define RAW_PUT(v) \
144: do { \
145: assert(raw_avail >= sizeof(v)); \
146: memcpy(raw, &v, sizeof(v)); \
147: raw += sizeof(v); \
148: raw_avail -= sizeof(v); \
149: } while (/* CONSTCOND */ 0)
150:
151: /* put in the sequence: */
152: raw_used = tme_m68k_sequence_empty(ic, raw, raw_avail);
153: raw += raw_used;
154: raw_avail -= raw_used;
155:
156: /* dispatch on the mode: */
157: switch (ic->_tme_m68k_group0_sequence._tme_m68k_sequence_mode) {
158:
159: case TME_M68K_MODE_EXECUTION:
160:
161: /* put in the instruction buffer: */
162: raw_used = tme_m68k_insn_buffer_empty(ic, raw, raw_avail);
163: raw += raw_used;
164: raw_avail -= raw_used;
165:
166: /* put in the EA address: */
167: function_code = ic->_tme_m68k_ea_function_code;
168: RAW_PUT(function_code);
169: RAW_PUT(ic->_tme_m68k_ea_address);
170:
171: /* put in the memory X and Y buffers: */
172: RAW_PUT(ic->tme_m68k_ireg_memx32);
173: RAW_PUT(ic->tme_m68k_ireg_memy32);
174:
175: /* done: */
176: break;
177:
178: case TME_M68K_MODE_EXCEPTION:
179:
180: /* put in the exceptions set: */
181: RAW_PUT(ic->_tme_m68k_exceptions);
182:
183: /* put in the shadow status register: */
184: RAW_PUT(ic->tme_m68k_ireg_shadow_sr);
185:
186: /* done: */
187: break;
188:
189: case TME_M68K_MODE_RTE:
190:
191: /* put in the shadow status register: */
192: RAW_PUT(ic->tme_m68k_ireg_shadow_sr);
193:
194: /* put in the next program counter: */
195: RAW_PUT(ic->tme_m68k_ireg_pc_next);
196:
197: /* put in the format/offset word: */
198: RAW_PUT(ic->tme_m68k_ireg_format_offset);
199:
200: break;
201:
202: default: abort();
203: }
204:
205: /* put in the internal state: */
206: raw_avail = raw - raw_state;
207: raw = raw_state;
208: #undef RAW_PUT
209: #define RAW_PUT(f) \
210: do { \
211: raw_used = TME_MIN(sizeof(f), raw_avail); \
212: memcpy(f, raw, raw_used); \
213: raw += raw_used; \
214: raw_avail -= raw_used; \
215: } while (/* CONSTCOND */ 0)
216:
217: /* use all of the reserved regions: */
218: RAW_PUT(fmt8.tme_m68k_fmt8_state0);
219: RAW_PUT(fmt8.tme_m68k_fmt8_state1);
220: RAW_PUT(fmt8.tme_m68k_fmt8_state2);
221: RAW_PUT(fmt8.tme_m68k_fmt8_state3);
222: #undef RAW_PUT
223:
224: /* put in the special status word and the data output buffer: */
225: ssw = 0;
226: flags = ic->_tme_m68k_group0_flags;
227: if (flags & TME_M68K_BUS_CYCLE_READ) {
228: ssw |= (TME_M68K_SSW8_RW
229: | ((flags & TME_M68K_BUS_CYCLE_FETCH)
230: ? TME_M68K_SSW8_IF
231: : TME_M68K_SSW8_DF));
232: assert(ic->_tme_m68k_group0_buffer_read_size <= sizeof(tme_uint16_t));
233: if (ic->_tme_m68k_group0_buffer_read_size == sizeof(tme_uint8_t)) {
234: ssw |= TME_M68K_SSW8_BX;
235: }
236: }
237: else {
238: assert(ic->_tme_m68k_group0_buffer_write_size <= sizeof(tme_uint16_t));
239: if (ic->_tme_m68k_group0_buffer_write_size == sizeof(tme_uint8_t)) {
240: ssw |= TME_M68K_SSW8_BX;
241: }
242: memcpy(fmt8.tme_m68k_fmt8_dob
243: + sizeof(fmt8.tme_m68k_fmt8_dob)
244: - ic->_tme_m68k_group0_buffer_write_size,
245: ic->_tme_m68k_group0_buffer_write,
246: ic->_tme_m68k_group0_buffer_write_size);
247: }
248: if (flags & TME_M68K_BUS_CYCLE_RMW) {
249: ssw |= TME_M68K_SSW8_RM;
250: }
251: ssw |= ic->_tme_m68k_group0_function_code;
252: fmt8.tme_m68k_fmt8_ssw = tme_htobe_u16(ssw);
253:
254: /* put in the fault address: */
255: fmt8.tme_m68k_fmt8_addr_high = tme_htobe_u16(ic->_tme_m68k_group0_address >> 16);
256: fmt8.tme_m68k_fmt8_addr_low = tme_htobe_u16(ic->_tme_m68k_group0_address & 0xffff);
257:
258: /* push the format 8 contents. we don't need to worry about
259: restarting here, because any fault is a double fault: */
260: ic->tme_m68k_ireg_a7 -= sizeof(fmt8);
261: ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_a7;
262: ic->_tme_m68k_ea_function_code = TME_M68K_FC_SD; /* XXX right? */
263: tme_m68k_write_mem(ic, (tme_uint8_t *) &fmt8, sizeof(fmt8));
264:
265: /* now finish the processing for this exception: */
266: tme_m68k_exception_process_finish(ic, TME_M68K_FORMAT_8,
1.1.1.2 root 267: ((exceptions & TME_M68K_EXCEPTION_BERR)
268: ? TME_M68K_VECTOR_BERR
269: : TME_M68K_VECTOR_AERR));
270: ic->_tme_m68k_exceptions = (exceptions &= ~ (TME_M68K_EXCEPTION_AERR
271: | TME_M68K_EXCEPTION_BERR));
1.1 root 272: }
273:
274: /* do normal exception processing: */
1.1.1.2 root 275: tme_m68000_exception_process(ic);
1.1 root 276: /* NOTREACHED */
277: }
278:
279: /* m68010 RTE processing: */
280: static void
281: _tme_m68010_rte(struct tme_m68k *ic)
282: {
283: tme_uint16_t format;
284: struct tme_m68k_fmt8 fmt8;
285: tme_uint32_t fmt8_address;
286: tme_uint8_t raw_state[19 * sizeof(tme_uint16_t)], *raw;
287: unsigned int raw_avail, raw_used;
288: tme_uint8_t function_code;
289: tme_uint16_t ssw;
290: unsigned int flags;
291: tme_uint8_t *ib;
292: unsigned int buffer_size;
293:
294: /* start the RTE: */
295: format = tme_m68k_rte_start(ic);
296:
297: /* if this is a format 0 stack frame, finish it now: */
298: if (format == TME_M68K_FORMAT_0) {
299: ic->_tme_m68k_mode = TME_M68K_MODE_EXECUTION;
300: TME_M68K_SEQUENCE_START;
301: tme_m68k_rte_finish(ic, 0);
302: /* NOTREACHED */
303: }
304:
305: /* whenever we detect a format error, begin exception processing
306: for a format error. we have to back the PC up by the size of the
307: RTE instruction so the PC points to it: */
308: #define FORMAT_ERROR_IF(e) \
309: do { \
310: if (e) { \
311: ic->tme_m68k_ireg_pc -= sizeof(tme_uint16_t); \
1.1.1.2 root 312: tme_m68k_exception(ic, TME_M68K_EXCEPTION_INST(TME_M68K_VECTOR_FORMAT));\
1.1 root 313: /* NOTREACHED */ \
314: } \
315: } while (/* CONSTCOND */ 0)
316:
317: /* this frame must be a format 8 frame: */
318: FORMAT_ERROR_IF(format != TME_M68K_FORMAT_8);
319:
320: /* do a read of the last word in the stack frame to determine
321: accessibility. we rely on tme_m68k_rte_start leaving
322: ic->_tme_m68k_ea_address pointing after the format/offset word: */
323: fmt8_address = ic->_tme_m68k_ea_address;
324: ic->_tme_m68k_ea_address += sizeof(fmt8) - sizeof(tme_uint16_t);
325: tme_m68k_read_memx16(ic);
326:
327: /* read in the format 8 information. if we get a bus error
328: during this operation it's a double fault: */
329: assert(ic->_tme_m68k_exceptions == 0);
1.1.1.2 root 330: ic->_tme_m68k_exceptions = TME_M68K_EXCEPTION_BERR;
1.1 root 331: ic->_tme_m68k_ea_address = fmt8_address;
332: tme_m68k_read_mem(ic, (tme_uint8_t *) &fmt8, sizeof(fmt8));
333: ic->_tme_m68k_exceptions = 0;
334:
335: /* get out the fault address: */
336: ic->_tme_m68k_group0_address = ((((tme_uint32_t) tme_betoh_u16(fmt8.tme_m68k_fmt8_addr_high)) << 16)
337: | tme_betoh_u16(fmt8.tme_m68k_fmt8_addr_low));
338:
339: /* get out the special status word and either the data/instruction
340: input buffer or the data output buffer: */
341: ssw = tme_betoh_u16(fmt8.tme_m68k_fmt8_ssw);
342: FORMAT_ERROR_IF(ssw & TME_M68K_SSW8_HI);
343: flags = 0;
344: ic->_tme_m68k_group0_buffer_read_size = 0;
345: ic->_tme_m68k_group0_buffer_read_softrr = 0;
346: ic->_tme_m68k_group0_buffer_write_size = 0;
347: ic->_tme_m68k_group0_buffer_write_softrr = 0;
348: buffer_size = ((ssw & TME_M68K_SSW8_BX)
349: ? sizeof(tme_uint8_t)
350: : sizeof(tme_uint16_t));
351:
352: /* if this was a read cycle: */
353: if (ssw & TME_M68K_SSW8_RW) {
354: flags |= TME_M68K_BUS_CYCLE_READ;
355:
356: /* if this was an instruction fetch cycle: */
357: if (ssw & TME_M68K_SSW8_IF) {
358: flags |= TME_M68K_BUS_CYCLE_FETCH;
359: FORMAT_ERROR_IF(ssw & TME_M68K_SSW8_DF);
360: ib = fmt8.tme_m68k_fmt8_iib;
361: }
362:
363: /* otherwise, this was a data fetch cycle: */
364: else {
365: FORMAT_ERROR_IF((ssw & (TME_M68K_SSW8_IF
366: | TME_M68K_SSW8_DF))
367: != TME_M68K_SSW8_DF);
368: ib = fmt8.tme_m68k_fmt8_dib;
369: }
370:
371: /* if the user reran this cycle, read in the appropriate
372: input buffer: */
373: if (ssw & TME_M68K_SSW8_RR) {
374: memcpy(ic->_tme_m68k_group0_buffer_read,
375: ib + sizeof(tme_uint16_t) - buffer_size,
376: buffer_size);
377: ic->_tme_m68k_group0_buffer_read_softrr = buffer_size;
378: ic->_tme_m68k_group0_buffer_read_size = buffer_size;
379: }
380: }
381:
382: /* otherwise, this was a write cycle: */
383: else {
384:
385: /* if the user reran this cycle, note that, otherwise
386: copy in the data output buffer: */
387: if (ssw & TME_M68K_SSW8_RR) {
388: ic->_tme_m68k_group0_buffer_write_softrr = buffer_size;
389: }
390: else {
391: memcpy(ic->_tme_m68k_group0_buffer_write,
392: fmt8.tme_m68k_fmt8_dob + sizeof(tme_uint16_t) - buffer_size,
393: buffer_size);
394: ic->_tme_m68k_group0_buffer_write_size = buffer_size;
395: }
396: }
397:
398: /* get the fault function code and address: */
399: ic->_tme_m68k_group0_function_code = ssw & TME_M68K_FC_7;
400: ic->_tme_m68k_group0_address =
401: ((((tme_uint32_t) tme_betoh_u16(fmt8.tme_m68k_fmt8_addr_high)) << 16)
402: | tme_betoh_u16(fmt8.tme_m68k_fmt8_addr_low));
403:
404: /* get out our internal state: */
405: raw = raw_state;
406: raw_avail = sizeof(raw_state);
407: #define RAW_GET(f) \
408: do { \
409: raw_used = TME_MIN(sizeof(f), raw_avail); \
410: memcpy(raw, f, raw_used); \
411: raw += raw_used; \
412: raw_avail -= raw_used; \
413: } while (/* CONSTCOND */ 0)
414:
415: /* use all of the reserved regions: */
416: RAW_GET(fmt8.tme_m68k_fmt8_state0);
417: RAW_GET(fmt8.tme_m68k_fmt8_state1);
418: RAW_GET(fmt8.tme_m68k_fmt8_state2);
419: RAW_GET(fmt8.tme_m68k_fmt8_state3);
420: #undef RAW_GET
421:
422: /* take apart the internal state: */
423: raw = raw_state;
424: raw_avail = sizeof(raw_state) - raw_avail;
425: #define RAW_GET(v) \
426: do { \
427: FORMAT_ERROR_IF(raw_avail < sizeof(v)); \
428: memcpy(&v, raw, sizeof(v)); \
429: raw += sizeof(v); \
430: raw_avail -= sizeof(v); \
431: } while (/* CONSTCOND */ 0)
432:
433: /* get out the sequence: */
434: raw_used = tme_m68k_sequence_fill(ic, raw, raw_avail);
1.1.1.3 root 435: FORMAT_ERROR_IF(raw_used <= 0);
1.1 root 436: raw += raw_used;
437: raw_avail -= raw_used;
438:
439: /* dispatch on the mode: */
440: switch (ic->_tme_m68k_group0_sequence._tme_m68k_sequence_mode) {
441:
442: case TME_M68K_MODE_EXECUTION:
443:
444: /* get out the instruction buffer: */
445: raw_used = tme_m68k_insn_buffer_fill(ic, raw, raw_avail);
1.1.1.3 root 446: FORMAT_ERROR_IF(raw_used <= 0);
1.1 root 447: raw += raw_used;
448: raw_avail -= raw_used;
449:
450: /* get out the EA address: */
451: RAW_GET(function_code);
452: ic->_tme_m68k_ea_function_code = function_code;
453: RAW_GET(ic->_tme_m68k_ea_address);
454:
455: /* get out the memory X and Y buffers: */
456: RAW_GET(ic->tme_m68k_ireg_memx32);
457: RAW_GET(ic->tme_m68k_ireg_memy32);
458:
459: /* done: */
460: break;
461:
462: case TME_M68K_MODE_EXCEPTION:
463:
464: /* get out the exceptions set: */
465: RAW_GET(ic->_tme_m68k_exceptions);
466:
467: /* get out the shadow status register: */
468: RAW_GET(ic->tme_m68k_ireg_shadow_sr);
469:
470: /* done: */
471: break;
472:
473: case TME_M68K_MODE_RTE:
474:
475: /* get out the shadow status register: */
476: RAW_GET(ic->tme_m68k_ireg_shadow_sr);
477:
478: /* get out the next program counter: */
479: RAW_GET(ic->tme_m68k_ireg_pc_next);
480:
481: /* get out the format/offset word: */
482: RAW_GET(ic->tme_m68k_ireg_format_offset);
483:
484: break;
485:
486: default: FORMAT_ERROR_IF(TRUE);
487: }
488:
489: /* finish the RTE: */
490: ic->_tme_m68k_sequence = ic->_tme_m68k_group0_sequence;
491: TME_M68K_SEQUENCE_RESTART;
492: tme_m68k_rte_finish(ic, sizeof(fmt8));
493: /* NOTREACHED */
494: }
495:
496: /* this creates and returns a new m68010: */
497: TME_ELEMENT_X_NEW_DECL(tme_ic_,m68k,m68010) {
498: struct tme_m68k *ic;
499:
500: /* allocate the m68k structure: */
501: ic = tme_new0(struct tme_m68k, 1);
502: ic->tme_m68k_element = element;
503:
504: /* fill in the m68010-specific parts of the structure: */
505: ic->tme_m68k_type = TME_M68K_M68010;
506: ic->_tme_m68k_mode_execute = _tme_m68010_execute;
507: ic->_tme_m68k_mode_exception = _tme_m68010_exception;
508: ic->_tme_m68k_mode_rte = _tme_m68010_rte;
1.1.1.2 root 509: tme_m68k_opcodes_init_m68010(tme_m68k_opcodes_m68010);
1.1 root 510:
511: /* call the common m68k new function: */
512: return (tme_m68k_new(ic, args, extra, _output));
513: }
1.1.1.4 ! root 514:
! 515: unsigned int
! 516: _tme_m68010_get_pc(struct tme_m68k *ic)
! 517: {
! 518: return ic->tme_m68k_ireg_pc;
! 519: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.