Annotation of tme/ic/m68k/m68k-misc.c, revision 1.1.1.4

1.1.1.4 ! root        1: /* $Id: m68k-misc.c,v 1.26 2007/08/25 22:45:12 fredette Exp $ */
1.1       root        2: 
1.1.1.2   root        3: /* ic/m68k/m68k-misc.c - miscellaneous things for the m68k emulator: */
                      4: 
                      5: /*
                      6:  * Copyright (c) 2002, 2003 Matt Fredette
                      7:  * All rights reserved.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *      This product includes software developed by Matt Fredette.
                     20:  * 4. The name of the author may not be used to endorse or promote products
                     21:  *    derived from this software without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     24:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     25:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     26:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
                     27:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     28:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     29:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     31:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     32:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     33:  * POSSIBILITY OF SUCH DAMAGE.
                     34:  */
1.1       root       35: 
                     36: /* includes: */
                     37: #include "m68k-impl.h"
                     38: 
1.1.1.4 ! root       39: _TME_RCSID("$Id: m68k-misc.c,v 1.26 2007/08/25 22:45:12 fredette Exp $");
1.1       root       40: 
                     41: /* the memory buffer read and write functions: */
                     42: #if TME_M68K_SIZE_8 != 1
                     43: #error "TME_M68K_SIZE_8 must be 1"
                     44: #endif
                     45: #if TME_M68K_SIZE_16 != 2
                     46: #error "TME_M68K_SIZE_16 must be 2"
                     47: #endif
                     48: #if TME_M68K_SIZE_32 != 4
                     49: #error "TME_M68K_SIZE_32 must be 4"
                     50: #endif
                     51: const _tme_m68k_xfer_memx _tme_m68k_read_memx[5] = {
                     52:   NULL,
                     53:   tme_m68k_read_memx8,
                     54:   tme_m68k_read_memx16,
                     55:   NULL,
                     56:   tme_m68k_read_memx32
                     57: };
                     58: const _tme_m68k_xfer_memx _tme_m68k_write_memx[5] = {
                     59:   NULL,
                     60:   tme_m68k_write_memx8,
                     61:   tme_m68k_write_memx16,
                     62:   NULL,
                     63:   tme_m68k_write_memx32
                     64: };
                     65: const _tme_m68k_xfer_mem _tme_m68k_read_mem[5] = {
                     66:   NULL,
                     67:   tme_m68k_read_mem8,
                     68:   tme_m68k_read_mem16,
                     69:   NULL,
                     70:   tme_m68k_read_mem32
                     71: };
                     72: const _tme_m68k_xfer_mem _tme_m68k_write_mem[5] = {
                     73:   NULL,
                     74:   tme_m68k_write_mem8,
                     75:   tme_m68k_write_mem16,
                     76:   NULL,
                     77:   tme_m68k_write_mem32
                     78: };
                     79: 
                     80: /* our bus signal handler: */
                     81: static int
                     82: _tme_m68k_bus_signal(struct tme_bus_connection *conn_bus, unsigned int signal)
                     83: {
                     84:   struct tme_m68k *ic;
                     85:   unsigned int level_edge;
                     86: 
                     87:   /* recover our IC: */
                     88:   ic = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
                     89: 
                     90:   /* take out the level and edge: */
1.1.1.3   root       91:   level_edge = signal;
                     92:   signal = TME_BUS_SIGNAL_WHICH(signal);
                     93:   level_edge ^= signal;
1.1       root       94: 
                     95:   /* lock the external mutex: */
                     96:   tme_mutex_lock(&ic->tme_m68k_external_mutex);
                     97: 
                     98:   /* on the falling edge of HALT or RESET, halt the processor: */
1.1.1.3   root       99:   if (((level_edge & TME_BUS_SIGNAL_LEVEL_MASK)
                    100:        == TME_BUS_SIGNAL_LEVEL_ASSERTED)
1.1       root      101:       && (signal == TME_BUS_SIGNAL_HALT
                    102:          || signal == TME_BUS_SIGNAL_RESET)) {
                    103:     ic->tme_m68k_external_halt = TRUE;
                    104:   }
                    105: 
                    106:   /* on the rising edge of RESET, reset the processor: */
                    107:   else if (signal == TME_BUS_SIGNAL_RESET
1.1.1.3   root      108:           && ((level_edge & TME_BUS_SIGNAL_LEVEL_MASK)
                    109:               == TME_BUS_SIGNAL_LEVEL_NEGATED)) {
1.1       root      110:     ic->tme_m68k_external_reset = TRUE;
                    111:   }
                    112: 
                    113:   /* on any other HALT or RESET, do nothing: */
                    114:   else if (signal == TME_BUS_SIGNAL_RESET
                    115:           || signal == TME_BUS_SIGNAL_HALT) {
                    116:     /* nothing */
                    117:   }
                    118: 
                    119:   /* anything else: */
                    120:   else {
                    121:     abort();
                    122:   }
                    123: 
                    124:   /* unlock the external mutex: */
                    125:   tme_mutex_unlock(&ic->tme_m68k_external_mutex);
                    126: 
                    127:   /* notify any threads waiting on the external condition: */
                    128:   tme_cond_notify(&ic->tme_m68k_external_cond, TRUE);
                    129:   return (TME_OK);
                    130: }
                    131: 
1.1.1.3   root      132: /* this enables or disables an m6888x: */
                    133: static int
                    134: _tme_m6888x_enable(struct tme_m68k_bus_connection *conn_m68k, int enabled)
                    135: {
                    136:   struct tme_m68k *ic;
                    137: 
                    138:   /* recover our IC: */
                    139:   ic = conn_m68k->tme_m68k_bus_connection.tme_bus_connection.tme_connection_element->tme_element_private;
                    140: 
                    141:   /* NB: we're lazy here and don't bother locking the external mutex: */
                    142:   if (ic->tme_m68k_fpu_type == TME_M68K_FPU_NONE) {
                    143:     return (ENXIO);
                    144:   }
                    145:   ic->tme_m68k_fpu_enabled = enabled;
                    146:   return (TME_OK);
                    147: }
                    148: 
1.1       root      149: /* our interrupt handler: */
                    150: static int
                    151: _tme_m68k_bus_interrupt(struct tme_m68k_bus_connection *conn_m68k, unsigned int ipl)
                    152: {
                    153:   struct tme_m68k *ic;
                    154: 
                    155:   /* recover our IC: */
                    156:   ic = conn_m68k->tme_m68k_bus_connection.tme_bus_connection.tme_connection_element->tme_element_private;
                    157: 
                    158:   /* lock the external mutex: */
                    159:   tme_mutex_lock(&ic->tme_m68k_external_mutex);
                    160: 
                    161:   /* set the interrupt line: */
                    162:   ic->tme_m68k_external_ipl = ipl;
                    163: 
1.1.1.3   root      164:   /* if the IPL has dropped below the NMI level, the next transition
                    165:      to that level will cause an NMI: */
                    166:   if (ipl < TME_M68K_IPL_NMI) {
                    167:     ic->tme_m68k_external_ipl_previous_nmi = FALSE;
                    168:   }
                    169: 
1.1       root      170:   /* unlock the external mutex: */
                    171:   tme_mutex_unlock(&ic->tme_m68k_external_mutex);
                    172: 
                    173:   /* notify any threads waiting on the external condition: */
                    174:   tme_cond_notify(&ic->tme_m68k_external_cond, TRUE);
                    175:   return (TME_OK);
                    176: }
                    177: 
                    178: /* this checks for external signals.  this must be called with the
                    179:    external mutex held: */
                    180: void
                    181: tme_m68k_external_check(struct tme_m68k *ic, tme_uint32_t internal_exceptions)
                    182: {
                    183:   unsigned int ipl;
                    184:   int vector;
                    185:   int rc;
                    186: 
                    187:   /* if an external reset has been requested, start reset exception
                    188:      processing: */
                    189:   if (ic->tme_m68k_external_reset) {
                    190:     ic->tme_m68k_external_reset = FALSE;
                    191:     tme_mutex_unlock(&ic->tme_m68k_external_mutex);
1.1.1.3   root      192:     tme_m68k_exception(ic, TME_M68K_EXCEPTION_RESET);
1.1       root      193:   }
                    194: 
                    195:   /* if an external halt has been requested, halt: */
                    196:   if (ic->tme_m68k_external_halt) {
                    197:     ic->tme_m68k_external_halt = FALSE;
                    198:     tme_mutex_unlock(&ic->tme_m68k_external_mutex);
                    199:     ic->_tme_m68k_mode = TME_M68K_MODE_HALT;
                    200:     TME_M68K_SEQUENCE_START;
                    201:     tme_m68k_redispatch(ic);
                    202:   }
                    203: 
                    204:   /* if we are not halted, and an interrupt can be serviced, start
                    205:      interrupt exception processing: */
                    206:   ipl = ic->tme_m68k_external_ipl;
                    207:   if (ic->_tme_m68k_mode != TME_M68K_MODE_HALT
                    208:       && ipl >= TME_M68K_IPL_MIN
                    209:       && ipl <= TME_M68K_IPL_MAX
1.1.1.3   root      210:       && ((ipl == TME_M68K_IPL_NMI
                    211:           && !ic->tme_m68k_external_ipl_previous_nmi)
1.1       root      212:          || ipl > TME_M68K_FLAG_IPM(ic->tme_m68k_ireg_sr))) {
1.1.1.3   root      213:     
                    214:     /* if this is an NMI, prevent it from being repeatedly accepted: */
                    215:     if (ipl == TME_M68K_IPL_NMI) {
                    216:       ic->tme_m68k_external_ipl_previous_nmi = TRUE;
                    217:     }
                    218: 
1.1       root      219:     tme_mutex_unlock(&ic->tme_m68k_external_mutex);
                    220:     
                    221:     /* acknowledge the interrupt and get the vector: */
1.1.1.4 ! root      222:     tme_m68k_callout_unlock(ic);
1.1       root      223:     rc = (*ic->_tme_m68k_bus_connection->tme_m68k_bus_connection.tme_bus_intack)
                    224:       (&ic->_tme_m68k_bus_connection->tme_m68k_bus_connection,
                    225:        ipl, &vector);
1.1.1.4 ! root      226:     tme_m68k_callout_relock(ic);
1.1       root      227:     if (rc == TME_EDEADLK) {
                    228:       abort();
                    229:     }
                    230: 
                    231:     /* if the interrupt acknowledge failed, this is a spurious interrupt: */
                    232:     if (rc == ENOENT) {
1.1.1.3   root      233:       vector = TME_M68K_VECTOR_SPURIOUS;
1.1       root      234:     }
                    235: 
                    236:     /* if no vector is given, use the autovector: */
                    237:     else if (vector == TME_BUS_INTERRUPT_VECTOR_UNDEF) {
1.1.1.3   root      238:       vector = TME_M68K_VECTOR_SPURIOUS + ipl;
1.1       root      239:     }
                    240: 
                    241:     /* dispatch the exceptions: */
1.1.1.3   root      242:     tme_m68k_exception(ic, internal_exceptions | TME_M68K_EXCEPTION_INT(ipl, vector));
1.1       root      243:   }
                    244: 
                    245:   /* if there are internal exceptions to process, do so: */
                    246:   if (internal_exceptions != 0) {
                    247:     tme_mutex_unlock(&ic->tme_m68k_external_mutex);
                    248:     tme_m68k_exception(ic, internal_exceptions);
                    249:   }
                    250: 
                    251:   /* there are no exceptions to process: */
                    252: }
                    253: 
                    254: /* the idle function, used when the processor is halted or stopped: */
                    255: static void
                    256: tme_m68k_idle(struct tme_m68k *ic)
                    257: {  
                    258:   /* lock the external mutex: */
                    259:   tme_mutex_lock(&ic->tme_m68k_external_mutex);
                    260: 
                    261:   /* loop forever: */
                    262:   for (;;) {
                    263: 
                    264:     /* check for any external signal: */
                    265:     tme_m68k_external_check(ic, 0);
                    266: 
                    267:     /* await an external condition: */
                    268:     tme_cond_wait_yield(&ic->tme_m68k_external_cond, &ic->tme_m68k_external_mutex);
                    269:   }
                    270: }
                    271: 
                    272: /* the m68k thread: */
                    273: static void
                    274: tme_m68k_thread(struct tme_m68k *ic)
                    275: {
                    276: 
                    277:   /* we use longjmp to redispatch: */
                    278:   do { } while (setjmp(ic->_tme_m68k_dispatcher));
                    279: 
1.1.1.4 ! root      280:   /* we must not have a busy fast instruction TLB entry: */
        !           281:   assert (ic->_tme_m68k_insn_fetch_fast_itlb == NULL);
        !           282: 
        !           283:   /* clear the group 0 hook: */
        !           284:   ic->_tme_m68k_group0_hook = NULL;
        !           285: 
1.1       root      286:   /* dispatch on the current mode: */
                    287:   switch (ic->_tme_m68k_mode) {
                    288: 
                    289:   case TME_M68K_MODE_EXECUTION:
                    290:     (*ic->_tme_m68k_mode_execute)(ic);
                    291:     /* NOTREACHED */
                    292: 
                    293:   case TME_M68K_MODE_EXCEPTION:
                    294:     (*ic->_tme_m68k_mode_exception)(ic);
                    295:     /* NOTREACHED */
                    296: 
                    297:   case TME_M68K_MODE_RTE:
                    298:     (*ic->_tme_m68k_mode_rte)(ic);
                    299:     /* NOTREACHED */
                    300: 
                    301:   case TME_M68K_MODE_STOP:
                    302:   case TME_M68K_MODE_HALT:
                    303:     tme_m68k_idle(ic);
                    304:     /* NOTREACHED */
                    305: 
                    306:   default:
                    307:     abort();
                    308:   }
                    309:   /* NOTREACHED */
                    310: }
                    311: 
                    312: /* the TLB filler for when we are on a generic bus: */
                    313: static int
                    314: _tme_m68k_generic_tlb_fill(struct tme_m68k_bus_connection *conn_m68k, 
                    315:                           struct tme_m68k_tlb *tlb,
                    316:                           unsigned int function_code, 
                    317:                           tme_uint32_t external_address, 
                    318:                           unsigned int cycles)
                    319: {
                    320:   struct tme_m68k *ic;
                    321: 
                    322:   /* recover our IC: */
                    323:   ic = conn_m68k->tme_m68k_bus_connection.tme_bus_connection.tme_connection_element->tme_element_private;
                    324: 
                    325:   /* call the generic bus TLB filler: */
                    326:   (ic->_tme_m68k_bus_generic->tme_bus_tlb_fill)
                    327:     (ic->_tme_m68k_bus_generic,
                    328:      &tlb->tme_m68k_tlb_bus_tlb,
                    329:      external_address,
                    330:      cycles);
                    331:   
                    332:   /* when we're on a generic bus a TLB entry is valid for all function codes: */
                    333:   tlb->tme_m68k_tlb_function_codes_mask = -1;
                    334: 
                    335:   return (TME_OK);
                    336: }
                    337: 
                    338: /* the connection scorer: */
                    339: static int
                    340: _tme_m68k_connection_score(struct tme_connection *conn, unsigned int *_score)
                    341: {
                    342:   struct tme_m68k_bus_connection *conn_m68k;
                    343:   struct tme_bus_connection *conn_bus;
                    344:   unsigned int score;
                    345: 
                    346:   /* assume that this connection is useless: */
                    347:   score = 0;
                    348: 
                    349:   /* dispatch on the connection type: */
                    350:   conn_m68k = (struct tme_m68k_bus_connection *) conn->tme_connection_other;
                    351:   conn_bus = (struct tme_bus_connection *) conn->tme_connection_other;
                    352:   switch (conn->tme_connection_type) {
                    353: 
                    354:     /* this must be a bus, and not another m68k chip: */
                    355:   case TME_CONNECTION_BUS_M68K:
                    356:     if (conn_bus->tme_bus_tlb_set_allocate != NULL
1.1.1.3   root      357:        && conn_m68k->tme_m68k_bus_tlb_fill != NULL
                    358:        && conn_m68k->tme_m68k_bus_m6888x_enable == NULL) {
1.1       root      359:       score = 10;
                    360:     }
                    361:     break;
                    362: 
                    363:     /* this must be a bus, and not another chip: */
                    364:   case TME_CONNECTION_BUS_GENERIC:
                    365:     if (conn_bus->tme_bus_tlb_set_allocate != NULL
                    366:        && conn_bus->tme_bus_tlb_fill != NULL) {
                    367:       score = 1;
                    368:     }
                    369:     break;
                    370: 
                    371:   default: abort();
                    372:   }
                    373: 
                    374:   *_score = score;
                    375:   return (TME_OK);
                    376: }
                    377: 
                    378: /* this makes a new connection: */
                    379: static int
                    380: _tme_m68k_connection_make(struct tme_connection *conn, unsigned int state)
                    381: {
                    382:   struct tme_m68k *ic;
                    383:   struct tme_m68k_bus_connection *conn_m68k;
                    384:   struct tme_bus_connection *conn_bus;
                    385:   struct tme_connection *conn_other;
                    386: 
                    387:   /* since the CPU is halted, it won't be making any connection calls,
                    388:      so we only have to do work when the connection is fully made: */
                    389:   if (state == TME_CONNECTION_FULL) {
                    390: 
                    391:     /* recover our IC: */
                    392:     ic = conn->tme_connection_element->tme_element_private;
                    393:     
                    394:     /* dispatch on the connection type: */
                    395:     conn_other = conn->tme_connection_other;
                    396:     conn_m68k = (struct tme_m68k_bus_connection *) conn_other;
                    397:     conn_bus = (struct tme_bus_connection *) conn_other;
                    398:     switch (conn->tme_connection_type) {
                    399:       
                    400:     case TME_CONNECTION_BUS_M68K:
                    401:       ic->_tme_m68k_bus_connection = conn_m68k;
                    402:       break;
                    403:       
                    404:       /* we need an adaptation layer: */
                    405:     case TME_CONNECTION_BUS_GENERIC:
                    406:       conn_m68k = tme_new0(struct tme_m68k_bus_connection, 1);
                    407:       conn_m68k->tme_m68k_bus_connection.tme_bus_connection.tme_connection_element = conn->tme_connection_element;
                    408:       conn_m68k->tme_m68k_bus_tlb_fill = _tme_m68k_generic_tlb_fill;
                    409:       ic->_tme_m68k_bus_connection = conn_m68k;
                    410:       ic->_tme_m68k_bus_generic = conn_bus;
                    411:       break;
                    412:       
                    413:     default: abort();
                    414:     }
                    415: 
                    416:     /* allocate the TLB hash set: */
                    417:     (*ic->_tme_m68k_bus_connection->tme_m68k_bus_connection.tme_bus_tlb_set_allocate)
                    418:       (&ic->_tme_m68k_bus_connection->tme_m68k_bus_connection, 
                    419:        _TME_M68K_TLB_HASH_SIZE, 
                    420:        sizeof(struct tme_m68k_tlb),
1.1.1.4 ! root      421:        &ic->_tme_m68k_tlb_array_bus,
        !           422:        &ic->_tme_m68k_tlbs_rwlock);
1.1       root      423: 
                    424:     /* allocate the ITLB set: */
                    425:     (*ic->_tme_m68k_bus_connection->tme_m68k_bus_connection.tme_bus_tlb_set_allocate)
                    426:       (&ic->_tme_m68k_bus_connection->tme_m68k_bus_connection, 
                    427:        1, 
                    428:        sizeof(struct tme_m68k_tlb),
1.1.1.4 ! root      429:        &ic->_tme_m68k_itlb_bus,
        !           430:        &ic->_tme_m68k_tlbs_rwlock);
1.1       root      431:   }
                    432: 
                    433:   /* NB: the machine needs to issue a reset to bring the CPU out of halt. */
                    434:   return (TME_OK);
                    435: }
                    436: 
                    437: /* this breaks a connection: */
                    438: static int 
                    439: _tme_m68k_connection_break(struct tme_connection *conn, unsigned int state)
                    440: {
                    441:   abort();
1.1.1.3   root      442:   return (0);
1.1       root      443: }
                    444: 
                    445: /* this makes new connection sides: */
                    446: static int
                    447: _tme_m68k_connections_new(struct tme_element *element, const char * const *args, struct tme_connection **_conns, char **_output)
                    448: {
                    449:   struct tme_m68k_bus_connection *conn_m68k;
                    450:   struct tme_bus_connection *conn_bus;
                    451:   struct tme_connection *conn;
                    452: 
                    453:   /* if we already have a bus connection, we can take no more connections: */
                    454:   if (((struct tme_m68k *) element->tme_element_private)->_tme_m68k_bus_connection != NULL) {
                    455:     return (TME_OK);
                    456:   }
                    457: 
                    458:   /* create our side of an m68k bus connection: */
                    459:   conn_m68k = tme_new0(struct tme_m68k_bus_connection, 1);
                    460:   conn_bus = &conn_m68k->tme_m68k_bus_connection;
                    461:   conn = &conn_bus->tme_bus_connection;
                    462: 
                    463:   /* fill in the generic connection: */
                    464:   conn->tme_connection_next = *_conns;
                    465:   conn->tme_connection_type = TME_CONNECTION_BUS_M68K;
                    466:   conn->tme_connection_score = _tme_m68k_connection_score;
                    467:   conn->tme_connection_make = _tme_m68k_connection_make;
                    468:   conn->tme_connection_break = _tme_m68k_connection_break;
                    469: 
                    470:   /* fill in the generic bus connection: */
                    471:   conn_bus->tme_bus_signal = _tme_m68k_bus_signal;
                    472:   conn_bus->tme_bus_tlb_set_allocate = NULL;
                    473: 
                    474:   /* full in the m68k bus connection: */
                    475:   conn_m68k->tme_m68k_bus_interrupt = _tme_m68k_bus_interrupt;
                    476:   conn_m68k->tme_m68k_bus_tlb_fill = NULL;
1.1.1.3   root      477:   conn_m68k->tme_m68k_bus_m6888x_enable = _tme_m6888x_enable;
1.1       root      478: 
                    479:   /* add this connection to the set of possibilities: */
                    480:   *_conns = conn;
                    481: 
                    482:   /* create our side of a generic bus connection: */
                    483:   conn_bus = tme_new0(struct tme_bus_connection, 1);
                    484:   conn = &conn_bus->tme_bus_connection;
                    485: 
                    486:   /* fill in the generic connection: */
                    487:   conn->tme_connection_next = *_conns;
                    488:   conn->tme_connection_type = TME_CONNECTION_BUS_GENERIC;
                    489:   conn->tme_connection_score = _tme_m68k_connection_score;
                    490:   conn->tme_connection_make = _tme_m68k_connection_make;
                    491:   conn->tme_connection_break = _tme_m68k_connection_break;
                    492: 
                    493:   /* fill in the generic bus connection: */
                    494:   conn_bus->tme_bus_signal = _tme_m68k_bus_signal;
                    495:   conn_bus->tme_bus_tlb_set_allocate = NULL;
                    496:   conn_bus->tme_bus_tlb_fill = NULL;
                    497: 
                    498:   /* add this connection to the set of possibilities: */
                    499:   *_conns = conn;
                    500: 
                    501:   /* done: */
                    502:   return (TME_OK);
                    503: }
                    504: 
                    505: /* the common m68k new function: */
                    506: int
                    507: tme_m68k_new(struct tme_m68k *ic, const char * const *args, const void *extra, char **_output)
                    508: {
                    509:   struct tme_element *element;
1.1.1.3   root      510:   int arg_i;
                    511:   int usage;
1.1       root      512: 
1.1.1.3   root      513:   /* check our arguments: */
                    514:   arg_i = 1;
                    515:   usage = FALSE;
                    516:   for (;;) {
                    517:     
                    518:     if (0) {
                    519: 
                    520:     }
                    521: 
                    522:     /* if we've run out of arguments: */
                    523:     else if (args[arg_i + 0] == NULL) {
                    524:       break;
                    525:     }
                    526: 
                    527:     /* this is either a bad argument or an FPU argument: */
                    528:     else {
                    529: 
                    530:       /* if this is not an FPU argument: */
                    531:       if (!tme_m68k_fpu_new(ic, args, &arg_i, &usage, _output)) {
                    532:        tme_output_append_error(_output,
                    533:                                "%s %s, ",
                    534:                                args[arg_i],
                    535:                                _("unexpected"));
                    536:        usage = TRUE;
                    537:       }
                    538:       
                    539:       if (usage) {
                    540:        break;
                    541:       }
                    542:     }
                    543:   }
                    544: 
                    545:   if (usage) {
                    546:     tme_output_append_error(_output, 
                    547:                            "%s %s",
1.1       root      548:                            _("usage:"),
                    549:                            args[0]);
1.1.1.3   root      550:     tme_m68k_fpu_usage(_output);
1.1       root      551:     tme_free(ic);
                    552:     return (EINVAL);
                    553:   }
                    554: 
                    555:   /* initialize the verifier: */
                    556:   tme_m68k_verify_init();
                    557: 
                    558:   /* dispatch on the type: */
                    559:   switch (ic->tme_m68k_type) {
                    560:   case TME_M68K_M68000:
1.1.1.4 ! root      561:     ic->_tme_m68k_bus_16bit = 1;
1.1       root      562:     break;
                    563:   case TME_M68K_M68010:
1.1.1.4 ! root      564:     ic->_tme_m68k_bus_16bit = 1;
1.1       root      565:     break;
                    566:   case TME_M68K_M68020:
1.1.1.4 ! root      567:     ic->_tme_m68k_bus_16bit = 0;
1.1       root      568:     break;
                    569:   default:
                    570:     abort();
                    571:   }
                    572: 
                    573:   /* we have no bus connection yet: */
                    574:   ic->_tme_m68k_bus_connection = NULL;
                    575: 
                    576:   /* fill the element: */
                    577:   element = ic->tme_m68k_element;
                    578:   element->tme_element_private = ic;
                    579:   element->tme_element_connections_new = _tme_m68k_connections_new;
                    580: 
                    581:   /* calculate the instruction burst size: */
                    582:   /* XXX TBD: */
1.1.1.3   root      583:   ic->_tme_m68k_instruction_burst = 200;
1.1.1.2   root      584:   ic->_tme_m68k_instruction_burst_remaining
                    585:     = ic->_tme_m68k_instruction_burst;
1.1       root      586: 
1.1.1.3   root      587:   /* set the status register T bits mask: */
                    588:   ic->_tme_m68k_sr_mask_t
                    589:     = (TME_M68K_FLAG_T1
                    590:        | ((ic->tme_m68k_type >= TME_M68K_M68020)
                    591:          * TME_M68K_FLAG_T0));
                    592: 
                    593:   /* initialize the small immediates: */
                    594:   ic->tme_m68k_ireg_uint32(TME_M68K_IREG_ZERO) = 0;
                    595:   ic->tme_m68k_ireg_uint32(TME_M68K_IREG_ONE) = 1;
                    596:   ic->tme_m68k_ireg_uint32(TME_M68K_IREG_TWO) = 2;
                    597:   ic->tme_m68k_ireg_uint32(TME_M68K_IREG_THREE) = 3;
                    598:   ic->tme_m68k_ireg_uint32(TME_M68K_IREG_FOUR) = 4;
                    599:   ic->tme_m68k_ireg_uint32(TME_M68K_IREG_FIVE) = 5;
                    600:   ic->tme_m68k_ireg_uint32(TME_M68K_IREG_SIX) = 6;
                    601:   ic->tme_m68k_ireg_uint32(TME_M68K_IREG_SEVEN) = 7;
                    602:   ic->tme_m68k_ireg_uint32(TME_M68K_IREG_EIGHT) = 8;
                    603: 
1.1       root      604:   /* force the processor to be halted: */
                    605:   ic->_tme_m68k_mode = TME_M68K_MODE_HALT;
                    606:   TME_M68K_SEQUENCE_START;
                    607: 
                    608:   /* start the m68k thread: */
                    609:   tme_thread_create((tme_thread_t) tme_m68k_thread, ic);
                    610: 
                    611:   return (TME_OK);
                    612: }  
                    613: 
                    614: /* the common m68k reset function: */
                    615: void
                    616: tme_m68k_do_reset(struct tme_m68k *ic)
                    617: {
                    618:   
                    619:   /* force the VBR to zero: */
                    620:   ic->tme_m68k_ireg_vbr = 0;
                    621: 
1.1.1.3   root      622:   /* clear the E and F bits in the CACR: */
                    623:   ic->tme_m68k_ireg_cacr = 0;
                    624: 
1.1       root      625:   /* force supervisor mode, interrupts disabled: */
                    626:   tme_m68k_change_sr(ic, TME_M68K_FLAG_S | (7 << 8));
                    627: 
                    628:   /* load the initial SSP and PC: */
1.1.1.3   root      629:   ic->_tme_m68k_ea_function_code = TME_M68K_FC_SP;
1.1       root      630:   ic->_tme_m68k_ea_address = 0;
                    631:   tme_m68k_read_mem32(ic, TME_M68K_IREG_A7);
                    632:   ic->_tme_m68k_ea_address += sizeof(ic->tme_m68k_ireg_a7);
                    633:   tme_m68k_read_mem32(ic, TME_M68K_IREG_PC);
                    634: 
                    635:   /* clear all exceptions: */
                    636:   ic->_tme_m68k_exceptions = 0;
                    637: 
1.1.1.3   root      638:   /* reset the FPU: */
                    639:   tme_m68k_fpu_reset(ic);
                    640: 
1.1       root      641:   /* start execution: */
                    642:   ic->_tme_m68k_mode = TME_M68K_MODE_EXECUTION;
                    643:   TME_M68K_SEQUENCE_START;
                    644:   tme_m68k_redispatch(ic);
                    645: }
                    646: 
                    647: /* this returns nonzero iff the slow instruction executor must be
                    648:    used: */
                    649: int
                    650: tme_m68k_go_slow(const struct tme_m68k *ic)
                    651: {
                    652:   struct tme_m68k_tlb *tlb;
                    653:   tme_uint32_t linear_pc;
1.1.1.4 ! root      654:   const tme_shared tme_uint8_t *emulator_load;
        !           655:   const tme_shared tme_uint8_t *emulator_load_last;
1.1       root      656: 
1.1.1.4 ! root      657:   tlb = tme_memory_atomic_pointer_read(struct tme_m68k_tlb *, ic->_tme_m68k_itlb, &ic->_tme_m68k_tlbs_rwlock);
        !           658:   emulator_load = tlb->tme_m68k_tlb_emulator_off_read;
        !           659:   emulator_load_last = emulator_load;
        !           660:   if (emulator_load != TME_EMULATOR_OFF_UNDEF) {
        !           661:     emulator_load += tlb->tme_m68k_tlb_linear_first;
        !           662:     emulator_load_last += tlb->tme_m68k_tlb_linear_last;
        !           663:     assert (emulator_load <= emulator_load_last);
        !           664:   }
1.1       root      665:   linear_pc = ic->tme_m68k_ireg_pc;
                    666:   return (
                    667:          
                    668:          /* the ITLB entry must support reads from emulator memory: */
                    669:          !TME_M68K_TLB_OK_FAST_READ(tlb, 
                    670:                                     TME_M68K_FUNCTION_CODE_PROGRAM(ic),
                    671:                                     linear_pc,
                    672:                                     linear_pc)
                    673: 
                    674:          /* the ITLB emulator memory must be 32-bit aligned for the
                    675:             benefit of the fast instruction word fetch macros, so
                    676:             that emulator address alignment goes with linear address
                    677:             alignment: */
                    678:          || (((unsigned long) tlb->tme_m68k_tlb_emulator_off_read)
                    679:              & (sizeof(tme_uint32_t) - 1))
                    680: 
1.1.1.4 ! root      681:          /* the ITLB emulator memory must not be so low that the
        !           682:             first valid pointer minus one, or the last valid pointer
        !           683:             minus (sizeof(tme_uint32_t) - 1), wraps around, nor so
        !           684:             high that the last valid pointer, plus one, wraps around: */
        !           685:          /* NB: this enables the fast instruction word fetch macros
        !           686:             to simply fetch 16 and 32 bit values until fetch_fast_next
        !           687:             is greater than ic->_tme_m68k_insn_fetch_fast_last, and 
        !           688:             not have to do any pointer math or ever check for pointer
        !           689:             wrapping: */
        !           690:          || ((emulator_load
        !           691:               - 1)
        !           692:              >= emulator_load)
        !           693:          || ((emulator_load_last
        !           694:               - (sizeof(tme_uint32_t) - 1))
        !           695:              >= emulator_load_last)
        !           696:          || ((emulator_load_last
        !           697:               + 1)
        !           698:              <= emulator_load_last)
        !           699: 
1.1       root      700:          /* the linear PC must be 16-bit aligned: */
                    701:          || (linear_pc & 1)
                    702: 
                    703:          /* there must be no tracing: */
1.1.1.3   root      704:          || (ic->tme_m68k_ireg_sr & ic->_tme_m68k_sr_mask_t) != 0);
1.1       root      705: }
                    706: 
                    707: /* this redispatches: */
                    708: void
                    709: tme_m68k_redispatch(struct tme_m68k *ic)
                    710: {
1.1.1.4 ! root      711:   struct tme_m68k_tlb *tlb;
        !           712: 
        !           713:   /* if we have a busy fast instruction TLB entry: */
        !           714:   tlb = ic->_tme_m68k_insn_fetch_fast_itlb;
        !           715:   if (__tme_predict_true(tlb != NULL)) {
        !           716: 
        !           717:     /* unbusy and forget the fast instruction TLB entry: */
        !           718:     tme_m68k_tlb_unbusy(tlb);
        !           719:     ic->_tme_m68k_insn_fetch_fast_itlb = NULL;
        !           720:   }
        !           721: 
        !           722:   /* do the redispatch: */
1.1.1.3   root      723: #ifdef _TME_M68K_STATS
                    724:   ic->tme_m68k_stats.tme_m68k_stats_redispatches++;
                    725: #endif /* _TME_M68K_STATS */
1.1       root      726:   longjmp(ic->_tme_m68k_dispatcher, 1);
                    727: }
                    728: 
                    729: /* this fills a TLB entry: */
                    730: void
                    731: tme_m68k_tlb_fill(struct tme_m68k *ic, struct tme_m68k_tlb *tlb, 
                    732:                  unsigned int function_code, 
                    733:                  tme_uint32_t linear_address, 
                    734:                  unsigned int cycles)
                    735: {
                    736:   tme_uint32_t external_address;
                    737:   struct tme_bus_tlb tlb_internal;
                    738:   
1.1.1.3   root      739: #ifdef _TME_M68K_STATS
                    740:   if (function_code == TME_M68K_FC_UP
                    741:       || function_code == TME_M68K_FC_SP) {
                    742:     ic->tme_m68k_stats.tme_m68k_stats_itlb_fill++;
                    743:   }
                    744:   else {
                    745:     ic->tme_m68k_stats.tme_m68k_stats_dtlb_fill++;
                    746:   }
                    747: #endif /* _TME_M68K_STATS */
                    748: 
1.1       root      749:   /* when emulating a CPU with a 16-bit bus, only 24 bits of address
                    750:      are external: */
                    751:   external_address = linear_address;
                    752:   if (ic->_tme_m68k_bus_16bit) {
                    753:     external_address &= 0x00ffffff;
                    754:   }
                    755: 
1.1.1.3   root      756:   /* this m68k implementation never fills TLB entries on the stack, so
                    757:      a TLB entry reserves itself.  this also means that we don't have
                    758:      to call tme_bus_tlb_back() after the fill: */
1.1.1.4 ! root      759:   tlb->tme_m68k_tlb_bus_tlb.tme_bus_tlb_global = &tlb->tme_m68k_tlb_bus_tlb;
        !           760: 
        !           761:   /* unbusy the TLB entry for filling: */
        !           762:   tme_bus_tlb_unbusy_fill(&tlb->tme_m68k_tlb_bus_tlb);
        !           763: 
        !           764:   /* unlock for the callout: */
        !           765:   tme_m68k_callout_unlock(ic);
1.1.1.3   root      766: 
1.1       root      767:   /* fill the TLB entry: */
                    768:   (*ic->_tme_m68k_bus_connection->tme_m68k_bus_tlb_fill)
                    769:     (ic->_tme_m68k_bus_connection, tlb,
                    770:      function_code,
                    771:      external_address,
                    772:      cycles);
                    773: 
1.1.1.4 ! root      774:   /* relock after the callout: */
        !           775:   tme_m68k_callout_relock(ic);
        !           776: 
        !           777:   /* rebusy the TLB entry: */
        !           778:   tme_bus_tlb_busy(&tlb->tme_m68k_tlb_bus_tlb);
        !           779: 
1.1       root      780:   /* if this code isn't 32-bit clean, we have to deal: */
                    781:   if (external_address != linear_address) {
1.1.1.4 ! root      782:     tlb_internal.tme_bus_tlb_addr_first
        !           783:       = (tlb->tme_m68k_tlb_linear_first
        !           784:         | (linear_address ^ external_address));
        !           785:     tlb_internal.tme_bus_tlb_addr_last
        !           786:       = (tlb->tme_m68k_tlb_linear_last
        !           787:         | (linear_address ^ external_address));
1.1       root      788:     tlb_internal.tme_bus_tlb_cycles_ok = tlb->tme_m68k_tlb_bus_tlb.tme_bus_tlb_cycles_ok;
                    789:     tme_bus_tlb_map(&tlb->tme_m68k_tlb_bus_tlb, external_address,
                    790:                    &tlb_internal, linear_address);
                    791:   }
                    792: }
                    793: 
                    794: /* this triggers exception processing: */
                    795: void
                    796: tme_m68k_exception(struct tme_m68k *ic, tme_uint32_t new_exceptions)
                    797: {
                    798:   assert(new_exceptions != 0);
                    799: 
                    800:   /* if the set of new exceptions includes a group zero exception: */
                    801:   if (new_exceptions & 
1.1.1.3   root      802:       (TME_M68K_EXCEPTION_RESET
                    803:        | TME_M68K_EXCEPTION_AERR
                    804:        | TME_M68K_EXCEPTION_BERR)) {
1.1       root      805:     
                    806:     /* there must be only one exception - you cannot trigger a group 0
                    807:        exception simultaneously with any other group 0, 1, or 2
                    808:        exception: */
                    809:     assert((new_exceptions & (new_exceptions - 1)) == 0);
                    810:     
                    811:     /* if this is a reset exception, it clears all other exceptions: */
1.1.1.3   root      812:     if (new_exceptions == TME_M68K_EXCEPTION_RESET) {
1.1       root      813:       ic->_tme_m68k_exceptions = 0;
                    814:     }
                    815: 
                    816:     /* otherwise, this is an address error or a bus error.  if we were
                    817:        already processing a group 0 exception, this is a
                    818:        double fault, and the processor enters the halted state: */
                    819:     else if (ic->_tme_m68k_exceptions &
1.1.1.3   root      820:             (TME_M68K_EXCEPTION_RESET
                    821:              | TME_M68K_EXCEPTION_AERR
                    822:              | TME_M68K_EXCEPTION_BERR)) {
                    823:       tme_log(TME_M68K_LOG_HANDLE(ic), 0, TME_OK,
                    824:              (TME_M68K_LOG_HANDLE(ic),
                    825:               _("double fault, processor halted")));
1.1       root      826:       ic->_tme_m68k_mode = TME_M68K_MODE_HALT;
                    827:       TME_M68K_SEQUENCE_START;
                    828:       tme_m68k_redispatch(ic);
                    829:     }
                    830:   }
                    831: 
                    832:   /* otherwise, exception processing must not already be happening: */
                    833:   else {
                    834:     assert(ic->_tme_m68k_exceptions == 0);
                    835:   }
                    836: 
                    837:   /* begin exception processing: */
                    838:   ic->_tme_m68k_exceptions |= new_exceptions;
                    839:   ic->_tme_m68k_mode = TME_M68K_MODE_EXCEPTION;
                    840:   TME_M68K_SEQUENCE_START;
                    841:   tme_m68k_redispatch(ic);
                    842: }
                    843: 
                    844: /* this changes SR, and swaps %a7 as needed: */
                    845: void
                    846: tme_m68k_change_sr(struct tme_m68k *ic, tme_uint16_t sr)
                    847: {
1.1.1.3   root      848:   tme_uint16_t flags_mode;
                    849: 
                    850:   /* only recognize the M bit on a 68020 or better: */
                    851:   flags_mode = (TME_M68K_FLAG_S
                    852:                | ((ic->tme_m68k_type >= TME_M68K_M68020)
                    853:                   * TME_M68K_FLAG_M));
1.1       root      854:   
                    855:   /* save %a7 in the proper stack pointer control register: */
1.1.1.3   root      856:   switch (ic->tme_m68k_ireg_sr & flags_mode) {
1.1       root      857:   case 0:
                    858:   case TME_M68K_FLAG_M:
                    859:     ic->tme_m68k_ireg_usp = ic->tme_m68k_ireg_a7;
                    860:     break;
                    861:   case TME_M68K_FLAG_S:
1.1.1.3   root      862:     ic->tme_m68k_ireg_isp = ic->tme_m68k_ireg_a7;
1.1       root      863:     break;
                    864:   case (TME_M68K_FLAG_S | TME_M68K_FLAG_M):
1.1.1.3   root      865:     ic->tme_m68k_ireg_msp = ic->tme_m68k_ireg_a7;
1.1       root      866:     break;
                    867:   }
                    868: 
                    869:   /* load %a7 from the proper stack pointer control register: */
                    870:   ic->tme_m68k_ireg_sr = sr;
1.1.1.3   root      871:   switch (ic->tme_m68k_ireg_sr & flags_mode) {
1.1       root      872:   case 0:
                    873:   case TME_M68K_FLAG_M:
                    874:     ic->tme_m68k_ireg_a7 = ic->tme_m68k_ireg_usp;
                    875:     break;
                    876:   case TME_M68K_FLAG_S:
1.1.1.3   root      877:     ic->tme_m68k_ireg_a7 = ic->tme_m68k_ireg_isp;
1.1       root      878:     break;
                    879:   case (TME_M68K_FLAG_S | TME_M68K_FLAG_M):
1.1.1.3   root      880:     ic->tme_m68k_ireg_a7 = ic->tme_m68k_ireg_msp;
1.1       root      881:     break;
                    882:   }
                    883: }
                    884: 
                    885: /* this starts processing an m68k exception: */
                    886: void
                    887: tme_m68k_exception_process_start(struct tme_m68k *ic, unsigned int ipl)
                    888: {
                    889:   tme_uint16_t sr;
                    890: 
                    891:   /* make an internal copy of the status register, then set S, clear
                    892:      T, and update I: */
                    893:   if (!TME_M68K_SEQUENCE_RESTARTING) {
                    894:     ic->tme_m68k_ireg_shadow_sr = ic->tme_m68k_ireg_sr;
1.1.1.3   root      895:     sr = (ic->tme_m68k_ireg_sr | TME_M68K_FLAG_S) & ~ic->_tme_m68k_sr_mask_t;
1.1       root      896:     if (ipl > TME_M68K_IPL_NONE) {
                    897:       assert(ipl == TME_M68K_IPL_NMI
                    898:             || ipl > TME_M68K_FLAG_IPM(sr));
                    899:       sr = (sr & ~(TME_M68K_IPL_MAX << 8)) | (ipl << 8);
                    900:     }
                    901:     tme_m68k_change_sr(ic, sr);
                    902:   }
                    903: }
                    904: 
                    905: /* this finishes processing an m68k exception: */
                    906: void
                    907: tme_m68k_exception_process_finish(struct tme_m68k *ic, tme_uint8_t format, tme_uint8_t vector)
                    908: {
                    909:   tme_uint16_t vector_offset;
                    910: 
                    911:   /* stack the frame format and vector offset, unless this is a 68000: */
                    912:   vector_offset = ((tme_uint16_t) vector) << 2;
                    913:   if (ic->tme_m68k_type != TME_M68K_M68000) {
                    914:     tme_m68k_push16(ic, (((tme_uint16_t) format) << 12) | vector_offset);
                    915:   }
                    916: 
                    917:   /* stack the program counter: */
                    918:   tme_m68k_push32(ic, ic->tme_m68k_ireg_pc);
                    919:   
                    920:   /* stack the internal copy of the status register: */
                    921:   tme_m68k_push16(ic, ic->tme_m68k_ireg_shadow_sr);
                    922: 
                    923:   /* do a bus cycle to read the vector into the program counter: */
                    924:   if (!TME_M68K_SEQUENCE_RESTARTING) {
1.1.1.3   root      925:     ic->_tme_m68k_ea_function_code = TME_M68K_FC_SD;
1.1       root      926:     ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_vbr + vector_offset;
                    927:   }
                    928:   tme_m68k_read_mem32(ic, TME_M68K_IREG_PC);
                    929: }
                    930: 
1.1.1.3   root      931: /* common m68000 and m68010 exception processing: */
1.1       root      932: void
1.1.1.3   root      933: tme_m68000_exception_process(struct tme_m68k *ic)
1.1       root      934: {
                    935:   tme_uint32_t exceptions;
1.1.1.3   root      936:   tme_uint8_t vector;
1.1       root      937: 
                    938:   /* get the set of exceptions.  we must have no group 0 exceptions: */
                    939:   exceptions = ic->_tme_m68k_exceptions;
1.1.1.3   root      940:   assert((exceptions & (TME_M68K_EXCEPTION_RESET
                    941:                        | TME_M68K_EXCEPTION_AERR
                    942:                        | TME_M68K_EXCEPTION_BERR)) == 0);
1.1       root      943: 
                    944:   /* these if statements are ordered to implement the priority
                    945:      relationship between the different exceptions as outlined in 
                    946:      the 68000 user's manual (pp 93 in my copy): */
                    947:   
1.1.1.3   root      948:   if (TME_M68K_EXCEPTION_IS_INST(exceptions)) {
1.1       root      949:     tme_m68k_exception_process_start(ic, 0);
1.1.1.3   root      950:     tme_m68k_exception_process_finish(ic, TME_M68K_FORMAT_0, TME_M68K_EXCEPTION_IS_INST(exceptions));
1.1       root      951:   }
                    952:   
1.1.1.3   root      953:   if (exceptions & TME_M68K_EXCEPTION_TRACE) {
1.1       root      954:     tme_m68k_exception_process_start(ic, 0);
1.1.1.3   root      955:     tme_m68k_exception_process_finish(ic, TME_M68K_FORMAT_0, TME_M68K_VECTOR_TRACE);
                    956:   }
                    957:   
                    958:   if (TME_M68K_EXCEPTION_IS_INT(exceptions)) {
                    959:     tme_m68k_exception_process_start(ic, TME_M68K_EXCEPTION_IS_INT(exceptions));
                    960:     tme_m68k_exception_process_finish(ic, TME_M68K_FORMAT_0, TME_M68K_EXCEPTION_INT_VEC(exceptions));
1.1       root      961:   }
                    962:   
1.1.1.3   root      963:   if (exceptions & TME_M68K_EXCEPTION_ILL) {
                    964:     if (TME_FIELD_EXTRACTU(ic->_tme_m68k_insn_opcode, 12, 4) == 0xa) {
                    965:       vector = TME_M68K_VECTOR_LINE_A;
                    966:     }
                    967:     else if (TME_FIELD_EXTRACTU(ic->_tme_m68k_insn_opcode, 12, 4) == 0xf) {
                    968:       vector = TME_M68K_VECTOR_LINE_F;
                    969:     }
                    970:     else {
                    971:       vector = TME_M68K_VECTOR_ILL;
                    972:     }
                    973:     tme_m68k_exception_process_start(ic, 0);
                    974:     tme_m68k_exception_process_finish(ic, TME_M68K_FORMAT_0, vector);
1.1       root      975:   }
                    976:   
1.1.1.3   root      977:   if (exceptions & TME_M68K_EXCEPTION_PRIV) {
1.1       root      978:     tme_m68k_exception_process_start(ic, 0);
1.1.1.3   root      979:     tme_m68k_exception_process_finish(ic, TME_M68K_FORMAT_0, TME_M68K_VECTOR_TRACE);
1.1       root      980:   }
                    981:   
1.1.1.3   root      982:   /* we have processed all exceptions - resume execution: */
                    983:   ic->_tme_m68k_exceptions = 0;
                    984:   ic->_tme_m68k_mode = TME_M68K_MODE_EXECUTION;
                    985:   TME_M68K_SEQUENCE_START;
                    986:   tme_m68k_redispatch(ic);
                    987: }
                    988: 
                    989: /* common m68020 and later exception processing: */
                    990: void
                    991: tme_m68020_exception_process(struct tme_m68k *ic)
                    992: {
                    993:   tme_uint32_t exceptions;
                    994:   tme_uint8_t vector;
                    995:   struct {
                    996:     tme_uint16_t tme_m68k_fmt1_sr;
                    997:     tme_uint16_t tme_m68k_fmt1_pc_hi;
                    998:     tme_uint16_t tme_m68k_fmt1_pc_lo;    
                    999:     tme_uint16_t tme_m68k_fmt1_vector_offset;
                   1000:   } fmt1;
                   1001: 
                   1002:   /* get the set of exceptions.  we must have no group 0 or 1
                   1003:      exceptions: */
                   1004:   exceptions = ic->_tme_m68k_exceptions;
                   1005:   assert((exceptions & (TME_M68K_EXCEPTION_RESET
                   1006:                        | TME_M68K_EXCEPTION_AERR
                   1007:                        | TME_M68K_EXCEPTION_BERR)) == 0);
                   1008: 
                   1009:   /* these if statements are ordered to implement the priority
                   1010:      relationship between the different exceptions as outlined in 
                   1011:      the 68020 user's manual (pp 144 in my copy): */
                   1012:   
                   1013:   /* group 2 exceptions: */
                   1014:   if (TME_M68K_EXCEPTION_IS_INST(exceptions)) {
1.1       root     1015:     tme_m68k_exception_process_start(ic, 0);
1.1.1.3   root     1016: 
                   1017:     /* get the vector number: */
                   1018:     vector = TME_M68K_EXCEPTION_IS_INST(exceptions);
                   1019: 
                   1020:     /* of the group 2 exceptions, only the Format Error and TRAP #N
                   1021:        exceptions generate a format 0 stack frame.  the RTE mode code
                   1022:        and the TRAP instruction code are expected to have left
                   1023:        ic->tme_m68k_ireg_pc as the PC they want stacked: */
                   1024:     if (vector == TME_M68K_VECTOR_FORMAT
                   1025:        || (TME_M68K_VECTOR_TRAP_0 <= vector
                   1026:            && vector < (TME_M68K_VECTOR_TRAP_0 + 16))) {
                   1027:       tme_m68k_exception_process_finish(ic, TME_M68K_FORMAT_0, vector);
                   1028:     }
                   1029: 
                   1030:     /* all other group 2 exceptions generate a format 2 stack frame.
                   1031:        all code that can signal this exception is expected to have
                   1032:        left ic->tme_m68k_ireg_pc *and* ic->tme_m68k_ireg_pc_last as
                   1033:        the PCs they want stacked: */
                   1034:     else {
                   1035:       
                   1036:       /* stack the program counter of the instruction that caused the exception: */
                   1037:       tme_m68k_push32(ic, ic->tme_m68k_ireg_pc_last);
                   1038: 
                   1039:       /* finish with a format 2 stack frame: */
                   1040:       tme_m68k_exception_process_finish(ic, TME_M68K_FORMAT_2, vector);
                   1041:     }
                   1042:   }
                   1043: 
                   1044:   /* group 3 exceptions: */
                   1045:   if (exceptions & TME_M68K_EXCEPTION_ILL) {
                   1046:     if (TME_FIELD_EXTRACTU(ic->_tme_m68k_insn_opcode, 12, 4) == 0xa) {
                   1047:       vector = TME_M68K_VECTOR_LINE_A;
                   1048:     }
                   1049:     else if (TME_FIELD_EXTRACTU(ic->_tme_m68k_insn_opcode, 12, 4) == 0xf) {
                   1050:       vector = TME_M68K_VECTOR_LINE_F;
                   1051:     }
                   1052:     else {
                   1053:       vector = TME_M68K_VECTOR_ILL;
                   1054:     }
                   1055:     tme_m68k_exception_process_start(ic, 0);
                   1056:     tme_m68k_exception_process_finish(ic, TME_M68K_FORMAT_0, vector);
                   1057:   }
                   1058:   if (exceptions & TME_M68K_EXCEPTION_PRIV) {
                   1059:     tme_m68k_exception_process_start(ic, 0);
                   1060:     tme_m68k_exception_process_finish(ic, TME_M68K_FORMAT_0, TME_M68K_VECTOR_PRIV);
                   1061:   }
                   1062: 
                   1063:   /* group 4.1 exceptions: */
                   1064:   if (exceptions & TME_M68K_EXCEPTION_TRACE) {
                   1065:     tme_m68k_exception_process_start(ic, 0);
                   1066:     tme_m68k_push32(ic, ic->tme_m68k_ireg_pc_last);
                   1067:     tme_m68k_exception_process_finish(ic, TME_M68K_FORMAT_2, TME_M68K_VECTOR_TRACE);
                   1068:   }
                   1069:   
                   1070:   /* group 4.2 exceptions: */
                   1071:   if (TME_M68K_EXCEPTION_IS_INT(exceptions)) {
                   1072:     tme_m68k_exception_process_start(ic, TME_M68K_EXCEPTION_IS_INT(exceptions));
                   1073:     tme_m68k_exception_process_finish(ic, TME_M68K_FORMAT_0, TME_M68K_EXCEPTION_INT_VEC(exceptions));
                   1074: 
                   1075:     /* if the M-bit is set: */
                   1076:     if (ic->tme_m68k_ireg_sr & TME_M68K_FLAG_M) {
                   1077: 
                   1078:       /* make the throwaway four-word stack frame (format 1): */
                   1079:       fmt1.tme_m68k_fmt1_vector_offset = tme_htobe_u16((TME_M68K_FORMAT_1 << 12) | (TME_M68K_EXCEPTION_INT_VEC(exceptions) << 2));
                   1080:       fmt1.tme_m68k_fmt1_pc_lo = tme_htobe_u16((ic->tme_m68k_ireg_pc >>  0) & 0xffff);
                   1081:       fmt1.tme_m68k_fmt1_pc_hi = tme_htobe_u16((ic->tme_m68k_ireg_pc >> 16) & 0xffff);
                   1082:       fmt1.tme_m68k_fmt1_sr = tme_htobe_u16(ic->tme_m68k_ireg_sr);
                   1083: 
                   1084:       /* store the throwaway four-word stack frame on the interrupt stack: */
                   1085:       if (!TME_M68K_SEQUENCE_RESTARTING) {
                   1086:        ic->_tme_m68k_ea_function_code = TME_M68K_FC_SD;
                   1087:        ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_isp - sizeof(fmt1);
                   1088:       }
                   1089:       tme_m68k_write_mem(ic, (tme_uint8_t *) &fmt1, sizeof(fmt1));
                   1090: 
                   1091:       /* move to the interrupt stack: */
                   1092:       ic->tme_m68k_ireg_isp -= sizeof(fmt1);
                   1093:       tme_m68k_change_sr(ic, ic->tme_m68k_ireg_sr & ~TME_M68K_FLAG_M);
                   1094:     }
1.1       root     1095:   }
                   1096:   
                   1097:   /* we have processed all exceptions - resume execution: */
                   1098:   ic->_tme_m68k_exceptions = 0;
                   1099:   ic->_tme_m68k_mode = TME_M68K_MODE_EXECUTION;
                   1100:   TME_M68K_SEQUENCE_START;
                   1101:   tme_m68k_redispatch(ic);
                   1102: }
                   1103: 
                   1104: /* this starts an m68k RTE: */
                   1105: tme_uint16_t
                   1106: tme_m68k_rte_start(struct tme_m68k *ic)
                   1107: {
                   1108: 
                   1109:   /* set up to read from the stack frame: */
1.1.1.3   root     1110:   if (!TME_M68K_SEQUENCE_RESTARTING) {
                   1111:     ic->_tme_m68k_ea_function_code = TME_M68K_FC_SD;
                   1112:     ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_a7;
                   1113:   }
1.1       root     1114: 
                   1115:   /* read the stacked status register: */
                   1116:   tme_m68k_read_mem16(ic, TME_M68K_IREG_SHADOW_SR);
1.1.1.3   root     1117:   if (!TME_M68K_SEQUENCE_RESTARTING) {
                   1118:     ic->_tme_m68k_ea_address += sizeof(ic->tme_m68k_ireg_shadow_sr);
                   1119:   }
1.1       root     1120: 
                   1121:   /* read the stacked PC: */
                   1122:   tme_m68k_read_mem32(ic, TME_M68K_IREG_PC_NEXT);
1.1.1.3   root     1123:   if (!TME_M68K_SEQUENCE_RESTARTING) {
                   1124:     ic->_tme_m68k_ea_address += sizeof(ic->tme_m68k_ireg_pc_next);
                   1125:   }
1.1       root     1126: 
                   1127:   /* read the stacked format/offset word, unless this is a 68000: */
                   1128:   if (ic->tme_m68k_type != TME_M68K_M68000) {
                   1129:     tme_m68k_read_mem16(ic, TME_M68K_IREG_FORMAT_OFFSET);
1.1.1.3   root     1130:     if (!TME_M68K_SEQUENCE_RESTARTING) {
                   1131:       ic->_tme_m68k_ea_address += sizeof(ic->tme_m68k_ireg_format_offset);
                   1132:     }
1.1       root     1133:   }
                   1134:   else {
                   1135:     ic->tme_m68k_ireg_format_offset = 0;
                   1136:   }
                   1137: 
                   1138:   /* return the frame format: */
                   1139:   return (ic->tme_m68k_ireg_format_offset >> 12);
                   1140: }
                   1141: 
                   1142: /* this finishes an m68k RTE: */
                   1143: void
                   1144: tme_m68k_rte_finish(struct tme_m68k *ic, tme_uint32_t format_extra)
                   1145: {
                   1146:   tme_uint32_t frame_size;
                   1147: 
                   1148:   /* calculate the total frame size.  the 68000 doesn't have a
                   1149:      format/status word: */
                   1150:   frame_size = (sizeof(ic->tme_m68k_ireg_shadow_sr)
                   1151:                + sizeof(ic->tme_m68k_ireg_pc_next)
                   1152:                + (ic->tme_m68k_type != TME_M68K_M68000
                   1153:                   ? sizeof(ic->tme_m68k_ireg_format_offset)
                   1154:                   : 0)
                   1155:                + format_extra);
                   1156:   assert((frame_size & 1) == 0);
                   1157: 
                   1158:   /* adjust the stack: */
                   1159:   ic->tme_m68k_ireg_a7 += frame_size;
                   1160:   
                   1161:   /* set the status register: */
                   1162:   tme_m68k_change_sr(ic, ic->tme_m68k_ireg_shadow_sr);
                   1163:                     
                   1164:   /* set the PC: */
                   1165:   ic->tme_m68k_ireg_pc = ic->tme_m68k_ireg_pc_next;
                   1166:   
                   1167:   /* redispatch: */
                   1168:   tme_m68k_redispatch(ic);
                   1169: }
                   1170: 
                   1171: /* this stores the group 0 sequence into a region of host memory.
                   1172:    this is used when preparing the state information to be stored
                   1173:    on the stack for a bus or address error: */
1.1.1.4 ! root     1174: unsigned int
1.1       root     1175: tme_m68k_sequence_empty(const struct tme_m68k *ic, tme_uint8_t *raw, unsigned int raw_avail)
                   1176: {
                   1177:   const struct _tme_m68k_sequence *sequence;
                   1178:   unsigned int raw_used;
                   1179:   
                   1180:   /* get the group 0 sequence: */
                   1181:   sequence = &ic->_tme_m68k_group0_sequence;
                   1182:   raw_used = 0;
                   1183: 
                   1184:   /* we use 8 bits for the mode (2 bits) and flags (6 bits): */
                   1185:   raw_used += sizeof(tme_uint8_t);
                   1186:   assert(raw_avail >= raw_used);
                   1187:   assert(sequence->_tme_m68k_sequence_mode < TME_BIT(2));
                   1188:   assert(sequence->_tme_m68k_sequence_mode_flags < TME_BIT(6));
                   1189:   *(raw++) = ((sequence->_tme_m68k_sequence_mode << 6)
                   1190:              | sequence->_tme_m68k_sequence_mode_flags);
                   1191:   
                   1192: 
                   1193:   /* we use 16 bits for the faulted memory transfer ordinal
                   1194:      (12 bits) and already-transferred byte count (4 bits): */
                   1195:   raw_used += sizeof(tme_uint16_t);
                   1196:   assert(raw_avail >= raw_used);
                   1197:   assert(sequence->_tme_m68k_sequence_transfer_faulted < TME_BIT(12));
                   1198:   assert(sequence->_tme_m68k_sequence_transfer_faulted_after < TME_BIT(4));
                   1199:   *(raw++) = sequence->_tme_m68k_sequence_transfer_faulted >> 4;
                   1200:   *(raw++) = ((sequence->_tme_m68k_sequence_transfer_faulted << 4)
                   1201:              | sequence->_tme_m68k_sequence_transfer_faulted_after);
                   1202: 
                   1203: #ifdef _TME_M68K_VERIFY
                   1204:   /* we use sizeof(_tme_m68k_sequence_uid) bytes for the sequence UID: */
                   1205:   raw_used += sizeof(sequence->_tme_m68k_sequence_uid);
                   1206:   assert(raw_avail >= raw_used);
                   1207:   memcpy(raw,
                   1208:         &sequence->_tme_m68k_sequence_uid,
                   1209:         sizeof(sequence->_tme_m68k_sequence_uid));
                   1210:   raw += sizeof(sequence->_tme_m68k_sequence_uid);
                   1211: #endif /* _TME_M68K_VERIFY */
                   1212: 
                   1213:   /* done: */
                   1214:   return (raw_used);
                   1215: }
                   1216: 
                   1217: /* this restores the group 0 sequence from a region of host memory.
                   1218:    this is used when reading the state information stored on the
                   1219:    stack for a bus or address error: */
1.1.1.4 ! root     1220: unsigned int
1.1       root     1221: tme_m68k_sequence_fill(struct tme_m68k *ic, const tme_uint8_t *raw, unsigned int raw_avail)
                   1222: {
                   1223:   struct _tme_m68k_sequence *sequence;
                   1224:   unsigned int raw_used;
                   1225:   
                   1226:   /* get the group 0 sequence: */
                   1227:   sequence = &ic->_tme_m68k_group0_sequence;
                   1228:   raw_used = 0;
                   1229: 
                   1230:   /* we used 8 bits for the mode (2 bits) and flags (6 bits): */
                   1231:   raw_used += sizeof(tme_uint8_t);
                   1232:   if (raw_avail < raw_used) {
1.1.1.4 ! root     1233:     return (0);
1.1       root     1234:   }
                   1235:   sequence->_tme_m68k_sequence_mode = *raw >> 6;
                   1236:   sequence->_tme_m68k_sequence_mode_flags = (*(raw++) & (TME_BIT(6) - 1));
                   1237: 
                   1238:   /* we used 16 bits for the faulted memory transfer ordinal
                   1239:      (12 bits) and already-transferred byte count (4 bits): */
                   1240:   raw_used += sizeof(tme_uint16_t);
                   1241:   if (raw_avail < raw_used) {
1.1.1.4 ! root     1242:     return (0);
1.1       root     1243:   }
                   1244:   sequence->_tme_m68k_sequence_transfer_faulted = 
                   1245:     (((tme_uint16_t) raw[0]) << 4)
                   1246:     | (raw[1] >> 4);
                   1247:   sequence->_tme_m68k_sequence_transfer_faulted_after = raw[1] & (TME_BIT(4) - 1);
                   1248:   raw += sizeof(tme_uint16_t);
                   1249: 
                   1250: #ifdef _TME_M68K_VERIFY
                   1251:   /* we used sizeof(_tme_m68k_sequence_uid) bytes for the sequence UID: */
                   1252:   raw_used += sizeof(sequence->_tme_m68k_sequence_uid);
                   1253:   if (raw_avail < raw_used) {
1.1.1.4 ! root     1254:     return (0);
1.1       root     1255:   }
                   1256:   memcpy(&sequence->_tme_m68k_sequence_uid,
                   1257:         raw,
                   1258:         sizeof(sequence->_tme_m68k_sequence_uid));
                   1259:   raw += sizeof(sequence->_tme_m68k_sequence_uid);
                   1260: #endif /* _TME_M68K_VERIFY */
                   1261: 
                   1262:   /* initialize this to one: */
                   1263:   sequence->_tme_m68k_sequence_transfer_next = 1;
                   1264: 
                   1265:   /* done: */
                   1266:   return (raw_used);
                   1267: }
                   1268: 
1.1.1.4 ! root     1269: /* this empties the instruction buffer into an exception frame: */
        !          1270: unsigned int
        !          1271: tme_m68k_insn_buffer_empty(const struct tme_m68k *ic, tme_uint8_t *raw, unsigned int raw_avail)
1.1       root     1272: {
1.1.1.4 ! root     1273:   unsigned int fetch_total;
        !          1274:   
        !          1275:   /* get the total number of bytes in the instruction buffer: */
        !          1276:   fetch_total = ic->_tme_m68k_insn_fetch_slow_count_total;
1.1       root     1277: 
1.1.1.4 ! root     1278:   /* save the total number of bytes fetched into the instruction
        !          1279:      buffer, the number of bytes in the instruction buffer fetched by
        !          1280:      the fast executor, and then the instruction buffer itself: */
        !          1281:   assert ((fetch_total % sizeof(tme_uint16_t)) == 0
        !          1282:          && fetch_total <= (TME_M68K_INSN_WORDS_MAX * sizeof(tme_uint16_t)));
        !          1283:   assert ((ic->_tme_m68k_insn_fetch_slow_count_fast % sizeof(tme_uint16_t)) == 0
        !          1284:          && ic->_tme_m68k_insn_fetch_slow_count_fast <= fetch_total);
        !          1285:   assert (raw_avail >= (sizeof(tme_uint8_t) + sizeof(tme_uint8_t) + fetch_total));
        !          1286:   raw[0] = fetch_total;
        !          1287:   raw[1] = ic->_tme_m68k_insn_fetch_slow_count_fast;
        !          1288:   memcpy(raw + 2,
        !          1289:         &ic->_tme_m68k_insn_fetch_buffer[0],
        !          1290:         fetch_total);
        !          1291:   
        !          1292:   /* return the number of bytes we put in an exception frame: */
        !          1293:   return (sizeof(tme_uint8_t) + sizeof(tme_uint8_t) + fetch_total);
        !          1294: }
1.1       root     1295: 
1.1.1.4 ! root     1296: /* this fills the instruction buffer from an exception frame: */
        !          1297: unsigned int
        !          1298: tme_m68k_insn_buffer_fill(struct tme_m68k *ic, const tme_uint8_t *raw, unsigned int raw_avail)
        !          1299: {
        !          1300:   unsigned int fetch_total;
        !          1301:   unsigned int fetch_fast;
1.1       root     1302: 
1.1.1.4 ! root     1303:   /* there must be at least two bytes in the exception frame: */
        !          1304:   if (raw_avail >= (sizeof(tme_uint8_t) + sizeof(tme_uint8_t))) {
        !          1305: 
        !          1306:     /* restore the total number of bytes fetched into the instruction
        !          1307:        buffer, and the number of bytes in the instruction buffer
        !          1308:        fetched by the fast executor: */
        !          1309:     fetch_total = raw[0];
        !          1310:     fetch_fast = raw[1];
        !          1311:     if ((fetch_total % sizeof(tme_uint16_t)) == 0
        !          1312:        && fetch_total <= (TME_M68K_INSN_WORDS_MAX * sizeof(tme_uint16_t))
        !          1313:        && (fetch_fast % sizeof(tme_uint16_t)) == 0
        !          1314:        && fetch_fast <= fetch_total
        !          1315:        && raw_avail >= (sizeof(tme_uint8_t) + sizeof(tme_uint8_t) + fetch_total)) {
        !          1316: 
        !          1317:       /* restore the total number of bytes fetched into the instruction
        !          1318:         buffer, the number of bytes in the instruction buffer fetched by
        !          1319:         the fast executor, and then the instruction buffer itself: */
        !          1320:       ic->_tme_m68k_insn_fetch_slow_count_total = fetch_total;
        !          1321:       ic->_tme_m68k_insn_fetch_slow_count_fast = fetch_fast;
        !          1322:       memcpy(&ic->_tme_m68k_insn_fetch_buffer[0],
        !          1323:             raw + 2,
        !          1324:             fetch_total);
        !          1325: 
        !          1326:       /* return the number of bytes restored from the exception frame: */
        !          1327:       return ((sizeof(tme_uint8_t) + sizeof(tme_uint8_t) + fetch_total));
1.1       root     1328:     }
                   1329:   }
                   1330: 
1.1.1.4 ! root     1331:   /* this exception frame is invalid: */
        !          1332:   return (0);
        !          1333: }
1.1       root     1334: 
1.1.1.4 ! root     1335: /* this unlocks data structures before a callout: */
        !          1336: void
        !          1337: tme_m68k_callout_unlock(struct tme_m68k *ic)
        !          1338: {
        !          1339:   struct tme_m68k_tlb *tlb;
        !          1340: 
        !          1341:   assert ((ic->_tme_m68k_mode == TME_M68K_MODE_EXECUTION)
        !          1342:          || (ic->_tme_m68k_insn_fetch_fast_itlb == NULL));
        !          1343: 
        !          1344:   /* if we have a busy fast instruction TLB entry: */
        !          1345:   tlb = ic->_tme_m68k_insn_fetch_fast_itlb;
        !          1346:   if (tlb != NULL) {
        !          1347: 
        !          1348:     /* unbusy the fast instruction TLB entry: */
        !          1349:     tme_m68k_tlb_unbusy(tlb);
        !          1350:   }
        !          1351: }
        !          1352: 
        !          1353: /* this relocks data structures after a callout: */
        !          1354: void
        !          1355: tme_m68k_callout_relock(struct tme_m68k *ic)
        !          1356: {
        !          1357:   struct tme_m68k_tlb *tlb;
        !          1358:   struct tme_m68k_tlb *tlb_now;
        !          1359: 
        !          1360:   assert ((ic->_tme_m68k_mode == TME_M68K_MODE_EXECUTION)
        !          1361:          || (ic->_tme_m68k_insn_fetch_fast_itlb == NULL));
        !          1362: 
        !          1363:   /* if we have a busy fast instruction TLB entry: */
        !          1364:   tlb = ic->_tme_m68k_insn_fetch_fast_itlb;
        !          1365:   if (tlb != NULL) {
        !          1366: 
        !          1367:     /* rebusy the fast instruction TLB entry: */
        !          1368:     tme_m68k_tlb_busy(tlb);
        !          1369:       
        !          1370:     /* get what should be our instruction TLB entry now: */
        !          1371:     tlb_now = tme_memory_atomic_pointer_read(struct tme_m68k_tlb *, ic->_tme_m68k_itlb, &ic->_tme_m68k_tlbs_rwlock);
        !          1372: 
        !          1373:     /* if the instruction TLB entry has changed or is invalid: */
        !          1374:     if (__tme_predict_false(tlb_now != tlb
        !          1375:                            || tme_bus_tlb_is_invalid(&tlb->tme_m68k_tlb_bus_tlb))) {
        !          1376: 
        !          1377:       /* poison ic->_tme_m68k_insn_fetch_fast_last so the fast
        !          1378:         instruction executor fetch macros will fail: */
        !          1379:       assert ((ic->_tme_m68k_insn_fetch_fast_next - 1) < ic->_tme_m68k_insn_fetch_fast_next);
        !          1380:       ic->_tme_m68k_insn_fetch_fast_last = ic->_tme_m68k_insn_fetch_fast_next - 1;
        !          1381:     }
        !          1382:   }
1.1       root     1383: }
                   1384: 
                   1385: /* this is the group 0 fault hook for the fast executor: */
                   1386: void
                   1387: tme_m68k_group0_hook_fast(struct tme_m68k *ic)
                   1388: {
1.1.1.4 ! root     1389:   unsigned int fetch_fast;
1.1       root     1390: 
1.1.1.4 ! root     1391:   /* get the number of bytes in the instruction buffer.  they have all
        !          1392:      been fetched by the fast executor: */
        !          1393:   /* NB: it's possible for this to be zero: */
        !          1394:   fetch_fast = (ic->_tme_m68k_insn_fetch_fast_next - ic->_tme_m68k_insn_fetch_fast_start);
        !          1395:   assert ((fetch_fast % sizeof(tme_uint16_t)) == 0
        !          1396:          && fetch_fast <= (TME_M68K_INSN_WORDS_MAX * sizeof(tme_uint16_t)));
        !          1397:   ic->_tme_m68k_insn_fetch_slow_count_total = fetch_fast;
        !          1398:   ic->_tme_m68k_insn_fetch_slow_count_fast = fetch_fast;
1.1       root     1399: }
                   1400: 
1.1.1.4 ! root     1401: /* this starts a read/modify/write cycle: */
        !          1402: int
        !          1403: tme_m68k_rmw_start(struct tme_m68k *ic,
        !          1404:                   struct tme_m68k_rmw *rmw)
1.1       root     1405: {
1.1.1.4 ! root     1406:   struct tme_m68k_tlb *tlb_set;
        !          1407:   struct tme_m68k_tlb *tlbs_all[3];
        !          1408:   int tlbs_busy[2];
1.1       root     1409:   struct tme_m68k_tlb *tlb;
1.1.1.4 ! root     1410:   struct tme_m68k_tlb *tlb_use;
        !          1411:   unsigned int tlb_i;
        !          1412:   unsigned int address_i;
        !          1413:   unsigned int address_i_fill;
        !          1414:   tme_uint32_t address;
        !          1415:   unsigned int address_cycles[2];
        !          1416:   unsigned int address_fills[2];
        !          1417:   tme_uint32_t *buffer_reg;
        !          1418:   int supported;
1.1       root     1419: 
1.1.1.4 ! root     1420:   /* if the user reran the cycle: */
1.1       root     1421:   if (TME_M68K_SEQUENCE_RESTARTING
                   1422:       && (ic->_tme_m68k_group0_buffer_read_softrr > 0
                   1423:          || ic->_tme_m68k_group0_buffer_write_softrr > 0)) {
1.1.1.4 ! root     1424: 
        !          1425:     /* return failure: */
        !          1426:     return (-1);
1.1       root     1427:   }
                   1428: 
                   1429:   /* we always rerun read/modify/write cycles in their entirety: */
                   1430:   ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_faulted
                   1431:     = ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_next - 1;
                   1432: 
1.1.1.4 ! root     1433:   /* we only support tas and cas, which have one address, and cas2,
        !          1434:      which has two addresses: */
        !          1435:   assert (rmw->tme_m68k_rmw_address_count == 1
        !          1436:          || rmw->tme_m68k_rmw_address_count == 2);
        !          1437: 
        !          1438:   /* get the TLB set from which we will get all TLB entries for this
        !          1439:      instruction.  for some machines it may be important to guarantee
        !          1440:      that no one can observe an atomic operation being split by a TLB
        !          1441:      set change: */
        !          1442:   tlb_set = tme_memory_atomic_pointer_read(struct tme_m68k_tlb *,
        !          1443:                                           ic->_tme_m68k_tlb_array,
        !          1444:                                           &ic->_tme_m68k_tlbs_rwlock);
        !          1445: 
        !          1446:   /* assume that we will only consider one TLB entry, for the first
        !          1447:      address: */
        !          1448:   tlbs_all[0] = TME_M68K_TLB_ENTRY_SET(tlb_set,
        !          1449:                                       ic->_tme_m68k_ea_function_code,
        !          1450:                                       rmw->tme_m68k_rmw_addresses[0]);
        !          1451:   tlbs_all[1] = NULL;
        !          1452: 
        !          1453:   /* if there are two addresses: */
        !          1454:   if (rmw->tme_m68k_rmw_address_count == 2) {
        !          1455: 
        !          1456:     /* we will consider another TLB entry for the second address: */
        !          1457:     tlbs_all[1] = TME_M68K_TLB_ENTRY_SET(tlb_set,
        !          1458:                                         ic->_tme_m68k_ea_function_code,
        !          1459:                                         rmw->tme_m68k_rmw_addresses[1]);
        !          1460: 
        !          1461:     /* if the TLB entry for the second address collides with the TLB
        !          1462:        entry for the first address: */
        !          1463:     if (tlbs_all[1] == tlbs_all[0]) {
        !          1464: 
        !          1465:       /* we will instead consider an alternate TLB entry for the
        !          1466:          second address: */
        !          1467:       tlbs_all[1] = TME_M68K_TLB_ENTRY_SET(tlb_set,
        !          1468:                                           ic->_tme_m68k_ea_function_code,
        !          1469:                                           (rmw->tme_m68k_rmw_addresses[1]
        !          1470:                                            + TME_M68K_TLB_ADDRESS_BIAS(1)));
        !          1471:       assert (tlbs_all[1] != tlbs_all[0]);
        !          1472:     }
        !          1473:   }
        !          1474: 
        !          1475:   /* make sure that the list of TLB entries to consider is terminated: */
        !          1476:   tlbs_all[2] = NULL;
        !          1477: 
        !          1478:   /* none of the TLB entries to consider are busy: */
        !          1479:   tlbs_busy[0] = FALSE;
        !          1480:   tlbs_busy[1] = FALSE;
        !          1481: 
        !          1482:   /* the addresses aren't using any TLB entries yet: */
        !          1483:   rmw->tme_m68k_rmw_tlbs[0] = NULL;
        !          1484:   rmw->tme_m68k_rmw_tlbs[1] = NULL;
        !          1485: 
        !          1486:   /* we haven't done any slow reads for any addresses yet: */
        !          1487:   rmw->tme_m68k_rmw_slow_reads[0] = FALSE;
        !          1488:   rmw->tme_m68k_rmw_slow_reads[1] = FALSE;
        !          1489: 
        !          1490:   /* whenever we need to find a TLB entry to use for an address, we
        !          1491:      always prefer one that allows both reading and writing, because
        !          1492:      we hope that such a TLB entry allows both fast reading and fast
        !          1493:      writing.
        !          1494: 
        !          1495:      if we can't find such a TLB entry initially, we try to fill a TLB
        !          1496:      entry for writing (you can't fill a TLB entry for both reading
        !          1497:      and writing), in the hopes that this gives us a TLB entry that
        !          1498:      allows both fast reading and fast writing.  filling for writing
        !          1499:      is important with some virtual memory hardware, and may actually
        !          1500:      be required to enable writing.
        !          1501: 
        !          1502:      if this fill gives us a TLB entry that doesn't allow both fast
        !          1503:      reading and fast writing, it actually might not allow reading at
        !          1504:      all.  to check for this, we then try to fill a TLB entry for
        !          1505:      reading.
        !          1506: 
        !          1507:      if we still don't have a TLB entry that allows both fast reading
        !          1508:      and fast writing, we must at least have a TLB entry that allows
        !          1509:      slow reading.  at this point we do a slow read to start a locked
        !          1510:      read-modify-write cycle (unless this is a cas2, in which case we
        !          1511:      do a normal slow read).
        !          1512: 
        !          1513:      we always want to return to the caller with a TLB entry that
        !          1514:      allows writing, so after we do a slow read we do one more TLB
        !          1515:      fill for writing.
        !          1516: 
        !          1517:      the first TLB fill we do for an address will be for writing, so
        !          1518:      that is how we initialize an address' address_cycles mask: */
        !          1519:   address_cycles[0] = TME_BUS_CYCLE_WRITE;
        !          1520:   address_cycles[1] = TME_BUS_CYCLE_WRITE;
        !          1521: 
        !          1522:   /* we haven't filled TLBs for any addresses yet: */
        !          1523:   address_fills[0] = 0;
        !          1524:   address_fills[1] = 0;
        !          1525: 
        !          1526:   /* assume that we can support this instruction on the given memory: */
        !          1527:   supported = TRUE;  
        !          1528: 
        !          1529:   /* loop forever: */
        !          1530:   for (;;) {
        !          1531: 
        !          1532:     /* assume that no address needs a TLB fill: */
        !          1533:     address_i_fill = rmw->tme_m68k_rmw_address_count;
        !          1534: 
        !          1535:     /* walk the addresses: */
        !          1536:     address_i = 0;
        !          1537:     do {
        !          1538:       
        !          1539:       /* get this address: */
        !          1540:       address = rmw->tme_m68k_rmw_addresses[address_i];
        !          1541: 
        !          1542:       /* this address isn't using a TLB entry yet: */
        !          1543:       tlb_use = NULL;
        !          1544: 
        !          1545:       /* walk the TLB entries we are considering: */
        !          1546:       for (tlb_i = 0; 
        !          1547:           (tlb = tlbs_all[tlb_i]) != NULL;
        !          1548:           tlb_i++) {
        !          1549: 
        !          1550:        /* if this TLB entry isn't busy, busy it: */
        !          1551:        if (!tlbs_busy[tlb_i]) {
        !          1552:          tme_bus_tlb_busy(&tlb->tme_m68k_tlb_bus_tlb);
        !          1553:          tlbs_busy[tlb_i] = TRUE;
        !          1554:        }
        !          1555: 
        !          1556:        /* if this TLB entry is valid, applies to this function code
        !          1557:           and address, and allows at least the desired cycle(s), and
        !          1558:           either this address isn't already using a TLB entry, or the
        !          1559:           TLB entry it's using doesn't cover the entire operand, or
        !          1560:           this TLB entry allows more cycles or allows both fast
        !          1561:           reading and fast writing: */
        !          1562:        if (tme_bus_tlb_is_valid(&tlb->tme_m68k_tlb_bus_tlb)
        !          1563:            && (tlb->tme_m68k_tlb_function_codes_mask
        !          1564:                & TME_BIT(ic->_tme_m68k_ea_function_code)) != 0
        !          1565:            && address >= tlb->tme_m68k_tlb_linear_first
        !          1566:            && address <= tlb->tme_m68k_tlb_linear_last
        !          1567:            && (tlb->tme_m68k_tlb_cycles_ok
        !          1568:                & address_cycles[address_i]) != 0
        !          1569:            && (tlb_use == NULL
        !          1570:                || (tlb_use->tme_m68k_tlb_linear_last - address) < rmw->tme_m68k_rmw_size
        !          1571:                || tlb->tme_m68k_tlb_cycles_ok > tlb_use->tme_m68k_tlb_cycles_ok
        !          1572:                || (tlb->tme_m68k_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF
        !          1573:                    && tlb->tme_m68k_tlb_emulator_off_write != TME_EMULATOR_OFF_UNDEF))) {
        !          1574: 
        !          1575:          /* update the TLB entry this address is using: */
        !          1576:          tlb_use = tlb;
        !          1577:        }
        !          1578:       }
        !          1579: 
        !          1580:       /* set the TLB entry being used by this address: */
        !          1581:       rmw->tme_m68k_rmw_tlbs[address_i] = tlb_use;
1.1       root     1582: 
1.1.1.4 ! root     1583:       /* if this address is not using any TLB entry: */
        !          1584:       if (tlb_use == NULL) {
        !          1585: 
        !          1586:        /* we need to fill a TLB entry for this address: */
        !          1587:        address_i_fill = address_i;
        !          1588:       }
        !          1589: 
        !          1590:     } while (++address_i < rmw->tme_m68k_rmw_address_count);
        !          1591: 
        !          1592:     /* if we need to fill a TLB entry for an address: */
        !          1593:     address_i = address_i_fill;
        !          1594:     if (address_i < rmw->tme_m68k_rmw_address_count) {
        !          1595: 
        !          1596:       /* get this address: */
        !          1597:       address = rmw->tme_m68k_rmw_addresses[address_i];
        !          1598: 
        !          1599:       /* get an unused TLB entry to fill: */
        !          1600:       tlb_i = 0;
        !          1601:       tlb = tlbs_all[0];
        !          1602:       if (tlb == rmw->tme_m68k_rmw_tlbs[!address_i]) {
        !          1603:        tlb_i = 1;
        !          1604:        tlb = tlbs_all[1];
        !          1605:       }
        !          1606:       assert (tlb != NULL
        !          1607:              && tlb != rmw->tme_m68k_rmw_tlbs[!address_i]);
        !          1608: 
        !          1609:       /* NB: cas2 can need two TLB entries.  we may find one good TLB
        !          1610:         entry for one address, but need to call out to fill a TLB for
        !          1611:         the second address, and unfortunately we have to unbusy the
        !          1612:         good one while we're doing the fill.  while the good one is
        !          1613:         unbusy, it can be invalidated, and we'll have to fill it
        !          1614:         again, unbusying the good one we just filled, possibly
        !          1615:         leading to a vicious cycle.
        !          1616: 
        !          1617:         it's also possible that the TLB entry we fill here could be
        !          1618:         invalidated after it's been filled and before we've busied it
        !          1619:         again.  this is also the case for the single-TLB operations:
        !          1620:         normal memory reads and writes, and tas and cas, and to
        !          1621:         handle that we simply loop around the fill.  since these
        !          1622:         operations only use a single TLB entry, we assume that there
        !          1623:         won't be a vicious cycle - that eventually a single filled
        !          1624:         TLB entry will stay valid until we can busy it and use it.
        !          1625: 
        !          1626:         but we can't really guarantee this for two TLB entries.
        !          1627:         there's not much we can do about this, except put a limit on
        !          1628:         the number of times we will fill for each address.  this
        !          1629:         limit is somewhat arbitrary: */
        !          1630:       /* XXX FIXME - this should be a macro, or a per-m68k argument: */
        !          1631:       if (rmw->tme_m68k_rmw_address_count == 2
        !          1632:          && address_fills[address_i]++ >= 20) {
        !          1633: 
        !          1634:        /* we can't support this instruction on this memory: */
        !          1635:        supported = FALSE;
        !          1636:        break;
        !          1637:       }
        !          1638: 
        !          1639:       /* if the other TLB entry is busy, unbusy it: */
        !          1640:       if (tlbs_busy[!tlb_i]) {
        !          1641:        tme_bus_tlb_unbusy(&tlbs_all[tlb_i]->tme_m68k_tlb_bus_tlb);
        !          1642:        tlbs_busy[!tlb_i] = FALSE;
        !          1643:       }
        !          1644: 
        !          1645:       /* fill this TLB entry: */
        !          1646:       tme_m68k_tlb_fill(ic,
        !          1647:                        tlb,
        !          1648:                        ic->_tme_m68k_ea_function_code,
        !          1649:                        address,
        !          1650:                        address_cycles[address_i]);
        !          1651: 
        !          1652:       /* restart: */
        !          1653:       continue;
        !          1654:     }
        !          1655: 
        !          1656:     /* walk the addresses: */
        !          1657:     address_i = 0;
        !          1658:     do {
        !          1659: 
        !          1660:       /* get this address and its TLB entry: */
        !          1661:       address = rmw->tme_m68k_rmw_addresses[address_i];
        !          1662:       tlb = rmw->tme_m68k_rmw_tlbs[address_i];
        !          1663: 
        !          1664:       /* if this TLB entry doesn't cover the entire operand: */
        !          1665:       if ((tlb->tme_m68k_tlb_linear_last - address) < rmw->tme_m68k_rmw_size) {
        !          1666: 
        !          1667:        /* we can't support this instruction on this memory, because
        !          1668:           we can't split an atomic operation across TLB entries.  on
        !          1669:           a real m68k, the CPU can do repeated bus cycles under one
        !          1670:           bus lock: */
        !          1671:        supported = FALSE;
        !          1672:        break;
        !          1673:       }
        !          1674: 
        !          1675:       /* if this TLB entry supports both fast reading and fast
        !          1676:          writing: */
        !          1677:       if (tlb->tme_m68k_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF
        !          1678:          && tlb->tme_m68k_tlb_emulator_off_write != TME_EMULATOR_OFF_UNDEF) {
        !          1679: 
        !          1680:        /* if fast reading and fast writing aren't to the same memory: */
        !          1681:        if (tlb->tme_m68k_tlb_emulator_off_read
        !          1682:            != tlb->tme_m68k_tlb_emulator_off_write) {
        !          1683:          
        !          1684:          /* we can't support this instruction on this memory, because
        !          1685:             we can't split an atomic operation across two memories.
        !          1686:             on a real m68k, the CPU can do repeated bus cycles under
        !          1687:             one bus lock: */
        !          1688:          supported = FALSE;
        !          1689:          break;
        !          1690:        }
        !          1691:       }
        !          1692: 
        !          1693:       /* otherwise, this TLB entry does not support both fast reading
        !          1694:         and fast writing: */
        !          1695: 
        !          1696:       /* if we have already done a slow read for this address: */
        !          1697:       else if (rmw->tme_m68k_rmw_slow_reads[address_i]) {
        !          1698: 
        !          1699:        /* this TLB entry must support writing: */
        !          1700:        assert (tlb->tme_m68k_tlb_cycles_ok & TME_BUS_CYCLE_WRITE);
        !          1701: 
        !          1702:        /* nothing to do: */
        !          1703:       }
        !          1704: 
        !          1705:       /* otherwise, we have not already done a slow read for this
        !          1706:          address: */
        !          1707: 
        !          1708:       /* if this TLB entry doesn't support slow reading: */
        !          1709:       else if ((tlb->tme_m68k_tlb_cycles_ok & TME_BUS_CYCLE_READ) == 0) {
        !          1710: 
        !          1711:        /* we must fill a TLB entry for reading: */
        !          1712:        assert (address_cycles[address_i] == TME_BUS_CYCLE_WRITE);
        !          1713:        address_cycles[address_i] = TME_BUS_CYCLE_READ;
        !          1714: 
        !          1715:        /* restart: */
        !          1716:        break;
        !          1717:       }
        !          1718: 
        !          1719:       /* otherwise, this TLB entry does support slow reading: */
        !          1720:       else {
        !          1721: 
        !          1722:        /* if the other TLB entry is busy, unbusy it: */
        !          1723:        tlb_i = (tlb == tlbs_all[1]);
        !          1724:        if (tlbs_busy[!tlb_i]) {
        !          1725:          tme_bus_tlb_unbusy(&tlbs_all[tlb_i]->tme_m68k_tlb_bus_tlb);
        !          1726:          tlbs_busy[!tlb_i] = FALSE;
        !          1727:        }
        !          1728: 
        !          1729:        /* this instruction can fault: */
        !          1730:        TME_M68K_INSN_CANFAULT;
        !          1731: 
        !          1732:        /* do a slow read.  if this is the first address, we start a
        !          1733:           slow read-modify-write cycle, otherwise we do a normal slow
        !          1734:           read cycle: */
        !          1735:        assert (rmw->tme_m68k_rmw_size <= sizeof(ic->tme_m68k_ireg_memx32));
        !          1736:        tme_m68k_read(ic,
        !          1737:                      tlb,
        !          1738:                      &ic->_tme_m68k_ea_function_code,
        !          1739:                      &rmw->tme_m68k_rmw_addresses[address_i],
        !          1740:                      (((tme_uint8_t *) 
        !          1741:                        (address_i == 0
        !          1742:                         ? &ic->tme_m68k_ireg_memx32
        !          1743:                         : &ic->tme_m68k_ireg_memy32))
        !          1744:                       + (TME_ENDIAN_NATIVE == TME_ENDIAN_BIG
        !          1745:                          ? (sizeof(ic->tme_m68k_ireg_memx32)
        !          1746:                             - rmw->tme_m68k_rmw_size)
        !          1747:                          : 0)),
        !          1748:                      rmw->tme_m68k_rmw_size,
        !          1749:                      (address_i == 0
        !          1750:                       ? TME_M68K_BUS_CYCLE_RMW
        !          1751:                       : TME_M68K_BUS_CYCLE_NORMAL));
        !          1752: 
        !          1753:        /* we have done a slow read for this address: */
        !          1754:        rmw->tme_m68k_rmw_slow_reads[address_i] = TRUE;
        !          1755: 
        !          1756:        /* now we need a TLB entry for this address that supports writing: */
        !          1757:        address_cycles[address_i] = TME_BUS_CYCLE_WRITE;
        !          1758: 
        !          1759:        /* restart: */
        !          1760:        break;
        !          1761:       }
        !          1762: 
        !          1763:     } while (++address_i < rmw->tme_m68k_rmw_address_count);
        !          1764: 
        !          1765:     /* if this instruction is not supported or we've handled all
        !          1766:        addresses, stop now: */
        !          1767:     if (!supported
        !          1768:        || address_i >= rmw->tme_m68k_rmw_address_count) {
        !          1769:       break;
        !          1770:     }
        !          1771:   }
        !          1772: 
        !          1773:   /* unbusy any TLB entries that aren't being used: */
        !          1774:   if (tlbs_busy[0]
        !          1775:       && (!supported
        !          1776:          || (tlbs_all[0] != rmw->tme_m68k_rmw_tlbs[0]
        !          1777:              && tlbs_all[0] != rmw->tme_m68k_rmw_tlbs[1]))) {
        !          1778:     tme_bus_tlb_unbusy(&tlbs_all[0]->tme_m68k_tlb_bus_tlb);
        !          1779:   }
        !          1780:   if (tlbs_busy[1]
        !          1781:       && (!supported
        !          1782:          || (tlbs_all[1] != rmw->tme_m68k_rmw_tlbs[0]
        !          1783:              && tlbs_all[1] != rmw->tme_m68k_rmw_tlbs[1]))) {
        !          1784:     tme_bus_tlb_unbusy(&tlbs_all[1]->tme_m68k_tlb_bus_tlb);
        !          1785:   }
        !          1786: 
        !          1787:   /* if this instruction is not supported on this memory: */
        !          1788:   if (!supported) {
        !          1789: 
        !          1790:     /* cause an illegal instruction exception: */
        !          1791:     TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_ILL);
        !          1792:   }
        !          1793: 
        !          1794:   /* if this is the cas2 instruction: */
        !          1795:   if (rmw->tme_m68k_rmw_address_count == 2) {
        !          1796: 
        !          1797:     /* cas2 is a difficult instruction to emulate, since it accesses
        !          1798:        two different addresses during one atomic read-modify-write
        !          1799:        cycle.
        !          1800: 
        !          1801:        most host CPUs can't do this, so when threads are not
        !          1802:        cooperative, we're forced to suspend all other threads when
        !          1803:        running a cas2 instruction: */
        !          1804:     if (!TME_THREADS_COOPERATIVE) {
        !          1805:       tme_thread_suspend_others();
        !          1806:     }
        !          1807: 
        !          1808:     /* the cas2 functions also assume that we have read all operands
        !          1809:        into the memory buffers, which means we have to fast-read any
        !          1810:        addresses that we haven't already slow-read: */
        !          1811:     address_i = 0;
        !          1812:     do {
        !          1813: 
        !          1814:       /* skip this address if we really did slow read it: */
        !          1815:       if (rmw->tme_m68k_rmw_slow_reads[address_i]) {
        !          1816:        continue;
        !          1817:       }
        !          1818: 
        !          1819:       /* get this address and its TLB entry: */
        !          1820:       address = rmw->tme_m68k_rmw_addresses[address_i];
        !          1821:       tlb = rmw->tme_m68k_rmw_tlbs[address_i];
        !          1822: 
        !          1823:       /* this TLB entry must support fast reading and fast writing: */
        !          1824:       assert (tlb->tme_m68k_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF
        !          1825:              && tlb->tme_m68k_tlb_emulator_off_write == tlb->tme_m68k_tlb_emulator_off_read);
        !          1826: 
        !          1827:       /* do the fast read.  all other threads are suspended here, so
        !          1828:         we can do a memcpy instead of an atomic read: */
        !          1829:       assert (rmw->tme_m68k_rmw_size <= sizeof(ic->tme_m68k_ireg_memx32));
        !          1830:       buffer_reg
        !          1831:        = (address_i == 0
        !          1832:           ? &ic->tme_m68k_ireg_memx32
        !          1833:           : &ic->tme_m68k_ireg_memy32);
        !          1834:       memcpy((((tme_uint8_t *) buffer_reg)
        !          1835:              + (sizeof(ic->tme_m68k_ireg_memx32)
        !          1836:                 - rmw->tme_m68k_rmw_size)),
        !          1837:             (((tme_uint8_t *)
        !          1838:               tlb->tme_m68k_tlb_emulator_off_read)
        !          1839:              + address),
        !          1840:             rmw->tme_m68k_rmw_size);
        !          1841: 
        !          1842:       /* byteswap the value read: */
        !          1843:       *buffer_reg = tme_betoh_u32(*buffer_reg);
        !          1844:     
        !          1845:     } while (++address_i < rmw->tme_m68k_rmw_address_count);
        !          1846:   }
        !          1847: 
        !          1848:   /* return success: */
        !          1849:   return (0);
        !          1850: }
        !          1851: 
        !          1852: /* this finishes a read/modify/write cycle: */
1.1       root     1853: void
1.1.1.4 ! root     1854: tme_m68k_rmw_finish(struct tme_m68k *ic, 
        !          1855:                    struct tme_m68k_rmw *rmw,
        !          1856:                    int do_write)
1.1       root     1857: {
1.1.1.4 ! root     1858:   struct tme_m68k_tlb *tlbs_all[2];
        !          1859:   int tlbs_busy[2];
        !          1860:   struct tme_m68k_tlb *tlb;
        !          1861:   unsigned int tlb_i;
        !          1862:   unsigned int address_i;
        !          1863:   tme_uint32_t address;
        !          1864:   int supported;
        !          1865:   tme_uint32_t *buffer_reg;
        !          1866: 
        !          1867:   /* recover the tlbs_all[] array and tlbs_busy[] information: */
        !          1868:   tlbs_all[0] = rmw->tme_m68k_rmw_tlbs[0];
        !          1869:   tlbs_busy[0] = TRUE;
        !          1870:   if (rmw->tme_m68k_rmw_tlbs[1] != NULL
        !          1871:       && rmw->tme_m68k_rmw_tlbs[1] != rmw->tme_m68k_rmw_tlbs[0]) {
        !          1872:     tlbs_all[1] = rmw->tme_m68k_rmw_tlbs[1];
        !          1873:     tlbs_busy[1] = TRUE;
        !          1874:   }
        !          1875:   else {
        !          1876:     tlbs_all[1] = NULL;
        !          1877:     tlbs_busy[1] = FALSE;
        !          1878:   }
        !          1879: 
        !          1880:   /* assume that this instruction is supported: */
        !          1881:   supported = TRUE;
        !          1882: 
        !          1883:   /* loop over the addresses: */
        !          1884:   address_i = 0;
        !          1885:   do {
        !          1886: 
        !          1887:     /* get this address and TLB entry: */
        !          1888:     address = rmw->tme_m68k_rmw_addresses[address_i];
        !          1889:     tlb = rmw->tme_m68k_rmw_tlbs[address_i];
        !          1890: 
        !          1891:     /* get the buffer for this address: */
        !          1892:     buffer_reg
        !          1893:       = (address_i == 0
        !          1894:         ? &ic->tme_m68k_ireg_memx32
        !          1895:         : &ic->tme_m68k_ireg_memy32);
        !          1896: 
        !          1897:     /* if we did a slow read for this operand: */
        !          1898:     if (rmw->tme_m68k_rmw_slow_reads[address_i]) {
        !          1899: 
        !          1900:       /* if the other TLB entry is busy, unbusy it: */
        !          1901:       tlb_i = (tlb == tlbs_all[1]);
        !          1902:       if (tlbs_busy[!tlb_i]) {
        !          1903:        tme_bus_tlb_unbusy(&tlbs_all[tlb_i]->tme_m68k_tlb_bus_tlb);
        !          1904:        tlbs_busy[!tlb_i] = FALSE;
        !          1905:       }
        !          1906: 
        !          1907:       /* do the slow write for this operand: */
        !          1908:       assert (rmw->tme_m68k_rmw_size <= sizeof(ic->tme_m68k_ireg_memx32));
        !          1909:       tme_m68k_write(ic,
        !          1910:                     tlb,
        !          1911:                     &ic->_tme_m68k_ea_function_code,
        !          1912:                     &rmw->tme_m68k_rmw_addresses[address_i],
        !          1913:                     (((tme_uint8_t *) buffer_reg)
        !          1914:                      + (TME_ENDIAN_NATIVE == TME_ENDIAN_BIG
        !          1915:                         ? (sizeof(ic->tme_m68k_ireg_memx32)
        !          1916:                            - rmw->tme_m68k_rmw_size)
        !          1917:                         : 0)),
        !          1918:                     rmw->tme_m68k_rmw_size,
        !          1919:                     (address_i == 0
        !          1920:                      ? TME_M68K_BUS_CYCLE_RMW
        !          1921:                      : TME_M68K_BUS_CYCLE_NORMAL));
        !          1922: 
        !          1923:       /* if this is the cas2 instruction: */
        !          1924:       if (rmw->tme_m68k_rmw_address_count == 2) {
        !          1925: 
        !          1926:        /* if a cas2 slow write doesn't fault, it just did a slow
        !          1927:           write to device memory, which is actually bad because we
        !          1928:           can't do an atomic cas2 involving any device memory at all
        !          1929:           (we can't do the dual reads and dual writes all atomically).
        !          1930: 
        !          1931:           we tried to do the slow write anyways hoping that the slow
        !          1932:           write was really to write-protected memory that would
        !          1933:           fault, and when we would restart this address would point
        !          1934:           to fast-writable memory.
        !          1935: 
        !          1936:           unfortunately, we can't undo the slow write.  we do cause
        !          1937:           an illegal instruction exception, to make this problem
        !          1938:           visible: */
        !          1939:        supported = FALSE;
        !          1940:        break;
        !          1941:       }
        !          1942:     }
        !          1943: 
        !          1944:     /* otherwise, if this is the cas2 instruction, and we're writing: */
        !          1945:     else if (rmw->tme_m68k_rmw_address_count == 2
        !          1946:             && do_write) {
        !          1947: 
        !          1948:       /* this TLB entry must support fast reading and fast writing: */
        !          1949:       assert (tlb->tme_m68k_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF
        !          1950:              && tlb->tme_m68k_tlb_emulator_off_write == tlb->tme_m68k_tlb_emulator_off_read);
        !          1951: 
        !          1952:       /* byteswap the value to write: */
        !          1953:       *buffer_reg = tme_htobe_u32(*buffer_reg);
        !          1954: 
        !          1955:       /* do the fast write.  all other threads are suspended here, so
        !          1956:         we can do a memcpy instead of an atomic write: */
        !          1957:       assert (rmw->tme_m68k_rmw_size <= sizeof(ic->tme_m68k_ireg_memx32));
        !          1958:       memcpy((((tme_uint8_t *)
        !          1959:               tlb->tme_m68k_tlb_emulator_off_read)
        !          1960:              + address),
        !          1961:             (((tme_uint8_t *) buffer_reg)
        !          1962:              + (sizeof(ic->tme_m68k_ireg_memx32)
        !          1963:                 - rmw->tme_m68k_rmw_size)),
        !          1964:             rmw->tme_m68k_rmw_size);
        !          1965:     }
        !          1966: 
        !          1967:   } while (++address_i < rmw->tme_m68k_rmw_address_count);
        !          1968: 
        !          1969:   /* unbusy all TLB entries: */
        !          1970:   if (tlbs_busy[0]) {
        !          1971:     tme_bus_tlb_unbusy(&tlbs_all[0]->tme_m68k_tlb_bus_tlb);
        !          1972:   }
        !          1973:   if (tlbs_busy[1]) {
        !          1974:     tme_bus_tlb_unbusy(&tlbs_all[1]->tme_m68k_tlb_bus_tlb);
        !          1975:   }
        !          1976: 
        !          1977:   /* cas2 is a difficult instruction to emulate, since it accesses two
        !          1978:      different addresses during one atomic read-modify-write cycle.
        !          1979:      most host CPUs can't do this, so when threads are not
        !          1980:      cooperative, we're forced to suspend all other threads when
        !          1981:      running a cas2 instruction: */
        !          1982:   if (!TME_THREADS_COOPERATIVE
        !          1983:       && rmw->tme_m68k_rmw_address_count > 1) {
        !          1984:     tme_thread_resume_others();
        !          1985:   }
        !          1986: 
        !          1987:   /* if this instruction is not supported on this memory: */
        !          1988:   if (!supported) {
        !          1989: 
        !          1990:     /* cause an illegal instruction exception: */
        !          1991:     TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_ILL);
        !          1992:   }
1.1       root     1993: }
                   1994: 
                   1995: /* this handles a bitfield offset.  if the bitfield is in memory,
                   1996:    and it hasn't already been done, this adjusts the effective
                   1997:    address to point to the beginning of the bitfield.  this always
                   1998:    returns a nonnegative bitfield offset: */
                   1999: unsigned int
                   2000: tme_m68k_bitfield_offset(struct tme_m68k *ic, int adjust)
                   2001: {
                   2002:   tme_int16_t specop;
                   2003:   tme_int32_t bf_offset;
                   2004:   tme_int32_t bf_ea_offset;
                   2005:     
                   2006:   /* get the bitfield offset from a data register or as an immediate: */
                   2007:   specop = ic->_tme_m68k_insn_specop;
                   2008:   bf_offset = ((specop & TME_BIT(11))
                   2009:               ? ic->tme_m68k_ireg_int32(TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(specop, 6, 3))
                   2010:               : (tme_int32_t) TME_FIELD_EXTRACTU(specop, 6, 5));
                   2011: 
                   2012:   /* if this bitfield is in a register (EA mode field is zero): */
                   2013:   if (TME_FIELD_EXTRACTU(ic->_tme_m68k_insn_opcode, 3, 3) == 0) {
                   2014: 
                   2015:     /* adjust the bitfield offset to be nonnegative: */
                   2016:     bf_offset &= 31;
                   2017:   }
                   2018: 
                   2019:   /* otherwise, this bitfield is in memory: */
                   2020:   else {
                   2021: 
                   2022:     /* calculate the effective address offset and adjust the bitfield
                   2023:        offset to be nonnegative: */
1.1.1.3   root     2024:     bf_ea_offset = ((bf_offset < 0
                   2025:                     ? (bf_offset - 7)
                   2026:                     : bf_offset)
                   2027:                    / 8);
1.1       root     2028:     bf_offset &= 7;
                   2029: 
                   2030:     /* if this is our first call to this function for this instruction
                   2031:        and we're not restarting, adjust the effective address: */
                   2032:     if (adjust
                   2033:        && !TME_M68K_SEQUENCE_RESTARTING) {
                   2034:       ic->_tme_m68k_ea_address += bf_ea_offset;
                   2035:     }
                   2036:   }
                   2037: 
                   2038:   /* return the nonnegative bitfield offset: */
                   2039:   return ((unsigned int) bf_offset);
                   2040: }
                   2041: 
                   2042: /* this returns a bitfield width: */
                   2043: unsigned int
                   2044: tme_m68k_bitfield_width(struct tme_m68k *ic)
                   2045: {
                   2046:   unsigned int bf_width;
                   2047:   tme_int16_t specop;
                   2048: 
                   2049:   /* get the bitfield width from a register or as an immediate: */
                   2050:   specop = ic->_tme_m68k_insn_specop;
                   2051:   if (specop & TME_BIT(5)) {
                   2052:     bf_width = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(specop, 0, 3));
1.1.1.3   root     2053:     bf_width &= 31;
1.1       root     2054:   }
                   2055:   else {
                   2056:     bf_width = TME_FIELD_EXTRACTU(specop, 0, 5);
                   2057:   }
                   2058:   if (bf_width == 0) bf_width = 32;
                   2059:   return (bf_width);
                   2060: }
                   2061: 
                   2062: /* this reads a bitfield: */
                   2063: tme_uint32_t
                   2064: _tme_m68k_bitfield_read(struct tme_m68k *ic, int is_signed)
                   2065: {
                   2066:   unsigned int bf_offset, bf_width;
                   2067:   unsigned int shift;
                   2068:   tme_uint8_t *bf_bytes;
                   2069:   tme_uint32_t bf_value;
                   2070:   int ireg;
                   2071: 
                   2072:   /* get the bitfield offset and width: */
                   2073:   bf_offset = tme_m68k_bitfield_offset(ic, TRUE);
                   2074:   bf_width = tme_m68k_bitfield_width(ic);
                   2075: 
                   2076:   /* if this expression is > 32, in a register this means the bitfield
1.1.1.3   root     2077:      wraps, and in memory this means the bitfield covers 5 bytes: */
1.1       root     2078:   shift = (bf_offset + bf_width);
                   2079: 
                   2080:   /* if this bitfield is in a register (EA mode field is zero): */
                   2081:   if (TME_FIELD_EXTRACTU(ic->_tme_m68k_insn_opcode, 3, 3) == 0) {
                   2082:     ireg = (TME_M68K_IREG_D0
                   2083:            + TME_FIELD_EXTRACTU(ic->_tme_m68k_insn_opcode, 0, 3));
                   2084: 
                   2085:     /* get the raw 32-bit word containing the bitfield: */
                   2086:     bf_value = ic->tme_m68k_ireg_uint32(ireg);
                   2087: 
                   2088:     /* if this bitfield wraps the register, shift in the wrapped part
                   2089:        on the right: */
                   2090:     if (shift > 32) {
                   2091:       shift -= 32;
                   2092:       bf_value = (bf_value << shift) | (bf_value >> (32 - shift));
                   2093:       bf_offset -= shift;
                   2094:     }
                   2095:   }
                   2096: 
                   2097:   /* otherwise, this bitfield is in memory: */
                   2098:   else {
                   2099: 
1.1.1.3   root     2100:     /* this instruction can fault: */
                   2101:     ic->_tme_m68k_mode_flags |= TME_M68K_EXECUTION_INST_CANFAULT;
                   2102: 
1.1       root     2103:     /* read in the bytes covering the bitfield: */
                   2104:     bf_bytes = (tme_uint8_t *) &ic->tme_m68k_ireg_memx32;
1.1.1.3   root     2105:     tme_m68k_read_mem(ic, bf_bytes, (bf_offset + bf_width + 7) / 8);
1.1       root     2106: 
                   2107:     /* get the raw 32-bit word containing the bitfield: */
                   2108:     bf_value = tme_betoh_u32(ic->tme_m68k_ireg_memx32);
                   2109: 
1.1.1.3   root     2110:     /* if this bitfield covers 5 bytes, shift in the part from the fifth byte
1.1       root     2111:        (actually in memy32!) on the right: */
                   2112:     if (shift > 32) {
                   2113:       shift -= 32;
                   2114:       bf_value = (bf_value << shift) | (bf_bytes[4] >> (8 - shift));
                   2115:       bf_offset -= shift;
                   2116:     }
                   2117:   }
                   2118:   
                   2119:   /* shift the value: */
                   2120:   shift = (32 - (bf_offset + bf_width));
                   2121:   bf_value >>= shift;
                   2122: 
                   2123:   /* mask the value: */
1.1.1.3   root     2124:   bf_value &= (0xffffffffUL >> (32 - bf_width));
1.1       root     2125: 
                   2126:   /* if this is a signed value, sign-extend it: */
                   2127:   if (is_signed
                   2128:       && (bf_value & TME_BIT(bf_width - 1))) {
1.1.1.3   root     2129:     bf_value |= (0xffffffffUL << (bf_width - 1));
1.1       root     2130:   }
                   2131: 
                   2132:   /* all bitfield instructions that read the bitfield set the flags: */
                   2133:   if (!TME_M68K_SEQUENCE_RESTARTING) {
                   2134:     ic->tme_m68k_ireg_ccr = ((ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X)
                   2135:                             | ((bf_value & TME_BIT(bf_width - 1))
                   2136:                                ? TME_M68K_FLAG_N
                   2137:                                : 0)
                   2138:                             | (bf_value
                   2139:                                ? 0
                   2140:                                : TME_M68K_FLAG_Z));
                   2141:   }
                   2142: 
                   2143:   /* return the bitfield value: */
                   2144:   return (bf_value);
                   2145: }
                   2146: 
                   2147: /* this writes a bitfield to memory: */
                   2148: void
                   2149: tme_m68k_bitfield_write_unsigned(struct tme_m68k *ic, tme_uint32_t bf_value, int set_flags)
                   2150: {
                   2151:   unsigned int bf_offset, bf_width;
                   2152:   unsigned int shift;
                   2153:   tme_uint8_t *bf_bytes;
                   2154:   unsigned int count;
                   2155:   int ireg;
                   2156: 
                   2157:   /* for bitfields in memory, we want to know if the memory covering
                   2158:      the bitfield is already in our memory buffer, so we can avoid
                   2159:      reading that memory again.  all bitfield instructions set flags
                   2160:      based on a bitfield value; if set_flags is FALSE our caller
                   2161:      must have tested the old bitfield value, and so the bitfield
                   2162:      memory must be in our buffer, otherwise assume that this is our
                   2163:      first access to the bitfield memory: */
                   2164: #define first_memory set_flags
                   2165:   
                   2166:   /* get the bitfield offset and width: */
                   2167:   bf_offset = tme_m68k_bitfield_offset(ic, first_memory);
                   2168:   bf_width = tme_m68k_bitfield_width(ic);
                   2169: 
                   2170:   /* if this expression is > 32, in a register this means the bitfield
1.1.1.3   root     2171:      wraps, and in memory this means the bitfield covers 5 bytes: */
1.1       root     2172:   shift = (bf_offset + bf_width);
                   2173: 
1.1.1.3   root     2174:   /* mask the value: */
                   2175:   bf_value &= (0xffffffffUL >> (32 - bf_width));
                   2176: 
1.1       root     2177:   /* if we're supposed to, set the flags: */
                   2178:   if (set_flags
                   2179:       && !TME_M68K_SEQUENCE_RESTARTING) {
                   2180:     ic->tme_m68k_ireg_ccr = ((ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X)
                   2181:                             | ((bf_value & TME_BIT(bf_width - 1))
                   2182:                                ? TME_M68K_FLAG_N
                   2183:                                : 0)
                   2184:                             | (bf_value
                   2185:                                ? 0
                   2186:                                : TME_M68K_FLAG_Z));
                   2187:   }
                   2188: 
                   2189:   /* if this bitfield is in a register (EA mode field is zero): */
                   2190:   if (TME_FIELD_EXTRACTU(ic->_tme_m68k_insn_opcode, 3, 3) == 0) {
                   2191:     ireg = (TME_M68K_IREG_D0
                   2192:            + TME_FIELD_EXTRACTU(ic->_tme_m68k_insn_opcode, 0, 3));
                   2193:     
                   2194:     /* if this bitfield wraps the register, put the wrapped
                   2195:        part in the left: */
                   2196:     if (shift > 32) {
                   2197:       shift -= 32;
                   2198:       ic->tme_m68k_ireg_uint32(ireg) = ((ic->tme_m68k_ireg_uint32(ireg)
                   2199:                                         & (0xffffffffUL >> shift))
                   2200:                                        | (bf_value << (32 - shift)));
                   2201:       bf_value >>= shift;
                   2202:       bf_width -= shift;
                   2203:     }
                   2204:     
                   2205:     /* update the register: */
                   2206:     shift = (32 - (bf_offset + bf_width));
                   2207:     ic->tme_m68k_ireg_uint32(ireg) = ((ic->tme_m68k_ireg_uint32(ireg)
1.1.1.3   root     2208:                                       & ~((0xffffffffUL >> (32 - bf_width)) << shift))
1.1       root     2209:                                      | (bf_value << shift));
                   2210:   }
                   2211: 
                   2212:   /* otherwise, this bitfield is in memory: */
                   2213:   else {
                   2214: 
1.1.1.3   root     2215:     /* this instruction can fault: */
                   2216:     ic->_tme_m68k_mode_flags |= TME_M68K_EXECUTION_INST_CANFAULT;
                   2217: 
1.1       root     2218:     /* read in the bytes covering the bitfield if we haven't yet: */
                   2219:     bf_bytes = (tme_uint8_t *) &ic->tme_m68k_ireg_memx32;
1.1.1.3   root     2220:     count = (bf_offset + bf_width + 7) / 8;
1.1       root     2221:     if (first_memory) {
                   2222:       tme_m68k_read_mem(ic, bf_bytes, count);
                   2223:     }
                   2224: 
1.1.1.3   root     2225:     /* if this bitfield covers 5 bytes, put the part for the fifth
1.1       root     2226:        byte (actually in memy32!) in on the left: */
                   2227:     if (shift > 32) {
                   2228:       shift -= 32;
                   2229:       if (!TME_M68K_SEQUENCE_RESTARTING) {
                   2230:        bf_bytes[4] = ((bf_bytes[4]
                   2231:                        & (0xff >> shift))
                   2232:                       | ((bf_value & 0xff) << (8 - shift)));
                   2233:       }
                   2234:       bf_value >>= shift;
                   2235:       bf_width -= shift;
                   2236:     }
                   2237: 
                   2238:     /* update the memory buffer: */
                   2239:     if (!TME_M68K_SEQUENCE_RESTARTING) {
                   2240:       shift = (32 - (bf_offset + bf_width));
                   2241:       ic->tme_m68k_ireg_memx32 =
                   2242:        tme_htobe_u32((tme_betoh_u32(ic->tme_m68k_ireg_memx32)
1.1.1.3   root     2243:                       & ~((0xffffffffUL >> (32 - bf_width)) << shift))
1.1       root     2244:                      | (bf_value << shift));
                   2245:     }
                   2246: 
                   2247:     /* write out the bytes covering bitfield to memory: */
                   2248:     tme_m68k_write_mem(ic, bf_bytes, count);
                   2249:   }
                   2250: #undef first_memory
                   2251: }
                   2252: 
                   2253: /* our global verify hook function: */
1.1.1.2   root     2254: #undef tme_m68k_verify_hook
1.1       root     2255: void
                   2256: tme_m68k_verify_hook(void)
                   2257: {
                   2258: }
                   2259: 
                   2260: #if 1
                   2261: #include <stdio.h>
                   2262: 
                   2263: /* this dumps out the m68k state: */
                   2264: void
                   2265: tme_m68k_dump(struct tme_m68k *ic)
                   2266: {
                   2267:   int ireg;
                   2268:   int count;
                   2269: 
                   2270:   /* dump out the integer registers: */
                   2271:   count = 0;
                   2272:   for (ireg = TME_M68K_IREG_D0;
                   2273:        ireg <= TME_M68K_IREG_A7;
                   2274:        ireg++) {
                   2275:     fprintf(stderr,
                   2276:            "%%%c%d[%p] = 0x%08x",
                   2277:            (ireg < TME_M68K_IREG_A0
                   2278:             ? 'd'
                   2279:             : 'a'),
                   2280:            ireg - (ireg < TME_M68K_IREG_A0
                   2281:                    ? TME_M68K_IREG_D0
                   2282:                    : TME_M68K_IREG_A0),
                   2283:            &ic->tme_m68k_ireg_uint32(ireg),
                   2284:            ic->tme_m68k_ireg_uint32(ireg));
                   2285:     if (++count == 2) {
                   2286:       fprintf(stderr, "\n");
                   2287:       count = 0;
                   2288:     }
                   2289:     else {
                   2290:       fprintf(stderr, "  ");
                   2291:     }
                   2292:   }
                   2293: 
                   2294:   /* dump out the PC and next PC: */
                   2295:   fprintf(stderr, "%%pc = 0x%08x  %%pc_next = 0x%08x\n",
                   2296:          ic->tme_m68k_ireg_pc,
                   2297:          ic->tme_m68k_ireg_pc_next);
                   2298: 
                   2299:   /* dump out the status register: */
                   2300:   fprintf(stderr, "%%sr = 0x%04x", ic->tme_m68k_ireg_sr);
                   2301:   fprintf(stderr, "  flags:");
                   2302:   if (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X) {
                   2303:     fprintf(stderr, " X");
                   2304:   }
                   2305:   if (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_N) {
                   2306:     fprintf(stderr, " N");
                   2307:   }
                   2308:   if (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_Z) {
                   2309:     fprintf(stderr, " Z");
                   2310:   }
                   2311:   if (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_V) {
                   2312:     fprintf(stderr, " V");
                   2313:   }
                   2314:   if (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_C) {
                   2315:     fprintf(stderr, " C");
                   2316:   }
                   2317:   fprintf(stderr, "\n");
                   2318: 
                   2319:   /* dump out the effective address and memory buffers: */
                   2320:   fprintf(stderr, "\n");
                   2321:   fprintf(stderr, "EA = %d:0x%08x\n",
                   2322:          ic->_tme_m68k_ea_function_code,
                   2323:          ic->_tme_m68k_ea_address);
                   2324:   fprintf(stderr, "%%memx[%p] = 0x%08x  %%memy[%p] = 0x%08x\n",
                   2325:          &ic->tme_m68k_ireg_memx32,
                   2326:          ic->tme_m68k_ireg_memx32,
                   2327:          &ic->tme_m68k_ireg_memy32,
                   2328:          ic->tme_m68k_ireg_memy32);
                   2329: 
                   2330:   /* dump out the control registers: */
                   2331:   fprintf(stderr, "\n");
                   2332:   fprintf(stderr, "%%usp = 0x%08x\n", ic->tme_m68k_ireg_usp);
                   2333:   fprintf(stderr, "%%isp = 0x%08x\n", ic->tme_m68k_ireg_isp);
                   2334:   fprintf(stderr, "%%msp = 0x%08x\n", ic->tme_m68k_ireg_msp);
                   2335:   fprintf(stderr, "%%sfc = 0x%08x\n", ic->tme_m68k_ireg_sfc);
                   2336:   fprintf(stderr, "%%dfc = 0x%08x\n", ic->tme_m68k_ireg_dfc);
                   2337:   fprintf(stderr, "%%vbr = 0x%08x\n", ic->tme_m68k_ireg_vbr);
                   2338:   
                   2339:   /* dump out instruction decoding information: */
                   2340:   fprintf(stderr, "\n");
1.1.1.3   root     2341:   fprintf(stderr, "opcode = 0x%04x  specop = 0x%04x\n",
1.1       root     2342:          ic->_tme_m68k_insn_opcode,
1.1.1.3   root     2343:          ic->_tme_m68k_insn_specop);
1.1       root     2344: }
1.1.1.4 ! root     2345: 
        !          2346: void
        !          2347: tme_m68k_dump_memory(struct tme_m68k *ic, tme_uint32_t address, tme_uint32_t resid)
        !          2348: {
        !          2349:   unsigned int saved_ea_function_code;
        !          2350:   tme_uint32_t saved_ea_address;
        !          2351:   tme_uint32_t address_display;
        !          2352:   tme_uint8_t buffer[16];
        !          2353:   tme_uint32_t count;
        !          2354:   tme_uint32_t byte_i;
        !          2355: 
        !          2356:   /* save any EA function code and address: */
        !          2357:   saved_ea_function_code = ic->_tme_m68k_ea_function_code;
        !          2358:   saved_ea_address = ic->_tme_m68k_ea_address;
        !          2359: 
        !          2360:   /* we always display aligned rows: */
        !          2361:   address_display = address & (((tme_uint32_t) 0) - sizeof(buffer));
        !          2362: 
        !          2363:   /* while we have memory to dump: */
        !          2364:   for (; resid > 0; ) {
        !          2365: 
        !          2366:     /* read more data: */
        !          2367:     byte_i = address % sizeof(buffer);
        !          2368:     count = TME_MIN(resid, sizeof(buffer) - byte_i);
        !          2369:     ic->_tme_m68k_ea_function_code = TME_M68K_FUNCTION_CODE_DATA(ic);
        !          2370:     ic->_tme_m68k_ea_address = address;
        !          2371:     tme_m68k_read_mem(ic, &buffer[byte_i], count);
        !          2372:     count += byte_i;
        !          2373: 
        !          2374:     /* display the row: */
        !          2375:     fprintf(stderr, "0x%08x ", address_display);
        !          2376:     for (byte_i = 0;
        !          2377:         byte_i < count;
        !          2378:         byte_i++, address_display++) {
        !          2379:       if (address_display < address) {
        !          2380:        fprintf(stderr, "   ");
        !          2381:       }
        !          2382:       else {
        !          2383:        fprintf(stderr, " %02x",
        !          2384:                buffer[byte_i]);
        !          2385:        address++;
        !          2386:        resid--;
        !          2387:       }
        !          2388:     }
        !          2389:     fputc('\n', stderr);
        !          2390:   }
        !          2391: 
        !          2392:   /* restore any EA function code and address: */
        !          2393:   ic->_tme_m68k_ea_function_code = saved_ea_function_code;
        !          2394:   ic->_tme_m68k_ea_address = saved_ea_address;
        !          2395: }
1.1       root     2396: #endif /* 1 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.