/[gxemul]/upstream/0.3.6.1/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.3.6.1/src/devices/dev_vr41xx.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 17 - (show annotations)
Mon Oct 8 16:19:05 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 16796 byte(s)
0.3.6.1
1 /*
2 * Copyright (C) 2004-2005 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.30 2005/08/05 09:11:48 debug Exp $
29 *
30 * VR41xx (actually, VR4122 and VR4131) misc functions.
31 *
32 * This is just a big hack. TODO: Fix.
33 */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include "console.h"
40 #include "cpu.h"
41 #include "device.h"
42 #include "devices.h"
43 #include "machine.h"
44 #include "memory.h"
45 #include "misc.h"
46
47 #include "bcureg.h"
48 #include "vripreg.h"
49 #include "vrkiureg.h"
50
51
52 #define DEV_VR41XX_TICKSHIFT 15
53
54 /* #define debug fatal */
55
56
57 static void recalc_kiu_int_assert(struct cpu *cpu, struct vr41xx_data *d)
58 {
59 if (d->kiu_int_assert != 0)
60 cpu_interrupt(cpu, 8 + d->kiu_irq_nr);
61 else
62 cpu_interrupt_ack(cpu, 8 + d->kiu_irq_nr);
63 }
64
65
66 /*
67 * vr41xx_keytick():
68 */
69 static void vr41xx_keytick(struct cpu *cpu, struct vr41xx_data *d)
70 {
71 int keychange = 0;
72
73 /*
74 * Keyboard input:
75 *
76 * Hardcoded for MobilePro 780. (See NetBSD's hpckbdkeymap.h for
77 * info on other keyboard layouts. mobilepro780_keytrans is the
78 * one used here.)
79 *
80 * TODO: Make this work with "any" keyboard layout.
81 *
82 * (Even MobilePro 770 seems to be different? Hm. TODO)
83 *
84 * ofs 0:
85 * 8000='o' 4000='.' 2000=DOWN 1000=UP
86 * 800=';' 400=''' 200='[' 100=?
87 * 80='l' 40=CR 20=RIGHT 10=LEFT
88 * 8='/' 4='\' 2=']' 1=SPACE
89 * ofs 2:
90 * 8000='a' 4000='s' 2000='d' 1000='f'
91 * 800='`' 400='-' 200='=' 100=?
92 * 80='z' 40='x' 20='c' 10='v'
93 * 8=? 4=? 2=?
94 * ofs 4:
95 * 8000='9' 4000='0' 2000=? 1000=?
96 * 800='b' 400='n' 200='m' 100=','
97 * 80='q' 40='w' 20='e' 10='r'
98 * 8='5' 4='6' 2='7' 1='8'
99 * ofs 6:
100 * 8000=ESC 4000=DEL 2000=CAPS 1000=?
101 * 800='t' 400='y' 200='u' 100='i'
102 * 80='1' 40='2' 20='3' 10='4'
103 * 8='g' 4='h' 2='j' 1='k'
104 * ofs 8:
105 * 200=ALT_L
106 * 80= 40=TAB 20='p' 10=BS
107 * 8= 4= 2= 1=ALT_R
108 * ofs a:
109 * 800=SHIFT 4=CTRL
110 *
111 *
112 * The following are for the IBM WorkPad Z50:
113 * (Not yet implemented, TODO)
114 *
115 * 00 f1 f3 f5 f7 f9 - - f11
116 * 08 f2 f4 f6 f8 f10 - - f12
117 * 10 ' [ - 0 p ; up /
118 * 18 - - - 9 o l . -
119 * 20 left ] = 8 i k , -
120 * 28 h y 6 7 u j m n
121 * 30 - bs num del - \ ent sp
122 * 38 g t 5 4 r f v b
123 * 40 - - - 3 e d c right
124 * 48 - - - 2 w s x down
125 * 50 esc tab ~ 1 q a z -
126 * 58 menu Ls Lc Rc La Ra Rs -
127 */
128
129 if (d->d0 != 0 || d->d1 != 0 || d->d2 != 0 ||
130 d->d3 != 0 || d->d4 != 0 || d->d5 != 0)
131 keychange = 1;
132
133 /* Release all keys: */
134 if (!d->dont_clear_next) {
135 d->d0 = d->d1 = d->d2 = d->d3 = d->d4 = d->d5 = 0;
136 } else
137 d->dont_clear_next = 0;
138
139 if (console_charavail(d->kiu_console_handle)) {
140 char ch = console_readchar(d->kiu_console_handle);
141
142 if (d->escape_state > 0) {
143 switch (d->escape_state) {
144 case 1: /* expecting a [ */
145 d->escape_state = 0;
146 if (ch == '[')
147 d->escape_state = 2;
148 break;
149 case 2: /* cursor keys etc: */
150 switch (ch) {
151 case 'A': d->d0 = 0x1000; break;
152 case 'B': d->d0 = 0x2000; break;
153 case 'C': d->d0 = 0x20; break;
154 case 'D': d->d0 = 0x10; break;
155 default: fatal("[ vr41xx kiu: "
156 "unimplemented escape 0x%02 ]\n", ch);
157 }
158 d->escape_state = 0;
159 }
160 } else switch (ch) {
161 case '+': console_makeavail(d->kiu_console_handle, '=');
162 d->d5 = 0x800; break;
163 case '_': console_makeavail(d->kiu_console_handle, '-');
164 d->d5 = 0x800; break;
165 case '<': console_makeavail(d->kiu_console_handle, ',');
166 d->d5 = 0x800; break;
167 case '>': console_makeavail(d->kiu_console_handle, '.');
168 d->d5 = 0x800; break;
169 case '{': console_makeavail(d->kiu_console_handle, '[');
170 d->d5 = 0x800; break;
171 case '}': console_makeavail(d->kiu_console_handle, ']');
172 d->d5 = 0x800; break;
173 case ':': console_makeavail(d->kiu_console_handle, ';');
174 d->d5 = 0x800; break;
175 case '"': console_makeavail(d->kiu_console_handle, '\'');
176 d->d5 = 0x800; break;
177 case '|': console_makeavail(d->kiu_console_handle, '\\');
178 d->d5 = 0x800; break;
179 case '?': console_makeavail(d->kiu_console_handle, '/');
180 d->d5 = 0x800; break;
181
182 case '!': console_makeavail(d->kiu_console_handle, '1');
183 d->d5 = 0x800; break;
184 case '@': console_makeavail(d->kiu_console_handle, '2');
185 d->d5 = 0x800; break;
186 case '#': console_makeavail(d->kiu_console_handle, '3');
187 d->d5 = 0x800; break;
188 case '$': console_makeavail(d->kiu_console_handle, '4');
189 d->d5 = 0x800; break;
190 case '%': console_makeavail(d->kiu_console_handle, '5');
191 d->d5 = 0x800; break;
192 case '^': console_makeavail(d->kiu_console_handle, '6');
193 d->d5 = 0x800; break;
194 case '&': console_makeavail(d->kiu_console_handle, '7');
195 d->d5 = 0x800; break;
196 case '*': console_makeavail(d->kiu_console_handle, '8');
197 d->d5 = 0x800; break;
198 case '(': console_makeavail(d->kiu_console_handle, '9');
199 d->d5 = 0x800; break;
200 case ')': console_makeavail(d->kiu_console_handle, '0');
201 d->d5 = 0x800; break;
202
203 case '1': d->d3 = 0x80; break;
204 case '2': d->d3 = 0x40; break;
205 case '3': d->d3 = 0x20; break;
206 case '4': d->d3 = 0x10; break;
207 case '5': d->d2 = 0x08; break;
208 case '6': d->d2 = 0x04; break;
209 case '7': d->d2 = 0x02; break;
210 case '8': d->d2 = 0x01; break;
211 case '9': d->d2 = 0x8000; break;
212 case '0': d->d2 = 0x4000; break;
213
214 case ';': d->d0 = 0x800; break;
215 case '\'': d->d0 = 0x400; break;
216 case '[': d->d0 = 0x200; break;
217 case '/': d->d0 = 0x8; break;
218 case '\\': d->d0 = 0x4; break;
219 case ']': d->d0 = 0x2; break;
220
221 case 'a': d->d1 = 0x8000; break;
222 case 'b': d->d2 = 0x800; break;
223 case 'c': d->d1 = 0x20; break;
224 case 'd': d->d1 = 0x2000; break;
225 case 'e': d->d2 = 0x20; break;
226 case 'f': d->d1 = 0x1000; break;
227 case 'g': d->d3 = 0x8; break;
228 case 'h': d->d3 = 0x4; break;
229 case 'i': d->d3 = 0x100; break;
230 case 'j': d->d3 = 0x2; break;
231 case 'k': d->d3 = 0x1; break;
232 case 'l': d->d0 = 0x80; break;
233 case 'm': d->d2 = 0x200; break;
234 case 'n': d->d2 = 0x400; break;
235 case 'o': d->d0 = 0x8000; break;
236 case 'p': d->d4 = 0x20; break;
237 case 'q': d->d2 = 0x80; break;
238 case 'r': d->d2 = 0x10; break;
239 case 's': d->d1 = 0x4000; break;
240 case 't': d->d3 = 0x800; break;
241 case 'u': d->d3 = 0x200; break;
242 case 'v': d->d1 = 0x10; break;
243 case 'w': d->d2 = 0x40; break;
244 case 'x': d->d1 = 0x40; break;
245 case 'y': d->d3 = 0x400; break;
246 case 'z': d->d1 = 0x80; break;
247
248 case ',': d->d2 = 0x100; break;
249 case '.': d->d0 = 0x4000; break;
250 case '-': d->d1 = 0x400; break;
251 case '=': d->d1 = 0x200; break;
252
253 case '\r':
254 case '\n': d->d0 = 0x40; break;
255 case ' ': d->d0 = 0x01; break;
256 case '\b': d->d4 = 0x10; break;
257
258 case 27: d->escape_state = 1; break;
259
260 default:
261 /* Shifted: */
262 if (ch >= 'A' && ch <= 'Z') {
263 console_makeavail(d->kiu_console_handle,
264 ch + 32);
265 d->d5 = 0x800;
266 d->dont_clear_next = 1;
267 break;
268 }
269
270 /* CTRLed: */
271 if (ch >= 1 && ch <= 26) {
272 console_makeavail(d->kiu_console_handle,
273 ch + 96);
274 d->d5 = 0x4;
275 d->dont_clear_next = 1;
276 break;
277 }
278 }
279
280 if (d->escape_state == 0)
281 keychange = 1;
282 }
283
284 if (keychange) {
285 /* 4=lost data, 2=data complete, 1=key input detected */
286 d->kiu_int_assert |= 3;
287 recalc_kiu_int_assert(cpu, d);
288 }
289 }
290
291
292 /*
293 * dev_vr41xx_tick():
294 */
295 void dev_vr41xx_tick(struct cpu *cpu, void *extra)
296 {
297 struct vr41xx_data *d = extra;
298
299 /*
300 * UGLY! TODO: fix this.
301 *
302 * Interrupts should be triggered if the corresponding unit (for
303 * example the RTC unit) is activated.
304 */
305 {
306 static unsigned int x = 0;
307 x++;
308
309 if (x > 100 && (x&3)==0) {
310 if (d->cpumodel == 4121 || d->cpumodel == 4181)
311 cpu_interrupt(cpu, 3);
312 else
313 cpu_interrupt(cpu, 8 + VRIP_INTR_ETIMER);
314 }
315 }
316
317 if (cpu->machine->use_x11)
318 vr41xx_keytick(cpu, d);
319 }
320
321
322 /*
323 * vr41xx_kiu():
324 *
325 * Keyboard Interface Unit. Return value is "odata".
326 * (See NetBSD's vrkiu.c for more info.)
327 */
328 static uint64_t vr41xx_kiu(struct cpu *cpu, int ofs, uint64_t idata,
329 int writeflag, struct vr41xx_data *d)
330 {
331 uint64_t odata = 0;
332
333 switch (ofs) {
334 case KIUDAT0:
335 odata = d->d0; break;
336 case KIUDAT1:
337 odata = d->d1; break;
338 case KIUDAT2:
339 odata = d->d2; break;
340 case KIUDAT3:
341 odata = d->d3; break;
342 case KIUDAT4:
343 odata = d->d4; break;
344 case KIUDAT5:
345 odata = d->d5; break;
346 case KIUSCANREP:
347 if (writeflag == MEM_WRITE) {
348 debug("[ vr41xx KIU: setting KIUSCANREP to 0x%04x ]\n",
349 (int)idata);
350 /* TODO */
351 } else
352 fatal("[ vr41xx KIU: unimplemented read from "
353 "KIUSCANREP ]\n");
354 break;
355 case KIUSCANS:
356 if (writeflag == MEM_WRITE) {
357 debug("[ vr41xx KIU: write to KIUSCANS: 0x%04x: TODO"
358 " ]\n", (int)idata);
359 /* TODO */
360 } else
361 debug("[ vr41xx KIU: unimplemented read from "
362 "KIUSCANS ]\n");
363 break;
364 case KIUINT:
365 /* Interrupt. A wild guess: zero-on-write */
366 if (writeflag == MEM_WRITE) {
367 d->kiu_int_assert &= ~idata;
368 } else {
369 odata = d->kiu_int_assert;
370 }
371 recalc_kiu_int_assert(cpu, d);
372 break;
373 case KIURST:
374 /* Reset. */
375 break;
376 default:
377 if (writeflag == MEM_WRITE)
378 debug("[ vr41xx KIU: unimplemented write to offset "
379 "0x%x, data=0x%016llx ]\n", ofs, (long long)idata);
380 else
381 debug("[ vr41xx KIU: unimplemented read from offset "
382 "0x%x ]\n", ofs);
383 }
384
385 return odata;
386 }
387
388
389 /*
390 * dev_vr41xx_access():
391 */
392 int dev_vr41xx_access(struct cpu *cpu, struct memory *mem,
393 uint64_t relative_addr, unsigned char *data, size_t len,
394 int writeflag, void *extra)
395 {
396 struct vr41xx_data *d = (struct vr41xx_data *) extra;
397 uint64_t idata = 0, odata = 0;
398 int regnr;
399 int revision = 0;
400
401 idata = memory_readmax64(cpu, data, len);
402 regnr = relative_addr / sizeof(uint64_t);
403
404 /* KIU ("Keyboard Interface Unit") is handled separately. */
405 if (relative_addr >= d->kiu_offset &&
406 relative_addr < d->kiu_offset + 0x20) {
407 odata = vr41xx_kiu(cpu, relative_addr - d->kiu_offset,
408 idata, writeflag, d);
409 goto ret;
410 }
411
412 /* TODO: Maybe these should be handled separately as well? */
413
414 switch (relative_addr) {
415 /* BCU: 0x00 .. 0x1c */
416 case BCUREVID_REG_W: /* 0x010 */
417 case BCU81REVID_REG_W: /* 0x014 */
418 /*
419 * TODO? Linux seems to read 0x14. The lowest bits are
420 * a divisor for PClock, bits 8 and up seem to be a
421 * divisor for VTClock (relative to PClock?)...
422 */
423 switch (d->cpumodel) {
424 case 4131: revision = BCUREVID_RID_4131; break;
425 case 4122: revision = BCUREVID_RID_4122; break;
426 case 4121: revision = BCUREVID_RID_4121; break;
427 case 4111: revision = BCUREVID_RID_4111; break;
428 case 4102: revision = BCUREVID_RID_4102; break;
429 case 4101: revision = BCUREVID_RID_4101; break;
430 case 4181: revision = BCUREVID_RID_4181; break;
431 }
432 odata = (revision << BCUREVID_RIDSHFT) | 0x020c;
433 break;
434 case BCU81CLKSPEED_REG_W: /* 0x018 */
435 /*
436 * TODO: Implement this for ALL cpu types:
437 */
438 odata = BCUCLKSPEED_DIVT4 << BCUCLKSPEED_DIVTSHFT;
439 break;
440
441 /* DMAAU: 0x20 .. 0x3c */
442
443 /* DCU: 0x40 .. 0x5c */
444
445 /* CMU: 0x60 .. 0x7c */
446
447 /* ICU: 0x80 .. 0xbc */
448 case 0x80: /* Level 1 system interrupt reg 1... */
449 if (writeflag == MEM_READ)
450 odata = d->sysint1;
451 else {
452 /* TODO: clear-on-write-one? */
453 d->sysint1 &= ~idata;
454 d->sysint1 &= 0xffff;
455 }
456 break;
457 case 0x88:
458 if (writeflag == MEM_READ)
459 odata = d->giuint;
460 else
461 d->giuint &= ~idata;
462 break;
463 case 0x8c:
464 if (writeflag == MEM_READ)
465 odata = d->msysint1;
466 else
467 d->msysint1 = idata;
468 break;
469 case 0x94:
470 if (writeflag == MEM_READ)
471 odata = d->giumask;
472 else
473 d->giumask = idata;
474 break;
475 case 0xa0: /* Level 1 system interrupt reg 2... */
476 if (writeflag == MEM_READ)
477 odata = d->sysint2;
478 else {
479 /* TODO: clear-on-write-one? */
480 d->sysint2 &= ~idata;
481 d->sysint2 &= 0xffff;
482 }
483 break;
484 case 0xa6:
485 if (writeflag == MEM_READ)
486 odata = d->msysint2;
487 else
488 d->msysint2 = idata;
489 break;
490
491 /* PMU: 0xc0 .. 0xfc */
492 /* RTC: 0x100 .. ? */
493
494 case 0x108:
495 if (writeflag == MEM_READ)
496 odata = d->giuint;
497 else
498 d->giuint &= ~idata;
499 break;
500 /* case 0x10a:
501 "High" part of GIU?
502 break;
503 */
504
505 case 0x13e: /* on 4181? */
506 /* RTC interrupt register... */
507 /* Ack. timer interrupts? */
508 cpu_interrupt_ack(cpu, 8 + VRIP_INTR_ETIMER);
509 break;
510
511 case 0x1de: /* on 4121? */
512 /* RTC interrupt register... */
513 /* Ack. timer interrupts? */
514 cpu_interrupt_ack(cpu, 3);
515 break;
516
517 default:
518 if (writeflag == MEM_WRITE)
519 debug("[ vr41xx: unimplemented write to address "
520 "0x%llx, data=0x%016llx ]\n",
521 (long long)relative_addr, (long long)idata);
522 else
523 debug("[ vr41xx: unimplemented read from address "
524 "0x%llx ]\n", (long long)relative_addr);
525 }
526
527 ret:
528 /* Recalculate interrupt assertions: */
529 cpu_interrupt_ack(cpu, 8 + 31); /* TODO: hopefully nothing
530 useful at irq 15 in
531 sysint2 */
532
533 if (writeflag == MEM_READ)
534 memory_writemax64(cpu, data, len, odata);
535
536 return 1;
537 }
538
539
540 /*
541 * dev_vr41xx_init():
542 */
543 struct vr41xx_data *dev_vr41xx_init(struct machine *machine,
544 struct memory *mem, int cpumodel)
545 {
546 uint64_t baseaddr = 0;
547 char tmps[100];
548 struct vr41xx_data *d = malloc(sizeof(struct vr41xx_data));
549
550 if (d == NULL) {
551 fprintf(stderr, "out of memory\n");
552 exit(1);
553 }
554 memset(d, 0, sizeof(struct vr41xx_data));
555
556 d->cpumodel = cpumodel;
557
558 /* TODO: VRC4173 has the KIU at offset 0x100? */
559 d->kiu_offset = 0x180;
560 d->kiu_console_handle = console_start_slave_inputonly(machine, "kiu");
561 d->kiu_irq_nr = VRIP_INTR_KIU;
562
563 switch (cpumodel) {
564 case 4101:
565 case 4102:
566 case 4111:
567 case 4121:
568 baseaddr = 0xb000000;
569 break;
570 case 4181:
571 baseaddr = 0xa000000;
572 dev_ram_init(mem, 0xb000000, 0x1000000, DEV_RAM_MIRROR,
573 0xa000000);
574 break;
575 case 4122:
576 case 4131:
577 baseaddr = 0xf000000;
578 break;
579 default:
580 printf("Unimplemented VR cpu model\n");
581 exit(1);
582 }
583
584 memory_device_register(mem, "vr41xx", baseaddr, DEV_VR41XX_LENGTH,
585 dev_vr41xx_access, (void *)d, MEM_DEFAULT, NULL);
586
587 /*
588 * TODO: Find out which controllers are at which addresses on
589 * which chips.
590 */
591 if (cpumodel == 4131) {
592 snprintf(tmps, sizeof(tmps), "ns16550 irq=%i addr=0x%llx "
593 "name2=siu", 8+VRIP_INTR_SIU, (long long)(baseaddr+0x800));
594 device_add(machine, tmps);
595 } else {
596 /* This is used by Linux and NetBSD: */
597 snprintf(tmps, sizeof(tmps), "ns16550 irq=%i addr=0x%x "
598 "name2=serial", 8+VRIP_INTR_SIU, 0xc000000);
599 device_add(machine, tmps);
600 }
601
602 /* Hm... maybe this should not be here. TODO */
603 device_add(machine, "pcic addr=0x140003e0");
604
605 machine_add_tickfunction(machine, dev_vr41xx_tick, d,
606 DEV_VR41XX_TICKSHIFT);
607
608 /* Some machines (?) use ISA space at 0x15000000 instead of
609 0x14000000, eg IBM WorkPad Z50. */
610 dev_ram_init(mem, 0x15000000, 0x1000000, DEV_RAM_MIRROR, 0x14000000);
611
612 return d;
613 }
614

  ViewVC Help
Powered by ViewVC 1.1.26