Merge branch 'master' into RP2040

This commit is contained in:
folkert van heusden 2023-04-07 20:51:19 +02:00
commit e6b7b3dbab
Signed by untrusted user who does not match committer: folkert
GPG key ID: 6B6455EDFEED3BD1
23 changed files with 317 additions and 108 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "ESP32/SHAdisplay"]
path = ESP32/SHAdisplay
url = https://github.com/krzychb/esp-epaper-29-dke

View file

@ -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

@ -0,0 +1 @@
Subproject commit 18b42491ceecbfdb70e0dac69a379f5787a84a5d

View file

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

View file

@ -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;

View 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
View 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;
};

View file

@ -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;

View file

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

View file

@ -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

View file

@ -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:
![(running on a regular ESP32 connected to a VT510 terminal)](images/KEK-ESP32-VT510.jpg)
![(running on a SHA2017-badge)](images/KEK-sha2017badge.jpg)
Click on the following picture to see it running (opens a youtube link):
[![running on a Linux laptop](images/KEK-linux-frame.jpg)](https://youtu.be/MPaGmVli8NA)
Released under MIT license.
Folkert van Heusden

12
SHA2017-badge.md Normal file
View 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
View file

@ -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;

View file

@ -1,4 +1,4 @@
// (C) 2018-2023 by Folkert van Heusden
// Released under MIT license
#define TURBO
// #define TURBO

View file

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

View file

@ -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
View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

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

Binary file not shown.

BIN
images/KEK-sha2017badge.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

21
tty.cpp
View file

@ -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
View file

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