/[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 18 - (show 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 /*
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 * $Id: dev_footbridge.c,v 1.26 2005/10/26 14:37:04 debug Exp $
29 *
30 * Footbridge. Used in Netwinder and Cats.
31 *
32 * TODO: Most things. For example:
33 *
34 * o) Fix the timer TODO (see below).
35 *
36 * o) Add actual support for the fcom serial port.
37 *
38 * o) FIQs.
39 *
40 * o) ..
41 */
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 #define TIMER_POLL_THRESHOLD 15
62
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 if (!d->timer_being_read)
77 d->timer_poll_mode = 0;
78
79 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 if (writeflag == MEM_WRITE) {
122 idata = memory_readmax64(cpu, data, len);
123 fatal("[ footbridge_isa: WARNING/TODO: write! ]\n");
124 }
125
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 if (writeflag == MEM_WRITE)
174 idata = memory_readmax64(cpu, data, len);
175
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 if (writeflag == MEM_WRITE)
231 idata = memory_readmax64(cpu, data, len);
232
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 odata = d->irq_enable;
290 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 odata = d->irq_enable;
302 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 /*
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 odata = d->timer_value[timer_nr];
363 d->timer_being_read = 0;
364 } 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 /* bus_pci_add(devinit->machine, d->pcibus,
450 devinit->machine->memory, 0xc0, 10, 0,
451 pci_dec21143_init, pci_dec21143_rr); */
452 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