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