main
io.c
1/*
2 Copyright 2013 Michael Pavone
3 This file is part of BlastEm.
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
5*/
6#include <unistd.h>
7#include <fcntl.h>
8#include <sys/socket.h>
9#include <sys/un.h>
10#include <sys/types.h>
11#include <sys/stat.h>
12#include <errno.h>
13#include <string.h>
14#include <stdlib.h>
15
16#include "serialize.h"
17#include "io.h"
18#include "blastem.h"
19#include "render.h"
20#include "util.h"
21#include "bindings.h"
22
23#define CYCLE_NEVER 0xFFFFFFFF
24#define MIN_POLL_INTERVAL 6840
25
26const char * device_type_names[] = {
27 "None",
28 "SMS gamepad",
29 "3-button gamepad",
30 "6-button gamepad",
31 "Mega Mouse",
32 "Saturn Keyboard",
33 "XBAND Keyboard",
34 "Menacer",
35 "Justifier",
36 "Sega multi-tap",
37 "EA 4-way Play cable A",
38 "EA 4-way Play cable B",
39 "Sega Parallel Transfer Board",
40 "Generic Device"
41};
42
43#define GAMEPAD_TH0 0
44#define GAMEPAD_TH1 1
45#define GAMEPAD_EXTRA 2
46#define GAMEPAD_NONE 0xF
47
48#define IO_TH0 0
49#define IO_TH1 1
50#define IO_STATE 2
51
52enum {
53 IO_WRITE_PENDING,
54 IO_WRITTEN,
55 IO_READ_PENDING,
56 IO_READ
57};
58
59typedef struct {
60 uint8_t states[2], value;
61} gp_button_def;
62
63
64static gp_button_def button_defs[NUM_GAMEPAD_BUTTONS] = {
65 [DPAD_UP] = {.states = {GAMEPAD_TH0, GAMEPAD_TH1}, .value = 0x1},
66 [DPAD_DOWN] = {.states = {GAMEPAD_TH0, GAMEPAD_TH1}, .value = 0x2},
67 [DPAD_LEFT] = {.states = {GAMEPAD_TH1, GAMEPAD_NONE}, .value = 0x4},
68 [DPAD_RIGHT] = {.states = {GAMEPAD_TH1, GAMEPAD_NONE}, .value = 0x8},
69 [BUTTON_A] = {.states = {GAMEPAD_TH0, GAMEPAD_NONE}, .value = 0x10},
70 [BUTTON_B] = {.states = {GAMEPAD_TH1, GAMEPAD_NONE}, .value = 0x10},
71 [BUTTON_C] = {.states = {GAMEPAD_TH1, GAMEPAD_NONE}, .value = 0x20},
72 [BUTTON_START] = {.states = {GAMEPAD_TH0, GAMEPAD_NONE}, .value = 0x20},
73 [BUTTON_X] = {.states = {GAMEPAD_EXTRA, GAMEPAD_NONE}, .value = 0x4},
74 [BUTTON_Y] = {.states = {GAMEPAD_EXTRA, GAMEPAD_NONE}, .value = 0x2},
75 [BUTTON_Z] = {.states = {GAMEPAD_EXTRA, GAMEPAD_NONE}, .value = 0x1},
76 [BUTTON_MODE] = {.states = {GAMEPAD_EXTRA, GAMEPAD_NONE}, .value = 0x8},
77};
78
79static io_port *find_gamepad(sega_io *io, uint8_t gamepad_num)
80{
81 for (int i = 0; i < 3; i++)
82 {
83 io_port *port = io->ports + i;
84 if (port->device_type < IO_MOUSE && port->device.pad.gamepad_num == gamepad_num) {
85 return port;
86 }
87 }
88 return NULL;
89}
90
91static io_port *find_mouse(sega_io *io, uint8_t mouse_num)
92{
93 for (int i = 0; i < 3; i++)
94 {
95 io_port *port = io->ports + i;
96 if (port->device_type == IO_MOUSE && port->device.mouse.mouse_num == mouse_num) {
97 return port;
98 }
99 }
100 return NULL;
101}
102
103static io_port *find_keyboard(sega_io *io)
104{
105 for (int i = 0; i < 3; i++)
106 {
107 io_port *port = io->ports + i;
108 if (port->device_type == IO_SATURN_KEYBOARD || port->device_type == IO_XBAND_KEYBOARD) {
109 return port;
110 }
111 }
112 return NULL;
113}
114
115void io_port_gamepad_down(io_port *port, uint8_t button)
116{
117 gp_button_def *def = button_defs + button;
118 port->input[def->states[0]] |= def->value;
119 if (def->states[1] != GAMEPAD_NONE) {
120 port->input[def->states[1]] |= def->value;
121 }
122}
123
124void io_port_gamepad_up(io_port *port, uint8_t button)
125{
126 gp_button_def *def = button_defs + button;
127 port->input[def->states[0]] &= ~def->value;
128 if (def->states[1] != GAMEPAD_NONE) {
129 port->input[def->states[1]] &= ~def->value;
130 }
131}
132
133void io_gamepad_down(sega_io *io, uint8_t gamepad_num, uint8_t button)
134{
135 io_port *port = find_gamepad(io, gamepad_num);
136 if (port) {
137 io_port_gamepad_down(port, button);
138 }
139}
140
141void io_gamepad_up(sega_io *io, uint8_t gamepad_num, uint8_t button)
142{
143 io_port *port = find_gamepad(io, gamepad_num);
144 if (port) {
145 io_port_gamepad_up(port, button);
146 }
147}
148
149void io_mouse_down(sega_io *io, uint8_t mouse_num, uint8_t button)
150{
151 io_port *port = find_mouse(io, mouse_num);
152 if (port) {
153 port->input[0] |= button;
154 }
155}
156
157void io_mouse_up(sega_io *io, uint8_t mouse_num, uint8_t button)
158{
159 io_port *port = find_mouse(io, mouse_num);
160 if (port) {
161 port->input[0] &= ~button;
162 }
163}
164
165void io_mouse_motion_absolute(sega_io *io, uint8_t mouse_num, uint16_t x, uint16_t y)
166{
167 io_port *port = find_mouse(io, mouse_num);
168 if (port) {
169 port->device.mouse.cur_x = x;
170 port->device.mouse.cur_y = y;
171 }
172}
173
174void io_mouse_motion_relative(sega_io *io, uint8_t mouse_num, int32_t x, int32_t y)
175{
176 io_port *port = find_mouse(io, mouse_num);
177 if (port) {
178 port->device.mouse.cur_x += x;
179 port->device.mouse.cur_y += y;
180 }
181}
182
183void store_key_event(io_port *keyboard_port, uint16_t code)
184{
185 if (keyboard_port && keyboard_port->device.keyboard.write_pos != keyboard_port->device.keyboard.read_pos) {
186 //there's room in the buffer, record this event
187 keyboard_port->device.keyboard.events[keyboard_port->device.keyboard.write_pos] = code;
188 if (keyboard_port->device.keyboard.read_pos == 0xFF) {
189 //ring buffer was empty, update read_pos to indicate there is now data
190 keyboard_port->device.keyboard.read_pos = keyboard_port->device.keyboard.write_pos;
191 }
192 keyboard_port->device.keyboard.write_pos = (keyboard_port->device.keyboard.write_pos + 1) & 7;
193 }
194}
195
196void io_keyboard_down(sega_io *io, uint8_t scancode)
197{
198 store_key_event(find_keyboard(io), scancode);
199}
200
201void io_keyboard_up(sega_io *io, uint8_t scancode)
202{
203 store_key_event(find_keyboard(io), 0xF000 | scancode);
204}
205
206uint8_t io_has_keyboard(sega_io *io)
207{
208 return find_keyboard(io) != NULL;
209}
210
211void process_device(char * device_type, io_port * port)
212{
213 //assuming that the io_port struct has been zeroed if this is the first time this has been called
214 if (!device_type)
215 {
216 return;
217 }
218
219 const int gamepad_len = strlen("gamepad");
220 if (startswith(device_type, "gamepad"))
221 {
222 if (
223 (device_type[gamepad_len] != '3' && device_type[gamepad_len] != '6' && device_type[gamepad_len] != '2')
224 || device_type[gamepad_len+1] != '.' || device_type[gamepad_len+2] < '1'
225 || device_type[gamepad_len+2] > '8' || device_type[gamepad_len+3] != 0
226 ) {
227 warning("%s is not a valid gamepad type\n", device_type);
228 } else if (device_type[gamepad_len] == '3') {
229 port->device_type = IO_GAMEPAD3;
230 } else if (device_type[gamepad_len] == '2') {
231 port->device_type = IO_GAMEPAD2;
232 } else {
233 port->device_type = IO_GAMEPAD6;
234 }
235 port->device.pad.gamepad_num = device_type[gamepad_len+2] - '0';
236 } else if(startswith(device_type, "mouse")) {
237 if (port->device_type != IO_MOUSE) {
238 port->device_type = IO_MOUSE;
239 port->device.mouse.mouse_num = device_type[strlen("mouse")+1] - '0';
240 port->device.mouse.last_read_x = 0;
241 port->device.mouse.last_read_y = 0;
242 port->device.mouse.cur_x = 0;
243 port->device.mouse.cur_y = 0;
244 port->device.mouse.latched_x = 0;
245 port->device.mouse.latched_y = 0;
246 port->device.mouse.ready_cycle = CYCLE_NEVER;
247 port->device.mouse.tr_counter = 0;
248 }
249 } else if(!strcmp(device_type, "saturn keyboard")) {
250 if (port->device_type != IO_SATURN_KEYBOARD) {
251 port->device_type = IO_SATURN_KEYBOARD;
252 port->device.keyboard.read_pos = 0xFF;
253 port->device.keyboard.write_pos = 0;
254 }
255 } else if(!strcmp(device_type, "xband keyboard")) {
256 if (port->device_type != IO_XBAND_KEYBOARD) {
257 port->device_type = IO_XBAND_KEYBOARD;
258 port->device.keyboard.read_pos = 0xFF;
259 port->device.keyboard.write_pos = 0;
260 }
261 } else if(!strcmp(device_type, "sega_parallel")) {
262 if (port->device_type != IO_SEGA_PARALLEL) {
263 port->device_type = IO_SEGA_PARALLEL;
264 port->device.stream.data_fd = -1;
265 port->device.stream.listen_fd = -1;
266 }
267 } else if(!strcmp(device_type, "generic")) {
268 if (port->device_type != IO_GENERIC) {
269 port->device_type = IO_GENERIC;
270 port->device.stream.data_fd = -1;
271 port->device.stream.listen_fd = -1;
272 }
273 }
274}
275
276char * io_name(int i)
277{
278 switch (i)
279 {
280 case 0:
281 return "1";
282 case 1:
283 return "2";
284 case 2:
285 return "EXT";
286 default:
287 return "invalid";
288 }
289}
290
291static char * sockfile_name;
292static void cleanup_sockfile()
293{
294 unlink(sockfile_name);
295}
296
297void setup_io_devices(tern_node * config, rom_info *rom, sega_io *io)
298{
299 io_port * ports = io->ports;
300 tern_node *io_nodes = tern_find_path(config, "io\0devices\0", TVAL_NODE).ptrval;
301 char * io_1 = rom->port1_override ? rom->port1_override : tern_find_ptr_default(io_nodes, "1", "gamepad6.1");
302 char * io_2 = rom->port2_override ? rom->port2_override : tern_find_ptr_default(io_nodes, "2", "gamepad6.2");
303 char * io_ext = rom->ext_override ? rom->ext_override : tern_find_ptr(io_nodes, "ext");
304
305 process_device(io_1, ports);
306 process_device(io_2, ports+1);
307 process_device(io_ext, ports+2);
308
309 uint8_t mouse_mode;
310 if (ports[0].device_type == IO_MOUSE || ports[1].device_type == IO_MOUSE || ports[2].device_type == IO_MOUSE) {
311 if (rom->mouse_mode && !strcmp(rom->mouse_mode, "absolute")) {
312 mouse_mode = MOUSE_ABSOLUTE;
313 } else {
314 mouse_mode = MOUSE_CAPTURE;
315 }
316 } else {
317 mouse_mode = MOUSE_NONE;
318 }
319 bindings_set_mouse_mode(mouse_mode);
320
321 for (int i = 0; i < 3; i++)
322 {
323 if (ports[i].device_type == IO_SEGA_PARALLEL && ports[i].device.stream.data_fd == -1)
324 {
325 char *pipe_name = tern_find_path(config, "io\0parallel_pipe\0", TVAL_PTR).ptrval;
326 if (!pipe_name)
327 {
328 warning("IO port %s is configured to use the sega parallel board, but no paralell_pipe is set!\n", io_name(i));
329 ports[i].device_type = IO_NONE;
330 } else {
331 debug_message("IO port: %s connected to device '%s' with pipe name: %s\n", io_name(i), device_type_names[ports[i].device_type], pipe_name);
332 if (!strcmp("stdin", pipe_name))
333 {
334 ports[i].device.stream.data_fd = STDIN_FILENO;
335 } else {
336 if (mkfifo(pipe_name, 0666) && errno != EEXIST)
337 {
338 warning("Failed to create fifo %s for Sega parallel board emulation: %d %s\n", pipe_name, errno, strerror(errno));
339 ports[i].device_type = IO_NONE;
340 } else {
341 ports[i].device.stream.data_fd = open(pipe_name, O_NONBLOCK | O_RDONLY);
342 if (ports[i].device.stream.data_fd == -1)
343 {
344 warning("Failed to open fifo %s for Sega parallel board emulation: %d %s\n", pipe_name, errno, strerror(errno));
345 ports[i].device_type = IO_NONE;
346 }
347 }
348 }
349 }
350 } else if (ports[i].device_type == IO_GENERIC && ports[i].device.stream.data_fd == -1) {
351 char *sock_name = tern_find_path(config, "io\0socket\0", TVAL_PTR).ptrval;
352 if (!sock_name)
353 {
354 warning("IO port %s is configured to use generic IO, but no socket is set!\n", io_name(i));
355 ports[i].device_type = IO_NONE;
356 } else {
357 debug_message("IO port: %s connected to device '%s' with socket name: %s\n", io_name(i), device_type_names[ports[i].device_type], sock_name);
358 ports[i].device.stream.data_fd = -1;
359 ports[i].device.stream.listen_fd = socket(AF_UNIX, SOCK_STREAM, 0);
360 size_t pathlen = strlen(sock_name);
361 size_t addrlen = offsetof(struct sockaddr_un, sun_path) + pathlen + 1;
362 struct sockaddr_un *saddr = malloc(addrlen);
363 saddr->sun_family = AF_UNIX;
364 memcpy(saddr->sun_path, sock_name, pathlen+1);
365 if (bind(ports[i].device.stream.listen_fd, (struct sockaddr *)saddr, addrlen))
366 {
367 warning("Failed to bind socket for IO Port %s to path %s: %d %s\n", io_name(i), sock_name, errno, strerror(errno));
368 goto cleanup_sock;
369 }
370 if (listen(ports[i].device.stream.listen_fd, 1))
371 {
372 warning("Failed to listen on socket for IO Port %s: %d %s\n", io_name(i), errno, strerror(errno));
373 goto cleanup_sockfile;
374 }
375 sockfile_name = sock_name;
376 atexit(cleanup_sockfile);
377 continue;
378cleanup_sockfile:
379 unlink(sock_name);
380cleanup_sock:
381 close(ports[i].device.stream.listen_fd);
382 ports[i].device_type = IO_NONE;
383 }
384 } else
385 if (ports[i].device_type == IO_GAMEPAD3 || ports[i].device_type == IO_GAMEPAD6 || ports[i].device_type == IO_GAMEPAD2) {
386 debug_message("IO port %s connected to gamepad #%d with type '%s'\n", io_name(i), ports[i].device.pad.gamepad_num, device_type_names[ports[i].device_type]);
387 } else {
388 debug_message("IO port %s connected to device '%s'\n", io_name(i), device_type_names[ports[i].device_type]);
389 }
390 }
391}
392
393
394#define TH 0x40
395#define TR 0x20
396#define TH_TIMEOUT 56000
397
398void mouse_check_ready(io_port *port, uint32_t current_cycle)
399{
400 if (current_cycle >= port->device.mouse.ready_cycle) {
401 port->device.mouse.tr_counter++;
402 port->device.mouse.ready_cycle = CYCLE_NEVER;
403 if (port->device.mouse.tr_counter == 3) {
404 port->device.mouse.latched_x = port->device.mouse.cur_x;
405 port->device.mouse.latched_y = port->device.mouse.cur_y;
406 /* FIXME mouse mode owned by bindings now
407 if (current_io->mouse_mode == MOUSE_ABSOLUTE) {
408 //avoid overflow in absolute mode
409 int deltax = port->device.mouse.latched_x - port->device.mouse.last_read_x;
410 if (abs(deltax) > 255) {
411 port->device.mouse.latched_x = port->device.mouse.last_read_x + (deltax > 0 ? 255 : -255);
412 }
413 int deltay = port->device.mouse.latched_y - port->device.mouse.last_read_y;
414 if (abs(deltay) > 255) {
415 port->device.mouse.latched_y = port->device.mouse.last_read_y + (deltay > 0 ? 255 : -255);
416 }
417 }*/
418 }
419 }
420}
421
422uint32_t last_poll_cycle;
423void io_adjust_cycles(io_port * port, uint32_t current_cycle, uint32_t deduction)
424{
425 /*uint8_t control = pad->control | 0x80;
426 uint8_t th = control & pad->output;
427 if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) {
428 printf("adjust_cycles | control: %X, TH: %X, GAMEPAD_TH0: %X, GAMEPAD_TH1: %X, TH Counter: %d, Timeout: %d, Cycle: %d\n", control, th, pad->input[GAMEPAD_TH0], pad->input[GAMEPAD_TH1], pad->th_counter,pad->timeout_cycle, current_cycle);
429 }*/
430 if (port->device_type == IO_GAMEPAD6)
431 {
432 if (current_cycle >= port->device.pad.timeout_cycle)
433 {
434 port->device.pad.th_counter = 0;
435 } else {
436 port->device.pad.timeout_cycle -= deduction;
437 }
438 } else if (port->device_type == IO_MOUSE) {
439 mouse_check_ready(port, current_cycle);
440 if (port->device.mouse.ready_cycle != CYCLE_NEVER) {
441 port->device.mouse.ready_cycle -= deduction;
442 }
443 }
444 for (int i = 0; i < 8; i++)
445 {
446 if (port->slow_rise_start[i] != CYCLE_NEVER) {
447 if (port->slow_rise_start[i] >= deduction) {
448 port->slow_rise_start[i] -= deduction;
449 } else {
450 port->slow_rise_start[i] = CYCLE_NEVER;
451 }
452 }
453 }
454 if (last_poll_cycle >= deduction) {
455 last_poll_cycle -= deduction;
456 } else {
457 last_poll_cycle = 0;
458 }
459}
460
461static void wait_for_connection(io_port * port)
462{
463 if (port->device.stream.data_fd == -1)
464 {
465 debug_message("Waiting for socket connection...");
466 port->device.stream.data_fd = accept(port->device.stream.listen_fd, NULL, NULL);
467 fcntl(port->device.stream.data_fd, F_SETFL, O_NONBLOCK | O_RDWR);
468 }
469}
470
471static void service_pipe(io_port * port)
472{
473 uint8_t value;
474 int numRead = read(port->device.stream.data_fd, &value, sizeof(value));
475 if (numRead > 0)
476 {
477 port->input[IO_TH0] = (value & 0xF) | 0x10;
478 port->input[IO_TH1] = (value >> 4) | 0x10;
479 } else if(numRead == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
480 warning("Error reading pipe for IO port: %d %s\n", errno, strerror(errno));
481 }
482}
483
484static void service_socket(io_port *port)
485{
486 uint8_t buf[32];
487 uint8_t blocking = 0;
488 int numRead = 0;
489 while (numRead <= 0)
490 {
491 numRead = recv(port->device.stream.data_fd, buf, sizeof(buf), 0);
492 if (numRead > 0)
493 {
494 port->input[IO_TH0] = buf[numRead-1];
495 if (port->input[IO_STATE] == IO_READ_PENDING)
496 {
497 port->input[IO_STATE] = IO_READ;
498 if (blocking)
499 {
500 //pending read satisfied, back to non-blocking mode
501 fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR | O_NONBLOCK);
502 }
503 } else if (port->input[IO_STATE] == IO_WRITTEN) {
504 port->input[IO_STATE] = IO_READ;
505 }
506 } else if (numRead == 0) {
507 port->device.stream.data_fd = -1;
508 wait_for_connection(port);
509 } else if (errno != EAGAIN && errno != EWOULDBLOCK) {
510 warning("Error reading from socket for IO port: %d %s\n", errno, strerror(errno));
511 close(port->device.stream.data_fd);
512 wait_for_connection(port);
513 } else if (port->input[IO_STATE] == IO_READ_PENDING) {
514 //clear the nonblocking flag so the next read will block
515 if (!blocking)
516 {
517 fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR);
518 blocking = 1;
519 }
520 } else {
521 //no new data, but that's ok
522 break;
523 }
524 }
525
526 if (port->input[IO_STATE] == IO_WRITE_PENDING)
527 {
528 uint8_t value = port->output & port->control;
529 int written = 0;
530 blocking = 0;
531 while (written <= 0)
532 {
533 send(port->device.stream.data_fd, &value, sizeof(value), 0);
534 if (written > 0)
535 {
536 port->input[IO_STATE] = IO_WRITTEN;
537 if (blocking)
538 {
539 //pending write satisfied, back to non-blocking mode
540 fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR | O_NONBLOCK);
541 }
542 } else if (written == 0) {
543 port->device.stream.data_fd = -1;
544 wait_for_connection(port);
545 } else if (errno != EAGAIN && errno != EWOULDBLOCK) {
546 warning("Error writing to socket for IO port: %d %s\n", errno, strerror(errno));
547 close(port->device.stream.data_fd);
548 wait_for_connection(port);
549 } else {
550 //clear the nonblocking flag so the next write will block
551 if (!blocking)
552 {
553 fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR);
554 blocking = 1;
555 }
556 }
557 }
558 }
559}
560
561const int mouse_delays[] = {112*7, 120*7, 96*7, 132*7, 104*7, 96*7, 112*7, 96*7};
562
563enum {
564 KB_SETUP,
565 KB_READ,
566 KB_WRITE
567};
568
569void io_control_write(io_port *port, uint8_t value, uint32_t current_cycle)
570{
571 uint8_t changes = value ^ port->control;
572 if (changes) {
573 for (int i = 0; i < 8; i++)
574 {
575 if (!(value & 1 << i) && !(port->output & 1 << i)) {
576 //port switched from output to input and the output value was 0
577 //since there is a weak pull-up on input pins, this will lead
578 //to a slow rise from 0 to 1 if the pin isn't being externally driven
579 port->slow_rise_start[i] = current_cycle;
580 } else {
581 port->slow_rise_start[i] = CYCLE_NEVER;
582 }
583 }
584 port->control = value;
585 }
586}
587
588void io_data_write(io_port * port, uint8_t value, uint32_t current_cycle)
589{
590 uint8_t old_output = (port->control & port->output) | (~port->control & 0xFF);
591 uint8_t output = (port->control & value) | (~port->control & 0xFF);
592 switch (port->device_type)
593 {
594 case IO_GAMEPAD6:
595 //check if TH has changed
596 if ((old_output & TH) ^ (output & TH)) {
597 if (current_cycle >= port->device.pad.timeout_cycle) {
598 port->device.pad.th_counter = 0;
599 }
600 if ((output & TH)) {
601 port->device.pad.th_counter++;
602 }
603 port->device.pad.timeout_cycle = current_cycle + TH_TIMEOUT;
604 }
605 break;
606 case IO_MOUSE:
607 mouse_check_ready(port, current_cycle);
608 if (output & TH) {
609 //request is over or mouse is being reset
610 if (port->device.mouse.tr_counter) {
611 //request is over
612 port->device.mouse.last_read_x = port->device.mouse.latched_x;
613 port->device.mouse.last_read_y = port->device.mouse.latched_y;
614 }
615 port->device.mouse.tr_counter = 0;
616 port->device.mouse.ready_cycle = CYCLE_NEVER;
617 } else {
618 if ((output & TR) != (old_output & TR)) {
619 int delay_index = port->device.mouse.tr_counter >= sizeof(mouse_delays) ? sizeof(mouse_delays)-1 : port->device.mouse.tr_counter;
620 port->device.mouse.ready_cycle = current_cycle + mouse_delays[delay_index];
621 }
622 }
623 break;
624 case IO_SATURN_KEYBOARD:
625 if (output & TH) {
626 //request is over
627 if (port->device.keyboard.tr_counter >= 10 && port->device.keyboard.read_pos != 0xFF) {
628 //remove scan code from buffer
629 port->device.keyboard.read_pos++;
630 port->device.keyboard.read_pos &= 7;
631 if (port->device.keyboard.read_pos == port->device.keyboard.write_pos) {
632 port->device.keyboard.read_pos = 0xFF;
633 }
634 }
635 port->device.keyboard.tr_counter = 0;
636 } else {
637 if ((output & TR) != (old_output & TR)) {
638 port->device.keyboard.tr_counter++;
639 }
640 }
641 break;
642 case IO_XBAND_KEYBOARD:
643 if (output & TH) {
644 //request is over
645 if (
646 port->device.keyboard.mode == KB_READ && port->device.keyboard.tr_counter > 6
647 && (port->device.keyboard.tr_counter & 1)
648 ) {
649 if (port->device.keyboard.events[port->device.keyboard.read_pos] & 0xFF00) {
650 port->device.keyboard.events[port->device.keyboard.read_pos] &= 0xFF;
651 } else {
652 port->device.keyboard.read_pos++;
653 port->device.keyboard.read_pos &= 7;
654 if (port->device.keyboard.read_pos == port->device.keyboard.write_pos) {
655 port->device.keyboard.read_pos = 0xFF;
656 }
657 }
658 }
659 port->device.keyboard.tr_counter = 0;
660 port->device.keyboard.mode = KB_SETUP;
661 } else {
662 if ((output & TR) != (old_output & TR)) {
663 port->device.keyboard.tr_counter++;
664 if (port->device.keyboard.tr_counter == 2) {
665 port->device.keyboard.mode = (output & 0xF) ? KB_READ : KB_WRITE;
666 } else if (port->device.keyboard.mode == KB_WRITE) {
667 switch (port->device.keyboard.tr_counter)
668 {
669 case 3:
670 //host writes 0b0001
671 break;
672 case 4:
673 //host writes 0b0000
674 break;
675 case 5:
676 //host writes 0b0000
677 break;
678 case 6:
679 port->device.keyboard.cmd = output << 4;
680 break;
681 case 7:
682 port->device.keyboard.cmd |= output & 0xF;
683 //TODO: actually do something with the command
684 break;
685 }
686 } else if (
687 port->device.keyboard.mode == KB_READ && port->device.keyboard.tr_counter > 7
688 && !(port->device.keyboard.tr_counter & 1)
689 ) {
690
691 if (port->device.keyboard.events[port->device.keyboard.read_pos] & 0xFF00) {
692 port->device.keyboard.events[port->device.keyboard.read_pos] &= 0xFF;
693 } else {
694 port->device.keyboard.read_pos++;
695 port->device.keyboard.read_pos &= 7;
696 if (port->device.keyboard.read_pos == port->device.keyboard.write_pos) {
697 port->device.keyboard.read_pos = 0xFF;
698 }
699 }
700 }
701 }
702 }
703 break;
704 case IO_GENERIC:
705 wait_for_connection(port);
706 port->input[IO_STATE] = IO_WRITE_PENDING;
707 service_socket(port);
708 break;
709 }
710 port->output = value;
711
712}
713
714uint8_t get_scancode_bytes(io_port *port)
715{
716 if (port->device.keyboard.read_pos == 0xFF) {
717 return 0;
718 }
719 uint8_t bytes = 0, read_pos = port->device.keyboard.read_pos;
720 do {
721 bytes += port->device.keyboard.events[read_pos] & 0xFF00 ? 2 : 1;
722 read_pos++;
723 read_pos &= 7;
724 } while (read_pos != port->device.keyboard.write_pos);
725
726 return bytes;
727}
728
729#define SLOW_RISE_DEVICE (30*7)
730#define SLOW_RISE_INPUT (12*7)
731
732static uint8_t get_output_value(io_port *port, uint32_t current_cycle, uint32_t slow_rise_delay)
733{
734 uint8_t output = (port->control | 0x80) & port->output;
735 for (int i = 0; i < 8; i++)
736 {
737 if (!(port->control & 1 << i)) {
738 if (port->slow_rise_start[i] != CYCLE_NEVER) {
739 if (current_cycle - port->slow_rise_start[i] >= slow_rise_delay) {
740 output |= 1 << i;
741 }
742 } else {
743 output |= 1 << i;
744 }
745 }
746 }
747 return output;
748}
749
750uint8_t io_data_read(io_port * port, uint32_t current_cycle)
751{
752 uint8_t output = get_output_value(port, current_cycle, SLOW_RISE_DEVICE);
753 uint8_t control = port->control | 0x80;
754 uint8_t th = output & 0x40;
755 uint8_t input;
756 uint8_t device_driven;
757 if (current_cycle - last_poll_cycle > MIN_POLL_INTERVAL) {
758 process_events();
759 last_poll_cycle = current_cycle;
760 }
761 switch (port->device_type)
762 {
763 case IO_GAMEPAD2:
764 input = ~port->input[GAMEPAD_TH1];
765 device_driven = 0x3F;
766 break;
767 case IO_GAMEPAD3:
768 {
769 input = port->input[th ? GAMEPAD_TH1 : GAMEPAD_TH0];
770 if (!th) {
771 input |= 0xC;
772 }
773 //controller output is logically inverted
774 input = ~input;
775 device_driven = 0x3F;
776 break;
777 }
778 case IO_GAMEPAD6:
779 {
780 if (current_cycle >= port->device.pad.timeout_cycle) {
781 port->device.pad.th_counter = 0;
782 }
783 /*if (port->input[GAMEPAD_TH0] || port->input[GAMEPAD_TH1]) {
784 printf("io_data_read | control: %X, TH: %X, GAMEPAD_TH0: %X, GAMEPAD_TH1: %X, TH Counter: %d, Timeout: %d, Cycle: %d\n", control, th, port->input[GAMEPAD_TH0], port->input[GAMEPAD_TH1], port->th_counter,port->timeout_cycle, context->current_cycle);
785 }*/
786 if (th) {
787 if (port->device.pad.th_counter == 3) {
788 input = port->input[GAMEPAD_EXTRA];
789 } else {
790 input = port->input[GAMEPAD_TH1];
791 }
792 } else {
793 if (port->device.pad.th_counter == 2) {
794 input = port->input[GAMEPAD_TH0] | 0xF;
795 } else if(port->device.pad.th_counter == 3) {
796 input = port->input[GAMEPAD_TH0] & 0x30;
797 } else {
798 input = port->input[GAMEPAD_TH0] | 0xC;
799 }
800 }
801 //controller output is logically inverted
802 input = ~input;
803 device_driven = 0x3F;
804 break;
805 }
806 case IO_MOUSE:
807 {
808 mouse_check_ready(port, current_cycle);
809 uint8_t tr = output & TR;
810 if (th) {
811 if (tr) {
812 input = 0x10;
813 } else {
814 input = 0;
815 }
816 } else {
817
818 int16_t delta_x = port->device.mouse.latched_x - port->device.mouse.last_read_x;
819 int16_t delta_y = port->device.mouse.last_read_y - port->device.mouse.latched_y;
820 switch (port->device.mouse.tr_counter)
821 {
822 case 0:
823 input = 0xB;
824 break;
825 case 1:
826 case 2:
827 input = 0xF;
828 break;
829 case 3:
830 input = 0;
831 if (delta_y > 255 || delta_y < -255) {
832 input |= 8;
833 }
834 if (delta_x > 255 || delta_x < -255) {
835 input |= 4;
836 }
837 if (delta_y < 0) {
838 input |= 2;
839 }
840 if (delta_x < 0) {
841 input |= 1;
842 }
843 break;
844 case 4:
845 input = port->input[0];
846 break;
847 case 5:
848 input = delta_x >> 4 & 0xF;
849 break;
850 case 6:
851 input = delta_x & 0xF;
852 break;
853 case 7:
854 input = delta_y >> 4 & 0xF;
855 break;
856 case 8:
857 default:
858 input = delta_y & 0xF;
859 break;
860 }
861 input |= ((port->device.mouse.tr_counter & 1) == 0) << 4;
862 }
863 device_driven = 0x1F;
864 break;
865 }
866 case IO_SATURN_KEYBOARD:
867 {
868 if (th) {
869 input = 0x11;
870 } else {
871 uint16_t code = port->device.keyboard.read_pos == 0xFF ? 0
872 : port->device.keyboard.events[port->device.keyboard.read_pos];
873 switch (port->device.keyboard.tr_counter)
874 {
875 case 0:
876 input = 1;
877 break;
878 case 1:
879 //Saturn peripheral ID
880 input = 3;
881 break;
882 case 2:
883 //data size
884 input = 4;
885 break;
886 case 3:
887 //d-pad
888 //TODO: set these based on keyboard state
889 input = 0xF;
890 break;
891 case 4:
892 //Start ABC
893 //TODO: set these based on keyboard state
894 input = 0xF;
895 break;
896 case 5:
897 //R XYZ
898 //TODO: set these based on keyboard state
899 input = 0xF;
900 break;
901 case 6:
902 //L and KBID
903 //TODO: set L based on keyboard state
904 input = 0x8;
905 break;
906 case 7:
907 //Capslock, Numlock, Scrolllock
908 //TODO: set these based on keyboard state
909 input = 0;
910 break;
911 case 8:
912 input = 6;
913 if (code & 0xFF00) {
914 //break
915 input |= 1;
916 } else if (code) {
917 input |= 8;
918 }
919 break;
920 case 9:
921 input = code >> 4 & 0xF;
922 break;
923 case 10:
924 input = code & 0xF;
925 break;
926 case 11:
927 input = 0;
928 break;
929 default:
930 input = 1;
931 break;
932 }
933 input |= ((port->device.keyboard.tr_counter & 1) == 0) << 4;
934 }
935 device_driven = 0x1F;
936 break;
937 }
938 case IO_XBAND_KEYBOARD:
939 {
940 if (th) {
941 input = 0x1C;
942 } else {
943 uint8_t size;
944 if (port->device.keyboard.mode == KB_SETUP || port->device.keyboard.mode == KB_READ) {
945 switch (port->device.keyboard.tr_counter)
946 {
947 case 0:
948 input = 0x3;
949 break;
950 case 1:
951 input = 0x6;
952 break;
953 case 2:
954 //This is where thoe host indicates a read or write
955 //presumably, the keyboard only outputs this if the host
956 //is not already driving the data bus low
957 input = 0x9;
958 break;
959 case 3:
960 size = get_scancode_bytes(port);
961 if (size) {
962 ++size;
963 }
964 if (size > 15) {
965 size = 15;
966 }
967 input = size;
968 break;
969 case 4:
970 case 5:
971 //always send packet type 0 for now
972 input = 0;
973 break;
974 default:
975 if (port->device.keyboard.read_pos == 0xFF) {
976 //we've run out of bytes
977 input = 0;
978 } else if (port->device.keyboard.events[port->device.keyboard.read_pos] & 0xFF00) {
979 if (port->device.keyboard.tr_counter & 1) {
980 input = port->device.keyboard.events[port->device.keyboard.read_pos] >> 8 & 0xF;
981 } else {
982 input = port->device.keyboard.events[port->device.keyboard.read_pos] >> 12;
983 }
984 } else {
985 if (port->device.keyboard.tr_counter & 1) {
986 input = port->device.keyboard.events[port->device.keyboard.read_pos] & 0xF;
987 } else {
988 input = port->device.keyboard.events[port->device.keyboard.read_pos] >> 4;
989 }
990 }
991 break;
992 }
993 } else {
994 input = 0xF;
995 }
996 input |= ((port->device.keyboard.tr_counter & 1) == 0) << 4;
997 }
998 //this is not strictly correct at all times, but good enough for now
999 device_driven = 0x1F;
1000 break;
1001 }
1002 case IO_SEGA_PARALLEL:
1003 if (!th)
1004 {
1005 service_pipe(port);
1006 }
1007 input = port->input[th ? IO_TH1 : IO_TH0];
1008 device_driven = 0x3F;
1009 break;
1010 case IO_GENERIC:
1011 if (port->input[IO_TH0] & 0x80 && port->input[IO_STATE] == IO_WRITTEN)
1012 {
1013 //device requested a blocking read after writes
1014 port->input[IO_STATE] = IO_READ_PENDING;
1015 }
1016 service_socket(port);
1017 input = port->input[IO_TH0];
1018 device_driven = 0x7F;
1019 break;
1020 default:
1021 input = 0;
1022 device_driven = 0;
1023 break;
1024 }
1025 uint8_t value = (input & (~control) & device_driven) | (port->output & control);
1026 //deal with pins that are configured as inputs, but not being actively driven by the device
1027 uint8_t floating = (~device_driven) & (~control);
1028 if (floating) {
1029 value |= get_output_value(port, current_cycle, SLOW_RISE_INPUT) & floating;
1030 }
1031 /*if (port->input[GAMEPAD_TH0] || port->input[GAMEPAD_TH1]) {
1032 printf ("value: %X\n", value);
1033 }*/
1034 return value;
1035}
1036
1037void io_serialize(io_port *port, serialize_buffer *buf)
1038{
1039 save_int8(buf, port->output);
1040 save_int8(buf, port->control);
1041 save_int8(buf, port->serial_out);
1042 save_int8(buf, port->serial_in);
1043 save_int8(buf, port->serial_ctrl);
1044 save_int8(buf, port->device_type);
1045 save_buffer32(buf, port->slow_rise_start, 8);
1046 switch (port->device_type)
1047 {
1048 case IO_GAMEPAD6:
1049 save_int32(buf, port->device.pad.timeout_cycle);
1050 save_int16(buf, port->device.pad.th_counter);
1051 break;
1052 case IO_MOUSE:
1053 save_int32(buf, port->device.mouse.ready_cycle);
1054 save_int16(buf, port->device.mouse.last_read_x);
1055 save_int16(buf, port->device.mouse.last_read_y);
1056 save_int16(buf, port->device.mouse.latched_x);
1057 save_int16(buf, port->device.mouse.latched_y);
1058 save_int8(buf, port->device.mouse.tr_counter);
1059 break;
1060 case IO_SATURN_KEYBOARD:
1061 case IO_XBAND_KEYBOARD:
1062 save_int8(buf, port->device.keyboard.tr_counter);
1063 if (port->device_type == IO_XBAND_KEYBOARD) {
1064 save_int8(buf, port->device.keyboard.mode);
1065 save_int8(buf, port->device.keyboard.cmd);
1066 }
1067 break;
1068 }
1069}
1070
1071void io_deserialize(deserialize_buffer *buf, void *vport)
1072{
1073 io_port *port = vport;
1074 port->output = load_int8(buf);
1075 port->control = load_int8(buf);
1076 port->serial_out = load_int8(buf);
1077 port->serial_in = load_int8(buf);
1078 port->serial_ctrl = load_int8(buf);
1079 uint8_t device_type = load_int8(buf);
1080 if (device_type != port->device_type) {
1081 warning("Loaded save state has a different device type from the current configuration");
1082 return;
1083 }
1084 switch (port->device_type)
1085 {
1086 case IO_GAMEPAD6:
1087 port->device.pad.timeout_cycle = load_int32(buf);
1088 port->device.pad.th_counter = load_int16(buf);
1089 break;
1090 case IO_MOUSE:
1091 port->device.mouse.ready_cycle = load_int32(buf);
1092 port->device.mouse.last_read_x = load_int16(buf);
1093 port->device.mouse.last_read_y = load_int16(buf);
1094 port->device.mouse.latched_x = load_int16(buf);
1095 port->device.mouse.latched_y = load_int16(buf);
1096 port->device.mouse.tr_counter = load_int8(buf);
1097 break;
1098 case IO_SATURN_KEYBOARD:
1099 case IO_XBAND_KEYBOARD:
1100 port->device.keyboard.tr_counter = load_int8(buf);
1101 if (port->device_type == IO_XBAND_KEYBOARD) {
1102 port->device.keyboard.mode = load_int8(buf);
1103 port->device.keyboard.cmd = load_int8(buf);
1104 }
1105 break;
1106 }
1107}