diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fee93a..c2a75a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,9 @@ set(CMAKE_CXX_STANDARD_REQUIRED True) add_executable( kek bus.cpp + console.cpp + console_ncurses.cpp + console_posix.cpp cpu.cpp error.cpp main.cpp diff --git a/console.cpp b/console.cpp new file mode 100644 index 0000000..5c1920b --- /dev/null +++ b/console.cpp @@ -0,0 +1,47 @@ +#include "console.h" + + +console::console(std::atomic_bool *const terminate) : + terminate(terminate) +{ + th = new std::thread(std::ref(*this)); +} + +console::~console() +{ + th->join(); + + delete th; +} + +bool console::poll_char() +{ + return buffer.empty() == false; +} + +uint8_t console::get_char() +{ + if (buffer.empty()) + return 0x00; + + char c = buffer.at(0); + + buffer.erase(buffer.begin() + 0); + + return c; +} + +void console::operator()() +{ + while(!*terminate) { + auto c = wait_for_char(500); + + if (c.has_value() == false) + continue; + + if (c == 3) + *terminate = true; + else + buffer.push_back(c.value()); + } +} diff --git a/console.h b/console.h new file mode 100644 index 0000000..3229fbc --- /dev/null +++ b/console.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include +#include + + +class console +{ +private: + std::atomic_bool *const terminate { nullptr }; + + std::thread *th { nullptr }; + + std::vector buffer; + +protected: + virtual std::optional wait_for_char(const int timeout) = 0; + +public: + console(std::atomic_bool *const terminate); + virtual ~console(); + + bool poll_char(); + + uint8_t get_char(); + + virtual void put_char(const char c) = 0; + + virtual void resize_terminal() = 0; + + void operator()(); +}; diff --git a/console_ncurses.cpp b/console_ncurses.cpp new file mode 100644 index 0000000..f671444 --- /dev/null +++ b/console_ncurses.cpp @@ -0,0 +1,69 @@ +#include +#include +#include +#include + +#include "console_ncurses.h" +#include "error.h" + + +console_ncurses::console_ncurses(std::atomic_bool *const terminate) : console(terminate) +{ + init_ncurses(true); + + resize_terminal(); +} + +console_ncurses::~console_ncurses() +{ + wprintw(w_main->win, "\n\n *** PRESS ENTER TO TERMINATE ***\n"); + mydoupdate(); + + while(getch() != 13) { + } + + endwin(); +} + +std::optional console_ncurses::wait_for_char(const int timeout) +{ + struct pollfd fds[] = { { STDIN_FILENO, POLLIN, timeout } }; + + if (poll(fds, 1, 0) == 1 && fds[0].revents) + return getch(); + + return { }; +} + +void console_ncurses::put_char(const char c) +{ + if (c >= 32 || (c != 12 && c != 27 && c != 13)) { + wprintw(w_main->win, "%c", c); + + mydoupdate(); + } +} + +void console_ncurses::resize_terminal() +{ + determine_terminal_size(); + + if (ERR == resizeterm(max_y, max_x)) + error_exit(true, "problem resizing terminal"); + + wresize(stdscr, max_y, max_x); + + endwin(); + refresh(); + + wclear(stdscr); + + delete_window(w_main_b); + delete_window(w_main); + + create_win_border(0, 0, max_x - 2, max_y - 2, "window", &w_main_b, &w_main, false); + + scrollok(w_main -> win, TRUE); + + mydoupdate(); +} diff --git a/console_ncurses.h b/console_ncurses.h new file mode 100644 index 0000000..ee9d1d8 --- /dev/null +++ b/console_ncurses.h @@ -0,0 +1,23 @@ +#include + +#include "console.h" +#include "terminal.h" + + +class console_ncurses : public console +{ +private: + NEWWIN *w_main_b { nullptr }; + NEWWIN *w_main { nullptr }; + +protected: + std::optional wait_for_char(const int timeout) override; + +public: + console_ncurses(std::atomic_bool *const terminate); + virtual ~console_ncurses(); + + void put_char(const char c) override; + + void resize_terminal() override; +}; diff --git a/console_posix.cpp b/console_posix.cpp new file mode 100644 index 0000000..3a31210 --- /dev/null +++ b/console_posix.cpp @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +#include "console_posix.h" +#include "error.h" + + +console_posix::console_posix(std::atomic_bool *const terminate) : console(terminate) +{ + if (tcgetattr(STDIN_FILENO, &org_tty_opts) == -1) + error_exit(true, "console_posix: tcgetattr failed"); + + struct termios tty_opts_raw { 0 }; + cfmakeraw(&tty_opts_raw); + + if (tcsetattr(STDIN_FILENO, TCSANOW, &tty_opts_raw) == -1) + error_exit(true, "console_posix: tcsetattr failed"); +} + +console_posix::~console_posix() +{ + if (tcsetattr(STDIN_FILENO, TCSANOW, &org_tty_opts) == -1) + error_exit(true, "~console_posix: tcsetattr failed"); +} + +std::optional console_posix::wait_for_char(const int timeout) +{ + struct pollfd fds[] = { { STDIN_FILENO, POLLIN, timeout } }; + + if (poll(fds, 1, 0) == 1 && fds[0].revents) + return getchar(); + + return { }; +} + +void console_posix::put_char(const char c) +{ + printf("%c", c); + + fflush(nullptr); +} + +void console_posix::resize_terminal() +{ +} diff --git a/console_posix.h b/console_posix.h new file mode 100644 index 0000000..35f36a7 --- /dev/null +++ b/console_posix.h @@ -0,0 +1,21 @@ +#include + +#include "console.h" + + +class console_posix : public console +{ +private: + struct termios org_tty_opts { 0 }; + +protected: + std::optional wait_for_char(const int timeout) override; + +public: + console_posix(std::atomic_bool *const terminate); + virtual ~console_posix(); + + void put_char(const char c) override; + + void resize_terminal() override; +}; diff --git a/main.cpp b/main.cpp index 8989b4e..7e9329e 100644 --- a/main.cpp +++ b/main.cpp @@ -1,14 +1,14 @@ // (C) 2018-2022 by Folkert van Heusden // Released under Apache License v2.0 #include -#include #include #include #include -#include #include #include "memory.h" +#include "console_ncurses.h" +#include "console_posix.h" #include "cpu.h" #include "tty.h" #include "utils.h" @@ -16,20 +16,11 @@ #include "terminal.h" #include "error.h" -struct termios org_tty_opts { 0 }; bool withUI { false }; uint32_t event { 0 }; std::atomic_bool terminate { false }; -void reset_terminal() -{ - if (withUI) - endwin(); - else - tcsetattr(STDIN_FILENO, TCSANOW, &org_tty_opts); -} - void loadbin(bus *const b, uint16_t base, const char *const file) { FILE *fh = fopen(file, "rb"); @@ -133,30 +124,6 @@ uint16_t loadTape(bus *const b, const char *const file) return start; } -NEWWIN *w_main_b = nullptr, *w_main = nullptr; - -void resize_terminal() -{ - determine_terminal_size(); - - if (ERR == resizeterm(max_y, max_x)) - error_exit(true, "problem resizing terminal"); - - wresize(stdscr, max_y, max_x); - - endwin(); - refresh(); - - wclear(stdscr); - - delete_window(w_main_b); - delete_window(w_main); - create_win_border(0, 0, max_x - 2, max_y - 2, "window", &w_main_b, &w_main, false); - scrollok(w_main -> win, TRUE); - - mydoupdate(); -} - volatile bool sw = false; void sw_handler(int s) { @@ -169,47 +136,6 @@ void sw_handler(int s) } } -bool poll_char() -{ - struct pollfd fds[] = { { STDIN_FILENO, POLLIN, 0 } }; - - return poll(fds, 1, 0) == 1 && fds[0].revents; -} - -char get_char() -{ - char c = getchar(); - - if (c == 3) - event = 1; - - return c; -} - -char get_char_ui() -{ - char c = getch(); - - if (c == 3) - event = 1; - - return c; -} - -void put_char(char c) -{ - printf("%c", c); - fflush(nullptr); -} - -void put_char_ui(char c) -{ - if (c >= 32 || (c != 12 && c != 27 && c != 13)) { - wprintw(w_main -> win, "%c", c); - mydoupdate(); - } -} - void help() { printf("-h this help\n"); @@ -285,13 +211,15 @@ int main(int argc, char *argv[]) return 1; } } - - tty *tty_ = nullptr; + + console *cnsl = nullptr; if (withUI) - tty_ = new tty(poll_char, get_char_ui, put_char_ui); + cnsl = new console_ncurses(&terminate); else - tty_ = new tty(poll_char, get_char, put_char); + cnsl = new console_posix(&terminate); + + tty *tty_ = new tty(cnsl); b->add_tty(tty_); @@ -306,25 +234,11 @@ int main(int argc, char *argv[]) sa.sa_flags = SA_RESTART; if (withUI) { - init_ncurses(true); - sigaction(SIGWINCH, &sa, nullptr); - - resize_terminal(); } - sigaction(SIGTERM , &sa, nullptr); - sigaction(SIGINT , &sa, nullptr); - - atexit(reset_terminal); - - tcgetattr(STDIN_FILENO, &org_tty_opts); - - struct termios tty_opts_raw { 0 }; - cfmakeraw(&tty_opts_raw); - tcsetattr(STDIN_FILENO, TCSANOW, &tty_opts_raw); - - struct pollfd fds[] = { { STDIN_FILENO, POLLIN, 0 } }; + sigaction(SIGTERM, &sa, nullptr); + sigaction(SIGINT , &sa, nullptr); uint32_t icount = 0; uint64_t total_icount = 0; @@ -376,11 +290,11 @@ int main(int argc, char *argv[]) fprintf(stderr, "instructions_executed: %u, took_ms: %lu, new refresh_interval: %u\n", icount, took_ms, refresh_interval); - if (withUI) { - mvwprintw(w_main_b -> win, 0, 24, "%.1f/s ", icount * 1000.0 / took_ms); - mvwprintw(w_main_b -> win, 0, 42, "%06o", b->get_switch_register()); - mydoupdate(); - } +// if (withUI) { +// mvwprintw(w_main_b -> win, 0, 24, "%.1f/s ", icount * 1000.0 / took_ms); +// mvwprintw(w_main_b -> win, 0, 42, "%06o", b->get_switch_register()); +// mydoupdate(); +// } if (terminate) event = 1; @@ -390,8 +304,9 @@ int main(int argc, char *argv[]) } } - if (withUI) - endwin(); + terminate = true; + + delete cnsl; fprintf(stderr, "Instructions per second: %.3f\n\n", icount * 1000.0 / (get_ms() - start)); diff --git a/tty.cpp b/tty.cpp index 27f5dbc..e028fbd 100644 --- a/tty.cpp +++ b/tty.cpp @@ -19,6 +19,7 @@ extern NEWWIN *w_main; #endif + const char * const regnames[] = { "reader status ", "reader buffer ", @@ -26,10 +27,7 @@ const char * const regnames[] = { "puncher buffer" }; -tty::tty(std::function poll_char, std::function get_char, std::function put_char) : - poll_char(poll_char), - get_char(get_char), - put_char(put_char) +tty::tty(console *const c) : c(c) { #if defined(ESP32) queue = xQueueCreate(10, sizeof(char)); @@ -63,7 +61,7 @@ uint16_t tty::readWord(const uint16_t addr) have_char_2 = true; } else if (have_char_2 == false) { - have_char_1 = poll_char(); + have_char_1 = c->poll_char(); } if (addr == PDP11TTY_TKS) { @@ -71,9 +69,9 @@ uint16_t tty::readWord(const uint16_t addr) } else if (addr == PDP11TTY_TKB) { if (have_char_2) { - uint8_t c = get_char(); + uint8_t ch = c->get_char(); - vtemp = c | (parity(c) << 7); + vtemp = ch | (parity(ch) << 7); have_char_2 = false; } @@ -115,15 +113,15 @@ void tty::writeWord(const uint16_t addr, uint16_t v) D(fprintf(stderr, "PDP11TTY write %o (%s): %o\n", addr, regnames[reg], v);) if (addr == PDP11TTY_TPB) { - char c = v & 127; + char ch = v & 127; - D(fprintf(stderr, "PDP11TTY print '%c'\n", c);) + D(fprintf(stderr, "PDP11TTY print '%c'\n", ch);) #if defined(ESP32) - if (xQueueSend(queue, &c, portMAX_DELAY) != pdTRUE) + if (xQueueSend(queue, &ch, portMAX_DELAY) != pdTRUE) Serial.println(F("queue TTY character failed")); #else - put_char(c); + c->put_char(ch); #endif } diff --git a/tty.h b/tty.h index 421a74f..41a5902 100644 --- a/tty.h +++ b/tty.h @@ -2,11 +2,13 @@ // Released under Apache License v2.0 #pragma once -#include #include #include #include +#include "console.h" + + #define PDP11TTY_TKS 0177560 // reader status #define PDP11TTY_TKB 0177562 // reader buffer #define PDP11TTY_TPS 0177564 // puncher status @@ -19,9 +21,7 @@ class memory; class tty { private: - std::function poll_char; - std::function get_char; - std::function put_char; + console *const c { nullptr }; bool have_char_1 { false }; // RCVR BUSY bit high (11) bool have_char_2 { false }; // RCVR DONE bit high (7) uint16_t registers[4] { 0 }; @@ -32,7 +32,7 @@ private: #endif public: - tty(std::function poll_char, std::function get_char, std::function put_char); + tty(console *const c); virtual ~tty(); #if defined(ESP32)