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