From 0aa59317baf9879b30d88bcde8bb2741647f7f27 Mon Sep 17 00:00:00 2001 From: Ash Wolf Date: Wed, 25 Dec 2019 19:25:34 +0000 Subject: [PATCH] fix broken timekeeping on 5mx and touch panel on 5mx --- README.md | 4 ++-- WindCore/arm710.cpp | 31 +++++++++++++++++++++++++++++++ WindCore/arm710.h | 1 + WindCore/etna.cpp | 12 ++++++------ WindCore/windermere.cpp | 20 +++++++++++++------- 5 files changed, 53 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 6efb1ad..0544361 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Psion 5mx (EPOC R5) features: - ✅ LCD: partially implemented - ✅ Keyboard: implemented -- ❌ Touch panel: not implemented +- ✅ Touch panel: implemented - ❌ Audio: not implemented - ❌ Serial/UART support: stubbed out - ❌ ETNA (PCMCIA/CompactFlash): mostly stubbed out @@ -20,7 +20,7 @@ Psion 5mx (EPOC R5) features: Oregon Scientific Osaris (EPOC R4) features: - ✅ LCD: implemented -- ✅ Keyboard: mostly implemented (key mappings wrong) +- ✅ Keyboard: implemented (somewhat buggy) - ✅ Touch panel: implemented - ❌ Audio: not implemented - ❌ Serial/UART support: stubbed out diff --git a/WindCore/arm710.cpp b/WindCore/arm710.cpp index bbb6401..c9fc626 100644 --- a/WindCore/arm710.cpp +++ b/WindCore/arm710.cpp @@ -161,6 +161,8 @@ uint32_t ARM710::executeInstruction(uint32_t i) { cycles += execSingleDataSwap(extract1(i,22), extract(i,19,16), extract(i,15,12), extract(i,3,0)); else if ((i & 0x0F8000F0) == 0x00000090) cycles += execMultiply(extract(i,21,20), extract(i,19,16), extract(i,15,12), extract(i,11,8), extract(i,3,0)); + else if ((i & 0x0F8000F0) == 0x00800090 && isTVersion) + cycles += execMultiplyLong(extract(i,22,20), extract(i,19,16), extract(i,15,12), extract(i,11,8), extract(i,3,0)); else if ((i & 0x0C000000) == 0x00000000) cycles += execDataProcessing(extract1(i,25), extract(i,24,21), extract1(i,20), extract(i,19,16), extract(i,15,12), extract(i,11,0)); else @@ -399,6 +401,35 @@ uint32_t ARM710::execMultiply(uint32_t AS, uint32_t Rd, uint32_t Rn, uint32_t Rs return 0; } +// ARM710T only! +uint32_t ARM710::execMultiplyLong(uint32_t UAS, uint32_t RdHi, uint32_t RdLo, uint32_t Rs, uint32_t Rm) +{ + // no need for R15 fuckery + // datasheet says it's not allowed here + uint64_t result; + if (UAS & 4) // unsigned + result = (uint64_t)GPRs[Rm] * (uint64_t)GPRs[Rs]; + else // signed + result = (uint64_t)((int64_t)GPRs[Rm] * (int64_t)GPRs[Rs]); + + if (UAS & 2) { + // accumulate + uint64_t addend = (uint64_t)GPRs[RdLo] | ((uint64_t)GPRs[RdHi] << 32); + result += addend; + } + + if (UAS & 1) { + CPSR &= ~(CPSR_N | CPSR_Z); + CPSR |= result ? 0 : CPSR_Z; + CPSR |= (result & 0x8000000000000000) ? CPSR_N : 0; + } + + GPRs[RdLo] = result & 0xFFFFFFFF; + GPRs[RdHi] = result >> 32; + + return 0; +} + uint32_t ARM710::execSingleDataSwap(bool B, uint32_t Rn, uint32_t Rd, uint32_t Rm) { auto valueSize = B ? V8 : V32; diff --git a/WindCore/arm710.h b/WindCore/arm710.h index c8179c6..c6cf91f 100644 --- a/WindCore/arm710.h +++ b/WindCore/arm710.h @@ -287,6 +287,7 @@ private: uint32_t execDataProcessing(bool I, uint32_t Opcode, bool S, uint32_t Rn, uint32_t Rd, uint32_t Operand2); uint32_t execMultiply(uint32_t AS, uint32_t Rd, uint32_t Rn, uint32_t Rs, uint32_t Rm); + uint32_t execMultiplyLong(uint32_t UAS, uint32_t RdHi, uint32_t RdLo, uint32_t Rs, uint32_t Rm); uint32_t execSingleDataSwap(bool B, uint32_t Rn, uint32_t Rd, uint32_t Rm); uint32_t execSingleDataTransfer(uint32_t IPUBWL, uint32_t Rn, uint32_t Rd, uint32_t offset); uint32_t execBlockDataTransfer(uint32_t PUSWL, uint32_t Rn, uint32_t registerList); diff --git a/WindCore/etna.cpp b/WindCore/etna.cpp index 2267db7..1e7c75b 100644 --- a/WindCore/etna.cpp +++ b/WindCore/etna.cpp @@ -79,14 +79,14 @@ Etna::Etna(ARM710 *owner) { chk ^= prom[i]; // EPOC is expecting 66 - prom[0x7F] = chk ^ 66; + prom[0x7F] = chk ^ 66; } uint32_t Etna::readReg8(uint32_t reg) { - if (!promReadActive) - printf("ETNA readReg8: reg=%s @ pc=%08x,lr=%08x\n", nameReg(reg), owner->getGPR(15) - 4, owner->getGPR(14)); +// if (!promReadActive) +// owner->log("ETNA readReg8: reg=%s @ pc=%08x,lr=%08x", nameReg(reg), owner->getGPR(15) - 4, owner->getGPR(14)); switch (reg) { case regIntClear: return 0; case regSktVarA0: return 1; // will store some status flags @@ -100,14 +100,14 @@ uint32_t Etna::readReg8(uint32_t reg) uint32_t Etna::readReg32(uint32_t reg) { // may be able to remove this, p. sure Etna is byte addressing only - printf("ETNA readReg32: reg=%x\n", reg); + owner->log("ETNA readReg32: reg=%x", reg); return 0xFFFFFFFF; } void Etna::writeReg8(uint32_t reg, uint8_t value) { if (!promReadActive) - printf("ETNA writeReg8: reg=%s value=%02x @ pc=%08x,lr=%08x\n", nameReg(reg), value, owner->getGPR(15) - 4, owner->getGPR(14)); + owner->log("ETNA writeReg8: reg=%s value=%02x @ pc=%08x,lr=%08x", nameReg(reg), value, owner->getGPR(15) - 4, owner->getGPR(14)); switch (reg) { case regIntClear: pendingInterrupts &= ~value; break; case regWake1: wake1 = value; break; @@ -118,7 +118,7 @@ void Etna::writeReg8(uint32_t reg, uint8_t value) void Etna::writeReg32(uint32_t reg, uint32_t value) { // may be able to remove this, p. sure Etna is byte addressing only - printf("ETNA writeReg32: reg=%x value=%08x\n", reg, value); + owner->log("ETNA writeReg32: reg=%x value=%08x", reg, value); } void Etna::setPromBit0High() diff --git a/WindCore/windermere.cpp b/WindCore/windermere.cpp index 335d3eb..2de2128 100644 --- a/WindCore/windermere.cpp +++ b/WindCore/windermere.cpp @@ -76,10 +76,8 @@ uint32_t Emulator::readReg32(uint32_t reg) { // as per 5000A7B0 in 5mx rom uint16_t ssiValue = 0; switch (lastSSIRequest) { -// case 0x9093: ssiValue = (uint16_t)(1156 - (touchY * 3.96)); break; -// case 0xD0D3: ssiValue = (uint16_t)(2819 - (touchX * 3.91)); break; - case 0x9093: ssiValue = (uint16_t)(1156 - (touchY * 3.96)); break; - case 0xD0D3: ssiValue = (uint16_t)(1276 + (touchX * 3.91)); break; + case 0xD0D3: ssiValue = (uint16_t)(50 + (touchX * 5.7)); break; + case 0x9093: ssiValue = (uint16_t)(3834 - (touchY * 13.225)); break; case 0xA4A4: ssiValue = 3100; break; // MainBattery case 0xE4E4: ssiValue = 3100; break; // BackupBattery } @@ -97,11 +95,11 @@ uint32_t Emulator::readReg32(uint32_t reg) { return 0; } else if (reg == RTCDRL) { uint16_t v = rtc & 0xFFFF; -// printf("RTCDRL: %04x\n", v); +// log("RTCDRL: %04x", v); return v; } else if (reg == RTCDRU) { uint16_t v = rtc >> 16; -// printf("RTCDRU: %04x\n", v); +// log("RTCDRU: %04x", v); return v; } else if (reg == KSCAN) { return kScan; @@ -207,6 +205,14 @@ void Emulator::writeReg32(uint32_t reg, uint32_t value) { tc2.load(value); } else if (reg == TC2EOI) { pendingInterrupts &= ~(1 << TC2OI); + } else if (reg == RTCDRL) { + rtc &= 0xFFFF0000; + rtc |= (value & 0xFFFF); + log("RTC write lower: %04x", value); + } else if (reg == RTCDRU) { + rtc &= 0x0000FFFF; + rtc |= (value & 0xFFFF) << 16; + log("RTC write upper: %04x", value); } else { // printf("RegWrite32 unknown:: pc=%08x reg=%03x value=%08x\n", getGPR(15)-4, reg, value); } @@ -523,7 +529,7 @@ void Emulator::debugPC(uint32_t pc) { case 15: n = "EButton3Up"; break; case 16: n = "ESwitchOff"; break; } - log("EVENT %s: tick=%d params=%08x,%08x", n, evtTick, evtParamA, evtParamB); + log("EVENT %s: tick=%d params=%d,%d", n, evtTick, evtParamA, evtParamB); } }