From 9e6f6c5a67db16949d1183d03075a528f23590ae Mon Sep 17 00:00:00 2001 From: Toby Jaffey Date: Sun, 7 Dec 2025 20:29:10 +0000 Subject: [PATCH] Added IOREQ_MILLIS and IOREQ_GETC to get current time and poll keyboard. IOREQ_GETC implemented inefficiently, but is fine for demo purposes. --- common/uvm32_common_custom.h | 1 + host/Makefile | 2 +- host/host.c | 90 +++++++++++++++++++++++++++++++++--- 3 files changed, 86 insertions(+), 7 deletions(-) diff --git a/common/uvm32_common_custom.h b/common/uvm32_common_custom.h index e5c0a35..7f6d0a8 100644 --- a/common/uvm32_common_custom.h +++ b/common/uvm32_common_custom.h @@ -7,4 +7,5 @@ #define IOREQ_PRINTX 0x13D #define IOREQ_MILLIS 0x13F #define IOREQ_PRINTC 0x140 +#define IOREQ_GETC 0x141 diff --git a/host/Makefile b/host/Makefile index 0adb487..d31fa90 100644 --- a/host/Makefile +++ b/host/Makefile @@ -1,5 +1,5 @@ all: - gcc -Wall -Werror -pedantic -std=c99 -DUVM32_MEMORY_SIZE=16384 -I../uvm32 -o host ../uvm32/uvm32.c host.c + gcc -Wall -Werror -pedantic -std=c99 -O2 -DUVM32_MEMORY_SIZE=65535 -I../uvm32 -o host ../uvm32/uvm32.c host.c clean: rm -f host diff --git a/host/host.c b/host/host.c index d342558..0370e08 100644 --- a/host/host.c +++ b/host/host.c @@ -1,11 +1,16 @@ #include #include #include - +#include +#include +#include #include "uvm32.h" #include "../common/uvm32_common_custom.h" +// stash terminal settings on startup +static struct termios orig_termios; + // ioreqs exposed to vm environement typedef enum { F_PRINT, @@ -14,6 +19,7 @@ typedef enum { F_PRINTC, F_PRINTLN, F_MILLIS, + F_GETC, } f_code_t; // Map exposed ioreqs to CSRs @@ -24,8 +30,24 @@ const uvm32_mapping_t env[] = { { .csr = IOREQ_PRINTX, .typ = IOREQ_TYP_U32_WR, .code = F_PRINTX }, { .csr = IOREQ_PRINTC, .typ = IOREQ_TYP_U32_WR, .code = F_PRINTC }, { .csr = IOREQ_MILLIS, .typ = IOREQ_TYP_U32_RD, .code = F_MILLIS }, + { .csr = IOREQ_GETC, .typ = IOREQ_TYP_U32_RD, .code = F_GETC }, }; +void disableRawMode(void) { + tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios); +} +void enableRawMode(void) { + tcgetattr(STDIN_FILENO, &orig_termios); + atexit(disableRawMode); + struct termios raw = orig_termios; + raw.c_lflag &= ~(ECHO | ICANON | IEXTEN); + raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + raw.c_cflag |= (CS8); + tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw); + raw.c_cc[VMIN] = 0; + raw.c_cc[VTIME] = 1; +} + static uint8_t *read_file(const char* filename, int *len) { FILE* f = fopen(filename, "rb"); uint8_t *buf = NULL; @@ -56,15 +78,60 @@ static uint8_t *read_file(const char* filename, int *len) { return buf; } +// Poll for input, inelegant, but works and doesn't confuse the main +// flow of the program with select/poll +bool poll_getch(uint8_t* c) { + struct timeval tv; + fd_set readfds; + int ret; + + FD_ZERO(&readfds); + FD_SET(STDIN_FILENO, &readfds); + + tv.tv_sec = 0; + tv.tv_usec = 200; + + ret = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &tv); + + if (ret == -1) { + printf("console read failed\r\n"); + exit(1); + } else if (!ret) { + // timeout + return false; + } + + if (FD_ISSET(STDIN_FILENO, &readfds)) { + int len; + + len = read(STDIN_FILENO, c, 1); + if (len == -1) { + printf("console read failed\r\n"); + exit(1); + } + + if (len) { + if (*c == 0x03 || *c == 0x04) { // ctrl-c ctrl-d + exit(0); + } + if (*c == 0x0d) { + *c = '\n'; + } + return true; + } + } + return false; +} + void hexdump(const uint8_t *p, int len) { while(len--) { printf("%02x", *p++); } } - int main(int argc, char *argv[]) { uvm32_state_t vmst; + clock_t start_time = clock() / (CLOCKS_PER_SEC / 1000); argc--; argv++; @@ -92,8 +159,10 @@ int main(int argc, char *argv[]) { uint32_t total_instrs = 0; uint32_t num_ioreqs = 0; + enableRawMode(); + while(isrunning) { - total_instrs += uvm32_run(&vmst, &evt, 100); // num instructions before vm considered hung + total_instrs += uvm32_run(&vmst, &evt, 1000000); // num instructions before vm considered hung num_ioreqs++; switch(evt.typ) { @@ -126,10 +195,17 @@ int main(int argc, char *argv[]) { case F_PRINTX: printf("%08x", evt.data.ioreq.val.u32); break; + case F_GETC: { + uint8_t ch; + if (poll_getch(&ch)) { + *evt.data.ioreq.val.u32p = ch; + } else { + *evt.data.ioreq.val.u32p = 0xFFFFFFFF; // nothing + } + } break; case F_MILLIS: { - static uint32_t t = 0; - *evt.data.ioreq.val.u32p = t; - t++; + clock_t now = clock() / (CLOCKS_PER_SEC / 1000); + *evt.data.ioreq.val.u32p = now - start_time; } break; default: // catch any others switch(evt.data.ioreq.typ) { @@ -162,5 +238,7 @@ int main(int argc, char *argv[]) { printf("Executed total of %d instructions and %d ioreqs\n", (int)total_instrs, (int)num_ioreqs); free(rom); + + disableRawMode(); return 0; }