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