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);