/[gxemul]/trunk/src/devices/dev_footbridge.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 /trunk/src/devices/dev_footbridge.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 18 - (hide annotations)
Mon Oct 8 16:19:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 12863 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1004 2005/10/27 14:01:10 debug Exp $
20051011        Passing -A as the default boot arg for CATS (works fine with
                OpenBSD/cats).
20051012	Fixing the VGA cursor offset bug, and speeding up framebuffer
		redraws if character cells contain the same thing as during
		the last redraw.
20051013	Adding a slow strd ARM instruction hack.
20051017	Minor updates: Adding a dummy i80321 Verde controller (for
		XScale emulation), fixing the disassembly of the ARM "ldrd"
		instruction, adding "support" for less-than-4KB pages for ARM
		(by not adding them to translation tables).
20051020	Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints
		some boot messages on an emulated Jornada 720.
		Making dev_ram work better with dyntrans (speeds up some things
		quite a bit).
20051021	Automatically generating some of the most common ARM load/store
		multiple instructions.
20051022	Better statistics gathering for the ARM load/store multiple.
		Various other dyntrans and device updates.
20051023	Various minor updates.
20051024	Continuing; minor device and dyntrans fine-tuning. Adding the
		first "reasonable" instruction combination hacks for ARM (the
		cores of NetBSD/cats' memset and memcpy).
20051025	Fixing a dyntrans-related bug in dev_vga. Also changing the
		dyntrans low/high access notification to only be updated on
		writes, not reads. Hopefully it will be enough. (dev_vga in
		charcell mode now seems to work correctly with both reads and
		writes.)
		Experimenting with gathering dyntrans statistics (which parts
		of emulated RAM that are actually executed), and adding
		instruction combination hacks for cache cleaning and a part of
		NetBSD's scanc() function.
20051026	Adding a bitmap for ARM emulation which indicates if a page is
		(specifically) user accessible; loads and stores with the t-
		flag set can now use the translation arrays, which results in
		a measurable speedup.
20051027	Dyntrans updates; adding an extra bitmap array for 32-bit
		emulation modes, speeding up the check whether a physical page
		has any code translations or not (O(n) -> O(1)). Doing a
		similar reduction of O(n) to O(1) by avoiding the scan through
		the translation entries on a translation update (32-bit mode
		only).
		Various other minor hacks.
20051029	Quick release, without any testing at all.

==============  RELEASE 0.3.6.2  ==============


1 dpavlin 14 /*
2     * Copyright (C) 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 18 * $Id: dev_footbridge.c,v 1.26 2005/10/26 14:37:04 debug Exp $
29 dpavlin 14 *
30     * Footbridge. Used in Netwinder and Cats.
31     *
32     * TODO: Most things. For example:
33     *
34 dpavlin 18 * o) Fix the timer TODO (see below).
35     *
36 dpavlin 14 * o) Add actual support for the fcom serial port.
37 dpavlin 18 *
38 dpavlin 14 * o) FIQs.
39 dpavlin 18 *
40     * o) ..
41 dpavlin 14 */
42    
43     #include <stdio.h>
44     #include <stdlib.h>
45     #include <string.h>
46    
47     #include "bus_pci.h"
48     #include "console.h"
49     #include "cpu.h"
50     #include "device.h"
51     #include "devices.h" /* for struct footbridge_data */
52     #include "machine.h"
53     #include "memory.h"
54     #include "misc.h"
55    
56    
57     #include "dc21285reg.h"
58    
59     #define DEV_FOOTBRIDGE_TICK_SHIFT 14
60     #define DEV_FOOTBRIDGE_LENGTH 0x400
61 dpavlin 18 #define TIMER_POLL_THRESHOLD 15
62 dpavlin 14
63    
64     /*
65     * dev_footbridge_tick():
66     *
67     * The 4 footbridge timers should decrease every now and then, and cause
68     * interrupts. Periodic interrupts restart as soon as they are acknowledged,
69     * non-periodic interrupts need to be "reloaded" to restart.
70     */
71     void dev_footbridge_tick(struct cpu *cpu, void *extra)
72     {
73     int i;
74     struct footbridge_data *d = (struct footbridge_data *) extra;
75    
76 dpavlin 18 if (!d->timer_being_read)
77     d->timer_poll_mode = 0;
78    
79 dpavlin 14 for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {
80     int amount = 1 << DEV_FOOTBRIDGE_TICK_SHIFT;
81     if (d->timer_control[i] & TIMER_FCLK_16)
82     amount >>= 4;
83     else if (d->timer_control[i] & TIMER_FCLK_256)
84     amount >>= 8;
85    
86     if (d->timer_tick_countdown[i] == 0)
87     continue;
88    
89     if (d->timer_value[i] > amount)
90     d->timer_value[i] -= amount;
91     else
92     d->timer_value[i] = 0;
93    
94     if (d->timer_value[i] == 0) {
95     d->timer_tick_countdown[i] --;
96     if (d->timer_tick_countdown[i] > 0)
97     continue;
98    
99     if (d->timer_control[i] & TIMER_ENABLE)
100     cpu_interrupt(cpu, IRQ_TIMER_1 + i);
101     d->timer_tick_countdown[i] = 0;
102     }
103     }
104     }
105    
106    
107     /*
108     * dev_footbridge_isa_access():
109     *
110     * NetBSD seems to read 0x79000000 to find out which ISA interrupt occurred,
111     * a quicker way than dealing with legacy 0x20/0xa0 ISA ports.
112     */
113     int dev_footbridge_isa_access(struct cpu *cpu, struct memory *mem,
114     uint64_t relative_addr, unsigned char *data, size_t len,
115     int writeflag, void *extra)
116     {
117     /* struct footbridge_data *d = extra; */
118     uint64_t idata = 0, odata = 0;
119     int x;
120    
121 dpavlin 18 if (writeflag == MEM_WRITE) {
122     idata = memory_readmax64(cpu, data, len);
123 dpavlin 14 fatal("[ footbridge_isa: WARNING/TODO: write! ]\n");
124 dpavlin 18 }
125 dpavlin 14
126     /*
127     * NetBSD seems to want a value of 0x20 + x, where x is the highest
128     * priority ISA interrupt which is currently asserted and not masked.
129     */
130    
131     for (x=0; x<16; x++) {
132     if (x == 2)
133     continue;
134     if (x < 8 && (cpu->machine->isa_pic_data.pic1->irr &
135     ~cpu->machine->isa_pic_data.pic1->ier &
136     (1 << x)))
137     break;
138     if (x >= 8 && (cpu->machine->isa_pic_data.pic2->irr &
139     ~cpu->machine->isa_pic_data.pic2->ier &
140     (1 << (x&7))))
141     break;
142     }
143    
144     if (x == 16)
145     fatal("_\n_ SPORADIC but INVALID ISA interrupt\n_\n");
146    
147     odata = 0x20 + (x & 15);
148    
149     if (writeflag == MEM_READ)
150     memory_writemax64(cpu, data, len, odata);
151    
152     return 1;
153     }
154    
155    
156     /*
157     * dev_footbridge_pci_access():
158     *
159     * The Footbridge PCI configuration space is not implemented as "address +
160     * data port" pair, but instead a 24-bit (16 MB) chunk of physical memory
161     * decodes as the address. This function translates that into bus_pci_access
162     * calls.
163     */
164     int dev_footbridge_pci_access(struct cpu *cpu, struct memory *mem,
165     uint64_t relative_addr, unsigned char *data, size_t len,
166     int writeflag, void *extra)
167     {
168     struct footbridge_data *d = extra;
169     uint64_t idata = 0, odata = 0;
170     int bus, device, function, regnr, res;
171     uint64_t pci_word;
172    
173 dpavlin 18 if (writeflag == MEM_WRITE)
174     idata = memory_readmax64(cpu, data, len);
175 dpavlin 14
176     bus = (relative_addr >> 16) & 0xff;
177     device = (relative_addr >> 11) & 0x1f;
178     function = (relative_addr >> 8) & 0x7;
179     regnr = relative_addr & 0xff;
180    
181     if (bus == 255) {
182     fatal("[ footbridge DEBUG ERROR: bus 255 unlikely,"
183     " pc (might not be updated) = 0x%08x ]\n", (int)cpu->pc);
184     exit(1);
185     }
186    
187     debug("[ footbridge_pci: %s bus %i, device %i, function "
188     "%i, register %i ]\n", writeflag == MEM_READ? "read from"
189     : "write to", bus, device, function, regnr);
190    
191     if (d->pcibus == NULL) {
192     fatal("dev_footbridge_pci_access(): no PCI bus?\n");
193     return 0;
194     }
195    
196     pci_word = relative_addr & 0x00ffffff;
197    
198     res = bus_pci_access(cpu, mem, BUS_PCI_ADDR,
199     &pci_word, MEM_WRITE, d->pcibus);
200     if (writeflag == MEM_READ) {
201     res = bus_pci_access(cpu, mem, BUS_PCI_DATA,
202     &pci_word, MEM_READ, d->pcibus);
203     odata = pci_word;
204     } else {
205     pci_word = idata;
206     res = bus_pci_access(cpu, mem, BUS_PCI_DATA,
207     &pci_word, MEM_WRITE, d->pcibus);
208     }
209    
210     if (writeflag == MEM_READ)
211     memory_writemax64(cpu, data, len, odata);
212    
213     return 1;
214     }
215    
216    
217     /*
218     * dev_footbridge_access():
219     *
220     * The DC21285 registers.
221     */
222     int dev_footbridge_access(struct cpu *cpu, struct memory *mem,
223     uint64_t relative_addr, unsigned char *data, size_t len,
224     int writeflag, void *extra)
225     {
226     struct footbridge_data *d = extra;
227     uint64_t idata = 0, odata = 0;
228     int timer_nr = 0;
229    
230 dpavlin 18 if (writeflag == MEM_WRITE)
231     idata = memory_readmax64(cpu, data, len);
232 dpavlin 14
233     if (relative_addr >= TIMER_1_LOAD && relative_addr <= TIMER_4_CLEAR) {
234     timer_nr = (relative_addr >> 5) & (N_FOOTBRIDGE_TIMERS - 1);
235     relative_addr &= ~0x060;
236     }
237    
238     switch (relative_addr) {
239    
240     case VENDOR_ID:
241     odata = 0x1011; /* DC21285_VENDOR_ID */
242     break;
243    
244     case DEVICE_ID:
245     odata = 0x1065; /* DC21285_DEVICE_ID */
246     break;
247    
248     case REVISION:
249     odata = 3; /* footbridge revision number */
250     break;
251    
252     case UART_DATA:
253     if (writeflag == MEM_WRITE)
254     console_putchar(d->console_handle, idata);
255     break;
256    
257     case UART_RX_STAT:
258     /* TODO */
259     odata = 0;
260     break;
261    
262     case UART_FLAGS:
263     odata = UART_TX_EMPTY;
264     break;
265    
266     case IRQ_STATUS:
267     if (writeflag == MEM_READ)
268     odata = d->irq_status & d->irq_enable;
269     else {
270     fatal("[ WARNING: footbridge write to irq status? ]\n");
271     exit(1);
272     }
273     break;
274    
275     case IRQ_RAW_STATUS:
276     if (writeflag == MEM_READ)
277     odata = d->irq_status;
278     else {
279     fatal("[ footbridge write to irq_raw_status ]\n");
280     exit(1);
281     }
282     break;
283    
284     case IRQ_ENABLE_SET:
285     if (writeflag == MEM_WRITE) {
286     d->irq_enable |= idata;
287     cpu_interrupt(cpu, 64);
288     } else {
289 dpavlin 18 odata = d->irq_enable;
290 dpavlin 14 fatal("[ WARNING: footbridge read from "
291     "ENABLE SET? ]\n");
292     exit(1);
293     }
294     break;
295    
296     case IRQ_ENABLE_CLEAR:
297     if (writeflag == MEM_WRITE) {
298     d->irq_enable &= ~idata;
299     cpu_interrupt(cpu, 64);
300     } else {
301 dpavlin 18 odata = d->irq_enable;
302 dpavlin 14 fatal("[ WARNING: footbridge read from "
303     "ENABLE CLEAR? ]\n");
304     exit(1);
305     }
306     break;
307    
308     case FIQ_STATUS:
309     if (writeflag == MEM_READ)
310     odata = d->fiq_status & d->fiq_enable;
311     else {
312     fatal("[ WARNING: footbridge write to fiq status? ]\n");
313     exit(1);
314     }
315     break;
316    
317     case FIQ_RAW_STATUS:
318     if (writeflag == MEM_READ)
319     odata = d->fiq_status;
320     else {
321     fatal("[ footbridge write to fiq_raw_status ]\n");
322     exit(1);
323     }
324     break;
325    
326     case FIQ_ENABLE_SET:
327     if (writeflag == MEM_WRITE)
328     d->fiq_enable |= idata;
329     break;
330    
331     case FIQ_ENABLE_CLEAR:
332     if (writeflag == MEM_WRITE)
333     d->fiq_enable &= ~idata;
334     break;
335    
336     case TIMER_1_LOAD:
337     if (writeflag == MEM_READ)
338     odata = d->timer_load[timer_nr];
339     else {
340     d->timer_value[timer_nr] =
341     d->timer_load[timer_nr] = idata & TIMER_MAX_VAL;
342     debug("[ footbridge: timer %i (1-based), value %i ]\n",
343     timer_nr + 1, (int)d->timer_value[timer_nr]);
344     d->timer_tick_countdown[timer_nr] = 1;
345     cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);
346     }
347     break;
348    
349     case TIMER_1_VALUE:
350     if (writeflag == MEM_READ) {
351 dpavlin 18 /*
352     * TODO: This is INCORRECT! but speeds up NetBSD
353     * and OpenBSD boot sequences. A better solution
354     * would be to only call dev_footbridge_tick() if
355     * the timer is polled "very often" (such as during
356     * bootup), but not during normal operation.
357     */
358     d->timer_being_read = 1;
359     d->timer_poll_mode ++;
360     if (d->timer_poll_mode > TIMER_POLL_THRESHOLD)
361     dev_footbridge_tick(cpu, d);
362 dpavlin 14 odata = d->timer_value[timer_nr];
363 dpavlin 18 d->timer_being_read = 0;
364 dpavlin 14 } else
365     d->timer_value[timer_nr] = idata & TIMER_MAX_VAL;
366     break;
367    
368     case TIMER_1_CONTROL:
369     if (writeflag == MEM_READ)
370     odata = d->timer_control[timer_nr];
371     else {
372     d->timer_control[timer_nr] = idata;
373     if (idata & TIMER_FCLK_16 &&
374     idata & TIMER_FCLK_256) {
375     fatal("TODO: footbridge timer: "
376     "both 16 and 256?\n");
377     exit(1);
378     }
379     if (idata & TIMER_ENABLE) {
380     d->timer_value[timer_nr] =
381     d->timer_load[timer_nr];
382     d->timer_tick_countdown[timer_nr] = 1;
383     }
384     cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);
385     }
386     break;
387    
388     case TIMER_1_CLEAR:
389     if (d->timer_control[timer_nr] & TIMER_MODE_PERIODIC) {
390     d->timer_value[timer_nr] = d->timer_load[timer_nr];
391     d->timer_tick_countdown[timer_nr] = 1;
392     }
393     cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);
394     break;
395    
396     default:if (writeflag == MEM_READ) {
397     fatal("[ footbridge: read from 0x%x ]\n",
398     (int)relative_addr);
399     } else {
400     fatal("[ footbridge: write to 0x%x: 0x%llx ]\n",
401     (int)relative_addr, (long long)idata);
402     }
403     }
404    
405     if (writeflag == MEM_READ)
406     memory_writemax64(cpu, data, len, odata);
407    
408     return 1;
409     }
410    
411    
412     /*
413     * devinit_footbridge():
414     */
415     int devinit_footbridge(struct devinit *devinit)
416     {
417     struct footbridge_data *d;
418     uint64_t pci_addr = 0x7b000000;
419     int i;
420    
421     d = malloc(sizeof(struct footbridge_data));
422     if (d == NULL) {
423     fprintf(stderr, "out of memory\n");
424     exit(1);
425     }
426     memset(d, 0, sizeof(struct footbridge_data));
427    
428     /* DC21285 register access: */
429     memory_device_register(devinit->machine->memory, devinit->name,
430     devinit->addr, DEV_FOOTBRIDGE_LENGTH,
431     dev_footbridge_access, d, MEM_DEFAULT, NULL);
432    
433     /* ISA interrupt status word: */
434     memory_device_register(devinit->machine->memory, "footbridge_isa",
435     0x79000000, 8, dev_footbridge_isa_access, d, MEM_DEFAULT, NULL);
436    
437     /* The "fcom" console: */
438     d->console_handle = console_start_slave(devinit->machine, "fcom");
439    
440     /* A PCI bus: */
441     d->pcibus = bus_pci_init(devinit->irq_nr);
442    
443     /* ... with some default devices for known machine types: */
444     switch (devinit->machine->machine_type) {
445     case MACHINE_CATS:
446     bus_pci_add(devinit->machine, d->pcibus,
447     devinit->machine->memory, 0xc0, 7, 0,
448     pci_ali_m1543_init, pci_ali_m1543_rr);
449 dpavlin 18 /* bus_pci_add(devinit->machine, d->pcibus,
450     devinit->machine->memory, 0xc0, 10, 0,
451     pci_dec21143_init, pci_dec21143_rr); */
452 dpavlin 14 bus_pci_add(devinit->machine, d->pcibus,
453     devinit->machine->memory, 0xc0, 16, 0,
454     pci_ali_m5229_init, pci_ali_m5229_rr);
455     break;
456     case MACHINE_NETWINDER:
457     bus_pci_add(devinit->machine, d->pcibus,
458     devinit->machine->memory, 0xc0, 11, 0,
459     pci_symphony_83c553_init, pci_symphony_83c553_rr);
460     bus_pci_add(devinit->machine, d->pcibus,
461     devinit->machine->memory, 0xc0, 11, 1,
462     pci_symphony_82c105_init, pci_symphony_82c105_rr);
463     break;
464     default:fatal("footbridge: unimplemented machine type.\n");
465     exit(1);
466     }
467    
468     /* PCI configuration space: */
469     memory_device_register(devinit->machine->memory,
470     "footbridge_pci", pci_addr, 0x1000000,
471     dev_footbridge_pci_access, d, MEM_DEFAULT, NULL);
472    
473     /* Timer ticks: */
474     for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {
475     d->timer_control[i] = TIMER_MODE_PERIODIC;
476     d->timer_load[i] = TIMER_MAX_VAL;
477     }
478     machine_add_tickfunction(devinit->machine,
479     dev_footbridge_tick, d, DEV_FOOTBRIDGE_TICK_SHIFT);
480    
481     devinit->return_ptr = d;
482     return 1;
483     }
484    

  ViewVC Help
Powered by ViewVC 1.1.26