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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 36 - (show 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 /*
2 * Copyright (C) 2006-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_dreamcast_maple.c,v 1.14 2007/03/08 19:04:09 debug Exp $
29 *
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 * The Controller (up/down/left/right, buttons, etc).
45 */
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 #if 0
100 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 #endif
113 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 int key;
145
146 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
154 #if 0
155 /*
156 * NOTE/TODO:
157 *
158 * Implement the controller in a reasonable way!
159 */
160
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 #endif
218 }
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 * buf[0] = shift keys (1 = left ctrl, 2 = shift, 0x10 = right ctrl)
324 * 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 d->device[0] = NULL; /* &maple_device_controller; */
641 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