Mercurial > repos > blastem
comparison io.c @ 2025:e7a516f08cec
Implement serial IO, a generic serial device type and external interrupts
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Wed, 10 Feb 2021 20:12:16 -0800 |
parents | 52a47611a273 |
children | 0f54a898db03 |
comparison
equal
deleted
inserted
replaced
2022:380bc5d4a2cf | 2025:e7a516f08cec |
---|---|
37 "Justifier", | 37 "Justifier", |
38 "Sega multi-tap", | 38 "Sega multi-tap", |
39 "EA 4-way Play cable A", | 39 "EA 4-way Play cable A", |
40 "EA 4-way Play cable B", | 40 "EA 4-way Play cable B", |
41 "Sega Parallel Transfer Board", | 41 "Sega Parallel Transfer Board", |
42 "Generic Device" | 42 "Generic Device", |
43 "Generic Serial" | |
43 }; | 44 }; |
44 | 45 |
45 #define GAMEPAD_TH0 0 | 46 #define GAMEPAD_TH0 0 |
46 #define GAMEPAD_TH1 1 | 47 #define GAMEPAD_TH1 1 |
47 #define GAMEPAD_EXTRA 2 | 48 #define GAMEPAD_EXTRA 2 |
208 uint8_t io_has_keyboard(sega_io *io) | 209 uint8_t io_has_keyboard(sega_io *io) |
209 { | 210 { |
210 return find_keyboard(io) != NULL; | 211 return find_keyboard(io) != NULL; |
211 } | 212 } |
212 | 213 |
214 static void set_serial_clock(io_port *port) | |
215 { | |
216 switch(port->serial_ctrl >> 6) | |
217 { | |
218 case 0: port->serial_divider = 11186; break; //4800 bps | |
219 case 1: port->serial_divider = 22372; break; //2400 bps | |
220 case 2: port->serial_divider = 44744; break; //1200 bps | |
221 case 3: port->serial_divider = 178976; break; //300 bps | |
222 } | |
223 } | |
224 | |
213 void process_device(char * device_type, io_port * port) | 225 void process_device(char * device_type, io_port * port) |
214 { | 226 { |
227 set_serial_clock(port); | |
215 //assuming that the io_port struct has been zeroed if this is the first time this has been called | 228 //assuming that the io_port struct has been zeroed if this is the first time this has been called |
216 if (!device_type) | 229 if (!device_type) |
217 { | 230 { |
218 return; | 231 return; |
219 } | 232 } |
267 port->device.stream.listen_fd = -1; | 280 port->device.stream.listen_fd = -1; |
268 } | 281 } |
269 } else if(!strcmp(device_type, "generic")) { | 282 } else if(!strcmp(device_type, "generic")) { |
270 if (port->device_type != IO_GENERIC) { | 283 if (port->device_type != IO_GENERIC) { |
271 port->device_type = IO_GENERIC; | 284 port->device_type = IO_GENERIC; |
285 port->device.stream.data_fd = -1; | |
286 port->device.stream.listen_fd = -1; | |
287 } | |
288 } else if(!strcmp(device_type, "serial")) { | |
289 if (port->device_type != IO_GENERIC_SERIAL) { | |
290 port->device_type = IO_GENERIC_SERIAL; | |
272 port->device.stream.data_fd = -1; | 291 port->device.stream.data_fd = -1; |
273 port->device.stream.listen_fd = -1; | 292 port->device.stream.listen_fd = -1; |
274 } | 293 } |
275 } | 294 } |
276 } | 295 } |
352 ports[i].device_type = IO_NONE; | 371 ports[i].device_type = IO_NONE; |
353 } | 372 } |
354 } | 373 } |
355 } | 374 } |
356 } | 375 } |
357 } else if (ports[i].device_type == IO_GENERIC && ports[i].device.stream.data_fd == -1) { | 376 } else if (ports[i].device_type == IO_GENERIC || ports[i].device_type == IO_GENERIC_SERIAL && ports[i].device.stream.data_fd == -1) { |
358 char *sock_name = tern_find_path(config, "io\0socket\0", TVAL_PTR).ptrval; | 377 char *sock_name = tern_find_path(config, "io\0socket\0", TVAL_PTR).ptrval; |
359 if (!sock_name) | 378 if (!sock_name) |
360 { | 379 { |
361 warning("IO port %s is configured to use generic IO, but no socket is set!\n", io_name(i)); | 380 warning("IO port %s is configured to use generic IO, but no socket is set!\n", io_name(i)); |
362 ports[i].device_type = IO_NONE; | 381 ports[i].device_type = IO_NONE; |
425 }*/ | 444 }*/ |
426 } | 445 } |
427 } | 446 } |
428 } | 447 } |
429 | 448 |
430 uint32_t last_poll_cycle; | |
431 void io_adjust_cycles(io_port * port, uint32_t current_cycle, uint32_t deduction) | 449 void io_adjust_cycles(io_port * port, uint32_t current_cycle, uint32_t deduction) |
432 { | 450 { |
433 /*uint8_t control = pad->control | 0x80; | 451 /*uint8_t control = pad->control | 0x80; |
434 uint8_t th = control & pad->output; | 452 uint8_t th = control & pad->output; |
435 if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) { | 453 if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) { |
457 } else { | 475 } else { |
458 port->slow_rise_start[i] = CYCLE_NEVER; | 476 port->slow_rise_start[i] = CYCLE_NEVER; |
459 } | 477 } |
460 } | 478 } |
461 } | 479 } |
462 if (last_poll_cycle >= deduction) { | 480 if (port->transmit_end >= deduction) { |
463 last_poll_cycle -= deduction; | 481 port->transmit_end -= deduction; |
464 } else { | 482 } else { |
465 last_poll_cycle = 0; | 483 port->transmit_end = 0; |
484 } | |
485 if (port->receive_end >= deduction) { | |
486 port->receive_end -= deduction; | |
487 } else { | |
488 port->receive_end = 0; | |
489 } | |
490 if (port->last_poll_cycle >= deduction) { | |
491 port->last_poll_cycle -= deduction; | |
492 } else { | |
493 port->last_poll_cycle = 0; | |
466 } | 494 } |
467 } | 495 } |
468 | 496 |
469 #ifndef _WIN32 | 497 #ifndef _WIN32 |
470 static void wait_for_connection(io_port * port) | 498 static void wait_for_connection(io_port *port) |
471 { | 499 { |
472 if (port->device.stream.data_fd == -1) | 500 if (port->device.stream.data_fd == -1) |
473 { | 501 { |
474 debug_message("Waiting for socket connection..."); | 502 debug_message("Waiting for socket connection...\n"); |
475 port->device.stream.data_fd = accept(port->device.stream.listen_fd, NULL, NULL); | 503 port->device.stream.data_fd = accept(port->device.stream.listen_fd, NULL, NULL); |
476 fcntl(port->device.stream.data_fd, F_SETFL, O_NONBLOCK | O_RDWR); | 504 fcntl(port->device.stream.data_fd, F_SETFL, O_NONBLOCK | O_RDWR); |
477 } | 505 } |
478 } | 506 } |
479 | 507 |
480 static void service_pipe(io_port * port) | 508 static void poll_for_connection(io_port *port) |
509 { | |
510 if (port->device.stream.data_fd == -1) | |
511 { | |
512 fcntl(port->device.stream.listen_fd, F_SETFL, O_NONBLOCK | O_RDWR); | |
513 port->device.stream.data_fd = accept(port->device.stream.listen_fd, NULL, NULL); | |
514 fcntl(port->device.stream.listen_fd, F_SETFL, O_RDWR); | |
515 if (port->device.stream.data_fd != -1) { | |
516 fcntl(port->device.stream.data_fd, F_SETFL, O_NONBLOCK | O_RDWR); | |
517 } | |
518 } | |
519 } | |
520 | |
521 static void write_serial_byte(io_port *port) | |
522 { | |
523 fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR); | |
524 for (int sent = 0; sent != sizeof(port->serial_transmitting);) | |
525 { | |
526 sent = send(port->device.stream.data_fd, &port->serial_transmitting, sizeof(port->serial_transmitting), 0); | |
527 if (sent < 0) { | |
528 close(port->device.stream.data_fd); | |
529 port->device.stream.data_fd = -1; | |
530 wait_for_connection(port); | |
531 fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR); | |
532 } | |
533 } | |
534 fcntl(port->device.stream.data_fd, F_SETFL, O_NONBLOCK | O_RDWR); | |
535 } | |
536 | |
537 static void read_serial_byte(io_port *port) | |
538 { | |
539 poll_for_connection(port); | |
540 if (port->device.stream.data_fd == -1) { | |
541 return; | |
542 } | |
543 int read = recv(port->device.stream.data_fd, &port->serial_receiving, sizeof(port->serial_receiving), 0); | |
544 if (read < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { | |
545 close(port->device.stream.data_fd); | |
546 port->device.stream.data_fd = -1; | |
547 } | |
548 if (read > 0) { | |
549 port->receive_end = port->serial_cycle + 10 * port->serial_divider; | |
550 } | |
551 } | |
552 | |
553 static void service_pipe(io_port *port) | |
481 { | 554 { |
482 uint8_t value; | 555 uint8_t value; |
483 int numRead = read(port->device.stream.data_fd, &value, sizeof(value)); | 556 int numRead = read(port->device.stream.data_fd, &value, sizeof(value)); |
484 if (numRead > 0) | 557 if (numRead > 0) |
485 { | 558 { |
573 enum { | 646 enum { |
574 KB_SETUP, | 647 KB_SETUP, |
575 KB_READ, | 648 KB_READ, |
576 KB_WRITE | 649 KB_WRITE |
577 }; | 650 }; |
651 | |
652 enum { | |
653 SCTRL_BIT_TX_FULL = 1, | |
654 SCTRL_BIT_RX_READY = 2, | |
655 SCTRL_BIT_RX_ERROR = 4, | |
656 SCTRL_BIT_RX_INTEN = 8, | |
657 SCTRL_BIT_TX_ENABLE = 0x10, | |
658 SCTRL_BIT_RX_ENABLE = 0x20 | |
659 }; | |
660 | |
661 void io_run(io_port *port, uint32_t current_cycle) | |
662 { | |
663 uint32_t new_serial_cycle = ((current_cycle - port->serial_cycle) / port->serial_divider) * port->serial_divider + port->serial_cycle; | |
664 if (port->transmit_end && port->transmit_end <= new_serial_cycle) { | |
665 port->transmit_end = 0; | |
666 | |
667 if (port->serial_ctrl & SCTRL_BIT_TX_ENABLE) { | |
668 switch (port->device_type) | |
669 { | |
670 #ifndef _WIN32 | |
671 case IO_GENERIC_SERIAL: | |
672 write_serial_byte(port); | |
673 break; | |
674 #endif | |
675 //TODO: think about how serial mode might interact with non-serial peripherals | |
676 } | |
677 } | |
678 } | |
679 if (!port->transmit_end && new_serial_cycle != port->serial_cycle && (port->serial_ctrl & SCTRL_BIT_TX_FULL)) { | |
680 //there's a transmit byte pending and no byte is currently being sent | |
681 port->serial_transmitting = port->serial_out; | |
682 port->serial_ctrl &= ~SCTRL_BIT_TX_FULL; | |
683 //1 start bit, 8 data bits and 1 stop bit | |
684 port->transmit_end = new_serial_cycle + 10 * port->serial_divider; | |
685 } | |
686 port->serial_cycle = new_serial_cycle; | |
687 if (port->serial_ctrl && SCTRL_BIT_RX_ENABLE) { | |
688 if (port->receive_end && new_serial_cycle >= port->receive_end) { | |
689 port->serial_in = port->serial_receiving; | |
690 port->serial_ctrl |= SCTRL_BIT_RX_READY; | |
691 port->receive_end = 0; | |
692 } | |
693 if (!port->receive_end) { | |
694 switch(port->device_type) | |
695 { | |
696 #ifndef _WIN32 | |
697 case IO_GENERIC_SERIAL: | |
698 read_serial_byte(port); | |
699 break; | |
700 #endif | |
701 //TODO: think about how serial mode might interact with non-serial peripherals | |
702 } | |
703 } | |
704 } | |
705 } | |
578 | 706 |
579 void io_control_write(io_port *port, uint8_t value, uint32_t current_cycle) | 707 void io_control_write(io_port *port, uint8_t value, uint32_t current_cycle) |
580 { | 708 { |
581 uint8_t changes = value ^ port->control; | 709 uint8_t changes = value ^ port->control; |
582 if (changes) { | 710 if (changes) { |
721 } | 849 } |
722 port->output = value; | 850 port->output = value; |
723 | 851 |
724 } | 852 } |
725 | 853 |
854 void io_tx_write(io_port *port, uint8_t value, uint32_t current_cycle) | |
855 { | |
856 io_run(port, current_cycle); | |
857 port->serial_out = value; | |
858 port->serial_ctrl |= SCTRL_BIT_TX_FULL; | |
859 } | |
860 | |
861 void io_sctrl_write(io_port *port, uint8_t value, uint32_t current_cycle) | |
862 { | |
863 io_run(port, current_cycle); | |
864 port->serial_ctrl = (port->serial_ctrl & 0x7) | (value & 0xF8); | |
865 set_serial_clock(port); | |
866 } | |
867 | |
726 uint8_t get_scancode_bytes(io_port *port) | 868 uint8_t get_scancode_bytes(io_port *port) |
727 { | 869 { |
728 if (port->device.keyboard.read_pos == 0xFF) { | 870 if (port->device.keyboard.read_pos == 0xFF) { |
729 return 0; | 871 return 0; |
730 } | 872 } |
764 uint8_t output = get_output_value(port, current_cycle, SLOW_RISE_DEVICE); | 906 uint8_t output = get_output_value(port, current_cycle, SLOW_RISE_DEVICE); |
765 uint8_t control = port->control | 0x80; | 907 uint8_t control = port->control | 0x80; |
766 uint8_t th = output & 0x40; | 908 uint8_t th = output & 0x40; |
767 uint8_t input; | 909 uint8_t input; |
768 uint8_t device_driven; | 910 uint8_t device_driven; |
769 if (current_cycle - last_poll_cycle > MIN_POLL_INTERVAL) { | 911 if (current_cycle - port->last_poll_cycle > MIN_POLL_INTERVAL) { |
770 process_events(); | 912 process_events(); |
771 last_poll_cycle = current_cycle; | 913 port->last_poll_cycle = current_cycle; |
772 } | 914 } |
773 switch (port->device_type) | 915 switch (port->device_type) |
774 { | 916 { |
775 case IO_GAMEPAD2: | 917 case IO_GAMEPAD2: |
776 input = ~port->input[GAMEPAD_TH1]; | 918 input = ~port->input[GAMEPAD_TH1]; |
1047 printf ("value: %X\n", value); | 1189 printf ("value: %X\n", value); |
1048 }*/ | 1190 }*/ |
1049 return value; | 1191 return value; |
1050 } | 1192 } |
1051 | 1193 |
1194 uint8_t io_rx_read(io_port * port, uint32_t current_cycle) | |
1195 { | |
1196 io_run(port, current_cycle); | |
1197 port->serial_ctrl &= ~SCTRL_BIT_RX_READY; | |
1198 return port->serial_in; | |
1199 } | |
1200 | |
1201 uint8_t io_sctrl_read(io_port *port, uint32_t current_cycle) | |
1202 { | |
1203 io_run(port, current_cycle); | |
1204 return port->serial_ctrl; | |
1205 } | |
1206 | |
1207 uint32_t io_next_interrupt(io_port *port, uint32_t current_cycle) | |
1208 { | |
1209 if (!(port->control & 0x80)) { | |
1210 return CYCLE_NEVER; | |
1211 } | |
1212 if (port->serial_ctrl & SCTRL_BIT_RX_INTEN) { | |
1213 if (port->serial_ctrl & SCTRL_BIT_RX_READY) { | |
1214 return current_cycle; | |
1215 } | |
1216 if ((port->serial_ctrl & SCTRL_BIT_RX_ENABLE) && port->receive_end) { | |
1217 return port->receive_end; | |
1218 } | |
1219 } | |
1220 //TODO: handle external interrupts from TH transitions | |
1221 return CYCLE_NEVER; | |
1222 } | |
1223 | |
1052 void io_serialize(io_port *port, serialize_buffer *buf) | 1224 void io_serialize(io_port *port, serialize_buffer *buf) |
1053 { | 1225 { |
1054 save_int8(buf, port->output); | 1226 save_int8(buf, port->output); |
1055 save_int8(buf, port->control); | 1227 save_int8(buf, port->control); |
1056 save_int8(buf, port->serial_out); | 1228 save_int8(buf, port->serial_out); |