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