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/ESP32/console.cpp b/ESP32/console.cpp new file mode 120000 index 0000000..1e29138 --- /dev/null +++ b/ESP32/console.cpp @@ -0,0 +1 @@ +../console.cpp \ No newline at end of file diff --git a/ESP32/console.h b/ESP32/console.h new file mode 120000 index 0000000..e323210 --- /dev/null +++ b/ESP32/console.h @@ -0,0 +1 @@ +../console.h \ No newline at end of file diff --git a/ESP32/console_esp32.cpp b/ESP32/console_esp32.cpp new file mode 100644 index 0000000..27fd0e7 --- /dev/null +++ b/ESP32/console_esp32.cpp @@ -0,0 +1,36 @@ +#include +#include +#include + +#include "console_esp32.h" +#include "error.h" + + +console_esp32::console_esp32(std::atomic_bool *const terminate) : console(terminate) +{ +} + +console_esp32::~console_esp32() +{ +} + +int console_esp32::wait_for_char(const int timeout) +{ + for(int i=0; i + +#include "console.h" + + +class console_esp32 : public console +{ +protected: + int wait_for_char(const int timeout) override; + +public: + console_esp32(std::atomic_bool *const terminate); + virtual ~console_esp32(); + + void put_char(const char c) override; + + void resize_terminal() override; +}; diff --git a/ESP32/main.ino b/ESP32/main.ino index d500889..e4e665f 100644 --- a/ESP32/main.ino +++ b/ESP32/main.ino @@ -10,6 +10,7 @@ #include #include +#include "console_esp32.h" #include "cpu.h" #include "error.h" #include "esp32.h" @@ -20,9 +21,10 @@ #define NEOPIXELS_PIN 25 -bus *b = nullptr; -cpu *c = nullptr; -tty *tty_ = nullptr; +bus *b = nullptr; +cpu *c = nullptr; +tty *tty_ = nullptr; +console *cnsl = nullptr; uint32_t event = 0; @@ -30,11 +32,12 @@ uint16_t exec_addr = 0; uint32_t start_ts = 0; -std::atomic_bool running { false }; -std::atomic_bool on_wifi { false }; -std::atomic_bool console_telnet_clients { false }; -std::atomic_bool disk_read_activity { false }; -std::atomic_bool disk_write_activity { false }; +std::atomic_bool terminate { false }; + +std::atomic_bool running { false }; +std::atomic_bool on_wifi { false }; +std::atomic_bool disk_read_activity { false }; +std::atomic_bool disk_write_activity { false }; void setBootLoader(bus *const b) { cpu *const c = b->getCpu(); @@ -134,145 +137,9 @@ void panel(void *p) { } } -SemaphoreHandle_t terminal_mutex = xSemaphoreCreateMutex(); - -constexpr int terminal_columns = 80; -constexpr int terminal_rows = 25; -char terminal[terminal_columns * terminal_rows]; -uint8_t tx = 0, ty = terminal_rows - 1; -QueueHandle_t to_telnet_queue = xQueueCreate(10, sizeof(char)); - -void delete_first_line() { - memmove(&terminal[0], &terminal[terminal_columns], terminal_columns * (terminal_rows - 1)); - memset(&terminal[terminal_columns * (terminal_rows - 1)], ' ', terminal_columns); -} - -void telnet_terminal(void *p) { - bus *const b = reinterpret_cast(p); - tty *const tty_ = b->getTty(); - - Serial.println(F("telnet_terminal task started")); - - if (!tty_) - Serial.println(F(" *** NO TTY ***")); - - for(;;) { - char cc { 0 }; - - xQueueReceive(tty_->getTerminalQueue(), &cc, portMAX_DELAY); - - Serial.print(cc); - - // update terminal buffer - xSemaphoreTake(terminal_mutex, portMAX_DELAY); - - if (cc == 13) - tx = 0; - else if (cc == 10) - ty++; - else { - terminal[ty * terminal_columns + tx] = cc; - - tx++; - - if (tx == terminal_columns) - tx = 0, ty++; - } - - if (ty == terminal_rows) { - delete_first_line(); - ty--; - } - - xSemaphoreGive(terminal_mutex); - - // pass through to telnet clients - if (xQueueSend(to_telnet_queue, &cc, portMAX_DELAY) != pdTRUE) - Serial.println(F("queue TTY character failed")); - } -} - -void wifi(void *p) { - Serial.println(F("wifi task started")); - - int fd = socket(AF_INET, SOCK_STREAM, 0); - - struct sockaddr_in server { 0 }; - server.sin_family = AF_INET; - server.sin_addr.s_addr = INADDR_ANY; - server.sin_port = htons(23); - - if (bind(fd, (struct sockaddr *)&server, sizeof(server)) == -1) - Serial.println(F("bind failed")); - - if (listen(fd, 3) == -1) - Serial.println(F("listen failed")); - - struct pollfd fds[] = { { fd, POLLIN, 0 } }; - - std::vector clients; - - for(;;) { - on_wifi = WiFi.status() == WL_CONNECTED; - - int rc = poll(fds, 1, 10); - - if (rc == 1) { - int client = accept(fd, nullptr, nullptr); - if (client != -1) { - clients.push_back(client); - - constexpr const uint8_t dont_auth[] = { 0xff, 0xf4, 0x25, // don't auth - 0xff, 0xfb, 0x03, // suppress goahead - 0xff, 0xfe, 0x22, // don't line-mode - 0xff, 0xfe, 0x27, // don't new envt0 - 0xff, 0xfb, 0x01, // will echo - 0xff, 0xfe, 0x01, // don't echo - 0xff, 0xfd, 0x2d }; // no echo - - write(client, dont_auth, sizeof(dont_auth)); - - // send initial terminal stat - write(client, "\033[2J", 4); - - xSemaphoreTake(terminal_mutex, portMAX_DELAY); - - for(int y=0; ysetEmulateMFPT(true); + Serial.println(F("Init console")); + cnsl = new console_esp32(&terminate); + Serial.println(F("Init TTY")); - tty_ = new tty(poll_char, get_char, put_char); + tty_ = new tty(cnsl); Serial.println(F("Connect TTY to bus")); b->add_tty(tty_); @@ -356,12 +227,7 @@ void setup() { Serial.println(F(")")); xTaskCreatePinnedToCore(&panel, "panel", 2048, b, 1, nullptr, 0); - memset(terminal, ' ', sizeof(terminal)); - xTaskCreatePinnedToCore(&telnet_terminal, "telnet", 2048, b, 7, nullptr, 0); - - xTaskCreatePinnedToCore(&wifi, "wifi", 2048, b, 7, nullptr, 0); - - setup_wifi_stations(); + // setup_wifi_stations(); Serial.println(F("Load RK05")); b->add_rk05(new rk05("", b, &disk_read_activity, &disk_write_activity)); @@ -448,7 +314,7 @@ void loop() { c->step(); - if (event) { + if (event || terminate) { running = false; Serial.println(F("")); @@ -463,6 +329,9 @@ void loop() { start_ts = millis(); icount = 0; - running = true; + terminate = false; + event = 0; + + running = true; } } diff --git a/ESP32/platformio.ini b/ESP32/platformio.ini index fcc4e12..93ccaf2 100644 --- a/ESP32/platformio.ini +++ b/ESP32/platformio.ini @@ -16,5 +16,5 @@ monitor_speed = 115200 upload_speed = 1000000 lib_deps = greiman/SdFat@^2.1.2 adafruit/Adafruit NeoPixel@^1.10.4 -build_flags = -std=gnu++17 -Ofast -DESP32=1 +build_flags = -std=c++17 -Ofast -DESP32=1 build_unflags = -std=gnu++11 -Os diff --git a/console.cpp b/console.cpp new file mode 100644 index 0000000..6fc73a2 --- /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) { + int c = wait_for_char(500); + + if (c == -1) + continue; + + if (c == 3) + *terminate = true; + else + buffer.push_back(c); + } +} diff --git a/console.h b/console.h new file mode 100644 index 0000000..958462e --- /dev/null +++ b/console.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include + + +class console +{ +private: + std::atomic_bool *const terminate { nullptr }; + + std::thread *th { nullptr }; + + std::vector buffer; + +protected: + virtual int 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..bd3c0fd --- /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(); +} + +int 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 -1; +} + +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..a255bc5 --- /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: + int 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..581883b --- /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"); +} + +int 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 -1; +} + +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..7722576 --- /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: + int 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/cpu.cpp b/cpu.cpp index 4ef38d0..5f96640 100644 --- a/cpu.cpp +++ b/cpu.cpp @@ -878,7 +878,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) setPSW_z(v == 0); setPSW_v(false); - fprintf(stderr, "MTP%c: address %06o, value %06o\n", word_mode ? 'D' : 'I', a, v); + D(fprintf(stderr, "MTP%c: address %06o, value %06o\n", word_mode ? 'D' : 'I', a, v);) if (dst_mode == 0) putGAM(dst_mode, dst_reg, false, v, false); // ??? 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..57efe8a 100644 --- a/tty.cpp +++ b/tty.cpp @@ -1,11 +1,6 @@ // (C) 2018 by Folkert van Heusden // // Released under Apache License v2.0 #include -#if defined(ESP32) -#include -#else -#include -#endif #include #include @@ -14,10 +9,6 @@ #include "memory.h" #include "utils.h" -#if !defined(ESP32) -#include "terminal.h" -extern NEWWIN *w_main; -#endif const char * const regnames[] = { "reader status ", @@ -26,17 +17,8 @@ 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)); - - if (queue == nullptr) - Serial.println(F("Problem creating TTY queue")); -#endif } tty::~tty() @@ -63,7 +45,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 +53,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,16 +97,11 @@ 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) - Serial.println(F("queue TTY character failed")); -#else - put_char(c); -#endif + c->put_char(ch); } D(fprintf(stderr, "set register %o to %o\n", addr, v);) diff --git a/tty.h b/tty.h index 421a74f..20d3d6f 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,26 +21,16 @@ 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 }; bool withUI { false }; -#if defined(ESP32) - QueueHandle_t queue { nullptr }; -#endif - public: - tty(std::function poll_char, std::function get_char, std::function put_char); + tty(console *const c); virtual ~tty(); -#if defined(ESP32) - QueueHandle_t & getTerminalQueue() { return queue; } -#endif - uint8_t readByte(const uint16_t addr); uint16_t readWord(const uint16_t addr);