Merge branch 'master' into RP2040
This commit is contained in:
commit
e6b7b3dbab
23 changed files with 317 additions and 108 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "ESP32/SHAdisplay"]
|
||||
path = ESP32/SHAdisplay
|
||||
url = https://github.com/krzychb/esp-epaper-29-dke
|
|
@ -9,6 +9,8 @@ add_compile_options(-Wall -pedantic -Wextra)
|
|||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
if (NOT WIN32)
|
||||
|
||||
add_executable(
|
||||
kek
|
||||
bus.cpp
|
||||
|
@ -34,6 +36,10 @@ add_executable(
|
|||
utils.cpp
|
||||
)
|
||||
|
||||
endif (NOT WIN32)
|
||||
|
||||
if (WIN32)
|
||||
|
||||
add_executable(
|
||||
kek-win32
|
||||
bus.cpp
|
||||
|
@ -58,6 +64,8 @@ add_executable(
|
|||
win32.cpp
|
||||
)
|
||||
|
||||
endif (WIN32)
|
||||
|
||||
include(CheckIPOSupported)
|
||||
check_ipo_supported(RESULT supported)
|
||||
|
||||
|
@ -68,10 +76,13 @@ set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
|
|||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
find_package(Threads)
|
||||
if (NOT WIN32)
|
||||
target_link_libraries(kek Threads::Threads)
|
||||
else ()
|
||||
target_link_libraries(kek-win32 Threads::Threads)
|
||||
|
||||
target_link_libraries(kek-win32 ws2_32)
|
||||
endif ()
|
||||
|
||||
include(FindPkgConfig)
|
||||
|
||||
|
|
1
ESP32/SHAdisplay
Submodule
1
ESP32/SHAdisplay
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 18b42491ceecbfdb70e0dac69a379f5787a84a5d
|
|
@ -9,12 +9,13 @@
|
|||
#include "console_esp32.h"
|
||||
#include "cpu.h"
|
||||
#include "error.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
#define NEOPIXELS_PIN 25
|
||||
|
||||
console_esp32::console_esp32(std::atomic_uint32_t *const stop_event, bus *const b, std::vector<Stream *> & io_ports) :
|
||||
console(stop_event, b),
|
||||
console_esp32::console_esp32(std::atomic_uint32_t *const stop_event, bus *const b, std::vector<Stream *> & io_ports, const int t_width, const int t_height) :
|
||||
console(stop_event, b, t_width, t_height),
|
||||
io_ports(io_ports)
|
||||
{
|
||||
}
|
||||
|
@ -104,31 +105,39 @@ void console_esp32::panel_update_thread()
|
|||
for(;;) {
|
||||
vTaskDelay(20 / portTICK_RATE_MS);
|
||||
|
||||
// note that these are approximately as there's no mutex on the emulation
|
||||
uint16_t current_PSW = c->getPSW();
|
||||
int run_mode = current_PSW >> 14;
|
||||
try {
|
||||
// note that these are approximately as there's no mutex on the emulation
|
||||
uint16_t current_PSW = c->getPSW();
|
||||
int run_mode = current_PSW >> 14;
|
||||
|
||||
uint16_t current_PC = c->getPC();
|
||||
uint32_t full_addr = b->calculate_physical_address(run_mode, current_PC, false, false, true, i_space);
|
||||
uint16_t current_PC = c->getPC();
|
||||
uint32_t full_addr = b->calculate_physical_address(run_mode, current_PC, false, false, true, i_space);
|
||||
|
||||
uint16_t current_instr = b->readWord(current_PC);
|
||||
uint16_t current_instr = b->readWord(current_PC);
|
||||
|
||||
uint32_t led_color = run_mode_led_color[run_mode];
|
||||
uint32_t led_color = run_mode_led_color[run_mode];
|
||||
|
||||
for(uint8_t b=0; b<22; b++)
|
||||
pixels.setPixelColor(b, full_addr & (1 << b) ? led_color : 0);
|
||||
for(uint8_t b=0; b<22; b++)
|
||||
pixels.setPixelColor(b, full_addr & (1 << b) ? led_color : 0);
|
||||
|
||||
for(uint8_t b=0; b<16; b++)
|
||||
pixels.setPixelColor(b + 22, current_PSW & (1l << b) ? magenta : 0);
|
||||
for(uint8_t b=0; b<16; b++)
|
||||
pixels.setPixelColor(b + 22, current_PSW & (1l << b) ? magenta : 0);
|
||||
|
||||
for(uint8_t b=0; b<16; b++)
|
||||
pixels.setPixelColor(b + 38, current_instr & (1l << b) ? red : 0);
|
||||
for(uint8_t b=0; b<16; b++)
|
||||
pixels.setPixelColor(b + 38, current_instr & (1l << b) ? red : 0);
|
||||
|
||||
pixels.setPixelColor(54, running_flag ? white : 0);
|
||||
pixels.setPixelColor(54, running_flag ? white : 0);
|
||||
|
||||
pixels.setPixelColor(55, disk_read_activity_flag ? blue : 0);
|
||||
pixels.setPixelColor(56, disk_write_activity_flag ? blue : 0);
|
||||
pixels.setPixelColor(55, disk_read_activity_flag ? blue : 0);
|
||||
pixels.setPixelColor(56, disk_write_activity_flag ? blue : 0);
|
||||
|
||||
pixels.show();
|
||||
pixels.show();
|
||||
}
|
||||
catch(std::exception & e) {
|
||||
put_string_lf(format("Exception in panel thread: %s", e.what()));
|
||||
}
|
||||
catch(...) {
|
||||
put_string_lf("Unknown exception in panel thread");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ protected:
|
|||
void put_char_ll(const char c) override;
|
||||
|
||||
public:
|
||||
console_esp32(std::atomic_uint32_t *const stop_event, bus *const b, std::vector<Stream *> & io_ports);
|
||||
console_esp32(std::atomic_uint32_t *const stop_event, bus *const b, std::vector<Stream *> & io_ports, const int t_width, const int t_height);
|
||||
virtual ~console_esp32();
|
||||
|
||||
void put_string_lf(const std::string & what) override;
|
||||
|
|
77
ESP32/console_shabadge.cpp
Normal file
77
ESP32/console_shabadge.cpp
Normal file
|
@ -0,0 +1,77 @@
|
|||
// (C) 2023 by Folkert van Heusden
|
||||
// Released under MIT license
|
||||
|
||||
#include <SPI.h>
|
||||
#include <stdio.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "console_shabadge.h"
|
||||
#include "cpu.h"
|
||||
#include "error.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
#define COLORED 0
|
||||
#define UNCOLORED 1
|
||||
|
||||
console_shabadge::console_shabadge(std::atomic_uint32_t *const stop_event, bus *const b, std::vector<Stream *> & io_ports) :
|
||||
console_esp32(stop_event, b, io_ports, 296 / 8, 128 / 8)
|
||||
{
|
||||
if (epd.Init() != 0)
|
||||
Serial.println("Init of DEPG0290B01 failed");
|
||||
else {
|
||||
Serial.println("DEPG0290B01 initialized");
|
||||
|
||||
paint = new Paint(image, 0, 0);
|
||||
|
||||
paint->SetRotate(ROTATE_270);
|
||||
paint->SetWidth(128);
|
||||
paint->SetHeight(296);
|
||||
paint->Clear(UNCOLORED);
|
||||
|
||||
epd.ClearFrameMemory(UNCOLORED);
|
||||
}
|
||||
}
|
||||
|
||||
console_shabadge::~console_shabadge()
|
||||
{
|
||||
stop_thread();
|
||||
|
||||
delete paint;
|
||||
}
|
||||
|
||||
void console_shabadge::put_char_ll(const char c)
|
||||
{
|
||||
console_esp32::put_char_ll(c);
|
||||
|
||||
screen_updated_ts = millis();
|
||||
screen_updated = true;
|
||||
}
|
||||
|
||||
void console_shabadge::panel_update_thread()
|
||||
{
|
||||
for(;;) {
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
|
||||
if (screen_updated && millis() - screen_updated_ts >= 1000) {
|
||||
screen_updated = false;
|
||||
|
||||
paint->Clear(UNCOLORED);
|
||||
|
||||
for(int y=0; y<t_height; y++) {
|
||||
for(int x=0; x<t_width; x++) {
|
||||
char c = screen_buffer[y * t_width + x];
|
||||
|
||||
if (c <= 0)
|
||||
c = ' ';
|
||||
|
||||
paint->DrawCharAt(x * 8, y * 8, c, &Font8, COLORED);
|
||||
}
|
||||
}
|
||||
|
||||
epd.SetFrameMemory(paint->GetImage(), 0, 0, paint->GetWidth(), paint->GetHeight());
|
||||
epd.DisplayFrame();
|
||||
}
|
||||
}
|
||||
}
|
29
ESP32/console_shabadge.h
Normal file
29
ESP32/console_shabadge.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
// (C) 2023 by Folkert van Heusden
|
||||
// Released under MIT license
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <epd2in9-badge.h>
|
||||
#include <epdpaint.h>
|
||||
#include <vector>
|
||||
|
||||
#include "console_esp32.h"
|
||||
|
||||
|
||||
class console_shabadge : public console_esp32
|
||||
{
|
||||
private:
|
||||
unsigned char image[4736];
|
||||
Paint *paint { nullptr };
|
||||
Epd epd;
|
||||
|
||||
std::atomic_int screen_updated_ts { 0 };
|
||||
std::atomic_bool screen_updated { false };
|
||||
|
||||
void put_char_ll(const char c) override;
|
||||
|
||||
public:
|
||||
console_shabadge(std::atomic_uint32_t *const stop_event, bus *const b, std::vector<Stream *> & io_ports);
|
||||
virtual ~console_shabadge();
|
||||
|
||||
void panel_update_thread() override;
|
||||
};
|
|
@ -37,7 +37,7 @@ bool disk_backend_esp32::read(const off_t offset, const size_t n, uint8_t *const
|
|||
{
|
||||
DOLOG(debug, false, "disk_backend_esp32::read: read %zu bytes from offset %zu", n, offset);
|
||||
|
||||
#if defined(ESP32)
|
||||
#if defined(ESP32) && !defined(SHA2017)
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
#endif
|
||||
|
||||
|
@ -49,7 +49,7 @@ bool disk_backend_esp32::read(const off_t offset, const size_t n, uint8_t *const
|
|||
if (fh->read(target, n) != size_t(n)) {
|
||||
DOLOG(debug, true, "fread error: %s", strerror(errno));
|
||||
|
||||
#if defined(ESP32)
|
||||
#if defined(ESP32) && !defined(SHA2017)
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#endif
|
||||
return false;
|
||||
|
@ -57,7 +57,7 @@ bool disk_backend_esp32::read(const off_t offset, const size_t n, uint8_t *const
|
|||
|
||||
yield();
|
||||
|
||||
#if defined(ESP32)
|
||||
#if defined(ESP32) && !defined(SHA2017)
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#endif
|
||||
|
||||
|
@ -68,7 +68,7 @@ bool disk_backend_esp32::write(const off_t offset, const size_t n, const uint8_t
|
|||
{
|
||||
DOLOG(debug, false, "disk_backend_esp32::write: write %zu bytes to offset %zu", n, offset);
|
||||
|
||||
#if defined(ESP32)
|
||||
#if defined(ESP32) && !defined(SHA2017)
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
#endif
|
||||
|
||||
|
@ -80,7 +80,7 @@ bool disk_backend_esp32::write(const off_t offset, const size_t n, const uint8_t
|
|||
if (fh->write(from, n) != n) {
|
||||
DOLOG(ll_error, true, "RK05 fwrite error %s", strerror(errno));
|
||||
|
||||
#if defined(ESP32)
|
||||
#if defined(ESP32) && !defined(SHA2017)
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#endif
|
||||
return false;
|
||||
|
@ -88,8 +88,8 @@ bool disk_backend_esp32::write(const off_t offset, const size_t n, const uint8_t
|
|||
|
||||
yield();
|
||||
|
||||
#if defined(ESP32)
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#if defined(ESP32) && !defined(SHA2017)
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
|
|
|
@ -14,7 +14,11 @@
|
|||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined(SHA2017)
|
||||
#include "console_shabadge.h"
|
||||
#else
|
||||
#include "console_esp32.h"
|
||||
#endif
|
||||
#include "cpu.h"
|
||||
#include "debugger.h"
|
||||
#include "disk_backend.h"
|
||||
|
@ -188,8 +192,12 @@ std::optional<disk_backend_t> select_disk_backend(console *const c)
|
|||
c->put_string("1. network (NBD), 2. local SD card, 9. abort");
|
||||
|
||||
int ch = -1;
|
||||
while(ch == -1 && ch != '1' && ch != '2' && ch != '9')
|
||||
ch = c->wait_char(500);
|
||||
while(ch == -1 && ch != '1' && ch != '2' && ch != '9') {
|
||||
auto temp = c->wait_char(500);
|
||||
|
||||
if (temp.has_value())
|
||||
ch = temp.value();
|
||||
}
|
||||
|
||||
c->put_string_lf(format("%c", ch));
|
||||
|
||||
|
@ -208,8 +216,12 @@ std::optional<disk_type_t> select_disk_type(console *const c)
|
|||
c->put_string("1. RK05, 2. RL02, 9. abort");
|
||||
|
||||
int ch = -1;
|
||||
while(ch == -1 && ch != '1' && ch != '2' && ch != '9')
|
||||
ch = c->wait_char(500);
|
||||
while(ch == -1 && ch != '1' && ch != '2' && ch != '9') {
|
||||
auto temp = c->wait_char(500);
|
||||
|
||||
if (temp.has_value())
|
||||
ch = temp.value();
|
||||
}
|
||||
|
||||
c->put_string_lf(format("%c", ch));
|
||||
|
||||
|
@ -274,8 +286,13 @@ std::optional<std::pair<std::vector<disk_backend *>, std::vector<disk_backend *>
|
|||
|
||||
c->put_string_lf("Files on SD-card:");
|
||||
|
||||
#if defined(SHA2017)
|
||||
if (!sd.begin(21, SD_SCK_MHZ(10)))
|
||||
sd.initErrorHalt();
|
||||
#else
|
||||
if (!sd.begin(SS, SD_SCK_MHZ(15)))
|
||||
sd.initErrorHalt();
|
||||
#endif
|
||||
|
||||
for(;;) {
|
||||
sd.ls("/", LS_DATE | LS_SIZE | LS_R);
|
||||
|
@ -340,7 +357,7 @@ void set_disk_configuration(std::pair<std::vector<disk_backend *>, std::vector<d
|
|||
void configure_disk(console *const c)
|
||||
{
|
||||
for(;;) {
|
||||
Serial.println(F("Load disk"));
|
||||
c->put_string_lf("Load disk");
|
||||
|
||||
auto backend = select_disk_backend(cnsl);
|
||||
|
||||
|
@ -505,7 +522,11 @@ void setup()
|
|||
Serial_RS232.println(F("\014Console enabled on TTY"));
|
||||
|
||||
std::vector<Stream *> serial_ports { &Serial_RS232, &Serial };
|
||||
cnsl = new console_esp32(&stop_event, b, serial_ports);
|
||||
#if defined(SHA2017)
|
||||
cnsl = new console_shabadge(&stop_event, b, serial_ports);
|
||||
#else
|
||||
cnsl = new console_esp32(&stop_event, b, serial_ports, 80, 25);
|
||||
#endif
|
||||
|
||||
Serial.println(F("Start line-frequency interrupt"));
|
||||
kw11_l *lf = new kw11_l(b, cnsl);
|
||||
|
@ -525,11 +546,15 @@ void setup()
|
|||
Serial.print(F("Free RAM after init: "));
|
||||
Serial.println(ESP.getFreeHeap());
|
||||
|
||||
#if !defined(SHA2017)
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
#endif
|
||||
|
||||
Serial.flush();
|
||||
|
||||
cnsl->start_thread();
|
||||
|
||||
cnsl->put_string_lf("PDP-11/70 emulator, (C) Folkert van Heusden");
|
||||
}
|
||||
|
||||
void loop()
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
# Released under MIT license
|
||||
|
||||
[platformio]
|
||||
default_envs = ESP32
|
||||
default_envs = ESP32-wemos
|
||||
src_dir = .
|
||||
lib_ignore = SHAdisplay
|
||||
|
||||
[env:ESP32]
|
||||
lib_ldf_mode = deep+
|
||||
build_src_filter = +<*> -<.git/> -<.svn/> -<example/> -<examples/> -<test/> -<tests/> -<build> -<player.cpp>
|
||||
[env:ESP32-wemos]
|
||||
build_src_filter = +<*> -<.git/> -<.svn/> -<example/> -<examples/> -<test/> -<tests/> -<build> -<player.cpp> -<SHAdisplay/> -<console_shabadge.cpp>
|
||||
platform = espressif32
|
||||
board = wemos_d1_mini32
|
||||
framework = arduino
|
||||
|
@ -20,15 +20,17 @@ lib_deps = greiman/SdFat@^2.1.2
|
|||
build_flags = -std=gnu++17 -Ofast -DESP32=1 -ggdb3 -D_GLIBCXX_USE_C99
|
||||
build_unflags = -std=gnu++11 -Os
|
||||
|
||||
#[env:PICO]
|
||||
#lib_ldf_mode = deep+
|
||||
#src_filter = +<*> -<.git/> -<.svn/> -<example/> -<examples/> -<test/> -<tests/> -<build> -<player.cpp>
|
||||
#platform = raspberrypi
|
||||
#board = pico
|
||||
#framework = arduino
|
||||
#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 -ggdb3 -D_GLIBCXX_USE_C99
|
||||
#build_unflags = -std=gnu++11 -Os
|
||||
[env:SHA2017-badge]
|
||||
build_src_filter = +<*> -<.git/> -<.svn/> -<example/> -<examples/> -<test/> -<tests/> -<build> -<player.cpp> -<SHAdisplay/main/> -<SHAdisplay/components> -<SHAdisplay/Arduino/epd2in9-badge>
|
||||
platform = espressif32
|
||||
board = esp32doit-devkit-v1
|
||||
framework = arduino
|
||||
monitor_speed = 115200
|
||||
upload_speed = 460800
|
||||
board_build.filesystem = littlefs
|
||||
lib_deps = greiman/SdFat@^2.1.2
|
||||
adafruit/Adafruit NeoPixel
|
||||
bblanchon/ArduinoJson@^6.19.4
|
||||
build_flags = -std=gnu++17 -Ofast -DESP32=1 -DSHA2017 -ggdb3 -D_GLIBCXX_USE_C99 -ISHAdisplay/Arduino/libraries/epd2in9-badge -ISHAdisplay/Arduino/libraries/epdpaint -ISHAdisplay/components/epaper-29-dke
|
||||
build_unflags = -std=gnu++11 -Os
|
||||
upload_protocol = esptool
|
||||
|
|
17
README.md
17
README.md
|
@ -6,7 +6,7 @@ To build for e.g. linux:
|
|||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make kek
|
||||
make
|
||||
|
||||
Required:
|
||||
* libncursesw5-dev
|
||||
|
@ -16,7 +16,7 @@ To build for e.g. windows:
|
|||
mkdir build-win32
|
||||
cd build-win32
|
||||
cmake -DCMAKE_TOOLCHAIN_FILE=../mingw64.cmake ..
|
||||
make kek-win32
|
||||
make
|
||||
|
||||
|
||||
To run a disk image:
|
||||
|
@ -50,6 +50,19 @@ Wiring of the MAX232 connection:
|
|||
* RX : 16
|
||||
|
||||
|
||||
See SHA2017-badge.md if you want to flash your SHA20127 badge with this software.
|
||||
|
||||
|
||||
Some pictures:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Click on the following picture to see it running (opens a youtube link):
|
||||
|
||||
[](https://youtu.be/MPaGmVli8NA)
|
||||
|
||||
Released under MIT license.
|
||||
|
||||
Folkert van Heusden
|
||||
|
|
12
SHA2017-badge.md
Normal file
12
SHA2017-badge.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
This procedure will remove the default micropython environment.
|
||||
Maybe you can undo that, but I have not tried that.
|
||||
|
||||
* esptool.py erase\_flash
|
||||
|
||||
* pio run -e SHA2017-badge
|
||||
|
||||
* esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default\_reset --after hard\_reset write\_flash -z --flash\_mode dio --flash\_freq 80m --flash\_size detect 0x1000 ./.pio/build/ESP32-wemos/bootloader.bin
|
||||
|
||||
* pio run -e SHA2017-badge -t upload
|
||||
|
||||
After this, you can connect a serial terminal to /dev/ttyUSB0 at 115k2 bps.
|
14
bus.cpp
14
bus.cpp
|
@ -14,6 +14,8 @@
|
|||
#include "tty.h"
|
||||
|
||||
#if defined(ESP32)
|
||||
#include <esp_debug_helpers.h>
|
||||
|
||||
// ESP32 goes in a crash-loop when allocating 128kB
|
||||
// see also https://github.com/espressif/esp-idf/issues/1934
|
||||
constexpr int n_pages = 12;
|
||||
|
@ -641,7 +643,19 @@ void bus::addToMMR1(const int8_t delta, const uint8_t reg)
|
|||
assert(reg >= 0 && reg <= 7);
|
||||
assert(delta >= -2 && delta <= 2);
|
||||
|
||||
if (getMMR0() & 0160000) // MMR1 etc are locked
|
||||
return;
|
||||
|
||||
#if defined(ESP32)
|
||||
if (MMR1 > 255)
|
||||
esp_backtrace_print(32);
|
||||
#else
|
||||
if (MMR1 > 255) {
|
||||
extern FILE *lfh;
|
||||
fflush(lfh);
|
||||
}
|
||||
assert(MMR1 < 256);
|
||||
#endif
|
||||
|
||||
MMR1 <<= 8;
|
||||
|
||||
|
|
2
config.h
2
config.h
|
@ -1,4 +1,4 @@
|
|||
// (C) 2018-2023 by Folkert van Heusden
|
||||
// Released under MIT license
|
||||
|
||||
#define TURBO
|
||||
// #define TURBO
|
||||
|
|
38
console.cpp
38
console.cpp
|
@ -2,6 +2,7 @@
|
|||
// Released under MIT license
|
||||
|
||||
#include <chrono>
|
||||
#include <optional>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -14,11 +15,14 @@
|
|||
#include "utils.h"
|
||||
|
||||
|
||||
console::console(std::atomic_uint32_t *const stop_event, bus *const b) :
|
||||
console::console(std::atomic_uint32_t *const stop_event, bus *const b, const int t_width, const int t_height) :
|
||||
stop_event(stop_event),
|
||||
b(b)
|
||||
b(b),
|
||||
t_width(t_width),
|
||||
t_height(t_height)
|
||||
{
|
||||
memset(screen_buffer, ' ', sizeof screen_buffer);
|
||||
|
||||
screen_buffer = new char[t_width * t_height]();
|
||||
}
|
||||
|
||||
console::~console()
|
||||
|
@ -26,6 +30,8 @@ console::~console()
|
|||
// done as well in subclasses but also here to
|
||||
// stop lgtm.com complaining about it
|
||||
stop_thread();
|
||||
|
||||
delete [] screen_buffer;
|
||||
}
|
||||
|
||||
void console::start_thread()
|
||||
|
@ -70,7 +76,7 @@ int console::get_char()
|
|||
return c;
|
||||
}
|
||||
|
||||
int console::wait_char(const int timeout_ms)
|
||||
std::optional<char> console::wait_char(const int timeout_ms)
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(input_lock);
|
||||
|
||||
|
@ -86,7 +92,7 @@ int console::wait_char(const int timeout_ms)
|
|||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
return { };
|
||||
}
|
||||
|
||||
void console::flush_input()
|
||||
|
@ -111,34 +117,34 @@ std::string console::read_line(const std::string & prompt)
|
|||
std::string str;
|
||||
|
||||
for(;;) {
|
||||
char c = wait_char(500);
|
||||
auto c = wait_char(250);
|
||||
|
||||
if (*stop_event == EVENT_TERMINATE)
|
||||
return "";
|
||||
|
||||
if (c == -1 || c == 255 /* ESP32 has unsigned char? */)
|
||||
if (c.has_value() == false)
|
||||
continue;
|
||||
|
||||
if (c == 13 || c == 10)
|
||||
if (c.value() == 13 || c.value() == 10)
|
||||
break;
|
||||
|
||||
if (c == 8 || c == 127) { // backspace
|
||||
if (c.value() == 8 || c.value() == 127) { // backspace
|
||||
if (!str.empty()) {
|
||||
str = str.substr(0, str.size() - 1);
|
||||
|
||||
emit_backspace();
|
||||
}
|
||||
}
|
||||
else if (c == 21) { // ^u
|
||||
else if (c.value() == 21) { // ^u
|
||||
for(size_t i=0; i<str.size(); i++)
|
||||
emit_backspace();
|
||||
|
||||
str.clear();
|
||||
}
|
||||
else if (c >= 32) {
|
||||
str += c;
|
||||
else if (c.value() >= 32) {
|
||||
str += c.value();
|
||||
|
||||
put_char(c);
|
||||
put_char(c.value());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,7 +192,7 @@ void console::put_char(const char c)
|
|||
tx--;
|
||||
}
|
||||
else {
|
||||
screen_buffer[ty][tx++] = c;
|
||||
screen_buffer[ty * t_width + tx++] = c;
|
||||
|
||||
if (tx == t_width) {
|
||||
tx = 0;
|
||||
|
@ -199,11 +205,11 @@ void console::put_char(const char c)
|
|||
}
|
||||
|
||||
if (ty == t_height) {
|
||||
memmove(&screen_buffer[0], &screen_buffer[1], sizeof(char) * t_width * (t_height - 1));
|
||||
memmove(&screen_buffer[0 * t_width], &screen_buffer[1 * t_width], sizeof(char) * t_width * (t_height - 1));
|
||||
|
||||
ty--;
|
||||
|
||||
memset(screen_buffer[t_height - 1], ' ', t_width);
|
||||
memset(&screen_buffer[(t_height - 1) * t_width], ' ', t_width);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
12
console.h
12
console.h
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <optional>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
|
@ -15,9 +16,6 @@
|
|||
#endif
|
||||
|
||||
|
||||
constexpr const int t_width { 80 };
|
||||
constexpr const int t_height { 25 };
|
||||
|
||||
class console
|
||||
{
|
||||
private:
|
||||
|
@ -36,7 +34,9 @@ protected:
|
|||
|
||||
bool stop_thread_flag { false };
|
||||
|
||||
char screen_buffer[t_height][t_width];
|
||||
const int t_width { 0 };
|
||||
const int t_height { 0 };
|
||||
char *screen_buffer { nullptr };
|
||||
uint8_t tx { 0 };
|
||||
uint8_t ty { 0 };
|
||||
|
||||
|
@ -47,7 +47,7 @@ protected:
|
|||
virtual void put_char_ll(const char c) = 0;
|
||||
|
||||
public:
|
||||
console(std::atomic_uint32_t *const stop_event, bus *const b);
|
||||
console(std::atomic_uint32_t *const stop_event, bus *const b, const int t_width = 80, const int t_height = 25);
|
||||
virtual ~console();
|
||||
|
||||
void start_thread();
|
||||
|
@ -55,7 +55,7 @@ public:
|
|||
|
||||
bool poll_char();
|
||||
int get_char();
|
||||
int wait_char(const int timeout_ms);
|
||||
std::optional<char> wait_char(const int timeout_ms);
|
||||
std::string read_line(const std::string & prompt);
|
||||
void flush_input();
|
||||
|
||||
|
|
52
cpu.cpp
52
cpu.cpp
|
@ -71,7 +71,7 @@ std::tuple<double, double, uint64_t> cpu::get_mips_rel_speed()
|
|||
{
|
||||
uint64_t instr_count = get_instructions_executed_count();
|
||||
|
||||
uint32_t t_diff = get_ms() - running_since;
|
||||
uint32_t t_diff = get_ms() - running_since; // TODO fix this because we now implement WAIT where it sits idle
|
||||
|
||||
double mips = instr_count / (1000.0 * t_diff);
|
||||
|
||||
|
@ -259,7 +259,7 @@ bool cpu::check_queued_interrupts()
|
|||
uint8_t current_level = getPSW_spl();
|
||||
|
||||
// uint8_t start_level = current_level <= 3 ? 0 : current_level + 1;
|
||||
uint8_t start_level = current_level + 1;
|
||||
uint8_t start_level = current_level + 1;
|
||||
|
||||
for(uint8_t i=start_level; i < 8; i++) {
|
||||
auto interrupts = queued_interrupts.find(i);
|
||||
|
@ -301,9 +301,6 @@ void cpu::queue_interrupt(const uint8_t level, const uint8_t vector)
|
|||
|
||||
void cpu::addToMMR1(const uint8_t mode, const uint8_t reg, const word_mode_t word_mode)
|
||||
{
|
||||
if (b->getMMR0() & 0160000 /* bits frozen? */)
|
||||
return;
|
||||
|
||||
bool neg = mode == 4 || mode == 5;
|
||||
|
||||
if (word_mode == wm_word || reg >= 6 || mode == 6 || mode == 7)
|
||||
|
@ -406,13 +403,13 @@ gam_rc_t cpu::getGAMAddress(const uint8_t mode, const int reg, const word_mode_t
|
|||
|
||||
bool cpu::double_operand_instructions(const uint16_t instr)
|
||||
{
|
||||
const word_mode_t word_mode = instr & 0x8000 ? wm_byte : wm_word;
|
||||
|
||||
const uint8_t operation = (instr >> 12) & 7;
|
||||
|
||||
if (operation == 0b000)
|
||||
return single_operand_instructions(instr);
|
||||
|
||||
const word_mode_t word_mode = instr & 0x8000 ? wm_byte : wm_word;
|
||||
|
||||
if (operation == 0b111) {
|
||||
if (word_mode == wm_byte)
|
||||
return false;
|
||||
|
@ -424,11 +421,6 @@ bool cpu::double_operand_instructions(const uint16_t instr)
|
|||
const uint8_t src_mode = (src >> 3) & 7;
|
||||
const uint8_t src_reg = src & 7;
|
||||
|
||||
gam_rc_t g_src { wm_word, rm_cur, i_space, { }, { }, { } };
|
||||
|
||||
if (operation != 0b110)
|
||||
g_src = getGAM(src_mode, src_reg, word_mode, rm_cur);
|
||||
|
||||
const uint8_t dst = instr & 63;
|
||||
const uint8_t dst_mode = (dst >> 3) & 7;
|
||||
const uint8_t dst_reg = dst & 7;
|
||||
|
@ -437,6 +429,8 @@ bool cpu::double_operand_instructions(const uint16_t instr)
|
|||
|
||||
switch(operation) {
|
||||
case 0b001: { // MOV/MOVB Move Word/Byte
|
||||
gam_rc_t g_src = getGAM(src_mode, src_reg, word_mode, rm_cur);
|
||||
|
||||
if (word_mode == wm_byte && dst_mode == 0)
|
||||
setRegister(dst_reg, int8_t(g_src.value.value())); // int8_t: sign extension
|
||||
else {
|
||||
|
@ -452,6 +446,8 @@ bool cpu::double_operand_instructions(const uint16_t instr)
|
|||
}
|
||||
|
||||
case 0b010: { // CMP/CMPB Compare Word/Byte
|
||||
gam_rc_t g_src = getGAM(src_mode, src_reg, word_mode, rm_cur);
|
||||
|
||||
auto g_dst = getGAM(dst_mode, dst_reg, word_mode, rm_cur);
|
||||
|
||||
uint16_t temp = (g_src.value.value() - g_dst.value.value()) & (word_mode == wm_byte ? 0xff : 0xffff);
|
||||
|
@ -465,7 +461,10 @@ bool cpu::double_operand_instructions(const uint16_t instr)
|
|||
}
|
||||
|
||||
case 0b011: { // BIT/BITB Bit Test Word/Byte
|
||||
gam_rc_t g_src = getGAM(src_mode, src_reg, word_mode, rm_cur);
|
||||
|
||||
auto g_dst = getGAM(dst_mode, dst_reg, word_mode, rm_cur);
|
||||
|
||||
uint16_t result = (g_dst.value.value() & g_src.value.value()) & (word_mode == wm_byte ? 0xff : 0xffff);
|
||||
|
||||
setPSW_flags_nzv(result, word_mode);
|
||||
|
@ -474,6 +473,8 @@ bool cpu::double_operand_instructions(const uint16_t instr)
|
|||
}
|
||||
|
||||
case 0b100: { // BIC/BICB Bit Clear Word/Byte
|
||||
gam_rc_t g_src = getGAM(src_mode, src_reg, word_mode, rm_cur);
|
||||
|
||||
auto g_dst = getGAM(dst_mode, dst_reg, word_mode, rm_cur);
|
||||
|
||||
uint16_t result = g_dst.value.value() & ~g_src.value.value();
|
||||
|
@ -485,6 +486,8 @@ bool cpu::double_operand_instructions(const uint16_t instr)
|
|||
}
|
||||
|
||||
case 0b101: { // BIS/BISB Bit Set Word/Byte
|
||||
gam_rc_t g_src = getGAM(src_mode, src_reg, word_mode, rm_cur);
|
||||
|
||||
auto g_dst = getGAM(dst_mode, dst_reg, word_mode, rm_cur);
|
||||
|
||||
uint16_t result = g_dst.value.value() | g_src.value.value();
|
||||
|
@ -1549,8 +1552,7 @@ bool cpu::misc_operations(const uint16_t instr)
|
|||
|
||||
int dst_reg = instr & 7;
|
||||
|
||||
word_mode_t word_mode = wm_word;
|
||||
setPC(getGAMAddress(dst_mode, dst_reg, word_mode).addr.value());
|
||||
setPC(getGAMAddress(dst_mode, dst_reg, wm_word).addr.value());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1569,14 +1571,14 @@ bool cpu::misc_operations(const uint16_t instr)
|
|||
// PUSH link
|
||||
pushStack(getRegister(link_reg));
|
||||
|
||||
b->addToMMR1(-2, 6);
|
||||
|
||||
// MOVE PC,link
|
||||
setRegister(link_reg, getPC());
|
||||
|
||||
// JMP dst
|
||||
setPC(dst_value);
|
||||
|
||||
b->addToMMR1(-2, 6);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1625,15 +1627,15 @@ void cpu::trap(uint16_t vector, const int new_ipl, const bool is_interrupt)
|
|||
}
|
||||
}
|
||||
else {
|
||||
bool mmr1_locked = b->getMMR0() & 0160000;
|
||||
|
||||
before_psw = getPSW();
|
||||
if (!mmr1_locked)
|
||||
b->addToMMR1(-2, 6);
|
||||
|
||||
b->addToMMR1(-2, 6);
|
||||
|
||||
before_pc = getPC();
|
||||
if (!mmr1_locked)
|
||||
b->addToMMR1(-2, 6);
|
||||
|
||||
b->addToMMR1(-2, 6);
|
||||
|
||||
// TODO set MMR2?
|
||||
}
|
||||
|
||||
// make sure the trap vector is retrieved from kernel space
|
||||
|
@ -2163,8 +2165,10 @@ void cpu::step_a()
|
|||
if ((b->getMMR0() & 0160000) == 0)
|
||||
b->clearMMR1();
|
||||
|
||||
if (any_queued_interrupts && check_queued_interrupts())
|
||||
return; // documentation
|
||||
if (any_queued_interrupts && check_queued_interrupts()) {
|
||||
if ((b->getMMR0() & 0160000) == 0)
|
||||
b->clearMMR1();
|
||||
}
|
||||
}
|
||||
|
||||
void cpu::step_b()
|
||||
|
|
BIN
images/KEK-ESP32-VT510.jpg
Normal file
BIN
images/KEK-ESP32-VT510.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 150 KiB |
BIN
images/KEK-linux-frame.jpg
Normal file
BIN
images/KEK-linux-frame.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
BIN
images/KEK-linux.mp4
Normal file
BIN
images/KEK-linux.mp4
Normal file
Binary file not shown.
BIN
images/KEK-sha2017badge.jpg
Normal file
BIN
images/KEK-sha2017badge.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 88 KiB |
21
tty.cpp
21
tty.cpp
|
@ -45,6 +45,14 @@ uint8_t tty::readByte(const uint16_t addr)
|
|||
return v;
|
||||
}
|
||||
|
||||
void tty::notify_rx()
|
||||
{
|
||||
registers[(PDP11TTY_TKS - PDP11TTY_BASE) / 2] |= 128;
|
||||
|
||||
if (registers[(PDP11TTY_TKS - PDP11TTY_BASE) / 2] & 64)
|
||||
b->getCpu()->queue_interrupt(4, 060);
|
||||
}
|
||||
|
||||
uint16_t tty::readWord(const uint16_t addr)
|
||||
{
|
||||
const int reg = (addr - PDP11TTY_BASE) / 2;
|
||||
|
@ -69,12 +77,8 @@ uint16_t tty::readWord(const uint16_t addr)
|
|||
|
||||
vtemp = ch | (parity(ch) << 7);
|
||||
|
||||
if (chars.empty() == false) {
|
||||
registers[(PDP11TTY_TKS - PDP11TTY_BASE) / 2] |= 128;
|
||||
|
||||
if (registers[(PDP11TTY_TKS - PDP11TTY_BASE) / 2] & 64)
|
||||
b->getCpu()->queue_interrupt(4, 060);
|
||||
}
|
||||
if (chars.empty() == false)
|
||||
notify_rx();
|
||||
}
|
||||
}
|
||||
else if (addr == PDP11TTY_TPS) {
|
||||
|
@ -96,10 +100,7 @@ void tty::operator()()
|
|||
|
||||
chars.push_back(c->get_char());
|
||||
|
||||
registers[(PDP11TTY_TKS - PDP11TTY_BASE) / 2] |= 128;
|
||||
|
||||
if (registers[(PDP11TTY_TKS - PDP11TTY_BASE) / 2] & 64)
|
||||
b->getCpu()->queue_interrupt(4, 060);
|
||||
notify_rx();
|
||||
}
|
||||
else {
|
||||
myusleep(100000);
|
||||
|
|
2
tty.h
2
tty.h
|
@ -35,6 +35,8 @@ private:
|
|||
std::thread *th { nullptr };
|
||||
std::atomic_bool stop_flag { false };
|
||||
|
||||
void notify_rx();
|
||||
|
||||
public:
|
||||
tty(console *const c, bus *const b);
|
||||
virtual ~tty();
|
||||
|
|
Loading…
Add table
Reference in a new issue