/[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 34 - (hide annotations)
Mon Oct 8 16:21:17 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 16085 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1480 2007/02/19 01:34:42 debug Exp $
20061029	Changing usleep(1) calls in the debugger to usleep(10000)
20061107	Adding a new disk image option (-d o...) which sets the ISO9660
		filesystem base offset; also making some other hacks to allow
		NetBSD/dreamcast and homebrew demos/games to boot directly
		from a filesystem image.
		Moving Dreamcast-specific stuff in the documentation to its
		own page (dreamcast.html).
		Adding a border to the Dreamcast PVR framebuffer.
20061108	Adding a -T command line option (again?), for halting the
		emulator on unimplemented memory accesses.
20061109	Continuing on various SH4 and Dreamcast related things.
		The emulator should now halt on more unimplemented device
		accesses, instead of just printing a warning, forcing me to
		actually implement missing stuff :)
20061111	Continuing on SH4 and Dreamcast stuff.
		Adding a bogus Landisk (SH4) machine mode.
20061112	Implementing some parts of the Dreamcast GDROM device. With
		some ugly hacks, NetBSD can (barely) mount an ISO image.
20061113	NetBSD/dreamcast now starts booting from the Live CD image,
		but crashes randomly quite early on in the boot process.
20061122	Beginning on a skeleton interrupt.h and interrupt.c for the
		new interrupt subsystem.
20061124	Continuing on the new interrupt system; taking the first steps
		to attempt to connect CPUs (SuperH and MIPS) and devices
		(dev_cons and SH4 timer interrupts) to it. Many things will
		probably break from now on.
20061125	Converting dev_ns16550, dev_8253 to the new interrupt system.
		Attempting to begin to convert the ISA bus.
20061130	Incorporating a patch from Brian Foley for the configure
		script, which checks for X11 libs in /usr/X11R6/lib64 (which
		is used on some Linux systems).
20061227	Adding a note in the man page about booting from Dreamcast
		CDROM images (i.e. that no external kernel is needed).
20061229	Continuing on the interrupt system rewrite: beginning to
		convert more devices, adding abort() calls for legacy interrupt
		system calls so that everything now _has_ to be rewritten!
		Almost all machine modes are now completely broken.
20061230	More progress on removing old interrupt code, mostly related
		to the ISA bus + devices, the LCA bus (on AlphaBook1), and
		the Footbridge bus (for CATS). And some minor PCI stuff.
		Connecting the ARM cpu to the new interrupt system.
		The CATS, NetWinder, and QEMU_MIPS machine modes now work with
		the new interrupt system :)
20061231	Connecting PowerPC CPUs to the new interrupt system.
		Making PReP machines (IBM 6050) work again.
		Beginning to convert the GT PCI controller (for e.g. Malta
		and Cobalt emulation). Some things work, but not everything.
		Updating Copyright notices for 2007.
20070101	Converting dev_kn02 from legacy style to devinit; the 3max
		machine mode now works with the new interrupt system :-]
20070105	Beginning to convert the SGI O2 machine to the new interrupt
		system; finally converting O2 (IP32) devices to devinit, etc.
20070106	Continuing on the interrupt system redesign/rewrite; KN01
		(PMAX), KN230, and Dreamcast ASIC interrupts should work again,
		moving out stuff from machine.h and devices.h into the
		corresponding devices, beginning the rewrite of i80321
		interrupts, etc.
20070107	Beginning on the rewrite of Eagle interrupt stuff (PReP, etc).
20070117	Beginning the rewrite of Algor (V3) interrupts (finally
		changing dev_v3 into devinit style).
20070118	Removing the "bus" registry concept from machine.h, because
		it was practically meaningless.
		Continuing on the rewrite of Algor V3 ISA interrupts.
20070121	More work on Algor interrupts; they are now working again,
		well enough to run NetBSD/algor. :-)
20070122	Converting VR41xx (HPCmips) interrupts. NetBSD/hpcmips
		can be installed using the new interrupt system :-)
20070123	Making the testmips mode work with the new interrupt system.
20070127	Beginning to convert DEC5800 devices to devinit, and to the
		new interrupt system.
		Converting Playstation 2 devices to devinit, and converting
		the interrupt system. Also fixing a severe bug: the interrupt
		mask register on Playstation 2 is bitwise _toggled_ on writes.
20070128	Removing the dummy NetGear machine mode and the 8250 device
		(which was only used by the NetGear machine).
		Beginning to convert the MacPPC GC (Grand Central) interrupt
		controller to the new interrupt system.
		Converting Jazz interrupts (PICA61 etc.) to the new interrupt
		system. NetBSD/arc can be installed again :-)
		Fixing the JAZZ timer (hardcoding it at 100 Hz, works with
		NetBSD and it is better than a completely dummy timer as it
		was before).
		Converting dev_mp to the new interrupt system, although I
		haven't had time to actually test it yet.
		Completely removing src/machines/interrupts.c, cpu_interrupt
		and cpu_interrupt_ack in src/cpu.c, and
		src/include/machine_interrupts.h! Adding fatal error messages
		+ abort() in the few places that are left to fix.
		Converting dev_z8530 to the new interrupt system.
		FINALLY removing the md_int struct completely from the
		machine struct.
		SH4 fixes (adding a PADDR invalidation in the ITLB replacement
		code in memory_sh.c); the NetBSD/dreamcast LiveCD now runs
		all the way to the login prompt, and can be interacted with :-)
		Converting the CPC700 controller (PCI and interrupt controller
		for PM/PPC) to the new interrupt system.
20070129	Fixing MACE ISA interrupts (SGI IP32 emulation). Both NetBSD/
		sgimips' and OpenBSD/sgi's ramdisk kernels can now be
		interacted with again.
20070130	Moving out the MIPS multi_lw and _sw instruction combinations
		so that they are auto-generated at compile time instead.
20070131	Adding detection of amd64/x86_64 hosts in the configure script,
		for doing initial experiments (again :-) with native code
		generation.
		Adding a -k command line option to set the size of the dyntrans
		cache, and a -B command line option to disable native code
		generation, even if GXemul was compiled with support for
		native code generation for the specific host CPU architecture.
20070201	Experimenting with a skeleton for native code generation.
		Changing the default behaviour, so that native code generation
		is now disabled by default, and has to be enabled by using
		-b on the command line.
20070202	Continuing the native code generation experiments.
		Making PCI interrupts work for Footbridge again.
20070203	More native code generation experiments.
		Removing most of the native code generation experimental code,
		it does not make sense to include any quick hacks like this.
		Minor cleanup/removal of some more legacy MIPS interrupt code.
20070204	Making i80321 interrupts work again (for NetBSD/evbarm etc.),
		and fixing the timer at 100 Hz.
20070206	Experimenting with removing the wdc interrupt slowness hack.
20070207	Lowering the number of dyntrans TLB entries for MIPS from
		192 to 128, resulting in a minor speed improvement.
		Minor optimization to the code invalidation routine in
		cpu_dyntrans.c.
20070208	Increasing (experimentally) the nr of dyntrans instructions per
		loop from 60 to 120.
20070210	Commenting out (experimentally) the dyntrans_device_danger
		detection in memory_rw.c.
		Changing the testmips and baremips machines to use a revision 2
		MIPS64 CPU by default, instead of revision 1.
		Removing the dummy i960, IA64, x86, AVR32, and HP PA-RISC
		files, the PC bios emulation, and the Olivetti M700 (ARC) and
		db64360 emulation modes.
20070211	Adding an "mp" demo to the demos directory, which tests the
		SMP functionality of the testmips machine.
		Fixing PReP interrupts some more. NetBSD/prep now boots again.
20070216	Adding a "nop workaround" for booting Mach/PMAX to the
		documentation; thanks to Artur Bujdoso for the values.
		Converting more of the MacPPC interrupt stuff to the new
		system.
		Beginning to convert BeBox interrupts to the new system.
		PPC603e should NOT have the PPC_NO_DEC flag! Removing it.
		Correcting BeBox clock speed (it was set to 100 in the NetBSD
		bootinfo block, but should be 33000000/4), allowing NetBSD
		to start without using the (incorrect) PPC_NO_DEC hack.
20070217	Implementing (slow) AltiVec vector loads and stores, allowing
		NetBSD/macppc to finally boot using the GENERIC kernel :-)
		Updating the documentation with install instructions for
		NetBSD/macppc.
20070218-19	Regression testing for the release.

==============  RELEASE 0.4.4  ==============


1 dpavlin 14 /*
2 dpavlin 34 * Copyright (C) 2005-2007 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 34 * $Id: dev_footbridge.c,v 1.55 2007/02/03 16:18:56 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 dpavlin 34 * as guest OSes.)
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 dpavlin 32 #include "timer.h"
53 dpavlin 14
54    
55     #include "dc21285reg.h"
56    
57     #define DEV_FOOTBRIDGE_TICK_SHIFT 14
58     #define DEV_FOOTBRIDGE_LENGTH 0x400
59    
60 dpavlin 34 #define N_FOOTBRIDGE_TIMERS 4
61 dpavlin 14
62 dpavlin 34 struct footbridge_data {
63     struct interrupt irq;
64    
65     struct pci_data *pcibus;
66    
67     int console_handle;
68    
69     uint32_t timer_load[N_FOOTBRIDGE_TIMERS];
70     uint32_t timer_value[N_FOOTBRIDGE_TIMERS];
71     uint32_t timer_control[N_FOOTBRIDGE_TIMERS];
72    
73     struct interrupt timer_irq[N_FOOTBRIDGE_TIMERS];
74     struct timer *timer[N_FOOTBRIDGE_TIMERS];
75     int pending_timer_interrupts[N_FOOTBRIDGE_TIMERS];
76    
77     int irq_asserted;
78    
79     uint32_t irq_status;
80     uint32_t irq_enable;
81    
82     uint32_t fiq_status;
83     uint32_t fiq_enable;
84     };
85    
86    
87 dpavlin 32 static void timer_tick0(struct timer *t, void *extra)
88     { ((struct footbridge_data *)extra)->pending_timer_interrupts[0] ++; }
89     static void timer_tick1(struct timer *t, void *extra)
90     { ((struct footbridge_data *)extra)->pending_timer_interrupts[1] ++; }
91     static void timer_tick2(struct timer *t, void *extra)
92     { ((struct footbridge_data *)extra)->pending_timer_interrupts[2] ++; }
93     static void timer_tick3(struct timer *t, void *extra)
94     { ((struct footbridge_data *)extra)->pending_timer_interrupts[3] ++; }
95    
96    
97     static void reload_timer_value(struct cpu *cpu, struct footbridge_data *d,
98     int timer_nr)
99     {
100     double freq = (double)cpu->machine->emulated_hz;
101     int cycles = d->timer_load[timer_nr];
102    
103     if (d->timer_control[timer_nr] & TIMER_FCLK_16)
104     cycles <<= 4;
105     else if (d->timer_control[timer_nr] & TIMER_FCLK_256)
106     cycles <<= 8;
107     freq /= (double)cycles;
108    
109     d->timer_value[timer_nr] = d->timer_load[timer_nr];
110    
111     /* printf("%i: %i -> %f Hz\n", timer_nr,
112     d->timer_load[timer_nr], freq); */
113    
114     if (d->timer[timer_nr] == NULL) {
115     switch (timer_nr) {
116     case 0: d->timer[0] = timer_add(freq, timer_tick0, d); break;
117     case 1: d->timer[1] = timer_add(freq, timer_tick1, d); break;
118     case 2: d->timer[2] = timer_add(freq, timer_tick2, d); break;
119     case 3: d->timer[3] = timer_add(freq, timer_tick3, d); break;
120     }
121     } else {
122     timer_update_frequency(d->timer[timer_nr], freq);
123     }
124     }
125    
126    
127 dpavlin 14 /*
128     * dev_footbridge_tick():
129     *
130 dpavlin 32 * The 4 footbridge timers should decrease and cause interrupts. Periodic
131     * interrupts restart as soon as they are acknowledged, non-periodic
132     * interrupts need to be "reloaded" to restart.
133     *
134     * TODO: Hm. I thought I had solved this, but it didn't quite work.
135     * This needs to be re-checked against documentation, sometime.
136 dpavlin 14 */
137     void dev_footbridge_tick(struct cpu *cpu, void *extra)
138     {
139     int i;
140     struct footbridge_data *d = (struct footbridge_data *) extra;
141    
142     for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {
143 dpavlin 32 if (d->timer_control[i] & TIMER_ENABLE) {
144     if (d->pending_timer_interrupts[i] > 0) {
145     d->timer_value[i] = random() % d->timer_load[i];
146 dpavlin 34 INTERRUPT_ASSERT(d->timer_irq[i]);
147 dpavlin 32 }
148 dpavlin 14 }
149     }
150     }
151    
152    
153     /*
154 dpavlin 34 * footbridge_interrupt_assert():
155     */
156     void footbridge_interrupt_assert(struct interrupt *interrupt)
157     {
158     struct footbridge_data *d = (struct footbridge_data *) interrupt->extra;
159     d->irq_status |= interrupt->line;
160    
161     if ((d->irq_status & d->irq_enable) && !d->irq_asserted) {
162     d->irq_asserted = 1;
163     INTERRUPT_ASSERT(d->irq);
164     }
165     }
166    
167    
168     /*
169     * footbridge_interrupt_deassert():
170     */
171     void footbridge_interrupt_deassert(struct interrupt *interrupt)
172     {
173     struct footbridge_data *d = (struct footbridge_data *) interrupt->extra;
174     d->irq_status &= ~interrupt->line;
175    
176     if (!(d->irq_status & d->irq_enable) && d->irq_asserted) {
177     d->irq_asserted = 0;
178     INTERRUPT_DEASSERT(d->irq);
179     }
180     }
181    
182    
183     /*
184 dpavlin 14 * dev_footbridge_isa_access():
185     *
186 dpavlin 20 * Reading the byte at 0x79000000 is a quicker way to figure out which ISA
187     * interrupt has occurred (and acknowledging it at the same time), than
188     * dealing with the legacy 0x20/0xa0 ISA ports.
189 dpavlin 14 */
190 dpavlin 22 DEVICE_ACCESS(footbridge_isa)
191 dpavlin 14 {
192     /* struct footbridge_data *d = extra; */
193     uint64_t idata = 0, odata = 0;
194     int x;
195    
196 dpavlin 18 if (writeflag == MEM_WRITE) {
197     idata = memory_readmax64(cpu, data, len);
198 dpavlin 14 fatal("[ footbridge_isa: WARNING/TODO: write! ]\n");
199 dpavlin 18 }
200 dpavlin 14
201 dpavlin 20 x = cpu->machine->isa_pic_data.last_int;
202     if (x < 8)
203     odata = cpu->machine->isa_pic_data.pic1->irq_base + x;
204     else
205     odata = cpu->machine->isa_pic_data.pic2->irq_base + x - 8;
206 dpavlin 14
207     if (writeflag == MEM_READ)
208     memory_writemax64(cpu, data, len, odata);
209    
210     return 1;
211     }
212    
213    
214     /*
215 dpavlin 30 * Reset pin at ISA port 0x338, at least in the NetWinder:
216     *
217     * TODO: NOT WORKING YET!
218     */
219     DEVICE_ACCESS(footbridge_reset)
220     {
221     uint64_t idata = 0;
222    
223     if (writeflag == MEM_WRITE) {
224     idata = memory_readmax64(cpu, data, len);
225     if (idata & 0x40) {
226     debug("[ footbridge_reset: GP16: Halting. ]\n");
227     cpu->running = 0;
228     exit(1);
229     }
230     }
231    
232     return 1;
233     }
234    
235    
236     /*
237 dpavlin 14 * dev_footbridge_pci_access():
238     *
239 dpavlin 22 * The Footbridge PCI configuration space is implemented as a direct memory
240     * space (i.e. not one port for addr and one port for data). This function
241     * translates that into bus_pci calls.
242 dpavlin 14 */
243 dpavlin 22 DEVICE_ACCESS(footbridge_pci)
244 dpavlin 14 {
245     struct footbridge_data *d = extra;
246     uint64_t idata = 0, odata = 0;
247 dpavlin 22 int bus, dev, func, reg;
248 dpavlin 14
249 dpavlin 18 if (writeflag == MEM_WRITE)
250 dpavlin 22 idata = memory_readmax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN);
251 dpavlin 14
252 dpavlin 22 /* Decompose the (direct) address into its components: */
253     bus_pci_decompose_1(relative_addr, &bus, &dev, &func, &reg);
254     bus_pci_setaddr(cpu, d->pcibus, bus, dev, func, reg);
255 dpavlin 14
256     if (bus == 255) {
257     fatal("[ footbridge DEBUG ERROR: bus 255 unlikely,"
258     " pc (might not be updated) = 0x%08x ]\n", (int)cpu->pc);
259     exit(1);
260     }
261    
262 dpavlin 22 debug("[ footbridge pci: %s bus %i, device %i, function %i, register "
263     "%i ]\n", writeflag == MEM_READ? "read from" : "write to", bus,
264     dev, func, reg);
265 dpavlin 14
266 dpavlin 22 bus_pci_data_access(cpu, d->pcibus, writeflag == MEM_READ?
267     &odata : &idata, len, writeflag);
268 dpavlin 14
269     if (writeflag == MEM_READ)
270 dpavlin 22 memory_writemax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN, odata);
271 dpavlin 14
272     return 1;
273     }
274    
275    
276     /*
277     * dev_footbridge_access():
278     *
279     * The DC21285 registers.
280     */
281 dpavlin 22 DEVICE_ACCESS(footbridge)
282 dpavlin 14 {
283     struct footbridge_data *d = extra;
284     uint64_t idata = 0, odata = 0;
285     int timer_nr = 0;
286    
287 dpavlin 18 if (writeflag == MEM_WRITE)
288     idata = memory_readmax64(cpu, data, len);
289 dpavlin 14
290     if (relative_addr >= TIMER_1_LOAD && relative_addr <= TIMER_4_CLEAR) {
291     timer_nr = (relative_addr >> 5) & (N_FOOTBRIDGE_TIMERS - 1);
292     relative_addr &= ~0x060;
293     }
294    
295     switch (relative_addr) {
296    
297     case VENDOR_ID:
298     odata = 0x1011; /* DC21285_VENDOR_ID */
299     break;
300    
301     case DEVICE_ID:
302     odata = 0x1065; /* DC21285_DEVICE_ID */
303     break;
304    
305 dpavlin 20 case 0x04:
306     case 0x0c:
307     case 0x10:
308     case 0x14:
309     case 0x18:
310     /* TODO. Written to by Linux. */
311     break;
312    
313 dpavlin 14 case REVISION:
314     odata = 3; /* footbridge revision number */
315     break;
316    
317 dpavlin 20 case PCI_ADDRESS_EXTENSION:
318     /* TODO: Written to by Linux. */
319     if (writeflag == MEM_WRITE && idata != 0)
320     fatal("[ footbridge: TODO: write to PCI_ADDRESS_"
321     "EXTENSION: 0x%llx ]\n", (long long)idata);
322     break;
323    
324 dpavlin 22 case SA_CONTROL:
325     /* Read by Linux: */
326     odata = PCI_CENTRAL_FUNCTION;
327     break;
328    
329 dpavlin 14 case UART_DATA:
330     if (writeflag == MEM_WRITE)
331     console_putchar(d->console_handle, idata);
332     break;
333    
334     case UART_RX_STAT:
335     /* TODO */
336     odata = 0;
337     break;
338    
339     case UART_FLAGS:
340     odata = UART_TX_EMPTY;
341     break;
342    
343     case IRQ_STATUS:
344     if (writeflag == MEM_READ)
345     odata = d->irq_status & d->irq_enable;
346     else {
347     fatal("[ WARNING: footbridge write to irq status? ]\n");
348     exit(1);
349     }
350     break;
351    
352     case IRQ_RAW_STATUS:
353     if (writeflag == MEM_READ)
354     odata = d->irq_status;
355     else {
356     fatal("[ footbridge write to irq_raw_status ]\n");
357     exit(1);
358     }
359     break;
360    
361     case IRQ_ENABLE_SET:
362     if (writeflag == MEM_WRITE) {
363     d->irq_enable |= idata;
364 dpavlin 34 if (d->irq_status & d->irq_enable)
365     INTERRUPT_ASSERT(d->irq);
366     else
367     INTERRUPT_DEASSERT(d->irq);
368 dpavlin 14 } else {
369 dpavlin 18 odata = d->irq_enable;
370 dpavlin 14 fatal("[ WARNING: footbridge read from "
371     "ENABLE SET? ]\n");
372     exit(1);
373     }
374     break;
375    
376     case IRQ_ENABLE_CLEAR:
377     if (writeflag == MEM_WRITE) {
378     d->irq_enable &= ~idata;
379 dpavlin 34 if (d->irq_status & d->irq_enable)
380     INTERRUPT_ASSERT(d->irq);
381     else
382     INTERRUPT_DEASSERT(d->irq);
383 dpavlin 14 } else {
384 dpavlin 18 odata = d->irq_enable;
385 dpavlin 14 fatal("[ WARNING: footbridge read from "
386     "ENABLE CLEAR? ]\n");
387     exit(1);
388     }
389     break;
390    
391     case FIQ_STATUS:
392     if (writeflag == MEM_READ)
393     odata = d->fiq_status & d->fiq_enable;
394     else {
395     fatal("[ WARNING: footbridge write to fiq status? ]\n");
396     exit(1);
397     }
398     break;
399    
400     case FIQ_RAW_STATUS:
401     if (writeflag == MEM_READ)
402     odata = d->fiq_status;
403     else {
404     fatal("[ footbridge write to fiq_raw_status ]\n");
405     exit(1);
406     }
407     break;
408    
409     case FIQ_ENABLE_SET:
410     if (writeflag == MEM_WRITE)
411     d->fiq_enable |= idata;
412     break;
413    
414     case FIQ_ENABLE_CLEAR:
415     if (writeflag == MEM_WRITE)
416     d->fiq_enable &= ~idata;
417     break;
418    
419     case TIMER_1_LOAD:
420     if (writeflag == MEM_READ)
421     odata = d->timer_load[timer_nr];
422     else {
423 dpavlin 32 d->timer_load[timer_nr] = idata & TIMER_MAX_VAL;
424     reload_timer_value(cpu, d, timer_nr);
425     /* debug("[ footbridge: timer %i (1-based), "
426     "value %i ]\n", timer_nr + 1,
427     (int)d->timer_value[timer_nr]); */
428 dpavlin 34 INTERRUPT_DEASSERT(d->timer_irq[timer_nr]);
429 dpavlin 14 }
430     break;
431    
432     case TIMER_1_VALUE:
433 dpavlin 32 if (writeflag == MEM_READ)
434 dpavlin 14 odata = d->timer_value[timer_nr];
435 dpavlin 32 else
436 dpavlin 14 d->timer_value[timer_nr] = idata & TIMER_MAX_VAL;
437     break;
438    
439     case TIMER_1_CONTROL:
440     if (writeflag == MEM_READ)
441     odata = d->timer_control[timer_nr];
442     else {
443     d->timer_control[timer_nr] = idata;
444     if (idata & TIMER_FCLK_16 &&
445     idata & TIMER_FCLK_256) {
446     fatal("TODO: footbridge timer: "
447     "both 16 and 256?\n");
448     exit(1);
449     }
450     if (idata & TIMER_ENABLE) {
451 dpavlin 32 reload_timer_value(cpu, d, timer_nr);
452     } else {
453     d->pending_timer_interrupts[timer_nr] = 0;
454 dpavlin 14 }
455 dpavlin 34 INTERRUPT_DEASSERT(d->timer_irq[timer_nr]);
456 dpavlin 14 }
457     break;
458    
459     case TIMER_1_CLEAR:
460     if (d->timer_control[timer_nr] & TIMER_MODE_PERIODIC) {
461 dpavlin 32 reload_timer_value(cpu, d, timer_nr);
462 dpavlin 14 }
463 dpavlin 32
464     if (d->pending_timer_interrupts[timer_nr] > 0) {
465     d->pending_timer_interrupts[timer_nr] --;
466     }
467    
468 dpavlin 34 INTERRUPT_DEASSERT(d->timer_irq[timer_nr]);
469 dpavlin 14 break;
470    
471     default:if (writeflag == MEM_READ) {
472     fatal("[ footbridge: read from 0x%x ]\n",
473     (int)relative_addr);
474     } else {
475     fatal("[ footbridge: write to 0x%x: 0x%llx ]\n",
476     (int)relative_addr, (long long)idata);
477     }
478     }
479    
480     if (writeflag == MEM_READ)
481     memory_writemax64(cpu, data, len, odata);
482    
483     return 1;
484     }
485    
486    
487 dpavlin 22 DEVINIT(footbridge)
488 dpavlin 14 {
489     struct footbridge_data *d;
490 dpavlin 34 char irq_path[300], irq_path_isa[300];
491 dpavlin 14 uint64_t pci_addr = 0x7b000000;
492     int i;
493    
494     d = malloc(sizeof(struct footbridge_data));
495     if (d == NULL) {
496     fprintf(stderr, "out of memory\n");
497     exit(1);
498     }
499     memset(d, 0, sizeof(struct footbridge_data));
500    
501 dpavlin 34 /* Connect to the CPU which this footbridge will interrupt: */
502     INTERRUPT_CONNECT(devinit->interrupt_path, d->irq);
503    
504 dpavlin 14 /* DC21285 register access: */
505     memory_device_register(devinit->machine->memory, devinit->name,
506     devinit->addr, DEV_FOOTBRIDGE_LENGTH,
507 dpavlin 20 dev_footbridge_access, d, DM_DEFAULT, NULL);
508 dpavlin 14
509 dpavlin 20 /* ISA interrupt status/acknowledgement: */
510 dpavlin 14 memory_device_register(devinit->machine->memory, "footbridge_isa",
511 dpavlin 20 0x79000000, 8, dev_footbridge_isa_access, d, DM_DEFAULT, NULL);
512 dpavlin 14
513     /* The "fcom" console: */
514 dpavlin 22 d->console_handle = console_start_slave(devinit->machine, "fcom", 0);
515 dpavlin 14
516 dpavlin 34 /* Register 32 footbridge interrupts: */
517     snprintf(irq_path, sizeof(irq_path), "%s.footbridge",
518     devinit->interrupt_path);
519     for (i=0; i<32; i++) {
520     struct interrupt interrupt_template;
521     char tmpstr[200];
522    
523     memset(&interrupt_template, 0, sizeof(interrupt_template));
524     interrupt_template.line = 1 << i;
525     snprintf(tmpstr, sizeof(tmpstr), "%s.%i", irq_path, i);
526     interrupt_template.name = tmpstr;
527    
528     interrupt_template.extra = d;
529     interrupt_template.interrupt_assert =
530     footbridge_interrupt_assert;
531     interrupt_template.interrupt_deassert =
532     footbridge_interrupt_deassert;
533     interrupt_handler_register(&interrupt_template);
534    
535     /* Connect locally to some interrupts: */
536     if (i>=IRQ_TIMER_1 && i<=IRQ_TIMER_4)
537     INTERRUPT_CONNECT(tmpstr, d->timer_irq[i-IRQ_TIMER_1]);
538     }
539    
540     switch (devinit->machine->machine_type) {
541     case MACHINE_CATS:
542     snprintf(irq_path_isa, sizeof(irq_path_isa), "%s.10", irq_path);
543     break;
544     case MACHINE_NETWINDER:
545     snprintf(irq_path_isa, sizeof(irq_path_isa), "%s.11", irq_path);
546     break;
547     default:fatal("footbridge unimpl machine type\n");
548     exit(1);
549     }
550    
551 dpavlin 14 /* A PCI bus: */
552 dpavlin 20 d->pcibus = bus_pci_init(
553 dpavlin 22 devinit->machine,
554 dpavlin 34 irq_path,
555 dpavlin 20 0x7c000000, /* PCI device io offset */
556     0x80000000, /* PCI device mem offset */
557     0x00000000, /* PCI port base */
558     0x00000000, /* PCI mem base */
559 dpavlin 34 irq_path, /* PCI irq base */
560 dpavlin 20 0x7c000000, /* ISA port base */
561     0x80000000, /* ISA mem base */
562 dpavlin 34 irq_path_isa); /* ISA port base */
563 dpavlin 14
564     /* ... with some default devices for known machine types: */
565     switch (devinit->machine->machine_type) {
566     case MACHINE_CATS:
567     bus_pci_add(devinit->machine, d->pcibus,
568 dpavlin 20 devinit->machine->memory, 0xc0, 7, 0, "ali_m1543");
569 dpavlin 14 bus_pci_add(devinit->machine, d->pcibus,
570 dpavlin 20 devinit->machine->memory, 0xc0, 10, 0, "dec21143");
571     bus_pci_add(devinit->machine, d->pcibus,
572     devinit->machine->memory, 0xc0, 16, 0, "ali_m5229");
573 dpavlin 14 break;
574     case MACHINE_NETWINDER:
575     bus_pci_add(devinit->machine, d->pcibus,
576 dpavlin 20 devinit->machine->memory, 0xc0, 11, 0, "symphony_83c553");
577 dpavlin 14 bus_pci_add(devinit->machine, d->pcibus,
578 dpavlin 20 devinit->machine->memory, 0xc0, 11, 1, "symphony_82c105");
579 dpavlin 30 memory_device_register(devinit->machine->memory,
580     "footbridge_reset", 0x7c000338, 1,
581     dev_footbridge_reset_access, d, DM_DEFAULT, NULL);
582 dpavlin 14 break;
583     default:fatal("footbridge: unimplemented machine type.\n");
584     exit(1);
585     }
586    
587     /* PCI configuration space: */
588     memory_device_register(devinit->machine->memory,
589     "footbridge_pci", pci_addr, 0x1000000,
590 dpavlin 20 dev_footbridge_pci_access, d, DM_DEFAULT, NULL);
591 dpavlin 14
592     /* Timer ticks: */
593     for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {
594     d->timer_control[i] = TIMER_MODE_PERIODIC;
595     d->timer_load[i] = TIMER_MAX_VAL;
596     }
597     machine_add_tickfunction(devinit->machine,
598 dpavlin 24 dev_footbridge_tick, d, DEV_FOOTBRIDGE_TICK_SHIFT, 0.0);
599 dpavlin 14
600 dpavlin 34 devinit->return_ptr = d->pcibus;
601 dpavlin 14 return 1;
602     }
603    

  ViewVC Help
Powered by ViewVC 1.1.26