This commit is contained in:
OBattler
2022-07-13 03:33:01 +02:00
15 changed files with 1152 additions and 111 deletions

View File

@@ -76,6 +76,7 @@ jobs:
${{ matrix.environment.prefix }}-zlib ${{ matrix.environment.prefix }}-zlib
${{ matrix.environment.prefix }}-libpng ${{ matrix.environment.prefix }}-libpng
${{ matrix.environment.prefix }}-libvncserver ${{ matrix.environment.prefix }}-libvncserver
${{ matrix.environment.prefix }}-openal
${{ matrix.environment.prefix }}-rtmidi ${{ matrix.environment.prefix }}-rtmidi
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Configure CMake - name: Configure CMake
@@ -230,7 +231,7 @@ jobs:
librtmidi-dev librtmidi-dev
qtbase5-dev qtbase5-dev
qttools5-dev qttools5-dev
libfaudio-dev libopenal-dev
- name: Configure CMake - name: Configure CMake
run: >- run: >-
cmake -G Ninja -S . -B build --preset ${{ matrix.build.preset }} cmake -G Ninja -S . -B build --preset ${{ matrix.build.preset }}
@@ -271,7 +272,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install dependencies - 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 - name: Configure CMake
run: >- run: >-
PATH=/usr/local/opt/qt@5/bin:$PATH PATH=/usr/local/opt/qt@5/bin:$PATH

View File

@@ -18,12 +18,8 @@ cmake_minimum_required(VERSION 3.16)
cmake_policy(SET CMP0091 NEW) cmake_policy(SET CMP0091 NEW)
cmake_policy(SET CMP0079 NEW) cmake_policy(SET CMP0079 NEW)
# if(HAIKU)
# set(OPENAL ON)
# set(RTMIDI OFF)
# endif()
set(OPENAL ON)
if(HAIKU) if(HAIKU)
set(OPENAL ON)
set(RTMIDI OFF) set(RTMIDI OFF)
endif() endif()
@@ -131,7 +127,7 @@ set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
# ------ ----------- ---- # ------ ----------- ----
option(RELEASE "Release build" OFF) option(RELEASE "Release build" OFF)
option(DYNAREC "Dynamic recompiler" ON) option(DYNAREC "Dynamic recompiler" ON)
option(OPENAL "OpenAL" OFF) option(OPENAL "OpenAL" ON)
option(RTMIDI "RtMidi" ON) option(RTMIDI "RtMidi" ON)
option(FLUIDSYNTH "FluidSynth" ON) option(FLUIDSYNTH "FluidSynth" ON)
option(MUNT "MUNT" ON) option(MUNT "MUNT" ON)

View File

@@ -96,6 +96,7 @@
#include <86box/thread.h> #include <86box/thread.h>
#include <86box/version.h> #include <86box/version.h>
#include <86box/gdbstub.h> #include <86box/gdbstub.h>
#include <86box/machine_status.h>
// Disable c99-designator to avoid the warnings about int ng // Disable c99-designator to avoid the warnings about int ng
#ifdef __clang__ #ifdef __clang__
@@ -891,6 +892,8 @@ pc_init_modules(void)
video_reset_close(); video_reset_close();
machine_status_init();
return(1); return(1);
} }

View File

@@ -17,7 +17,7 @@
add_executable(86Box 86box.c config.c log.c random.c timer.c io.c acpi.c apm.c 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 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") if(CMAKE_SYSTEM_NAME MATCHES "Linux")
add_compile_definitions(_FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE=1 _LARGEFILE64_SOURCE=1) add_compile_definitions(_FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE=1 _LARGEFILE64_SOURCE=1)

View File

@@ -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- disabled, the Read Multiple operation is rejected with an Aborted Com-
mand error. */ mand error. */
ide->blockcount = 0; 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*/ /*FALLTHROUGH*/
case WIN_READ: case WIN_READ:
@@ -1658,6 +1655,7 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
ide->atastat = BSY_STAT; ide->atastat = BSY_STAT;
if (ide->type == IDE_HDD) { if (ide->type == IDE_HDD) {
ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1);
uint32_t sec_count; uint32_t sec_count;
double wait_time; double wait_time;
if ((val == WIN_READ_DMA) || (val == WIN_READ_DMA_ALT)) { 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); double xfer_time = ide_get_xfer_time(ide, 512);
ide_set_callback(ide, seek_time + xfer_time); 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); ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0);
} }
} }

View File

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

View File

@@ -70,10 +70,12 @@ extern int strnicmp(const char* s1, const char* s2, size_t n);
#ifdef __cplusplus #ifdef __cplusplus
#include <atomic> #include <atomic>
#define atomic_flag_t std::atomic_flag #define atomic_flag_t std::atomic_flag
#define atomic_bool_t std::atomic_bool
extern "C" { extern "C" {
#else #else
#include <stdatomic.h> #include <stdatomic.h>
#define atomic_flag_t atomic_flag #define atomic_flag_t atomic_flag
#define atomic_bool_t atomic_bool
#endif #endif
/* Global variables residing in the platform module. */ /* Global variables residing in the platform module. */

View File

@@ -70,8 +70,8 @@ extern void ui_sb_update_panes(void);
extern void ui_sb_update_text(void); extern void ui_sb_update_text(void);
extern void ui_sb_update_tip(int meaning); extern void ui_sb_update_tip(int meaning);
extern void ui_sb_timer_callback(int pane); extern void ui_sb_timer_callback(int pane);
extern void ui_sb_update_icon(int tag, int val); extern void ui_sb_update_icon(int tag, int active);
extern void ui_sb_update_icon_state(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_w(wchar_t *wstr);
extern void ui_sb_set_text(char *str); extern void ui_sb_set_text(char *str);
extern void ui_sb_bugui(char *str); extern void ui_sb_bugui(char *str);

52
src/machine_status.c Normal file
View File

@@ -0,0 +1,52 @@
#include <inttypes.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#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;
}

View File

@@ -39,6 +39,7 @@ extern uint64_t tsc;
#include <86box/machine.h> #include <86box/machine.h>
#include <86box/network.h> #include <86box/network.h>
#include <86box/ui.h> #include <86box/ui.h>
#include <86box/machine_status.h>
}; };
#include <QIcon> #include <QIcon>
@@ -92,17 +93,21 @@ namespace {
struct StateActive { struct StateActive {
std::unique_ptr<QLabel> label; std::unique_ptr<QLabel> label;
QTimer timer;
PixmapSetActive* pixmaps = nullptr; PixmapSetActive* pixmaps = nullptr;
bool active = false; bool active = false;
void setActive(bool b) { void setActive(bool b) {
active = b; if (!label || b == active)
if (! label) { return;
active = b;
refresh();
}
void refresh() {
if (!label)
return; return;
}
label->setPixmap(active ? pixmaps->active : pixmaps->normal); label->setPixmap(active ? pixmaps->active : pixmaps->normal);
timer.start(75);
} }
}; };
struct StateEmpty { struct StateEmpty {
@@ -111,33 +116,42 @@ namespace {
bool empty = false; bool empty = false;
void setEmpty(bool e) { void setEmpty(bool e) {
empty = e; if (!label || e == empty)
if (! label) { return;
empty = e;
refresh();
}
void refresh() {
if (!label)
return; return;
}
label->setPixmap(empty ? pixmaps->empty : pixmaps->normal); label->setPixmap(empty ? pixmaps->empty : pixmaps->normal);
} }
}; };
struct StateEmptyActive { struct StateEmptyActive {
std::unique_ptr<QLabel> label; std::unique_ptr<QLabel> label;
QTimer timer;
PixmapSetEmptyActive* pixmaps = nullptr; PixmapSetEmptyActive* pixmaps = nullptr;
bool empty = false; bool empty = false;
bool active = false; bool active = false;
void setActive(bool b) { void setActive(bool b) {
if (!label || b == active)
return;
active = b; active = b;
refresh(); refresh();
timer.start(75);
} }
void setEmpty(bool b) { void setEmpty(bool b) {
if (!label || b == empty)
return;
empty = b; empty = b;
refresh(); refresh();
} }
void refresh() { void refresh() {
if (! label) { if (!label)
return; return;
}
if (empty) { if (empty) {
label->setPixmap(active ? pixmaps->empty_active : pixmaps->empty); label->setPixmap(active ? pixmaps->empty_active : pixmaps->empty);
} else { } else {
@@ -190,26 +204,20 @@ struct MachineStatus::States {
cartridge[0].pixmaps = &pixmaps.cartridge; cartridge[0].pixmaps = &pixmaps.cartridge;
cartridge[1].pixmaps = &pixmaps.cartridge; cartridge[1].pixmaps = &pixmaps.cartridge;
cassette.pixmaps = &pixmaps.cassette; cassette.pixmaps = &pixmaps.cassette;
QObject::connect(&cassette.timer, &QTimer::timeout, parent, [&]{ cassette.setActive(false); });
for (auto& f : fdd) { for (auto& f : fdd) {
f.pixmaps = &pixmaps.floppy_disabled; f.pixmaps = &pixmaps.floppy_disabled;
QObject::connect(&f.timer, &QTimer::timeout, parent, [&]{ f.setActive(false); });
} }
for (auto& c : cdrom) { for (auto& c : cdrom) {
c.pixmaps = &pixmaps.cdrom; c.pixmaps = &pixmaps.cdrom;
QObject::connect(&c.timer, &QTimer::timeout, parent, [&]{ c.setActive(false); });
} }
for (auto& z : zip) { for (auto& z : zip) {
z.pixmaps = &pixmaps.zip; z.pixmaps = &pixmaps.zip;
QObject::connect(&z.timer, &QTimer::timeout, parent, [&]{ z.setActive(false); });
} }
for (auto& m : mo) { for (auto& m : mo) {
m.pixmaps = &pixmaps.mo; m.pixmaps = &pixmaps.mo;
QObject::connect(&m.timer, &QTimer::timeout, parent, [&]{ m.setActive(false); });
} }
for (auto& h : hdds) { for (auto& h : hdds) {
h.pixmaps = &pixmaps.hd; h.pixmaps = &pixmaps.hd;
QObject::connect(&h.timer, &QTimer::timeout, parent, [&]{ h.setActive(false); });
} }
net.pixmaps = &pixmaps.net; net.pixmaps = &pixmaps.net;
} }
@@ -227,9 +235,12 @@ struct MachineStatus::States {
}; };
MachineStatus::MachineStatus(QObject *parent) : MachineStatus::MachineStatus(QObject *parent) :
QObject(parent) QObject(parent),
refreshTimer(new QTimer(this))
{ {
d = std::make_unique<MachineStatus::States>(this); d = std::make_unique<MachineStatus::States>(this);
connect(refreshTimer, &QTimer::timeout, this, &MachineStatus::refreshIcons);
refreshTimer->start(75);
} }
MachineStatus::~MachineStatus() = default; MachineStatus::~MachineStatus() = default;
@@ -321,6 +332,38 @@ static int hdd_count(int bus) {
return(c); 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) { void MachineStatus::refresh(QStatusBar* sbar) {
bool has_mfm = machine_has_flags(machine, MACHINE_MFM) > 0; bool has_mfm = machine_has_flags(machine, MACHINE_MFM) > 0;
bool has_xta = machine_has_flags(machine, MACHINE_XTA) > 0; bool has_xta = machine_has_flags(machine, MACHINE_XTA) > 0;
@@ -358,6 +401,7 @@ void MachineStatus::refresh(QStatusBar* sbar) {
if (cassette_enable) { if (cassette_enable) {
d->cassette.label = std::make_unique<ClickableLabel>(); d->cassette.label = std::make_unique<ClickableLabel>();
d->cassette.setEmpty(QString(cassette_fname).isEmpty()); d->cassette.setEmpty(QString(cassette_fname).isEmpty());
d->cassette.refresh();
connect((ClickableLabel*)d->cassette.label.get(), &ClickableLabel::clicked, [](QPoint pos) { connect((ClickableLabel*)d->cassette.label.get(), &ClickableLabel::clicked, [](QPoint pos) {
MediaMenu::ptr->cassetteMenu->popup(pos - QPoint(0, MediaMenu::ptr->cassetteMenu->sizeHint().height())); 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) { for (int i = 0; i < 2; ++i) {
d->cartridge[i].label = std::make_unique<ClickableLabel>(); d->cartridge[i].label = std::make_unique<ClickableLabel>();
d->cartridge[i].setEmpty(QString(cart_fns[i]).isEmpty()); 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) { 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())); 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<ClickableLabel>(); d->fdd[i].label = std::make_unique<ClickableLabel>();
d->fdd[i].setEmpty(QString(floppyfns[i]).isEmpty()); d->fdd[i].setEmpty(QString(floppyfns[i]).isEmpty());
d->fdd[i].setActive(false); d->fdd[i].setActive(false);
d->fdd[i].refresh();
connect((ClickableLabel*)d->fdd[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) { 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())); 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<ClickableLabel>(); d->cdrom[i].label = std::make_unique<ClickableLabel>();
d->cdrom[i].setEmpty(cdrom[i].host_drive != 200 || QString(cdrom[i].image_path).isEmpty()); d->cdrom[i].setEmpty(cdrom[i].host_drive != 200 || QString(cdrom[i].image_path).isEmpty());
d->cdrom[i].setActive(false); d->cdrom[i].setActive(false);
d->cdrom[i].refresh();
connect((ClickableLabel*)d->cdrom[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) { 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())); 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<ClickableLabel>(); d->zip[i].label = std::make_unique<ClickableLabel>();
d->zip[i].setEmpty(QString(zip_drives[i].image_path).isEmpty()); d->zip[i].setEmpty(QString(zip_drives[i].image_path).isEmpty());
d->zip[i].setActive(false); d->zip[i].setActive(false);
d->zip[i].refresh();
connect((ClickableLabel*)d->zip[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) { 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())); 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<ClickableLabel>(); d->mo[i].label = std::make_unique<ClickableLabel>();
d->mo[i].setEmpty(QString(mo_drives[i].image_path).isEmpty()); d->mo[i].setEmpty(QString(mo_drives[i].image_path).isEmpty());
d->mo[i].setActive(false); d->mo[i].setActive(false);
d->mo[i].refresh();
connect((ClickableLabel*)d->mo[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) { 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())); 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) { if ((has_mfm || hdc_name.left(5) == QStringLiteral("st506")) && c_mfm > 0) {
d->hdds[HDD_BUS_MFM].label = std::make_unique<QLabel>(); d->hdds[HDD_BUS_MFM].label = std::make_unique<QLabel>();
d->hdds[HDD_BUS_MFM].setActive(false); 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")); d->hdds[HDD_BUS_MFM].label->setToolTip(tr("Hard disk (%s)").replace("%s", "MFM/RLL"));
sbar->addWidget(d->hdds[HDD_BUS_MFM].label.get()); sbar->addWidget(d->hdds[HDD_BUS_MFM].label.get());
} }
if ((has_esdi || hdc_name.left(4) == QStringLiteral("esdi")) && c_esdi > 0) { if ((has_esdi || hdc_name.left(4) == QStringLiteral("esdi")) && c_esdi > 0) {
d->hdds[HDD_BUS_ESDI].label = std::make_unique<QLabel>(); d->hdds[HDD_BUS_ESDI].label = std::make_unique<QLabel>();
d->hdds[HDD_BUS_ESDI].setActive(false); 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")); d->hdds[HDD_BUS_ESDI].label->setToolTip(tr("Hard disk (%s)").replace("%s", "ESDI"));
sbar->addWidget(d->hdds[HDD_BUS_ESDI].label.get()); sbar->addWidget(d->hdds[HDD_BUS_ESDI].label.get());
} }
if ((has_xta || hdc_name.left(3) == QStringLiteral("xta")) && c_xta > 0) { if ((has_xta || hdc_name.left(3) == QStringLiteral("xta")) && c_xta > 0) {
d->hdds[HDD_BUS_XTA].label = std::make_unique<QLabel>(); d->hdds[HDD_BUS_XTA].label = std::make_unique<QLabel>();
d->hdds[HDD_BUS_XTA].setActive(false); 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")); d->hdds[HDD_BUS_XTA].label->setToolTip(tr("Hard disk (%s)").replace("%s", "XTA"));
sbar->addWidget(d->hdds[HDD_BUS_XTA].label.get()); 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) { 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<QLabel>(); d->hdds[HDD_BUS_IDE].label = std::make_unique<QLabel>();
d->hdds[HDD_BUS_IDE].setActive(false); 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")); d->hdds[HDD_BUS_IDE].label->setToolTip(tr("Hard disk (%s)").replace("%s", "IDE"));
sbar->addWidget(d->hdds[HDD_BUS_IDE].label.get()); 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) { (scsi_card_current[2] != 0) || (scsi_card_current[3] != 0)) && c_scsi > 0) {
d->hdds[HDD_BUS_SCSI].label = std::make_unique<QLabel>(); d->hdds[HDD_BUS_SCSI].label = std::make_unique<QLabel>();
d->hdds[HDD_BUS_SCSI].setActive(false); 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")); d->hdds[HDD_BUS_SCSI].label->setToolTip(tr("Hard disk (%s)").replace("%s", "SCSI"));
sbar->addWidget(d->hdds[HDD_BUS_SCSI].label.get()); sbar->addWidget(d->hdds[HDD_BUS_SCSI].label.get());
} }
@@ -489,6 +543,7 @@ void MachineStatus::refresh(QStatusBar* sbar) {
if (do_net) { if (do_net) {
d->net.label = std::make_unique<QLabel>(); d->net.label = std::make_unique<QLabel>();
d->net.setActive(false); d->net.setActive(false);
d->net.refresh();
d->net.label->setToolTip(tr("Network")); d->net.label->setToolTip(tr("Network"));
sbar->addWidget(d->net.label.get()); sbar->addWidget(d->net.label.get());
} }
@@ -505,72 +560,6 @@ void MachineStatus::refresh(QStatusBar* sbar) {
sbar->addWidget(d->text.get()); 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) { void MachineStatus::message(const QString &msg) {
d->text->setText(msg); d->text->setText(msg);
} }

View File

@@ -70,14 +70,14 @@ public:
QString getMessage(); QString getMessage();
public slots: public slots:
void refresh(QStatusBar* sbar); void refresh(QStatusBar* sbar);
void setActivity(int tag, bool active);
void setEmpty(int tag, bool active);
void message(const QString& msg); void message(const QString& msg);
void updateTip(int tag); void updateTip(int tag);
void refreshIcons();
private: private:
struct States; struct States;
std::unique_ptr<States> d; std::unique_ptr<States> d;
QTimer *refreshTimer;
}; };
#endif // QT_MACHINESTATUS_HPP #endif // QT_MACHINESTATUS_HPP

View File

@@ -268,8 +268,6 @@ MainWindow::MainWindow(QWidget *parent) :
}); });
connect(this, &MainWindow::updateStatusBarPanes, this, &MainWindow::refreshMediaMenu); connect(this, &MainWindow::updateStatusBarPanes, this, &MainWindow::refreshMediaMenu);
connect(this, &MainWindow::updateStatusBarTip, status.get(), &MachineStatus::updateTip); 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); connect(this, &MainWindow::statusBarMessage, status.get(), &MachineStatus::message, Qt::QueuedConnection);
ui->actionKeyboard_requires_capture->setChecked(kbd_req_capture); ui->actionKeyboard_requires_capture->setChecked(kbd_req_capture);

View File

@@ -132,8 +132,6 @@ void ProgSettings::accept()
main_window->refreshMediaMenu(); main_window->refreshMediaMenu();
main_window->status->message(msg); main_window->status->message(msg);
connect(main_window, &MainWindow::updateStatusBarTip, main_window->status.get(), &MachineStatus::updateTip); 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); connect(main_window, &MainWindow::statusBarMessage, main_window->status.get(), &MachineStatus::message, Qt::QueuedConnection);
mouse_sensitivity = mouseSensitivity; mouse_sensitivity = mouseSensitivity;
QDialog::accept(); QDialog::accept();

View File

@@ -25,6 +25,7 @@
#include <QStatusBar> #include <QStatusBar>
#include "qt_mainwindow.hpp" #include "qt_mainwindow.hpp"
#include "qt_machinestatus.hpp"
MainWindow* main_window = nullptr; MainWindow* main_window = nullptr;
@@ -36,6 +37,20 @@ extern "C" {
#include <86box/plat.h> #include <86box/plat.h>
#include <86box/ui.h> #include <86box/ui.h>
#include <86box/mouse.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 void
plat_delay_ms(uint32_t count) plat_delay_ms(uint32_t count)
@@ -174,16 +189,70 @@ void ui_sb_set_ready(int ready) {
void void
ui_sb_update_icon_state(int tag, int state) { ui_sb_update_icon_state(int tag, int state) {
if (main_window == nullptr) { int category = tag & 0xfffffff0;
return; 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 void
ui_sb_update_icon(int tag, int active) { ui_sb_update_icon(int tag, int active) {
if (!update_icons) return; int category = tag & 0xfffffff0;
main_window->updateStatusBarActivity(tag, active > 0 ? true : false); 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;
}
} }
} }

903
src/upi42.c Normal file
View File

@@ -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, <richardg867@gmail.com>
*
* Copyright 2022 RichardG.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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);
}
}