diff --git a/README.md b/README.md index 926c6db..6efb1ad 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Oregon Scientific Osaris (EPOC R4) features: - ✅ LCD: implemented - ✅ Keyboard: mostly implemented (key mappings wrong) -- ❌ Touch panel: not implemented +- ✅ Touch panel: implemented - ❌ Audio: not implemented - ❌ Serial/UART support: stubbed out - ❌ PCMCIA: mostly stubbed out diff --git a/WindCore/clps7111.cpp b/WindCore/clps7111.cpp index 487d1b5..c764e9d 100644 --- a/WindCore/clps7111.cpp +++ b/WindCore/clps7111.cpp @@ -49,6 +49,7 @@ uint32_t Emulator::readReg32(uint32_t reg) { return flg; } else if (reg == SYSFLG1) { uint32_t flg = sysFlg1; + flg |= 2; // external power present flg |= (rtcDiv << 16); // maybe set more stuff? return flg; @@ -64,6 +65,21 @@ uint32_t Emulator::readReg32(uint32_t reg) { return tc2.value; } else if (reg == RTCDR) { return rtc; + } else if (reg == SYNCIO) { + switch (lastSyncioRequest & 0xFF) { + case 0xC1: // DigitiserX + return (touchX * 8) + 305; + case 0x81: // DigitiserY + return (touchY * 13.53) + 680; + case 0x91: // MainBattery + return 3000; + case 0xD1: // BackupBattery + return 3100; + case 0xA1: // Reference + return 1000; + } + log("SYNCIO read unknown:: req=%08x", lastSyncioRequest); + return 0xFFFFFFFF; } else if (reg == PALLSW) { return lcdPalette & 0xFFFFFFFF; } else if (reg == PALMSW) { @@ -149,6 +165,8 @@ void Emulator::writeReg32(uint32_t reg, uint32_t value) { tc2.load(value); } else if (reg == RTCDR) { rtc = value; + } else if (reg == SYNCIO) { + lastSyncioRequest = value & 0xFFFF; } else if (reg == PALLSW) { lcdPalette &= 0xFFFFFFFF00000000; lcdPalette |= value; @@ -337,7 +355,7 @@ const char *Emulator::identifyObjectCon(uint32_t ptr) { if (ptr == readVirtualDebug(0x800008AC, V32).value()) return "library"; // if (ptr == readVirtualDebug(0x800008B0, V32).value()) return "unk8B0"; // name always null // if (ptr == readVirtualDebug(0x800008B4, V32).value()) return "unk8B4"; // name always null - return "???"; + return nullptr; } void Emulator::fetchStr(uint32_t str, char *buf) { @@ -405,15 +423,46 @@ void Emulator::debugPC(uint32_t pc) { log("DPlatChunkHw MAPPING: v:%08x p:%08x size:%08x arg:%08x", virtAddr, physAddr, regionSize, a); } + + if (pc == 0x16198) { + uint32_t rawEvent = getGPR(0); + uint32_t evtType = readVirtualDebug(rawEvent, V32).value_or(0); + uint32_t evtTick = readVirtualDebug(rawEvent + 4, V32).value_or(0); + uint32_t evtParamA = readVirtualDebug(rawEvent + 8, V32).value_or(0); + uint32_t evtParamB = readVirtualDebug(rawEvent + 0xC, V32).value_or(0); + const char *n = "???"; + switch (evtType) { + case 0: n = "ENone"; break; + case 1: n = "EPointerMove"; break; + case 2: n = "EPointerSwitchOn"; break; + case 3: n = "EKeyDown"; break; + case 4: n = "EKeyUp"; break; + case 5: n = "ERedraw"; break; + case 6: n = "ESwitchOn"; break; + case 7: n = "EActive"; break; + case 8: n = "EInactive"; break; + case 9: n = "EUpdateModifiers"; break; + case 10: n = "EButton1Down"; break; + case 11: n = "EButton1Up"; break; + case 12: n = "EButton2Down"; break; + case 13: n = "EButton2Up"; break; + case 14: n = "EButton3Down"; break; + case 15: n = "EButton3Up"; break; + case 16: n = "ESwitchOff"; break; + } + log("EVENT %s: tick=%d params=%08x,%08x", n, evtTick, evtParamA, evtParamB); + } } -int Emulator::getLCDWidth() const { - return 320; -} -int Emulator::getLCDHeight() const { - return 200; -} +const char *Emulator::getDeviceName() const { return "Osaris"; } +int Emulator::getDigitiserWidth() const { return 440; } +int Emulator::getDigitiserHeight() const { return 200; } +int Emulator::getLCDOffsetX() const { return 60; } +int Emulator::getLCDOffsetY() const { return 0; } +int Emulator::getLCDWidth() const { return 320; } +int Emulator::getLCDHeight() const { return 200; } + void Emulator::readLCDIntoBuffer(uint8_t **lines) const { if (lcdAddress == 0xC0000000) { int width = 320, height = 200; @@ -568,4 +617,14 @@ void Emulator::setKeyboardKey(EpocKey key, bool value) { } } + +void Emulator::updateTouchInput(int32_t x, int32_t y, bool down) { + pendingInterrupts &= ~(1 << EINT2); + if (down) + pendingInterrupts |= (1 << EINT2); + log("Touch: x=%d y=%d down=%s", x, y, down ? "yes" : "no"); + touchX = x; + touchY = y; +} + } diff --git a/WindCore/clps7111.h b/WindCore/clps7111.h index 9068062..f494525 100644 --- a/WindCore/clps7111.h +++ b/WindCore/clps7111.h @@ -24,10 +24,12 @@ private: uint32_t rtc = 0; uint32_t rtcDiv = 0; uint64_t lcdPalette = 0; + uint16_t lastSyncioRequest = 0; uint32_t kScan = 0; uint8_t keyboardColumns[7] = {0,0,0,0,0,0,0}; uint8_t keyboardExtra = 0; + int32_t touchX = 0, touchY = 0; Timer tc1, tc2; CLPS7600 pcCardController; @@ -62,9 +64,15 @@ public: void loadROM(uint8_t *buffer, size_t size) override; void executeUntil(int64_t cycles) override; int32_t getClockSpeed() const override { return CLOCK_SPEED; } + const char *getDeviceName() const override; + int getDigitiserWidth() const override; + int getDigitiserHeight() const override; + int getLCDOffsetX() const override; + int getLCDOffsetY() const override; int getLCDWidth() const override; int getLCDHeight() const override; void readLCDIntoBuffer(uint8_t **lines) const override; void setKeyboardKey(EpocKey key, bool value) override; + void updateTouchInput(int32_t x, int32_t y, bool down) override; }; } diff --git a/WindCore/emubase.h b/WindCore/emubase.h index a1653f0..0fbf70f 100644 --- a/WindCore/emubase.h +++ b/WindCore/emubase.h @@ -114,10 +114,16 @@ public: virtual void loadROM(uint8_t *buffer, size_t size) = 0; virtual void executeUntil(int64_t cycles) = 0; virtual int32_t getClockSpeed() const = 0; + virtual const char *getDeviceName() const = 0; + virtual int getDigitiserWidth() const = 0; + virtual int getDigitiserHeight() const = 0; + virtual int getLCDOffsetX() const = 0; + virtual int getLCDOffsetY() const = 0; virtual int getLCDWidth() const = 0; virtual int getLCDHeight() const = 0; virtual void readLCDIntoBuffer(uint8_t **lines) const = 0; virtual void setKeyboardKey(EpocKey key, bool value) = 0; + virtual void updateTouchInput(int32_t x, int32_t y, bool down) = 0; std::unordered_set &breakpoints() { return _breakpoints; } uint64_t currentCycles() const { return passedCycles; } diff --git a/WindCore/windermere.cpp b/WindCore/windermere.cpp index f781058..a6623be 100644 --- a/WindCore/windermere.cpp +++ b/WindCore/windermere.cpp @@ -478,12 +478,14 @@ void Emulator::debugPC(uint32_t pc) { } -int Emulator::getLCDWidth() const { - return 640; -} -int Emulator::getLCDHeight() const { - return 240; -} +const char *Emulator::getDeviceName() const { return "Series 5mx"; } +int Emulator::getDigitiserWidth() const { return 695; } +int Emulator::getDigitiserHeight() const { return 280; } +int Emulator::getLCDOffsetX() const { return 45; } +int Emulator::getLCDOffsetY() const { return 5; } +int Emulator::getLCDWidth() const { return 640; } +int Emulator::getLCDHeight() const { return 240; } + void Emulator::readLCDIntoBuffer(uint8_t **lines) const { if ((lcdAddress >> 24) == 0xC0) { const uint8_t *lcdBuf = &MemoryBlockC0[lcdAddress & MemoryBlockMask]; @@ -657,4 +659,7 @@ void Emulator::setKeyboardKey(EpocKey key, bool value) { } } +void Emulator::updateTouchInput(int32_t x, int32_t y, bool down) { +} + } diff --git a/WindCore/windermere.h b/WindCore/windermere.h index 469a929..36a3359 100644 --- a/WindCore/windermere.h +++ b/WindCore/windermere.h @@ -62,9 +62,15 @@ public: void loadROM(uint8_t *buffer, size_t size) override; void executeUntil(int64_t cycles) override; int32_t getClockSpeed() const override { return CLOCK_SPEED; } + const char *getDeviceName() const override; + int getDigitiserWidth() const override; + int getDigitiserHeight() const override; + int getLCDOffsetX() const override; + int getLCDOffsetY() const override; int getLCDWidth() const override; int getLCDHeight() const override; void readLCDIntoBuffer(uint8_t **lines) const override; void setKeyboardKey(EpocKey key, bool value) override; + void updateTouchInput(int32_t x, int32_t y, bool down) override; }; } diff --git a/WindQt/WindQt.pro b/WindQt/WindQt.pro index aae565c..9bab131 100644 --- a/WindQt/WindQt.pro +++ b/WindQt/WindQt.pro @@ -25,10 +25,12 @@ QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.14 SOURCES += \ main.cpp \ - mainwindow.cpp + mainwindow.cpp \ + pdascreenwindow.cpp HEADERS += \ - mainwindow.h + mainwindow.h \ + pdascreenwindow.h FORMS += \ mainwindow.ui diff --git a/WindQt/main.cpp b/WindQt/main.cpp index b0012bc..3d9b87d 100644 --- a/WindQt/main.cpp +++ b/WindQt/main.cpp @@ -12,7 +12,7 @@ int main(int argc, char *argv[]) QString romFile; if (args.length() > 1) - romFile = args.first(); + romFile = args.last(); else romFile = QFileDialog::getOpenFileName(nullptr, "Select a ROM"); if (romFile.isNull()) return 0; diff --git a/WindQt/mainwindow.cpp b/WindQt/mainwindow.cpp index e1883d9..ef610d9 100644 --- a/WindQt/mainwindow.cpp +++ b/WindQt/mainwindow.cpp @@ -1,12 +1,13 @@ #include "mainwindow.h" #include "ui_mainwindow.h" #include -#include #include "../WindCore/decoder.h" +#include "clps7111.h" MainWindow::MainWindow(EmuBase *emu, QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), + pdaScreen(emu), emu(emu) { ui->setupUi(this); @@ -20,6 +21,8 @@ MainWindow::MainWindow(EmuBase *emu, QWidget *parent) : timer->setInterval(1000/64); connect(timer, SIGNAL(timeout()), SLOT(execTimer())); + pdaScreen.show(); + updateScreen(); } @@ -100,67 +103,10 @@ void MainWindow::updateScreen() ui->codeLabel->setText(codeLines.join('\n')); // now, the actual screen - uint8_t *lines[1024]; - QImage img(emu->getLCDWidth(), emu->getLCDHeight(), QImage::Format_Grayscale8); - for (int y = 0; y < img.height(); y++) - lines[y] = img.scanLine(y); - emu->readLCDIntoBuffer(lines); - - ui->screen->setPixmap(QPixmap::fromImage(std::move(img))); + pdaScreen.updateScreen(); } -static EpocKey resolveKey(int key) { - switch (key) { - case Qt::Key_Apostrophe: return EStdKeySingleQuote; - case Qt::Key_Backspace: return EStdKeyBackspace; - case Qt::Key_Escape: return EStdKeyEscape; - case Qt::Key_Enter: return EStdKeyEnter; - case Qt::Key_Return: return EStdKeyEnter; - case Qt::Key_Alt: return EStdKeyMenu; - case Qt::Key_Tab: return EStdKeyTab; -#ifdef Q_OS_MAC - case Qt::Key_Meta: return EStdKeyLeftCtrl; -#else - case Qt::Key_Control: return EStdKeyLeftCtrl; -#endif - case Qt::Key_Down: return EStdKeyDownArrow; - case Qt::Key_Period: return EStdKeyFullStop; -#ifdef Q_OS_MAC - case Qt::Key_Control: return EStdKeyLeftFunc; -#else - case Qt::Key_Meta: return EStdKeyLeftFunc; -#endif - case Qt::Key_Shift: return EStdKeyLeftShift; - case Qt::Key_Right: return EStdKeyRightArrow; - case Qt::Key_Left: return EStdKeyLeftArrow; - case Qt::Key_Comma: return EStdKeyComma; - case Qt::Key_Up: return EStdKeyUpArrow; - case Qt::Key_Space: return EStdKeySpace; - } - - if (key >= '0' && key <= '9') return (EpocKey)key; - if (key >= 'A' && key <= 'Z') return (EpocKey)key; - return EStdKeyNull; -} - - -void MainWindow::keyPressEvent(QKeyEvent *event) -{ - EpocKey k = resolveKey(event->key()); - if (k != EStdKeyNull) - emu->setKeyboardKey(k, true); -} - -void MainWindow::keyReleaseEvent(QKeyEvent *event) -{ - EpocKey k = resolveKey(event->key()); - if (k != EStdKeyNull) - emu->setKeyboardKey(k, false); -} - - - void MainWindow::on_startButton_clicked() { diff --git a/WindQt/mainwindow.h b/WindQt/mainwindow.h index 781caad..5c11efb 100644 --- a/WindQt/mainwindow.h +++ b/WindQt/mainwindow.h @@ -3,6 +3,7 @@ #include #include "../WindCore/emubase.h" +#include "pdascreenwindow.h" namespace Ui { class MainWindow; @@ -44,16 +45,13 @@ private slots: private: Ui::MainWindow *ui; + PDAScreenWindow pdaScreen; EmuBase *emu; QTimer *timer; void updateScreen(); void updateBreakpointsList(); void updateMemory(); void adjustMemoryAddress(int offset); - -protected: - void keyPressEvent(QKeyEvent *event) override; - void keyReleaseEvent(QKeyEvent *event) override; }; #endif // MAINWINDOW_H diff --git a/WindQt/mainwindow.ui b/WindQt/mainwindow.ui index c2250b6..d176e06 100644 --- a/WindQt/mainwindow.ui +++ b/WindQt/mainwindow.ui @@ -25,7 +25,7 @@ - 0 + 2 diff --git a/WindQt/pdascreenwindow.cpp b/WindQt/pdascreenwindow.cpp new file mode 100644 index 0000000..8cea790 --- /dev/null +++ b/WindQt/pdascreenwindow.cpp @@ -0,0 +1,107 @@ +#include "pdascreenwindow.h" +#include + +PDAScreenWindow::PDAScreenWindow(EmuBase *emu, QWidget *parent) : + QWidget(parent), + emu(emu), + lcd(new QLabel(this)) +{ + setWindowTitle("WindEmu"); + setFixedSize(emu->getDigitiserWidth(), emu->getDigitiserHeight()); + lcd->setGeometry(emu->getLCDOffsetX(), emu->getLCDOffsetY(), emu->getLCDWidth(), emu->getLCDHeight()); + + const char *who = emu->getDeviceName(); + if (strcmp(who, "Osaris") == 0) { + // some cheap and cheerful placeholders + int bitW = (emu->getDigitiserWidth() - emu->getLCDWidth()) / 2; + int bitH = emu->getDigitiserHeight() / 5; + int leftX = 0; + int rightX = bitW + emu->getLCDWidth(); + (new QLabel("Word", this))->setGeometry(leftX, bitH * 0, bitW, bitH); + (new QLabel("Sheet", this))->setGeometry(leftX, bitH * 1, bitW, bitH); + (new QLabel("Data", this))->setGeometry(leftX, bitH * 2, bitW, bitH); + (new QLabel("Agenda", this))->setGeometry(leftX, bitH * 3, bitW, bitH); + (new QLabel("Extras", this))->setGeometry(leftX, bitH * 4, bitW, bitH); + (new QLabel("EPOC", this))->setGeometry(rightX, bitH * 0, bitW, bitH); + (new QLabel("Menu", this))->setGeometry(rightX, bitH * 1, bitW, bitH); + (new QLabel("Copy/Paste", this))->setGeometry(rightX, bitH * 2, bitW, bitH); + (new QLabel("Zoom In", this))->setGeometry(rightX, bitH * 3, bitW, bitH); + (new QLabel("Zoom Out", this))->setGeometry(rightX, bitH * 4, bitW, bitH); + } +} + +void PDAScreenWindow::updateScreen() { + uint8_t *lines[1024]; + QImage img(emu->getLCDWidth(), emu->getLCDHeight(), QImage::Format_Grayscale8); + for (int y = 0; y < img.height(); y++) + lines[y] = img.scanLine(y); + emu->readLCDIntoBuffer(lines); + + lcd->setPixmap(QPixmap::fromImage(std::move(img))); +} + +static EpocKey resolveKey(int key) { + switch (key) { + case Qt::Key_Apostrophe: return EStdKeySingleQuote; + case Qt::Key_Backspace: return EStdKeyBackspace; + case Qt::Key_Escape: return EStdKeyEscape; + case Qt::Key_Enter: return EStdKeyEnter; + case Qt::Key_Return: return EStdKeyEnter; + case Qt::Key_Alt: return EStdKeyMenu; + case Qt::Key_Tab: return EStdKeyTab; +#ifdef Q_OS_MAC + case Qt::Key_Meta: return EStdKeyLeftCtrl; +#else + case Qt::Key_Control: return EStdKeyLeftCtrl; +#endif + case Qt::Key_Down: return EStdKeyDownArrow; + case Qt::Key_Period: return EStdKeyFullStop; +#ifdef Q_OS_MAC + case Qt::Key_Control: return EStdKeyLeftFunc; +#else + case Qt::Key_Meta: return EStdKeyLeftFunc; +#endif + case Qt::Key_Shift: return EStdKeyLeftShift; + case Qt::Key_Right: return EStdKeyRightArrow; + case Qt::Key_Left: return EStdKeyLeftArrow; + case Qt::Key_Comma: return EStdKeyComma; + case Qt::Key_Up: return EStdKeyUpArrow; + case Qt::Key_Space: return EStdKeySpace; + } + + if (key >= '0' && key <= '9') return (EpocKey)key; + if (key >= 'A' && key <= 'Z') return (EpocKey)key; + return EStdKeyNull; +} + + +void PDAScreenWindow::keyPressEvent(QKeyEvent *event) +{ + EpocKey k = resolveKey(event->key()); + if (k != EStdKeyNull) + emu->setKeyboardKey(k, true); +} + +void PDAScreenWindow::keyReleaseEvent(QKeyEvent *event) +{ + EpocKey k = resolveKey(event->key()); + if (k != EStdKeyNull) + emu->setKeyboardKey(k, false); +} + + +void PDAScreenWindow::mousePressEvent(QMouseEvent *event) +{ + emu->updateTouchInput(event->x(), event->y(), true); +} + +void PDAScreenWindow::mouseReleaseEvent(QMouseEvent *event) +{ + emu->updateTouchInput(event->x(), event->y(), false); +} + +void PDAScreenWindow::mouseMoveEvent(QMouseEvent *event) +{ + if (event->buttons() & Qt::LeftButton) + emu->updateTouchInput(event->x(), event->y(), true); +} diff --git a/WindQt/pdascreenwindow.h b/WindQt/pdascreenwindow.h new file mode 100644 index 0000000..e18ca78 --- /dev/null +++ b/WindQt/pdascreenwindow.h @@ -0,0 +1,29 @@ +#ifndef PDASCREENWINDOW_H +#define PDASCREENWINDOW_H + +#include +#include +#include "emubase.h" + +class PDAScreenWindow : public QWidget +{ + Q_OBJECT +private: + EmuBase *emu; + QLabel *lcd; + +public: + explicit PDAScreenWindow(EmuBase *emu, QWidget *parent = nullptr); + +public slots: + void updateScreen(); + +protected: + void keyPressEvent(QKeyEvent *event) override; + void keyReleaseEvent(QKeyEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; +}; + +#endif // PDASCREENWINDOW_H