|
|
1.1 root 1: /* $Id: sun3-control.c,v 1.2 2005/02/18 03:58:07 fredette Exp $ */
2:
3: /* machine/sun3/sun3-control.c - implementation of Sun 3 emulation control space: */
4:
5: /*
6: * Copyright (c) 2003, 2004 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: sun3-control.c,v 1.2 2005/02/18 03:58:07 fredette Exp $");
38:
39: /* includes: */
40: #include "sun3-impl.h"
41:
42: /* the bus cycle handler for function code three space: */
43: int
44: _tme_sun3_control_cycle_handler(void *_sun3, struct tme_bus_cycle *cycle_init)
45: {
46: struct tme_sun3 *sun3;
47: struct tme_bus_cycle cycle_resp;
48: tme_uint32_t address, reg;
49: tme_uint8_t port_data[sizeof(tme_uint32_t)];
50: tme_uint8_t *port_data8;
51: tme_uint32_t *port_data32;
52: tme_uint32_t value32;
53: tme_uint8_t enable_old, enable_new;
54: int rc;
55:
56: /* recover our sun3: */
57: sun3 = (struct tme_sun3 *) _sun3;
58:
59: /* get the address, convert it into a register number, then mask
60: the address: */
61: address = cycle_init->tme_bus_cycle_address;
62: reg = TME_SUN3_CONTROL_REG(address);
63: if (reg != TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_IDPROM)) {
64: address &= TME_SUN3_CONTROL_MASK_ADDRESS;
65: }
66:
67: /* dispatch on the register, to get bytes for our port: */
68: port_data8 = &port_data[0];
69: port_data32 = (tme_uint32_t *) &port_data[0];
70: switch (reg) {
71:
72: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_IDPROM):
73: memcpy(port_data,
74: &sun3->tme_sun3_idprom_contents[(address & (TME_SUN_IDPROM_SIZE - 1))],
75: TME_MIN(sizeof(port_data),
76: TME_SUN_IDPROM_SIZE - (address & (TME_SUN_IDPROM_SIZE - 1))));
77: break;
78:
79: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_PGMAP):
80: rc = _tme_sun3_mmu_pte_get(sun3, address, &value32);
81: assert(rc == TME_OK);
82: *port_data32 = tme_htobe_u32(value32);
83: break;
84:
85: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_SEGMAP):
86: *port_data8 = tme_sun_mmu_segmap_get(sun3->tme_sun3_mmu, sun3->tme_sun3_context, address);
87: break;
88:
89: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_CONTEXT):
90: *port_data8 = sun3->tme_sun3_context;
91: break;
92:
93: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_ENABLE):
94: *port_data8 = sun3->tme_sun3_enable;
95: break;
96:
97: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_UDVMA):
98: *port_data8 = sun3->tme_sun3_udvma;
99: break;
100:
101: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_BUSERR):
102: *port_data8 = sun3->tme_sun3_buserr;
103: break;
104:
105: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_DIAG):
106: *port_data8 = sun3->tme_sun3_diag;
107: break;
108:
109: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_VAC_TAGS):
110: abort();
111: break;
112:
113: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_VAC_DATA):
114: abort();
115: break;
116:
117: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_VAC_FLUSH):
118: abort();
119: break;
120:
121: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_COPY):
122: abort();
123: break;
124:
125: default:
126: abort();
127: }
128:
129: /* run the bus cycle: */
130: cycle_resp.tme_bus_cycle_buffer = &port_data[0];
131: cycle_resp.tme_bus_cycle_buffer_increment = 1;
132: cycle_resp.tme_bus_cycle_lane_routing = cycle_init->tme_bus_cycle_lane_routing;
133: cycle_resp.tme_bus_cycle_address = 0;
134: cycle_resp.tme_bus_cycle_type = (cycle_init->tme_bus_cycle_type
135: ^ (TME_BUS_CYCLE_WRITE
136: | TME_BUS_CYCLE_READ));
137: cycle_resp.tme_bus_cycle_port = TME_BUS_CYCLE_PORT(0, TME_BUS32_LOG2);
138: tme_bus_cycle_xfer(cycle_init, &cycle_resp);
139:
140: /* whenever the bus error register is read or written, it is
141: cleared: */
142: if (reg == TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_BUSERR)) {
143: sun3->tme_sun3_buserr = 0;
144: }
145:
146: /* these registers only need action taken when they're written: */
147: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
148:
149: /* dispatch on the register: */
150: switch (reg) {
151:
152: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_PGMAP):
153: value32 = tme_betoh_u32(*port_data32);
154: rc = _tme_sun3_mmu_pte_set(sun3, address, value32);
155: assert (rc == TME_OK);
156: break;
157:
158: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_SEGMAP):
159: tme_sun_mmu_segmap_set(sun3->tme_sun3_mmu, sun3->tme_sun3_context, address, *port_data8 % TME_SUN3_PMEGS);
160: break;
161:
162: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_CONTEXT):
163: sun3->tme_sun3_context = *port_data8;
164: _tme_sun3_mmu_context_set(sun3);
165: break;
166:
167: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_ENABLE):
168: enable_old = sun3->tme_sun3_enable;
169: enable_new = (enable_old & TME_SUN3_ENA_DIAG) | (*port_data8 & ~TME_SUN3_ENA_DIAG);
170: sun3->tme_sun3_enable = enable_new;
171:
172: /* if we're changing to or from boot state, make a pseudo-context change: */
173: if ((enable_old ^ enable_new) & TME_SUN3_ENA_NOTBOOT) {
174: _tme_sun3_mmu_context_set(sun3);
175: }
176:
177: /* if we're changing the m6888x enable bit, call out the change: */
178: if ((enable_old ^ enable_new) & TME_SUN3_ENA_FPP) {
179: rc = ((*sun3->tme_sun3_m68k->tme_m68k_bus_m6888x_enable)
180: (sun3->tme_sun3_m68k, (enable_new & TME_SUN3_ENA_FPP)));
181: assert (rc == TME_OK);
182: }
183:
184: /* if we're enabling or disabling system DVMA, call out the change: */
185: if ((enable_old ^ enable_new) & TME_SUN3_ENA_SDVMA) {
186: _tme_sun3_mmu_sdvma_change(sun3);
187: }
188:
189: /* certain things can't be enabled: */
190: if (enable_new
191: & (TME_SUN3_ENA_COPY
192: | TME_SUN3_ENA_CACHE)) {
193: abort();
194: }
195: break;
196:
197: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_UDVMA):
198: if (sun3->tme_sun3_enable & TME_SUN3_ENA_NOTBOOT) {
199: abort();
200: }
201: sun3->tme_sun3_udvma = *port_data8;
202: break;
203:
204: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_DIAG):
205: sun3->tme_sun3_diag = *port_data8;
206: /* TBD */
207: break;
208:
209: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_VAC_TAGS):
210: abort();
211: break;
212:
213: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_VAC_DATA):
214: abort();
215: break;
216:
217: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_VAC_FLUSH):
218: abort();
219: break;
220:
221: case TME_SUN3_CONTROL_REG(TME_SUN3_CONTROL_COPY):
222: abort();
223: break;
224: }
225: }
226:
227: return (TME_OK);
228: }
229:
230: /* the bus cycle handler for the interrupt register: */
231: int
232: _tme_sun3_intreg_cycle_handler(void *_sun3, struct tme_bus_cycle *cycle_init)
233: {
234: struct tme_sun3 *sun3;
235: int rc;
236:
237: /* recover our sun3: */
238: sun3 = (struct tme_sun3 *) _sun3;
239:
240: /* do the transfer: */
241: tme_bus_cycle_xfer_memory(cycle_init,
242: &sun3->tme_sun3_ints,
243: sizeof(sun3->tme_sun3_ints) - 1);
244:
245: /* if the interrupt register has been written: */
246: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
247: rc = _tme_sun3_ipl_check(sun3);
248: assert(rc == TME_OK);
249: }
250:
251: return (TME_OK);
252: }
253:
254: /* this calls out a memory error interrupt change: */
255: static void
256: _tme_sun3_memerr_callout(struct tme_sun3 *sun3)
257: {
258: unsigned int int_asserted;
259: struct tme_bus_connection *conn_bus;
260: int rc;
261:
262: /* see if the memory error interrupt should be asserted: */
263: int_asserted
264: = ((sun3->tme_sun3_memerr_csr
265: & (TME_SUN3_MEMERR_X_INT_ACTIVE
266: | TME_SUN3_MEMERR_X_ENABLE_INT))
267: == (TME_SUN3_MEMERR_X_INT_ACTIVE
268: | TME_SUN3_MEMERR_X_ENABLE_INT));
269:
270: /* if we need to call out an interrupt change: */
271: if (!int_asserted != !sun3->tme_sun3_memerr_int_asserted) {
272:
273: /* get our bus connection: */
274: conn_bus = sun3->tme_sun3_memerr_bus;
275:
276: /* call out the bus interrupt signal edge: */
277: rc = (*conn_bus->tme_bus_signal)
278: (conn_bus,
279: TME_BUS_SIGNAL_INT_UNSPEC
280: | (int_asserted
281: ? TME_BUS_SIGNAL_LEVEL_ASSERTED
282: : TME_BUS_SIGNAL_LEVEL_NEGATED));
283:
284: /* if this callout was successful, note the new state of the
285: interrupt signal: */
286: if (rc == TME_OK) {
287: sun3->tme_sun3_memerr_int_asserted = int_asserted;
288: }
289:
290: /* otherwise, abort: */
291: else {
292: abort();
293: }
294: }
295: }
296:
297: /* the bus cycle handler for the memory error register: */
298: int
299: _tme_sun3_memerr_cycle_handler(void *_sun3, struct tme_bus_cycle *cycle_init)
300: {
301: struct tme_sun3 *sun3;
302: tme_uint8_t memerr_reg[TME_SUN3_MEMERR_SIZ_REG];
303: int write_csr, unlatch;
304: tme_uint8_t csr_old, csr_new;
305:
306: /* the read-only bits: */
307: #define TME_SUN3_MEMERR_RO (TME_SUN3_MEMERR_X_INT_ACTIVE \
308: | TME_SUN3_MEMERR_PAR_ERR_BL3 \
309: | TME_SUN3_MEMERR_PAR_ERR_BL2 \
310: | TME_SUN3_MEMERR_PAR_ERR_BL1 \
311: | TME_SUN3_MEMERR_PAR_ERR_BL0)
312:
313: /* recover our sun3: */
314: sun3 = (struct tme_sun3 *) _sun3;
315:
316: /* fill the memory error register: */
317: memerr_reg[TME_SUN3_MEMERR_REG_CSR] = sun3->tme_sun3_memerr_csr;
318: *((tme_uint32_t *) &memerr_reg[TME_SUN3_MEMERR_SIZ_VADDR]) = tme_htobe_u32(sun3->tme_sun3_memerr_vaddr);
319:
320: /* assume this cycle won't write the CSR or unlatch the register: */
321: write_csr = FALSE;
322: unlatch = FALSE;
323:
324: /* if this is a write: */
325: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
326:
327: /* see if this writes the CSR: */
328: write_csr = TME_RANGES_OVERLAP(cycle_init->tme_bus_cycle_address,
329: (cycle_init->tme_bus_cycle_address
330: + cycle_init->tme_bus_cycle_size
331: - 1),
332: TME_SUN3_MEMERR_REG_CSR,
333: (TME_SUN3_MEMERR_REG_CSR
334: + TME_SUN3_MEMERR_SIZ_CSR
335: - 1));
336:
337: /* see if this write unlatches the register: */
338: unlatch = TME_RANGES_OVERLAP(cycle_init->tme_bus_cycle_address,
339: (cycle_init->tme_bus_cycle_address
340: + cycle_init->tme_bus_cycle_size
341: - 1),
342: TME_SUN3_MEMERR_REG_VADDR,
343: TME_SUN3_MEMERR_REG_VADDR);
344: }
345:
346: /* do the transfer: */
347: tme_bus_cycle_xfer_memory(cycle_init,
348: memerr_reg,
349: sizeof(memerr_reg) - 1);
350:
351: /* if this is a write: */
352: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
353:
354: /* get the old CSR value, and assume that the new CSR value is the
355: same: */
356: csr_old = sun3->tme_sun3_memerr_csr;
357: csr_new = csr_old;
358:
359: /* if the CSR register has been written: */
360: if (write_csr) {
361:
362: /* get the new CSR value, but preserve the read-only bits: */
363: csr_new = ((csr_new & TME_SUN3_MEMERR_RO)
364: | (memerr_reg[TME_SUN3_MEMERR_REG_CSR] & ~TME_SUN3_MEMERR_RO));
365: }
366:
367: /* if the memory error register has been unlatched: */
368: if (unlatch) {
369:
370: /* clear the memory error: */
371: csr_new &= ~TME_SUN3_MEMERR_RO;
372: sun3->tme_sun3_memerr_vaddr = 0;
373: }
374:
375: /* if the CSR register has changed: */
376: if (csr_new != csr_old) {
377:
378: /* set the new CSR value and call out an interrupt change: */
379: sun3->tme_sun3_memerr_csr = csr_new;
380: _tme_sun3_memerr_callout(sun3);
381:
382: /* if the memory error register is being tested: */
383: if (csr_new & TME_SUN3_MEMERR_PAR_TEST) {
384:
385: /* if the test is just beginning, invalidate all TLB entries: */
386: if (!(csr_old & TME_SUN3_MEMERR_PAR_TEST)) {
387: tme_sun_mmu_tlbs_invalidate(sun3->tme_sun3_mmu);
388: }
389: }
390: }
391: }
392:
393: return (TME_OK);
394: }
395:
396: /* the bus cycle handler for the memory error register test: */
397: int
398: _tme_sun3_memerr_test_cycle_handler(void *_sun3, struct tme_bus_cycle *cycle_init)
399: {
400: struct tme_sun3 *sun3;
401: struct tme_bus_tlb *tlb;
402: tme_uint32_t vaddr, cycle_align;
403: tme_uint8_t csr;
404: int rc;
405:
406: /* recover our sun3: */
407: sun3 = (struct tme_sun3 *) _sun3;
408:
409: /* get the memory error test TLB entry: */
410: tlb = sun3->tme_sun3_memerr_tlb;
411: if (tlb == NULL) {
412: abort();
413: }
414:
415: /* recover the virtual address from the TLB entry. this TLB entry
416: should be for normal memory, which means it should have no shift: */
417: if (tlb->tme_bus_tlb_addr_shift != 0) {
418: abort();
419: }
420: vaddr = (cycle_init->tme_bus_cycle_address
421: - tlb->tme_bus_tlb_addr_offset);
422:
423: /* calculate the number of bytes after the last byte of the cycle
424: until the next 32-bit boundary. this bus cycle must not cross a
425: 32-bit boundary: */
426: cycle_align = ((vaddr & (sizeof(tme_uint32_t) - 1))
427: + cycle_init->tme_bus_cycle_size);
428: if (cycle_align > sizeof(tme_uint32_t)) {
429: abort();
430: }
431: cycle_align = sizeof(tme_uint32_t) - cycle_align;
432:
433: /* make the pending csr value. this calculates a mask of
434: TME_SUN3_MEMERR_PAR_ERR_BLx bits corresponding to the byte lanes
435: being read or written in this cycle: */
436: csr = (1 << cycle_init->tme_bus_cycle_size) - 1;
437: csr <<= cycle_align;
438:
439: /* if this cycle is a read: */
440: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ) {
441:
442: /* parity checking must be enabled and there must be no memory
443: error pending: */
444: if ((sun3->tme_sun3_memerr_csr
445: & (TME_SUN3_MEMERR_X_INT_ACTIVE
446: | TME_SUN3_MEMERR_PAR_ENABLE))
447: != TME_SUN3_MEMERR_PAR_ENABLE) {
448: abort();
449: }
450:
451: /* this must be a read of the written address: */
452: if ((sun3->tme_sun3_memerr_pending_csr & csr) == 0
453: || ((sun3->tme_sun3_memerr_pending_vaddr ^ vaddr) & -sizeof(tme_uint32_t)) != 0) {
454: abort();
455: }
456:
457: /* do the read: */
458: rc = ((*sun3->tme_sun3_memerr_cycle)
459: (sun3->tme_sun3_memerr_cycle_private,
460: cycle_init));
461:
462: /* set the memory error control register: */
463: sun3->tme_sun3_memerr_csr
464: = ((sun3->tme_sun3_memerr_csr
465: & ~TME_SUN3_MEMERR_RO)
466: | TME_SUN3_MEMERR_X_INT_ACTIVE
467: | (sun3->tme_sun3_memerr_pending_csr & csr));
468:
469: /* set the memory error address register: */
470: sun3->tme_sun3_memerr_vaddr
471: = ((sun3->tme_sun3_context << 28)
472: | vaddr);
473:
474: /* call out an interrupt: */
475: _tme_sun3_memerr_callout(sun3);
476:
477: /* invalidate the memory test TLB entry: */
478: tme_bus_tlb_invalidate(tlb);
479: sun3->tme_sun3_memerr_tlb = NULL;
480:
481: /* tell the CPU that a synchronous event of some kind has happened
482: on the bus: */
483: return (rc == TME_OK
484: ? TME_BUS_CYCLE_SYNCHRONOUS_EVENT
485: : rc);
486: }
487:
488: /* otherwise, this must be a write: */
489: if (cycle_init->tme_bus_cycle_type != TME_BUS_CYCLE_WRITE) {
490: abort();
491: }
492:
493: /* this must be the first write: */
494: if (sun3->tme_sun3_memerr_pending_csr != 0) {
495: abort();
496: }
497:
498: /* remember the pending memory error address and CSR value: */
499: sun3->tme_sun3_memerr_pending_csr = csr;
500: sun3->tme_sun3_memerr_pending_vaddr = vaddr;
501:
502: /* run the cycle normally: */
503: return ((*sun3->tme_sun3_memerr_cycle)
504: (sun3->tme_sun3_memerr_cycle_private,
505: cycle_init));
506:
507: #undef TME_SUN3_MEMERR_RO
508: }
509:
510: #if 1
511: #include <stdio.h>
512:
513: /* this dumps out the sun3 state: */
514: void
515: tme_sun3_dump(struct tme_sun3 *sun3)
516: {
517:
518: /* dump out the page map register: */
519: fprintf(stderr, "CONTEXT = 0x%02x\n", sun3->tme_sun3_context);
520: fprintf(stderr, "\n");
521: fprintf(stderr, "DIAG = 0x%02x\n", sun3->tme_sun3_diag);
522: fprintf(stderr, "UDVMA = 0x%02x\n", sun3->tme_sun3_udvma);
523: fprintf(stderr, "BUSERR = 0x%04x\n", sun3->tme_sun3_buserr);
524: fprintf(stderr, "ENABLE = 0x%02x\n", sun3->tme_sun3_enable);
525: fprintf(stderr, "INTS = 0x%02x\n", sun3->tme_sun3_ints);
526: fprintf(stderr, "MEMERR = 0x%02x 0x%04x\n", sun3->tme_sun3_memerr_csr, sun3->tme_sun3_memerr_vaddr);
527: }
528: #endif /* 1 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.