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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 36 - (hide annotations)
Mon Oct 8 16:21:34 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 18541 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1497 2007/03/18 03:41:36 debug Exp $
20070224	Minor update to the initialization of the ns16550 in
		machine_walnut.c, to allow that machine type to boot with the
		new interrupt system (although it is still a dummy machine).
		Adding a wdc at 0x14000000 to machine_landisk.c, and fixing
		the SCIF serial interrupts of the SH4 cpu enough to get
		NetBSD/landisk booting from a disk image :-)  Adding a
		preliminary install instruction skeleton to guestoses.html.
20070306	Adding SH-IPL+G PROM emulation, and also passing the "end"
		symbol in r5 on bootup, for Landisk emulation. This is enough
		to get OpenBSD/landisk to install :)  Adding a preliminary
		install instruction skeleton to the documentation. SuperH
		emulation is still shaky, though :-/
20070307	Fixed a strangeness in memory_sh.c (read/write was never
		returned for any page). (Unknown whether this fixes any actual
		problems, though.)
20070308	dev_ram.c fix: invalidate code translations on writes to
		RAM, emulated as separate devices. Linux/dreamcast gets
		further in the boot process than before, but still bugs out
		in userland.
		Fixing bugs in the "stc.l gbr,@-rN" and "ldc.l @rN+,gbr" SuperH 
		instructions (they should NOT check the MD bit), allowing the
		Linux/dreamcast Live CD to reach userland correctly :-)
20070310	Changing the cpu name "Alpha" in src/useremul.c to "21364" to
		unbreak userland syscall emulation of FreeBSD/Alpha binaries.
20070314	Applying a patch from Michael Yaroslavtsev which fixes the
		previous Linux lib64 patch to the configure script.
20070315	Adding a (dummy) sun4v machine type, and SPARC T1 cpu type.
20070316	Creating a new directory, src/disk, and moving diskimage.c
		to it. Separating out bootblock loading stuff from emul.c into
		new files in src/disk.
		Adding some more SPARC registers.
20070318	Preparing/testing for a minirelease, 0.4.4.1.

==============  RELEASE 0.4.4.1  ==============


1 dpavlin 32 /*
2 dpavlin 34 * Copyright (C) 2006-2007 Anders Gavare. All rights reserved.
3 dpavlin 32 *
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 36 * $Id: dev_dreamcast_maple.c,v 1.14 2007/03/08 19:04:09 debug Exp $
29 dpavlin 32 *
30     * Dreamcast "Maple" bus controller.
31     *
32     * The Maple bus has 4 ports (A-D), and each port has up to 6 possible "units"
33     * (where unit 0 is the main unit). Communication is done using DMA; each
34     * DMA transfer sends one or more requests, and for each of these requests
35     * a response is generated (or a timeout if there was no device at the
36     * specific port).
37     *
38     * See Marcus Comstedt's page (http://mc.pp.se/dc/maplebus.html) for more
39     * details about the DMA request/responses.
40     *
41     *
42     * TODO:
43     * Unit numbers / IDs for real Maple devices.
44 dpavlin 36 * The Controller (up/down/left/right, buttons, etc).
45 dpavlin 32 */
46    
47     #include <stdio.h>
48     #include <stdlib.h>
49     #include <string.h>
50     #include <sys/time.h>
51    
52     #include "console.h"
53     #include "cpu.h"
54     #include "device.h"
55     #include "machine.h"
56     #include "memory.h"
57     #include "misc.h"
58    
59     #include "dreamcast_maple.h"
60     #include "dreamcast_sysasicvar.h"
61    
62    
63     #define debug fatal
64    
65     #define N_MAPLE_PORTS 4
66    
67     #define MAX_CHARS 8192
68     #define MAX_CONTROLLER_DATA 4096
69    
70     #define MAPLE_TICK_SHIFT 17
71    
72     struct maple_device {
73     struct maple_devinfo devinfo;
74     };
75    
76     struct dreamcast_maple_data {
77     /* Registers: */
78     uint32_t dmaaddr;
79     int enable;
80     int timeout;
81    
82     /* Attached devices: */
83     struct maple_device *device[N_MAPLE_PORTS];
84    
85     /* For keyboard/controller input: */
86     int console_handle;
87     uint8_t char_queue[MAX_CHARS];
88     uint16_t controller_queue[MAX_CONTROLLER_DATA];
89     int char_queue_head, char_queue_tail;
90     int controller_queue_head, controller_queue_tail;
91     };
92    
93    
94     /*
95     * Maple devices:
96     *
97     * TODO: Figure out strings and numbers of _real_ Maple devices.
98     */
99 dpavlin 36 #if 0
100 dpavlin 32 static struct maple_device maple_device_controller = {
101     {
102     BE32_TO_HOST(MAPLE_FUNC(MAPLE_FN_CONTROLLER)), /* di_func */
103     { 0,0,0 }, /* di_function_data[3] */
104     0, /* di_area_code */
105     0, /* di_connector_direction */
106     "Dreamcast Controller", /* di_product_name */
107     "di_product_license", /* di_product_license */
108     LE16_TO_HOST(100), /* di_standby_power */
109     LE16_TO_HOST(100) /* di_max_power */
110     }
111     };
112 dpavlin 36 #endif
113 dpavlin 32 static struct maple_device maple_device_keyboard = {
114     {
115     BE32_TO_HOST(MAPLE_FUNC(MAPLE_FN_KEYBOARD)),/* di_func */
116     { LE32_TO_HOST(2),0,0 }, /* di_function_data[3] */
117     0, /* di_area_code */
118     0, /* di_connector_direction */
119     "Keyboard", /* di_product_name */
120     "di_product_license", /* di_product_license */
121     LE16_TO_HOST(100), /* di_standby_power */
122     LE16_TO_HOST(100) /* di_max_power */
123     }
124     };
125     #if 0
126     static struct maple_device maple_device_mouse = {
127     {
128     BE32_TO_HOST(MAPLE_FUNC(MAPLE_FN_MOUSE)),/* di_func */
129     { 0,0,0 }, /* di_function_data[3] */
130     0, /* di_area_code */
131     0, /* di_connector_direction */
132     "Dreamcast Mouse", /* di_product_name */
133     "di_product_license", /* di_product_license */
134     LE16_TO_HOST(100), /* di_standby_power */
135     LE16_TO_HOST(100) /* di_max_power */
136     }
137     };
138     #endif
139    
140    
141     DEVICE_TICK(maple)
142     {
143     struct dreamcast_maple_data *d = (struct dreamcast_maple_data *) extra;
144 dpavlin 36 int key;
145 dpavlin 32
146 dpavlin 36 while ((key = console_readchar(d->console_handle)) >= 0) {
147     /* Add to the keyboard queue: */
148     d->char_queue[d->char_queue_head] = key;
149     d->char_queue_head = (d->char_queue_head + 1) % MAX_CHARS;
150     if (d->char_queue_head == d->char_queue_tail)
151     fatal("[ dreamcast_maple: KEYBOARD QUEUE OVERRUN! ]\n");
152     }
153 dpavlin 32
154 dpavlin 36 #if 0
155     /*
156     * NOTE/TODO:
157     *
158     * Implement the controller in a reasonable way!
159     */
160 dpavlin 32
161     control_bits = 0;
162     switch (key) {
163     case 'a':
164     case 'A':
165     control_bits = 0x0004;
166     break;
167     case 'b':
168     case 'B':
169     control_bits = 0x0002;
170     break;
171     case 'c':
172     case 'C':
173     control_bits = 0x0001;
174     break;
175     case 'x':
176     case 'X':
177     control_bits = 0x0400;
178     break;
179     case 'y':
180     case 'Y':
181     control_bits = 0x0200;
182     break;
183     case 'z':
184     case 'Z':
185     control_bits = 0x0100;
186     break;
187     case 's':
188     case 'S': /* Start */
189     control_bits = 0x0008;
190     break;
191     case '8': /* up */
192     control_bits = 0x0010;
193     break;
194     case '2': /* down */
195     case 'k':
196     control_bits = 0x0020;
197     break;
198     case '4': /* left */
199     case 'u':
200     control_bits = 0x0040;
201     break;
202     case '6': /* right */
203     case 'o':
204     control_bits = 0x0080;
205     break;
206     }
207    
208     if (control_bits != 0) {
209     /* Add to the controller queue: */
210     d->controller_queue[d->controller_queue_head] = control_bits;
211     d->controller_queue_head =
212     (d->controller_queue_head + 1) % MAX_CONTROLLER_DATA;
213     if (d->controller_queue_head == d->controller_queue_tail)
214     fatal("[ dreamcast_maple: CONTROLLER QUEUE "
215     "OVERRUN! ]\n");
216     }
217 dpavlin 36 #endif
218 dpavlin 32 }
219    
220    
221     static int get_key(struct dreamcast_maple_data *d)
222     {
223     int key = d->char_queue[d->char_queue_tail];
224     if (d->char_queue_head == d->char_queue_tail)
225     return -1;
226    
227     d->char_queue_tail = (d->char_queue_tail + 1) % MAX_CHARS;
228     return key;
229     }
230    
231    
232     static int get_controller(struct dreamcast_maple_data *d)
233     {
234     int c = d->controller_queue[d->controller_queue_tail];
235     if (d->controller_queue_head == d->controller_queue_tail)
236     return 0;
237    
238     d->controller_queue_tail = (d->controller_queue_tail + 1)
239     % MAX_CONTROLLER_DATA;
240     return c;
241     }
242    
243    
244     /*
245     * maple_getcond_controller_response():
246     *
247     * Generate a controller response. Based on info from Marcus
248     * Comstedt's page: http://mc.pp.se/dc/controller.html
249     */
250     static void maple_getcond_controller_response(struct dreamcast_maple_data *d,
251     struct cpu *cpu, int port, uint32_t receive_addr)
252     {
253     uint8_t buf[8];
254     uint32_t response_code, transfer_code;
255     int c;
256    
257     transfer_code = (MAPLE_RESPONSE_DATATRF << 24) |
258     (((port << 6) | 0x20) << 16) |
259     ((port << 6) << 8) |
260     3 /* Transfer length in 32-bit words */;
261     transfer_code = BE32_TO_HOST(transfer_code);
262     cpu->memory_rw(cpu, cpu->mem, receive_addr, (void *) &transfer_code,
263     4, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL);
264     receive_addr += 4;
265    
266     response_code = BE32_TO_HOST(MAPLE_FUNC(MAPLE_FN_CONTROLLER));
267     cpu->memory_rw(cpu, cpu->mem, receive_addr, (void *) &response_code,
268     4, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL);
269     receive_addr += 4;
270    
271     /* NOTE: Inverse of the buttons pressed! */
272     c = ~get_controller(d);
273    
274     /*
275     * buf[0..1] = little endian button bitfield
276     * buf[2] = right analogue trigger (0-255)
277     * buf[3] = left analogue trigger (0-255)
278     * buf[4] = analogue joystick X (0-255)
279     * buf[5] = analogue joystick Y (0-255)
280     * buf[6] = second analogue joystick X (0-255)
281     * buf[7] = second analogue joystick Y (0-255)
282     */
283     memset(buf, 0, 8);
284     buf[0] = c & 0xff;
285     buf[1] = c >> 8;
286     buf[4] = buf[5] = buf[6] = buf[7] = 0;
287    
288     cpu->memory_rw(cpu, cpu->mem, receive_addr, (void *) &buf, 8,
289     MEM_WRITE, NO_EXCEPTIONS | PHYSICAL);
290     }
291    
292    
293     /*
294     * maple_getcond_keyboard_response():
295     *
296     * Generate a keyboard key-press response. Based on info from Marcus
297     * Comstedt's page: http://mc.pp.se/dc/kbd.html
298     */
299     static void maple_getcond_keyboard_response(struct dreamcast_maple_data *d,
300     struct cpu *cpu, int port, uint32_t receive_addr)
301     {
302     int key;
303     uint8_t buf[8];
304     uint32_t response_code, transfer_code;
305    
306     transfer_code = (MAPLE_RESPONSE_DATATRF << 24) |
307     (((port << 6) | 0x20) << 16) |
308     ((port << 6) << 8) |
309     3 /* Transfer length in 32-bit words */;
310     transfer_code = BE32_TO_HOST(transfer_code);
311     cpu->memory_rw(cpu, cpu->mem, receive_addr, (void *) &transfer_code,
312     4, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL);
313     receive_addr += 4;
314    
315     response_code = BE32_TO_HOST(MAPLE_FUNC(MAPLE_FN_KEYBOARD));
316     cpu->memory_rw(cpu, cpu->mem, receive_addr, (void *) &response_code,
317     4, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL);
318     receive_addr += 4;
319    
320     key = get_key(d);
321    
322     /*
323 dpavlin 36 * buf[0] = shift keys (1 = left ctrl, 2 = shift, 0x10 = right ctrl)
324 dpavlin 32 * buf[1] = led state
325     * buf[2] = key
326     */
327     memset(buf, 0, 8);
328    
329     if (key >= 'a' && key <= 'z') buf[2] = 4 + key - 'a';
330     if (key >= 'A' && key <= 'Z') buf[0] = 2, buf[2] = 4 + key - 'A';
331     if (key >= 1 && key <= 26) buf[0] = 1, buf[2] = 4 + key - 1;
332     if (key >= '1' && key <= '9') buf[2] = 0x1e + key - '1';
333     if (key == '!') buf[0] = 2, buf[2] = 0x1e;
334     if (key == '"') buf[0] = 2, buf[2] = 0x1f;
335     if (key == '#') buf[0] = 2, buf[2] = 0x20;
336     if (key == '$') buf[0] = 2, buf[2] = 0x21;
337     if (key == '%') buf[0] = 2, buf[2] = 0x22;
338     if (key == '^') buf[0] = 2, buf[2] = 0x23;
339     if (key == '&') buf[0] = 2, buf[2] = 0x24;
340     if (key == '*') buf[0] = 2, buf[2] = 0x25;
341     if (key == '(') buf[0] = 2, buf[2] = 0x26;
342     if (key == '@') buf[0] = 2, buf[2] = 0x1f;
343     if (key == '\n' || key == '\r') buf[0] = 0, buf[2] = 0x28;
344     if (key == ')') buf[0] = 2, buf[2] = 0x27;
345     if (key == '\b') buf[0] = 0, buf[2] = 0x2a;
346     if (key == '\t') buf[0] = 0, buf[2] = 0x2b;
347     if (key == ' ') buf[0] = 0, buf[2] = 0x2c;
348     if (key == '0') buf[2] = 0x27;
349     if (key == 27) buf[2] = 0x29;
350     if (key == '-') buf[2] = 0x2d;
351     if (key == '=') buf[2] = 0x2e;
352     if (key == '[') buf[2] = 0x2f;
353     if (key == '\\') buf[2] = 0x31;
354     if (key == '|') buf[2] = 0x31, buf[0] = 2;
355     if (key == ']') buf[2] = 0x32;
356     if (key == ';') buf[2] = 0x33;
357     if (key == ':') buf[2] = 0x34;
358     if (key == ',') buf[2] = 0x36;
359     if (key == '.') buf[2] = 0x37;
360     if (key == '/') buf[2] = 0x38;
361     if (key == '<') buf[2] = 0x36, buf[0] = 2;
362     if (key == '>') buf[2] = 0x37, buf[0] = 2;
363     if (key == '?') buf[2] = 0x38, buf[0] = 2;
364     if (key == '+') buf[2] = 0x57;
365    
366     cpu->memory_rw(cpu, cpu->mem, receive_addr, (void *) &buf, 8,
367     MEM_WRITE, NO_EXCEPTIONS | PHYSICAL);
368     }
369    
370    
371     /*
372     * maple_do_dma_xfer():
373     *
374     * Perform a DMA transfer. enable should be 1, and dmaaddr should point to
375     * the memory to transfer.
376     */
377     void maple_do_dma_xfer(struct cpu *cpu, struct dreamcast_maple_data *d)
378     {
379     uint32_t addr = d->dmaaddr;
380    
381     if (!d->enable) {
382     fatal("[ maple_do_dma_xfer: not enabled? ]\n");
383     return;
384     }
385    
386     /* debug("[ dreamcast_maple: DMA transfer, dmaaddr = "
387     "0x%08"PRIx32" ]\n", addr); */
388    
389     /*
390     * DMA transfers must be 32-byte aligned, according to Marcus
391     * Comstedt's Maple demo program.
392     */
393     if (addr & 0x1f) {
394     fatal("[ dreamcast_maple: dmaaddr 0x%08"PRIx32" is NOT"
395     " 32-byte aligned; aborting ]\n", addr);
396     return;
397     }
398    
399     /*
400     * Handle one or more requests/responses:
401     *
402     * (This is "reverse engineered" from Comstedt's maple demo program;
403     * it might not be good enough to emulate how the Maple is being
404     * used by other programs.)
405     */
406     for (;;) {
407     uint32_t receive_addr, response_code, cond;
408     int datalen, port, last_message, cmd, to, from, datalen_cmd;
409     int unit;
410     uint8_t buf[8];
411    
412     /* Read the message' two control words: */
413     cpu->memory_rw(cpu, cpu->mem, addr, (void *) &buf, 8, MEM_READ,
414     NO_EXCEPTIONS | PHYSICAL);
415     addr += 8;
416    
417     datalen = buf[0] * sizeof(uint32_t);
418     if (buf[1] & 2) {
419     fatal("[ dreamcast_maple: TODO: GUN bit. ]\n");
420     /* TODO: Set some bits in A05F80C4 to indicate
421     which raster position a lightgun is pointing
422     at! */
423     exit(1);
424     }
425     port = buf[2];
426     last_message = buf[3] & 0x80;
427     receive_addr = buf[4] + (buf[5] << 8) + (buf[6] << 16)
428     + (buf[7] << 24);
429    
430     if (receive_addr & 0xe000001f)
431     fatal("[ dreamcast_maple: WARNING! receive address 0x"
432     "%08"PRIx32" isn't valid! ]\n", receive_addr);
433    
434     /* Read the command word for this message: */
435     cpu->memory_rw(cpu, cpu->mem, addr, (void *) &buf, 4, MEM_READ,
436     NO_EXCEPTIONS | PHYSICAL);
437     addr += 4;
438    
439     cmd = buf[0];
440     to = buf[1];
441     from = buf[2];
442     datalen_cmd = buf[3];
443    
444     /* Decode the unit number: */
445     unit = 0;
446     switch (to & 0x3f) {
447     case 0x00:
448     case 0x20: unit = 0; break;
449     case 0x01: unit = 1; break;
450     case 0x02: unit = 2; break;
451     case 0x04: unit = 3; break;
452     case 0x08: unit = 4; break;
453     case 0x10: unit = 5; break;
454     default: fatal("[ dreamcast_maple: ERROR! multiple "
455     "units? Not yet implemented. to = 0x%02x ]\n", to);
456     exit(1);
457     }
458    
459     /* debug("[ dreamcast_maple: cmd=0x%02x, port=%c, unit=%i"
460     ", datalen=%i words ]\n", cmd, port+'A', unit,
461     datalen_cmd); */
462    
463     /*
464     * Handle the command:
465     */
466     switch (cmd) {
467    
468     case MAPLE_COMMAND_DEVINFO:
469     if (d->device[port] == NULL || unit != 0) {
470     /* No device present: Timeout. */
471     /* debug("[ dreamcast_maple: response="
472     "timeout ]\n"); */
473     response_code = (uint32_t) -1;
474     response_code = LE32_TO_HOST(response_code);
475     cpu->memory_rw(cpu, cpu->mem, receive_addr,
476     (void *) &response_code, 4, MEM_WRITE,
477     NO_EXCEPTIONS | PHYSICAL);
478     } else {
479     /* Device present: */
480     int i;
481     struct maple_devinfo *di =
482     &d->device[port]->devinfo;
483     /* debug("[ dreamcast_maple: response="
484     "\"%s\" ]\n", di->di_product_name); */
485     response_code = MAPLE_RESPONSE_DEVINFO |
486     (((port << 6) | 0x20) << 8) |
487     ((port << 6) << 16) |
488     ((sizeof(struct maple_devinfo) /
489     sizeof(uint32_t)) << 24);
490     response_code = LE32_TO_HOST(response_code);
491     cpu->memory_rw(cpu, cpu->mem, receive_addr,
492     (void *) &response_code, 4, MEM_WRITE,
493     NO_EXCEPTIONS | PHYSICAL);
494     for (i=0; i<sizeof(struct maple_devinfo); i++)
495     cpu->memory_rw(cpu, cpu->mem,
496     receive_addr + 4 + i, (unsigned
497     char *) di + i, 1, MEM_WRITE,
498     NO_EXCEPTIONS | PHYSICAL);
499     }
500     break;
501    
502     case MAPLE_COMMAND_GETCOND:
503     cpu->memory_rw(cpu, cpu->mem, addr, (void *) &buf, 4,
504     MEM_READ, NO_EXCEPTIONS | PHYSICAL);
505     cond = buf[3] + (buf[2] << 8) + (buf[1] << 16)
506     + (buf[0] << 24);
507     if (cond & MAPLE_FUNC(MAPLE_FN_CONTROLLER)) {
508     maple_getcond_controller_response(
509     d, cpu, port, receive_addr);
510     } else if (cond & MAPLE_FUNC(MAPLE_FN_KEYBOARD)) {
511     maple_getcond_keyboard_response(
512     d, cpu, port, receive_addr);
513     } else {
514     fatal("[ dreamcast_maple: WARNING: GETCOND: "
515     "UNIMPLEMENTED 0x%08"PRIx32" ]\n", cond);
516     }
517     break;
518    
519     case MAPLE_COMMAND_BWRITE:
520     fatal("[ dreamcast_maple: BWRITE: TODO ]\n");
521     break;
522    
523     default:fatal("[ dreamcast_maple: command %i: TODO ]\n", cmd);
524     exit(1);
525     }
526    
527     addr += datalen_cmd * 4;
528    
529     /* Last request? Then stop. */
530     if (last_message)
531     break;
532     }
533    
534     /* Assert the SYSASIC_EVENT_MAPLE_DMADONE event: */
535     SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_MAPLE_DMADONE);
536     }
537    
538    
539     DEVICE_ACCESS(dreamcast_maple)
540     {
541     struct dreamcast_maple_data *d = (struct dreamcast_maple_data *) extra;
542     uint64_t idata = 0, odata = 0;
543    
544     if (writeflag == MEM_WRITE)
545     idata = memory_readmax64(cpu, data, len);
546    
547     switch (relative_addr) {
548    
549     case 0x04: /* MAPLE_DMAADDR */
550     if (writeflag == MEM_WRITE) {
551     d->dmaaddr = idata;
552     /* debug("[ dreamcast_maple: dmaaddr set to 0x%08x"
553     " ]\n", d->dmaaddr); */
554     } else {
555     fatal("[ dreamcast_maple: TODO: read from dmaaddr ]\n");
556     odata = d->dmaaddr;
557     }
558     break;
559    
560     case 0x10: /* MAPLE_RESET2 */
561     if (writeflag == MEM_WRITE && idata != 0)
562     fatal("[ dreamcast_maple: UNIMPLEMENTED reset2 value"
563     " 0x%08x ]\n", (int)idata);
564     break;
565    
566     case 0x14: /* MAPLE_ENABLE */
567     if (writeflag == MEM_WRITE)
568     d->enable = idata;
569     else
570     odata = d->enable;
571     break;
572    
573     case 0x18: /* MAPLE_STATE */
574     if (writeflag == MEM_WRITE) {
575     switch (idata) {
576     case 0: break;
577     case 1: maple_do_dma_xfer(cpu, d);
578     break;
579     default:fatal("[ dreamcast_maple: UNIMPLEMENTED "
580     "state value %i ]\n", (int)idata);
581     }
582     } else {
583     /* Always return 0 to indicate DMA xfer complete. */
584     odata = 0;
585     }
586     break;
587    
588     case 0x80: /* MAPLE_SPEED */
589     if (writeflag == MEM_WRITE) {
590     d->timeout = (idata >> 16) & 0xffff;
591     /* TODO: Bits 8..9 are "speed", but only the value
592     0 (indicating 2 Mbit/s) should be used. */
593     debug("[ dreamcast_maple: timeout set to %i ]\n",
594     d->timeout);
595     } else {
596     odata = d->timeout << 16;
597     }
598     break;
599    
600     case 0x8c: /* MAPLE_RESET */
601     if (writeflag == MEM_WRITE) {
602     if (idata != 0x6155404f)
603     fatal("[ dreamcast_maple: UNIMPLEMENTED reset "
604     "value 0x%08x ]\n", (int)idata);
605     d->enable = 0;
606     }
607     break;
608    
609     default:if (writeflag == MEM_READ) {
610     fatal("[ dreamcast_maple: UNIMPLEMENTED read from "
611     "addr 0x%x ]\n", (int)relative_addr);
612     } else {
613     fatal("[ dreamcast_maple: UNIMPLEMENTED write to addr "
614     "0x%x: 0x%x ]\n", (int)relative_addr, (int)idata);
615     }
616     }
617    
618     if (writeflag == MEM_READ)
619     memory_writemax64(cpu, data, len, odata);
620    
621     return 1;
622     }
623    
624    
625     DEVINIT(dreamcast_maple)
626     {
627     struct machine *machine = devinit->machine;
628     struct dreamcast_maple_data *d =
629     malloc(sizeof(struct dreamcast_maple_data));
630     if (d == NULL) {
631     fprintf(stderr, "out of memory\n");
632     exit(1);
633     }
634     memset(d, 0, sizeof(struct dreamcast_maple_data));
635    
636     memory_device_register(machine->memory, devinit->name,
637     0x5f6c00, 0x100, dev_dreamcast_maple_access, d, DM_DEFAULT, NULL);
638    
639     /* Devices connected to port A..D: */
640 dpavlin 36 d->device[0] = NULL; /* &maple_device_controller; */
641 dpavlin 32 d->device[1] = NULL;
642     d->device[2] = &maple_device_keyboard;
643     d->device[3] = NULL; /* TODO: &maple_device_mouse; */
644    
645     d->console_handle = console_start_slave_inputonly(machine, "maple", 1);
646     machine->main_console_handle = d->console_handle;
647    
648     machine_add_tickfunction(devinit->machine, dev_maple_tick, d,
649     MAPLE_TICK_SHIFT, 0.0);
650    
651     return 1;
652     }
653    

  ViewVC Help
Powered by ViewVC 1.1.26