|
|
1.1.1.2 ! root 1: /* $Id: m68010.c,v 1.8 2005/03/23 11:49:31 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.2 ! root 37: _TME_RCSID("$Id: m68010.c,v 1.8 2005/03/23 11:49:31 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); 435: FORMAT_ERROR_IF(raw_used < 0); 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); 446: FORMAT_ERROR_IF(raw_used < 0); 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.