|
|
1.1.1.2 ! root 1: /* $Id: m68k-misc.c,v 1.15 2003/10/25 17:08:01 fredette Exp $ */ 1.1 root 2: 1.1.1.2 ! root 3: /* ic/m68k/m68k-misc.c - miscellaneous things for the m68k emulator: */ ! 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: */ 1.1 root 35: 36: /* includes: */ 37: #include "m68k-impl.h" 38: 1.1.1.2 ! root 39: _TME_RCSID("$Id: m68k-misc.c,v 1.15 2003/10/25 17:08:01 fredette Exp $"); 1.1 root 40: 41: /* small immediates: */ 42: const tme_uint32_t _tme_m68k_imm32[9] = { 43: 0, 1, 2, 3, 4, 5, 6, 7, 8 44: }; 45: const tme_uint16_t _tme_m68k_imm16[9] = { 46: 0, 1, 2, 3, 4, 5, 6, 7, 8 47: }; 48: const tme_uint8_t _tme_m68k_imm8[9] = { 49: 0, 1, 2, 3, 4, 5, 6, 7, 8 50: }; 51: 52: /* the memory buffer read and write functions: */ 53: #if TME_M68K_SIZE_8 != 1 54: #error "TME_M68K_SIZE_8 must be 1" 55: #endif 56: #if TME_M68K_SIZE_16 != 2 57: #error "TME_M68K_SIZE_16 must be 2" 58: #endif 59: #if TME_M68K_SIZE_32 != 4 60: #error "TME_M68K_SIZE_32 must be 4" 61: #endif 62: const _tme_m68k_xfer_memx _tme_m68k_read_memx[5] = { 63: NULL, 64: tme_m68k_read_memx8, 65: tme_m68k_read_memx16, 66: NULL, 67: tme_m68k_read_memx32 68: }; 69: const _tme_m68k_xfer_memx _tme_m68k_write_memx[5] = { 70: NULL, 71: tme_m68k_write_memx8, 72: tme_m68k_write_memx16, 73: NULL, 74: tme_m68k_write_memx32 75: }; 76: const _tme_m68k_xfer_mem _tme_m68k_read_mem[5] = { 77: NULL, 78: tme_m68k_read_mem8, 79: tme_m68k_read_mem16, 80: NULL, 81: tme_m68k_read_mem32 82: }; 83: const _tme_m68k_xfer_mem _tme_m68k_write_mem[5] = { 84: NULL, 85: tme_m68k_write_mem8, 86: tme_m68k_write_mem16, 87: NULL, 88: tme_m68k_write_mem32 89: }; 90: 91: /* our bus signal handler: */ 92: static int 93: _tme_m68k_bus_signal(struct tme_bus_connection *conn_bus, unsigned int signal) 94: { 95: struct tme_m68k *ic; 96: unsigned int level_edge; 97: 98: /* recover our IC: */ 99: ic = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private; 100: 101: /* take out the level and edge: */ 102: level_edge = signal & (TME_BUS_SIGNAL_LEVEL_MASK 103: | TME_BUS_SIGNAL_EDGE); 104: signal &= ~(TME_BUS_SIGNAL_LEVEL_MASK 105: | TME_BUS_SIGNAL_EDGE); 106: 107: /* lock the external mutex: */ 108: tme_mutex_lock(&ic->tme_m68k_external_mutex); 109: 110: /* on the falling edge of HALT or RESET, halt the processor: */ 111: if (level_edge == (TME_BUS_SIGNAL_LEVEL_ASSERTED 112: | TME_BUS_SIGNAL_EDGE) 113: && (signal == TME_BUS_SIGNAL_HALT 114: || signal == TME_BUS_SIGNAL_RESET)) { 115: ic->tme_m68k_external_halt = TRUE; 116: } 117: 118: /* on the rising edge of RESET, reset the processor: */ 119: else if (signal == TME_BUS_SIGNAL_RESET 120: && level_edge == (TME_BUS_SIGNAL_LEVEL_NEGATED 121: | TME_BUS_SIGNAL_EDGE)) { 122: ic->tme_m68k_external_reset = TRUE; 123: } 124: 125: /* on any other HALT or RESET, do nothing: */ 126: else if (signal == TME_BUS_SIGNAL_RESET 127: || signal == TME_BUS_SIGNAL_HALT) { 128: /* nothing */ 129: } 130: 131: /* anything else: */ 132: else { 133: abort(); 134: } 135: 136: /* unlock the external mutex: */ 137: tme_mutex_unlock(&ic->tme_m68k_external_mutex); 138: 139: /* notify any threads waiting on the external condition: */ 140: tme_cond_notify(&ic->tme_m68k_external_cond, TRUE); 141: return (TME_OK); 142: } 143: 144: /* our interrupt handler: */ 145: static int 146: _tme_m68k_bus_interrupt(struct tme_m68k_bus_connection *conn_m68k, unsigned int ipl) 147: { 148: struct tme_m68k *ic; 149: 150: /* recover our IC: */ 151: ic = conn_m68k->tme_m68k_bus_connection.tme_bus_connection.tme_connection_element->tme_element_private; 152: 153: /* lock the external mutex: */ 154: tme_mutex_lock(&ic->tme_m68k_external_mutex); 155: 156: /* set the interrupt line: */ 157: ic->tme_m68k_external_ipl = ipl; 158: 159: /* unlock the external mutex: */ 160: tme_mutex_unlock(&ic->tme_m68k_external_mutex); 161: 162: /* notify any threads waiting on the external condition: */ 163: tme_cond_notify(&ic->tme_m68k_external_cond, TRUE); 164: return (TME_OK); 165: } 166: 167: /* this checks for external signals. this must be called with the 168: external mutex held: */ 169: void 170: tme_m68k_external_check(struct tme_m68k *ic, tme_uint32_t internal_exceptions) 171: { 172: unsigned int ipl; 173: int vector; 174: int rc; 175: 176: /* if an external reset has been requested, start reset exception 177: processing: */ 178: if (ic->tme_m68k_external_reset) { 179: ic->tme_m68k_external_reset = FALSE; 180: tme_mutex_unlock(&ic->tme_m68k_external_mutex); 181: tme_m68k_exception(ic, TME_M68K_EXCEPTION_GROUP0_RESET); 182: } 183: 184: /* if an external halt has been requested, halt: */ 185: if (ic->tme_m68k_external_halt) { 186: ic->tme_m68k_external_halt = FALSE; 187: tme_mutex_unlock(&ic->tme_m68k_external_mutex); 188: ic->_tme_m68k_mode = TME_M68K_MODE_HALT; 189: TME_M68K_SEQUENCE_START; 190: tme_m68k_redispatch(ic); 191: } 192: 193: /* if we are not halted, and an interrupt can be serviced, start 194: interrupt exception processing: */ 195: ipl = ic->tme_m68k_external_ipl; 196: if (ic->_tme_m68k_mode != TME_M68K_MODE_HALT 197: && ipl >= TME_M68K_IPL_MIN 198: && ipl <= TME_M68K_IPL_MAX 199: && (ipl == TME_M68K_IPL_NMI 200: || ipl > TME_M68K_FLAG_IPM(ic->tme_m68k_ireg_sr))) { 201: tme_mutex_unlock(&ic->tme_m68k_external_mutex); 202: 203: /* acknowledge the interrupt and get the vector: */ 204: rc = (*ic->_tme_m68k_bus_connection->tme_m68k_bus_connection.tme_bus_intack) 205: (&ic->_tme_m68k_bus_connection->tme_m68k_bus_connection, 206: ipl, &vector); 207: if (rc == TME_EDEADLK) { 208: abort(); 209: } 210: 211: /* if the interrupt acknowledge failed, this is a spurious interrupt: */ 212: if (rc == ENOENT) { 213: vector = 24; 214: } 215: 216: /* if no vector is given, use the autovector: */ 217: else if (vector == TME_BUS_INTERRUPT_VECTOR_UNDEF) { 218: vector = 24 + ipl; 219: } 220: 221: /* dispatch the exceptions: */ 222: tme_m68k_exception(ic, internal_exceptions | TME_M68K_EXCEPTION_GROUP1_INT(ipl, vector)); 223: } 224: 225: /* if there are internal exceptions to process, do so: */ 226: if (internal_exceptions != 0) { 227: tme_mutex_unlock(&ic->tme_m68k_external_mutex); 228: tme_m68k_exception(ic, internal_exceptions); 229: } 230: 231: /* there are no exceptions to process: */ 232: } 233: 234: /* the idle function, used when the processor is halted or stopped: */ 235: static void 236: tme_m68k_idle(struct tme_m68k *ic) 237: { 238: /* lock the external mutex: */ 239: tme_mutex_lock(&ic->tme_m68k_external_mutex); 240: 241: /* loop forever: */ 242: for (;;) { 243: 244: /* check for any external signal: */ 245: tme_m68k_external_check(ic, 0); 246: 247: /* await an external condition: */ 248: tme_cond_wait_yield(&ic->tme_m68k_external_cond, &ic->tme_m68k_external_mutex); 249: } 250: } 251: 252: /* the m68k thread: */ 253: static void 254: tme_m68k_thread(struct tme_m68k *ic) 255: { 256: 257: /* we use longjmp to redispatch: */ 258: do { } while (setjmp(ic->_tme_m68k_dispatcher)); 259: 260: /* dispatch on the current mode: */ 261: switch (ic->_tme_m68k_mode) { 262: 263: case TME_M68K_MODE_EXECUTION: 264: (*ic->_tme_m68k_mode_execute)(ic); 265: /* NOTREACHED */ 266: 267: case TME_M68K_MODE_EXCEPTION: 268: (*ic->_tme_m68k_mode_exception)(ic); 269: /* NOTREACHED */ 270: 271: case TME_M68K_MODE_RTE: 272: (*ic->_tme_m68k_mode_rte)(ic); 273: /* NOTREACHED */ 274: 275: case TME_M68K_MODE_STOP: 276: case TME_M68K_MODE_HALT: 277: tme_m68k_idle(ic); 278: /* NOTREACHED */ 279: 280: default: 281: abort(); 282: } 283: /* NOTREACHED */ 284: } 285: 286: /* the TLB filler for when we are on a generic bus: */ 287: static int 288: _tme_m68k_generic_tlb_fill(struct tme_m68k_bus_connection *conn_m68k, 289: struct tme_m68k_tlb *tlb, 290: unsigned int function_code, 291: tme_uint32_t external_address, 292: unsigned int cycles) 293: { 294: struct tme_m68k *ic; 295: 296: /* recover our IC: */ 297: ic = conn_m68k->tme_m68k_bus_connection.tme_bus_connection.tme_connection_element->tme_element_private; 298: 299: /* call the generic bus TLB filler: */ 300: (ic->_tme_m68k_bus_generic->tme_bus_tlb_fill) 301: (ic->_tme_m68k_bus_generic, 302: &tlb->tme_m68k_tlb_bus_tlb, 303: external_address, 304: cycles); 305: 306: /* when we're on a generic bus a TLB entry is valid for all function codes: */ 307: tlb->tme_m68k_tlb_function_codes_mask = -1; 308: 309: return (TME_OK); 310: } 311: 312: /* the connection scorer: */ 313: static int 314: _tme_m68k_connection_score(struct tme_connection *conn, unsigned int *_score) 315: { 316: struct tme_m68k_bus_connection *conn_m68k; 317: struct tme_bus_connection *conn_bus; 318: unsigned int score; 319: 320: /* assume that this connection is useless: */ 321: score = 0; 322: 323: /* dispatch on the connection type: */ 324: conn_m68k = (struct tme_m68k_bus_connection *) conn->tme_connection_other; 325: conn_bus = (struct tme_bus_connection *) conn->tme_connection_other; 326: switch (conn->tme_connection_type) { 327: 328: /* this must be a bus, and not another m68k chip: */ 329: case TME_CONNECTION_BUS_M68K: 330: if (conn_bus->tme_bus_tlb_set_allocate != NULL 331: && conn_m68k->tme_m68k_bus_tlb_fill != NULL) { 332: score = 10; 333: } 334: break; 335: 336: /* this must be a bus, and not another chip: */ 337: case TME_CONNECTION_BUS_GENERIC: 338: if (conn_bus->tme_bus_tlb_set_allocate != NULL 339: && conn_bus->tme_bus_tlb_fill != NULL) { 340: score = 1; 341: } 342: break; 343: 344: default: abort(); 345: } 346: 347: *_score = score; 348: return (TME_OK); 349: } 350: 351: /* this makes a new connection: */ 352: static int 353: _tme_m68k_connection_make(struct tme_connection *conn, unsigned int state) 354: { 355: struct tme_m68k *ic; 356: struct tme_m68k_bus_connection *conn_m68k; 357: struct tme_bus_connection *conn_bus; 358: struct tme_connection *conn_other; 359: 360: /* since the CPU is halted, it won't be making any connection calls, 361: so we only have to do work when the connection is fully made: */ 362: if (state == TME_CONNECTION_FULL) { 363: 364: /* recover our IC: */ 365: ic = conn->tme_connection_element->tme_element_private; 366: 367: /* dispatch on the connection type: */ 368: conn_other = conn->tme_connection_other; 369: conn_m68k = (struct tme_m68k_bus_connection *) conn_other; 370: conn_bus = (struct tme_bus_connection *) conn_other; 371: switch (conn->tme_connection_type) { 372: 373: case TME_CONNECTION_BUS_M68K: 374: ic->_tme_m68k_bus_connection = conn_m68k; 375: break; 376: 377: /* we need an adaptation layer: */ 378: case TME_CONNECTION_BUS_GENERIC: 379: conn_m68k = tme_new0(struct tme_m68k_bus_connection, 1); 380: conn_m68k->tme_m68k_bus_connection.tme_bus_connection.tme_connection_element = conn->tme_connection_element; 381: conn_m68k->tme_m68k_bus_tlb_fill = _tme_m68k_generic_tlb_fill; 382: ic->_tme_m68k_bus_connection = conn_m68k; 383: ic->_tme_m68k_bus_generic = conn_bus; 384: break; 385: 386: default: abort(); 387: } 388: 389: /* allocate the TLB hash set: */ 390: (*ic->_tme_m68k_bus_connection->tme_m68k_bus_connection.tme_bus_tlb_set_allocate) 391: (&ic->_tme_m68k_bus_connection->tme_m68k_bus_connection, 392: _TME_M68K_TLB_HASH_SIZE, 393: sizeof(struct tme_m68k_tlb), 394: TME_ATOMIC_POINTER((struct tme_bus_tlb **) &ic->_tme_m68k_tlb_array)); 395: 396: /* allocate the ITLB set: */ 397: (*ic->_tme_m68k_bus_connection->tme_m68k_bus_connection.tme_bus_tlb_set_allocate) 398: (&ic->_tme_m68k_bus_connection->tme_m68k_bus_connection, 399: 1, 400: sizeof(struct tme_m68k_tlb), 401: TME_ATOMIC_POINTER((struct tme_bus_tlb **) &ic->_tme_m68k_itlb)); 402: } 403: 404: /* NB: the machine needs to issue a reset to bring the CPU out of halt. */ 405: return (TME_OK); 406: } 407: 408: /* this breaks a connection: */ 409: static int 410: _tme_m68k_connection_break(struct tme_connection *conn, unsigned int state) 411: { 412: abort(); 413: } 414: 415: /* this makes new connection sides: */ 416: static int 417: _tme_m68k_connections_new(struct tme_element *element, const char * const *args, struct tme_connection **_conns, char **_output) 418: { 419: struct tme_m68k_bus_connection *conn_m68k; 420: struct tme_bus_connection *conn_bus; 421: struct tme_connection *conn; 422: 423: /* if we already have a bus connection, we can take no more connections: */ 424: if (((struct tme_m68k *) element->tme_element_private)->_tme_m68k_bus_connection != NULL) { 425: return (TME_OK); 426: } 427: 428: /* create our side of an m68k bus connection: */ 429: conn_m68k = tme_new0(struct tme_m68k_bus_connection, 1); 430: conn_bus = &conn_m68k->tme_m68k_bus_connection; 431: conn = &conn_bus->tme_bus_connection; 432: 433: /* fill in the generic connection: */ 434: conn->tme_connection_next = *_conns; 435: conn->tme_connection_type = TME_CONNECTION_BUS_M68K; 436: conn->tme_connection_score = _tme_m68k_connection_score; 437: conn->tme_connection_make = _tme_m68k_connection_make; 438: conn->tme_connection_break = _tme_m68k_connection_break; 439: 440: /* fill in the generic bus connection: */ 441: conn_bus->tme_bus_signal = _tme_m68k_bus_signal; 442: conn_bus->tme_bus_tlb_set_allocate = NULL; 443: 444: /* full in the m68k bus connection: */ 445: conn_m68k->tme_m68k_bus_interrupt = _tme_m68k_bus_interrupt; 446: conn_m68k->tme_m68k_bus_tlb_fill = NULL; 447: 448: /* add this connection to the set of possibilities: */ 449: *_conns = conn; 450: 451: /* create our side of a generic bus connection: */ 452: conn_bus = tme_new0(struct tme_bus_connection, 1); 453: conn = &conn_bus->tme_bus_connection; 454: 455: /* fill in the generic connection: */ 456: conn->tme_connection_next = *_conns; 457: conn->tme_connection_type = TME_CONNECTION_BUS_GENERIC; 458: conn->tme_connection_score = _tme_m68k_connection_score; 459: conn->tme_connection_make = _tme_m68k_connection_make; 460: conn->tme_connection_break = _tme_m68k_connection_break; 461: 462: /* fill in the generic bus connection: */ 463: conn_bus->tme_bus_signal = _tme_m68k_bus_signal; 464: conn_bus->tme_bus_tlb_set_allocate = NULL; 465: conn_bus->tme_bus_tlb_fill = NULL; 466: 467: /* add this connection to the set of possibilities: */ 468: *_conns = conn; 469: 470: /* done: */ 471: return (TME_OK); 472: } 473: 474: /* the common m68k new function: */ 475: int 476: tme_m68k_new(struct tme_m68k *ic, const char * const *args, const void *extra, char **_output) 477: { 478: struct tme_element *element; 479: 480: /* we take no arguments: */ 481: if (args[1] != NULL) { 482: tme_output_append_error(_output, 483: "%s %s, %s %s", 484: args[1], 485: _("unexpected"), 486: _("usage:"), 487: args[0]); 488: tme_free(ic); 489: return (EINVAL); 490: } 491: 492: /* initialize the verifier: */ 493: tme_m68k_verify_init(); 494: 495: /* dispatch on the type: */ 496: switch (ic->tme_m68k_type) { 497: case TME_M68K_M68000: 498: ic->_tme_m68k_bus_16bit = TRUE; 499: break; 500: case TME_M68K_M68010: 501: ic->_tme_m68k_bus_16bit = TRUE; 502: break; 503: case TME_M68K_M68020: 504: ic->_tme_m68k_bus_16bit = FALSE; 505: break; 506: default: 507: abort(); 508: } 509: 510: /* we have no bus connection yet: */ 511: ic->_tme_m68k_bus_connection = NULL; 512: 513: /* fill the element: */ 514: element = ic->tme_m68k_element; 515: element->tme_element_private = ic; 516: element->tme_element_connections_new = _tme_m68k_connections_new; 517: 518: /* calculate the instruction burst size: */ 519: /* XXX TBD: */ 520: ic->_tme_m68k_instruction_burst = 20; 1.1.1.2 ! root 521: ic->_tme_m68k_instruction_burst_remaining ! 522: = ic->_tme_m68k_instruction_burst; 1.1 root 523: 524: /* force the processor to be halted: */ 525: ic->_tme_m68k_mode = TME_M68K_MODE_HALT; 526: TME_M68K_SEQUENCE_START; 527: 528: /* start the m68k thread: */ 529: tme_thread_create((tme_thread_t) tme_m68k_thread, ic); 530: 531: return (TME_OK); 532: } 533: 534: /* the common m68k reset function: */ 535: void 536: tme_m68k_do_reset(struct tme_m68k *ic) 537: { 538: 539: /* force the VBR to zero: */ 540: ic->tme_m68k_ireg_vbr = 0; 541: 542: /* force supervisor mode, interrupts disabled: */ 543: tme_m68k_change_sr(ic, TME_M68K_FLAG_S | (7 << 8)); 544: 545: /* load the initial SSP and PC: */ 546: ic->_tme_m68k_ea_function_code = TME_M68K_FC_SD; 547: ic->_tme_m68k_ea_address = 0; 548: tme_m68k_read_mem32(ic, TME_M68K_IREG_A7); 549: ic->_tme_m68k_ea_address += sizeof(ic->tme_m68k_ireg_a7); 550: tme_m68k_read_mem32(ic, TME_M68K_IREG_PC); 551: 552: /* clear all exceptions: */ 553: ic->_tme_m68k_exceptions = 0; 554: 555: /* start execution: */ 556: ic->_tme_m68k_mode = TME_M68K_MODE_EXECUTION; 557: TME_M68K_SEQUENCE_START; 558: tme_m68k_redispatch(ic); 559: } 560: 561: /* this returns nonzero iff the slow instruction executor must be 562: used: */ 563: int 564: tme_m68k_go_slow(const struct tme_m68k *ic) 565: { 566: struct tme_m68k_tlb *tlb; 567: tme_uint32_t linear_pc; 568: 569: tlb = TME_ATOMIC_READ(struct tme_m68k_tlb *, ic->_tme_m68k_itlb); 570: linear_pc = ic->tme_m68k_ireg_pc; 571: return ( 572: 573: /* the ITLB entry must support reads from emulator memory: */ 574: !TME_M68K_TLB_OK_FAST_READ(tlb, 575: TME_M68K_FUNCTION_CODE_PROGRAM(ic), 576: linear_pc, 577: linear_pc) 578: 579: /* the ITLB emulator memory must be 32-bit aligned for the 580: benefit of the fast instruction word fetch macros, so 581: that emulator address alignment goes with linear address 582: alignment: */ 583: || (((unsigned long) tlb->tme_m68k_tlb_emulator_off_read) 584: & (sizeof(tme_uint32_t) - 1)) 585: 586: /* the linear PC must be 16-bit aligned: */ 587: || (linear_pc & 1) 588: 589: /* there must be no tracing: */ 590: || TME_M68K_FLAG_T(ic->tme_m68k_ireg_sr) != 0); 591: } 592: 593: /* this redispatches: */ 594: void 595: tme_m68k_redispatch(struct tme_m68k *ic) 596: { 597: longjmp(ic->_tme_m68k_dispatcher, 1); 598: } 599: 600: /* this fills a TLB entry: */ 601: void 602: tme_m68k_tlb_fill(struct tme_m68k *ic, struct tme_m68k_tlb *tlb, 603: unsigned int function_code, 604: tme_uint32_t linear_address, 605: unsigned int cycles) 606: { 607: tme_uint32_t external_address; 608: struct tme_bus_tlb tlb_internal; 609: 610: /* when emulating a CPU with a 16-bit bus, only 24 bits of address 611: are external: */ 612: external_address = linear_address; 613: if (ic->_tme_m68k_bus_16bit) { 614: external_address &= 0x00ffffff; 615: } 616: 617: /* fill the TLB entry: */ 618: (*ic->_tme_m68k_bus_connection->tme_m68k_bus_tlb_fill) 619: (ic->_tme_m68k_bus_connection, tlb, 620: function_code, 621: external_address, 622: cycles); 623: 624: /* if this code isn't 32-bit clean, we have to deal: */ 625: if (external_address != linear_address) { 626: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb_internal.tme_bus_tlb_addr_first, 627: TME_ATOMIC_READ(tme_bus_addr_t, tlb->tme_m68k_tlb_linear_first) 628: | (linear_address ^ external_address)); 629: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb_internal.tme_bus_tlb_addr_last, 630: TME_ATOMIC_READ(tme_bus_addr_t, tlb->tme_m68k_tlb_linear_last) 631: | (linear_address ^ external_address)); 632: tlb_internal.tme_bus_tlb_cycles_ok = tlb->tme_m68k_tlb_bus_tlb.tme_bus_tlb_cycles_ok; 633: tme_bus_tlb_map(&tlb->tme_m68k_tlb_bus_tlb, external_address, 634: &tlb_internal, linear_address); 635: } 636: } 637: 638: /* this triggers exception processing: */ 639: void 640: tme_m68k_exception(struct tme_m68k *ic, tme_uint32_t new_exceptions) 641: { 642: assert(new_exceptions != 0); 643: 644: /* if the set of new exceptions includes a group zero exception: */ 645: if (new_exceptions & 646: (TME_M68K_EXCEPTION_GROUP0_RESET 647: | TME_M68K_EXCEPTION_GROUP0_AERR 648: | TME_M68K_EXCEPTION_GROUP0_BERR)) { 649: 650: /* there must be only one exception - you cannot trigger a group 0 651: exception simultaneously with any other group 0, 1, or 2 652: exception: */ 653: assert((new_exceptions & (new_exceptions - 1)) == 0); 654: 655: /* if this is a reset exception, it clears all other exceptions: */ 656: if (new_exceptions == TME_M68K_EXCEPTION_GROUP0_RESET) { 657: ic->_tme_m68k_exceptions = 0; 658: } 659: 660: /* otherwise, this is an address error or a bus error. if we were 661: already processing a group 0 exception, this is a 662: double fault, and the processor enters the halted state: */ 663: else if (ic->_tme_m68k_exceptions & 664: (TME_M68K_EXCEPTION_GROUP0_RESET 665: | TME_M68K_EXCEPTION_GROUP0_AERR 666: | TME_M68K_EXCEPTION_GROUP0_BERR)) { 667: ic->_tme_m68k_mode = TME_M68K_MODE_HALT; 668: TME_M68K_SEQUENCE_START; 669: tme_m68k_redispatch(ic); 670: } 671: } 672: 673: /* otherwise, exception processing must not already be happening: */ 674: else { 675: assert(ic->_tme_m68k_exceptions == 0); 676: } 677: 678: /* begin exception processing: */ 679: ic->_tme_m68k_exceptions |= new_exceptions; 680: ic->_tme_m68k_mode = TME_M68K_MODE_EXCEPTION; 681: TME_M68K_SEQUENCE_START; 682: tme_m68k_redispatch(ic); 683: } 684: 685: /* this changes SR, and swaps %a7 as needed: */ 686: void 687: tme_m68k_change_sr(struct tme_m68k *ic, tme_uint16_t sr) 688: { 689: 690: /* save %a7 in the proper stack pointer control register: */ 691: switch (ic->tme_m68k_ireg_sr & (TME_M68K_FLAG_S | TME_M68K_FLAG_M)) { 692: case 0: 693: case TME_M68K_FLAG_M: 694: ic->tme_m68k_ireg_usp = ic->tme_m68k_ireg_a7; 695: break; 696: case TME_M68K_FLAG_S: 697: ic->tme_m68k_ireg_msp = ic->tme_m68k_ireg_a7; 698: break; 699: case (TME_M68K_FLAG_S | TME_M68K_FLAG_M): 700: ic->tme_m68k_ireg_isp = ic->tme_m68k_ireg_a7; 701: break; 702: } 703: 704: /* load %a7 from the proper stack pointer control register: */ 705: ic->tme_m68k_ireg_sr = sr; 706: switch (ic->tme_m68k_ireg_sr & (TME_M68K_FLAG_S | TME_M68K_FLAG_M)) { 707: case 0: 708: case TME_M68K_FLAG_M: 709: ic->tme_m68k_ireg_a7 = ic->tme_m68k_ireg_usp; 710: break; 711: case TME_M68K_FLAG_S: 712: ic->tme_m68k_ireg_a7 = ic->tme_m68k_ireg_msp; 713: break; 714: case (TME_M68K_FLAG_S | TME_M68K_FLAG_M): 715: ic->tme_m68k_ireg_a7 = ic->tme_m68k_ireg_isp; 716: break; 717: } 718: } 719: 720: /* this starts processing an m68k exception: */ 721: void 722: tme_m68k_exception_process_start(struct tme_m68k *ic, unsigned int ipl) 723: { 724: tme_uint16_t sr; 725: 726: /* make an internal copy of the status register, then set S, clear 727: T, and update I: */ 728: if (!TME_M68K_SEQUENCE_RESTARTING) { 729: ic->tme_m68k_ireg_shadow_sr = ic->tme_m68k_ireg_sr; 1.1.1.2 ! root 730: sr = (ic->tme_m68k_ireg_sr | TME_M68K_FLAG_S) & ~(0x3 << 14); 1.1 root 731: if (ipl > TME_M68K_IPL_NONE) { 732: assert(ipl == TME_M68K_IPL_NMI 733: || ipl > TME_M68K_FLAG_IPM(sr)); 734: sr = (sr & ~(TME_M68K_IPL_MAX << 8)) | (ipl << 8); 735: } 736: tme_m68k_change_sr(ic, sr); 737: } 738: } 739: 740: /* this finishes processing an m68k exception: */ 741: void 742: tme_m68k_exception_process_finish(struct tme_m68k *ic, tme_uint8_t format, tme_uint8_t vector) 743: { 744: tme_uint16_t vector_offset; 745: 746: /* stack the frame format and vector offset, unless this is a 68000: */ 747: vector_offset = ((tme_uint16_t) vector) << 2; 748: if (ic->tme_m68k_type != TME_M68K_M68000) { 749: tme_m68k_push16(ic, (((tme_uint16_t) format) << 12) | vector_offset); 750: } 751: 752: /* stack the program counter: */ 753: tme_m68k_push32(ic, ic->tme_m68k_ireg_pc); 754: 755: /* stack the internal copy of the status register: */ 756: tme_m68k_push16(ic, ic->tme_m68k_ireg_shadow_sr); 757: 758: /* do a bus cycle to read the vector into the program counter: */ 759: if (!TME_M68K_SEQUENCE_RESTARTING) { 760: ic->_tme_m68k_ea_function_code = TME_M68K_FC_SD; /* XXX is this right? */ 761: ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_vbr + vector_offset; 762: } 763: tme_m68k_read_mem32(ic, TME_M68K_IREG_PC); 764: } 765: 766: /* common m68k exception processing: */ 767: void 768: tme_m68k_exception_process(struct tme_m68k *ic) 769: { 770: tme_uint32_t exceptions; 771: 772: /* get the set of exceptions. we must have no group 0 exceptions: */ 773: exceptions = ic->_tme_m68k_exceptions; 774: assert((exceptions & (TME_M68K_EXCEPTION_GROUP0_RESET 775: | TME_M68K_EXCEPTION_GROUP0_AERR 776: | TME_M68K_EXCEPTION_GROUP0_BERR)) == 0); 777: 778: /* these if statements are ordered to implement the priority 779: relationship between the different exceptions as outlined in 780: the 68000 user's manual (pp 93 in my copy): */ 781: 782: if (TME_M68K_EXCEPTION_IS_GROUP2(exceptions)) { 783: tme_m68k_exception_process_start(ic, 0); 784: tme_m68k_exception_process_finish(ic, TME_M68K_FORMAT_0, TME_M68K_EXCEPTION_IS_GROUP2(exceptions)); 785: } 786: 787: if (exceptions & TME_M68K_EXCEPTION_GROUP1_TRACE) { 788: tme_m68k_exception_process_start(ic, 0); 789: tme_m68k_exception_process_finish(ic, TME_M68K_FORMAT_0, 0x09); 790: } 791: 792: if (TME_M68K_EXCEPTION_IS_GROUP1_INT(exceptions)) { 793: tme_m68k_exception_process_start(ic, TME_M68K_EXCEPTION_IS_GROUP1_INT(exceptions)); 794: tme_m68k_exception_process_finish(ic, TME_M68K_FORMAT_0, TME_M68K_EXCEPTION_GROUP1_INT_VEC(exceptions)); 795: } 796: 797: if (exceptions & TME_M68K_EXCEPTION_GROUP1_ILL) { 798: tme_m68k_exception_process_start(ic, 0); 799: tme_m68k_exception_process_finish(ic, TME_M68K_FORMAT_0, 0x04); 800: } 801: 802: if (exceptions & TME_M68K_EXCEPTION_GROUP1_PRIV) { 803: tme_m68k_exception_process_start(ic, 0); 804: tme_m68k_exception_process_finish(ic, TME_M68K_FORMAT_0, 0x08); 805: } 806: 807: /* we have processed all exceptions - resume execution: */ 808: ic->_tme_m68k_exceptions = 0; 809: ic->_tme_m68k_mode = TME_M68K_MODE_EXECUTION; 810: TME_M68K_SEQUENCE_START; 811: tme_m68k_redispatch(ic); 812: } 813: 814: /* this starts an m68k RTE: */ 815: tme_uint16_t 816: tme_m68k_rte_start(struct tme_m68k *ic) 817: { 818: 819: /* set up to read from the stack frame: */ 820: ic->_tme_m68k_ea_function_code = TME_M68K_FC_SD; 821: ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_a7; 822: 823: /* read the stacked status register: */ 824: tme_m68k_read_mem16(ic, TME_M68K_IREG_SHADOW_SR); 825: ic->_tme_m68k_ea_address += sizeof(ic->tme_m68k_ireg_shadow_sr); 826: 827: /* read the stacked PC: */ 828: tme_m68k_read_mem32(ic, TME_M68K_IREG_PC_NEXT); 829: ic->_tme_m68k_ea_address += sizeof(ic->tme_m68k_ireg_pc_next); 830: 831: /* read the stacked format/offset word, unless this is a 68000: */ 832: if (ic->tme_m68k_type != TME_M68K_M68000) { 833: tme_m68k_read_mem16(ic, TME_M68K_IREG_FORMAT_OFFSET); 834: ic->_tme_m68k_ea_address += sizeof(ic->tme_m68k_ireg_format_offset); 835: } 836: else { 837: ic->tme_m68k_ireg_format_offset = 0; 838: } 839: 840: /* return the frame format: */ 841: return (ic->tme_m68k_ireg_format_offset >> 12); 842: } 843: 844: /* this finishes an m68k RTE: */ 845: void 846: tme_m68k_rte_finish(struct tme_m68k *ic, tme_uint32_t format_extra) 847: { 848: tme_uint32_t frame_size; 849: 850: /* calculate the total frame size. the 68000 doesn't have a 851: format/status word: */ 852: frame_size = (sizeof(ic->tme_m68k_ireg_shadow_sr) 853: + sizeof(ic->tme_m68k_ireg_pc_next) 854: + (ic->tme_m68k_type != TME_M68K_M68000 855: ? sizeof(ic->tme_m68k_ireg_format_offset) 856: : 0) 857: + format_extra); 858: assert((frame_size & 1) == 0); 859: 860: /* adjust the stack: */ 861: ic->tme_m68k_ireg_a7 += frame_size; 862: 863: /* set the status register: */ 864: tme_m68k_change_sr(ic, ic->tme_m68k_ireg_shadow_sr); 865: 866: /* set the PC: */ 867: ic->tme_m68k_ireg_pc = ic->tme_m68k_ireg_pc_next; 868: 869: /* redispatch: */ 870: tme_m68k_redispatch(ic); 871: } 872: 873: /* this stores the group 0 sequence into a region of host memory. 874: this is used when preparing the state information to be stored 875: on the stack for a bus or address error: */ 876: int 877: tme_m68k_sequence_empty(const struct tme_m68k *ic, tme_uint8_t *raw, unsigned int raw_avail) 878: { 879: const struct _tme_m68k_sequence *sequence; 880: unsigned int raw_used; 881: 882: /* get the group 0 sequence: */ 883: sequence = &ic->_tme_m68k_group0_sequence; 884: raw_used = 0; 885: 886: /* we use 8 bits for the mode (2 bits) and flags (6 bits): */ 887: raw_used += sizeof(tme_uint8_t); 888: assert(raw_avail >= raw_used); 889: assert(sequence->_tme_m68k_sequence_mode < TME_BIT(2)); 890: assert(sequence->_tme_m68k_sequence_mode_flags < TME_BIT(6)); 891: *(raw++) = ((sequence->_tme_m68k_sequence_mode << 6) 892: | sequence->_tme_m68k_sequence_mode_flags); 893: 894: 895: /* we use 16 bits for the faulted memory transfer ordinal 896: (12 bits) and already-transferred byte count (4 bits): */ 897: raw_used += sizeof(tme_uint16_t); 898: assert(raw_avail >= raw_used); 899: assert(sequence->_tme_m68k_sequence_transfer_faulted < TME_BIT(12)); 900: assert(sequence->_tme_m68k_sequence_transfer_faulted_after < TME_BIT(4)); 901: *(raw++) = sequence->_tme_m68k_sequence_transfer_faulted >> 4; 902: *(raw++) = ((sequence->_tme_m68k_sequence_transfer_faulted << 4) 903: | sequence->_tme_m68k_sequence_transfer_faulted_after); 904: 905: #ifdef _TME_M68K_VERIFY 906: /* we use sizeof(_tme_m68k_sequence_uid) bytes for the sequence UID: */ 907: raw_used += sizeof(sequence->_tme_m68k_sequence_uid); 908: assert(raw_avail >= raw_used); 909: memcpy(raw, 910: &sequence->_tme_m68k_sequence_uid, 911: sizeof(sequence->_tme_m68k_sequence_uid)); 912: raw += sizeof(sequence->_tme_m68k_sequence_uid); 913: #endif /* _TME_M68K_VERIFY */ 914: 915: /* done: */ 916: return (raw_used); 917: } 918: 919: /* this restores the group 0 sequence from a region of host memory. 920: this is used when reading the state information stored on the 921: stack for a bus or address error: */ 922: int 923: tme_m68k_sequence_fill(struct tme_m68k *ic, const tme_uint8_t *raw, unsigned int raw_avail) 924: { 925: struct _tme_m68k_sequence *sequence; 926: unsigned int raw_used; 927: 928: /* get the group 0 sequence: */ 929: sequence = &ic->_tme_m68k_group0_sequence; 930: raw_used = 0; 931: 932: /* we used 8 bits for the mode (2 bits) and flags (6 bits): */ 933: raw_used += sizeof(tme_uint8_t); 934: if (raw_avail < raw_used) { 935: return (-1); 936: } 937: sequence->_tme_m68k_sequence_mode = *raw >> 6; 938: sequence->_tme_m68k_sequence_mode_flags = (*(raw++) & (TME_BIT(6) - 1)); 939: 940: /* we used 16 bits for the faulted memory transfer ordinal 941: (12 bits) and already-transferred byte count (4 bits): */ 942: raw_used += sizeof(tme_uint16_t); 943: if (raw_avail < raw_used) { 944: return (-1); 945: } 946: sequence->_tme_m68k_sequence_transfer_faulted = 947: (((tme_uint16_t) raw[0]) << 4) 948: | (raw[1] >> 4); 949: sequence->_tme_m68k_sequence_transfer_faulted_after = raw[1] & (TME_BIT(4) - 1); 950: raw += sizeof(tme_uint16_t); 951: 952: #ifdef _TME_M68K_VERIFY 953: /* we used sizeof(_tme_m68k_sequence_uid) bytes for the sequence UID: */ 954: raw_used += sizeof(sequence->_tme_m68k_sequence_uid); 955: if (raw_avail < raw_used) { 956: return (-1); 957: } 958: memcpy(&sequence->_tme_m68k_sequence_uid, 959: raw, 960: sizeof(sequence->_tme_m68k_sequence_uid)); 961: raw += sizeof(sequence->_tme_m68k_sequence_uid); 962: #endif /* _TME_M68K_VERIFY */ 963: 964: /* initialize this to one: */ 965: sequence->_tme_m68k_sequence_transfer_next = 1; 966: 967: /* done: */ 968: return (raw_used); 969: } 970: 971: /* this transfers the instruction buffer to or from a region of host 972: memory. unlike the raw region in host memory, where the 16- and 973: 32-bit parts of the instruction are contiguous and therefore 974: potentially misaligned, in the instruction buffer these instruction 975: parts are all properly aligned. given the instruction buffer, a 976: contiguous host memory buffer, a count of instruction bytes and the 977: sizes of the instruction fetches, this transfers from one buffer to 978: the other. 979: 980: this is used to fill the instruction buffer when we're restoring 981: our state from an exception stack or when we fault anywhere inside 982: the fast executor, and it's used to empty the instruction buffer 983: into an exception stack when we fault: */ 984: int 985: tme_m68k_insn_buffer_xfer(struct tme_m68k *ic, tme_uint8_t *raw, unsigned int raw_avail, int what) 986: { 987: int fill, sanity_assert; 988: tme_uint16_t fetch_total; 989: tme_uint16_t fetch_sizes; 990: unsigned int fetch_sizes_bits; 991: unsigned int insn_buffer_off, fetch_off, fetch_size, resid; 992: #define _FETCH_SIZES_BITS (8 * sizeof(ic->_tme_m68k_insn_buffer_fetch_sizes)) 993: #define _FETCH_SIZE_BIT (1 << (_FETCH_SIZES_BITS - 1)) 994: #define _FETCH_SANITY(e) \ 995: do { \ 996: if (sanity_assert) \ 997: assert(e); \ 998: else if (!(e)) \ 999: return (-1); \ 1000: } while (/* CONSTCOND */ 0) 1001: 1002: /* if what is zero, we faulted somewhere inside the fast executor 1003: and we need to fill the instruction buffer from raw host memory: */ 1004: if (what == 0) { 1005: fill = TRUE; 1006: sanity_assert = TRUE; 1007: 1008: /* the fetch total and sizes are in the state: */ 1009: fetch_total = ic->_tme_m68k_insn_buffer_fetch_total; 1010: fetch_sizes = ic->_tme_m68k_insn_buffer_fetch_sizes; 1011: raw_avail = fetch_total; 1012: } 1013: 1014: /* else, if what is one, we're emptying the instruction buffer into 1015: an exception frame: */ 1016: else if (what == 1) { 1017: fill = FALSE; 1018: sanity_assert = TRUE; 1019: 1020: /* the fetch total and sizes are in the state: */ 1021: fetch_total = ic->_tme_m68k_insn_buffer_fetch_total; 1022: fetch_sizes = ic->_tme_m68k_insn_buffer_fetch_sizes; 1023: 1024: /* the first word we place into the exception frame is 1025: (fetch_sizes << 4) | (fetch_total >> 1): */ 1026: _FETCH_SANITY(raw_avail >= sizeof(tme_uint16_t)); 1027: raw[1] = (fetch_sizes << 4) | (fetch_total >> 1); 1028: raw[0] = (fetch_sizes >> 4); 1029: raw += sizeof(tme_uint16_t); 1030: raw_avail -= sizeof(tme_uint16_t); 1031: } 1032: 1033: /* otherwise, we're filling the instruction buffer from an exception 1034: frame: */ 1035: else { 1036: fill = TRUE; 1037: sanity_assert = FALSE; 1038: 1039: /* this function previously emptied the instruction buffer into 1040: this exception frame, and the first big-endian word placed 1041: there is (fetch_sizes << 4) | (fetch_total >> 1): */ 1042: _FETCH_SANITY(raw_avail >= sizeof(tme_uint16_t)); 1043: fetch_total = (raw[1] & 0x0f) << 1; 1044: fetch_sizes = (raw[0] << 4) | (raw[1] >> 4); 1045: raw += sizeof(tme_uint16_t); 1046: raw_avail -= sizeof(tme_uint16_t); 1047: } 1048: 1049: /* fetch_total must be even, because we only fetch some multiple of 1050: 16-bit words: */ 1051: _FETCH_SANITY((fetch_total & (sizeof(tme_uint16_t) - 1)) == 0); 1052: 1053: /* fetch_sizes is a bitmask, with a one bit representing a 32-bit 1054: fetch and a zero bit representing a 16-bit fetch, and the least 1055: significant bit is the *last* fetch performed. count the number 1056: of significant bits in fetch_sizes and confirm that it makes 1057: sense with fetch_total: */ 1058: fetch_sizes_bits = 0; 1059: for (fetch_off = 0; fetch_off < fetch_total; ) { 1060: _FETCH_SANITY(fetch_sizes_bits < _FETCH_SIZES_BITS); 1061: fetch_off += ((fetch_sizes & (1 << fetch_sizes_bits)) 1062: /* a 32-bit fetch: */ 1063: ? sizeof(tme_uint32_t) 1064: /* a 16-bit fetch: */ 1065: : sizeof(tme_uint16_t)); 1066: fetch_sizes_bits++; 1067: } 1068: _FETCH_SANITY(fetch_off == fetch_total); 1069: 1070: /* we must have enough raw space available: */ 1071: _FETCH_SANITY(raw_avail >= fetch_total); 1072: 1073: /* shift fetch_sizes up so the bit for the first transfer 1074: is the most significant bit: */ 1075: fetch_sizes <<= (_FETCH_SIZES_BITS - fetch_sizes_bits); 1076: 1077: /* now fill or empty the instruction buffer: */ 1078: insn_buffer_off = 0; 1079: for (fetch_off = 0; fetch_off < fetch_total; ) { 1080: 1081: /* get the size of this fetch: */ 1082: fetch_size = ((fetch_sizes & _FETCH_SIZE_BIT) 1083: /* a 32-bit fetch: */ 1084: ? sizeof(tme_uint32_t) 1085: /* a 16-bit fetch: */ 1086: : sizeof(tme_uint16_t)); 1087: fetch_sizes <<= 1; 1088: 1089: /* do one transfer. the insn buffer is kept in host byte 1090: order, like the internal registers are: */ 1091: insn_buffer_off = TME_ALIGN(insn_buffer_off, fetch_size); 1092: if (fill) { 1093: for (resid = fetch_size; resid-- > 0; ) { 1094: ic->_tme_m68k_insn_buffer[(insn_buffer_off 1095: + (resid 1096: #ifndef WORDS_BIGENDIAN 1097: ^ (fetch_size - 1) 1098: #endif /* !WORDS_BIGENDIAN */ 1099: ))] 1100: = raw[fetch_off + resid]; 1101: } 1102: } 1103: else { 1104: for (resid = fetch_size; resid-- > 0; ) { 1105: raw[fetch_off + resid] = 1106: ic->_tme_m68k_insn_buffer[(insn_buffer_off 1107: + (resid 1108: #ifndef WORDS_BIGENDIAN 1109: ^ (fetch_size - 1) 1110: #endif /* !WORDS_BIGENDIAN */ 1111: ))]; 1112: } 1113: } 1114: insn_buffer_off += fetch_size; 1115: fetch_off += fetch_size; 1116: 1117: /* if we faulted somewhere in the fast executor, we need to 1118: account for the instruction fetches in the group0 sequence: */ 1119: if (what == 0) { 1120: ic->_tme_m68k_group0_sequence._tme_m68k_sequence_transfer_next++; 1121: } 1122: } 1123: 1124: /* NB: for total consistency we might want to store the fetch total 1125: and sizes into the state when we're filling the instruction 1126: buffer from an execution frame. however this isn't really needed 1127: because the fetch pattern from the restarting slow executor 1128: should be exactly the same and it doesn't care anyways. 1129: if the user bashes the exception frame all bets are off. */ 1130: 1131: /* return the number of bytes we put in an exception frame: */ 1132: return (sizeof(tme_uint16_t) + fetch_total); 1133: } 1134: 1135: /* this is the group 0 fault hook for the fast executor: */ 1136: void 1137: tme_m68k_group0_hook_fast(struct tme_m68k *ic) 1138: { 1139: struct tme_m68k_tlb *tlb; 1140: tme_uint8_t *raw; 1141: 1142: /* fill the instruction buffer and increase the transfer count 1143: as if the slow executor had been doing the fetching: */ 1144: tlb = TME_ATOMIC_READ(struct tme_m68k_tlb *, ic->_tme_m68k_itlb); 1145: raw = tlb->tme_m68k_tlb_emulator_off_read + ic->tme_m68k_ireg_pc; 1146: tme_m68k_insn_buffer_xfer(ic, raw, 0, 0); 1147: } 1148: 1149: /* this starts a read/modify/write cycle. this works in conjunction 1150: with the tme_m68k_readSIZE() and tme_m68k_writeSIZE() functions to 1151: aggregate many bus transactions into a larger transaction: */ 1152: struct tme_m68k_tlb * 1153: tme_m68k_rmw_start(struct tme_m68k *ic) 1154: { 1155: struct tme_m68k_tlb *tlb; 1156: 1157: /* if the user reran the cycle, do nothing: */ 1158: if (TME_M68K_SEQUENCE_RESTARTING 1159: && (ic->_tme_m68k_group0_buffer_read_softrr > 0 1160: || ic->_tme_m68k_group0_buffer_write_softrr > 0)) { 1161: return (NULL); 1162: } 1163: 1164: /* we always rerun read/modify/write cycles in their entirety: */ 1165: ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_faulted 1166: = ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_next - 1; 1167: 1168: /* get an applicable TLB entry: */ 1169: tlb = TME_M68K_TLB_ENTRY(ic, ic->_tme_m68k_ea_function_code, ic->_tme_m68k_ea_address); 1170: 1171: /* we *must* guarantee that a read/modify/write cycle be atomic. 1172: unfortunately, the only way we can really do that is to acquire a 1173: single lock, now, that somehow protects all of the things we want 1174: to do, and hold that lock for the duration. 1175: 1176: the only way we can do this is to require that read/modify/write 1177: cycles always involve TLB entries that allow fast reads and 1178: writes. this gives us a single rwlock that we can lock for 1179: writing now and hold until we're done: */ 1180: 1181: /* we invalidate the TLB entry so we can set the TLB rwlock to NULL, 1182: which is seen by the first tme_m68k_readSIZE (or 1183: tme_m68k_writeSIZE, in the bizarre case that that's called first) 1184: as a signal that, after it reloads the TLB entry, it has to lock 1185: the rwlock: */ 1186: tme_bus_tlb_invalidate(&tlb->tme_m68k_tlb_bus_tlb); 1187: tlb->tme_m68k_tlb_bus_rwlock = NULL; 1188: 1189: return (tlb); 1190: } 1191: 1192: /* this finishes a read/modify/write cycle. this works in conjunction 1193: with the tme_m68k_readSIZE() and tme_m68k_writeSIZE() functions to 1194: aggregate many bus transactions into a larger transaction: */ 1195: void 1196: tme_m68k_rmw_finish(struct tme_m68k *ic, struct tme_m68k_tlb *tlb) 1197: { 1198: 1199: /* if we didn't acquire the rwlock, something is wrong: */ 1200: assert(tlb->tme_m68k_tlb_bus_rwlock != NULL); 1201: 1202: /* unlock the lock: */ 1203: tme_rwlock_unlock(tlb->tme_m68k_tlb_bus_rwlock); 1204: } 1205: 1206: /* this handles a bitfield offset. if the bitfield is in memory, 1207: and it hasn't already been done, this adjusts the effective 1208: address to point to the beginning of the bitfield. this always 1209: returns a nonnegative bitfield offset: */ 1210: unsigned int 1211: tme_m68k_bitfield_offset(struct tme_m68k *ic, int adjust) 1212: { 1213: tme_int16_t specop; 1214: tme_int32_t bf_offset; 1215: tme_int32_t bf_ea_offset; 1216: 1217: /* get the bitfield offset from a data register or as an immediate: */ 1218: specop = ic->_tme_m68k_insn_specop; 1219: bf_offset = ((specop & TME_BIT(11)) 1220: ? ic->tme_m68k_ireg_int32(TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(specop, 6, 3)) 1221: : (tme_int32_t) TME_FIELD_EXTRACTU(specop, 6, 5)); 1222: 1223: /* if this bitfield is in a register (EA mode field is zero): */ 1224: if (TME_FIELD_EXTRACTU(ic->_tme_m68k_insn_opcode, 3, 3) == 0) { 1225: 1226: /* adjust the bitfield offset to be nonnegative: */ 1227: bf_offset &= 31; 1228: } 1229: 1230: /* otherwise, this bitfield is in memory: */ 1231: else { 1232: 1233: /* calculate the effective address offset and adjust the bitfield 1234: offset to be nonnegative: */ 1235: bf_ea_offset = ((bf_offset < 0) 1236: ? ((bf_offset + 1) / 8) - 1 1237: : bf_offset / 8); 1238: bf_offset &= 7; 1239: 1240: /* if this is our first call to this function for this instruction 1241: and we're not restarting, adjust the effective address: */ 1242: if (adjust 1243: && !TME_M68K_SEQUENCE_RESTARTING) { 1244: ic->_tme_m68k_ea_address += bf_ea_offset; 1245: } 1246: } 1247: 1248: /* return the nonnegative bitfield offset: */ 1249: return ((unsigned int) bf_offset); 1250: } 1251: 1252: /* this returns a bitfield width: */ 1253: unsigned int 1254: tme_m68k_bitfield_width(struct tme_m68k *ic) 1255: { 1256: unsigned int bf_width; 1257: tme_int16_t specop; 1258: 1259: /* get the bitfield width from a register or as an immediate: */ 1260: specop = ic->_tme_m68k_insn_specop; 1261: if (specop & TME_BIT(5)) { 1262: bf_width = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(specop, 0, 3)); 1263: } 1264: else { 1265: bf_width = TME_FIELD_EXTRACTU(specop, 0, 5); 1266: } 1267: bf_width &= 31; 1268: if (bf_width == 0) bf_width = 32; 1269: return (bf_width); 1270: } 1271: 1272: /* this reads a bitfield: */ 1273: tme_uint32_t 1274: _tme_m68k_bitfield_read(struct tme_m68k *ic, int is_signed) 1275: { 1276: unsigned int bf_offset, bf_width; 1277: unsigned int shift; 1278: tme_uint8_t *bf_bytes; 1279: tme_uint32_t bf_value; 1280: int ireg; 1281: 1282: /* get the bitfield offset and width: */ 1283: bf_offset = tme_m68k_bitfield_offset(ic, TRUE); 1284: bf_width = tme_m68k_bitfield_width(ic); 1285: 1286: /* if this expression is > 32, in a register this means the bitfield 1287: wraps, and in memory this means the bitfield is 5-bytes wide: */ 1288: shift = (bf_offset + bf_width); 1289: 1290: /* if this bitfield is in a register (EA mode field is zero): */ 1291: if (TME_FIELD_EXTRACTU(ic->_tme_m68k_insn_opcode, 3, 3) == 0) { 1292: ireg = (TME_M68K_IREG_D0 1293: + TME_FIELD_EXTRACTU(ic->_tme_m68k_insn_opcode, 0, 3)); 1294: 1295: /* get the raw 32-bit word containing the bitfield: */ 1296: bf_value = ic->tme_m68k_ireg_uint32(ireg); 1297: 1298: /* if this bitfield wraps the register, shift in the wrapped part 1299: on the right: */ 1300: if (shift > 32) { 1301: shift -= 32; 1302: bf_value = (bf_value << shift) | (bf_value >> (32 - shift)); 1303: bf_offset -= shift; 1304: } 1305: } 1306: 1307: /* otherwise, this bitfield is in memory: */ 1308: else { 1309: 1310: /* read in the bytes covering the bitfield: */ 1311: bf_bytes = (tme_uint8_t *) &ic->tme_m68k_ireg_memx32; 1312: tme_m68k_read_mem(ic, bf_bytes, (bf_offset + bf_width + 7) >> 3); 1313: 1314: /* get the raw 32-bit word containing the bitfield: */ 1315: bf_value = tme_betoh_u32(ic->tme_m68k_ireg_memx32); 1316: 1317: /* if this bitfield is 5 bytes wide, shift in the part from the fifth byte 1318: (actually in memy32!) on the right: */ 1319: if (shift > 32) { 1320: shift -= 32; 1321: bf_value = (bf_value << shift) | (bf_bytes[4] >> (8 - shift)); 1322: bf_offset -= shift; 1323: } 1324: } 1325: 1326: /* shift the value: */ 1327: shift = (32 - (bf_offset + bf_width)); 1328: bf_value >>= shift; 1329: 1330: /* mask the value: */ 1331: bf_value &= TME_BIT(bf_width) - 1; 1332: 1333: /* if this is a signed value, sign-extend it: */ 1334: if (is_signed 1335: && (bf_value & TME_BIT(bf_width - 1))) { 1336: bf_value |= (0xffffffff ^ (TME_BIT(bf_width) - 1)); 1337: } 1338: 1339: /* all bitfield instructions that read the bitfield set the flags: */ 1340: if (!TME_M68K_SEQUENCE_RESTARTING) { 1341: ic->tme_m68k_ireg_ccr = ((ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X) 1342: | ((bf_value & TME_BIT(bf_width - 1)) 1343: ? TME_M68K_FLAG_N 1344: : 0) 1345: | (bf_value 1346: ? 0 1347: : TME_M68K_FLAG_Z)); 1348: } 1349: 1350: /* return the bitfield value: */ 1351: return (bf_value); 1352: } 1353: 1354: /* this writes a bitfield to memory: */ 1355: void 1356: tme_m68k_bitfield_write_unsigned(struct tme_m68k *ic, tme_uint32_t bf_value, int set_flags) 1357: { 1358: unsigned int bf_offset, bf_width; 1359: unsigned int shift; 1360: tme_uint8_t *bf_bytes; 1361: unsigned int count; 1362: int ireg; 1363: 1364: /* for bitfields in memory, we want to know if the memory covering 1365: the bitfield is already in our memory buffer, so we can avoid 1366: reading that memory again. all bitfield instructions set flags 1367: based on a bitfield value; if set_flags is FALSE our caller 1368: must have tested the old bitfield value, and so the bitfield 1369: memory must be in our buffer, otherwise assume that this is our 1370: first access to the bitfield memory: */ 1371: #define first_memory set_flags 1372: 1373: /* get the bitfield offset and width: */ 1374: bf_offset = tme_m68k_bitfield_offset(ic, first_memory); 1375: bf_width = tme_m68k_bitfield_width(ic); 1376: 1377: /* if this expression is > 32, in a register this means the bitfield 1378: wraps, and in memory this means the bitfield is 5-bytes wide: */ 1379: shift = (bf_offset + bf_width); 1380: 1381: /* if we're supposed to, set the flags: */ 1382: if (set_flags 1383: && !TME_M68K_SEQUENCE_RESTARTING) { 1384: ic->tme_m68k_ireg_ccr = ((ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X) 1385: | ((bf_value & TME_BIT(bf_width - 1)) 1386: ? TME_M68K_FLAG_N 1387: : 0) 1388: | (bf_value 1389: ? 0 1390: : TME_M68K_FLAG_Z)); 1391: } 1392: 1393: /* mask the value: */ 1394: bf_value &= TME_BIT(bf_width) - 1; 1395: 1396: /* if this bitfield is in a register (EA mode field is zero): */ 1397: if (TME_FIELD_EXTRACTU(ic->_tme_m68k_insn_opcode, 3, 3) == 0) { 1398: ireg = (TME_M68K_IREG_D0 1399: + TME_FIELD_EXTRACTU(ic->_tme_m68k_insn_opcode, 0, 3)); 1400: 1401: /* if this bitfield wraps the register, put the wrapped 1402: part in the left: */ 1403: if (shift > 32) { 1404: shift -= 32; 1405: ic->tme_m68k_ireg_uint32(ireg) = ((ic->tme_m68k_ireg_uint32(ireg) 1406: & (0xffffffffUL >> shift)) 1407: | (bf_value << (32 - shift))); 1408: bf_value >>= shift; 1409: bf_width -= shift; 1410: } 1411: 1412: /* update the register: */ 1413: shift = (32 - (bf_offset + bf_width)); 1414: ic->tme_m68k_ireg_uint32(ireg) = ((ic->tme_m68k_ireg_uint32(ireg) 1415: & ((TME_BIT(bf_width) - 1) << shift)) 1416: | (bf_value << shift)); 1417: } 1418: 1419: /* otherwise, this bitfield is in memory: */ 1420: else { 1421: 1422: /* read in the bytes covering the bitfield if we haven't yet: */ 1423: bf_bytes = (tme_uint8_t *) &ic->tme_m68k_ireg_memx32; 1424: count = (bf_offset + bf_width + 7) >> 3; 1425: if (first_memory) { 1426: tme_m68k_read_mem(ic, bf_bytes, count); 1427: } 1428: 1429: /* if this bitfield is 5 bytes wide, put the part for the fifth 1430: byte (actually in memy32!) in on the left: */ 1431: if (shift > 32) { 1432: shift -= 32; 1433: if (!TME_M68K_SEQUENCE_RESTARTING) { 1434: bf_bytes[4] = ((bf_bytes[4] 1435: & (0xff >> shift)) 1436: | ((bf_value & 0xff) << (8 - shift))); 1437: } 1438: bf_value >>= shift; 1439: bf_width -= shift; 1440: } 1441: 1442: /* update the memory buffer: */ 1443: if (!TME_M68K_SEQUENCE_RESTARTING) { 1444: shift = (32 - (bf_offset + bf_width)); 1445: ic->tme_m68k_ireg_memx32 = 1446: tme_htobe_u32((tme_betoh_u32(ic->tme_m68k_ireg_memx32) 1447: & ((TME_BIT(bf_width) - 1) << shift)) 1448: | (bf_value << shift)); 1449: } 1450: 1451: /* write out the bytes covering bitfield to memory: */ 1452: tme_m68k_write_mem(ic, bf_bytes, count); 1453: } 1454: #undef first_memory 1455: } 1456: 1457: /* our global verify hook function: */ 1.1.1.2 ! root 1458: #undef tme_m68k_verify_hook 1.1 root 1459: void 1460: tme_m68k_verify_hook(void) 1461: { 1462: } 1463: 1464: #if 1 1465: #include <stdio.h> 1466: 1467: /* this dumps out the m68k state: */ 1468: void 1469: tme_m68k_dump(struct tme_m68k *ic) 1470: { 1471: int ireg; 1472: int count; 1473: 1474: /* dump out the integer registers: */ 1475: count = 0; 1476: for (ireg = TME_M68K_IREG_D0; 1477: ireg <= TME_M68K_IREG_A7; 1478: ireg++) { 1479: fprintf(stderr, 1480: "%%%c%d[%p] = 0x%08x", 1481: (ireg < TME_M68K_IREG_A0 1482: ? 'd' 1483: : 'a'), 1484: ireg - (ireg < TME_M68K_IREG_A0 1485: ? TME_M68K_IREG_D0 1486: : TME_M68K_IREG_A0), 1487: &ic->tme_m68k_ireg_uint32(ireg), 1488: ic->tme_m68k_ireg_uint32(ireg)); 1489: if (++count == 2) { 1490: fprintf(stderr, "\n"); 1491: count = 0; 1492: } 1493: else { 1494: fprintf(stderr, " "); 1495: } 1496: } 1497: 1498: /* dump out the PC and next PC: */ 1499: fprintf(stderr, "%%pc = 0x%08x %%pc_next = 0x%08x\n", 1500: ic->tme_m68k_ireg_pc, 1501: ic->tme_m68k_ireg_pc_next); 1502: 1503: /* dump out the status register: */ 1504: fprintf(stderr, "%%sr = 0x%04x", ic->tme_m68k_ireg_sr); 1505: fprintf(stderr, " flags:"); 1506: if (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X) { 1507: fprintf(stderr, " X"); 1508: } 1509: if (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_N) { 1510: fprintf(stderr, " N"); 1511: } 1512: if (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_Z) { 1513: fprintf(stderr, " Z"); 1514: } 1515: if (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_V) { 1516: fprintf(stderr, " V"); 1517: } 1518: if (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_C) { 1519: fprintf(stderr, " C"); 1520: } 1521: fprintf(stderr, "\n"); 1522: 1523: /* dump out the effective address and memory buffers: */ 1524: fprintf(stderr, "\n"); 1525: fprintf(stderr, "EA = %d:0x%08x\n", 1526: ic->_tme_m68k_ea_function_code, 1527: ic->_tme_m68k_ea_address); 1528: fprintf(stderr, "%%memx[%p] = 0x%08x %%memy[%p] = 0x%08x\n", 1529: &ic->tme_m68k_ireg_memx32, 1530: ic->tme_m68k_ireg_memx32, 1531: &ic->tme_m68k_ireg_memy32, 1532: ic->tme_m68k_ireg_memy32); 1533: 1534: /* dump out the control registers: */ 1535: fprintf(stderr, "\n"); 1536: fprintf(stderr, "%%usp = 0x%08x\n", ic->tme_m68k_ireg_usp); 1537: fprintf(stderr, "%%isp = 0x%08x\n", ic->tme_m68k_ireg_isp); 1538: fprintf(stderr, "%%msp = 0x%08x\n", ic->tme_m68k_ireg_msp); 1539: fprintf(stderr, "%%sfc = 0x%08x\n", ic->tme_m68k_ireg_sfc); 1540: fprintf(stderr, "%%dfc = 0x%08x\n", ic->tme_m68k_ireg_dfc); 1541: fprintf(stderr, "%%vbr = 0x%08x\n", ic->tme_m68k_ireg_vbr); 1542: 1543: /* dump out instruction decoding information: */ 1544: fprintf(stderr, "\n"); 1545: fprintf(stderr, "opcode = 0x%04x specop = 0x%04x specop2 = 0x%04x\n", 1546: ic->_tme_m68k_insn_opcode, 1547: ic->_tme_m68k_insn_specop, 1548: ic->_tme_m68k_insn_specop2); 1549: } 1550: #endif /* 1 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.