|
|
1.1 ! root 1: /* $Id: sun44c-control.c,v 1.3 2007/03/29 01:17:49 fredette Exp $ */ ! 2: ! 3: /* machine/sun4/sun4-control.c - implementation of Sun 4/4c control space emulation: */ ! 4: ! 5: /* ! 6: * Copyright (c) 2006 Matt Fredette ! 7: * All rights reserved. ! 8: * ! 9: * Redistribution and use in source and binary forms, with or without ! 10: * modification, are permitted provided that the following conditions ! 11: * are met: ! 12: * 1. Redistributions of source code must retain the above copyright ! 13: * notice, this list of conditions and the following disclaimer. ! 14: * 2. Redistributions in binary form must reproduce the above copyright ! 15: * notice, this list of conditions and the following disclaimer in the ! 16: * documentation and/or other materials provided with the distribution. ! 17: * 3. All advertising materials mentioning features or use of this software ! 18: * must display the following acknowledgement: ! 19: * This product includes software developed by Matt Fredette. ! 20: * 4. The name of the author may not be used to endorse or promote products ! 21: * derived from this software without specific prior written permission. ! 22: * ! 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ! 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ! 25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ! 26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ! 27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ! 28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ! 29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ! 31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ! 32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ! 33: * POSSIBILITY OF SUCH DAMAGE. ! 34: */ ! 35: ! 36: #include <tme/common.h> ! 37: _TME_RCSID("$Id: sun44c-control.c,v 1.3 2007/03/29 01:17:49 fredette Exp $"); ! 38: ! 39: /* includes: */ ! 40: #include "sun4-impl.h" ! 41: ! 42: /* the bus cycle handler for control spaces: */ ! 43: int ! 44: _tme_sun44c_control_cycle_handler(void *_sun4_asi, struct tme_bus_cycle *cycle_init) ! 45: { ! 46: struct tme_sun4_asi *sun4_asi; ! 47: struct tme_sun4 *sun4; ! 48: struct tme_bus_cycle cycle_resp; ! 49: tme_uint32_t asi; ! 50: tme_uint32_t address; ! 51: tme_uint8_t *clear_data8; ! 52: tme_uint32_t *clear_data32; ! 53: tme_uint32_t value32; ! 54: tme_uint8_t enable_old, enable_new; ! 55: int rc; ! 56: ! 57: /* recover our sun4 and asi: */ ! 58: sun4_asi = (struct tme_sun4_asi *) _sun4_asi; ! 59: sun4 = sun4_asi->tme_sun4_asi_sun4; ! 60: asi = sun4_asi - &sun4->tme_sun4_asis[0]; ! 61: ! 62: /* get the address: */ ! 63: address = cycle_init->tme_bus_cycle_address; ! 64: ! 65: /* dispatch on the ASI and address, to get a value for our port: */ ! 66: value32 = 0; ! 67: clear_data8 = NULL; ! 68: clear_data32 = NULL; ! 69: switch (asi) { ! 70: ! 71: case TME_SUN44C_ASI_SEGMAP: ! 72: value32 = tme_sun_mmu_segmap_get(sun4->tme_sun44c_mmu, sun4->tme_sun44c_context, address); ! 73: break; ! 74: ! 75: case TME_SUN44C_ASI_PGMAP: ! 76: rc = _tme_sun44c_mmu_pte_get(sun4, address, &value32); ! 77: assert(rc == TME_OK); ! 78: break; ! 79: ! 80: case TME_SUN4C_ASI_HW_FLUSH_SEG: /* TME_SUN4_ASI_COPY */ ! 81: if (TME_SUN4_IS_SUN4C(sun4)) { ! 82: if (cycle_init->tme_bus_cycle_type != TME_BUS_CYCLE_WRITE) { ! 83: abort(); ! 84: } ! 85: } ! 86: else { ! 87: abort(); ! 88: } ! 89: break; ! 90: ! 91: case TME_SUN4C_ASI_HW_FLUSH_PG: /* TME_SUN4_ASI_REGMAP */ ! 92: if (TME_SUN4_IS_SUN4C(sun4)) { ! 93: if (cycle_init->tme_bus_cycle_type != TME_BUS_CYCLE_WRITE) { ! 94: abort(); ! 95: } ! 96: } ! 97: else { ! 98: abort(); ! 99: } ! 100: break; ! 101: ! 102: case TME_SUN4C_ASI_HW_FLUSH_ALL: /* TME_SUN4_ASI_FLUSH_USER */ ! 103: case TME_SUN4C_ASI_HW_FLUSH_CONTEXT: /* TME_SUN4_ASI_FLUSH_REG */ ! 104: case TME_SUN44C_ASI_FLUSH_CONTEXT: ! 105: case TME_SUN44C_ASI_FLUSH_SEG: ! 106: case TME_SUN44C_ASI_FLUSH_PG: ! 107: if (cycle_init->tme_bus_cycle_type != TME_BUS_CYCLE_WRITE) { ! 108: abort(); ! 109: } ! 110: break; ! 111: ! 112: case TME_SUN4_32_ASI_CONTROL: ! 113: ! 114: /* dispatch on a smaller register number: */ ! 115: switch (TME_SUN44C_CONTROL_REG(address)) { ! 116: ! 117: case TME_SUN44C_CONTROL_REG(TME_SUN4_CONTROL_IDPROM): ! 118: abort(); ! 119: break; ! 120: ! 121: case TME_SUN44C_CONTROL_REG(TME_SUN44C_CONTROL_CONTEXT): ! 122: value32 = sun4->tme_sun44c_context; ! 123: break; ! 124: ! 125: case TME_SUN44C_CONTROL_REG(TME_SUN44C_CONTROL_ENABLE): ! 126: value32 = sun4->tme_sun44c_enable; ! 127: break; ! 128: ! 129: case TME_SUN44C_CONTROL_REG(TME_SUN4_CONTROL_UDVMA): ! 130: value32 = sun4->tme_sun4_udvma; ! 131: break; ! 132: ! 133: case TME_SUN44C_CONTROL_REG(TME_SUN4C_CONTROL_SYNC_ERR): /* TME_SUN4_CONTROL_BUSERR */ ! 134: if (TME_SUN4_IS_SUN4C(sun4)) { ! 135: switch (address) { ! 136: case TME_SUN4C_CONTROL_SYNC_ERR: ! 137: clear_data32 = &sun4->tme_sun4c_sync_err; ! 138: break; ! 139: case TME_SUN4C_CONTROL_SYNC_VADDR: ! 140: /* XXX FIXME - SunOS' include/sun4c/buserr.h doesn't say if ! 141: the synchronous address register is cleared when read: */ ! 142: value32 = sun4->tme_sun4c_sync_vaddr; ! 143: break; ! 144: case TME_SUN4C_CONTROL_ASYNC_ERR: ! 145: clear_data32 = &sun4->tme_sun4c_async_err; ! 146: break; ! 147: case TME_SUN4C_CONTROL_ASYNC_VADDR: ! 148: clear_data32 = &sun4->tme_sun4c_async_vaddr; ! 149: break; ! 150: case TME_SUN4C_CONTROL_ASYNC_DATA_LO: ! 151: clear_data32 = &sun4->tme_sun4c_async_data_lo; ! 152: break; ! 153: case TME_SUN4C_CONTROL_ASYNC_DATA_HI: ! 154: clear_data32 = &sun4->tme_sun4c_async_data_hi; ! 155: break; ! 156: default: ! 157: abort(); ! 158: } ! 159: if (clear_data32 != NULL) { ! 160: value32 = *clear_data32; ! 161: } ! 162: } ! 163: else { ! 164: value32 = sun4->tme_sun4_buserr; ! 165: clear_data8 = &sun4->tme_sun4_buserr; ! 166: } ! 167: break; ! 168: ! 169: case TME_SUN44C_CONTROL_REG(TME_SUN4_CONTROL_DIAG): ! 170: value32 = sun4->tme_sun4_diag; ! 171: break; ! 172: ! 173: case TME_SUN44C_CONTROL_REG(TME_SUN44C_CONTROL_CACHE_TAGS): ! 174: case TME_SUN44C_CONTROL_REG(TME_SUN44C_CONTROL_CACHE_DATA): ! 175: return (_tme_sun44c_cache_cycle_control(sun4, cycle_init)); ! 176: break; ! 177: ! 178: case TME_SUN44C_CONTROL_REG(TME_SUN4_CONTROL_UDVMA_MAP): ! 179: abort(); ! 180: break; ! 181: ! 182: case TME_SUN44C_CONTROL_REG(TME_SUN4_CONTROL_VME_INTVEC): ! 183: abort(); ! 184: break; ! 185: ! 186: default: ! 187: abort(); ! 188: } ! 189: break; ! 190: ! 191: default: ! 192: abort(); ! 193: } ! 194: ! 195: /* run the bus cycle: */ ! 196: cycle_resp.tme_bus_cycle_buffer ! 197: = (((tme_uint8_t *) &value32) ! 198: + (TME_ENDIAN_NATIVE == TME_ENDIAN_BIG ! 199: ? (sizeof(value32) ! 200: - cycle_init->tme_bus_cycle_size) ! 201: : ((unsigned int) cycle_init->tme_bus_cycle_size ! 202: - 1))); ! 203: cycle_resp.tme_bus_cycle_buffer_increment ! 204: = (TME_ENDIAN_NATIVE == TME_ENDIAN_BIG ! 205: ? 1 ! 206: : -1); ! 207: cycle_resp.tme_bus_cycle_lane_routing = cycle_init->tme_bus_cycle_lane_routing; ! 208: cycle_resp.tme_bus_cycle_address = 0; ! 209: cycle_resp.tme_bus_cycle_type = (cycle_init->tme_bus_cycle_type ! 210: ^ (TME_BUS_CYCLE_WRITE ! 211: | TME_BUS_CYCLE_READ)); ! 212: cycle_resp.tme_bus_cycle_port = TME_BUS_CYCLE_PORT(0, TME_BUS32_LOG2); ! 213: tme_bus_cycle_xfer(cycle_init, &cycle_resp); ! 214: ! 215: /* whenever certain registers are read and/or written, they are cleared: */ ! 216: if (clear_data8 != NULL) { ! 217: *clear_data8 = 0; ! 218: } ! 219: if (clear_data32 != NULL) { ! 220: *clear_data32 = 0; ! 221: } ! 222: ! 223: /* only these registers need action taken when they're written: */ ! 224: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) { ! 225: ! 226: /* dispatch on the ASI and address: */ ! 227: switch (asi) { ! 228: ! 229: case TME_SUN44C_ASI_SEGMAP: ! 230: value32 &= (sun4->tme_sun44c_mmu_pmegs - 1); ! 231: tme_sun_mmu_segmap_set(sun4->tme_sun44c_mmu, sun4->tme_sun44c_context, address, value32); ! 232: break; ! 233: ! 234: case TME_SUN44C_ASI_PGMAP: ! 235: rc = _tme_sun44c_mmu_pte_set(sun4, address, value32); ! 236: assert (rc == TME_OK); ! 237: break; ! 238: ! 239: case TME_SUN4C_ASI_HW_FLUSH_SEG: /* TME_SUN4_ASI_COPY */ ! 240: if (TME_SUN4_IS_SUN4C(sun4)) { ! 241: if (__tme_predict_false((sun4->tme_sun44c_enable & TME_SUN44C_ENA_NOTBOOT) == 0)) { ! 242: _tme_sun44c_cache_cycle_flush(sun4, asi, address); ! 243: } ! 244: } ! 245: else { ! 246: abort(); ! 247: } ! 248: break; ! 249: ! 250: case TME_SUN4C_ASI_HW_FLUSH_PG: /* TME_SUN4_ASI_REGMAP */ ! 251: if (TME_SUN4_IS_SUN4C(sun4)) { ! 252: if (__tme_predict_false((sun4->tme_sun44c_enable & TME_SUN44C_ENA_NOTBOOT) == 0)) { ! 253: _tme_sun44c_cache_cycle_flush(sun4, asi, address); ! 254: } ! 255: } ! 256: else { ! 257: abort(); ! 258: } ! 259: break; ! 260: ! 261: case TME_SUN4C_ASI_HW_FLUSH_ALL: /* TME_SUN4_ASI_FLUSH_USER */ ! 262: case TME_SUN4C_ASI_HW_FLUSH_CONTEXT: /* TME_SUN4_ASI_FLUSH_REG */ ! 263: case TME_SUN44C_ASI_FLUSH_CONTEXT: ! 264: case TME_SUN44C_ASI_FLUSH_SEG: ! 265: case TME_SUN44C_ASI_FLUSH_PG: ! 266: if (__tme_predict_false((sun4->tme_sun44c_enable & TME_SUN44C_ENA_NOTBOOT) == 0)) { ! 267: _tme_sun44c_cache_cycle_flush(sun4, asi, address); ! 268: } ! 269: break; ! 270: ! 271: case TME_SUN4_32_ASI_CONTROL: ! 272: ! 273: /* dispatch on a smaller register number: */ ! 274: switch (TME_SUN44C_CONTROL_REG(address)) { ! 275: ! 276: case TME_SUN44C_CONTROL_REG(TME_SUN44C_CONTROL_CONTEXT): ! 277: sun4->tme_sun44c_context = value32; ! 278: _tme_sun44c_mmu_context_set(sun4); ! 279: break; ! 280: ! 281: case TME_SUN44C_CONTROL_REG(TME_SUN44C_CONTROL_ENABLE): ! 282: ! 283: /* get the old and initial new values for the enable register: */ ! 284: enable_old = sun4->tme_sun44c_enable; ! 285: enable_new = value32; ! 286: ! 287: /* fix up the new value for the enable register: */ ! 288: if (TME_SUN4_IS_SUN4C(sun4)) { ! 289: ! 290: /* if this is a software reset, clear all other bits in the ! 291: enable register: */ ! 292: if (enable_new & TME_SUN4C_ENA_RESET_SW) { ! 293: enable_new = TME_SUN4C_ENA_RESET_SW; ! 294: } ! 295: } ! 296: else { ! 297: /* XXX FIXME - we need to handle the "monitor" bit here: */ ! 298: abort(); ! 299: enable_new = (enable_old & TME_SUN4_ENA_DIAG) | (enable_new & ~TME_SUN4_ENA_DIAG); ! 300: } ! 301: ! 302: /* set the new value of the enable register: */ ! 303: sun4->tme_sun44c_enable = enable_new; ! 304: ! 305: /* if we're changing to or from boot state: */ ! 306: if ((enable_old ^ enable_new) & TME_SUN44C_ENA_NOTBOOT) { ! 307: ! 308: /* make a pseudo-context change: */ ! 309: _tme_sun44c_mmu_context_set(sun4); ! 310: ! 311: /* set the FPU strictness: */ ! 312: ((*sun4->tme_sun4_sparc->tme_sparc_bus_fpu_strict) ! 313: (sun4->tme_sun4_sparc, !(enable_new & TME_SUN44C_ENA_NOTBOOT))); ! 314: } ! 315: ! 316: /* if we're changing the cache enable, call out the change: */ ! 317: if ((enable_old ^ enable_new) & TME_SUN44C_ENA_CACHE) { ! 318: _tme_sun44c_cache_enable_change(sun4); ! 319: } ! 320: ! 321: /* if we're enabling or disabling system DVMA, call out the change: */ ! 322: if ((enable_old ^ enable_new) & TME_SUN44C_ENA_SDVMA) { ! 323: _tme_sun44c_mmu_sdvma_change(sun4); ! 324: } ! 325: ! 326: /* sun4c-specific enable register changes: */ ! 327: if (TME_SUN4_IS_SUN4C(sun4)) { ! 328: ! 329: /* if this is a software reset: */ ! 330: if (enable_new & TME_SUN4C_ENA_RESET_SW) { ! 331: return (_tme_sun4_reset(sun4, TRUE)); ! 332: } ! 333: } ! 334: ! 335: /* sun4-specific enable register changes: */ ! 336: else { ! 337: abort(); ! 338: } ! 339: break; ! 340: ! 341: case TME_SUN44C_CONTROL_REG(TME_SUN4C_CONTROL_SYNC_ERR): /* TME_SUN4_CONTROL_BUSERR */ ! 342: if (TME_SUN4_IS_SUN4C(sun4)) { ! 343: switch (address) { ! 344: case TME_SUN4C_CONTROL_SYNC_ERR: ! 345: sun4->tme_sun4c_sync_err = value32; ! 346: break; ! 347: case TME_SUN4C_CONTROL_SYNC_VADDR: ! 348: sun4->tme_sun4c_sync_vaddr = value32; ! 349: break; ! 350: case TME_SUN4C_CONTROL_ASYNC_ERR: ! 351: sun4->tme_sun4c_async_err = value32; ! 352: break; ! 353: case TME_SUN4C_CONTROL_ASYNC_VADDR: ! 354: sun4->tme_sun4c_async_vaddr = value32; ! 355: break; ! 356: case TME_SUN4C_CONTROL_ASYNC_DATA_LO: ! 357: sun4->tme_sun4c_async_data_lo = value32; ! 358: break; ! 359: case TME_SUN4C_CONTROL_ASYNC_DATA_HI: ! 360: sun4->tme_sun4c_async_data_hi = value32; ! 361: break; ! 362: default: ! 363: abort(); ! 364: } ! 365: } ! 366: else { ! 367: sun4->tme_sun4_buserr = value32; ! 368: } ! 369: break; ! 370: ! 371: case TME_SUN44C_CONTROL_REG(TME_SUN4_CONTROL_UDVMA): ! 372: if (sun4->tme_sun44c_enable & TME_SUN44C_ENA_NOTBOOT) { ! 373: abort(); ! 374: } ! 375: sun4->tme_sun4_udvma = value32; ! 376: break; ! 377: ! 378: case TME_SUN44C_CONTROL_REG(TME_SUN4_CONTROL_DIAG): ! 379: sun4->tme_sun4_diag = value32; ! 380: /* TBD */ ! 381: break; ! 382: ! 383: case TME_SUN44C_CONTROL_REG(TME_SUN44C_CONTROL_CACHE_TAGS): ! 384: case TME_SUN44C_CONTROL_REG(TME_SUN44C_CONTROL_CACHE_DATA): ! 385: assert(FALSE); ! 386: ! 387: default: ! 388: break; ! 389: } ! 390: break; ! 391: ! 392: default: ! 393: break; ! 394: } ! 395: } ! 396: ! 397: return (TME_OK); ! 398: } ! 399: ! 400: /* the bus cycle handler for the interrupt register: */ ! 401: int ! 402: _tme_sun44c_intreg_cycle_control(void *_sun4, struct tme_bus_cycle *cycle_init) ! 403: { ! 404: struct tme_sun4 *sun4; ! 405: tme_uint8_t ints_old; ! 406: int rc; ! 407: ! 408: /* recover our sun4: */ ! 409: sun4 = (struct tme_sun4 *) _sun4; ! 410: ! 411: /* get the current interrupt register value: */ ! 412: ints_old = sun4->tme_sun44c_ints; ! 413: ! 414: /* do the transfer: */ ! 415: tme_bus_cycle_xfer_memory(cycle_init, ! 416: &sun4->tme_sun44c_ints, ! 417: sizeof(sun4->tme_sun44c_ints) - 1); ! 418: ! 419: /* assume that we will return no special code: */ ! 420: rc = TME_OK; ! 421: ! 422: /* if the interrupt register has been written: */ ! 423: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) { ! 424: ! 425: /* on a sun4c, disabling interrupts clears an NMI: */ ! 426: if (TME_SUN4_IS_SUN4C(sun4) ! 427: && (ints_old & TME_SUN44C_IREG_INTS_ENAB) ! 428: && !(sun4->tme_sun44c_ints & TME_SUN44C_IREG_INTS_ENAB)) { ! 429: sun4->tme_sun4_int_signals[TME_SPARC_IPL_NMI / 8] &= ~TME_BIT(TME_SPARC_IPL_NMI % 8); ! 430: } ! 431: ! 432: #if 1 /* emulation speed problem */ ! 433: /* the simple loop that the SS2 PROM power-on self test uses to ! 434: wait for an level 14 timer interrupt times out before we can ! 435: deliver the interrupt. this is either because of the large ! 436: instruction burst that the CY7C601 emulation uses (many ! 437: iterations of that loop run without yielding to other threads ! 438: and checking for the interrupt), or because the CY7C601 ! 439: emulation on a particular host runs much faster than the CPU in ! 440: a real SS2. ! 441: ! 442: since this problem is more or less tied to the machine-specific ! 443: PROM, we deal with this problem here in the machine emulation ! 444: instead of in the CPU emulation. ! 445: ! 446: whenever the interrupt register is written to open up the level ! 447: 14 interrupt, and the enable register is still in the boot state, ! 448: we assume that this test is running, and we immediately cause ! 449: the timer interrupt to be delivered and the CPU to check for it. ! 450: ! 451: assuming that this will be a problem for all sun4/4c, we do it ! 452: for all models for now: */ ! 453: if ((sun4->tme_sun44c_enable & TME_SUN44C_ENA_NOTBOOT) == 0 ! 454: && ((sun4->tme_sun44c_ints ! 455: & (TME_SUN44C_IREG_INTS_ENAB ! 456: | TME_SUN44C_IREG_COUNTER_L14)) ! 457: == (TME_SUN44C_IREG_INTS_ENAB ! 458: | TME_SUN44C_IREG_COUNTER_L14)) ! 459: && ((ints_old ! 460: & (TME_SUN44C_IREG_INTS_ENAB ! 461: | TME_SUN44C_IREG_COUNTER_L14)) ! 462: != (TME_SUN44C_IREG_INTS_ENAB ! 463: | TME_SUN44C_IREG_COUNTER_L14))) { ! 464: _tme_sun4_timer_int_force(sun4, &sun4->tme_sun4_timer_l14); ! 465: rc = TME_BUS_CYCLE_SYNCHRONOUS_EVENT; ! 466: } ! 467: #endif /* emulation speed problem */ ! 468: ! 469: /* if an interrupt is pending, get the CPU to check for it now: */ ! 470: if (_tme_sun4_ipl_check(sun4)) { ! 471: rc = TME_BUS_CYCLE_SYNCHRONOUS_EVENT; ! 472: } ! 473: } ! 474: ! 475: return (rc); ! 476: } ! 477: ! 478: /* the bus cycle handler for the auxiliary register: */ ! 479: int ! 480: _tme_sun4c_auxreg_cycle_control(void *_sun4, struct tme_bus_cycle *cycle_init) ! 481: { ! 482: struct tme_sun4 *sun4; ! 483: ! 484: /* recover our sun4: */ ! 485: sun4 = (struct tme_sun4 *) _sun4; ! 486: ! 487: /* do the transfer: */ ! 488: tme_bus_cycle_xfer_memory(cycle_init, ! 489: &sun4->tme_sun4c4m_aux, ! 490: sizeof(sun4->tme_sun4c4m_aux) - 1); ! 491: ! 492: return (TME_OK); ! 493: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.