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

Contents of /trunk/src/devices/dev_footbridge.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 34 - (show 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 /*
2 * Copyright (C) 2005-2007 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_footbridge.c,v 1.55 2007/02/03 16:18:56 debug Exp $
29 *
30 * Footbridge. Used in Netwinder and Cats.
31 *
32 * TODO:
33 * o) Add actual support for the fcom serial port.
34 * o) FIQs.
35 * o) Pretty much everything else as well :) (This entire thing
36 * is a quick hack to work primarily with NetBSD and OpenBSD
37 * as guest OSes.)
38 */
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 #include "devices.h"
49 #include "machine.h"
50 #include "memory.h"
51 #include "misc.h"
52 #include "timer.h"
53
54
55 #include "dc21285reg.h"
56
57 #define DEV_FOOTBRIDGE_TICK_SHIFT 14
58 #define DEV_FOOTBRIDGE_LENGTH 0x400
59
60 #define N_FOOTBRIDGE_TIMERS 4
61
62 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 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 /*
128 * dev_footbridge_tick():
129 *
130 * 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 */
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 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 INTERRUPT_ASSERT(d->timer_irq[i]);
147 }
148 }
149 }
150 }
151
152
153 /*
154 * 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 * dev_footbridge_isa_access():
185 *
186 * 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 */
190 DEVICE_ACCESS(footbridge_isa)
191 {
192 /* struct footbridge_data *d = extra; */
193 uint64_t idata = 0, odata = 0;
194 int x;
195
196 if (writeflag == MEM_WRITE) {
197 idata = memory_readmax64(cpu, data, len);
198 fatal("[ footbridge_isa: WARNING/TODO: write! ]\n");
199 }
200
201 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
207 if (writeflag == MEM_READ)
208 memory_writemax64(cpu, data, len, odata);
209
210 return 1;
211 }
212
213
214 /*
215 * 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 * dev_footbridge_pci_access():
238 *
239 * 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 */
243 DEVICE_ACCESS(footbridge_pci)
244 {
245 struct footbridge_data *d = extra;
246 uint64_t idata = 0, odata = 0;
247 int bus, dev, func, reg;
248
249 if (writeflag == MEM_WRITE)
250 idata = memory_readmax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN);
251
252 /* 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
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 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
266 bus_pci_data_access(cpu, d->pcibus, writeflag == MEM_READ?
267 &odata : &idata, len, writeflag);
268
269 if (writeflag == MEM_READ)
270 memory_writemax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN, odata);
271
272 return 1;
273 }
274
275
276 /*
277 * dev_footbridge_access():
278 *
279 * The DC21285 registers.
280 */
281 DEVICE_ACCESS(footbridge)
282 {
283 struct footbridge_data *d = extra;
284 uint64_t idata = 0, odata = 0;
285 int timer_nr = 0;
286
287 if (writeflag == MEM_WRITE)
288 idata = memory_readmax64(cpu, data, len);
289
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 case 0x04:
306 case 0x0c:
307 case 0x10:
308 case 0x14:
309 case 0x18:
310 /* TODO. Written to by Linux. */
311 break;
312
313 case REVISION:
314 odata = 3; /* footbridge revision number */
315 break;
316
317 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 case SA_CONTROL:
325 /* Read by Linux: */
326 odata = PCI_CENTRAL_FUNCTION;
327 break;
328
329 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 if (d->irq_status & d->irq_enable)
365 INTERRUPT_ASSERT(d->irq);
366 else
367 INTERRUPT_DEASSERT(d->irq);
368 } else {
369 odata = d->irq_enable;
370 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 if (d->irq_status & d->irq_enable)
380 INTERRUPT_ASSERT(d->irq);
381 else
382 INTERRUPT_DEASSERT(d->irq);
383 } else {
384 odata = d->irq_enable;
385 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 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 INTERRUPT_DEASSERT(d->timer_irq[timer_nr]);
429 }
430 break;
431
432 case TIMER_1_VALUE:
433 if (writeflag == MEM_READ)
434 odata = d->timer_value[timer_nr];
435 else
436 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 reload_timer_value(cpu, d, timer_nr);
452 } else {
453 d->pending_timer_interrupts[timer_nr] = 0;
454 }
455 INTERRUPT_DEASSERT(d->timer_irq[timer_nr]);
456 }
457 break;
458
459 case TIMER_1_CLEAR:
460 if (d->timer_control[timer_nr] & TIMER_MODE_PERIODIC) {
461 reload_timer_value(cpu, d, timer_nr);
462 }
463
464 if (d->pending_timer_interrupts[timer_nr] > 0) {
465 d->pending_timer_interrupts[timer_nr] --;
466 }
467
468 INTERRUPT_DEASSERT(d->timer_irq[timer_nr]);
469 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 DEVINIT(footbridge)
488 {
489 struct footbridge_data *d;
490 char irq_path[300], irq_path_isa[300];
491 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 /* Connect to the CPU which this footbridge will interrupt: */
502 INTERRUPT_CONNECT(devinit->interrupt_path, d->irq);
503
504 /* DC21285 register access: */
505 memory_device_register(devinit->machine->memory, devinit->name,
506 devinit->addr, DEV_FOOTBRIDGE_LENGTH,
507 dev_footbridge_access, d, DM_DEFAULT, NULL);
508
509 /* ISA interrupt status/acknowledgement: */
510 memory_device_register(devinit->machine->memory, "footbridge_isa",
511 0x79000000, 8, dev_footbridge_isa_access, d, DM_DEFAULT, NULL);
512
513 /* The "fcom" console: */
514 d->console_handle = console_start_slave(devinit->machine, "fcom", 0);
515
516 /* 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 /* A PCI bus: */
552 d->pcibus = bus_pci_init(
553 devinit->machine,
554 irq_path,
555 0x7c000000, /* PCI device io offset */
556 0x80000000, /* PCI device mem offset */
557 0x00000000, /* PCI port base */
558 0x00000000, /* PCI mem base */
559 irq_path, /* PCI irq base */
560 0x7c000000, /* ISA port base */
561 0x80000000, /* ISA mem base */
562 irq_path_isa); /* ISA port base */
563
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 devinit->machine->memory, 0xc0, 7, 0, "ali_m1543");
569 bus_pci_add(devinit->machine, d->pcibus,
570 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 break;
574 case MACHINE_NETWINDER:
575 bus_pci_add(devinit->machine, d->pcibus,
576 devinit->machine->memory, 0xc0, 11, 0, "symphony_83c553");
577 bus_pci_add(devinit->machine, d->pcibus,
578 devinit->machine->memory, 0xc0, 11, 1, "symphony_82c105");
579 memory_device_register(devinit->machine->memory,
580 "footbridge_reset", 0x7c000338, 1,
581 dev_footbridge_reset_access, d, DM_DEFAULT, NULL);
582 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 dev_footbridge_pci_access, d, DM_DEFAULT, NULL);
591
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 dev_footbridge_tick, d, DEV_FOOTBRIDGE_TICK_SHIFT, 0.0);
599
600 devinit->return_ptr = d->pcibus;
601 return 1;
602 }
603

  ViewVC Help
Powered by ViewVC 1.1.26