diff --git a/Makefile b/Makefile index 5159d2c..4c9a3ad 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,8 @@ CFILES = src/main.c \ src/keyboard.c \ src/mmu.c \ src/mouse.c \ - src/screen.c + src/screen.c \ + src/serial.c FOX32ROM_IN = fox32.rom FOX32ROM_OUT = fox32rom.h diff --git a/docs/io_bus.md b/docs/io_bus.md index 1913854..053df79 100644 --- a/docs/io_bus.md +++ b/docs/io_bus.md @@ -28,6 +28,9 @@ Writing to this register outputs the lowest 8 bits as a byte on the debug serial port (stdout in case of the fox32 emulator). If necessary, the CPU is stalled long enough to ensure that the byte is output rather than discarded. +Reading from this register gets a byte of input from the serial port, if +available, or zero otherwise. + ## 0x80000000: Display diff --git a/src/bus.c b/src/bus.c index e3a210e..83c1f20 100644 --- a/src/bus.c +++ b/src/bus.c @@ -16,6 +16,7 @@ #include "framebuffer.h" #include "keyboard.h" #include "mouse.h" +#include "serial.h" bool bus_requests_exit = false; @@ -29,6 +30,11 @@ extern mouse_t mouse; int bus_io_read(void *user, uint32_t *value, uint32_t port) { (void) user; switch (port) { + case 0x00000000: { // serial port + *value = serial_get(); + break; + }; + case 0x80000000 ... 0x8000031F: { // overlay port uint8_t overlay_number = port & 0x000000FF; uint8_t setting = (port & 0x0000FF00) >> 8; @@ -152,9 +158,8 @@ int bus_io_read(void *user, uint32_t *value, uint32_t port) { int bus_io_write(void *user, uint32_t value, uint32_t port) { (void) user; switch (port) { - case 0x00000000: { // terminal output port - putchar((int) value); - fflush(stdout); + case 0x00000000: { // serial port + serial_put(value); break; }; diff --git a/src/main.c b/src/main.c index d08e84a..cb31e2d 100644 --- a/src/main.c +++ b/src/main.c @@ -16,6 +16,7 @@ #include "keyboard.h" #include "mouse.h" #include "screen.h" +#include "serial.h" #include "../fox32rom.h" @@ -110,6 +111,8 @@ int main(int argc, char *argv[]) { ScreenDraw(); } + serial_init(); + tick_start = SDL_GetTicks(); tick_end = SDL_GetTicks(); diff --git a/src/serial.c b/src/serial.c new file mode 100644 index 0000000..2d68d56 --- /dev/null +++ b/src/serial.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +#include + +static struct termios saved_tios; +static bool is_terminal = false; + +static void exit_handler(void) { + if (is_terminal) + tcsetattr(0, TCSANOW, &saved_tios); +} + +void serial_init(void) { + struct termios tios; + + if (tcgetattr(0, &tios) != -1) { + is_terminal = 1; + saved_tios = tios; + + atexit(exit_handler); + } + + if (is_terminal) { + tios.c_lflag &= ~(ICANON|ECHO); + tcsetattr(0, TCSANOW, &tios); + } +} + +int serial_get(void) { + fd_set readfds; + int fd = STDIN_FILENO; + struct timeval tm = { 0, 0 }; + + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + int ready = select(fd + 1, &readfds, NULL, NULL, &tm); + + if (ready == 1 && FD_ISSET(fd, &readfds)) { + char c; + int ret = read(fd, &c, 1); + + if (ret == 1) + return c; + } + + return 0; +} + +void serial_put(int value) { + putchar((int) value); + fflush(stdout); +} diff --git a/src/serial.h b/src/serial.h new file mode 100644 index 0000000..cbd5a33 --- /dev/null +++ b/src/serial.h @@ -0,0 +1,5 @@ +#pragma once + +void serial_init(void); +int serial_get(void); +void serial_put(int value);