abstracted text-output into console-classes

This commit is contained in:
folkert van heusden 2022-03-22 11:07:20 +01:00
parent 643075aa86
commit 7649ab6b29
10 changed files with 276 additions and 119 deletions

View file

@ -8,6 +8,9 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
add_executable( add_executable(
kek kek
bus.cpp bus.cpp
console.cpp
console_ncurses.cpp
console_posix.cpp
cpu.cpp cpu.cpp
error.cpp error.cpp
main.cpp main.cpp

47
console.cpp Normal file
View file

@ -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());
}
}

34
console.h Normal file
View file

@ -0,0 +1,34 @@
#pragma once
#include <atomic>
#include <optional>
#include <thread>
#include <vector>
class console
{
private:
std::atomic_bool *const terminate { nullptr };
std::thread *th { nullptr };
std::vector<char> buffer;
protected:
virtual std::optional<char> 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()();
};

69
console_ncurses.cpp Normal file
View file

@ -0,0 +1,69 @@
#include <poll.h>
#include <stdio.h>
#include <ncurses.h>
#include <unistd.h>
#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<char> 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();
}

23
console_ncurses.h Normal file
View file

@ -0,0 +1,23 @@
#include <ncurses.h>
#include "console.h"
#include "terminal.h"
class console_ncurses : public console
{
private:
NEWWIN *w_main_b { nullptr };
NEWWIN *w_main { nullptr };
protected:
std::optional<char> 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;
};

47
console_posix.cpp Normal file
View file

@ -0,0 +1,47 @@
#include <poll.h>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#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<char> 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()
{
}

21
console_posix.h Normal file
View file

@ -0,0 +1,21 @@
#include <termios.h>
#include "console.h"
class console_posix : public console
{
private:
struct termios org_tty_opts { 0 };
protected:
std::optional<char> 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;
};

117
main.cpp
View file

@ -1,14 +1,14 @@
// (C) 2018-2022 by Folkert van Heusden // (C) 2018-2022 by Folkert van Heusden
// Released under Apache License v2.0 // Released under Apache License v2.0
#include <atomic> #include <atomic>
#include <poll.h>
#include <signal.h> #include <signal.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <termios.h>
#include <unistd.h> #include <unistd.h>
#include "memory.h" #include "memory.h"
#include "console_ncurses.h"
#include "console_posix.h"
#include "cpu.h" #include "cpu.h"
#include "tty.h" #include "tty.h"
#include "utils.h" #include "utils.h"
@ -16,20 +16,11 @@
#include "terminal.h" #include "terminal.h"
#include "error.h" #include "error.h"
struct termios org_tty_opts { 0 };
bool withUI { false }; bool withUI { false };
uint32_t event { 0 }; uint32_t event { 0 };
std::atomic_bool terminate { false }; 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) void loadbin(bus *const b, uint16_t base, const char *const file)
{ {
FILE *fh = fopen(file, "rb"); FILE *fh = fopen(file, "rb");
@ -133,30 +124,6 @@ uint16_t loadTape(bus *const b, const char *const file)
return start; 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; volatile bool sw = false;
void sw_handler(int s) 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() void help()
{ {
printf("-h this help\n"); printf("-h this help\n");
@ -286,12 +212,14 @@ int main(int argc, char *argv[])
} }
} }
tty *tty_ = nullptr; console *cnsl = nullptr;
if (withUI) if (withUI)
tty_ = new tty(poll_char, get_char_ui, put_char_ui); cnsl = new console_ncurses(&terminate);
else else
tty_ = new tty(poll_char, get_char, put_char); cnsl = new console_posix(&terminate);
tty *tty_ = new tty(cnsl);
b->add_tty(tty_); b->add_tty(tty_);
@ -306,26 +234,12 @@ int main(int argc, char *argv[])
sa.sa_flags = SA_RESTART; sa.sa_flags = SA_RESTART;
if (withUI) { if (withUI) {
init_ncurses(true);
sigaction(SIGWINCH, &sa, nullptr); sigaction(SIGWINCH, &sa, nullptr);
resize_terminal();
} }
sigaction(SIGTERM , &sa, nullptr); sigaction(SIGTERM, &sa, nullptr);
sigaction(SIGINT , &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 } };
uint32_t icount = 0; uint32_t icount = 0;
uint64_t total_icount = 0; uint64_t total_icount = 0;
uint32_t refresh_interval = 262144; uint32_t refresh_interval = 262144;
@ -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); fprintf(stderr, "instructions_executed: %u, took_ms: %lu, new refresh_interval: %u\n", icount, took_ms, refresh_interval);
if (withUI) { // if (withUI) {
mvwprintw(w_main_b -> win, 0, 24, "%.1f/s ", icount * 1000.0 / took_ms); // 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()); // mvwprintw(w_main_b -> win, 0, 42, "%06o", b->get_switch_register());
mydoupdate(); // mydoupdate();
} // }
if (terminate) if (terminate)
event = 1; event = 1;
@ -390,8 +304,9 @@ int main(int argc, char *argv[])
} }
} }
if (withUI) terminate = true;
endwin();
delete cnsl;
fprintf(stderr, "Instructions per second: %.3f\n\n", icount * 1000.0 / (get_ms() - start)); fprintf(stderr, "Instructions per second: %.3f\n\n", icount * 1000.0 / (get_ms() - start));

20
tty.cpp
View file

@ -19,6 +19,7 @@
extern NEWWIN *w_main; extern NEWWIN *w_main;
#endif #endif
const char * const regnames[] = { const char * const regnames[] = {
"reader status ", "reader status ",
"reader buffer ", "reader buffer ",
@ -26,10 +27,7 @@ const char * const regnames[] = {
"puncher buffer" "puncher buffer"
}; };
tty::tty(std::function<bool()> poll_char, std::function<uint8_t()> get_char, std::function<void(char c)> put_char) : tty::tty(console *const c) : c(c)
poll_char(poll_char),
get_char(get_char),
put_char(put_char)
{ {
#if defined(ESP32) #if defined(ESP32)
queue = xQueueCreate(10, sizeof(char)); queue = xQueueCreate(10, sizeof(char));
@ -63,7 +61,7 @@ uint16_t tty::readWord(const uint16_t addr)
have_char_2 = true; have_char_2 = true;
} }
else if (have_char_2 == false) { else if (have_char_2 == false) {
have_char_1 = poll_char(); have_char_1 = c->poll_char();
} }
if (addr == PDP11TTY_TKS) { if (addr == PDP11TTY_TKS) {
@ -71,9 +69,9 @@ uint16_t tty::readWord(const uint16_t addr)
} }
else if (addr == PDP11TTY_TKB) { else if (addr == PDP11TTY_TKB) {
if (have_char_2) { 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; 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);) D(fprintf(stderr, "PDP11TTY write %o (%s): %o\n", addr, regnames[reg], v);)
if (addr == PDP11TTY_TPB) { 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 defined(ESP32)
if (xQueueSend(queue, &c, portMAX_DELAY) != pdTRUE) if (xQueueSend(queue, &ch, portMAX_DELAY) != pdTRUE)
Serial.println(F("queue TTY character failed")); Serial.println(F("queue TTY character failed"));
#else #else
put_char(c); c->put_char(ch);
#endif #endif
} }

10
tty.h
View file

@ -2,11 +2,13 @@
// Released under Apache License v2.0 // Released under Apache License v2.0
#pragma once #pragma once
#include <functional>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string> #include <string>
#include "console.h"
#define PDP11TTY_TKS 0177560 // reader status #define PDP11TTY_TKS 0177560 // reader status
#define PDP11TTY_TKB 0177562 // reader buffer #define PDP11TTY_TKB 0177562 // reader buffer
#define PDP11TTY_TPS 0177564 // puncher status #define PDP11TTY_TPS 0177564 // puncher status
@ -19,9 +21,7 @@ class memory;
class tty class tty
{ {
private: private:
std::function<bool()> poll_char; console *const c { nullptr };
std::function<uint8_t()> get_char;
std::function<void(char c)> put_char;
bool have_char_1 { false }; // RCVR BUSY bit high (11) bool have_char_1 { false }; // RCVR BUSY bit high (11)
bool have_char_2 { false }; // RCVR DONE bit high (7) bool have_char_2 { false }; // RCVR DONE bit high (7)
uint16_t registers[4] { 0 }; uint16_t registers[4] { 0 };
@ -32,7 +32,7 @@ private:
#endif #endif
public: public:
tty(std::function<bool()> poll_char, std::function<uint8_t()> get_char, std::function<void(char c)> put_char); tty(console *const c);
virtual ~tty(); virtual ~tty();
#if defined(ESP32) #if defined(ESP32)