/[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 30 - (hide annotations)
Mon Oct 8 16:20:40 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 12995 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1325 2006/08/15 15:38:37 debug Exp $
20060723	More Transputer instructions (pfix, nfix, opr, mint, ldl, ldlp,
		eqc, rev, ajw, stl, stlf, sthf, sub, ldnl, ldnlp, ldpi, move,
		wcnt, add, bcnt).
		Adding more SPARC instructions (andcc, addcc, bl, rdpr).
		Progress on the igsfb framebuffer used by NetBSD/netwinder.
		Enabling 8-bit fills in dev_fb.
		NetBSD/netwinder 3.0.1 can now run from a disk image :-)
20060724	Cleanup/performance fix for 64-bit virtual translation table
		updates (by removing the "timestamp" stuff). A full NetBSD/pmax
		3.0.1 install for R4400 has dropped from 667 seconds to 584 :)
		Fixing the igsfb "almost vga" color (it is 24-bit, not 18-bit).
		Adding some MIPS instruction combinations (3*lw, and 3*addu).
		The 8048 keyboard now turns off interrupt enable between the
		KBR_ACK and the KBR_RSTDONE, to work better with Linux 2.6.
		Not causing PPC DEC interrupts if PPC_NO_DEC is set for a
		specific CPU; NetBSD/bebox gets slightly further than before.
		Adding some more SPARC instructions: branches, udiv.
20060725	Refreshing dev_pckbc.c a little.
		Cleanups for the SH emulation mode, and adding the first
		"compact" (16-bit) instructions: various simple movs, nop,
		shll, stc, or, ldc.
20060726	Adding dummy "pcn" (AMD PCnet NIC) PCI glue.
20060727	Various cleanups; removing stuff from cpu.h, such as
		running_translated (not really meaningful anymore), and
		page flags (breaking into the debugger clears all translations
		anyway).
		Minor MIPS instruction combination updates.
20060807	Expanding the 3*sw and 3*lw MIPS instruction combinations to
		work with 2* and 4* too, resulting in a minor performance gain.
		Implementing a usleep hack for the RM52xx/MIPS32/MIPS64 "wait"
		instruction (when emulating 1 cpu).
20060808	Experimenting with some more MIPS instruction combinations.
		Implementing support for showing a (hardcoded 12x22) text
		cursor in igsfb.
20060809	Simplifying the NetBSD/evbmips (Malta) install instructions
		somewhat (by using a NetBSD/pmax ramdisk install kernel).
20060812	Experimenting more with the MIPS 'wait' instruction.
		PCI configuration register writes can now be handled, which
		allow PCI IDE controllers to work with NetBSD/Malta 3.0.1 and
		NetBSD/cobalt 3.0.1. (Previously only NetBSD 2.1 worked.)
20060813	Updating dev_gt.c based on numbers from Alec Voropay, to enable
		Linux 2.6 to use PCI on Malta.
		Continuing on Algor interrupt stuff.
20060814	Adding support for routing ISA interrupts to two different
		interrupts, making it possible to run NetBSD/algor :-)
20060814-15	Testing for the release.

==============  RELEASE 0.4.2  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26