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