From f70649af7c2e0c8b599d736c6f776cd4aa2130ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Wed, 13 Jul 2022 00:21:54 +0200 Subject: [PATCH 1/5] Properly enable OpenAL by default --- .github/workflows/cmake.yml | 6 +++--- CMakeLists.txt | 8 ++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 112a54283..c6ac100f7 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -76,7 +76,7 @@ jobs: ${{ matrix.environment.prefix }}-zlib ${{ matrix.environment.prefix }}-libpng ${{ matrix.environment.prefix }}-libvncserver - ${{ matrix.environment.prefix }}-rtmidi + ${{ matrix.environment.prefix }}-openal - uses: actions/checkout@v2 - name: Configure CMake run: >- @@ -230,7 +230,7 @@ jobs: librtmidi-dev qtbase5-dev qttools5-dev - libfaudio-dev + libopenal-dev - name: Configure CMake run: >- cmake -G Ninja -S . -B build --preset ${{ matrix.build.preset }} @@ -271,7 +271,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install dependencies - run: brew install freetype sdl2 libpng rtmidi qt@5 faudio ninja + run: brew install freetype sdl2 libpng rtmidi qt@5 openal-soft ninja - name: Configure CMake run: >- PATH=/usr/local/opt/qt@5/bin:$PATH diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b393f41a..b78e4efe4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,12 +18,8 @@ cmake_minimum_required(VERSION 3.16) cmake_policy(SET CMP0091 NEW) cmake_policy(SET CMP0079 NEW) -# if(HAIKU) - # set(OPENAL ON) - # set(RTMIDI OFF) -# endif() -set(OPENAL ON) if(HAIKU) + set(OPENAL ON) set(RTMIDI OFF) endif() @@ -131,7 +127,7 @@ set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON) # ------ ----------- ---- option(RELEASE "Release build" OFF) option(DYNAREC "Dynamic recompiler" ON) -option(OPENAL "OpenAL" OFF) +option(OPENAL "OpenAL" ON) option(RTMIDI "RtMidi" ON) option(FLUIDSYNTH "FluidSynth" ON) option(MUNT "MUNT" ON) From 24ee676b1397dad534f37c891c65d6e64a77a9d1 Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Wed, 13 Jul 2022 01:04:01 +0200 Subject: [PATCH 2/5] qt: switch to polling for status bar updating --- src/86box.c | 3 + src/CMakeLists.txt | 2 +- src/include/86box/machine_status.h | 32 ++++++ src/include/86box/plat.h | 2 + src/include/86box/ui.h | 4 +- src/machine_status.c | 52 ++++++++++ src/qt/qt_machinestatus.cpp | 159 ++++++++++++++--------------- src/qt/qt_machinestatus.hpp | 4 +- src/qt/qt_mainwindow.cpp | 2 - src/qt/qt_progsettings.cpp | 2 - src/qt/qt_ui.cpp | 79 +++++++++++++- 11 files changed, 242 insertions(+), 99 deletions(-) create mode 100644 src/include/86box/machine_status.h create mode 100644 src/machine_status.c diff --git a/src/86box.c b/src/86box.c index 24f74b04a..449588c5d 100644 --- a/src/86box.c +++ b/src/86box.c @@ -96,6 +96,7 @@ #include <86box/thread.h> #include <86box/version.h> #include <86box/gdbstub.h> +#include <86box/machine_status.h> // Disable c99-designator to avoid the warnings about int ng #ifdef __clang__ @@ -891,6 +892,8 @@ pc_init_modules(void) video_reset_close(); + machine_status_init(); + return(1); } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 36df54404..d1da45172 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,7 +17,7 @@ add_executable(86Box 86box.c config.c log.c random.c timer.c io.c acpi.c apm.c dma.c ddma.c discord.c nmi.c pic.c pit.c port_6x.c port_92.c ppi.c pci.c - mca.c usb.c fifo8.c device.c nvr.c nvr_at.c nvr_ps2.c) + mca.c usb.c fifo8.c device.c nvr.c nvr_at.c nvr_ps2.c machine_status.c) if(CMAKE_SYSTEM_NAME MATCHES "Linux") add_compile_definitions(_FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE=1 _LARGEFILE64_SOURCE=1) diff --git a/src/include/86box/machine_status.h b/src/include/86box/machine_status.h new file mode 100644 index 000000000..2afed078e --- /dev/null +++ b/src/include/86box/machine_status.h @@ -0,0 +1,32 @@ +#ifndef EMU_MACHINE_STATUS_H +#define EMU_MACHINE_STATUS_H + +typedef struct { + atomic_bool_t empty; + atomic_bool_t active; +} dev_status_empty_active_t; + +typedef struct { + atomic_bool_t active; +} dev_status_active_t; + +typedef struct { + atomic_bool_t empty; +} dev_status_empty_t; + +typedef struct { + dev_status_empty_active_t fdd[FDD_NUM]; + dev_status_empty_active_t cdrom[CDROM_NUM]; + dev_status_empty_active_t zip[ZIP_NUM]; + dev_status_empty_active_t mo[MO_NUM]; + dev_status_empty_active_t cassette; + dev_status_active_t hdd[HDD_BUS_USB]; + dev_status_active_t net; + dev_status_empty_t cartridge[2]; +} machine_status_t; + +extern machine_status_t machine_status; + +extern void machine_status_init(); + +#endif /*EMU_MACHINE_STATUS_H*/ \ No newline at end of file diff --git a/src/include/86box/plat.h b/src/include/86box/plat.h index 5b810ed22..d4b50e0a5 100644 --- a/src/include/86box/plat.h +++ b/src/include/86box/plat.h @@ -68,10 +68,12 @@ extern int strnicmp(const char* s1, const char* s2, size_t n); #ifdef __cplusplus #include #define atomic_flag_t std::atomic_flag +#define atomic_bool_t std::atomic_bool extern "C" { #else #include #define atomic_flag_t atomic_flag +#define atomic_bool_t atomic_bool #endif /* Global variables residing in the platform module. */ diff --git a/src/include/86box/ui.h b/src/include/86box/ui.h index 847b8c706..adfb84581 100644 --- a/src/include/86box/ui.h +++ b/src/include/86box/ui.h @@ -70,8 +70,8 @@ extern void ui_sb_update_panes(void); extern void ui_sb_update_text(void); extern void ui_sb_update_tip(int meaning); extern void ui_sb_timer_callback(int pane); -extern void ui_sb_update_icon(int tag, int val); -extern void ui_sb_update_icon_state(int tag, int active); +extern void ui_sb_update_icon(int tag, int active); +extern void ui_sb_update_icon_state(int tag, int state); extern void ui_sb_set_text_w(wchar_t *wstr); extern void ui_sb_set_text(char *str); extern void ui_sb_bugui(char *str); diff --git a/src/machine_status.c b/src/machine_status.c new file mode 100644 index 000000000..258c16821 --- /dev/null +++ b/src/machine_status.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include + +#include <86box/86box.h> +#include <86box/plat.h> +#include <86box/ui.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/fdd.h> +#include <86box/hdc.h> +#include <86box/scsi.h> +#include <86box/scsi_device.h> +#include <86box/cartridge.h> +#include <86box/cassette.h> +#include <86box/cdrom.h> +#include <86box/zip.h> +#include <86box/mo.h> +#include <86box/hdd.h> +#include <86box/machine_status.h> + +machine_status_t machine_status; + +void +machine_status_init() { + for (size_t i = 0; i < FDD_NUM; ++i) { + machine_status.fdd[i].empty = (strlen(floppyfns[i]) == 0); + machine_status.fdd[i].active = false; + } + for (size_t i = 0; i < CDROM_NUM; ++i) { + machine_status.cdrom[i].empty = cdrom[i].host_drive != 200 || (strlen(cdrom[i].image_path) == 0); + machine_status.cdrom[i].active = false; + } + for (size_t i = 0; i < ZIP_NUM; i++) { + machine_status.zip[i].empty = (strlen(zip_drives[i].image_path) == 0); + machine_status.zip[i].active = false; + } + for (size_t i = 0; i < MO_NUM; i++) { + machine_status.mo[i].empty = (strlen(mo_drives[i].image_path) == 0); + machine_status.mo[i].active = false; + } + + machine_status.cassette.empty = (strlen(cassette_fname) == 0); + + for (size_t i = 0; i < HDD_BUS_USB; i++) { + machine_status.hdd[i].active = false; + } + + machine_status.net.active = false; +} \ No newline at end of file diff --git a/src/qt/qt_machinestatus.cpp b/src/qt/qt_machinestatus.cpp index bd0e491f1..773566319 100644 --- a/src/qt/qt_machinestatus.cpp +++ b/src/qt/qt_machinestatus.cpp @@ -39,6 +39,7 @@ extern uint64_t tsc; #include <86box/machine.h> #include <86box/network.h> #include <86box/ui.h> +#include <86box/machine_status.h> }; #include @@ -92,17 +93,21 @@ namespace { struct StateActive { std::unique_ptr label; - QTimer timer; PixmapSetActive* pixmaps = nullptr; bool active = false; void setActive(bool b) { - active = b; - if (! label) { + if (!label || b == active) + return; + active = b; + + refresh(); + } + + void refresh() { + if (!label) return; - } label->setPixmap(active ? pixmaps->active : pixmaps->normal); - timer.start(75); } }; struct StateEmpty { @@ -111,33 +116,42 @@ namespace { bool empty = false; void setEmpty(bool e) { - empty = e; - if (! label) { + if (!label || e == empty) + return; + empty = e; + + refresh(); + } + + void refresh() { + if (!label) return; - } label->setPixmap(empty ? pixmaps->empty : pixmaps->normal); } }; struct StateEmptyActive { std::unique_ptr label; - QTimer timer; PixmapSetEmptyActive* pixmaps = nullptr; bool empty = false; bool active = false; void setActive(bool b) { + if (!label || b == active) + return; + active = b; refresh(); - timer.start(75); } void setEmpty(bool b) { + if (!label || b == empty) + return; + empty = b; refresh(); } void refresh() { - if (! label) { + if (!label) return; - } if (empty) { label->setPixmap(active ? pixmaps->empty_active : pixmaps->empty); } else { @@ -190,26 +204,20 @@ struct MachineStatus::States { cartridge[0].pixmaps = &pixmaps.cartridge; cartridge[1].pixmaps = &pixmaps.cartridge; cassette.pixmaps = &pixmaps.cassette; - QObject::connect(&cassette.timer, &QTimer::timeout, parent, [&]{ cassette.setActive(false); }); for (auto& f : fdd) { f.pixmaps = &pixmaps.floppy_disabled; - QObject::connect(&f.timer, &QTimer::timeout, parent, [&]{ f.setActive(false); }); } for (auto& c : cdrom) { c.pixmaps = &pixmaps.cdrom; - QObject::connect(&c.timer, &QTimer::timeout, parent, [&]{ c.setActive(false); }); } for (auto& z : zip) { z.pixmaps = &pixmaps.zip; - QObject::connect(&z.timer, &QTimer::timeout, parent, [&]{ z.setActive(false); }); } for (auto& m : mo) { m.pixmaps = &pixmaps.mo; - QObject::connect(&m.timer, &QTimer::timeout, parent, [&]{ m.setActive(false); }); } for (auto& h : hdds) { h.pixmaps = &pixmaps.hd; - QObject::connect(&h.timer, &QTimer::timeout, parent, [&]{ h.setActive(false); }); } net.pixmaps = &pixmaps.net; } @@ -227,9 +235,12 @@ struct MachineStatus::States { }; MachineStatus::MachineStatus(QObject *parent) : - QObject(parent) + QObject(parent), + refreshTimer(new QTimer(this)) { d = std::make_unique(this); + connect(refreshTimer, &QTimer::timeout, this, &MachineStatus::refreshIcons); + refreshTimer->start(75); } MachineStatus::~MachineStatus() = default; @@ -321,6 +332,38 @@ static int hdd_count(int bus) { return(c); } +void MachineStatus::refreshIcons() { + for (size_t i = 0; i < FDD_NUM; ++i) { + d->fdd[i].setActive(machine_status.fdd[i].active); + d->fdd[i].setEmpty(machine_status.fdd[i].empty); + } + for (size_t i = 0; i < CDROM_NUM; ++i) { + d->cdrom[i].setActive(machine_status.cdrom[i].active); + d->cdrom[i].setEmpty(machine_status.cdrom[i].empty); + } + for (size_t i = 0; i < ZIP_NUM; i++) { + d->zip[i].setActive(machine_status.zip[i].active); + d->zip[i].setEmpty(machine_status.zip[i].empty); + } + for (size_t i = 0; i < MO_NUM; i++) { + d->mo[i].setActive(machine_status.mo[i].active); + d->mo[i].setEmpty(machine_status.mo[i].empty); + } + + d->cassette.setEmpty(machine_status.cassette.empty); + + for (size_t i = 0; i < HDD_BUS_USB; i++) { + d->hdds[i].setActive(machine_status.hdd[i].active); + } + + d->net.setActive(machine_status.net.active); + + for (int i = 0; i < 2; ++i) { + d->cartridge[i].setEmpty(machine_status.cartridge[i].empty); + } + +} + void MachineStatus::refresh(QStatusBar* sbar) { bool has_mfm = machine_has_flags(machine, MACHINE_MFM) > 0; bool has_xta = machine_has_flags(machine, MACHINE_XTA) > 0; @@ -358,6 +401,7 @@ void MachineStatus::refresh(QStatusBar* sbar) { if (cassette_enable) { d->cassette.label = std::make_unique(); d->cassette.setEmpty(QString(cassette_fname).isEmpty()); + d->cassette.refresh(); connect((ClickableLabel*)d->cassette.label.get(), &ClickableLabel::clicked, [](QPoint pos) { MediaMenu::ptr->cassetteMenu->popup(pos - QPoint(0, MediaMenu::ptr->cassetteMenu->sizeHint().height())); }); @@ -373,6 +417,7 @@ void MachineStatus::refresh(QStatusBar* sbar) { for (int i = 0; i < 2; ++i) { d->cartridge[i].label = std::make_unique(); d->cartridge[i].setEmpty(QString(cart_fns[i]).isEmpty()); + d->cartridge[i].refresh(); connect((ClickableLabel*)d->cartridge[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) { MediaMenu::ptr->cartridgeMenus[i]->popup(pos - QPoint(0, MediaMenu::ptr->cartridgeMenus[i]->sizeHint().height())); }); @@ -397,6 +442,7 @@ void MachineStatus::refresh(QStatusBar* sbar) { d->fdd[i].label = std::make_unique(); d->fdd[i].setEmpty(QString(floppyfns[i]).isEmpty()); d->fdd[i].setActive(false); + d->fdd[i].refresh(); connect((ClickableLabel*)d->fdd[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) { MediaMenu::ptr->floppyMenus[i]->popup(pos - QPoint(0, MediaMenu::ptr->floppyMenus[i]->sizeHint().height())); }); @@ -412,6 +458,7 @@ void MachineStatus::refresh(QStatusBar* sbar) { d->cdrom[i].label = std::make_unique(); d->cdrom[i].setEmpty(cdrom[i].host_drive != 200 || QString(cdrom[i].image_path).isEmpty()); d->cdrom[i].setActive(false); + d->cdrom[i].refresh(); connect((ClickableLabel*)d->cdrom[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) { MediaMenu::ptr->cdromMenus[i]->popup(pos - QPoint(0, MediaMenu::ptr->cdromMenus[i]->sizeHint().height())); }); @@ -427,6 +474,7 @@ void MachineStatus::refresh(QStatusBar* sbar) { d->zip[i].label = std::make_unique(); d->zip[i].setEmpty(QString(zip_drives[i].image_path).isEmpty()); d->zip[i].setActive(false); + d->zip[i].refresh(); connect((ClickableLabel*)d->zip[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) { MediaMenu::ptr->zipMenus[i]->popup(pos - QPoint(0, MediaMenu::ptr->zipMenus[i]->sizeHint().height())); }); @@ -442,6 +490,7 @@ void MachineStatus::refresh(QStatusBar* sbar) { d->mo[i].label = std::make_unique(); d->mo[i].setEmpty(QString(mo_drives[i].image_path).isEmpty()); d->mo[i].setActive(false); + d->mo[i].refresh(); connect((ClickableLabel*)d->mo[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) { MediaMenu::ptr->moMenus[i]->popup(pos - QPoint(0, MediaMenu::ptr->moMenus[i]->sizeHint().height())); }); @@ -457,24 +506,28 @@ void MachineStatus::refresh(QStatusBar* sbar) { if ((has_mfm || hdc_name.left(5) == QStringLiteral("st506")) && c_mfm > 0) { d->hdds[HDD_BUS_MFM].label = std::make_unique(); d->hdds[HDD_BUS_MFM].setActive(false); + d->hdds[HDD_BUS_MFM].refresh(); d->hdds[HDD_BUS_MFM].label->setToolTip(tr("Hard disk (%s)").replace("%s", "MFM/RLL")); sbar->addWidget(d->hdds[HDD_BUS_MFM].label.get()); } if ((has_esdi || hdc_name.left(4) == QStringLiteral("esdi")) && c_esdi > 0) { d->hdds[HDD_BUS_ESDI].label = std::make_unique(); d->hdds[HDD_BUS_ESDI].setActive(false); + d->hdds[HDD_BUS_ESDI].refresh(); d->hdds[HDD_BUS_ESDI].label->setToolTip(tr("Hard disk (%s)").replace("%s", "ESDI")); sbar->addWidget(d->hdds[HDD_BUS_ESDI].label.get()); } if ((has_xta || hdc_name.left(3) == QStringLiteral("xta")) && c_xta > 0) { d->hdds[HDD_BUS_XTA].label = std::make_unique(); d->hdds[HDD_BUS_XTA].setActive(false); + d->hdds[HDD_BUS_XTA].refresh(); d->hdds[HDD_BUS_XTA].label->setToolTip(tr("Hard disk (%s)").replace("%s", "XTA")); sbar->addWidget(d->hdds[HDD_BUS_XTA].label.get()); } if ((hasIDE() || hdc_name.left(5) == QStringLiteral("xtide") || hdc_name.left(3) == QStringLiteral("ide")) && c_ide > 0) { d->hdds[HDD_BUS_IDE].label = std::make_unique(); d->hdds[HDD_BUS_IDE].setActive(false); + d->hdds[HDD_BUS_IDE].refresh(); d->hdds[HDD_BUS_IDE].label->setToolTip(tr("Hard disk (%s)").replace("%s", "IDE")); sbar->addWidget(d->hdds[HDD_BUS_IDE].label.get()); } @@ -482,6 +535,7 @@ void MachineStatus::refresh(QStatusBar* sbar) { (scsi_card_current[2] != 0) || (scsi_card_current[3] != 0)) && c_scsi > 0) { d->hdds[HDD_BUS_SCSI].label = std::make_unique(); d->hdds[HDD_BUS_SCSI].setActive(false); + d->hdds[HDD_BUS_SCSI].refresh(); d->hdds[HDD_BUS_SCSI].label->setToolTip(tr("Hard disk (%s)").replace("%s", "SCSI")); sbar->addWidget(d->hdds[HDD_BUS_SCSI].label.get()); } @@ -489,6 +543,7 @@ void MachineStatus::refresh(QStatusBar* sbar) { if (do_net) { d->net.label = std::make_unique(); d->net.setActive(false); + d->net.refresh(); d->net.label->setToolTip(tr("Network")); sbar->addWidget(d->net.label.get()); } @@ -505,72 +560,6 @@ void MachineStatus::refresh(QStatusBar* sbar) { sbar->addWidget(d->text.get()); } -void MachineStatus::setActivity(int tag, bool active) { - int category = tag & 0xfffffff0; - int item = tag & 0xf; - switch (category) { - case SB_CASSETTE: - break; - case SB_CARTRIDGE: - break; - case SB_FLOPPY: - d->fdd[item].setActive(active); - break; - case SB_CDROM: - d->cdrom[item].setActive(active); - break; - case SB_ZIP: - d->zip[item].setActive(active); - break; - case SB_MO: - d->mo[item].setActive(active); - break; - case SB_HDD: - d->hdds[item].setActive(active); - break; - case SB_NETWORK: - d->net.setActive(active); - break; - case SB_SOUND: - break; - case SB_TEXT: - break; - } -} - -void MachineStatus::setEmpty(int tag, bool empty) { - int category = tag & 0xfffffff0; - int item = tag & 0xf; - switch (category) { - case SB_CASSETTE: - d->cassette.setEmpty(empty); - break; - case SB_CARTRIDGE: - d->cartridge[item].setEmpty(empty); - break; - case SB_FLOPPY: - d->fdd[item].setEmpty(empty); - break; - case SB_CDROM: - d->cdrom[item].setEmpty(empty); - break; - case SB_ZIP: - d->zip[item].setEmpty(empty); - break; - case SB_MO: - d->mo[item].setEmpty(empty); - break; - case SB_HDD: - break; - case SB_NETWORK: - break; - case SB_SOUND: - break; - case SB_TEXT: - break; - } -} - void MachineStatus::message(const QString &msg) { d->text->setText(msg); } diff --git a/src/qt/qt_machinestatus.hpp b/src/qt/qt_machinestatus.hpp index ba30d36f2..8c31dd238 100644 --- a/src/qt/qt_machinestatus.hpp +++ b/src/qt/qt_machinestatus.hpp @@ -70,14 +70,14 @@ public: QString getMessage(); public slots: void refresh(QStatusBar* sbar); - void setActivity(int tag, bool active); - void setEmpty(int tag, bool active); void message(const QString& msg); void updateTip(int tag); + void refreshIcons(); private: struct States; std::unique_ptr d; + QTimer *refreshTimer; }; #endif // QT_MACHINESTATUS_HPP diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 31ab4886b..d0549311b 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -266,8 +266,6 @@ MainWindow::MainWindow(QWidget *parent) : }); connect(this, &MainWindow::updateStatusBarPanes, this, &MainWindow::refreshMediaMenu); connect(this, &MainWindow::updateStatusBarTip, status.get(), &MachineStatus::updateTip); - connect(this, &MainWindow::updateStatusBarActivity, status.get(), &MachineStatus::setActivity); - connect(this, &MainWindow::updateStatusBarEmpty, status.get(), &MachineStatus::setEmpty); connect(this, &MainWindow::statusBarMessage, status.get(), &MachineStatus::message, Qt::QueuedConnection); ui->actionKeyboard_requires_capture->setChecked(kbd_req_capture); diff --git a/src/qt/qt_progsettings.cpp b/src/qt/qt_progsettings.cpp index 803fddc24..b11466c08 100644 --- a/src/qt/qt_progsettings.cpp +++ b/src/qt/qt_progsettings.cpp @@ -132,8 +132,6 @@ void ProgSettings::accept() main_window->refreshMediaMenu(); main_window->status->message(msg); connect(main_window, &MainWindow::updateStatusBarTip, main_window->status.get(), &MachineStatus::updateTip); - connect(main_window, &MainWindow::updateStatusBarActivity, main_window->status.get(), &MachineStatus::setActivity); - connect(main_window, &MainWindow::updateStatusBarEmpty, main_window->status.get(), &MachineStatus::setEmpty); connect(main_window, &MainWindow::statusBarMessage, main_window->status.get(), &MachineStatus::message, Qt::QueuedConnection); mouse_sensitivity = mouseSensitivity; QDialog::accept(); diff --git a/src/qt/qt_ui.cpp b/src/qt/qt_ui.cpp index 128631282..74cc88ebf 100644 --- a/src/qt/qt_ui.cpp +++ b/src/qt/qt_ui.cpp @@ -25,6 +25,7 @@ #include #include "qt_mainwindow.hpp" +#include "qt_machinestatus.hpp" MainWindow* main_window = nullptr; @@ -35,6 +36,20 @@ extern "C" { #include <86box/plat.h> #include <86box/ui.h> #include <86box/mouse.h> +#include <86box/timer.h> +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/fdd.h> +#include <86box/hdc.h> +#include <86box/scsi.h> +#include <86box/scsi_device.h> +#include <86box/cartridge.h> +#include <86box/cassette.h> +#include <86box/cdrom.h> +#include <86box/zip.h> +#include <86box/mo.h> +#include <86box/hdd.h> +#include <86box/machine_status.h> void plat_delay_ms(uint32_t count) @@ -161,16 +176,70 @@ void ui_sb_set_ready(int ready) { void ui_sb_update_icon_state(int tag, int state) { - if (main_window == nullptr) { - return; + int category = tag & 0xfffffff0; + int item = tag & 0xf; + switch (category) { + case SB_CASSETTE: + machine_status.cassette.empty = state > 0 ? true : false; + break; + case SB_CARTRIDGE: + machine_status.cartridge[item].empty = state > 0 ? true : false; + break; + case SB_FLOPPY: + machine_status.fdd[item].empty = state > 0 ? true : false; + break; + case SB_CDROM: + machine_status.cdrom[item].empty = state > 0 ? true : false; + break; + case SB_ZIP: + machine_status.zip[item].empty = state > 0 ? true : false; + break; + case SB_MO: + machine_status.mo[item].empty = state > 0 ? true : false; + break; + case SB_HDD: + break; + case SB_NETWORK: + break; + case SB_SOUND: + break; + case SB_TEXT: + break; } - main_window->updateStatusBarEmpty(tag, state > 0 ? true : false); } void ui_sb_update_icon(int tag, int active) { - if (!update_icons) return; - main_window->updateStatusBarActivity(tag, active > 0 ? true : false); + int category = tag & 0xfffffff0; + int item = tag & 0xf; + switch (category) { + case SB_CASSETTE: + break; + case SB_CARTRIDGE: + break; + case SB_FLOPPY: + machine_status.fdd[item].active = active > 0 ? true : false; + break; + case SB_CDROM: + machine_status.cdrom[item].active = active > 0 ? true : false; + break; + case SB_ZIP: + machine_status.zip[item].active = active > 0 ? true : false; + break; + case SB_MO: + machine_status.mo[item].active = active > 0 ? true : false; + break; + case SB_HDD: + machine_status.hdd[item].active = active > 0 ? true : false; + break; + case SB_NETWORK: + machine_status.net.active = active > 0 ? true : false; + break; + case SB_SOUND: + break; + case SB_TEXT: + break; + } } } From 2f9597d13a760f39c401cad7b65e68cbea365d5f Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Wed, 13 Jul 2022 01:04:40 +0200 Subject: [PATCH 3/5] Fix IDE activity status updating --- src/disk/hdc_ide.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index a4a9f2ddc..b005cbd6d 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -1642,9 +1642,6 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) disabled, the Read Multiple operation is rejected with an Aborted Com- mand error. */ ide->blockcount = 0; - /* Turn on the activity indicator *here* so that it gets turned on - less times. */ - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); /*FALLTHROUGH*/ case WIN_READ: @@ -1658,6 +1655,7 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide->atastat = BSY_STAT; if (ide->type == IDE_HDD) { + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); uint32_t sec_count; double wait_time; if ((val == WIN_READ_DMA) || (val == WIN_READ_DMA_ALT)) { @@ -1908,7 +1906,7 @@ ide_read_data(ide_t *ide, int length) double xfer_time = ide_get_xfer_time(ide, 512); ide_set_callback(ide, seek_time + xfer_time); } - } else if (ide->command != WIN_READ_MULTIPLE) + } else ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); } } From aa9fc2d44a21cac19ec70d624597938b24058725 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Tue, 12 Jul 2022 19:41:44 -0400 Subject: [PATCH 4/5] Fix accidental removal of rtmidi --- .github/workflows/cmake.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index c6ac100f7..5606f1342 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -77,6 +77,7 @@ jobs: ${{ matrix.environment.prefix }}-libpng ${{ matrix.environment.prefix }}-libvncserver ${{ matrix.environment.prefix }}-openal + ${{ matrix.environment.prefix }}-rtmidi - uses: actions/checkout@v2 - name: Configure CMake run: >- From 7430df2cc30258e4244576ed8a97beaa33e3883b Mon Sep 17 00:00:00 2001 From: richardg867 Date: Tue, 12 Jul 2022 22:22:00 -0300 Subject: [PATCH 5/5] Add incomplete (and standalone for now) 8042 emulator --- src/upi42.c | 903 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 903 insertions(+) create mode 100644 src/upi42.c diff --git a/src/upi42.c b/src/upi42.c new file mode 100644 index 000000000..e98af5496 --- /dev/null +++ b/src/upi42.c @@ -0,0 +1,903 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Intel UPI-42/MCS-48 microcontroller emulation. + * + * + * + * Authors: RichardG, + * + * Copyright 2022 RichardG. + */ +#include +#include +#include +#include +#define fatal printf +#define pclog printf + +enum { + UPI42_8042 = 0, + UPI42_80C42 +}; + +typedef struct _upi42_ { + int (*ops[256])(struct _upi42_ *upi42, uint32_t fetchdat); + uint8_t ram[256], rom[4096], /* memory */ + ports[7], /* I/O ports */ + dbb_in, dbb_out; /* UPI-42 data buffer */ + + uint8_t rammask, + a, /* accumulator */ + t, /* timer counter */ + psw, /* program status word */ + sts; /* UPI-42 status */ + + uint16_t pc; /* program counter */ + + unsigned int prescaler : 5, tf : 1, tcnti : 1, run_timer : 1, run_counter : 1, skip_timer_inc : 1, /* timer/counter */ + i : 1, i_asserted : 1, tcnti_asserted : 1, irq_mask : 1, /* interrupts */ + dbf : 1, /* ROM bank */ + t0 : 1, t1 : 1, /* T0/T1 signals */ + flags : 1, /* buffer flag pins */ + suspend : 1; /* 80C42 suspend flag */ + + int cycs; /* cycle counter */ +} upi42_t; + +#define UPI42_REG_READ(upi42, r) ((upi42->psw & 0x10) ? (upi42->ram[24 + ((r) &7)]) : (upi42->ram[(r) &7])) +#define UPI42_REG_WRITE(upi42, r, op) ((upi42->psw & 0x10) ? (upi42->ram[24 + ((r) &7)] op) : (upi42->ram[(r) &7] op)) + +static inline void +upi42_mirror_f0(upi42_t *upi42) +{ + /* Update status register F0 flag to match PSW F0 flag. */ + upi42->sts = ((upi42->psw & 0x20) >> 3) | (upi42->sts & ~0x04); +} + +static int +upi42_op_MOV_A_Rr(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = UPI42_REG_READ(upi42, fetchdat); + return 1; +} + +static int +upi42_op_MOV_Rr_A(upi42_t *upi42, uint32_t fetchdat) +{ + UPI42_REG_WRITE(upi42, fetchdat, = upi42->a); + return 1; +} + +static int +upi42_op_MOV_A_indRr(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = upi42->ram[upi42->ram[fetchdat & 1] & upi42->rammask]; + return 1; +} + +static int +upi42_op_MOV_indRr_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->ram[upi42->ram[fetchdat & 1] & upi42->rammask] = upi42->a; + return 1; +} + +static int +upi42_op_MOV_Rr_imm(upi42_t *upi42, uint32_t fetchdat) +{ + UPI42_REG_WRITE(upi42, fetchdat, = fetchdat >> 8); + upi42->cycs--; + return 2; +} + +static int +upi42_op_MOV_indRr_imm(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->ram[upi42->ram[fetchdat & 1] & upi42->rammask] = fetchdat >> 8; + upi42->cycs--; + return 2; +} + +static int +upi42_op_MOV_A_imm(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = fetchdat >> 8; + upi42->cycs--; + return 2; +} + +static int +upi42_op_MOV_A_PSW(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = upi42->psw; + upi42_mirror_f0(upi42); + return 1; +} + +static int +upi42_op_MOV_PSW_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->psw = upi42->a; + upi42_mirror_f0(upi42); + return 1; +} + +static int +upi42_op_MOV_A_T(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = upi42->t; + return 1; +} + +static int +upi42_op_MOV_T_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->t = upi42->a; + return 1; +} + +static int +upi42_op_MOV_STS_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->sts = (upi42->a & 0xf0) | (upi42->sts & 0x0f); + return 1; +} + +static int +upi42_op_MOVP_A_indA(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = upi42->rom[(upi42->pc & 0xff00) | upi42->a]; + upi42->cycs--; + return 1; +} + +static int +upi42_op_MOVP3_A_indA(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = upi42->rom[0x300 | upi42->a]; + upi42->cycs--; + return 1; +} + +static int +upi42_op_XCH_A_Rr(upi42_t *upi42, uint32_t fetchdat) +{ + uint8_t temp = upi42->a; + upi42->a = UPI42_REG_READ(upi42, fetchdat); + UPI42_REG_WRITE(upi42, fetchdat, = temp); + return 1; +} + +static int +upi42_op_XCH_A_indRr(upi42_t *upi42, uint32_t fetchdat) +{ + uint8_t temp = upi42->a, addr = upi42->ram[fetchdat & 1] & upi42->rammask; + upi42->a = upi42->ram[addr]; + upi42->ram[addr] = temp; + return 1; +} + +static int +upi42_op_XCHD_A_indRr(upi42_t *upi42, uint32_t fetchdat) +{ + uint8_t temp = upi42->a, addr = upi42->ram[fetchdat & 1] & upi42->rammask; + upi42->a = (upi42->a & 0xf0) | (upi42->ram[addr] & 0x0f); + upi42->ram[addr] = (upi42->ram[addr] & 0xf0) | (temp & 0x0f); + return 1; +} + +static int +upi42_op_SWAP_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = (upi42->a << 4) | (upi42->a >> 4); + return 1; +} + +static int +upi42_op_IN_A_Pp(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = upi42->ports[fetchdat & 3]; + upi42->cycs--; + return 1; +} + +static int +upi42_op_IN_A_DBB(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = upi42->dbb_in; + return 1; +} + +static int +upi42_op_OUTL_Pp_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->ports[fetchdat & 3] = upi42->a; + upi42->cycs--; + return 1; +} + +static int +upi42_op_OUT_DBB_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->dbb_out = upi42->a; + upi42->sts |= 0x01; + return 1; +} + +static int +upi42_op_MOVD_A_Pp(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = upi42->ports[4 | (fetchdat & 3)] & 0x0f; + upi42->cycs--; + return 1; +} + +static int +upi42_op_MOVD_Pp_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->ports[4 | (fetchdat & 3)] = upi42->a & 0x0f; + upi42->cycs--; + return 1; +} + +static int +upi42_op_ANL_A_Rr(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a &= UPI42_REG_READ(upi42, fetchdat); + return 1; +} + +static int +upi42_op_ORL_A_Rr(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a |= UPI42_REG_READ(upi42, fetchdat); + return 1; +} + +static int +upi42_op_XRL_A_Rr(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a ^= UPI42_REG_READ(upi42, fetchdat); + return 1; +} + +static int +upi42_op_ANL_A_indRr(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a &= upi42->ram[upi42->ram[fetchdat & 1] & upi42->rammask]; + return 1; +} + +static int +upi42_op_ORL_A_indRr(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a |= upi42->ram[upi42->ram[fetchdat & 1] & upi42->rammask]; + return 1; +} + +static int +upi42_op_XRL_A_indRr(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a ^= upi42->ram[upi42->ram[fetchdat & 1] & upi42->rammask]; + return 1; +} + +static int +upi42_op_ANL_A_imm(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a &= fetchdat >> 8; + upi42->cycs--; + return 2; +} + +static int +upi42_op_ORL_A_imm(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a |= fetchdat >> 8; + upi42->cycs--; + return 2; +} + +static int +upi42_op_XRL_A_imm(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a ^= fetchdat >> 8; + upi42->cycs--; + return 2; +} + +static int +upi42_op_ANL_Pp_imm(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->ports[fetchdat & 3] &= fetchdat >> 8; + upi42->cycs--; + return 2; +} + +static int +upi42_op_ORL_Pp_imm(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->ports[fetchdat & 3] |= fetchdat >> 8; + upi42->cycs--; + return 2; +} + +static int +upi42_op_ANLD_Pp_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->ports[4 | (fetchdat & 3)] &= upi42->a; + upi42->cycs--; + return 1; +} + +static int +upi42_op_ORLD_Pp_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->ports[4 | (fetchdat & 3)] |= upi42->a; + upi42->cycs--; + return 1; +} + +static int +upi42_op_RR_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = (upi42->a << 7) | (upi42->a >> 1); + return 1; +} + +static int +upi42_op_RL_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = (upi42->a >> 7) | (upi42->a << 1); + return 1; +} + +static int +upi42_op_RRC_A(upi42_t *upi42, uint32_t fetchdat) +{ + uint8_t temp = upi42->a; + upi42->a = (upi42->psw & 0x80) | (temp >> 1); + upi42->psw = (temp << 7) | (upi42->psw & ~0x80); + return 1; +} + +static int +upi42_op_RLC_A(upi42_t *upi42, uint32_t fetchdat) +{ + uint8_t temp = upi42->a; + upi42->a = (temp << 1) | (upi42->psw >> 7); + upi42->psw = (temp & 0x80) | (upi42->psw & ~0x80); + return 1; +} + +static int +upi42_op_INC_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a++; + return 1; +} + +static int +upi42_op_INC_Rr(upi42_t *upi42, uint32_t fetchdat) +{ + UPI42_REG_WRITE(upi42, fetchdat, ++); + return 1; +} + +static int +upi42_op_INC_indRr(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->ram[upi42->ram[fetchdat & 1] & upi42->rammask]++; + return 1; +} + +static int +upi42_op_DEC_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a--; + return 1; +} + +static int +upi42_op_DEC_Rr(upi42_t *upi42, uint32_t fetchdat) +{ + UPI42_REG_WRITE(upi42, fetchdat, --); + return 1; +} + +static int +upi42_op_DJNZ_Rr_imm(upi42_t *upi42, uint32_t fetchdat) +{ + UPI42_REG_WRITE(upi42, fetchdat, --); + if (UPI42_REG_READ(upi42, fetchdat)) { + upi42->pc = (upi42->pc & 0xff00) | ((fetchdat >> 8) & 0xff); + return 0; + } else { + return 2; + } +} + +static int +upi42_op_ADD_A_Rr(upi42_t *upi42, uint32_t fetchdat) +{ + int res = upi42->a + UPI42_REG_READ(upi42, fetchdat); + upi42->a = res; + upi42->psw = ((res >> 1) & 0x80) | (upi42->psw & ~0x80); + return 1; +} + +static int +upi42_op_ADDC_A_Rr(upi42_t *upi42, uint32_t fetchdat) +{ + int res = upi42->a + (upi42->psw >> 7) + UPI42_REG_READ(upi42, fetchdat); + upi42->a = res; + upi42->psw = ((res >> 1) & 0x80) | (upi42->psw & ~0x80); + return 1; +} + +static int +upi42_op_ADD_A_indRr(upi42_t *upi42, uint32_t fetchdat) +{ + int res = upi42->a + upi42->ram[UPI42_REG_READ(upi42, fetchdat) & upi42->rammask]; + upi42->a = res; + upi42->psw = ((res >> 1) & 0x80) | (upi42->psw & ~0x80); + return 1; +} + +static int +upi42_op_ADDC_A_indRr(upi42_t *upi42, uint32_t fetchdat) +{ + int res = upi42->a + (upi42->psw >> 7) + upi42->ram[UPI42_REG_READ(upi42, fetchdat) & upi42->rammask]; + upi42->a = res; + upi42->psw = ((res >> 1) & 0x80) | (upi42->psw & ~0x80); + return 1; +} + +static int +upi42_op_ADD_A_imm(upi42_t *upi42, uint32_t fetchdat) +{ + int res = upi42->a + (fetchdat >> 8); + upi42->a = res; + upi42->psw = ((res >> 1) & 0x80) | (upi42->psw & ~0x80); + upi42->cycs--; + return 2; +} + +static int +upi42_op_ADDC_A_imm(upi42_t *upi42, uint32_t fetchdat) +{ + int res = upi42->a + (upi42->psw >> 7) + (fetchdat >> 8); + upi42->a = res; + upi42->psw = ((res >> 1) & 0x80) | (upi42->psw & ~0x80); + upi42->cycs--; + return 2; +} + +static int +upi42_op_CLR_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = 0; + return 1; +} + +static int +upi42_op_CPL_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = ~upi42->a; + return 1; +} + +static int +upi42_op_DA_A(upi42_t *upi42, uint32_t fetchdat) +{ + if (((upi42->a & 0x0f) > 9) || (upi42->psw & 0x40)) + upi42->a += 6; + if (((upi42->a >> 4) > 9) || (upi42->psw & 0x80)) { + int res = upi42->a + (6 << 4); + upi42->a = res; + upi42->psw = ((res >> 1) & 0x80) | (upi42->psw & ~0x80); + } + return 1; +} + +static int +upi42_op_CLR_C(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->psw &= ~0x80; + return 1; +} + +static int +upi42_op_CPL_C(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->psw ^= 0x80; + return 1; +} + +static int +upi42_op_CLR_F0(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->psw &= ~0x20; + upi42_mirror_f0(upi42); + return 1; +} + +static int +upi42_op_CPL_F0(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->psw ^= 0x20; + upi42_mirror_f0(upi42); + return 1; +} + +static int +upi42_op_CLR_F1(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->sts &= ~0x08; + return 1; +} + +static int +upi42_op_CPL_F1(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->sts ^= 0x08; + return 1; +} + +static int +upi42_op_EN_I(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->i = 1; + upi42->skip_timer_inc = 1; + return 1; +} + +static int +upi42_op_DIS_I(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->i = 0; + upi42->skip_timer_inc = 1; + return 1; +} + +static int +upi42_op_EN_TCNTI(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->tcnti = 1; + return 1; +} + +static int +upi42_op_DIS_TCNTI(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->tcnti = upi42->tcnti_asserted = 0; + return 1; +} + +static int +upi42_op_STRT_T(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->run_timer = 1; + upi42->prescaler = 0; + upi42->skip_timer_inc = 1; + return 1; +} + +static int +upi42_op_STRT_CNT(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->run_counter = 1; + upi42->skip_timer_inc = 1; + return 1; +} + +static int +upi42_op_STOP_TCNT(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->run_timer = upi42->run_counter = 0; + upi42->skip_timer_inc = 1; + return 1; +} + +static int +upi42_op_SEL_PMB0(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->dbf = 0; + return 1; +} + +static int +upi42_op_SEL_PMB1(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->dbf = 1; + return 1; +} + +static int +upi42_op_SEL_RB0(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->psw &= ~0x10; + return 1; +} + +static int +upi42_op_SEL_RB1(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->psw |= 0x10; + return 1; +} + +static int +upi42_op_NOP(upi42_t *upi42, uint32_t fetchdat) +{ + return 1; +} + +static int +upi42_op_CALL_imm(upi42_t *upi42, uint32_t fetchdat) +{ + /* Push new frame onto stack. */ + uint8_t sp = (upi42->psw & 0x07) << 1; + upi42->ram[8 + sp++] = upi42->pc; /* stack frame format is undocumented! */ + upi42->ram[8 + sp++] = (upi42->psw & 0xf0) | ((upi42->pc >> 8) & 0x07); + upi42->psw = (upi42->psw & 0xf8) | (sp >> 1); + + /* Load new program counter. */ + upi42->pc = (upi42->dbf << 11) | ((fetchdat << 3) & 0x0700) | ((fetchdat >> 8) & 0x00ff); + + /* Don't decrease cycle counter if this is an interrupt call. */ + if (fetchdat & 0xff) + upi42->cycs--; + return 0; +} + +static int +upi42_op_RET(upi42_t *upi42, uint32_t fetchdat) +{ + /* Pop frame off the stack. */ + uint8_t sp = (upi42->psw & 0x07) << 1; + uint8_t frame1 = upi42->ram[8 + --sp]; + uint8_t frame0 = upi42->ram[8 + --sp]; + upi42->psw = (upi42->psw & 0xf8) | (sp >> 1); + + /* Load new program counter. */ + upi42->pc = ((frame1 & 0x0f) << 8) | frame0; + + /* Load new Program Status Word and unmask interrupts if this is RETR. */ + if (fetchdat & 0x10) { + upi42->psw = (frame1 & 0xf0) | (upi42->psw & 0x0f); + upi42_mirror_f0(upi42); + + upi42->irq_mask = 0; + } + + upi42->cycs--; + return 0; +} + +static int +upi42_op_JMP_imm(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->pc = (upi42->dbf << 11) | ((fetchdat << 3) & 0x0700) | ((fetchdat >> 8) & 0x00ff); + upi42->cycs--; + return 0; +} + +static int +upi42_op_JMPP_indA(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->pc = (upi42->pc & 0xff00) | upi42->a; + upi42->cycs--; + return 0; +} + +#define UPI42_COND_JMP_IMM(insn, cond, post) \ + static int \ + upi42_op_##insn##_imm(upi42_t *upi42, uint32_t fetchdat) \ + { \ + if (cond) \ + upi42->pc = (upi42->pc & 0xff00) | ((fetchdat >> 8) & 0x00ff); \ + post \ + upi42->cycs--; \ + return 2 * !(cond); \ + } +UPI42_COND_JMP_IMM(JC, upi42->psw & 0x80, ;) +UPI42_COND_JMP_IMM(JNC, !(upi42->psw & 0x80), ;) +UPI42_COND_JMP_IMM(JZ, !upi42->a, ;) +UPI42_COND_JMP_IMM(JNZ, upi42->a, ;) +UPI42_COND_JMP_IMM(JT0, upi42->t0, ;) +UPI42_COND_JMP_IMM(JNT0, !upi42->t0, ;) +UPI42_COND_JMP_IMM(JT1, upi42->t1, ;) +UPI42_COND_JMP_IMM(JNT1, !upi42->t1, ;) +UPI42_COND_JMP_IMM(JF0, upi42->psw & 0x20, ;) +UPI42_COND_JMP_IMM(JF1, upi42->sts & 0x08, ;) +UPI42_COND_JMP_IMM(JTF, !upi42->tf, upi42->tf = 0;) +UPI42_COND_JMP_IMM(JBb, upi42->a &(1 << ((fetchdat >> 5) & 7)), ;) +UPI42_COND_JMP_IMM(JNIBF, !(upi42->sts & 0x02), ;) +UPI42_COND_JMP_IMM(JOBF, upi42->sts & 0x01, ;) + +static int +upi42_op_EN_A20(upi42_t *upi42, uint32_t fetchdat) +{ + /* Enable fast A20 until reset. */ + return 1; +} + +static int +upi42_op_EN_DMA(upi42_t *upi42, uint32_t fetchdat) +{ + return 1; +} + +static int +upi42_op_EN_FLAGS(upi42_t *upi42, uint32_t fetchdat) +{ + return 1; +} + +static int +upi42_op_SUSPEND(upi42_t *upi42, uint32_t fetchdatr) +{ + /* Inhibit execution until reset. */ + upi42->suspend = 1; + return 1; +} + +static void +upi42_exec(void *priv) +{ + upi42_t *upi42 = (upi42_t *) priv; + + /* Skip interrupt handling and code execution if we're suspended or in a multi-cycle instruction. */ + if (upi42->suspend || ++upi42->cycs < 0) + return; + + /* Trigger interrupt if requested. */ + if (upi42->irq_mask) { + /* Masked, we're currently in an ISR. */ + } else if (upi42->i_asserted) { + /* External interrupt. Higher priority than the timer interrupt. */ + upi42->irq_mask = 1; + upi42->i_asserted = 0; + upi42_op_CALL_imm(upi42, 3 << 8); + return; + } else if (upi42->tcnti_asserted) { + /* Timer interrupt. */ + upi42->irq_mask = 1; + upi42->tcnti_asserted = 0; + upi42_op_CALL_imm(upi42, 7 << 8); + return; + } + + /* Fetch instruction. */ + uint32_t fetchdat = *((uint32_t *) &upi42->rom[upi42->pc]); + pclog("%04X @ %04X R0=%02X", fetchdat & 0xffff, upi42->pc, upi42->ram[0]); + + /* Decode instruction. */ + uint8_t insn = fetchdat & 0xff; + if (upi42->ops[insn]) { + /* Execute instruction and increment program counter. */ + upi42->pc += upi42->ops[insn](upi42, fetchdat); + + /* Decrement cycle counter. Multi-cycle instructions also decrement within their code. */ + upi42->cycs--; + } else { + fatal("UPI42: Unknown opcode %02X (%08X)\n", insn, fetchdat); + return; + } + + /* Some instructions don't increment the timer. */ + if (upi42->skip_timer_inc) { + upi42->skip_timer_inc = 0; + } else { + /* Increment counter once the prescaler overflows, + and set timer flag once the main value overflows. */ + if ((++upi42->prescaler == 0) && (++upi42->t == 0)) { + upi42->tf = 1; + + /* Fire counter interrupt if enabled. */ + if (upi42->tcnti) + upi42->tcnti_asserted = 1; + } + } +} + +static const int (*ops_80c42[256])(upi42_t *upi42, uint32_t fetchdat) = { + // clang-format off + /* 0 / 8 */ /* 1 / 9 */ /* 2 / a */ /* 3 / b */ /* 4 / c */ /* 5 / d */ /* 6 / e */ /* 7 / f */ + /* 00 */ upi42_op_NOP, NULL, upi42_op_OUT_DBB_A, upi42_op_ADD_A_imm, upi42_op_JMP_imm, upi42_op_EN_I, NULL, upi42_op_DEC_A, + /* 08 */ upi42_op_IN_A_Pp, upi42_op_IN_A_Pp, upi42_op_IN_A_Pp, NULL, upi42_op_MOVD_A_Pp, upi42_op_MOVD_A_Pp, upi42_op_MOVD_A_Pp, upi42_op_MOVD_A_Pp, + /* 10 */ upi42_op_INC_indRr, upi42_op_INC_indRr, upi42_op_JBb_imm, upi42_op_ADDC_A_imm, upi42_op_CALL_imm, upi42_op_DIS_I, upi42_op_JTF_imm, upi42_op_INC_A, + /* 18 */ upi42_op_INC_Rr, upi42_op_INC_Rr, upi42_op_INC_Rr, upi42_op_INC_Rr, upi42_op_INC_Rr, upi42_op_INC_Rr, upi42_op_INC_Rr, upi42_op_INC_Rr, + /* 20 */ upi42_op_XCH_A_indRr, upi42_op_XCH_A_indRr, upi42_op_IN_A_DBB, upi42_op_MOV_A_imm, upi42_op_JMP_imm, upi42_op_EN_TCNTI, upi42_op_JNT0_imm, upi42_op_CLR_A, + /* 28 */ upi42_op_XCH_A_Rr, upi42_op_XCH_A_Rr, upi42_op_XCH_A_Rr, upi42_op_XCH_A_Rr, upi42_op_XCH_A_Rr, upi42_op_XCH_A_Rr, upi42_op_XCH_A_Rr, upi42_op_XCH_A_Rr, + /* 30 */ upi42_op_XCHD_A_indRr, upi42_op_XCHD_A_indRr, upi42_op_JBb_imm, upi42_op_EN_A20, upi42_op_CALL_imm, upi42_op_DIS_TCNTI, upi42_op_JT0_imm, upi42_op_CPL_A, + /* 38 */ upi42_op_OUTL_Pp_A, upi42_op_OUTL_Pp_A, upi42_op_OUTL_Pp_A, upi42_op_OUTL_Pp_A, upi42_op_MOVD_Pp_A, upi42_op_MOVD_Pp_A, upi42_op_MOVD_Pp_A, upi42_op_MOVD_Pp_A, + /* 40 */ upi42_op_ORL_A_indRr, upi42_op_ORL_A_indRr, upi42_op_MOV_A_T, upi42_op_ORL_A_imm, upi42_op_JMP_imm, upi42_op_STRT_CNT, upi42_op_JNT1_imm, upi42_op_SWAP_A, + /* 48 */ upi42_op_ORL_A_Rr, upi42_op_ORL_A_Rr, upi42_op_ORL_A_Rr, upi42_op_ORL_A_Rr, upi42_op_ORL_A_Rr, upi42_op_ORL_A_Rr, upi42_op_ORL_A_Rr, upi42_op_ORL_A_Rr, + /* 50 */ upi42_op_ANL_A_indRr, upi42_op_ANL_A_indRr, upi42_op_JBb_imm, upi42_op_ANL_A_imm, upi42_op_CALL_imm, upi42_op_STRT_T, upi42_op_JT1_imm, upi42_op_DA_A, + /* 58 */ upi42_op_ANL_A_Rr, upi42_op_ANL_A_Rr, upi42_op_ANL_A_Rr, upi42_op_ANL_A_Rr, upi42_op_ANL_A_Rr, upi42_op_ANL_A_Rr, upi42_op_ANL_A_Rr, upi42_op_ANL_A_Rr, + /* 60 */ upi42_op_ADD_A_indRr, upi42_op_ADD_A_indRr, upi42_op_MOV_T_A, NULL, upi42_op_JMP_imm, upi42_op_STOP_TCNT, NULL, upi42_op_RRC_A, + /* 68 */ upi42_op_ADD_A_Rr, upi42_op_ADD_A_Rr, upi42_op_ADD_A_Rr, upi42_op_ADD_A_Rr, upi42_op_ADD_A_Rr, upi42_op_ADD_A_Rr, upi42_op_ADD_A_Rr, upi42_op_ADD_A_Rr, + /* 70 */ upi42_op_ADDC_A_indRr, upi42_op_ADDC_A_indRr, upi42_op_JBb_imm, NULL, upi42_op_CALL_imm, NULL, upi42_op_JF1_imm, upi42_op_RR_A, + /* 78 */ upi42_op_ADDC_A_Rr, upi42_op_ADDC_A_Rr, upi42_op_ADDC_A_Rr, upi42_op_ADDC_A_Rr, upi42_op_ADDC_A_Rr, upi42_op_ADDC_A_Rr, upi42_op_ADDC_A_Rr, upi42_op_ADDC_A_Rr, + /* 80 */ NULL, NULL, upi42_op_SUSPEND, upi42_op_RET, upi42_op_JMP_imm, upi42_op_CLR_F0, upi42_op_JOBF_imm, NULL, + /* 88 */ upi42_op_ORL_Pp_imm, upi42_op_ORL_Pp_imm, upi42_op_ORL_Pp_imm, upi42_op_ORL_Pp_imm, upi42_op_ORLD_Pp_A, upi42_op_ORLD_Pp_A, upi42_op_ORLD_Pp_A, upi42_op_ORLD_Pp_A, + /* 90 */ upi42_op_MOV_STS_A, NULL, upi42_op_JBb_imm, upi42_op_RET, upi42_op_CALL_imm, upi42_op_CPL_F0, upi42_op_JNZ_imm, upi42_op_CLR_C, + /* 98 */ upi42_op_ANL_Pp_imm, upi42_op_ANL_Pp_imm, upi42_op_ANL_Pp_imm, upi42_op_ANL_Pp_imm, upi42_op_ANLD_Pp_A, upi42_op_ANLD_Pp_A, upi42_op_ANLD_Pp_A, upi42_op_ANLD_Pp_A, + /* a0 */ upi42_op_MOV_indRr_A, upi42_op_MOV_indRr_A, NULL, upi42_op_MOVP_A_indA, upi42_op_JMP_imm, upi42_op_CLR_F1, NULL, upi42_op_CPL_C, + /* a8 */ upi42_op_MOV_Rr_A, upi42_op_MOV_Rr_A, upi42_op_MOV_Rr_A, upi42_op_MOV_Rr_A, upi42_op_MOV_Rr_A, upi42_op_MOV_Rr_A, upi42_op_MOV_Rr_A, upi42_op_MOV_Rr_A, + /* b0 */ upi42_op_MOV_indRr_imm,upi42_op_MOV_indRr_imm,upi42_op_JBb_imm, upi42_op_JMPP_indA, upi42_op_CALL_imm, upi42_op_CPL_F1, upi42_op_JF0_imm, NULL, + /* b8 */ upi42_op_MOV_Rr_imm, upi42_op_MOV_Rr_imm, upi42_op_MOV_Rr_imm, upi42_op_MOV_Rr_imm, upi42_op_MOV_Rr_imm, upi42_op_MOV_Rr_imm, upi42_op_MOV_Rr_imm, upi42_op_MOV_Rr_imm, + /* c0 */ NULL, NULL, NULL, NULL, upi42_op_JMP_imm, NULL, upi42_op_JZ_imm, upi42_op_MOV_A_PSW, + /* c8 */ upi42_op_DEC_Rr, upi42_op_DEC_Rr, upi42_op_DEC_Rr, upi42_op_DEC_Rr, upi42_op_DEC_Rr, upi42_op_DEC_Rr, upi42_op_DEC_Rr, upi42_op_DEC_Rr, + /* d0 */ upi42_op_XRL_A_indRr, upi42_op_XRL_A_indRr, upi42_op_JBb_imm, upi42_op_XRL_A_imm, upi42_op_CALL_imm, NULL, upi42_op_JNIBF_imm, upi42_op_MOV_PSW_A, + /* d8 */ upi42_op_XRL_A_Rr, upi42_op_XRL_A_Rr, upi42_op_XRL_A_Rr, upi42_op_XRL_A_Rr, upi42_op_XRL_A_Rr, upi42_op_XRL_A_Rr, upi42_op_XRL_A_Rr, upi42_op_XRL_A_Rr, + /* e0 */ NULL, NULL, upi42_op_SUSPEND, upi42_op_MOVP3_A_indA, upi42_op_JMP_imm, upi42_op_EN_DMA, upi42_op_JNC_imm, upi42_op_RL_A, + /* e8 */ upi42_op_DJNZ_Rr_imm, upi42_op_DJNZ_Rr_imm, upi42_op_DJNZ_Rr_imm, upi42_op_DJNZ_Rr_imm, upi42_op_DJNZ_Rr_imm, upi42_op_DJNZ_Rr_imm, upi42_op_DJNZ_Rr_imm, upi42_op_DJNZ_Rr_imm, + /* f0 */ upi42_op_MOV_A_indRr, upi42_op_MOV_A_indRr, upi42_op_JBb_imm, NULL, upi42_op_CALL_imm, upi42_op_EN_FLAGS, upi42_op_JC_imm, upi42_op_RLC_A, + /* f8 */ upi42_op_MOV_A_Rr, upi42_op_MOV_A_Rr, upi42_op_MOV_A_Rr, upi42_op_MOV_A_Rr, upi42_op_MOV_A_Rr, upi42_op_MOV_A_Rr, upi42_op_MOV_A_Rr, upi42_op_MOV_A_Rr + // clang-format on +}; + +static void +upi42_reset(upi42_t *upi42) +{ + upi42->pc = 0; /* program counter */ + upi42->psw = 0; /* stack pointer, register bank and F0 */ + upi42->dbf = 0; /* memory bank */ + upi42->i = upi42->tcnti = 0; /* both interrupts */ + upi42->tf = 0; /* timer flag */ + upi42->sts = 0; /* F1 */ + upi42->suspend = 0; /* 80C42 suspend flag */ +} + +static upi42_t * +upi42_init(int type) +{ + /* Allocate state structure. */ + upi42_t *upi42 = (upi42_t *) malloc(sizeof(upi42_t)); + memset(upi42, 0, sizeof(upi42_t)); + + /* Build instruction table. */ + memcpy(upi42->ops, ops_80c42, sizeof(ops_80c42)); + if (type < UPI42_80C42) { + /* Remove 80C42-only instructions. */ + upi42->ops[0x33] = NULL; /* EN A20 */ + upi42->ops[0x63] = NULL; /* SEL PMB0 */ + upi42->ops[0x73] = NULL; /* SEL PMB1 */ + upi42->ops[0x42] = NULL; /* SUSPEND */ + upi42->ops[0xe2] = NULL; /* SUSPEND */ + } + + return upi42; +} + +int +main(int argc, char **argv) +{ + upi42_t *upi42 = upi42_init(UPI42_8042); + + /* Load ROM. */ + FILE *f = fopen("1503033.bin", "rb"); + fread(upi42->rom, 1, sizeof(upi42->rom), f); + fclose(f); + + /* Start execution. */ + char buf[256]; + while (1) { + upi42->sts |= 0x02; + upi42->sts |= 0x08; + upi42->dbb_in = 0xaa; + upi42->cycs = 0; + + upi42_exec(upi42); + fgets(buf, 256, stdin); + } +}