/[gxemul]/upstream/0.4.6/src/devices/dev_vr41xx.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/0.4.6/src/devices/dev_vr41xx.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 43 - (show annotations)
Mon Oct 8 16:22:43 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 22066 byte(s)
0.4.6
1 /*
2 * Copyright (C) 2004-2007 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 * $Id: dev_vr41xx.c,v 1.46 2007/06/15 19:57:34 debug Exp $
29 *
30 * COMMENT: VR41xx (VR4122 and VR4131) misc functions
31 *
32 * This is just a big hack.
33 *
34 * TODO: Implement more functionality some day.
35 */
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include "console.h"
42 #include "cpu.h"
43 #include "device.h"
44 #include "devices.h"
45 #include "interrupt.h"
46 #include "machine.h"
47 #include "memory.h"
48 #include "misc.h"
49 #include "timer.h"
50
51 #include "bcureg.h"
52 #include "vripreg.h"
53 #include "vrkiureg.h"
54 #include "vr_rtcreg.h"
55
56
57 /* #define debug fatal */
58
59 #define DEV_VR41XX_TICKSHIFT 14
60
61 #define DEV_VR41XX_LENGTH 0x800 /* TODO? */
62 struct vr41xx_data {
63 struct interrupt cpu_irq; /* Connected to MIPS irq 2 */
64 int cpumodel; /* Model nr, e.g. 4121 */
65
66 /* KIU: */
67 int kiu_console_handle;
68 uint32_t kiu_offset;
69 struct interrupt kiu_irq;
70 int kiu_int_assert;
71 int old_kiu_int_assert;
72
73 int d0, d1, d2, d3, d4, d5;
74 int dont_clear_next;
75 int escape_state;
76
77 /* Timer: */
78 int pending_timer_interrupts;
79 struct interrupt timer_irq;
80 struct timer *timer;
81
82 /* See icureg.h in NetBSD for more info. */
83 uint16_t sysint1;
84 uint16_t msysint1;
85 uint16_t giuint;
86 uint16_t giumask;
87 uint16_t sysint2;
88 uint16_t msysint2;
89 struct interrupt giu_irq;
90 };
91
92
93 /*
94 * vr41xx_vrip_interrupt_assert():
95 * vr41xx_vrip_interrupt_deassert():
96 */
97 void vr41xx_vrip_interrupt_assert(struct interrupt *interrupt)
98 {
99 struct vr41xx_data *d = interrupt->extra;
100 int line = interrupt->line;
101 if (line < 16)
102 d->sysint1 |= (1 << line);
103 else
104 d->sysint2 |= (1 << (line-16));
105 if ((d->sysint1 & d->msysint1) | (d->sysint2 & d->msysint2))
106 INTERRUPT_ASSERT(d->cpu_irq);
107 }
108 void vr41xx_vrip_interrupt_deassert(struct interrupt *interrupt)
109 {
110 struct vr41xx_data *d = interrupt->extra;
111 int line = interrupt->line;
112 if (line < 16)
113 d->sysint1 &= ~(1 << line);
114 else
115 d->sysint2 &= ~(1 << (line-16));
116 if (!(d->sysint1 & d->msysint1) && !(d->sysint2 & d->msysint2))
117 INTERRUPT_DEASSERT(d->cpu_irq);
118 }
119
120
121 /*
122 * vr41xx_giu_interrupt_assert():
123 * vr41xx_giu_interrupt_deassert():
124 */
125 void vr41xx_giu_interrupt_assert(struct interrupt *interrupt)
126 {
127 struct vr41xx_data *d = interrupt->extra;
128 int line = interrupt->line;
129 d->giuint |= (1 << line);
130 if (d->giuint & d->giumask)
131 INTERRUPT_ASSERT(d->giu_irq);
132 }
133 void vr41xx_giu_interrupt_deassert(struct interrupt *interrupt)
134 {
135 struct vr41xx_data *d = interrupt->extra;
136 int line = interrupt->line;
137 d->giuint &= ~(1 << line);
138 if (!(d->giuint & d->giumask))
139 INTERRUPT_DEASSERT(d->giu_irq);
140 }
141
142
143 static void recalc_kiu_int_assert(struct cpu *cpu, struct vr41xx_data *d)
144 {
145 if (d->kiu_int_assert != d->old_kiu_int_assert) {
146 d->old_kiu_int_assert = d->kiu_int_assert;
147 if (d->kiu_int_assert != 0)
148 INTERRUPT_ASSERT(d->kiu_irq);
149 else
150 INTERRUPT_DEASSERT(d->kiu_irq);
151 }
152 }
153
154
155 /*
156 * vr41xx_keytick():
157 */
158 static void vr41xx_keytick(struct cpu *cpu, struct vr41xx_data *d)
159 {
160 int keychange = 0;
161
162 /*
163 * Keyboard input:
164 *
165 * Hardcoded for MobilePro. (See NetBSD's hpckbdkeymap.h for
166 * info on other keyboard layouts. mobilepro780_keytrans is the
167 * one used here.)
168 *
169 * TODO: Make this work with "any" keyboard layout.
170 *
171 * ofs 0:
172 * 8000='o' 4000='.' 2000=DOWN 1000=UP
173 * 800=';' 400=''' 200='[' 100=?
174 * 80='l' 40=CR 20=RIGHT 10=LEFT
175 * 8='/' 4='\' 2=']' 1=SPACE
176 * ofs 2:
177 * 8000='a' 4000='s' 2000='d' 1000='f'
178 * 800='`' 400='-' 200='=' 100=?
179 * 80='z' 40='x' 20='c' 10='v'
180 * 8=? 4=? 2=?
181 * ofs 4:
182 * 8000='9' 4000='0' 2000=? 1000=?
183 * 800='b' 400='n' 200='m' 100=','
184 * 80='q' 40='w' 20='e' 10='r'
185 * 8='5' 4='6' 2='7' 1='8'
186 * ofs 6:
187 * 8000=ESC 4000=DEL 2000=CAPS 1000=?
188 * 800='t' 400='y' 200='u' 100='i'
189 * 80='1' 40='2' 20='3' 10='4'
190 * 8='g' 4='h' 2='j' 1='k'
191 * ofs 8:
192 * 200=ALT_L
193 * 80= 40=TAB 20='p' 10=BS
194 * 8= 4= 2= 1=ALT_R
195 * ofs a:
196 * 800=SHIFT 4=CTRL
197 *
198 *
199 * The following are for the IBM WorkPad Z50:
200 * (Not yet implemented, TODO)
201 *
202 * 00 f1 f3 f5 f7 f9 - - f11
203 * 08 f2 f4 f6 f8 f10 - - f12
204 * 10 ' [ - 0 p ; up /
205 * 18 - - - 9 o l . -
206 * 20 left ] = 8 i k , -
207 * 28 h y 6 7 u j m n
208 * 30 - bs num del - \ ent sp
209 * 38 g t 5 4 r f v b
210 * 40 - - - 3 e d c right
211 * 48 - - - 2 w s x down
212 * 50 esc tab ~ 1 q a z -
213 * 58 menu Ls Lc Rc La Ra Rs -
214 */
215
216 if (d->d0 != 0 || d->d1 != 0 || d->d2 != 0 ||
217 d->d3 != 0 || d->d4 != 0 || d->d5 != 0)
218 keychange = 1;
219
220 /* Release all keys: */
221 if (!d->dont_clear_next) {
222 d->d0 = d->d1 = d->d2 = d->d3 = d->d4 = d->d5 = 0;
223 } else
224 d->dont_clear_next = 0;
225
226 if (console_charavail(d->kiu_console_handle)) {
227 char ch = console_readchar(d->kiu_console_handle);
228
229 if (d->escape_state > 0) {
230 switch (d->escape_state) {
231 case 1: /* expecting a [ */
232 d->escape_state = 0;
233 if (ch == '[')
234 d->escape_state = 2;
235 break;
236 case 2: /* cursor keys etc: */
237 /* Ugly hack for Mobilepro770: */
238 if (cpu->machine->machine_subtype ==
239 MACHINE_HPCMIPS_NEC_MOBILEPRO_770) {
240 switch (ch) {
241 case 'A': d->d0 = 0x2000; break;
242 case 'B': d->d0 = 0x20; break;
243 case 'C': d->d0 = 0x1000; break;
244 case 'D': d->d0 = 0x10; break;
245 default: fatal("[ vr41xx kiu: unimpl"
246 "emented escape 0x%02 ]\n", ch);
247 }
248 } else {
249 switch (ch) {
250 case 'A': d->d0 = 0x1000; break;
251 case 'B': d->d0 = 0x2000; break;
252 case 'C': d->d0 = 0x20; break;
253 case 'D': d->d0 = 0x10; break;
254 default: fatal("[ vr41xx kiu: unimpl"
255 "emented escape 0x%02 ]\n", ch);
256 }
257 }
258 d->escape_state = 0;
259 }
260 } else switch (ch) {
261 case '+': console_makeavail(d->kiu_console_handle, '=');
262 d->d5 = 0x800; break;
263 case '_': console_makeavail(d->kiu_console_handle, '-');
264 d->d5 = 0x800; break;
265 case '<': console_makeavail(d->kiu_console_handle, ',');
266 d->d5 = 0x800; break;
267 case '>': console_makeavail(d->kiu_console_handle, '.');
268 d->d5 = 0x800; break;
269 case '{': console_makeavail(d->kiu_console_handle, '[');
270 d->d5 = 0x800; break;
271 case '}': console_makeavail(d->kiu_console_handle, ']');
272 d->d5 = 0x800; break;
273 case ':': console_makeavail(d->kiu_console_handle, ';');
274 d->d5 = 0x800; break;
275 case '"': console_makeavail(d->kiu_console_handle, '\'');
276 d->d5 = 0x800; break;
277 case '|': console_makeavail(d->kiu_console_handle, '\\');
278 d->d5 = 0x800; break;
279 case '?': console_makeavail(d->kiu_console_handle, '/');
280 d->d5 = 0x800; break;
281
282 case '!': console_makeavail(d->kiu_console_handle, '1');
283 d->d5 = 0x800; break;
284 case '@': console_makeavail(d->kiu_console_handle, '2');
285 d->d5 = 0x800; break;
286 case '#': console_makeavail(d->kiu_console_handle, '3');
287 d->d5 = 0x800; break;
288 case '$': console_makeavail(d->kiu_console_handle, '4');
289 d->d5 = 0x800; break;
290 case '%': console_makeavail(d->kiu_console_handle, '5');
291 d->d5 = 0x800; break;
292 case '^': console_makeavail(d->kiu_console_handle, '6');
293 d->d5 = 0x800; break;
294 case '&': console_makeavail(d->kiu_console_handle, '7');
295 d->d5 = 0x800; break;
296 case '*': console_makeavail(d->kiu_console_handle, '8');
297 d->d5 = 0x800; break;
298 case '(': console_makeavail(d->kiu_console_handle, '9');
299 d->d5 = 0x800; break;
300 case ')': console_makeavail(d->kiu_console_handle, '0');
301 d->d5 = 0x800; break;
302
303 case '1': d->d3 = 0x80; break;
304 case '2': d->d3 = 0x40; break;
305 case '3': d->d3 = 0x20; break;
306 case '4': d->d3 = 0x10; break;
307 case '5': d->d2 = 0x08; break;
308 case '6': d->d2 = 0x04; break;
309 case '7': d->d2 = 0x02; break;
310 case '8': d->d2 = 0x01; break;
311 case '9': d->d2 = 0x8000; break;
312 case '0': d->d2 = 0x4000; break;
313
314 case ';': d->d0 = 0x800; break;
315 case '\'': d->d0 = 0x400; break;
316 case '[': d->d0 = 0x200; break;
317 case '/': d->d0 = 0x8; break;
318 case '\\': d->d0 = 0x4; break;
319 case ']': d->d0 = 0x2; break;
320
321 case 'a': d->d1 = 0x8000; break;
322 case 'b': d->d2 = 0x800; break;
323 case 'c': d->d1 = 0x20; break;
324 case 'd': d->d1 = 0x2000; break;
325 case 'e': d->d2 = 0x20; break;
326 case 'f': d->d1 = 0x1000; break;
327 case 'g': d->d3 = 0x8; break;
328 case 'h': d->d3 = 0x4; break;
329 case 'i': d->d3 = 0x100; break;
330 case 'j': d->d3 = 0x2; break;
331 case 'k': d->d3 = 0x1; break;
332 case 'l': d->d0 = 0x80; break;
333 case 'm': d->d2 = 0x200; break;
334 case 'n': d->d2 = 0x400; break;
335 case 'o': d->d0 = 0x8000; break;
336 case 'p': d->d4 = 0x20; break;
337 case 'q': d->d2 = 0x80; break;
338 case 'r': d->d2 = 0x10; break;
339 case 's': d->d1 = 0x4000; break;
340 case 't': d->d3 = 0x800; break;
341 case 'u': d->d3 = 0x200; break;
342 case 'v': d->d1 = 0x10; break;
343 case 'w': d->d2 = 0x40; break;
344 case 'x': d->d1 = 0x40; break;
345 case 'y': d->d3 = 0x400; break;
346 case 'z': d->d1 = 0x80; break;
347
348 case ',': d->d2 = 0x100; break;
349 case '.': d->d0 = 0x4000; break;
350 case '-': d->d1 = 0x400; break;
351 case '=': d->d1 = 0x200; break;
352
353 case '\r':
354 case '\n': d->d0 = 0x40; break;
355 case ' ': d->d0 = 0x01; break;
356 case '\b': d->d4 = 0x10; break;
357
358 case 27: d->escape_state = 1; break;
359
360 default:
361 /* Shifted: */
362 if (ch >= 'A' && ch <= 'Z') {
363 console_makeavail(d->kiu_console_handle,
364 ch + 32);
365 d->d5 = 0x800;
366 d->dont_clear_next = 1;
367 break;
368 }
369
370 /* CTRLed: */
371 if (ch >= 1 && ch <= 26) {
372 console_makeavail(d->kiu_console_handle,
373 ch + 96);
374 d->d5 = 0x4;
375 d->dont_clear_next = 1;
376 break;
377 }
378 }
379
380 if (d->escape_state == 0)
381 keychange = 1;
382 }
383
384 if (keychange) {
385 /* 4=lost data, 2=data complete, 1=key input detected */
386 d->kiu_int_assert |= 3;
387 recalc_kiu_int_assert(cpu, d);
388 }
389 }
390
391
392 /*
393 * timer_tick():
394 */
395 static void timer_tick(struct timer *timer, void *extra)
396 {
397 struct vr41xx_data *d = extra;
398 d->pending_timer_interrupts ++;
399 }
400
401
402 DEVICE_TICK(vr41xx)
403 {
404 struct vr41xx_data *d = extra;
405
406 if (d->pending_timer_interrupts > 0)
407 INTERRUPT_ASSERT(d->timer_irq);
408
409 if (cpu->machine->x11_md.in_use)
410 vr41xx_keytick(cpu, d);
411 }
412
413
414 /*
415 * vr41xx_kiu():
416 *
417 * Keyboard Interface Unit. Return value is "odata".
418 * (See NetBSD's vrkiu.c for more info.)
419 */
420 static uint64_t vr41xx_kiu(struct cpu *cpu, int ofs, uint64_t idata,
421 int writeflag, struct vr41xx_data *d)
422 {
423 uint64_t odata = 0;
424
425 switch (ofs) {
426 case KIUDAT0:
427 odata = d->d0; break;
428 case KIUDAT1:
429 odata = d->d1; break;
430 case KIUDAT2:
431 odata = d->d2; break;
432 case KIUDAT3:
433 odata = d->d3; break;
434 case KIUDAT4:
435 odata = d->d4; break;
436 case KIUDAT5:
437 odata = d->d5; break;
438 case KIUSCANREP:
439 if (writeflag == MEM_WRITE) {
440 debug("[ vr41xx KIU: setting KIUSCANREP to 0x%04x ]\n",
441 (int)idata);
442 /* TODO */
443 } else
444 fatal("[ vr41xx KIU: unimplemented read from "
445 "KIUSCANREP ]\n");
446 break;
447 case KIUSCANS:
448 if (writeflag == MEM_WRITE) {
449 debug("[ vr41xx KIU: write to KIUSCANS: 0x%04x: TODO"
450 " ]\n", (int)idata);
451 /* TODO */
452 } else
453 debug("[ vr41xx KIU: unimplemented read from "
454 "KIUSCANS ]\n");
455 break;
456 case KIUINT:
457 /* Interrupt. A wild guess: zero-on-write */
458 if (writeflag == MEM_WRITE) {
459 d->kiu_int_assert &= ~idata;
460 } else {
461 odata = d->kiu_int_assert;
462 }
463 recalc_kiu_int_assert(cpu, d);
464 break;
465 case KIURST:
466 /* Reset. */
467 break;
468 default:
469 if (writeflag == MEM_WRITE)
470 debug("[ vr41xx KIU: unimplemented write to offset "
471 "0x%x, data=0x%016"PRIx64" ]\n", ofs,
472 (uint64_t) idata);
473 else
474 debug("[ vr41xx KIU: unimplemented read from offset "
475 "0x%x ]\n", ofs);
476 }
477
478 return odata;
479 }
480
481
482 DEVICE_ACCESS(vr41xx)
483 {
484 struct vr41xx_data *d = extra;
485 uint64_t idata = 0, odata = 0;
486 int regnr;
487 int revision = 0;
488
489 if (writeflag == MEM_WRITE)
490 idata = memory_readmax64(cpu, data, len);
491
492 regnr = relative_addr / sizeof(uint64_t);
493
494 /* KIU ("Keyboard Interface Unit") is handled separately. */
495 if (relative_addr >= d->kiu_offset &&
496 relative_addr < d->kiu_offset + 0x20) {
497 odata = vr41xx_kiu(cpu, relative_addr - d->kiu_offset,
498 idata, writeflag, d);
499 goto ret;
500 }
501
502 /* TODO: Maybe these should be handled separately as well? */
503
504 switch (relative_addr) {
505
506 /* BCU: 0x00 .. 0x1c */
507 case BCUREVID_REG_W: /* 0x010 */
508 case BCU81REVID_REG_W: /* 0x014 */
509 /*
510 * TODO? Linux seems to read 0x14. The lowest bits are
511 * a divisor for PClock, bits 8 and up seem to be a
512 * divisor for VTClock (relative to PClock?)...
513 */
514 switch (d->cpumodel) {
515 case 4131: revision = BCUREVID_RID_4131; break;
516 case 4122: revision = BCUREVID_RID_4122; break;
517 case 4121: revision = BCUREVID_RID_4121; break;
518 case 4111: revision = BCUREVID_RID_4111; break;
519 case 4102: revision = BCUREVID_RID_4102; break;
520 case 4101: revision = BCUREVID_RID_4101; break;
521 case 4181: revision = BCUREVID_RID_4181; break;
522 }
523 odata = (revision << BCUREVID_RIDSHFT) | 0x020c;
524 break;
525 case BCU81CLKSPEED_REG_W: /* 0x018 */
526 /*
527 * TODO: Implement this for ALL cpu types:
528 */
529 odata = BCUCLKSPEED_DIVT4 << BCUCLKSPEED_DIVTSHFT;
530 break;
531
532 /* DMAAU: 0x20 .. 0x3c */
533
534 /* DCU: 0x40 .. 0x5c */
535
536 /* CMU: 0x60 .. 0x7c */
537
538 /* ICU: 0x80 .. 0xbc */
539 case 0x80: /* Level 1 system interrupt reg 1... */
540 if (writeflag == MEM_READ)
541 odata = d->sysint1;
542 else {
543 /* TODO: clear-on-write-one? */
544 d->sysint1 &= ~idata;
545 d->sysint1 &= 0xffff;
546 }
547 break;
548 case 0x88:
549 if (writeflag == MEM_READ)
550 odata = d->giuint;
551 else
552 d->giuint &= ~idata;
553 break;
554 case 0x8c:
555 if (writeflag == MEM_READ)
556 odata = d->msysint1;
557 else
558 d->msysint1 = idata;
559 break;
560 case 0x94:
561 if (writeflag == MEM_READ)
562 odata = d->giumask;
563 else
564 d->giumask = idata;
565 break;
566 case 0xa0: /* Level 1 system interrupt reg 2... */
567 if (writeflag == MEM_READ)
568 odata = d->sysint2;
569 else {
570 /* TODO: clear-on-write-one? */
571 d->sysint2 &= ~idata;
572 d->sysint2 &= 0xffff;
573 }
574 break;
575 case 0xa6:
576 if (writeflag == MEM_READ)
577 odata = d->msysint2;
578 else
579 d->msysint2 = idata;
580 break;
581
582 /* RTC: */
583 case 0xc0:
584 case 0xc2:
585 case 0xc4:
586 {
587 struct timeval tv;
588 gettimeofday(&tv, NULL);
589 /* Adjust time by 120 years and 29 days. */
590 tv.tv_sec += (int64_t) (120*365 + 29) * 24*60*60;
591
592 switch (relative_addr) {
593 case 0xc0:
594 odata = (tv.tv_sec & 1) << 15;
595 break;
596 case 0xc2:
597 odata = (tv.tv_sec >> 1) & 0xffff;
598 break;
599 case 0xc4:
600 odata = (tv.tv_sec >> 17) & 0xffff;
601 break;
602 }
603 }
604 break;
605
606 case 0xd0: /* RTCL1_L_REG_W */
607 if (writeflag == MEM_WRITE && idata != 0) {
608 int hz = RTCL1_L_HZ / idata;
609 debug("[ vr41xx: rtc interrupts at %i Hz ]\n", hz);
610 if (d->timer == NULL)
611 d->timer = timer_add(hz, timer_tick, d);
612 else
613 timer_update_frequency(d->timer, hz);
614 }
615 break;
616 case 0xd2: /* RTCL1_H_REG_W */
617 break;
618
619 case 0x108:
620 if (writeflag == MEM_READ)
621 odata = d->giuint;
622 else
623 d->giuint &= ~idata;
624 break;
625 /* case 0x10a:
626 "High" part of GIU?
627 break;
628 */
629
630 case 0x13e: /* on 4181? */
631 case 0x1de: /* on 4121? */
632 /* RTC interrupt register... */
633 /* Ack. timer interrupts? */
634 INTERRUPT_DEASSERT(d->timer_irq);
635 if (d->pending_timer_interrupts > 0)
636 d->pending_timer_interrupts --;
637 break;
638
639 default:
640 if (writeflag == MEM_WRITE)
641 debug("[ vr41xx: unimplemented write to address "
642 "0x%"PRIx64", data=0x%016"PRIx64" ]\n",
643 (uint64_t) relative_addr, (uint64_t) idata);
644 else
645 debug("[ vr41xx: unimplemented read from address "
646 "0x%"PRIx64" ]\n", (uint64_t) relative_addr);
647 }
648
649 ret:
650 /*
651 * Recalculate interrupt assertions:
652 */
653 if (d->giuint & d->giumask)
654 INTERRUPT_ASSERT(d->giu_irq);
655 else
656 INTERRUPT_DEASSERT(d->giu_irq);
657 if ((d->sysint1 & d->msysint1) | (d->sysint2 & d->msysint2))
658 INTERRUPT_ASSERT(d->cpu_irq);
659 else
660 INTERRUPT_DEASSERT(d->cpu_irq);
661
662 if (writeflag == MEM_READ)
663 memory_writemax64(cpu, data, len, odata);
664
665 return 1;
666 }
667
668
669 /*
670 * dev_vr41xx_init():
671 *
672 * machine->path is something like "emul[0].machine[0]".
673 */
674 struct vr41xx_data *dev_vr41xx_init(struct machine *machine,
675 struct memory *mem, int cpumodel)
676 {
677 struct vr41xx_data *d;
678 uint64_t baseaddr = 0;
679 char tmps[300];
680 int i;
681
682 CHECK_ALLOCATION(d = malloc(sizeof(struct vr41xx_data)));
683 memset(d, 0, sizeof(struct vr41xx_data));
684
685 /* Connect to MIPS irq 2: */
686 snprintf(tmps, sizeof(tmps), "%s.cpu[%i].2",
687 machine->path, machine->bootstrap_cpu);
688 INTERRUPT_CONNECT(tmps, d->cpu_irq);
689
690 /*
691 * Register VRIP interrupt lines 0..25:
692 */
693 for (i=0; i<=25; i++) {
694 struct interrupt template;
695 snprintf(tmps, sizeof(tmps), "%s.cpu[%i].vrip.%i",
696 machine->path, machine->bootstrap_cpu, i);
697 memset(&template, 0, sizeof(template));
698 template.line = i;
699 template.name = tmps;
700 template.extra = d;
701 template.interrupt_assert = vr41xx_vrip_interrupt_assert;
702 template.interrupt_deassert = vr41xx_vrip_interrupt_deassert;
703 interrupt_handler_register(&template);
704 }
705
706 /*
707 * Register GIU interrupt lines 0..31:
708 */
709 for (i=0; i<32; i++) {
710 struct interrupt template;
711 snprintf(tmps, sizeof(tmps), "%s.cpu[%i].vrip.%i.giu.%i",
712 machine->path, machine->bootstrap_cpu, VRIP_INTR_GIU, i);
713 memset(&template, 0, sizeof(template));
714 template.line = i;
715 template.name = tmps;
716 template.extra = d;
717 template.interrupt_assert = vr41xx_giu_interrupt_assert;
718 template.interrupt_deassert = vr41xx_giu_interrupt_deassert;
719 interrupt_handler_register(&template);
720 }
721
722 d->cpumodel = cpumodel;
723
724 /* TODO: VRC4173 has the KIU at offset 0x100? */
725 d->kiu_offset = 0x180;
726 d->kiu_console_handle = console_start_slave_inputonly(
727 machine, "kiu", 1);
728
729 /* Connect to the KIU and GIU interrupts: */
730 snprintf(tmps, sizeof(tmps), "%s.cpu[%i].vrip.%i",
731 machine->path, machine->bootstrap_cpu, VRIP_INTR_GIU);
732 INTERRUPT_CONNECT(tmps, d->giu_irq);
733 snprintf(tmps, sizeof(tmps), "%s.cpu[%i].vrip.%i",
734 machine->path, machine->bootstrap_cpu, VRIP_INTR_KIU);
735 INTERRUPT_CONNECT(tmps, d->kiu_irq);
736
737 if (machine->x11_md.in_use)
738 machine->main_console_handle = d->kiu_console_handle;
739
740 switch (cpumodel) {
741 case 4101:
742 case 4102:
743 case 4111:
744 case 4121:
745 baseaddr = 0xb000000;
746 break;
747 case 4181:
748 baseaddr = 0xa000000;
749 dev_ram_init(machine, 0xb000000, 0x1000000, DEV_RAM_MIRROR,
750 0xa000000);
751 break;
752 case 4122:
753 case 4131:
754 baseaddr = 0xf000000;
755 break;
756 default:
757 printf("Unimplemented VR cpu model\n");
758 exit(1);
759 }
760
761 if (d->cpumodel == 4121 || d->cpumodel == 4181)
762 snprintf(tmps, sizeof(tmps), "%s.cpu[%i].3",
763 machine->path, machine->bootstrap_cpu);
764 else
765 snprintf(tmps, sizeof(tmps), "%s.cpu[%i].vrip.%i",
766 machine->path, machine->bootstrap_cpu, VRIP_INTR_ETIMER);
767 INTERRUPT_CONNECT(tmps, d->timer_irq);
768
769 memory_device_register(mem, "vr41xx", baseaddr, DEV_VR41XX_LENGTH,
770 dev_vr41xx_access, (void *)d, DM_DEFAULT, NULL);
771
772 /*
773 * TODO: Find out which controllers are at which addresses on
774 * which chips.
775 */
776 if (cpumodel == 4131) {
777 snprintf(tmps, sizeof(tmps), "ns16550 irq=%s.cpu[%i].vrip.%i "
778 "addr=0x%"PRIx64" name2=siu", machine->path,
779 machine->bootstrap_cpu, VRIP_INTR_SIU,
780 (uint64_t) (baseaddr+0x800));
781 device_add(machine, tmps);
782 } else {
783 /* This is used by Linux and NetBSD: */
784 snprintf(tmps, sizeof(tmps), "ns16550 irq=%s.cpu[%i]."
785 "vrip.%i addr=0x%x name2=serial", machine->path,
786 machine->bootstrap_cpu, VRIP_INTR_SIU, 0xc000000);
787 device_add(machine, tmps);
788 }
789
790 /* Hm... maybe this should not be here. TODO */
791 snprintf(tmps, sizeof(tmps), "pcic irq=%s.cpu[%i].vrip.%i addr="
792 "0x140003e0", machine->path, machine->bootstrap_cpu,
793 VRIP_INTR_GIU);
794 device_add(machine, tmps);
795
796 machine_add_tickfunction(machine, dev_vr41xx_tick, d,
797 DEV_VR41XX_TICKSHIFT);
798
799 /* Some machines (?) use ISA space at 0x15000000 instead of
800 0x14000000, eg IBM WorkPad Z50. */
801 dev_ram_init(machine, 0x15000000, 0x1000000, DEV_RAM_MIRROR,
802 0x14000000);
803
804 return d;
805 }
806

  ViewVC Help
Powered by ViewVC 1.1.26