/[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

Annotation of /upstream/0.3.6.1/src/devices/dev_vr41xx.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 17 - (hide 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 dpavlin 4 /*
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 dpavlin 12 * $Id: dev_vr41xx.c,v 1.30 2005/08/05 09:11:48 debug Exp $
29 dpavlin 4 *
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 dpavlin 12 char tmps[100];
548 dpavlin 4 struct vr41xx_data *d = malloc(sizeof(struct vr41xx_data));
549 dpavlin 12
550 dpavlin 4 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 dpavlin 12 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 dpavlin 4 } else {
596     /* This is used by Linux and NetBSD: */
597 dpavlin 12 snprintf(tmps, sizeof(tmps), "ns16550 irq=%i addr=0x%x "
598     "name2=serial", 8+VRIP_INTR_SIU, 0xc000000);
599     device_add(machine, tmps);
600 dpavlin 4 }
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