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