1 /*
2 * Copyright (C) 2007-2014 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * COMMENT: Peripheral Channel Controller (PCC2) bus (used in MVME machines)
29 *
30 * See "Single Board Computers Programmer's Reference Guide (Part 2 of 2)",
31 * "VMESBCA2/PG1" (vmesbcp2.pdf) for more details.
32 *
33 * Note: This is somewhat MVME187-specific, at the moment.
34 *
35 * Implemented so far:
36 * Timers 1 and 2.
37 * The interrupt controller mechanism (partially!)
38 *
39 * TODO:
40 * All devices appart from the timers.
41 */
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46
47 #include "cpu.h"
48 #include "device.h"
49 #include "emul.h"
50 #include "interrupt.h"
51 #include "machine.h"
52 #include "memory.h"
53 #include "misc.h"
54
55 #include "thirdparty/mvme187.h"
56 #include "thirdparty/mvme_pcctworeg.h"
57
58
59 #define INTERRUPT_LEVEL_MASK 0x07
60
61 #define PCC_TIMER_TICK_HZ 100.0
62 #define DEV_PCC2_TICK_SHIFT 14
63
64
65 // #define debug fatal
66
67 struct pcc2_data {
68 struct interrupt cpu_irq;
69
70 uint8_t pcctwo_reg[PCC2_SIZE];
71
72 uint8_t cur_int_vec[8];
73
74 /* Timers: */
75 struct timer *timer;
76 int pending_timer1_interrupts;
77 int pending_timer2_interrupts;
78 };
79
80
read32(unsigned char * p)81 static uint32_t read32(unsigned char *p)
82 {
83 uint32_t x = 0;
84 size_t i;
85
86 for (i=0; i<sizeof(x); i++) {
87 x <<= 8;
88 x |= p[i];
89 }
90
91 return x;
92 }
93
94
write32(unsigned char * p,uint32_t x)95 static void write32(unsigned char *p, uint32_t x)
96 {
97 size_t i;
98
99 for (i=0; i<sizeof(x); i++) {
100 p[sizeof(x) - 1 - i] = x;
101 x >>= 8;
102 }
103 }
104
105
pcc_timer_tick(struct timer * t,void * extra)106 static void pcc_timer_tick(struct timer *t, void *extra)
107 {
108 struct pcc2_data *d = (struct pcc2_data *) extra;
109
110 /* The PCC2 timers run at 1 MHz. */
111 int steps = (int) (1000000.0 / PCC_TIMER_TICK_HZ);
112
113 uint32_t count1, count2, compare1, compare2;
114 int interrupt1 = 0, interrupt2 = 0;
115
116 /* Read values: */
117 count1 = read32(&d->pcctwo_reg[PCCTWO_T1COUNT]);
118 count2 = read32(&d->pcctwo_reg[PCCTWO_T2COUNT]);
119 compare1 = read32(&d->pcctwo_reg[PCCTWO_T1CMP]);
120 compare2 = read32(&d->pcctwo_reg[PCCTWO_T2CMP]);
121
122 /* Timer enabled? Then count... */
123 if (d->pcctwo_reg[PCCTWO_T1CTL] & PCC2_TCTL_CEN) {
124 uint32_t old_count1 = count1;
125 count1 += steps;
126
127 /* Did we pass the compare value? */
128 if ((old_count1 < compare1 && count1 >= compare1) ||
129 (old_count1 < compare1 && count1 < old_count1)) {
130 interrupt1 = 1;
131
132 if (d->pcctwo_reg[PCCTWO_T1CTL] & PCC2_TCTL_COC) {
133 while (count1 >= compare1) {
134 count1 -= compare1;
135 interrupt1 ++;
136 }
137 interrupt1 --;
138 }
139 }
140
141 /* Overflow? */
142 if ((int32_t) old_count1 >= 0 && (int32_t) count1 < 0) {
143 int oc = 1 + (d->pcctwo_reg[PCCTWO_T1CTL] >> 4);
144 d->pcctwo_reg[PCCTWO_T1CTL] &= ~PCC2_TCTL_OVF;
145 d->pcctwo_reg[PCCTWO_T1CTL] |= (oc << 4);
146 }
147 }
148
149 /* ... and the same for timer 2: */
150 if (d->pcctwo_reg[PCCTWO_T2CTL] & PCC2_TCTL_CEN) {
151 uint32_t old_count2 = count2;
152 count2 += steps;
153
154 if ((old_count2 < compare2 && count2 >= compare2) ||
155 (old_count2 < compare2 && count2 < old_count2)) {
156 interrupt2 = 1;
157 if (d->pcctwo_reg[PCCTWO_T2CTL] & PCC2_TCTL_COC) {
158 while (count2 >= compare2) {
159 count2 -= compare2;
160 interrupt2 ++;
161 }
162 interrupt2 --;
163 }
164 }
165
166 if ((int32_t) old_count2 >= 0 && (int32_t) count2 < 0) {
167 int oc = 1 + (d->pcctwo_reg[PCCTWO_T2CTL] >> 4);
168 d->pcctwo_reg[PCCTWO_T2CTL] &= ~PCC2_TCTL_OVF;
169 d->pcctwo_reg[PCCTWO_T2CTL] |= (oc << 4);
170 }
171 }
172
173 /* Should we cause interrupts? */
174 if (interrupt1 && d->pcctwo_reg[PCCTWO_T1ICR] & PCC2_TTIRQ_IEN)
175 d->pending_timer1_interrupts += interrupt1;
176 if (interrupt2 && d->pcctwo_reg[PCCTWO_T2ICR] & PCC2_TTIRQ_IEN)
177 d->pending_timer2_interrupts += interrupt2;
178
179 /* Write back values: */
180 write32(&d->pcctwo_reg[PCCTWO_T1COUNT], count1);
181 write32(&d->pcctwo_reg[PCCTWO_T2COUNT], count2);
182 }
183
184
reassert_interrupts(struct pcc2_data * d)185 static void reassert_interrupts(struct pcc2_data *d)
186 {
187 int assert = 0;
188
189 if (d->pcctwo_reg[PCCTWO_GENCTL] & PCC2_C040) {
190 /* The M68000 interrupt mechanism involves outputting
191 interrupt level on pins EIPL<2..0>. Not implemented
192 yet. */
193 fatal("pcc2: C040 interrupt assertions... TODO\n");
194 exit(1);
195 }
196
197 /*
198 * Recalculate current interrupt level:
199 */
200 d->pcctwo_reg[PCCTWO_IPL] = 0;
201
202 /* Timer interrupts? */
203 if (d->pending_timer1_interrupts > 0 &&
204 d->pcctwo_reg[PCCTWO_T1ICR] & PCC2_TTIRQ_IEN)
205 d->pcctwo_reg[PCCTWO_T1ICR] |= PCC2_TTIRQ_INT;
206 if (d->pending_timer2_interrupts > 0 &&
207 d->pcctwo_reg[PCCTWO_T2ICR] & PCC2_TTIRQ_IEN)
208 d->pcctwo_reg[PCCTWO_T2ICR] |= PCC2_TTIRQ_INT;
209
210 if (d->pcctwo_reg[PCCTWO_T1ICR] & PCC2_TTIRQ_INT) {
211 int intlevel = d->pcctwo_reg[PCCTWO_T1ICR] & PCC2_TTIRQ_IL;
212 d->cur_int_vec[intlevel] = PCC2V_TIMER1;
213 if (d->pcctwo_reg[PCCTWO_IPL] < intlevel)
214 d->pcctwo_reg[PCCTWO_IPL] = intlevel;
215 }
216 if (d->pcctwo_reg[PCCTWO_T2ICR] & PCC2_TTIRQ_INT) {
217 int intlevel = d->pcctwo_reg[PCCTWO_T2ICR] & PCC2_TTIRQ_IL;
218 d->cur_int_vec[intlevel] = PCC2V_TIMER2;
219 if (d->pcctwo_reg[PCCTWO_IPL] < intlevel)
220 d->pcctwo_reg[PCCTWO_IPL] = intlevel;
221 }
222
223 if (d->pcctwo_reg[PCCTWO_SCCTX] & PCC2_IRQ_IEN &&
224 d->pcctwo_reg[PCCTWO_SCCTX] & PCC2_IRQ_INT) {
225 int intlevel = d->pcctwo_reg[PCCTWO_SCCTX] & PCC2_IRQ_IPL;
226 d->cur_int_vec[intlevel] = PCC2V_SCC_TX;
227 if (d->pcctwo_reg[PCCTWO_IPL] < intlevel)
228 d->pcctwo_reg[PCCTWO_IPL] = intlevel;
229 }
230
231 if (d->pcctwo_reg[PCCTWO_SCCRX] & PCC2_IRQ_IEN &&
232 d->pcctwo_reg[PCCTWO_SCCRX] & PCC2_IRQ_INT) {
233 int intlevel = d->pcctwo_reg[PCCTWO_SCCRX] & PCC2_IRQ_IPL;
234 d->cur_int_vec[intlevel] = PCC2V_SCC_RX;
235 if (d->pcctwo_reg[PCCTWO_IPL] < intlevel)
236 d->pcctwo_reg[PCCTWO_IPL] = intlevel;
237 }
238
239 if (d->pcctwo_reg[PCCTWO_SCSIICR] & PCC2_IRQ_IEN &&
240 d->pcctwo_reg[PCCTWO_SCSIICR] & PCC2_IRQ_INT) {
241 int intlevel = d->pcctwo_reg[PCCTWO_SCSIICR] & PCC2_IRQ_IPL;
242 d->cur_int_vec[intlevel] = PCC2V_SCSI;
243 if (d->pcctwo_reg[PCCTWO_IPL] < intlevel)
244 d->pcctwo_reg[PCCTWO_IPL] = intlevel;
245 }
246
247 /* TODO: Other interrupt sources. */
248
249 /* Assert interrupt on the CPU if the IPL is higher than the mask: */
250 if ((d->pcctwo_reg[PCCTWO_IPL] & INTERRUPT_LEVEL_MASK) >
251 (d->pcctwo_reg[PCCTWO_MASK] & INTERRUPT_LEVEL_MASK))
252 assert = 1;
253
254 debug("[ pcc2: IPL = %i, MASK = %i => %s ]\n", d->pcctwo_reg[PCCTWO_IPL]& INTERRUPT_LEVEL_MASK,
255 d->pcctwo_reg[PCCTWO_MASK] & INTERRUPT_LEVEL_MASK,
256 assert ? "ASSERT" : "no assert");
257
258 /* ... but only allow interrupts if Master Interrupt Enable is on: */
259 if (!(d->pcctwo_reg[PCCTWO_GENCTL] & PCC2_MIEN))
260 assert = 0;
261
262 if (assert)
263 INTERRUPT_ASSERT(d->cpu_irq);
264 else
265 INTERRUPT_DEASSERT(d->cpu_irq);
266 }
267
268
pcctwo_interrupt_common(struct interrupt * interrupt,int assert)269 void pcctwo_interrupt_common(struct interrupt *interrupt, int assert)
270 {
271 struct pcc2_data *d = (struct pcc2_data *) interrupt->extra;
272
273 switch (interrupt->line) {
274
275 case PCC2V_SCSI:
276 if (assert)
277 d->pcctwo_reg[PCCTWO_SCSIICR] |= PCC2_IRQ_INT;
278 else
279 d->pcctwo_reg[PCCTWO_SCSIICR] &= ~PCC2_IRQ_INT;
280 break;
281
282 case PCC2V_SCC_TX:
283 if (assert)
284 d->pcctwo_reg[PCCTWO_SCCTX] |= PCC2_IRQ_INT;
285 else
286 d->pcctwo_reg[PCCTWO_SCCTX] &= ~PCC2_IRQ_INT;
287 break;
288
289 case PCC2V_SCC_RX:
290 if (assert)
291 d->pcctwo_reg[PCCTWO_SCCRX] |= PCC2_IRQ_INT;
292 else
293 d->pcctwo_reg[PCCTWO_SCCRX] &= ~PCC2_IRQ_INT;
294 break;
295
296 default:fatal("[ pcctwo_interrupt_common: TODO: line = %i ]\n",
297 interrupt->line);
298 exit(1);
299 }
300
301 reassert_interrupts(d);
302 }
303
304
pcctwo_interrupt_assert(struct interrupt * interrupt)305 static void pcctwo_interrupt_assert(struct interrupt *interrupt)
306 {
307 pcctwo_interrupt_common(interrupt, 1);
308 }
pcctwo_interrupt_deassert(struct interrupt * interrupt)309 static void pcctwo_interrupt_deassert(struct interrupt *interrupt)
310 {
311 pcctwo_interrupt_common(interrupt, 0);
312 }
313
314
DEVICE_TICK(pcc2)315 DEVICE_TICK(pcc2)
316 {
317 struct pcc2_data *d = (struct pcc2_data *) extra;
318 reassert_interrupts(d);
319 }
320
321
DEVICE_ACCESS(pcc2)322 DEVICE_ACCESS(pcc2)
323 {
324 uint64_t idata = 0;
325 struct pcc2_data *d = (struct pcc2_data *) extra;
326
327 /* 0xfff42000..0xfff42fff, but only 0x40 unique registers: */
328 relative_addr %= PCC2_SIZE;
329
330 if (writeflag == MEM_WRITE)
331 idata = memory_readmax64(cpu, data, len);
332
333 if (writeflag == MEM_READ)
334 memcpy(data, d->pcctwo_reg + relative_addr, len);
335
336 switch (relative_addr) {
337
338 case PCCTWO_CHIPID:
339 case PCCTWO_CHIPREV:
340 if (writeflag == MEM_WRITE) {
341 fatal("[ IGNORING write to read-only PCCTWO_CHIPID/"
342 "CHIPREV register ]\n");
343 }
344 break;
345
346 case PCCTWO_GENCTL:
347 if (len != 1) {
348 fatal("TODO: pcc2: non-byte reads and writes of "
349 "PCCTWO_GENCTL\n");
350 exit(1);
351 }
352 if (writeflag == MEM_WRITE) {
353 d->pcctwo_reg[relative_addr] = idata;
354 reassert_interrupts(d);
355 }
356 break;
357
358 case PCCTWO_VECBASE:
359 if (len != 1) {
360 fatal("TODO: pcc2: non-byte reads and writes of "
361 "PCCTWO_VECBASE\n");
362 exit(1);
363 }
364 if (writeflag == MEM_WRITE) {
365 d->pcctwo_reg[relative_addr] = idata & 0xf0;
366 if (idata & ~0xf0)
367 fatal("[ pcc2: HUH? write to PCCTWO_VECBASE"
368 " with value 0x%02x. ]\n", (int) idata);
369 }
370 break;
371
372 case PCCTWO_T1CMP:
373 case PCCTWO_T2CMP:
374 case PCCTWO_T1COUNT:
375 case PCCTWO_T2COUNT:
376 if (writeflag == MEM_WRITE)
377 memcpy(d->pcctwo_reg + relative_addr, data, len);
378 break;
379
380 case PCCTWO_PSCALEADJ:
381 if (len != 1) {
382 fatal("TODO: pcc2: non-byte reads and writes of "
383 "PCCTWO_PSCALEADJ\n");
384 exit(1);
385 }
386 if (writeflag == MEM_WRITE) {
387 fatal("[ pcc2: write to PSCALEADJ ignored (value "
388 "0x%02x) ]\n", (int)idata);
389 }
390 break;
391
392 case PCCTWO_T2CTL:
393 case PCCTWO_T1CTL:
394 if (len != 1) {
395 fatal("TODO: pcc2: non-byte reads and writes of "
396 "PCCTWO_TxCTL\n");
397 exit(1);
398 }
399 if (writeflag == MEM_WRITE) {
400 /* PCC2_TCTL_CEN and PCC2_TCTL_COC: */
401 d->pcctwo_reg[relative_addr] &= 0xfc;
402 d->pcctwo_reg[relative_addr] |= (idata & 3);
403
404 if (idata & PCC2_TCTL_COVF)
405 d->pcctwo_reg[relative_addr] &=
406 ~(PCC2_TCTL_OVF | PCC2_TCTL_COVF);
407
408 if (idata & ~7)
409 fatal("[ pcc2: HUH? write to PCCTWO_TxCTL"
410 " with value 0x%02x. ]\n", (int) idata);
411 }
412 break;
413
414 case PCCTWO_T2ICR:
415 case PCCTWO_T1ICR:
416 if (len != 1) {
417 fatal("TODO: pcc2: non-byte reads and writes of "
418 "PCCTWO_TxICR\n");
419 exit(1);
420 }
421 if (writeflag == MEM_WRITE) {
422 d->pcctwo_reg[relative_addr] &= ~0x17;
423 d->pcctwo_reg[relative_addr] |= (idata & 0x17);
424
425 if (relative_addr == PCCTWO_T1ICR &&
426 !(idata & PCC2_TTIRQ_IEN))
427 d->pending_timer1_interrupts = 0;
428 if (relative_addr == PCCTWO_T2ICR &&
429 !(idata & PCC2_TTIRQ_IEN))
430 d->pending_timer2_interrupts = 0;
431
432 if (relative_addr == PCCTWO_T1ICR && (idata & PCC2_TTIRQ_ICLR)
433 && d->pcctwo_reg[relative_addr] & PCC2_TTIRQ_INT
434 && d->pending_timer1_interrupts > 0)
435 d->pending_timer1_interrupts --;
436
437 if (relative_addr == PCCTWO_T2ICR && (idata & PCC2_TTIRQ_ICLR)
438 && d->pcctwo_reg[relative_addr] & PCC2_TTIRQ_INT
439 && d->pending_timer2_interrupts > 0)
440 d->pending_timer2_interrupts --;
441
442 if (idata & PCC2_TTIRQ_ICLR)
443 d->pcctwo_reg[relative_addr] &= ~PCC2_TTIRQ_INT;
444
445 if (idata & 0xe0)
446 fatal("[ pcc2: HUH? write to PCCTWO_TxICR"
447 " with value 0x%02x. ]\n", (int) idata);
448
449 reassert_interrupts(d);
450 }
451 break;
452
453 case PCCTWO_SCCERR:
454 if (len != 1) {
455 fatal("TODO: pcc2: non-byte reads and writes of "
456 "PCCTWO_SCCERR\n");
457 exit(1);
458 }
459 if (writeflag == MEM_WRITE)
460 d->pcctwo_reg[relative_addr] = 0; /* clear */
461 break;
462
463 case PCCTWO_SCCICR:
464 if (len != 1) {
465 fatal("TODO: pcc2: non-byte reads and writes of "
466 "PCCTWO_SCCICR\n");
467 exit(1);
468 }
469 if (writeflag == MEM_WRITE) {
470 d->pcctwo_reg[relative_addr] = idata & 0x1f;
471 if (idata & ~0x1f)
472 fatal("[ pcc2: HUH? write to PCCTWO_SCCICR"
473 " with value 0x%02x. ]\n", (int) idata);
474 reassert_interrupts(d);
475 }
476 break;
477
478 case PCCTWO_SCCTX:
479 if (len != 1) {
480 fatal("TODO: pcc2: non-byte reads and writes of "
481 "PCCTWO_SCCTX\n");
482 exit(1);
483 }
484 if (writeflag == MEM_WRITE) {
485 d->pcctwo_reg[relative_addr] = idata & 0x1f;
486 if (idata & ~0x1f)
487 fatal("[ pcc2: HUH? write to PCCTWO_SCCTX"
488 " with value 0x%02x. ]\n", (int) idata);
489 reassert_interrupts(d);
490 }
491 break;
492
493 case PCCTWO_SCCRX:
494 if (len != 1) {
495 fatal("TODO: pcc2: non-byte reads and writes of "
496 "PCCTWO_SCCRX\n");
497 exit(1);
498 }
499 if (writeflag == MEM_WRITE) {
500 d->pcctwo_reg[relative_addr] = idata & 0xdf;
501 if (idata & ~0xdf)
502 fatal("[ pcc2: HUH? write to PCCTWO_SCCRX"
503 " with value 0x%02x. ]\n", (int) idata);
504 reassert_interrupts(d);
505 }
506 break;
507
508 case PCCTWO_SCCRXIACK:
509 /* TODO. Hm. Is this enough? */
510 d->pcctwo_reg[PCCTWO_SCCRX] &= ~PCC2_IRQ_INT;
511 reassert_interrupts(d);
512 break;
513
514 case PCCTWO_SCSIICR:
515 if (len != 1) {
516 fatal("TODO: pcc2: non-byte reads and writes of "
517 "PCCTWO_SCSIICR\n");
518 exit(1);
519 }
520 if (writeflag == MEM_WRITE) {
521 d->pcctwo_reg[relative_addr] = idata & 0xdf;
522 if (idata & ~0xdf)
523 fatal("[ pcc2: HUH? write to PCCTWO_SCSIICR"
524 " with value 0x%02x. ]\n", (int) idata);
525 reassert_interrupts(d);
526 }
527 break;
528
529 case PCCTWO_IPL:
530 if (len != 1) {
531 fatal("TODO: pcc2: non-byte reads and writes of "
532 "PCCTWO_IPL\n");
533 exit(1);
534 }
535 if (writeflag == MEM_WRITE) {
536 fatal("[ pcc2: HUH? Write attempt to PCCTWO_IPL. ]\n");
537 exit(1);
538 } else {
539 if (d->pcctwo_reg[PCCTWO_IPL] == 0) {
540 fatal("pcc2: IPL == 0 on read!\n");
541 exit(1);
542 }
543 }
544 break;
545
546 case PCCTWO_MASK:
547 if (len != 1) {
548 fatal("TODO: pcc2: non-byte reads and writes of "
549 "PCCTWO_MASK\n");
550 exit(1);
551 }
552 if (writeflag == MEM_WRITE) {
553 d->pcctwo_reg[relative_addr] = idata;
554 reassert_interrupts(d);
555 }
556 break;
557
558 default:
559 debug("[ pcc2: unimplemented %s offset 0x%x",
560 writeflag == MEM_WRITE? "write to" : "read from",
561 (int) relative_addr);
562 if (writeflag == MEM_WRITE)
563 debug(": 0x%x", (int)idata);
564 debug(" ]\n");
565 exit(1);
566 }
567
568 return 1;
569 }
570
571
DEVICE_ACCESS(mvme187_iack)572 DEVICE_ACCESS(mvme187_iack)
573 {
574 uint64_t odata = 0;
575 struct pcc2_data *d = (struct pcc2_data *) extra;
576
577 if (writeflag == MEM_WRITE) {
578 fatal("[ pcc2: write to mvme187_iack? ]\n");
579 } else {
580 odata = d->pcctwo_reg[PCCTWO_VECBASE] + d->cur_int_vec[
581 (relative_addr >> 2) & INTERRUPT_LEVEL_MASK];
582 debug("[ pcc2: mvme187_iack level %i => vector 0x%02x ]\n",
583 (int)(relative_addr >> 2), (int)odata);
584
585 memory_writemax64(cpu, data, len, odata);
586 }
587
588 return 1;
589 }
590
591
DEVINIT(pcc2)592 DEVINIT(pcc2)
593 {
594 struct pcc2_data *d;
595 int i;
596
597 CHECK_ALLOCATION(d = (struct pcc2_data *) malloc(sizeof(struct pcc2_data)));
598 memset(d, 0, sizeof(struct pcc2_data));
599
600 /*
601 * Initial values, according to the manual:
602 *
603 * VECBASE is 0x0f after a reset, although the lowest four bits
604 * cannot be manually written to after startup.
605 */
606 d->pcctwo_reg[PCCTWO_CHIPID] = PCC2_ID;
607 d->pcctwo_reg[PCCTWO_CHIPREV] = 0x00;
608 d->pcctwo_reg[PCCTWO_GENCTL] = 0x00;
609 d->pcctwo_reg[PCCTWO_VECBASE] = 0x0f;
610 d->pcctwo_reg[PCCTWO_PSCALEADJ] = 256 - 33; // 256 - MHz (fake)
611
612 /* Connect to the CPU's interrupt pin: */
613 INTERRUPT_CONNECT(devinit->interrupt_path, d->cpu_irq);
614
615 /*
616 * Register the 16 PCC2 interrupt vectors:
617 */
618 for (i=0; i<16; i++) {
619 struct interrupt templ;
620 char n[300];
621 snprintf(n, sizeof(n), "%s.pcc2.%i",
622 devinit->interrupt_path, i);
623
624 memset(&templ, 0, sizeof(templ));
625 templ.line = i;
626 templ.name = n;
627 templ.extra = d;
628 templ.interrupt_assert = pcctwo_interrupt_assert;
629 templ.interrupt_deassert = pcctwo_interrupt_deassert;
630
631 interrupt_handler_register(&templ);
632 }
633
634 memory_device_register(devinit->machine->memory, "pcc2",
635 devinit->addr, 4096, dev_pcc2_access, (void *)d,
636 DM_DEFAULT, NULL);
637
638 memory_device_register(devinit->machine->memory, "mvme187_iack",
639 M187_IACK, 32, dev_mvme187_iack_access, (void *)d,
640 DM_DEFAULT, NULL);
641
642 d->timer = timer_add(PCC_TIMER_TICK_HZ, pcc_timer_tick, d);
643
644 machine_add_tickfunction(devinit->machine,
645 dev_pcc2_tick, d, DEV_PCC2_TICK_SHIFT);
646
647 return 1;
648 }
649
650