|
|
1.1 ! root 1: /* $Id: sparc-misc.c,v 1.7 2007/08/24 01:21:50 fredette Exp $ */ ! 2: ! 3: /* ic/sparc/sparc-misc.c - miscellaneous things for the SPARC emulator: */ ! 4: ! 5: /* ! 6: * Copyright (c) 2005 Matt Fredette ! 7: * All rights reserved. ! 8: * ! 9: * Redistribution and use in source and binary forms, with or without ! 10: * modification, are permitted provided that the following conditions ! 11: * are met: ! 12: * 1. Redistributions of source code must retain the above copyright ! 13: * notice, this list of conditions and the following disclaimer. ! 14: * 2. Redistributions in binary form must reproduce the above copyright ! 15: * notice, this list of conditions and the following disclaimer in the ! 16: * documentation and/or other materials provided with the distribution. ! 17: * 3. All advertising materials mentioning features or use of this software ! 18: * must display the following acknowledgement: ! 19: * This product includes software developed by Matt Fredette. ! 20: * 4. The name of the author may not be used to endorse or promote products ! 21: * derived from this software without specific prior written permission. ! 22: * ! 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ! 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ! 25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ! 26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ! 27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ! 28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ! 29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ! 31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ! 32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ! 33: * POSSIBILITY OF SUCH DAMAGE. ! 34: */ ! 35: ! 36: /* includes: */ ! 37: #include "sparc-impl.h" ! 38: ! 39: _TME_RCSID("$Id: sparc-misc.c,v 1.7 2007/08/24 01:21:50 fredette Exp $"); ! 40: ! 41: /* our bus signal handler: */ ! 42: static int ! 43: _tme_sparc_bus_signal(struct tme_bus_connection *conn_bus, unsigned int signal) ! 44: { ! 45: struct tme_sparc *ic; ! 46: unsigned int level_edge; ! 47: ! 48: /* recover our IC: */ ! 49: ic = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private; ! 50: ! 51: /* take out the level and edge: */ ! 52: level_edge = signal; ! 53: signal = TME_BUS_SIGNAL_WHICH(signal); ! 54: level_edge ^= signal; ! 55: ! 56: /* lock the external mutex: */ ! 57: tme_mutex_lock(&ic->tme_sparc_external_mutex); ! 58: ! 59: /* on the falling edge of HALT or RESET, halt the processor: */ ! 60: if (((level_edge & TME_BUS_SIGNAL_LEVEL_MASK) ! 61: == TME_BUS_SIGNAL_LEVEL_ASSERTED) ! 62: && (signal == TME_BUS_SIGNAL_HALT ! 63: || signal == TME_BUS_SIGNAL_RESET)) { ! 64: ic->tme_sparc_external_halt = TRUE; ! 65: } ! 66: ! 67: /* on the rising edge of RESET, reset the processor: */ ! 68: else if (signal == TME_BUS_SIGNAL_RESET ! 69: && ((level_edge & TME_BUS_SIGNAL_LEVEL_MASK) ! 70: == TME_BUS_SIGNAL_LEVEL_NEGATED)) { ! 71: ic->tme_sparc_external_reset = TRUE; ! 72: } ! 73: ! 74: /* on any other HALT or RESET, do nothing: */ ! 75: else if (signal == TME_BUS_SIGNAL_RESET ! 76: || signal == TME_BUS_SIGNAL_HALT) { ! 77: /* nothing */ ! 78: } ! 79: ! 80: /* anything else: */ ! 81: else { ! 82: abort(); ! 83: } ! 84: ! 85: /* unlock the external mutex: */ ! 86: tme_mutex_unlock(&ic->tme_sparc_external_mutex); ! 87: ! 88: /* notify any threads waiting on the external condition: */ ! 89: tme_cond_notify(&ic->tme_sparc_external_cond, TRUE); ! 90: return (TME_OK); ! 91: } ! 92: ! 93: /* our interrupt handler: */ ! 94: static int ! 95: _tme_sparc_bus_interrupt(struct tme_sparc_bus_connection *conn_sparc, unsigned int ipl) ! 96: { ! 97: struct tme_sparc *ic; ! 98: ! 99: /* recover our IC: */ ! 100: ic = conn_sparc->tme_sparc_bus_connection.tme_bus_connection.tme_connection_element->tme_element_private; ! 101: ! 102: /* lock the external mutex: */ ! 103: tme_mutex_lock(&ic->tme_sparc_external_mutex); ! 104: ! 105: /* set the interrupt line: */ ! 106: ic->tme_sparc_external_ipl = ipl; ! 107: ! 108: /* unlock the external mutex: */ ! 109: tme_mutex_unlock(&ic->tme_sparc_external_mutex); ! 110: ! 111: /* notify any threads waiting on the external condition: */ ! 112: tme_cond_notify(&ic->tme_sparc_external_cond, TRUE); ! 113: return (TME_OK); ! 114: } ! 115: ! 116: /* the idle function, used when the processor is halted or stopped: */ ! 117: static void ! 118: tme_sparc_idle(struct tme_sparc *ic) ! 119: { ! 120: /* lock the external mutex: */ ! 121: tme_mutex_lock(&ic->tme_sparc_external_mutex); ! 122: ! 123: /* loop forever: */ ! 124: for (;;) { ! 125: ! 126: /* check for any external signal: */ ! 127: tme_sparc32_external_check(ic); ! 128: ! 129: /* await an external condition: */ ! 130: tme_cond_wait_yield(&ic->tme_sparc_external_cond, &ic->tme_sparc_external_mutex); ! 131: } ! 132: } ! 133: ! 134: /* the sparc thread: */ ! 135: static void ! 136: tme_sparc_thread(struct tme_sparc *ic) ! 137: { ! 138: ! 139: /* we use longjmp to redispatch: */ ! 140: do { } while (setjmp(ic->_tme_sparc_dispatcher)); ! 141: ! 142: /* we must not have a busy instruction TLB entry: */ ! 143: assert (ic->_tme_sparc_itlb_busy == NULL); ! 144: ! 145: /* dispatch on the current mode: */ ! 146: switch (ic->_tme_sparc_mode) { ! 147: ! 148: case TME_SPARC_MODE_EXECUTION: ! 149: (*ic->_tme_sparc_execute)(ic); ! 150: /* NOTREACHED */ ! 151: ! 152: case TME_SPARC_MODE_STOP: ! 153: case TME_SPARC_MODE_HALT: ! 154: tme_sparc_idle(ic); ! 155: /* NOTREACHED */ ! 156: ! 157: default: ! 158: abort(); ! 159: } ! 160: /* NOTREACHED */ ! 161: } ! 162: ! 163: /* the TLB filler for when we are on a generic bus: */ ! 164: static int ! 165: _tme_sparc_generic_tlb_fill(struct tme_sparc_bus_connection *conn_sparc, ! 166: struct tme_sparc_tlb *tlb, ! 167: unsigned int address_space, ! 168: tme_bus_addr_t external_address, ! 169: unsigned int cycles) ! 170: { ! 171: struct tme_sparc *ic; ! 172: ! 173: /* recover our IC: */ ! 174: ic = conn_sparc->tme_sparc_bus_connection.tme_bus_connection.tme_connection_element->tme_element_private; ! 175: ! 176: /* call the generic bus TLB filler: */ ! 177: (ic->_tme_sparc_bus_generic->tme_bus_tlb_fill) ! 178: (ic->_tme_sparc_bus_generic, ! 179: &tlb->tme_sparc_tlb_bus_tlb, ! 180: external_address, ! 181: cycles); ! 182: ! 183: /* when we're on a generic bus a TLB entry is valid for all address spaces: */ ! 184: tlb->tme_sparc_tlb_asi_mask = ((tme_uint32_t) 0) - 1; ! 185: ! 186: return (TME_OK); ! 187: } ! 188: ! 189: /* the sparc command function: */ ! 190: static int ! 191: _tme_sparc_command(struct tme_element *element, const char * const * args, char **_output) ! 192: { ! 193: struct tme_sparc *ic; ! 194: unsigned int idle_type_saved; ! 195: ! 196: /* recover our IC: */ ! 197: ic = (struct tme_sparc *) element->tme_element_private; ! 198: ! 199: /* the "idle-type" command: */ ! 200: if (TME_ARG_IS(args[1], "idle-type")) { ! 201: ! 202: /* save the current idle type and set it to none: */ ! 203: idle_type_saved = ic->tme_sparc_idle_type; ! 204: ic->tme_sparc_idle_type = TME_SPARC_IDLE_TYPE_NULL; ! 205: ! 206: /* if we're not setting the idle type to none: */ ! 207: if (!TME_ARG_IS(args[2], "none")) { ! 208: ! 209: /* check for a supported idle type: */ ! 210: #define _TME_SPARC_IDLE_TYPE(x, s) \ ! 211: do { \ ! 212: if ((TME_SPARC_IDLE_TYPES_SUPPORTED \ ! 213: & (x)) \ ! 214: && TME_ARG_IS(args[2], s)) { \ ! 215: ic->tme_sparc_idle_type = (x); \ ! 216: } \ ! 217: } while (/* CONSTCOND */ 0) ! 218: _TME_SPARC_IDLE_TYPE(TME_SPARC_IDLE_TYPE_NETBSD32_TYPE_0, "netbsd32-type-0"); ! 219: _TME_SPARC_IDLE_TYPE(TME_SPARC_IDLE_TYPE_SUNOS32_TYPE_0, "sunos32-type-0"); ! 220: #undef _TME_SPARC_IDLE_TYPE ! 221: ! 222: /* if the idle type isn't supported: */ ! 223: if (ic->tme_sparc_idle_type == TME_SPARC_IDLE_TYPE_NULL) { ! 224: ! 225: /* restore the idle type and return a usage: */ ! 226: ic->tme_sparc_idle_type = idle_type_saved; ! 227: ! 228: tme_output_append_error(_output, ! 229: "%s %s idle-type { none", ! 230: _("usage:"), ! 231: args[0]); ! 232: ! 233: /* add in the supported idle types: */ ! 234: #define _TME_SPARC_IDLE_TYPE(x, s) \ ! 235: do { \ ! 236: if (TME_SPARC_IDLE_TYPES_SUPPORTED \ ! 237: & (x)) { \ ! 238: tme_output_append_error(_output, " | %s", \ ! 239: s); \ ! 240: } \ ! 241: } while (/* CONSTCOND */ 0) ! 242: _TME_SPARC_IDLE_TYPE(TME_SPARC_IDLE_TYPE_NETBSD32_TYPE_0, "netbsd32-type-0"); ! 243: _TME_SPARC_IDLE_TYPE(TME_SPARC_IDLE_TYPE_SUNOS32_TYPE_0, "sunos32-type-0"); ! 244: #undef _TME_SPARC_IDLE_TYPE ! 245: ! 246: tme_output_append_error(_output, " }"); ! 247: return (EINVAL); ! 248: } ! 249: } ! 250: ! 251: /* poison all idle type state: */ ! 252: ic->tme_sparc_idle_type_pc32 = TME_SPARC_IDLE_TYPE_PC_STATE(1); ! 253: } ! 254: ! 255: /* any other command: */ ! 256: else { ! 257: if (args[1] != NULL) { ! 258: tme_output_append_error(_output, ! 259: "%s '%s', ", ! 260: _("unknown command"), ! 261: args[1]); ! 262: } ! 263: tme_output_append_error(_output, ! 264: _("available %s commands:%s"), ! 265: args[0], ! 266: (TME_SPARC_IDLE_TYPES_SUPPORTED != 0 ! 267: ? " idle-type" ! 268: : "")); ! 269: return (EINVAL); ! 270: } ! 271: ! 272: return (TME_OK); ! 273: } ! 274: ! 275: /* the connection scorer: */ ! 276: static int ! 277: _tme_sparc_connection_score(struct tme_connection *conn, unsigned int *_score) ! 278: { ! 279: struct tme_sparc_bus_connection *conn_sparc; ! 280: struct tme_bus_connection *conn_bus; ! 281: unsigned int score; ! 282: ! 283: /* assume that this connection is useless: */ ! 284: score = 0; ! 285: ! 286: /* dispatch on the connection type: */ ! 287: conn_sparc = (struct tme_sparc_bus_connection *) conn->tme_connection_other; ! 288: conn_bus = (struct tme_bus_connection *) conn->tme_connection_other; ! 289: switch (conn->tme_connection_type) { ! 290: ! 291: /* this must be a bus, and not another sparc chip: */ ! 292: case TME_CONNECTION_BUS_SPARC: ! 293: if (conn_bus->tme_bus_tlb_set_allocate != NULL ! 294: && conn_sparc->tme_sparc_bus_tlb_fill != NULL ! 295: && conn_sparc->tme_sparc_bus_fpu_strict == NULL) { ! 296: score = 10; ! 297: } ! 298: break; ! 299: ! 300: /* this must be a bus, and not another chip: */ ! 301: case TME_CONNECTION_BUS_GENERIC: ! 302: if (conn_bus->tme_bus_tlb_set_allocate != NULL ! 303: && conn_bus->tme_bus_tlb_fill != NULL) { ! 304: score = 1; ! 305: } ! 306: break; ! 307: ! 308: default: abort(); ! 309: } ! 310: ! 311: *_score = score; ! 312: return (TME_OK); ! 313: } ! 314: ! 315: /* this makes a new connection: */ ! 316: static int ! 317: _tme_sparc_connection_make(struct tme_connection *conn, unsigned int state) ! 318: { ! 319: struct tme_sparc *ic; ! 320: struct tme_sparc_bus_connection *conn_sparc; ! 321: struct tme_bus_connection *conn_bus; ! 322: struct tme_connection *conn_other; ! 323: ! 324: /* since the CPU is halted, it won't be making any connection calls, ! 325: so we only have to do work when the connection is fully made: */ ! 326: if (state == TME_CONNECTION_FULL) { ! 327: ! 328: /* recover our IC: */ ! 329: ic = conn->tme_connection_element->tme_element_private; ! 330: ! 331: /* dispatch on the connection type: */ ! 332: conn_other = conn->tme_connection_other; ! 333: conn_sparc = (struct tme_sparc_bus_connection *) conn_other; ! 334: conn_bus = (struct tme_bus_connection *) conn_other; ! 335: switch (conn->tme_connection_type) { ! 336: ! 337: case TME_CONNECTION_BUS_SPARC: ! 338: ic->_tme_sparc_bus_connection = conn_sparc; ! 339: break; ! 340: ! 341: /* we need an adaptation layer: */ ! 342: case TME_CONNECTION_BUS_GENERIC: ! 343: conn_sparc = tme_new0(struct tme_sparc_bus_connection, 1); ! 344: conn_sparc->tme_sparc_bus_connection.tme_bus_connection.tme_connection_element = conn->tme_connection_element; ! 345: conn_sparc->tme_sparc_bus_tlb_fill = _tme_sparc_generic_tlb_fill; ! 346: ic->_tme_sparc_bus_connection = conn_sparc; ! 347: ic->_tme_sparc_bus_generic = conn_bus; ! 348: break; ! 349: ! 350: default: abort(); ! 351: } ! 352: ! 353: /* allocate the DTLB hash set: */ ! 354: (*ic->_tme_sparc_bus_connection->tme_sparc_bus_connection.tme_bus_tlb_set_allocate) ! 355: (&ic->_tme_sparc_bus_connection->tme_sparc_bus_connection, ! 356: _TME_SPARC_DTLB_HASH_SIZE, ! 357: sizeof(struct tme_sparc_tlb), ! 358: &ic->_tme_sparc_dtlb_array_bus, ! 359: &ic->_tme_sparc_tlb_rwlock); ! 360: ! 361: /* allocate the ITLB hash set: */ ! 362: (*ic->_tme_sparc_bus_connection->tme_sparc_bus_connection.tme_bus_tlb_set_allocate) ! 363: (&ic->_tme_sparc_bus_connection->tme_sparc_bus_connection, ! 364: _TME_SPARC_ITLB_HASH_SIZE, ! 365: sizeof(struct tme_sparc_tlb), ! 366: &ic->_tme_sparc_itlb_array_bus, ! 367: &ic->_tme_sparc_tlb_rwlock); ! 368: } ! 369: ! 370: /* NB: the machine needs to issue a reset to bring the CPU out of halt. */ ! 371: return (TME_OK); ! 372: } ! 373: ! 374: /* this breaks a connection: */ ! 375: static int ! 376: _tme_sparc_connection_break(struct tme_connection *conn, unsigned int state) ! 377: { ! 378: abort(); ! 379: return (0); ! 380: } ! 381: ! 382: /* this makes new connection sides: */ ! 383: static int ! 384: _tme_sparc_connections_new(struct tme_element *element, const char * const *args, struct tme_connection **_conns, char **_output) ! 385: { ! 386: struct tme_sparc_bus_connection *conn_sparc; ! 387: struct tme_bus_connection *conn_bus; ! 388: struct tme_connection *conn; ! 389: ! 390: /* if we already have a bus connection, we can take no more connections: */ ! 391: if (((struct tme_sparc *) element->tme_element_private)->_tme_sparc_bus_connection != NULL) { ! 392: return (TME_OK); ! 393: } ! 394: ! 395: /* create our side of an sparc bus connection: */ ! 396: conn_sparc = tme_new0(struct tme_sparc_bus_connection, 1); ! 397: conn_bus = &conn_sparc->tme_sparc_bus_connection; ! 398: conn = &conn_bus->tme_bus_connection; ! 399: ! 400: /* fill in the generic connection: */ ! 401: conn->tme_connection_next = *_conns; ! 402: conn->tme_connection_type = TME_CONNECTION_BUS_SPARC; ! 403: conn->tme_connection_score = _tme_sparc_connection_score; ! 404: conn->tme_connection_make = _tme_sparc_connection_make; ! 405: conn->tme_connection_break = _tme_sparc_connection_break; ! 406: ! 407: /* fill in the generic bus connection: */ ! 408: conn_bus->tme_bus_signal = _tme_sparc_bus_signal; ! 409: conn_bus->tme_bus_tlb_set_allocate = NULL; ! 410: ! 411: /* full in the sparc bus connection: */ ! 412: conn_sparc->tme_sparc_bus_interrupt = _tme_sparc_bus_interrupt; ! 413: conn_sparc->tme_sparc_bus_tlb_fill = NULL; ! 414: conn_sparc->tme_sparc_bus_fpu_strict = tme_sparc_fpu_strict; ! 415: ! 416: /* add this connection to the set of possibilities: */ ! 417: *_conns = conn; ! 418: ! 419: /* create our side of a generic bus connection: */ ! 420: conn_bus = tme_new0(struct tme_bus_connection, 1); ! 421: conn = &conn_bus->tme_bus_connection; ! 422: ! 423: /* fill in the generic connection: */ ! 424: conn->tme_connection_next = *_conns; ! 425: conn->tme_connection_type = TME_CONNECTION_BUS_GENERIC; ! 426: conn->tme_connection_score = _tme_sparc_connection_score; ! 427: conn->tme_connection_make = _tme_sparc_connection_make; ! 428: conn->tme_connection_break = _tme_sparc_connection_break; ! 429: ! 430: /* fill in the generic bus connection: */ ! 431: conn_bus->tme_bus_signal = _tme_sparc_bus_signal; ! 432: conn_bus->tme_bus_tlb_set_allocate = NULL; ! 433: conn_bus->tme_bus_tlb_fill = NULL; ! 434: ! 435: /* add this connection to the set of possibilities: */ ! 436: *_conns = conn; ! 437: ! 438: /* done: */ ! 439: return (TME_OK); ! 440: } ! 441: ! 442: /* the common sparc new function: */ ! 443: int ! 444: tme_sparc_new(struct tme_sparc *ic, const char * const *args, const void *extra, char **_output) ! 445: { ! 446: struct tme_element *element; ! 447: int arg_i; ! 448: int usage; ! 449: ! 450: /* assume that we have no FPU: */ ! 451: ic->tme_sparc_fpu_fsr = TME_SPARC_FSR_VER_missing; ! 452: ! 453: /* check our arguments: */ ! 454: arg_i = 1; ! 455: usage = FALSE; ! 456: for (;;) { ! 457: ! 458: if (0) { ! 459: ! 460: } ! 461: ! 462: /* if we've run out of arguments: */ ! 463: else if (args[arg_i + 0] == NULL) { ! 464: break; ! 465: } ! 466: ! 467: /* this is either a bad argument or an FPU argument: */ ! 468: else { ! 469: ! 470: /* if this is not an FPU argument: */ ! 471: if (!tme_sparc_fpu_new(ic, args, &arg_i, &usage, _output)) { ! 472: tme_output_append_error(_output, ! 473: "%s %s, ", ! 474: args[arg_i], ! 475: _("unexpected")); ! 476: usage = TRUE; ! 477: } ! 478: ! 479: if (usage) { ! 480: break; ! 481: } ! 482: } ! 483: } ! 484: ! 485: if (usage) { ! 486: tme_output_append_error(_output, ! 487: "%s %s", ! 488: _("usage:"), ! 489: args[0]); ! 490: tme_sparc_fpu_usage(ic, _output); ! 491: tme_free(ic); ! 492: return (EINVAL); ! 493: } ! 494: ! 495: /* initialize the verifier: */ ! 496: tme_sparc_verify_init(); ! 497: ! 498: /* we have no bus connection yet: */ ! 499: ic->_tme_sparc_bus_connection = NULL; ! 500: ! 501: /* fill the element: */ ! 502: element = ic->tme_sparc_element; ! 503: element->tme_element_private = ic; ! 504: element->tme_element_connections_new = _tme_sparc_connections_new; ! 505: element->tme_element_command = _tme_sparc_command; ! 506: ! 507: /* calculate the instruction burst size: */ ! 508: /* XXX TBD: */ ! 509: ic->_tme_sparc_instruction_burst = 800; ! 510: ic->_tme_sparc_instruction_burst_remaining ! 511: = ic->_tme_sparc_instruction_burst; ! 512: ! 513: /* force the processor to be halted: */ ! 514: ic->_tme_sparc_mode = TME_SPARC_MODE_HALT; ! 515: ! 516: /* poison all idle type state: */ ! 517: ic->tme_sparc_idle_type_pc32 = TME_SPARC_IDLE_TYPE_PC_STATE(1); ! 518: ! 519: /* start the sparc thread: */ ! 520: tme_thread_create((tme_thread_t) tme_sparc_thread, ic); ! 521: ! 522: return (TME_OK); ! 523: } ! 524: ! 525: /* this redispatches: */ ! 526: void ! 527: tme_sparc_redispatch(struct tme_sparc *ic) ! 528: { ! 529: struct tme_sparc_tlb *tlb; ! 530: ! 531: /* if we have a busy instruction TLB entry: */ ! 532: tlb = ic->_tme_sparc_itlb_busy; ! 533: if (__tme_predict_true(tlb != NULL)) { ! 534: ! 535: /* unbusy and forget the instruction TLB entry: */ ! 536: tme_sparc_tlb_unbusy(tlb); ! 537: ic->_tme_sparc_itlb_busy = NULL; ! 538: } ! 539: ! 540: /* do the redispatch: */ ! 541: #ifdef _TME_SPARC_STATS ! 542: ic->tme_sparc_stats.tme_sparc_stats_redispatches++; ! 543: #endif /* _TME_SPARC_STATS */ ! 544: longjmp(ic->_tme_sparc_dispatcher, 1); ! 545: } ! 546: ! 547: /* our global verify hook function: */ ! 548: #undef tme_sparc_verify_hook ! 549: void ! 550: tme_sparc_verify_hook(void) ! 551: { ! 552: } ! 553: ! 554: /* the common sparc reset function: */ ! 555: void ! 556: tme_sparc_do_reset(struct tme_sparc *ic) ! 557: { ! 558: ! 559: /* if this is a v7 or v8 CPU: */ ! 560: if (ic->tme_sparc_version < 9) { ! 561: ! 562: /* set the initial PCs: */ ! 563: ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC_NEXT) = 0; ! 564: ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC_NEXT_NEXT) = sizeof(tme_uint32_t); ! 565: ! 566: /* force supervisor mode, traps disabled: */ ! 567: ic->tme_sparc32_ireg_psr ! 568: = ((ic->tme_sparc32_ireg_psr ! 569: & ~TME_SPARC32_PSR_ET) ! 570: | TME_SPARC32_PSR_S); ! 571: } ! 572: ! 573: /* otherwise, this is a v9 CPU: */ ! 574: else { ! 575: ! 576: /* XXX WRITEME */ ! 577: abort(); ! 578: } ! 579: ! 580: /* reset the FPU: */ ! 581: tme_sparc_fpu_reset(ic); ! 582: ! 583: /* poison all idle type state, to force the idle type to retrain: */ ! 584: ic->tme_sparc_idle_type_pc32 = TME_SPARC_IDLE_TYPE_PC_STATE(1); ! 585: ! 586: /* start execution: */ ! 587: ic->_tme_sparc_mode = TME_SPARC_MODE_EXECUTION; ! 588: tme_sparc_redispatch(ic); ! 589: } ! 590: ! 591: /* the common sparc idle function: */ ! 592: void ! 593: tme_sparc_do_idle(struct tme_sparc *ic) ! 594: { ! 595: ! 596: /* NB: since the interrupt that causes us to leave stop mode will ! 597: call tme_sparc32_trap_preinstruction(), this function can only be ! 598: called on a preinstruction boundary (i.e., while PC still points ! 599: to the (completed!) instruction that triggered the idle ! 600: condition): */ ! 601: ! 602: /* redispatch into stop mode: */ ! 603: ic->_tme_sparc_mode = TME_SPARC_MODE_STOP; ! 604: tme_sparc_redispatch(ic); ! 605: } ! 606: ! 607: /* this checks for external signals. this must be called with the ! 608: external mutex held: */ ! 609: void ! 610: tme_sparc32_external_check(struct tme_sparc *ic) ! 611: { ! 612: unsigned int ipl; ! 613: int vector; ! 614: ! 615: /* if an external reset has been requested, start reset trap ! 616: processing: */ ! 617: if (ic->tme_sparc_external_reset) { ! 618: ic->tme_sparc_external_reset = FALSE; ! 619: tme_mutex_unlock(&ic->tme_sparc_external_mutex); ! 620: tme_sparc32_trap_preinstruction(ic, TME_SPARC_TRAP_reset); ! 621: } ! 622: ! 623: /* if an external halt has been requested, halt: */ ! 624: if (ic->tme_sparc_external_halt) { ! 625: ic->tme_sparc_external_halt = FALSE; ! 626: tme_mutex_unlock(&ic->tme_sparc_external_mutex); ! 627: ic->_tme_sparc_mode = TME_SPARC_MODE_HALT; ! 628: tme_sparc_redispatch(ic); ! 629: } ! 630: ! 631: /* if we are not halted and an interrupt can be serviced, start ! 632: interrupt trap processing: */ ! 633: ipl = ic->tme_sparc_external_ipl; ! 634: if (ic->_tme_sparc_mode != TME_SPARC_MODE_HALT ! 635: && (ic->tme_sparc32_ireg_psr & TME_SPARC32_PSR_ET) ! 636: && ipl >= TME_SPARC_IPL_MIN ! 637: && ipl <= TME_SPARC_IPL_MAX ! 638: && (ipl == TME_SPARC_IPL_NMI ! 639: || ipl > TME_FIELD_MASK_EXTRACTU(ic->tme_sparc32_ireg_psr, TME_SPARC32_PSR_PIL))) { ! 640: ! 641: tme_mutex_unlock(&ic->tme_sparc_external_mutex); ! 642: ! 643: /* acknowledge the interrupt: */ ! 644: (*ic->_tme_sparc_bus_connection->tme_sparc_bus_connection.tme_bus_intack) ! 645: (&ic->_tme_sparc_bus_connection->tme_sparc_bus_connection, ! 646: ipl, &vector); ! 647: ! 648: /* dispatch the trap: */ ! 649: tme_sparc32_trap_preinstruction(ic, TME_SPARC_TRAP_interrupt_level(ipl)); ! 650: } ! 651: ! 652: /* there are no traps to process: */ ! 653: } ! 654: ! 655: /* this triggers sparc32 trap processing on a preinstruction boundary: */ ! 656: void ! 657: tme_sparc32_trap_preinstruction(struct tme_sparc *ic, tme_uint32_t trap) ! 658: { ! 659: ! 660: /* shift the next instruction's PC and next-next PC up: */ ! 661: ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC) = ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC_NEXT); ! 662: ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC_NEXT) = ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC_NEXT_NEXT); ! 663: ! 664: /* do the rest of the sparc32 trap processing: */ ! 665: tme_sparc32_trap(ic, trap); ! 666: } ! 667: ! 668: /* this triggers sparc32 trap processing by an instruction: */ ! 669: void ! 670: tme_sparc32_trap(struct tme_sparc *ic, tme_uint32_t trap) ! 671: { ! 672: unsigned int cwp; ! 673: unsigned int cwp_offset; ! 674: ! 675: /* reset traps are handled specially: */ ! 676: if (__tme_predict_false(trap == TME_SPARC_TRAP_reset)) { ! 677: tme_sparc_do_reset(ic); ! 678: /* NOTREACHED */ ! 679: } ! 680: ! 681: /* "The processor enters error_mode state when a trap occurs while ! 682: ET = 0. An implementation should preserve as much processor state ! 683: as possible when this happens. Standard trap actions (such as ! 684: decrementing CWP and saving state information in locals) should ! 685: not occur when entering error_mode. In particular, the tt field ! 686: of the TBR is only written during a transition into error_mode ! 687: state in the singular case of a RETT instruction that traps while ! 688: ET = 0. In this case, tt is written to indicate the type of ! 689: exception that was induced by the RETT instruction. ! 690: ! 691: What occurs after error_mode is entered is ! 692: implementation-dependent; typically the processor triggers an ! 693: external reset, causing a reset trap (see below). */ ! 694: if (__tme_predict_false((ic->tme_sparc32_ireg_psr & TME_SPARC32_PSR_ET) == 0)) { ! 695: ! 696: /* if we were executing a RETT instruction: */ ! 697: assert (ic->_tme_sparc_mode == TME_SPARC_MODE_EXECUTION); ! 698: if ((ic->_tme_sparc_insn ! 699: & ((3 << 30) | (0x3f << 19))) ! 700: == ((tme_uint32_t) (2 << 30) | (0x39 << 19))) { ! 701: ! 702: /* update the TBR register: */ ! 703: TME_FIELD_MASK_DEPOSITU(ic->tme_sparc32_ireg_tbr, 0xff, trap); ! 704: } ! 705: ! 706: /* reset the processor: */ ! 707: tme_log(TME_SPARC_LOG_HANDLE(ic), 0, EPERM, ! 708: (TME_SPARC_LOG_HANDLE(ic), ! 709: _("took a trap while traps disabled, processor reset"))); ! 710: tme_sparc32_trap(ic, TME_SPARC_TRAP_reset); ! 711: } ! 712: ! 713: /* "Traps are disabled: ET <- 0. ! 714: The existing user/supervisor mode is preserved: PS <- S. ! 715: The user/supervisor mode is changed to supervisor: S <- 1." */ ! 716: ic->tme_sparc32_ireg_psr ! 717: = ((ic->tme_sparc32_ireg_psr ! 718: & ~(TME_SPARC32_PSR_ET ! 719: | TME_SPARC32_PSR_PS)) ! 720: | ((ic->tme_sparc32_ireg_psr ! 721: & TME_SPARC32_PSR_S) ! 722: / (TME_SPARC32_PSR_S ! 723: / TME_SPARC32_PSR_PS)) ! 724: | TME_SPARC32_PSR_S); ! 725: ! 726: /* "The register window is advanced to a new window: ! 727: CWP <- ((CWP - 1) modulo NWINDOWS) ! 728: [note: without test for window overflow]." */ ! 729: cwp = TME_FIELD_MASK_EXTRACTU(ic->tme_sparc32_ireg_psr, TME_SPARC32_PSR_CWP); ! 730: cwp -= 1; ! 731: cwp %= ic->tme_sparc_nwindows; ! 732: TME_FIELD_MASK_DEPOSITU(ic->tme_sparc32_ireg_psr, TME_SPARC32_PSR_CWP, cwp); ! 733: cwp_offset = TME_SPARC_CWP_OFFSET(cwp); ! 734: ic->tme_sparc_cwp_offset = cwp_offset; ! 735: ! 736: /* "The trapped program counters are saved in local registers 1 and ! 737: 2 of the new window: r[17] <- PC, r[18] <- nPC." */ ! 738: ic->tme_sparc_ireg_uint32(cwp_offset + 17) = ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC); ! 739: ic->tme_sparc_ireg_uint32(cwp_offset + 18) = ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC_NEXT); ! 740: ! 741: /* "The tt field is written to the particular value that identifies ! 742: the exception or interrupt request, except as defined for `Reset ! 743: Trap' and `Error Mode' above." */ ! 744: TME_FIELD_MASK_DEPOSITU(ic->tme_sparc32_ireg_tbr, 0x00000ff0, trap); ! 745: ! 746: /* "If the trap is not a reset trap, control is transferred into the ! 747: trap table: PC <- TBR, nPC <- TBR + 4." */ ! 748: ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC_NEXT) = ic->tme_sparc32_ireg_tbr; ! 749: ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC_NEXT_NEXT) = ic->tme_sparc32_ireg_tbr + sizeof(tme_uint32_t); ! 750: ! 751: /* redispatch: */ ! 752: ic->_tme_sparc_mode = TME_SPARC_MODE_EXECUTION; ! 753: tme_sparc_redispatch(ic); ! 754: } ! 755: ! 756: /* the default slow instruction fetcher: */ ! 757: tme_uint32_t ! 758: tme_sparc32_fetch_slow(struct tme_sparc *ic, int annulled) ! 759: { ! 760: tme_uint32_t pc; ! 761: const tme_shared tme_uint8_t *memory; ! 762: struct tme_sparc_tlb *dtlb; ! 763: tme_uint32_t insn; ! 764: ! 765: /* get the PC of the instruction: */ ! 766: pc = ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC); ! 767: ! 768: /* XXX FIXME - unfortunately, using tme_sparc32_load() means that we ! 769: we have to pollute the DTLB here: */ ! 770: /* get and busy the DTLB entry: */ ! 771: dtlb = TME_SPARC_DTLB_ENTRY(ic, pc); ! 772: tme_sparc_tlb_busy(dtlb); ! 773: ! 774: /* do a load for an instruction: */ ! 775: memory ! 776: = tme_sparc32_load(ic, ! 777: pc, ! 778: (sizeof(tme_uint32_t) ! 779: | TME_SPARC_SLOW_FLAG_INSN ! 780: | (annulled ! 781: ? TME_SPARC_SLOW_FLAG_NO_FAULTS ! 782: : 0))); ! 783: ! 784: /* if this instruction is annulled: */ ! 785: if (annulled) { ! 786: ! 787: /* we can return anything: */ ! 788: insn = 0; ! 789: } ! 790: ! 791: /* otherwise, this instruction is not annulled: */ ! 792: else { ! 793: ! 794: /* XXX FIXME - we don't currently finish a real slow load: */ ! 795: abort(); ! 796: } ! 797: ! 798: /* unbusy the DTLB entry: */ ! 799: tme_sparc_tlb_unbusy(dtlb); ! 800: ! 801: /* return the instruction: */ ! 802: return (insn); ! 803: } ! 804: ! 805: /* the default bus fault to trap mapping function: */ ! 806: tme_uint32_t ! 807: tme_sparc32_bus_fault(struct tme_sparc *ic, ! 808: const struct tme_bus_cycle *cycle, ! 809: unsigned int flags, ! 810: int err) ! 811: { ! 812: switch (err) { ! 813: case EFAULT: ! 814: case ENOENT: ! 815: case EIO: ! 816: if (flags & TME_SPARC_SLOW_FLAG_INSN) { ! 817: return ((flags & TME_SPARC_SLOW_FLAG_NO_FAULTS) ! 818: ? TME_SPARC_TRAP_none ! 819: : TME_SPARC_TRAP_instruction_access_exception); ! 820: } ! 821: assert (!(flags & TME_SPARC_SLOW_FLAG_NO_FAULTS)); ! 822: return (TME_SPARC_TRAP_data_access_exception); ! 823: default: abort(); ! 824: } ! 825: } ! 826: ! 827: /* this triggers sparc64 trap processing by an instruction: */ ! 828: void ! 829: tme_sparc64_trap(struct tme_sparc *ic, tme_uint32_t trap) ! 830: { ! 831: abort(); ! 832: } ! 833: ! 834: /* this fetches an instruction close enough to the current instruction ! 835: that it should be within the current instruction TLB entry. it ! 836: returns all-bits-one if the instruction isn't within the current ! 837: instruction TLB entry: */ ! 838: tme_uint32_t ! 839: tme_sparc_fetch_nearby(struct tme_sparc *ic, long offset_in_insns) ! 840: { ! 841: struct tme_sparc_tlb *itlb_current; ! 842: tme_bus_addr_t pc; ! 843: tme_uint32_t insn; ! 844: ! 845: /* get the address of the current instruction: */ ! 846: pc = ( ! 847: #ifdef TME_HAVE_INT64_T ! 848: (TME_SPARC_VERSION(ic) >= 9) ! 849: ? ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC) ! 850: : ! 851: #endif /* TME_HAVE_INT64_T */ ! 852: ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC)); ! 853: ! 854: /* assume that we can't fetch the nearby instruction: */ ! 855: insn = 0xffffffff; ! 856: ! 857: /* there must be a current instruction TLB entry, and it must be ! 858: busy, cover this ASI and address, and allow fast reading: */ ! 859: itlb_current = ic->_tme_sparc_itlb_busy; ! 860: assert (itlb_current != NULL); ! 861: /* XXX FIXME - there should be a tme_bus_tlb_assert_busy(): */ ! 862: assert (TME_SPARC_TLB_ASI_MASK_OK(itlb_current, ic->tme_sparc_asi_mask_insn)); ! 863: assert (itlb_current->tme_sparc_tlb_addr_first <= pc ! 864: && pc <= itlb_current->tme_sparc_tlb_addr_last); ! 865: assert (itlb_current->tme_sparc_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF); ! 866: ! 867: /* adjust the address to point to the nearby instruction: */ ! 868: pc += offset_in_insns * sizeof(tme_uint32_t); ! 869: ! 870: /* if the instruction TLB entry is valid and also covers this address: */ ! 871: if (tme_bus_tlb_is_valid(&itlb_current->tme_sparc_tlb_bus_tlb) ! 872: && itlb_current->tme_sparc_tlb_addr_first <= pc ! 873: && pc <= itlb_current->tme_sparc_tlb_addr_last) { ! 874: ! 875: /* fetch the nearby instruction: */ ! 876: insn = tme_memory_bus_read32((const tme_shared tme_uint32_t *) (itlb_current->tme_sparc_tlb_emulator_off_read + pc), ! 877: itlb_current->tme_sparc_tlb_bus_rwlock, ! 878: sizeof(tme_uint32_t), ! 879: (TME_SPARC_VERSION(ic) < 9 ! 880: ? sizeof(tme_uint32_t) ! 881: : sizeof(tme_uint32_t) * 2)); ! 882: insn = tme_betoh_u32(insn); ! 883: } ! 884: ! 885: return (insn); ! 886: } ! 887: ! 888: /* this unlocks data structures before a callout: */ ! 889: void ! 890: tme_sparc_callout_unlock(struct tme_sparc *ic) ! 891: { ! 892: struct tme_sparc_tlb *tlb; ! 893: ! 894: assert ((ic->_tme_sparc_mode == TME_SPARC_MODE_EXECUTION) ! 895: || (ic->_tme_sparc_itlb_busy == NULL)); ! 896: ! 897: /* if we have a busy instruction TLB entry: */ ! 898: tlb = ic->_tme_sparc_itlb_busy; ! 899: if (__tme_predict_true(tlb != NULL)) { ! 900: ! 901: /* unbusy the instruction TLB entry: */ ! 902: tme_sparc_tlb_unbusy(tlb); ! 903: } ! 904: } ! 905: ! 906: /* this relocks data structures after a callout: */ ! 907: void ! 908: tme_sparc_callout_relock(struct tme_sparc *ic) ! 909: { ! 910: struct tme_sparc_tlb *tlb; ! 911: ! 912: assert ((ic->_tme_sparc_mode == TME_SPARC_MODE_EXECUTION) ! 913: || (ic->_tme_sparc_itlb_busy == NULL)); ! 914: ! 915: /* if we have a busy instruction TLB entry: */ ! 916: tlb = ic->_tme_sparc_itlb_busy; ! 917: if (__tme_predict_true(tlb != NULL)) { ! 918: ! 919: /* rebusy the instruction TLB entry: */ ! 920: tme_sparc_tlb_busy(tlb); ! 921: ! 922: /* if this instruction TLB entry is invalid: */ ! 923: if (tme_bus_tlb_is_invalid(&tlb->tme_sparc_tlb_bus_tlb)) { ! 924: ! 925: /* poison this instruction TLB entry, so we won't try to do any ! 926: fast fetches with it: */ ! 927: tlb->tme_sparc_tlb_addr_first = 1; ! 928: tlb->tme_sparc_tlb_addr_last = 0; ! 929: } ! 930: } ! 931: } ! 932: ! 933: #if 0 ! 934: #include <stdio.h> ! 935: ! 936: /* this dumps out the sparc state: */ ! 937: void ! 938: tme_sparc32_dump(const struct tme_sparc *ic) ! 939: { ! 940: unsigned int cwp_first; ! 941: unsigned int cwp; ! 942: unsigned int reg_i; ! 943: unsigned int reg_base; ! 944: unsigned int ireg; ! 945: ! 946: /* dump out the windowed integer registers, finishing with the ! 947: current window: */ ! 948: cwp_first = TME_FIELD_MASK_EXTRACTU(ic->tme_sparc32_ireg_psr, TME_SPARC32_PSR_CWP); ! 949: cwp_first += TME_SPARC_NWINDOWS(ic) - 1; ! 950: cwp_first %= TME_SPARC_NWINDOWS(ic); ! 951: cwp = cwp_first; ! 952: do { ! 953: for (reg_i = 0; reg_i < 8; reg_i++) { ! 954: for (reg_base = 24; reg_base > 8; reg_base -= 8) { ! 955: ! 956: ireg = reg_base + reg_i + TME_SPARC_CWP_OFFSET(cwp); ! 957: if (ireg > (TME_SPARC_CWP_OFFSET(TME_SPARC_NWINDOWS(ic)) + 7)) { ! 958: ireg -= TME_SPARC_CWP_OFFSET(TME_SPARC_NWINDOWS(ic)); ! 959: } ! 960: ! 961: fprintf(stderr, ! 962: "w%u.%%%c%u[%p] = 0x%08x ", ! 963: cwp, ! 964: (reg_base == 24 ! 965: ? 'i' ! 966: : 'l'), ! 967: reg_i, ! 968: &ic->tme_sparc_ireg_uint32(ireg), ! 969: ic->tme_sparc_ireg_uint32(ireg)); ! 970: } ! 971: fprintf(stderr, "\n"); ! 972: } ! 973: cwp--; ! 974: cwp %= TME_SPARC_NWINDOWS(ic); ! 975: } while (cwp != cwp_first); ! 976: ! 977: /* dump out the global registers and the current window's output ! 978: registers: */ ! 979: cwp = TME_FIELD_MASK_EXTRACTU(ic->tme_sparc32_ireg_psr, TME_SPARC32_PSR_CWP); ! 980: for (reg_i = 0; reg_i < 8; reg_i++) { ! 981: ! 982: ireg = reg_i; ! 983: fprintf(stderr, ! 984: " %%g%u[%p] = 0x%08x ", ! 985: ireg, ! 986: &ic->tme_sparc_ireg_uint32(ireg), ! 987: ic->tme_sparc_ireg_uint32(ireg)); ! 988: ! 989: ireg = 8 + reg_i + TME_SPARC_CWP_OFFSET(cwp); ! 990: if (ireg > (TME_SPARC_CWP_OFFSET(TME_SPARC_NWINDOWS(ic)) + 7)) { ! 991: ireg -= TME_SPARC_CWP_OFFSET(TME_SPARC_NWINDOWS(ic)); ! 992: } ! 993: ! 994: fprintf(stderr, ! 995: "w%u.%%o%u[%p] = 0x%08x ", ! 996: cwp, ! 997: reg_i, ! 998: &ic->tme_sparc_ireg_uint32(ireg), ! 999: ic->tme_sparc_ireg_uint32(ireg)); ! 1000: fprintf(stderr, "\n"); ! 1001: } ! 1002: ! 1003: /* dump out the PCs: */ ! 1004: fprintf(stderr, "%%pc = 0x%08x %%pc_next = 0x%08x %%pc_next_next = 0x%08x\n", ! 1005: ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC), ! 1006: ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC_NEXT), ! 1007: ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC_NEXT_NEXT)); ! 1008: ! 1009: /* dump out the PSR: */ ! 1010: fprintf(stderr, "%%psr = 0x%08x", ic->tme_sparc32_ireg_psr); ! 1011: fprintf(stderr, " cwp = %u", ! 1012: TME_FIELD_MASK_EXTRACTU(ic->tme_sparc32_ireg_psr, TME_SPARC32_PSR_CWP)); ! 1013: fprintf(stderr, " pil = 0x%x", ! 1014: TME_FIELD_MASK_EXTRACTU(ic->tme_sparc32_ireg_psr, TME_SPARC32_PSR_PIL)); ! 1015: if (ic->tme_sparc32_ireg_psr & TME_SPARC32_PSR_ET) { ! 1016: fprintf(stderr, " ET"); ! 1017: } ! 1018: fprintf(stderr, " %c", ! 1019: (ic->tme_sparc32_ireg_psr & TME_SPARC32_PSR_S ! 1020: ? 'S' ! 1021: : 'U')); ! 1022: fprintf(stderr, " flags:"); ! 1023: if (ic->tme_sparc32_ireg_psr & TME_SPARC32_PSR_ICC_N) { ! 1024: fprintf(stderr, " N"); ! 1025: } ! 1026: if (ic->tme_sparc32_ireg_psr & TME_SPARC32_PSR_ICC_Z) { ! 1027: fprintf(stderr, " Z"); ! 1028: } ! 1029: if (ic->tme_sparc32_ireg_psr & TME_SPARC32_PSR_ICC_V) { ! 1030: fprintf(stderr, " V"); ! 1031: } ! 1032: if (ic->tme_sparc32_ireg_psr & TME_SPARC32_PSR_ICC_C) { ! 1033: fprintf(stderr, " C"); ! 1034: } ! 1035: fprintf(stderr, "\n"); ! 1036: ! 1037: /* dump out the instruction and the WIM: */ ! 1038: fprintf(stderr, "insn = 0x%08x %%wim = 0x%08x\n", ! 1039: ic->_tme_sparc_insn, ! 1040: ic->tme_sparc32_ireg_wim); ! 1041: } ! 1042: ! 1043: void ! 1044: tme_sparc32_dump_memory(struct tme_sparc *ic, tme_uint32_t address, tme_uint32_t resid) ! 1045: { ! 1046: tme_uint32_t address_display; ! 1047: struct tme_sparc_tlb *dtlb; ! 1048: tme_memory_atomic_flag_t tlb_busy_old; ! 1049: const tme_shared tme_uint8_t *memory; ! 1050: tme_uint32_t count; ! 1051: tme_uint32_t byte_i; ! 1052: ! 1053: /* we always display aligned rows: */ ! 1054: address_display = address & (((tme_uint32_t) 0) - (sizeof(tme_uint32_t) * 2)); ! 1055: resid += (address - address_display); ! 1056: ! 1057: /* while we have memory to dump: */ ! 1058: for (; resid > 0; ) { ! 1059: ! 1060: /* get the DTLB entry, and busy it if it isn't already: */ ! 1061: dtlb = TME_SPARC_DTLB_ENTRY(ic, address_display); ! 1062: tlb_busy_old = dtlb->tme_sparc_tlb_bus_tlb.tme_bus_tlb_busy; ! 1063: dtlb->tme_sparc_tlb_bus_tlb.tme_bus_tlb_busy = TRUE; ! 1064: ! 1065: /* read more data: */ ! 1066: count = TME_MIN(resid, sizeof(tme_uint32_t) * 2); ! 1067: memory ! 1068: = tme_sparc32_load(ic, ! 1069: address_display, ! 1070: (sizeof(tme_uint32_t) * 2)); ! 1071: ! 1072: /* restore the DTLB busy flag: */ ! 1073: dtlb->tme_sparc_tlb_bus_tlb.tme_bus_tlb_busy = tlb_busy_old; ! 1074: ! 1075: /* display the row: */ ! 1076: fprintf(stderr, "0x%08x ", address_display); ! 1077: for (byte_i = 0; ! 1078: byte_i < count; ! 1079: byte_i++, address_display++) { ! 1080: if (address_display < address) { ! 1081: fprintf(stderr, " "); ! 1082: } ! 1083: else { ! 1084: fprintf(stderr, " %02x", ! 1085: memory[address_display]); ! 1086: address++; ! 1087: } ! 1088: resid--; ! 1089: } ! 1090: fputc('\n', stderr); ! 1091: } ! 1092: } ! 1093: #endif /* 1 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.