diff --git a/README.md b/README.md index 50c3539..926c6db 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -WindEmu is an attempt to emulate the Psion Series 5mx (or as internally called, "Windermere"). I don't think anyone's done this before... or if they have, I can't find evidence online! +WindEmu is an attempt to emulate various Psion PDAs. - Platform-independent core emulation library written in C/C++ - Qt5 front-end (currently quite barebones...) - Very experimental -- Boots from the Psion 5mx Pro's Sys$rom.bin +- Basic support for multiple devices -Hardware features: +Psion 5mx (EPOC R5) features: - ✅ LCD: partially implemented - ✅ Keyboard: implemented @@ -17,14 +17,22 @@ Hardware features: - ❌ RTC alarm: not implemented - ❌ Standby mode: not implemented +Oregon Scientific Osaris (EPOC R4) features: + +- ✅ LCD: implemented +- ✅ Keyboard: mostly implemented (key mappings wrong) +- ❌ Touch panel: not implemented +- ❌ Audio: not implemented +- ❌ Serial/UART support: stubbed out +- ❌ PCMCIA: mostly stubbed out +- ✅ RTC: implemented (needs testing) +- ❌ RTC alarm: not implemented +- ❌ Standby mode: not implemented + Known issues: -- ROM path is hardcoded into WindQt/main.cpp right now -- Memory protection is not enforced -- Memory errors do not result in an Abort exception but instead make the emulator freak out - Some keys do not work properly - State is not saved (just like a real Psion :p) -- LCD controller is almost entirely unimplemented aside from the very basics to display the framebuffer - EPOC misbehaves massively with memory banks larger than 0x800000 (may be an OS design flaw? need to confirm) Copyright @@ -32,16 +40,16 @@ Copyright The Psion-specific code is copyright (c) 2019 Ash Wolf. -The ARM emulation core is a modified version of the one used in [mGBA](https://github.com/mgba-emu/mgba) by endrift. +The ARM disassembly code is a modified version of the one used in [mGBA](https://github.com/mgba-emu/mgba) by endrift. WindEmu is available under the Mozilla Public License 2.0. Resources --------- -Special thanks to [PsiLinux/OpenPsion](http://linux-7110.sourceforge.net/index.shtml) for providing an avenue to learn about the hardware definitions (registers, etc). +Special thanks to [PsiLinux/OpenPsion](http://linux-7110.sourceforge.net/index.shtml) for providing an avenue to learn about the 5mx hardware definitions (registers, etc). -More information on the hardware is available in the NetBSD port: http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/arch/epoc32/?only_with_tag=MAIN +More information on the 5mx hardware is available in the NetBSD port: http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/arch/epoc32/?only_with_tag=MAIN The EPOC C++ SDK is available here: https://web.archive.org/web/20071010101808/http://www.psionteklogix.com/teknet/pdk/netpad-pdk/epoc_downloads.htm @@ -49,6 +57,10 @@ The ARM variant used in the 5mx is documented here: http://infocenter.arm.com/he The datasheet for the CL-PS7110 SoC used in the Series 5 (_not_ the 5mx) is available here: https://www.igorkov.org/revo/datasheets/CL-PS7110.pdf - while not identical to Windermere, some components operate in similar fashion. +The datasheet for the CL-PS7111 SoC used in the Osaris is available here: https://www.digchip.com/datasheets/parts/datasheet/096/CL-PS7111-pdf.php + +The datasheet for the CL-PS6700 PCMCIA controller used in the Osaris is available here: https://pdf1.alldatasheet.com/datasheet-pdf/view/104907/CIRRUS/CL-PS6700.html + diff --git a/WindCore/WindCore.pro b/WindCore/WindCore.pro index 5d13113..f39561e 100644 --- a/WindCore/WindCore.pro +++ b/WindCore/WindCore.pro @@ -26,12 +26,10 @@ SOURCES += \ arm710.cpp \ clps7111.cpp \ clps7600.cpp \ + emubase.cpp \ etna.cpp \ - isa-arm.c \ decoder.c \ decoder-arm.c \ - arm.c \ - wind_defs.cpp \ windermere.cpp HEADERS += \ @@ -39,6 +37,7 @@ HEADERS += \ clps7111.h \ clps7111_defs.h \ clps7600.h \ + emubase.h \ etna.h \ hardware.h \ wind_defs.h \ @@ -50,7 +49,6 @@ HEADERS += \ decoder.h \ decoder-inlines.h \ common.h \ - arm.h \ windermere.h unix { target.path = /usr/lib diff --git a/WindCore/arm.c b/WindCore/arm.c deleted file mode 100644 index 80c7f0e..0000000 --- a/WindCore/arm.c +++ /dev/null @@ -1,236 +0,0 @@ -/* Copyright (c) 2013-2014 Jeffrey Pfau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "arm.h" -#include "isa-arm.h" -#include "isa-inlines.h" - -static inline enum RegisterBank _ARMSelectBank(enum PrivilegeMode); - -void ARMSetPrivilegeMode(struct ARMCore* cpu, enum PrivilegeMode mode) { - if (mode == cpu->privilegeMode) { - // Not switching modes after all - return; - } - - enum RegisterBank newBank = _ARMSelectBank(mode); - enum RegisterBank oldBank = _ARMSelectBank(cpu->privilegeMode); - if (newBank != oldBank) { - // Switch banked registers - if (mode == MODE_FIQ || cpu->privilegeMode == MODE_FIQ) { - int oldFIQBank = oldBank == BANK_FIQ; - int newFIQBank = newBank == BANK_FIQ; - cpu->bankedRegisters[oldFIQBank][2] = cpu->gprs[8]; - cpu->bankedRegisters[oldFIQBank][3] = cpu->gprs[9]; - cpu->bankedRegisters[oldFIQBank][4] = cpu->gprs[10]; - cpu->bankedRegisters[oldFIQBank][5] = cpu->gprs[11]; - cpu->bankedRegisters[oldFIQBank][6] = cpu->gprs[12]; - cpu->gprs[8] = cpu->bankedRegisters[newFIQBank][2]; - cpu->gprs[9] = cpu->bankedRegisters[newFIQBank][3]; - cpu->gprs[10] = cpu->bankedRegisters[newFIQBank][4]; - cpu->gprs[11] = cpu->bankedRegisters[newFIQBank][5]; - cpu->gprs[12] = cpu->bankedRegisters[newFIQBank][6]; - } - cpu->bankedRegisters[oldBank][0] = cpu->gprs[ARM_SP]; - cpu->bankedRegisters[oldBank][1] = cpu->gprs[ARM_LR]; - cpu->gprs[ARM_SP] = cpu->bankedRegisters[newBank][0]; - cpu->gprs[ARM_LR] = cpu->bankedRegisters[newBank][1]; - - cpu->bankedSPSRs[oldBank] = cpu->spsr.packed; - cpu->spsr.packed = cpu->bankedSPSRs[newBank]; - } - cpu->privilegeMode = mode; -} - -static inline enum RegisterBank _ARMSelectBank(enum PrivilegeMode mode) { - switch (mode) { - case MODE_USER: - case MODE_SYSTEM: - // No banked registers - return BANK_NONE; - case MODE_FIQ: - return BANK_FIQ; - case MODE_IRQ: - return BANK_IRQ; - case MODE_SUPERVISOR: - return BANK_SUPERVISOR; - case MODE_ABORT: - return BANK_ABORT; - case MODE_UNDEFINED: - return BANK_UNDEFINED; - default: - // This should be unreached - return BANK_NONE; - } -} - -void ARMReset(struct ARMCore* cpu) { - int i; - for (i = 0; i < 16; ++i) { - cpu->gprs[i] = 0; - } - for (i = 0; i < 6; ++i) { - cpu->bankedRegisters[i][0] = 0; - cpu->bankedRegisters[i][1] = 0; - cpu->bankedRegisters[i][2] = 0; - cpu->bankedRegisters[i][3] = 0; - cpu->bankedRegisters[i][4] = 0; - cpu->bankedRegisters[i][5] = 0; - cpu->bankedRegisters[i][6] = 0; - cpu->bankedSPSRs[i] = 0; - } - - cpu->privilegeMode = MODE_SYSTEM; - cpu->cpsr.packed = MODE_SYSTEM; - cpu->spsr.packed = 0; - - cpu->shifterOperand = 0; - cpu->shifterCarryOut = 0; - - ARMWritePC(cpu); - - cpu->cycles = 0; - cpu->nextEvent = 0; - cpu->halted = 0; - - cpu->irqh.reset(cpu); -} - -void ARMRaiseFIQ(struct ARMCore* cpu) { - if (cpu->cpsr.f) { - return; - } - union PSR cpsr = cpu->cpsr; - ARMSetPrivilegeMode(cpu, MODE_FIQ); - cpu->cpsr.priv = MODE_FIQ; - cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC]; - cpu->gprs[ARM_PC] = BASE_FIQ; - cpu->cycles += ARMWritePC(cpu); - cpu->spsr = cpsr; - cpu->cpsr.f = 1; - cpu->cpsr.i = 1; - cpu->halted = 0; -} - -void ARMRaiseIRQ(struct ARMCore* cpu) { - if (cpu->cpsr.i) { - return; - } - union PSR cpsr = cpu->cpsr; - ARMSetPrivilegeMode(cpu, MODE_IRQ); - cpu->cpsr.priv = MODE_IRQ; - cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC]; - cpu->gprs[ARM_PC] = BASE_IRQ; - cpu->cycles += ARMWritePC(cpu); - cpu->spsr = cpsr; - cpu->cpsr.i = 1; - cpu->halted = 0; -} - -void ARMRaiseSWI(struct ARMCore* cpu) { - union PSR cpsr = cpu->cpsr; - ARMSetPrivilegeMode(cpu, MODE_SUPERVISOR); - cpu->cpsr.priv = MODE_SUPERVISOR; - cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - 4; - cpu->gprs[ARM_PC] = BASE_SWI; - cpu->cycles += ARMWritePC(cpu); - cpu->spsr = cpsr; - cpu->cpsr.i = 1; -} - -void ARMRaiseUndefined(struct ARMCore* cpu) { - union PSR cpsr = cpu->cpsr; - ARMSetPrivilegeMode(cpu, MODE_UNDEFINED); - cpu->cpsr.priv = MODE_UNDEFINED; - cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - 4; - cpu->gprs[ARM_PC] = BASE_UNDEF; - cpu->cycles += ARMWritePC(cpu); - cpu->spsr = cpsr; - cpu->cpsr.i = 1; -} - -static inline void ARMStep(struct ARMCore* cpu) { - uint32_t opcode = cpu->prefetch[0]; - cpu->prefetch[0] = cpu->prefetch[1]; - cpu->gprs[ARM_PC] += 4; - cpu->prefetch[1] = cpu->memory.load32(cpu, cpu->gprs[ARM_PC], NULL); - - unsigned condition = opcode >> 28; - if (condition != 0xE) { - bool conditionMet = false; - switch (condition) { - case 0x0: - conditionMet = ARM_COND_EQ; - break; - case 0x1: - conditionMet = ARM_COND_NE; - break; - case 0x2: - conditionMet = ARM_COND_CS; - break; - case 0x3: - conditionMet = ARM_COND_CC; - break; - case 0x4: - conditionMet = ARM_COND_MI; - break; - case 0x5: - conditionMet = ARM_COND_PL; - break; - case 0x6: - conditionMet = ARM_COND_VS; - break; - case 0x7: - conditionMet = ARM_COND_VC; - break; - case 0x8: - conditionMet = ARM_COND_HI; - break; - case 0x9: - conditionMet = ARM_COND_LS; - break; - case 0xA: - conditionMet = ARM_COND_GE; - break; - case 0xB: - conditionMet = ARM_COND_LT; - break; - case 0xC: - conditionMet = ARM_COND_GT; - break; - case 0xD: - conditionMet = ARM_COND_LE; - break; - default: - break; - } - if (!conditionMet) { - cpu->cycles += ARM_PREFETCH_CYCLES; - return; - } - } - ARMInstruction instruction = _armTable[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)]; - instruction(cpu, opcode); -} - -void ARMRun(struct ARMCore* cpu) { - ARMStep(cpu); - if (cpu->cycles >= cpu->nextEvent) { - cpu->irqh.processEvents(cpu); - } -} - -void ARMRunLoop(struct ARMCore* cpu) { - while (cpu->cycles < cpu->nextEvent) { - ARMStep(cpu); - } - cpu->irqh.processEvents(cpu); -} - -void ARMRunFake(struct ARMCore* cpu, uint32_t opcode) { - cpu->gprs[ARM_PC] -= 4; - cpu->prefetch[1] = cpu->prefetch[0]; - cpu->prefetch[0] = opcode; -} diff --git a/WindCore/arm.h b/WindCore/arm.h deleted file mode 100644 index 0e61e6c..0000000 --- a/WindCore/arm.h +++ /dev/null @@ -1,174 +0,0 @@ -/* Copyright (c) 2013-2014 Jeffrey Pfau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef ARM_H -#define ARM_H - -#include "common.h" - -CXX_GUARD_START - -// #include - -enum { - ARM_SP = 13, - ARM_LR = 14, - ARM_PC = 15 -}; - -enum PrivilegeMode { - MODE_USER = 0x10, - MODE_FIQ = 0x11, - MODE_IRQ = 0x12, - MODE_SUPERVISOR = 0x13, - MODE_ABORT = 0x17, - MODE_UNDEFINED = 0x1B, - MODE_SYSTEM = 0x1F -}; - -enum ExecutionVector { - BASE_RESET = 0x00000000, - BASE_UNDEF = 0x00000004, - BASE_SWI = 0x00000008, - BASE_PABT = 0x0000000C, - BASE_DABT = 0x00000010, - BASE_IRQ = 0x00000018, - BASE_FIQ = 0x0000001C -}; - -enum RegisterBank { - BANK_NONE = 0, - BANK_FIQ = 1, - BANK_IRQ = 2, - BANK_SUPERVISOR = 3, - BANK_ABORT = 4, - BANK_UNDEFINED = 5 -}; - -enum LSMDirection { - LSM_B = 1, - LSM_D = 2, - LSM_IA = 0, - LSM_IB = 1, - LSM_DA = 2, - LSM_DB = 3 -}; - -struct ARMCore; - -union PSR { - struct { -#if defined(__POWERPC__) || defined(__PPC__) - unsigned n : 1; - unsigned z : 1; - unsigned c : 1; - unsigned v : 1; - unsigned unused : 20; - unsigned i : 1; - unsigned f : 1; - unsigned t : 1; - unsigned priv : 5; -#else - unsigned priv : 5; - unsigned t : 1; - unsigned f : 1; - unsigned i : 1; - unsigned unused : 20; - unsigned v : 1; - unsigned c : 1; - unsigned z : 1; - unsigned n : 1; -#endif - }; - - struct { -#if defined(__BIG_ENDIAN__) - uint8_t flags; - uint8_t status; - uint8_t extension; - uint8_t control; -#else - uint8_t control; - uint8_t extension; - uint8_t status; - uint8_t flags; -#endif - }; - - int32_t packed; -}; - -struct ARMMemory { - uint32_t (*load32)(struct ARMCore*, uint32_t address, int* cycleCounter); - uint32_t (*load16)(struct ARMCore*, uint32_t address, int* cycleCounter); - uint32_t (*load8)(struct ARMCore*, uint32_t address, int* cycleCounter); - - void (*store32)(struct ARMCore*, uint32_t address, int32_t value, int* cycleCounter); - void (*store16)(struct ARMCore*, uint32_t address, int16_t value, int* cycleCounter); - void (*store8)(struct ARMCore*, uint32_t address, int8_t value, int* cycleCounter); - - uint32_t (*loadMultiple)(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction, - int* cycleCounter); - uint32_t (*storeMultiple)(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction, - int* cycleCounter); - - uint32_t activeSeqCycles32; - // uint32_t activeSeqCycles16; - uint32_t activeNonseqCycles32; - // uint32_t activeNonseqCycles16; - int32_t (*stall)(struct ARMCore*, int32_t wait); -}; - -struct ARMInterruptHandler { - void (*reset)(struct ARMCore* cpu); - void (*processEvents)(struct ARMCore* cpu); - // void (*swi16)(struct ARMCore* cpu, int immediate); - void (*swi32)(struct ARMCore* cpu, int immediate); - void (*hitIllegal)(struct ARMCore* cpu, uint32_t opcode); - // void (*bkpt16)(struct ARMCore* cpu, int immediate); - void (*bkpt32)(struct ARMCore* cpu, int immediate); - void (*readCPSR)(struct ARMCore* cpu); - - void (*hitStub)(struct ARMCore* cpu, uint32_t opcode); -}; - -struct ARMCore { - int32_t gprs[16]; - union PSR cpsr; - union PSR spsr; - - int64_t cycles; - int64_t nextEvent; - int halted; - - int32_t bankedRegisters[6][7]; - int32_t bankedSPSRs[6]; - - int32_t shifterOperand; - int32_t shifterCarryOut; - - uint32_t prefetch[2]; - enum PrivilegeMode privilegeMode; - - struct ARMMemory memory; - struct ARMInterruptHandler irqh; - - void *owner; -}; - -void ARMReset(struct ARMCore* cpu); -void ARMSetPrivilegeMode(struct ARMCore*, enum PrivilegeMode); -void ARMRaiseIRQ(struct ARMCore*); -void ARMRaiseFIQ(struct ARMCore*); -void ARMRaiseSWI(struct ARMCore*); -void ARMRaiseUndefined(struct ARMCore*); - -void ARMRun(struct ARMCore* cpu); -void ARMRunLoop(struct ARMCore* cpu); -void ARMRunFake(struct ARMCore* cpu, uint32_t opcode); - -CXX_GUARD_END - -#endif diff --git a/WindCore/clps7111.cpp b/WindCore/clps7111.cpp index 17f864d..a007ad8 100644 --- a/WindCore/clps7111.cpp +++ b/WindCore/clps7111.cpp @@ -5,18 +5,19 @@ #include "common.h" -CLPS7111::CLPS7111() : ARM710(false), pcCardController(this) { +namespace CLPS7111 { +Emulator::Emulator() : EmuBase(false), pcCardController(this) { } -uint32_t CLPS7111::getRTC() { +uint32_t Emulator::getRTC() { return time(nullptr) - 946684800; } -uint32_t CLPS7111::readReg8(uint32_t reg) { +uint32_t Emulator::readReg8(uint32_t reg) { if (reg == PADR) { - return readKeyboard(); + return readKeyboard(kScan); } else if (reg == PBDR) { return (portValues >> 16) & 0xFF; } else if (reg == PDDR) { @@ -36,7 +37,7 @@ uint32_t CLPS7111::readReg8(uint32_t reg) { return 0xFF; } } -uint32_t CLPS7111::readReg32(uint32_t reg) { +uint32_t Emulator::readReg32(uint32_t reg) { if (reg == SYSCON1) { uint32_t flg = 0; if (tc1.config & Timer::PERIODIC) flg |= 0x10; @@ -80,7 +81,7 @@ uint32_t CLPS7111::readReg32(uint32_t reg) { } } -void CLPS7111::writeReg8(uint32_t reg, uint8_t value) { +void Emulator::writeReg8(uint32_t reg, uint8_t value) { if (reg == PADR) { uint32_t oldPorts = portValues; portValues &= 0x00FFFFFF; @@ -126,7 +127,7 @@ void CLPS7111::writeReg8(uint32_t reg, uint8_t value) { log("RegWrite8 unknown:: pc=%08x reg=%03x value=%02x", getRealPC(), reg, value); } } -void CLPS7111::writeReg32(uint32_t reg, uint32_t value) { +void Emulator::writeReg32(uint32_t reg, uint32_t value) { if (reg == SYSCON1) { kScan = value & 0xF; tc1.config = Timer::ENABLED; // always on with PS-7111! @@ -178,18 +179,7 @@ void CLPS7111::writeReg32(uint32_t reg, uint32_t value) { } } -bool CLPS7111::isPhysAddressValid(uint32_t physAddress) const { - uint8_t region = (physAddress >> 24) & 0xF1; - switch (region) { - case 0: return true; - case 0x80: return (physAddress <= 0x80000FFF); - case 0xC0: return true; - default: return false; - } -} - - -MaybeU32 CLPS7111::readPhysical(uint32_t physAddr, ValueSize valueSize) { +MaybeU32 Emulator::readPhysical(uint32_t physAddr, ValueSize valueSize) { uint8_t region = (physAddr >> 28); if (valueSize == V8) { if (region == 0) @@ -226,7 +216,7 @@ MaybeU32 CLPS7111::readPhysical(uint32_t physAddr, ValueSize valueSize) { return {}; } -bool CLPS7111::writePhysical(uint32_t value, uint32_t physAddr, ValueSize valueSize) { +bool Emulator::writePhysical(uint32_t value, uint32_t physAddr, ValueSize valueSize) { uint8_t region = (physAddr >> 28); if (valueSize == V8) { if (region == 0xC) @@ -256,7 +246,7 @@ bool CLPS7111::writePhysical(uint32_t value, uint32_t physAddr, ValueSize valueS -void CLPS7111::configure() { +void Emulator::configure() { if (configured) return; configured = true; @@ -273,13 +263,11 @@ void CLPS7111::configure() { reset(); } -void CLPS7111::loadROM(const char *path) { - FILE *f = fopen(path, "rb"); - fread(ROM, 1, sizeof(ROM), f); - fclose(f); +void Emulator::loadROM(uint8_t *buffer, size_t size) { + memcpy(ROM, buffer, min(size, sizeof(ROM))); } -void CLPS7111::executeUntil(int64_t cycles) { +void Emulator::executeUntil(int64_t cycles) { if (!configured) configure(); @@ -333,23 +321,8 @@ void CLPS7111::executeUntil(int64_t cycles) { } } -void CLPS7111::dumpRAM(const char *path) { - FILE *f = fopen(path, "wb"); - fwrite(MemoryBlockC0, 1, sizeof(MemoryBlockC0), f); - fclose(f); -} - - -void CLPS7111::printRegs() { - printf("R00:%08x R01:%08x R02:%08x R03:%08x\n", getGPR(0), getGPR(1), getGPR(2), getGPR(3)); - printf("R04:%08x R05:%08x R06:%08x R07:%08x\n", getGPR(4), getGPR(5), getGPR(6), getGPR(7)); - printf("R08:%08x R09:%08x R10:%08x R11:%08x\n", getGPR(8), getGPR(9), getGPR(10), getGPR(11)); - printf("R12:%08x R13:%08x R14:%08x R15:%08x\n", getGPR(12), getGPR(13), getGPR(14), getGPR(15)); -// printf("cpsr=%08x spsr=%08x\n", cpu.cpsr.packed, cpu.spsr.packed); -} - -const char *CLPS7111::identifyObjectCon(uint32_t ptr) { +const char *Emulator::identifyObjectCon(uint32_t ptr) { if (ptr == readVirtualDebug(0x80000880, V32).value()) return "process"; if (ptr == readVirtualDebug(0x80000884, V32).value()) return "thread"; if (ptr == readVirtualDebug(0x80000888, V32).value()) return "chunk"; @@ -366,7 +339,7 @@ const char *CLPS7111::identifyObjectCon(uint32_t ptr) { return "???"; } -void CLPS7111::fetchStr(uint32_t str, char *buf) { +void Emulator::fetchStr(uint32_t str, char *buf) { if (str == 0) { strcpy(buf, ""); return; @@ -378,15 +351,15 @@ void CLPS7111::fetchStr(uint32_t str, char *buf) { buf[size] = 0; } -void CLPS7111::fetchName(uint32_t obj, char *buf) { +void Emulator::fetchName(uint32_t obj, char *buf) { fetchStr(readVirtualDebug(obj + 0x10, V32).value(), buf); } -void CLPS7111::fetchProcessFilename(uint32_t obj, char *buf) { +void Emulator::fetchProcessFilename(uint32_t obj, char *buf) { fetchStr(readVirtualDebug(obj + 0x3C, V32).value(), buf); } -void CLPS7111::debugPC(uint32_t pc) { +void Emulator::debugPC(uint32_t pc) { char objName[1000]; if (pc == 0x32304) { // CObjectCon::AddL() @@ -431,41 +404,48 @@ void CLPS7111::debugPC(uint32_t pc) { log("DPlatChunkHw MAPPING: v:%08x p:%08x size:%08x arg:%08x", virtAddr, physAddr, regionSize, a); } -// if (pc == 0x3B250) { -// log("DBG 5003B250: pc=%08x lr=%08x sp=%08x", getRealPC(), getGPR(14), getGPR(13)); -// } } -const uint8_t *CLPS7111::getLCDBuffer() const { - if ((lcdAddress >> 24) == 0xC0) - return &MemoryBlockC0[lcdAddress & MemoryBlockMask]; - else - return nullptr; +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; + int bpp = 1; + if (lcdControl & 0x40000000) bpp = 2; + if (lcdControl & 0x80000000) bpp = 4; + int ppb = 8 / bpp; + // build our image out + int lineWidth = (width * bpp) / 8; + for (int y = 0; y < height; y++) { + int lineOffs = lineWidth * y; + for (int x = 0; x < width; x++) { + uint8_t byte = MemoryBlockC0[lineOffs + (x / ppb)]; + int shift = (x & (ppb - 1)) * bpp; + int mask = (1 << bpp) - 1; + int palIdx = (byte >> shift) & mask; + int palValue; + if (bpp == 1) + palValue = palIdx * 255; + else + palValue = (lcdPalette >> (palIdx * 4)) & 0xF; -uint8_t CLPS7111::readKeyboard() { - uint8_t val = 0; - if (kScan & 8) { - // Select one keyboard - int whichColumn = kScan & 7; - for (int i = 0; i < 7; i++) - if (keyboardKeys[whichColumn * 7 + i]) - val |= (1 << i); - } else if (kScan == 0) { - // Report all columns combined - // EPOC's keyboard driver relies on this... - for (int i = 0; i < 8*7; i++) - if (keyboardKeys[i]) - val |= (1 << (i % 7)); + palValue |= (palValue << 4); + lines[y][x] = palValue ^ 0xFF; + } + } } - return val; } -void CLPS7111::diffPorts(uint32_t oldval, uint32_t newval) { +void Emulator::diffPorts(uint32_t oldval, uint32_t newval) { uint32_t changes = oldval ^ newval; if (changes & 1) log("PRT E0: %d", newval&1); if (changes & 2) log("PRT E1: %d", newval&2); @@ -486,12 +466,5 @@ void CLPS7111::diffPorts(uint32_t oldval, uint32_t newval) { if (changes & 0x200000) log("PRT B5: %d", newval&0x200000); if (changes & 0x400000) log("PRT B6: %d", newval&0x400000); if (changes & 0x800000) log("PRT B7: %d", newval&0x800000); - if (changes & 0x1000000) log("PRT A0: %d", newval&0x1000000); - if (changes & 0x2000000) log("PRT A1: %d", newval&0x2000000); - if (changes & 0x4000000) log("PRT A2: %d", newval&0x4000000); - if (changes & 0x8000000) log("PRT A3: %d", newval&0x8000000); - if (changes & 0x10000000) log("PRT A4: %d", newval&0x10000000); - if (changes & 0x20000000) log("PRT A5: %d", newval&0x20000000); - if (changes & 0x40000000) log("PRT A6: %d", newval&0x40000000); - if (changes & 0x80000000) log("PRT A7: %d", newval&0x80000000); +} } diff --git a/WindCore/clps7111.h b/WindCore/clps7111.h index 3ab514a..925b405 100644 --- a/WindCore/clps7111.h +++ b/WindCore/clps7111.h @@ -1,12 +1,12 @@ #pragma once -#include "arm710.h" +#include "emubase.h" #include "clps7111_defs.h" #include "clps7600.h" #include "hardware.h" #include "etna.h" -#include -class CLPS7111 : public ARM710 { +namespace CLPS7111 { +class Emulator : public EmuBase { public: uint8_t ROM[0x800000]; uint8_t ROM2[0x40000]; @@ -26,13 +26,10 @@ private: uint32_t rtcDiv = 0; uint64_t lcdPalette = 0; - int64_t passedCycles = 0; - int64_t nextTickAt = 0; Timer tc1, tc2; CLPS7600 pcCardController; bool halted = false, asleep = false; - std::unordered_set _breakpoints; uint32_t getRTC(); @@ -42,19 +39,13 @@ private: void writeReg32(uint32_t reg, uint32_t value); public: - bool isPhysAddressValid(uint32_t addr) const; MaybeU32 readPhysical(uint32_t physAddr, ValueSize valueSize) override; bool writePhysical(uint32_t value, uint32_t physAddr, ValueSize valueSize) override; - const uint8_t *getLCDBuffer() const; - uint64_t getLCDPalette() const { return lcdPalette; } - uint32_t getLCDControl() const { return lcdControl; } - private: bool configured = false; void configure(); - void printRegs(); const char *identifyObjectCon(uint32_t ptr); void fetchStr(uint32_t str, char *buf); void fetchName(uint32_t obj, char *buf); @@ -62,15 +53,13 @@ private: void debugPC(uint32_t pc); void diffPorts(uint32_t oldval, uint32_t newval); - uint8_t readKeyboard(); public: - bool keyboardKeys[8*7] = {0}; - -public: - CLPS7111(); - void loadROM(const char *path); - void dumpRAM(const char *path); - void executeUntil(int64_t cycles); - std::unordered_set &breakpoints() { return _breakpoints; } - uint64_t currentCycles() const { return passedCycles; } + Emulator(); + void loadROM(uint8_t *buffer, size_t size) override; + void executeUntil(int64_t cycles) override; + int32_t getClockSpeed() const override { return CLOCK_SPEED; } + int getLCDWidth() const override; + int getLCDHeight() const override; + void readLCDIntoBuffer(uint8_t **lines) const override; }; +} diff --git a/WindCore/clps7111_defs.h b/WindCore/clps7111_defs.h index 86db239..af02b65 100644 --- a/WindCore/clps7111_defs.h +++ b/WindCore/clps7111_defs.h @@ -1,6 +1,7 @@ #pragma once #include +namespace CLPS7111 { enum { CLOCK_SPEED = 0x4800*1000, TICK_INTERVAL = CLOCK_SPEED / 64 @@ -30,7 +31,7 @@ enum Interrupt { IRQ_INTERRUPTS = 0xFFF0 }; -enum Clps7111Reg { +enum Register { PADR = 0, PBDR = 1, PDDR = 3, @@ -78,4 +79,5 @@ enum Clps7111Reg { UBRLCR2 = 0x14C0, KBDEOI = 0x1700 }; +} diff --git a/WindCore/decoder-inlines.h b/WindCore/decoder-inlines.h index ad10838..4dd80a0 100644 --- a/WindCore/decoder-inlines.h +++ b/WindCore/decoder-inlines.h @@ -8,8 +8,6 @@ #include "decoder.h" -#include "arm.h" - #include #include diff --git a/WindCore/decoder.h b/WindCore/decoder.h index 79007b5..31515e1 100644 --- a/WindCore/decoder.h +++ b/WindCore/decoder.h @@ -10,8 +10,6 @@ CXX_GUARD_START -#include "arm.h" - // Bit 0: a register is involved with this operand // Bit 1: an immediate is invovled with this operand // Bit 2: a memory access is invovled with this operand @@ -186,6 +184,9 @@ enum ARMMnemonic { }; enum { + ARM_SP = 13, + ARM_LR = 14, + ARM_PC = 15, ARM_CPSR = 16, ARM_SPSR = 17 }; diff --git a/WindCore/emubase.cpp b/WindCore/emubase.cpp new file mode 100644 index 0000000..86574b5 --- /dev/null +++ b/WindCore/emubase.cpp @@ -0,0 +1,19 @@ +#include "emubase.h" + +uint8_t EmuBase::readKeyboard(int kScan) { + uint8_t val = 0; + if (kScan & 8) { + // Select one keyboard + int whichColumn = kScan & 7; + for (int i = 0; i < 7; i++) + if (keyboardKeys[whichColumn * 7 + i]) + val |= (1 << i); + } else if (kScan == 0) { + // Report all columns combined + // EPOC's keyboard driver relies on this... + for (int i = 0; i < 8*7; i++) + if (keyboardKeys[i]) + val |= (1 << (i % 7)); + } + return val; +} diff --git a/WindCore/emubase.h b/WindCore/emubase.h new file mode 100644 index 0000000..dba5405 --- /dev/null +++ b/WindCore/emubase.h @@ -0,0 +1,28 @@ +#pragma once +#include "arm710.h" +#include + +class EmuBase : public ARM710 +{ +protected: + std::unordered_set _breakpoints; + int64_t passedCycles = 0; + int64_t nextTickAt = 0; + uint8_t readKeyboard(int kScan); + +public: + EmuBase(bool isTVersion) : ARM710(isTVersion) { } + + virtual void loadROM(uint8_t *buffer, size_t size) = 0; + virtual void executeUntil(int64_t cycles) = 0; + virtual int32_t getClockSpeed() const = 0; + virtual int getLCDWidth() const = 0; + virtual int getLCDHeight() const = 0; + virtual void readLCDIntoBuffer(uint8_t **lines) const = 0; + + std::unordered_set &breakpoints() { return _breakpoints; } + uint64_t currentCycles() const { return passedCycles; } + + bool keyboardKeys[8*7] = {0}; +}; + diff --git a/WindCore/isa-arm.c b/WindCore/isa-arm.c deleted file mode 100644 index 28970bc..0000000 --- a/WindCore/isa-arm.c +++ /dev/null @@ -1,741 +0,0 @@ -/* Copyright (c) 2013-2014 Jeffrey Pfau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "isa-arm.h" - -#include "arm.h" -#include "emitter-arm.h" -#include "isa-inlines.h" - -#define PSR_USER_MASK 0xF0000000 -#define PSR_PRIV_MASK 0x000000CF -#define PSR_STATE_MASK 0x00000020 - -// Addressing mode 1 -static inline void _shiftLSL(struct ARMCore* cpu, uint32_t opcode) { - int rm = opcode & 0x0000000F; - if (opcode & 0x00000010) { - int rs = (opcode >> 8) & 0x0000000F; - ++cpu->cycles; - int shift = cpu->gprs[rs]; - if (rs == ARM_PC) { - shift += 4; - } - shift &= 0xFF; - int32_t shiftVal = cpu->gprs[rm]; - if (rm == ARM_PC) { - shiftVal += 4; - } - if (!shift) { - cpu->shifterOperand = shiftVal; - cpu->shifterCarryOut = cpu->cpsr.c; - } else if (shift < 32) { - cpu->shifterOperand = shiftVal << shift; - cpu->shifterCarryOut = (shiftVal >> (32 - shift)) & 1; - } else if (shift == 32) { - cpu->shifterOperand = 0; - cpu->shifterCarryOut = shiftVal & 1; - } else { - cpu->shifterOperand = 0; - cpu->shifterCarryOut = 0; - } - } else { - int immediate = (opcode & 0x00000F80) >> 7; - if (!immediate) { - cpu->shifterOperand = cpu->gprs[rm]; - cpu->shifterCarryOut = cpu->cpsr.c; - } else { - cpu->shifterOperand = cpu->gprs[rm] << immediate; - cpu->shifterCarryOut = (cpu->gprs[rm] >> (32 - immediate)) & 1; - } - } -} - -static inline void _shiftLSR(struct ARMCore* cpu, uint32_t opcode) { - int rm = opcode & 0x0000000F; - if (opcode & 0x00000010) { - int rs = (opcode >> 8) & 0x0000000F; - ++cpu->cycles; - int shift = cpu->gprs[rs]; - if (rs == ARM_PC) { - shift += 4; - } - shift &= 0xFF; - uint32_t shiftVal = cpu->gprs[rm]; - if (rm == ARM_PC) { - shiftVal += 4; - } - if (!shift) { - cpu->shifterOperand = shiftVal; - cpu->shifterCarryOut = cpu->cpsr.c; - } else if (shift < 32) { - cpu->shifterOperand = shiftVal >> shift; - cpu->shifterCarryOut = (shiftVal >> (shift - 1)) & 1; - } else if (shift == 32) { - cpu->shifterOperand = 0; - cpu->shifterCarryOut = shiftVal >> 31; - } else { - cpu->shifterOperand = 0; - cpu->shifterCarryOut = 0; - } - } else { - int immediate = (opcode & 0x00000F80) >> 7; - if (immediate) { - cpu->shifterOperand = ((uint32_t) cpu->gprs[rm]) >> immediate; - cpu->shifterCarryOut = (cpu->gprs[rm] >> (immediate - 1)) & 1; - } else { - cpu->shifterOperand = 0; - cpu->shifterCarryOut = ARM_SIGN(cpu->gprs[rm]); - } - } -} - -static inline void _shiftASR(struct ARMCore* cpu, uint32_t opcode) { - int rm = opcode & 0x0000000F; - if (opcode & 0x00000010) { - int rs = (opcode >> 8) & 0x0000000F; - ++cpu->cycles; - int shift = cpu->gprs[rs]; - if (rs == ARM_PC) { - shift += 4; - } - shift &= 0xFF; - int shiftVal = cpu->gprs[rm]; - if (rm == ARM_PC) { - shiftVal += 4; - } - if (!shift) { - cpu->shifterOperand = shiftVal; - cpu->shifterCarryOut = cpu->cpsr.c; - } else if (shift < 32) { - cpu->shifterOperand = shiftVal >> shift; - cpu->shifterCarryOut = (shiftVal >> (shift - 1)) & 1; - } else if (cpu->gprs[rm] >> 31) { - cpu->shifterOperand = 0xFFFFFFFF; - cpu->shifterCarryOut = 1; - } else { - cpu->shifterOperand = 0; - cpu->shifterCarryOut = 0; - } - } else { - int immediate = (opcode & 0x00000F80) >> 7; - if (immediate) { - cpu->shifterOperand = cpu->gprs[rm] >> immediate; - cpu->shifterCarryOut = (cpu->gprs[rm] >> (immediate - 1)) & 1; - } else { - cpu->shifterCarryOut = ARM_SIGN(cpu->gprs[rm]); - cpu->shifterOperand = cpu->shifterCarryOut; - } - } -} - -static inline void _shiftROR(struct ARMCore* cpu, uint32_t opcode) { - int rm = opcode & 0x0000000F; - if (opcode & 0x00000010) { - int rs = (opcode >> 8) & 0x0000000F; - ++cpu->cycles; - int shift = cpu->gprs[rs]; - if (rs == ARM_PC) { - shift += 4; - } - shift &= 0xFF; - int shiftVal = cpu->gprs[rm]; - if (rm == ARM_PC) { - shiftVal += 4; - } - int rotate = shift & 0x1F; - if (!shift) { - cpu->shifterOperand = shiftVal; - cpu->shifterCarryOut = cpu->cpsr.c; - } else if (rotate) { - cpu->shifterOperand = ROR(shiftVal, rotate); - cpu->shifterCarryOut = (shiftVal >> (rotate - 1)) & 1; - } else { - cpu->shifterOperand = shiftVal; - cpu->shifterCarryOut = ARM_SIGN(shiftVal); - } - } else { - int immediate = (opcode & 0x00000F80) >> 7; - if (immediate) { - cpu->shifterOperand = ROR(cpu->gprs[rm], immediate); - cpu->shifterCarryOut = (cpu->gprs[rm] >> (immediate - 1)) & 1; - } else { - // RRX - cpu->shifterOperand = (cpu->cpsr.c << 31) | (((uint32_t) cpu->gprs[rm]) >> 1); - cpu->shifterCarryOut = cpu->gprs[rm] & 0x00000001; - } - } -} - -static inline void _immediate(struct ARMCore* cpu, uint32_t opcode) { - int rotate = (opcode & 0x00000F00) >> 7; - int immediate = opcode & 0x000000FF; - if (!rotate) { - cpu->shifterOperand = immediate; - cpu->shifterCarryOut = cpu->cpsr.c; - } else { - cpu->shifterOperand = ROR(immediate, rotate); - cpu->shifterCarryOut = ARM_SIGN(cpu->shifterOperand); - } -} - -// Instruction definitions -// Beware pre-processor antics - -ATTRIBUTE_NOINLINE static void _additionS(struct ARMCore* cpu, int32_t m, int32_t n, int32_t d) { - cpu->cpsr.flags = 0; - cpu->cpsr.n = ARM_SIGN(d); - cpu->cpsr.z = !d; - cpu->cpsr.c = ARM_CARRY_FROM(m, n, d); - cpu->cpsr.v = ARM_V_ADDITION(m, n, d); -} - -ATTRIBUTE_NOINLINE static void _subtractionS(struct ARMCore* cpu, int32_t m, int32_t n, int32_t d) { - cpu->cpsr.flags = 0; - cpu->cpsr.n = ARM_SIGN(d); - cpu->cpsr.z = !d; - cpu->cpsr.c = ARM_BORROW_FROM(m, n, d); - cpu->cpsr.v = ARM_V_SUBTRACTION(m, n, d); -} - -ATTRIBUTE_NOINLINE static void _neutralS(struct ARMCore* cpu, int32_t d) { - cpu->cpsr.n = ARM_SIGN(d); - cpu->cpsr.z = !d; \ - cpu->cpsr.c = cpu->shifterCarryOut; \ -} - -#define ARM_ADDITION_S(M, N, D) \ - if (rd == ARM_PC && _ARMModeHasSPSR(cpu->cpsr.priv)) { \ - cpu->cpsr = cpu->spsr; \ - _ARMReadCPSR(cpu); \ - } else { \ - _additionS(cpu, M, N, D); \ - } - -#define ARM_SUBTRACTION_S(M, N, D) \ - if (rd == ARM_PC && _ARMModeHasSPSR(cpu->cpsr.priv)) { \ - cpu->cpsr = cpu->spsr; \ - _ARMReadCPSR(cpu); \ - } else { \ - _subtractionS(cpu, M, N, D); \ - } - -#define ARM_SUBTRACTION_CARRY_S(M, N, D, C) \ - if (rd == ARM_PC && _ARMModeHasSPSR(cpu->cpsr.priv)) { \ - cpu->cpsr = cpu->spsr; \ - _ARMReadCPSR(cpu); \ - } else { \ - cpu->cpsr.n = ARM_SIGN(D); \ - cpu->cpsr.z = !(D); \ - cpu->cpsr.c = ARM_BORROW_FROM_CARRY(M, N, D, C); \ - cpu->cpsr.v = ARM_V_SUBTRACTION(M, N, D); \ - } - -#define ARM_NEUTRAL_S(M, N, D) \ - if (rd == ARM_PC && _ARMModeHasSPSR(cpu->cpsr.priv)) { \ - cpu->cpsr = cpu->spsr; \ - _ARMReadCPSR(cpu); \ - } else { \ - _neutralS(cpu, D); \ - } - -#define ARM_NEUTRAL_HI_S(DLO, DHI) \ - cpu->cpsr.n = ARM_SIGN(DHI); \ - cpu->cpsr.z = !((DHI) | (DLO)); - -#define ADDR_MODE_2_I_TEST (opcode & 0x00000F80) -#define ADDR_MODE_2_I ((opcode & 0x00000F80) >> 7) -#define ADDR_MODE_2_ADDRESS (address) -#define ADDR_MODE_2_RN (cpu->gprs[rn]) -#define ADDR_MODE_2_RM (cpu->gprs[rm]) -#define ADDR_MODE_2_IMMEDIATE (opcode & 0x00000FFF) -#define ADDR_MODE_2_INDEX(U_OP, M) (cpu->gprs[rn] U_OP M) -#define ADDR_MODE_2_WRITEBACK(ADDR) \ - cpu->gprs[rn] = ADDR; \ - if (UNLIKELY(rn == ARM_PC)) { \ - currentCycles += ARMWritePC(cpu); \ - } - -#define ADDR_MODE_2_WRITEBACK_PRE_STORE(WB) -#define ADDR_MODE_2_WRITEBACK_POST_STORE(WB) WB -#define ADDR_MODE_2_WRITEBACK_PRE_LOAD(WB) WB -#define ADDR_MODE_2_WRITEBACK_POST_LOAD(WB) - -#define ADDR_MODE_2_LSL (cpu->gprs[rm] << ADDR_MODE_2_I) -#define ADDR_MODE_2_LSR (ADDR_MODE_2_I_TEST ? ((uint32_t) cpu->gprs[rm]) >> ADDR_MODE_2_I : 0) -#define ADDR_MODE_2_ASR (ADDR_MODE_2_I_TEST ? ((int32_t) cpu->gprs[rm]) >> ADDR_MODE_2_I : ((int32_t) cpu->gprs[rm]) >> 31) -#define ADDR_MODE_2_ROR (ADDR_MODE_2_I_TEST ? ROR(cpu->gprs[rm], ADDR_MODE_2_I) : (cpu->cpsr.c << 31) | (((uint32_t) cpu->gprs[rm]) >> 1)) - -#define ADDR_MODE_3_ADDRESS ADDR_MODE_2_ADDRESS -#define ADDR_MODE_3_RN ADDR_MODE_2_RN -#define ADDR_MODE_3_RM ADDR_MODE_2_RM -#define ADDR_MODE_3_IMMEDIATE (((opcode & 0x00000F00) >> 4) | (opcode & 0x0000000F)) -#define ADDR_MODE_3_INDEX(U_OP, M) ADDR_MODE_2_INDEX(U_OP, M) -#define ADDR_MODE_3_WRITEBACK(ADDR) ADDR_MODE_2_WRITEBACK(ADDR) - -#define ADDR_MODE_4_WRITEBACK_LDM \ - if (!((1 << rn) & rs)) { \ - cpu->gprs[rn] = address; \ - } - -#define ADDR_MODE_4_WRITEBACK_STM cpu->gprs[rn] = address; - -#define ARM_LOAD_POST_BODY \ - currentCycles += cpu->memory.activeNonseqCycles32 - cpu->memory.activeSeqCycles32; \ - if (rd == ARM_PC) { \ - currentCycles += ARMWritePC(cpu); \ - } - -#define ARM_STORE_POST_BODY \ - currentCycles += cpu->memory.activeNonseqCycles32 - cpu->memory.activeSeqCycles32; - -#define DEFINE_INSTRUCTION_ARM(NAME, BODY) \ - static void _ARMInstruction ## NAME (struct ARMCore* cpu, uint32_t opcode) { \ - int currentCycles = ARM_PREFETCH_CYCLES; \ - BODY; \ - cpu->cycles += currentCycles; \ - } - -#define DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, S_BODY, SHIFTER, BODY) \ - DEFINE_INSTRUCTION_ARM(NAME, \ - int rd = (opcode >> 12) & 0xF; \ - int rn = (opcode >> 16) & 0xF; \ - UNUSED(rn); \ - SHIFTER(cpu, opcode); \ - BODY; \ - S_BODY; \ - if (rd == ARM_PC) { \ - currentCycles += ARMWritePC(cpu); \ - }) - -#define DEFINE_ALU_INSTRUCTION_ARM(NAME, S_BODY, BODY) \ - DEFINE_ALU_INSTRUCTION_EX_ARM(NAME ## _LSL, , _shiftLSL, BODY) \ - DEFINE_ALU_INSTRUCTION_EX_ARM(NAME ## S_LSL, S_BODY, _shiftLSL, BODY) \ - DEFINE_ALU_INSTRUCTION_EX_ARM(NAME ## _LSR, , _shiftLSR, BODY) \ - DEFINE_ALU_INSTRUCTION_EX_ARM(NAME ## S_LSR, S_BODY, _shiftLSR, BODY) \ - DEFINE_ALU_INSTRUCTION_EX_ARM(NAME ## _ASR, , _shiftASR, BODY) \ - DEFINE_ALU_INSTRUCTION_EX_ARM(NAME ## S_ASR, S_BODY, _shiftASR, BODY) \ - DEFINE_ALU_INSTRUCTION_EX_ARM(NAME ## _ROR, , _shiftROR, BODY) \ - DEFINE_ALU_INSTRUCTION_EX_ARM(NAME ## S_ROR, S_BODY, _shiftROR, BODY) \ - DEFINE_ALU_INSTRUCTION_EX_ARM(NAME ## I, , _immediate, BODY) \ - DEFINE_ALU_INSTRUCTION_EX_ARM(NAME ## SI, S_BODY, _immediate, BODY) - -#define DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(NAME, S_BODY, BODY) \ - DEFINE_ALU_INSTRUCTION_EX_ARM(NAME ## _LSL, S_BODY, _shiftLSL, BODY) \ - DEFINE_ALU_INSTRUCTION_EX_ARM(NAME ## _LSR, S_BODY, _shiftLSR, BODY) \ - DEFINE_ALU_INSTRUCTION_EX_ARM(NAME ## _ASR, S_BODY, _shiftASR, BODY) \ - DEFINE_ALU_INSTRUCTION_EX_ARM(NAME ## _ROR, S_BODY, _shiftROR, BODY) \ - DEFINE_ALU_INSTRUCTION_EX_ARM(NAME ## I, S_BODY, _immediate, BODY) - -#define DEFINE_MULTIPLY_INSTRUCTION_EX_ARM(NAME, BODY, S_BODY) \ - DEFINE_INSTRUCTION_ARM(NAME, \ - int rd = (opcode >> 16) & 0xF; \ - int rs = (opcode >> 8) & 0xF; \ - int rm = opcode & 0xF; \ - if (rd == ARM_PC) { \ - return; \ - } \ - ARM_WAIT_MUL(cpu->gprs[rs]); \ - BODY; \ - S_BODY; \ - currentCycles += cpu->memory.activeNonseqCycles32 - cpu->memory.activeSeqCycles32) - -#define DEFINE_MULTIPLY_INSTRUCTION_2_EX_ARM(NAME, BODY, S_BODY, WAIT) \ - DEFINE_INSTRUCTION_ARM(NAME, \ - int rd = (opcode >> 12) & 0xF; \ - int rdHi = (opcode >> 16) & 0xF; \ - int rs = (opcode >> 8) & 0xF; \ - int rm = opcode & 0xF; \ - if (rdHi == ARM_PC || rd == ARM_PC) { \ - return; \ - } \ - currentCycles += cpu->memory.stall(cpu, WAIT); \ - BODY; \ - S_BODY; \ - currentCycles += cpu->memory.activeNonseqCycles32 - cpu->memory.activeSeqCycles32) - -#define DEFINE_MULTIPLY_INSTRUCTION_ARM(NAME, BODY, S_BODY) \ - DEFINE_MULTIPLY_INSTRUCTION_EX_ARM(NAME, BODY, ) \ - DEFINE_MULTIPLY_INSTRUCTION_EX_ARM(NAME ## S, BODY, S_BODY) - -#define DEFINE_MULTIPLY_INSTRUCTION_2_ARM(NAME, BODY, S_BODY, WAIT) \ - DEFINE_MULTIPLY_INSTRUCTION_2_EX_ARM(NAME, BODY, , WAIT) \ - DEFINE_MULTIPLY_INSTRUCTION_2_EX_ARM(NAME ## S, BODY, S_BODY, WAIT) - -#define DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME, ADDRESS, WRITEBACK, LS, BODY) \ - DEFINE_INSTRUCTION_ARM(NAME, \ - uint32_t address; \ - int rn = (opcode >> 16) & 0xF; \ - int rd = (opcode >> 12) & 0xF; \ - int rm = opcode & 0xF; \ - UNUSED(rm); \ - address = ADDRESS; \ - ADDR_MODE_2_WRITEBACK_PRE_ ## LS (WRITEBACK); \ - BODY; \ - ADDR_MODE_2_WRITEBACK_POST_ ## LS (WRITEBACK);) - -#define DEFINE_LOAD_STORE_INSTRUCTION_SHIFTER_ARM(NAME, SHIFTER, LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME, ADDR_MODE_2_RN, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(-, SHIFTER)), LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## U, ADDR_MODE_2_RN, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(+, SHIFTER)), LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## P, ADDR_MODE_2_INDEX(-, SHIFTER), , LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## PW, ADDR_MODE_2_INDEX(-, SHIFTER), ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_ADDRESS), LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## PU, ADDR_MODE_2_INDEX(+, SHIFTER), , LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## PUW, ADDR_MODE_2_INDEX(+, SHIFTER), ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_ADDRESS), LS, BODY) - -#define DEFINE_LOAD_STORE_INSTRUCTION_ARM(NAME, LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_SHIFTER_ARM(NAME ## _LSL_, ADDR_MODE_2_LSL, LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_SHIFTER_ARM(NAME ## _LSR_, ADDR_MODE_2_LSR, LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_SHIFTER_ARM(NAME ## _ASR_, ADDR_MODE_2_ASR, LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_SHIFTER_ARM(NAME ## _ROR_, ADDR_MODE_2_ROR, LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## I, ADDR_MODE_2_RN, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(-, ADDR_MODE_2_IMMEDIATE)), LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IU, ADDR_MODE_2_RN, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(+, ADDR_MODE_2_IMMEDIATE)), LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IP, ADDR_MODE_2_INDEX(-, ADDR_MODE_2_IMMEDIATE), , LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IPW, ADDR_MODE_2_INDEX(-, ADDR_MODE_2_IMMEDIATE), ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_ADDRESS), LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IPU, ADDR_MODE_2_INDEX(+, ADDR_MODE_2_IMMEDIATE), , LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IPUW, ADDR_MODE_2_INDEX(+, ADDR_MODE_2_IMMEDIATE), ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_ADDRESS), LS, BODY) \ - -#define DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(NAME, LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME, ADDR_MODE_3_RN, ADDR_MODE_3_WRITEBACK(ADDR_MODE_3_INDEX(-, ADDR_MODE_3_RM)), LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## U, ADDR_MODE_3_RN, ADDR_MODE_3_WRITEBACK(ADDR_MODE_3_INDEX(+, ADDR_MODE_3_RM)), LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## P, ADDR_MODE_3_INDEX(-, ADDR_MODE_3_RM), , LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## PW, ADDR_MODE_3_INDEX(-, ADDR_MODE_3_RM), ADDR_MODE_3_WRITEBACK(ADDR_MODE_3_ADDRESS), LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## PU, ADDR_MODE_3_INDEX(+, ADDR_MODE_3_RM), , LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## PUW, ADDR_MODE_3_INDEX(+, ADDR_MODE_3_RM), ADDR_MODE_3_WRITEBACK(ADDR_MODE_3_ADDRESS), LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## I, ADDR_MODE_3_RN, ADDR_MODE_3_WRITEBACK(ADDR_MODE_3_INDEX(-, ADDR_MODE_3_IMMEDIATE)), LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IU, ADDR_MODE_3_RN, ADDR_MODE_3_WRITEBACK(ADDR_MODE_3_INDEX(+, ADDR_MODE_3_IMMEDIATE)), LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IP, ADDR_MODE_3_INDEX(-, ADDR_MODE_3_IMMEDIATE), , LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IPW, ADDR_MODE_3_INDEX(-, ADDR_MODE_3_IMMEDIATE), ADDR_MODE_3_WRITEBACK(ADDR_MODE_3_ADDRESS), LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IPU, ADDR_MODE_3_INDEX(+, ADDR_MODE_3_IMMEDIATE), , LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IPUW, ADDR_MODE_3_INDEX(+, ADDR_MODE_3_IMMEDIATE), ADDR_MODE_3_WRITEBACK(ADDR_MODE_3_ADDRESS), LS, BODY) \ - -#define DEFINE_LOAD_STORE_T_INSTRUCTION_SHIFTER_ARM(NAME, SHIFTER, LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME, SHIFTER, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(-, ADDR_MODE_2_RM)), LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## U, SHIFTER, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(+, ADDR_MODE_2_RM)), LS, BODY) \ - -#define DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(NAME, LS, BODY) \ - DEFINE_LOAD_STORE_T_INSTRUCTION_SHIFTER_ARM(NAME ## _LSL_, ADDR_MODE_2_LSL, LS, BODY) \ - DEFINE_LOAD_STORE_T_INSTRUCTION_SHIFTER_ARM(NAME ## _LSR_, ADDR_MODE_2_LSR, LS, BODY) \ - DEFINE_LOAD_STORE_T_INSTRUCTION_SHIFTER_ARM(NAME ## _ASR_, ADDR_MODE_2_ASR, LS, BODY) \ - DEFINE_LOAD_STORE_T_INSTRUCTION_SHIFTER_ARM(NAME ## _ROR_, ADDR_MODE_2_ROR, LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## I, ADDR_MODE_2_RN, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(-, ADDR_MODE_2_IMMEDIATE)), LS, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IU, ADDR_MODE_2_RN, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(+, ADDR_MODE_2_IMMEDIATE)), LS, BODY) \ - -#define ARM_MS_PRE(IS_LOAD) \ - enum PrivilegeMode privilegeMode = cpu->privilegeMode; \ - if (!(opcode & 0x8000) || !IS_LOAD) ARMSetPrivilegeMode(cpu, MODE_USER); - -#define ARM_MS_POST(IS_LOAD) \ - ARMSetPrivilegeMode(cpu, privilegeMode); \ - if (IS_LOAD && (opcode & 0x8000)) { \ - cpu->cpsr.packed = cpu->spsr.packed;\ - ARMSetPrivilegeMode(cpu, cpu->cpsr.priv);\ - } - -#define DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME, LS, WRITEBACK, S_PRE, S_POST, DIRECTION, POST_BODY) \ - DEFINE_INSTRUCTION_ARM(NAME, \ - int rn = (opcode >> 16) & 0xF; \ - int rs = opcode & 0x0000FFFF; \ - uint32_t address = cpu->gprs[rn]; \ - S_PRE; \ - address = cpu->memory. LS ## Multiple(cpu, address, rs, LSM_ ## DIRECTION, ¤tCycles); \ - POST_BODY; \ - WRITEBACK; \ - S_POST; \ - ) - - -#define DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_ARM(NAME, LS, IS_LOAD, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## DA, LS, , , , DA, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## DAW, LS, ADDR_MODE_4_WRITEBACK_ ## NAME, , , DA, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## DB, LS, , , , DB, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## DBW, LS, ADDR_MODE_4_WRITEBACK_ ## NAME, , , DB, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## IA, LS, , , , IA, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## IAW, LS, ADDR_MODE_4_WRITEBACK_ ## NAME, , , IA, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## IB, LS, , , , IB, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## IBW, LS, ADDR_MODE_4_WRITEBACK_ ## NAME, , , IB, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SDA, LS, , ARM_MS_PRE(IS_LOAD), ARM_MS_POST(IS_LOAD), DA, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SDAW, LS, ADDR_MODE_4_WRITEBACK_ ## NAME, ARM_MS_PRE(IS_LOAD), ARM_MS_POST(IS_LOAD), DA, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SDB, LS, , ARM_MS_PRE(IS_LOAD), ARM_MS_POST(IS_LOAD), DB, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SDBW, LS, ADDR_MODE_4_WRITEBACK_ ## NAME, ARM_MS_PRE(IS_LOAD), ARM_MS_POST(IS_LOAD), DB, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SIA, LS, , ARM_MS_PRE(IS_LOAD), ARM_MS_POST(IS_LOAD), IA, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SIAW, LS, ADDR_MODE_4_WRITEBACK_ ## NAME, ARM_MS_PRE(IS_LOAD), ARM_MS_POST(IS_LOAD), IA, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SIB, LS, , ARM_MS_PRE(IS_LOAD), ARM_MS_POST(IS_LOAD), IB, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SIBW, LS, ADDR_MODE_4_WRITEBACK_ ## NAME, ARM_MS_PRE(IS_LOAD), ARM_MS_POST(IS_LOAD), IB, POST_BODY) - -// Begin ALU definitions - -DEFINE_ALU_INSTRUCTION_ARM(ADD, ARM_ADDITION_S(n, cpu->shifterOperand, cpu->gprs[rd]), - int32_t n = cpu->gprs[rn]; - cpu->gprs[rd] = n + cpu->shifterOperand;) - -DEFINE_ALU_INSTRUCTION_ARM(ADC, ARM_ADDITION_S(n, cpu->shifterOperand, cpu->gprs[rd]), - int32_t n = cpu->gprs[rn]; - cpu->gprs[rd] = n + cpu->shifterOperand + cpu->cpsr.c;) - -DEFINE_ALU_INSTRUCTION_ARM(AND, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), - cpu->gprs[rd] = cpu->gprs[rn] & cpu->shifterOperand;) - -DEFINE_ALU_INSTRUCTION_ARM(BIC, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), - cpu->gprs[rd] = cpu->gprs[rn] & ~cpu->shifterOperand;) - -DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(CMN, ARM_ADDITION_S(cpu->gprs[rn], cpu->shifterOperand, aluOut), - int32_t aluOut = cpu->gprs[rn] + cpu->shifterOperand;) - -DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(CMP, ARM_SUBTRACTION_S(cpu->gprs[rn], cpu->shifterOperand, aluOut), - int32_t aluOut = cpu->gprs[rn] - cpu->shifterOperand;) - -DEFINE_ALU_INSTRUCTION_ARM(EOR, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), - cpu->gprs[rd] = cpu->gprs[rn] ^ cpu->shifterOperand;) - -DEFINE_ALU_INSTRUCTION_ARM(MOV, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), - cpu->gprs[rd] = cpu->shifterOperand;) - -DEFINE_ALU_INSTRUCTION_ARM(MVN, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), - cpu->gprs[rd] = ~cpu->shifterOperand;) - -DEFINE_ALU_INSTRUCTION_ARM(ORR, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), - cpu->gprs[rd] = cpu->gprs[rn] | cpu->shifterOperand;) - -DEFINE_ALU_INSTRUCTION_ARM(RSB, ARM_SUBTRACTION_S(cpu->shifterOperand, n, cpu->gprs[rd]), - int32_t n = cpu->gprs[rn]; - cpu->gprs[rd] = cpu->shifterOperand - n;) - -DEFINE_ALU_INSTRUCTION_ARM(RSC, ARM_SUBTRACTION_CARRY_S(cpu->shifterOperand, n, cpu->gprs[rd], !cpu->cpsr.c), - int32_t n = cpu->gprs[rn]; - cpu->gprs[rd] = cpu->shifterOperand - n - !cpu->cpsr.c;) - -DEFINE_ALU_INSTRUCTION_ARM(SBC, ARM_SUBTRACTION_CARRY_S(n, cpu->shifterOperand, cpu->gprs[rd], !cpu->cpsr.c), - int32_t n = cpu->gprs[rn]; - cpu->gprs[rd] = n - cpu->shifterOperand - !cpu->cpsr.c;) - -DEFINE_ALU_INSTRUCTION_ARM(SUB, ARM_SUBTRACTION_S(n, cpu->shifterOperand, cpu->gprs[rd]), - int32_t n = cpu->gprs[rn]; - cpu->gprs[rd] = n - cpu->shifterOperand;) - -DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(TEQ, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, aluOut), - int32_t aluOut = cpu->gprs[rn] ^ cpu->shifterOperand;) - -DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(TST, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, aluOut), - int32_t aluOut = cpu->gprs[rn] & cpu->shifterOperand;) - -// End ALU definitions - -// Begin multiply definitions - -DEFINE_MULTIPLY_INSTRUCTION_2_ARM(MLA, cpu->gprs[rdHi] = cpu->gprs[rm] * cpu->gprs[rs] + cpu->gprs[rd], ARM_NEUTRAL_S(, , cpu->gprs[rdHi]), 2) -DEFINE_MULTIPLY_INSTRUCTION_ARM(MUL, cpu->gprs[rd] = cpu->gprs[rm] * cpu->gprs[rs], ARM_NEUTRAL_S(cpu->gprs[rm], cpu->gprs[rs], cpu->gprs[rd])) - -DEFINE_MULTIPLY_INSTRUCTION_2_ARM(SMLAL, - int64_t d = ((int64_t) cpu->gprs[rm]) * ((int64_t) cpu->gprs[rs]); - int32_t dm = cpu->gprs[rd]; - int32_t dn = d; - cpu->gprs[rd] = dm + dn; - cpu->gprs[rdHi] = cpu->gprs[rdHi] + (d >> 32) + ARM_CARRY_FROM(dm, dn, cpu->gprs[rd]);, - ARM_NEUTRAL_HI_S(cpu->gprs[rd], cpu->gprs[rdHi]), 3) - -DEFINE_MULTIPLY_INSTRUCTION_2_ARM(SMULL, - int64_t d = ((int64_t) cpu->gprs[rm]) * ((int64_t) cpu->gprs[rs]); - cpu->gprs[rd] = d; - cpu->gprs[rdHi] = d >> 32;, - ARM_NEUTRAL_HI_S(cpu->gprs[rd], cpu->gprs[rdHi]), 2) - -DEFINE_MULTIPLY_INSTRUCTION_2_ARM(UMLAL, - uint64_t d = ARM_UXT_64(cpu->gprs[rm]) * ARM_UXT_64(cpu->gprs[rs]); - int32_t dm = cpu->gprs[rd]; - int32_t dn = d; - cpu->gprs[rd] = dm + dn; - cpu->gprs[rdHi] = cpu->gprs[rdHi] + (d >> 32) + ARM_CARRY_FROM(dm, dn, cpu->gprs[rd]);, - ARM_NEUTRAL_HI_S(cpu->gprs[rd], cpu->gprs[rdHi]), 3) - -DEFINE_MULTIPLY_INSTRUCTION_2_ARM(UMULL, - uint64_t d = ARM_UXT_64(cpu->gprs[rm]) * ARM_UXT_64(cpu->gprs[rs]); - cpu->gprs[rd] = d; - cpu->gprs[rdHi] = d >> 32;, - ARM_NEUTRAL_HI_S(cpu->gprs[rd], cpu->gprs[rdHi]), 2) - -// End multiply definitions - -// Begin load/store definitions - -DEFINE_LOAD_STORE_INSTRUCTION_ARM(LDR, LOAD, cpu->gprs[rd] = cpu->memory.load32(cpu, address, ¤tCycles); ARM_LOAD_POST_BODY;) -DEFINE_LOAD_STORE_INSTRUCTION_ARM(LDRB, LOAD, cpu->gprs[rd] = cpu->memory.load8(cpu, address, ¤tCycles); ARM_LOAD_POST_BODY;) -DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(LDRH, LOAD, cpu->gprs[rd] = cpu->memory.load16(cpu, address, ¤tCycles); ARM_LOAD_POST_BODY;) -DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(LDRSB, LOAD, cpu->gprs[rd] = ARM_SXT_8(cpu->memory.load8(cpu, address, ¤tCycles)); ARM_LOAD_POST_BODY;) -DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(LDRSH, LOAD, cpu->gprs[rd] = address & 1 ? ARM_SXT_8(cpu->memory.load16(cpu, address, ¤tCycles)) : ARM_SXT_16(cpu->memory.load16(cpu, address, ¤tCycles)); ARM_LOAD_POST_BODY;) -DEFINE_LOAD_STORE_INSTRUCTION_ARM(STR, STORE, cpu->memory.store32(cpu, address, cpu->gprs[rd], ¤tCycles); ARM_STORE_POST_BODY;) -DEFINE_LOAD_STORE_INSTRUCTION_ARM(STRB, STORE, cpu->memory.store8(cpu, address, cpu->gprs[rd], ¤tCycles); ARM_STORE_POST_BODY;) -DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(STRH, STORE, cpu->memory.store16(cpu, address, cpu->gprs[rd], ¤tCycles); ARM_STORE_POST_BODY;) - -DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(LDRBT, LOAD, - enum PrivilegeMode priv = cpu->privilegeMode; - ARMSetPrivilegeMode(cpu, MODE_USER); - int32_t r = cpu->memory.load8(cpu, address, ¤tCycles); - ARMSetPrivilegeMode(cpu, priv); - cpu->gprs[rd] = r; - ARM_LOAD_POST_BODY;) - -DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(LDRT, LOAD, - enum PrivilegeMode priv = cpu->privilegeMode; - ARMSetPrivilegeMode(cpu, MODE_USER); - int32_t r = cpu->memory.load32(cpu, address, ¤tCycles); - ARMSetPrivilegeMode(cpu, priv); - cpu->gprs[rd] = r; - ARM_LOAD_POST_BODY;) - -DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(STRBT, STORE, - enum PrivilegeMode priv = cpu->privilegeMode; - int32_t r = cpu->gprs[rd]; - ARMSetPrivilegeMode(cpu, MODE_USER); - cpu->memory.store8(cpu, address, r, ¤tCycles); - ARMSetPrivilegeMode(cpu, priv); - ARM_STORE_POST_BODY;) - -DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(STRT, STORE, - enum PrivilegeMode priv = cpu->privilegeMode; - int32_t r = cpu->gprs[rd]; - ARMSetPrivilegeMode(cpu, MODE_USER); - cpu->memory.store32(cpu, address, r, ¤tCycles); - ARMSetPrivilegeMode(cpu, priv); - ARM_STORE_POST_BODY;) - -DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_ARM(LDM, - load, true, - currentCycles += cpu->memory.activeNonseqCycles32 - cpu->memory.activeSeqCycles32; - if ((rs & 0x8000) || !rs) { - currentCycles += ARMWritePC(cpu); - }) - -DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_ARM(STM, - store, false, - ARM_STORE_POST_BODY;) - -DEFINE_INSTRUCTION_ARM(SWP, - int rm = opcode & 0xF; - int rd = (opcode >> 12) & 0xF; - int rn = (opcode >> 16) & 0xF; - int32_t d = cpu->memory.load32(cpu, cpu->gprs[rn], ¤tCycles); - cpu->memory.store32(cpu, cpu->gprs[rn], cpu->gprs[rm], ¤tCycles); - cpu->gprs[rd] = d;) - -DEFINE_INSTRUCTION_ARM(SWPB, - int rm = opcode & 0xF; - int rd = (opcode >> 12) & 0xF; - int rn = (opcode >> 16) & 0xF; - int32_t d = cpu->memory.load8(cpu, cpu->gprs[rn], ¤tCycles); - cpu->memory.store8(cpu, cpu->gprs[rn], cpu->gprs[rm], ¤tCycles); - cpu->gprs[rd] = d;) - -// End load/store definitions - -// Begin branch definitions - -DEFINE_INSTRUCTION_ARM(B, - int32_t offset = opcode << 8; - offset >>= 6; - cpu->gprs[ARM_PC] += offset; - currentCycles += ARMWritePC(cpu);) - -DEFINE_INSTRUCTION_ARM(BL, - int32_t immediate = (opcode & 0x00FFFFFF) << 8; - cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - 4; - cpu->gprs[ARM_PC] += immediate >> 6; - currentCycles += ARMWritePC(cpu);) - -DEFINE_INSTRUCTION_ARM(BX, - int rm = opcode & 0x0000000F; - cpu->gprs[ARM_PC] = cpu->gprs[rm] & 0xFFFFFFFE; - currentCycles += ARMWritePC(cpu); - ) - -// End branch definitions - -// Begin coprocessor definitions - -DEFINE_INSTRUCTION_ARM(CDP, ARM_STUB) -DEFINE_INSTRUCTION_ARM(LDC, ARM_STUB) -DEFINE_INSTRUCTION_ARM(STC, ARM_STUB) -DEFINE_INSTRUCTION_ARM(MCR, ARM_STUB) -DEFINE_INSTRUCTION_ARM(MRC, ARM_STUB) - -// Begin miscellaneous definitions - -DEFINE_INSTRUCTION_ARM(BKPT, cpu->irqh.bkpt32(cpu, ((opcode >> 4) & 0xFFF0) | (opcode & 0xF))); // Not strictly in ARMv4T, but here for convenience -DEFINE_INSTRUCTION_ARM(ILL, ARM_ILL) // Illegal opcode - -DEFINE_INSTRUCTION_ARM(MSR, - int c = opcode & 0x00010000; - int f = opcode & 0x00080000; - int32_t operand = cpu->gprs[opcode & 0x0000000F]; - int32_t mask = (c ? 0x000000FF : 0) | (f ? 0xFF000000 : 0); - if (mask & PSR_USER_MASK) { - cpu->cpsr.packed = (cpu->cpsr.packed & ~PSR_USER_MASK) | (operand & PSR_USER_MASK); - } - if (mask & PSR_STATE_MASK) { - cpu->cpsr.packed = (cpu->cpsr.packed & ~PSR_STATE_MASK) | (operand & PSR_STATE_MASK); - } - if (cpu->privilegeMode != MODE_USER && (mask & PSR_PRIV_MASK)) { - ARMSetPrivilegeMode(cpu, (enum PrivilegeMode) ((operand & 0x0000000F) | 0x00000010)); - cpu->cpsr.packed = (cpu->cpsr.packed & ~PSR_PRIV_MASK) | (operand & PSR_PRIV_MASK); - } - _ARMReadCPSR(cpu); - // LOAD_32(cpu->prefetch[0], (cpu->gprs[ARM_PC] - 4) & cpu->memory.activeMask, cpu->memory.activeRegion); - // LOAD_32(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion); - cpu->prefetch[0] = cpu->memory.load32(cpu, cpu->gprs[ARM_PC] - 4, NULL); - cpu->prefetch[1] = cpu->memory.load32(cpu, cpu->gprs[ARM_PC], NULL); - ) - -DEFINE_INSTRUCTION_ARM(MSRR, - int c = opcode & 0x00010000; - int f = opcode & 0x00080000; - int32_t operand = cpu->gprs[opcode & 0x0000000F]; - int32_t mask = (c ? 0x000000FF : 0) | (f ? 0xFF000000 : 0); - mask &= PSR_USER_MASK | PSR_PRIV_MASK | PSR_STATE_MASK; - cpu->spsr.packed = (cpu->spsr.packed & ~mask) | (operand & mask) | 0x00000010;) - -DEFINE_INSTRUCTION_ARM(MRS, \ - int rd = (opcode >> 12) & 0xF; \ - cpu->gprs[rd] = cpu->cpsr.packed;) - -DEFINE_INSTRUCTION_ARM(MRSR, \ - int rd = (opcode >> 12) & 0xF; \ - cpu->gprs[rd] = cpu->spsr.packed;) - -DEFINE_INSTRUCTION_ARM(MSRI, - int c = opcode & 0x00010000; - int f = opcode & 0x00080000; - int rotate = (opcode & 0x00000F00) >> 7; - int32_t operand = ROR(opcode & 0x000000FF, rotate); - int32_t mask = (c ? 0x000000FF : 0) | (f ? 0xFF000000 : 0); - if (mask & PSR_USER_MASK) { - cpu->cpsr.packed = (cpu->cpsr.packed & ~PSR_USER_MASK) | (operand & PSR_USER_MASK); - } - if (mask & PSR_STATE_MASK) { - cpu->cpsr.packed = (cpu->cpsr.packed & ~PSR_STATE_MASK) | (operand & PSR_STATE_MASK); - } - if (cpu->privilegeMode != MODE_USER && (mask & PSR_PRIV_MASK)) { - ARMSetPrivilegeMode(cpu, (enum PrivilegeMode) ((operand & 0x0000000F) | 0x00000010)); - cpu->cpsr.packed = (cpu->cpsr.packed & ~PSR_PRIV_MASK) | (operand & PSR_PRIV_MASK); - } - _ARMReadCPSR(cpu); - // LOAD_32(cpu->prefetch[0], (cpu->gprs[ARM_PC] - 4) & cpu->memory.activeMask, cpu->memory.activeRegion); - // LOAD_32(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion); - cpu->prefetch[0] = cpu->memory.load32(cpu, cpu->gprs[ARM_PC] - 4, NULL); - cpu->prefetch[1] = cpu->memory.load32(cpu, cpu->gprs[ARM_PC], NULL); - ) - -DEFINE_INSTRUCTION_ARM(MSRRI, - int c = opcode & 0x00010000; - int f = opcode & 0x00080000; - int rotate = (opcode & 0x00000F00) >> 7; - int32_t operand = ROR(opcode & 0x000000FF, rotate); - int32_t mask = (c ? 0x000000FF : 0) | (f ? 0xFF000000 : 0); - mask &= PSR_USER_MASK | PSR_PRIV_MASK | PSR_STATE_MASK; - cpu->spsr.packed = (cpu->spsr.packed & ~mask) | (operand & mask) | 0x00000010;) - -DEFINE_INSTRUCTION_ARM(SWI, cpu->irqh.swi32(cpu, opcode & 0xFFFFFF)) - -const ARMInstruction _armTable[0x1000] = { - DECLARE_ARM_EMITTER_BLOCK(_ARMInstruction) -}; diff --git a/WindCore/isa-inlines.h b/WindCore/isa-inlines.h index 2e2ab66..d13aabe 100644 --- a/WindCore/isa-inlines.h +++ b/WindCore/isa-inlines.h @@ -8,24 +8,6 @@ #include "macros.h" -#include "arm.h" - -#define ARM_COND_EQ (cpu->cpsr.z) -#define ARM_COND_NE (!cpu->cpsr.z) -#define ARM_COND_CS (cpu->cpsr.c) -#define ARM_COND_CC (!cpu->cpsr.c) -#define ARM_COND_MI (cpu->cpsr.n) -#define ARM_COND_PL (!cpu->cpsr.n) -#define ARM_COND_VS (cpu->cpsr.v) -#define ARM_COND_VC (!cpu->cpsr.v) -#define ARM_COND_HI (cpu->cpsr.c && !cpu->cpsr.z) -#define ARM_COND_LS (!cpu->cpsr.c || cpu->cpsr.z) -#define ARM_COND_GE (!cpu->cpsr.n == !cpu->cpsr.v) -#define ARM_COND_LT (!cpu->cpsr.n != !cpu->cpsr.v) -#define ARM_COND_GT (!cpu->cpsr.z && !cpu->cpsr.n == !cpu->cpsr.v) -#define ARM_COND_LE (cpu->cpsr.z || !cpu->cpsr.n != !cpu->cpsr.v) -#define ARM_COND_AL 1 - #define ARM_SIGN(I) ((I) >> 31) #define ARM_SXT_8(I) (((int8_t) (I) << 24) >> 24) #define ARM_SXT_16(I) (((int16_t) (I) << 16) >> 16) @@ -37,46 +19,4 @@ #define ARM_V_ADDITION(M, N, D) (!(ARM_SIGN((M) ^ (N))) && (ARM_SIGN((M) ^ (D)))) #define ARM_V_SUBTRACTION(M, N, D) ((ARM_SIGN((M) ^ (N))) && (ARM_SIGN((M) ^ (D)))) -#define ARM_WAIT_MUL(R) \ - { \ - int32_t wait; \ - if ((R & 0xFFFFFF00) == 0xFFFFFF00 || !(R & 0xFFFFFF00)) { \ - wait = 1; \ - } else if ((R & 0xFFFF0000) == 0xFFFF0000 || !(R & 0xFFFF0000)) { \ - wait = 2; \ - } else if ((R & 0xFF000000) == 0xFF000000 || !(R & 0xFF000000)) { \ - wait = 3; \ - } else { \ - wait = 4; \ - } \ - currentCycles += cpu->memory.stall(cpu, wait); \ - } - -#define ARM_STUB cpu->irqh.hitStub(cpu, opcode) -#define ARM_ILL cpu->irqh.hitIllegal(cpu, opcode) - -static inline int32_t ARMWritePC(struct ARMCore* cpu) { - cpu->gprs[ARM_PC] = (cpu->gprs[ARM_PC] & -4); - // cpu->memory.setActiveRegion(cpu, cpu->gprs[ARM_PC]); - // LOAD_32(cpu->prefetch[0], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion); - cpu->prefetch[0] = cpu->memory.load32(cpu, cpu->gprs[ARM_PC], NULL); - cpu->gprs[ARM_PC] += 4; - // LOAD_32(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion); - cpu->prefetch[1] = cpu->memory.load32(cpu, cpu->gprs[ARM_PC], NULL); - return 2 + cpu->memory.activeNonseqCycles32 + cpu->memory.activeSeqCycles32; -} - -static inline int _ARMModeHasSPSR(enum PrivilegeMode mode) { - return mode != MODE_SYSTEM && mode != MODE_USER; -} - -static inline void _ARMReadCPSR(struct ARMCore* cpu) { - ARMSetPrivilegeMode(cpu, cpu->cpsr.priv); - cpu->irqh.readCPSR(cpu); -} - -static inline uint32_t _ARMPCAddress(struct ARMCore* cpu) { - return cpu->gprs[ARM_PC] - 4 * 2; -} - #endif diff --git a/WindCore/wind_defs.cpp b/WindCore/wind_defs.cpp deleted file mode 100644 index c6b56d2..0000000 --- a/WindCore/wind_defs.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "wind_defs.h" -#include - -void windDiffPorts(uint32_t oldval, uint32_t newval) { - uint32_t changes = oldval ^ newval; - if (changes & 1) printf("PRT codec enable: %d\n", newval&1); - if (changes & 2) printf("PRT audio amp enable: %d\n", newval&2); - if (changes & 4) printf("PRT lcd power: %d\n", newval&4); - if (changes & 8) printf("PRT etna door: %d\n", newval&8); - if (changes & 0x10) printf("PRT sled: %d\n", newval&0x10); - if (changes & 0x20) printf("PRT pump pwr2: %d\n", newval&0x20); - if (changes & 0x40) printf("PRT pump pwr1: %d\n", newval&0x40); - if (changes & 0x80) printf("PRT etna err: %d\n", newval&0x80); - if (changes & 0x100) printf("PRT rs-232 rts: %d\n", newval&0x100); - if (changes & 0x200) printf("PRT rs-232 dtr toggle: %d\n", newval&0x200); - if (changes & 0x400) printf("PRT disable power led: %d\n", newval&0x400); - if (changes & 0x800) printf("PRT enable uart1: %d\n", newval&0x800); - if (changes & 0x1000) printf("PRT lcd backlight: %d\n", newval&0x1000); - if (changes & 0x2000) printf("PRT enable uart0: %d\n", newval&0x2000); - if (changes & 0x4000) printf("PRT dictaphone: %d\n", newval&0x4000); -// PROM read process makes this super spammy in stdout -// if (changes & 0x10000) printf("PRT EECS: %d\n", newval&0x10000); -// if (changes & 0x20000) printf("PRT EECLK: %d\n", newval&0x20000); - if (changes & 0x40000) printf("PRT contrast0: %d\n", newval&0x40000); - if (changes & 0x80000) printf("PRT contrast1: %d\n", newval&0x80000); - if (changes & 0x100000) printf("PRT contrast2: %d\n", newval&0x100000); - if (changes & 0x200000) printf("PRT contrast3: %d\n", newval&0x200000); - if (changes & 0x400000) printf("PRT case open: %d\n", newval&0x400000); - if (changes & 0x800000) printf("PRT etna cf power: %d\n", newval&0x800000); - if (changes & 0x1000000) printf("PRT kb0: %d\n", newval&0x1000000); - if (changes & 0x2000000) printf("PRT kb1: %d\n", newval&0x2000000); - if (changes & 0x4000000) printf("PRT kb2: %d\n", newval&0x4000000); - if (changes & 0x8000000) printf("PRT kb3: %d\n", newval&0x8000000); - if (changes & 0x10000000) printf("PRT kb4: %d\n", newval&0x10000000); - if (changes & 0x20000000) printf("PRT kb5: %d\n", newval&0x20000000); - if (changes & 0x40000000) printf("PRT kb6: %d\n", newval&0x40000000); - if (changes & 0x80000000) printf("PRT kb7: %d\n", newval&0x80000000); -} - -void windDiffInterrupts(uint16_t oldval, uint16_t newval) { - uint16_t changes = oldval ^ newval; - if (changes & 1) printf("INTCHG external=%d\n", newval & 1); - if (changes & 2) printf("INTCHG lowbat=%d\n", newval & 2); - if (changes & 4) printf("INTCHG watchdog=%d\n", newval & 4); - if (changes & 8) printf("INTCHG mediachg=%d\n", newval & 8); - if (changes & 0x10) printf("INTCHG codec=%d\n", newval & 0x10); - if (changes & 0x20) printf("INTCHG ext1=%d\n", newval & 0x20); - if (changes & 0x40) printf("INTCHG ext2=%d\n", newval & 0x40); - if (changes & 0x80) printf("INTCHG ext3=%d\n", newval & 0x80); - if (changes & 0x100) printf("INTCHG timer1=%d\n", newval & 0x100); - if (changes & 0x200) printf("INTCHG timer2=%d\n", newval & 0x200); - if (changes & 0x400) printf("INTCHG rtcmatch=%d\n", newval & 0x400); - if (changes & 0x800) printf("INTCHG tick=%d\n", newval & 0x800); - if (changes & 0x1000) printf("INTCHG uart1=%d\n", newval & 0x1000); - if (changes & 0x2000) printf("INTCHG uart2=%d\n", newval & 0x2000); - if (changes & 0x4000) printf("INTCHG lcd=%d\n", newval & 0x4000); - if (changes & 0x8000) printf("INTCHG spi=%d\n", newval & 0x8000); -} diff --git a/WindCore/wind_defs.h b/WindCore/wind_defs.h index c616e5f..9d74b8d 100644 --- a/WindCore/wind_defs.h +++ b/WindCore/wind_defs.h @@ -1,6 +1,7 @@ #pragma once #include +namespace Windermere { enum { CLOCK_SPEED = 0x9000*1000, TICK_INTERVAL = CLOCK_SPEED / 64 @@ -27,7 +28,7 @@ enum Interrupt { IRQ_INTERRUPTS = 0xFFF0 }; -enum WindermereReg { +enum Register { MEMCFG1 = 0, MEMCFG2 = 4, DRAM_CFG = 0x100, @@ -89,6 +90,4 @@ enum WindermereReg { KSCAN = 0xE28, LCDMUX = 0xE2C }; - -void windDiffPorts(uint32_t oldval, uint32_t newval); -void windDiffInterrupts(uint16_t oldval, uint16_t newval); +} diff --git a/WindCore/windermere.cpp b/WindCore/windermere.cpp index 898598e..7ada0c6 100644 --- a/WindCore/windermere.cpp +++ b/WindCore/windermere.cpp @@ -8,16 +8,17 @@ //#define INCLUDE_D //#define INCLUDE_BANK1 -Windermere::Windermere() : ARM710(true), etna(this) { +namespace Windermere { +Emulator::Emulator() : EmuBase(true), etna(this) { } -uint32_t Windermere::getRTC() { +uint32_t Emulator::getRTC() { return time(nullptr) - 946684800; } -uint32_t Windermere::readReg8(uint32_t reg) { +uint32_t Emulator::readReg8(uint32_t reg) { if ((reg & 0xF00) == 0x600) { return uart1.readReg8(reg & 0xFF); } else if ((reg & 0xF00) == 0x700) { @@ -27,7 +28,7 @@ uint32_t Windermere::readReg8(uint32_t reg) { } else if (reg == TC2CTRL) { return tc2.config; } else if (reg == PADR) { - return readKeyboard(); + return readKeyboard(kScan); } else if (reg == PBDR) { return (portValues >> 16) & 0xFF; } else if (reg == PCDR) { @@ -47,7 +48,7 @@ uint32_t Windermere::readReg8(uint32_t reg) { return 0xFF; } } -uint32_t Windermere::readReg32(uint32_t reg) { +uint32_t Emulator::readReg32(uint32_t reg) { if (reg == LCDCTL) { printf("LCD control read pc=%08x lr=%08x !!!\n", getGPR(15), getGPR(14)); return lcdControl; @@ -92,7 +93,7 @@ uint32_t Windermere::readReg32(uint32_t reg) { } } -void Windermere::writeReg8(uint32_t reg, uint8_t value) { +void Emulator::writeReg8(uint32_t reg, uint8_t value) { if ((reg & 0xF00) == 0x600) { uart1.writeReg8(reg & 0xFF, value); } else if ((reg & 0xF00) == 0x700) { @@ -105,7 +106,7 @@ void Windermere::writeReg8(uint32_t reg, uint8_t value) { uint32_t oldPorts = portValues; portValues &= 0x00FFFFFF; portValues |= (uint32_t)value << 24; - windDiffPorts(oldPorts, portValues); + diffPorts(oldPorts, portValues); } else if (reg == PBDR) { uint32_t oldPorts = portValues; portValues &= 0xFF00FFFF; @@ -116,17 +117,17 @@ void Windermere::writeReg8(uint32_t reg, uint8_t value) { etna.setPromBit0Low(); if ((portValues & 0x20000) && !(oldPorts & 0x20000)) etna.setPromBit1High(); - windDiffPorts(oldPorts, portValues); + diffPorts(oldPorts, portValues); } else if (reg == PCDR) { uint32_t oldPorts = portValues; portValues &= 0xFFFF00FF; portValues |= (uint32_t)value << 8; - windDiffPorts(oldPorts, portValues); + diffPorts(oldPorts, portValues); } else if (reg == PDDR) { uint32_t oldPorts = portValues; portValues &= 0xFFFFFF00; portValues |= (uint32_t)value; - windDiffPorts(oldPorts, portValues); + diffPorts(oldPorts, portValues); } else if (reg == PADDR) { portDirections &= 0x00FFFFFF; portDirections |= (uint32_t)value << 24; @@ -145,7 +146,7 @@ void Windermere::writeReg8(uint32_t reg, uint8_t value) { // printf("RegWrite8 unknown:: pc=%08x reg=%03x value=%02x\n", getGPR(15)-4, reg, value); } } -void Windermere::writeReg32(uint32_t reg, uint32_t value) { +void Emulator::writeReg32(uint32_t reg, uint32_t value) { if (reg == LCDCTL) { printf("LCD: ctl write %08x\n", value); lcdControl = value; @@ -159,10 +160,10 @@ void Windermere::writeReg32(uint32_t reg, uint32_t value) { } else if (reg == LCDT2) { printf("LCD: clocks write %08x\n", value); } else if (reg == INTENS) { -// windDiffInterrupts(interruptMask, interruptMask | value); +// diffInterrupts(interruptMask, interruptMask | value); interruptMask |= value; } else if (reg == INTENC) { -// windDiffInterrupts(interruptMask, interruptMask &~ value); +// diffInterrupts(interruptMask, interruptMask &~ value); interruptMask &= ~value; } else if (reg == HALT) { halted = true; @@ -190,21 +191,7 @@ void Windermere::writeReg32(uint32_t reg, uint32_t value) { } } -bool Windermere::isPhysAddressValid(uint32_t physAddress) const { - uint8_t region = (physAddress >> 24) & 0xF1; - switch (region) { - case 0: return true; - case 0x80: return (physAddress <= 0x80000FFF); - case 0xC0: return true; - case 0xC1: return true; - case 0xD0: return true; - case 0xD1: return true; - default: return false; - } -} - - -MaybeU32 Windermere::readPhysical(uint32_t physAddr, ValueSize valueSize) { +MaybeU32 Emulator::readPhysical(uint32_t physAddr, ValueSize valueSize) { uint8_t region = (physAddr >> 24) & 0xF1; if (valueSize == V8) { if (region == 0) @@ -273,7 +260,7 @@ MaybeU32 Windermere::readPhysical(uint32_t physAddr, ValueSize valueSize) { return {}; } -bool Windermere::writePhysical(uint32_t value, uint32_t physAddr, ValueSize valueSize) { +bool Emulator::writePhysical(uint32_t value, uint32_t physAddr, ValueSize valueSize) { uint8_t region = (physAddr >> 24) & 0xF1; if (valueSize == V8) { #if defined(INCLUDE_BANK1) @@ -336,7 +323,7 @@ bool Windermere::writePhysical(uint32_t value, uint32_t physAddr, ValueSize valu -void Windermere::configure() { +void Emulator::configure() { if (configured) return; configured = true; @@ -355,13 +342,11 @@ void Windermere::configure() { reset(); } -void Windermere::loadROM(const char *path) { - FILE *f = fopen(path, "rb"); - fread(ROM, 1, sizeof(ROM), f); - fclose(f); +void Emulator::loadROM(uint8_t *buffer, size_t size) { + memcpy(ROM, buffer, min(size, sizeof(ROM))); } -void Windermere::executeUntil(int64_t cycles) { +void Emulator::executeUntil(int64_t cycles) { if (!configured) configure(); @@ -415,26 +400,8 @@ void Windermere::executeUntil(int64_t cycles) { } } -void Windermere::dumpRAM(const char *path) { - FILE *f = fopen(path, "wb"); - fwrite(MemoryBlockC0, 1, sizeof(MemoryBlockC0), f); - fwrite(MemoryBlockC1, 1, sizeof(MemoryBlockC1), f); - fwrite(MemoryBlockD0, 1, sizeof(MemoryBlockD0), f); - fwrite(MemoryBlockD1, 1, sizeof(MemoryBlockD1), f); - fclose(f); -} - - -void Windermere::printRegs() { - printf("R00:%08x R01:%08x R02:%08x R03:%08x\n", getGPR(0), getGPR(1), getGPR(2), getGPR(3)); - printf("R04:%08x R05:%08x R06:%08x R07:%08x\n", getGPR(4), getGPR(5), getGPR(6), getGPR(7)); - printf("R08:%08x R09:%08x R10:%08x R11:%08x\n", getGPR(8), getGPR(9), getGPR(10), getGPR(11)); - printf("R12:%08x R13:%08x R14:%08x R15:%08x\n", getGPR(12), getGPR(13), getGPR(14), getGPR(15)); -// printf("cpsr=%08x spsr=%08x\n", cpu.cpsr.packed, cpu.spsr.packed); -} - -const char *Windermere::identifyObjectCon(uint32_t ptr) { +const char *Emulator::identifyObjectCon(uint32_t ptr) { if (ptr == readVirtualDebug(0x80000980, V32).value()) return "process"; if (ptr == readVirtualDebug(0x80000984, V32).value()) return "thread"; if (ptr == readVirtualDebug(0x80000988, V32).value()) return "chunk"; @@ -451,7 +418,7 @@ const char *Windermere::identifyObjectCon(uint32_t ptr) { return NULL; } -void Windermere::fetchStr(uint32_t str, char *buf) { +void Emulator::fetchStr(uint32_t str, char *buf) { if (str == 0) { strcpy(buf, ""); return; @@ -463,15 +430,15 @@ void Windermere::fetchStr(uint32_t str, char *buf) { buf[size] = 0; } -void Windermere::fetchName(uint32_t obj, char *buf) { +void Emulator::fetchName(uint32_t obj, char *buf) { fetchStr(readVirtualDebug(obj + 0x10, V32).value(), buf); } -void Windermere::fetchProcessFilename(uint32_t obj, char *buf) { +void Emulator::fetchProcessFilename(uint32_t obj, char *buf) { fetchStr(readVirtualDebug(obj + 0x3C, V32).value(), buf); } -void Windermere::debugPC(uint32_t pc) { +void Emulator::debugPC(uint32_t pc) { char objName[1000]; if (pc == 0x2CBC4) { // CObjectCon::AddL() @@ -511,28 +478,88 @@ void Windermere::debugPC(uint32_t pc) { } -const uint8_t *Windermere::getLCDBuffer() const { - if ((lcdAddress >> 24) == 0xC0) - return &MemoryBlockC0[lcdAddress & MemoryBlockMask]; - else - return nullptr; +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]; + int width = 640, height = 240; + // fetch palette + int bpp = 1 << (lcdBuf[1] >> 4); + int ppb = 8 / bpp; + uint16_t palette[16]; + for (int i = 0; i < 16; i++) + palette[i] = lcdBuf[i*2] | ((lcdBuf[i*2+1] << 8) & 0xF00); -uint8_t Windermere::readKeyboard() { - uint8_t val = 0; - if (kScan & 8) { - // Select one keyboard - int whichColumn = kScan & 7; - for (int i = 0; i < 7; i++) - if (keyboardKeys[whichColumn * 7 + i]) - val |= (1 << i); - } else if (kScan == 0) { - // Report all columns combined - // EPOC's keyboard driver relies on this... - for (int i = 0; i < 8*7; i++) - if (keyboardKeys[i]) - val |= (1 << (i % 7)); + // build our image out + int lineWidth = (width * bpp) / 8; + for (int y = 0; y < height; y++) { + int lineOffs = 0x20 + (lineWidth * y); + for (int x = 0; x < width; x++) { + uint8_t byte = lcdBuf[lineOffs + (x / ppb)]; + int shift = (x & (ppb - 1)) * bpp; + int mask = (1 << bpp) - 1; + int palIdx = (byte >> shift) & mask; + int palValue = palette[palIdx]; + + palValue |= (palValue << 4); + lines[y][x] = palValue ^ 0xFF; + } + } } - return val; +} + + +void Emulator::diffPorts(uint32_t oldval, uint32_t newval) { + uint32_t changes = oldval ^ newval; + if (changes & 1) log("PRT codec enable: %d", newval&1); + if (changes & 2) log("PRT audio amp enable: %d", newval&2); + if (changes & 4) log("PRT lcd power: %d", newval&4); + if (changes & 8) log("PRT etna door: %d", newval&8); + if (changes & 0x10) log("PRT sled: %d", newval&0x10); + if (changes & 0x20) log("PRT pump pwr2: %d", newval&0x20); + if (changes & 0x40) log("PRT pump pwr1: %d", newval&0x40); + if (changes & 0x80) log("PRT etna err: %d", newval&0x80); + if (changes & 0x100) log("PRT rs-232 rts: %d", newval&0x100); + if (changes & 0x200) log("PRT rs-232 dtr toggle: %d", newval&0x200); + if (changes & 0x400) log("PRT disable power led: %d", newval&0x400); + if (changes & 0x800) log("PRT enable uart1: %d", newval&0x800); + if (changes & 0x1000) log("PRT lcd backlight: %d", newval&0x1000); + if (changes & 0x2000) log("PRT enable uart0: %d", newval&0x2000); + if (changes & 0x4000) log("PRT dictaphone: %d", newval&0x4000); +// PROM read process makes this super spammy in stdout +// if (changes & 0x10000) log("PRT EECS: %d", newval&0x10000); +// if (changes & 0x20000) log("PRT EECLK: %d", newval&0x20000); + if (changes & 0x40000) log("PRT contrast0: %d", newval&0x40000); + if (changes & 0x80000) log("PRT contrast1: %d", newval&0x80000); + if (changes & 0x100000) log("PRT contrast2: %d", newval&0x100000); + if (changes & 0x200000) log("PRT contrast3: %d", newval&0x200000); + if (changes & 0x400000) log("PRT case open: %d", newval&0x400000); + if (changes & 0x800000) log("PRT etna cf power: %d", newval&0x800000); +} + +void Emulator::diffInterrupts(uint16_t oldval, uint16_t newval) { + uint16_t changes = oldval ^ newval; + if (changes & 1) log("INTCHG external=%d", newval & 1); + if (changes & 2) log("INTCHG lowbat=%d", newval & 2); + if (changes & 4) log("INTCHG watchdog=%d", newval & 4); + if (changes & 8) log("INTCHG mediachg=%d", newval & 8); + if (changes & 0x10) log("INTCHG codec=%d", newval & 0x10); + if (changes & 0x20) log("INTCHG ext1=%d", newval & 0x20); + if (changes & 0x40) log("INTCHG ext2=%d", newval & 0x40); + if (changes & 0x80) log("INTCHG ext3=%d", newval & 0x80); + if (changes & 0x100) log("INTCHG timer1=%d", newval & 0x100); + if (changes & 0x200) log("INTCHG timer2=%d", newval & 0x200); + if (changes & 0x400) log("INTCHG rtcmatch=%d", newval & 0x400); + if (changes & 0x800) log("INTCHG tick=%d", newval & 0x800); + if (changes & 0x1000) log("INTCHG uart1=%d", newval & 0x1000); + if (changes & 0x2000) log("INTCHG uart2=%d", newval & 0x2000); + if (changes & 0x4000) log("INTCHG lcd=%d", newval & 0x4000); + if (changes & 0x8000) log("INTCHG spi=%d", newval & 0x8000); +} } diff --git a/WindCore/windermere.h b/WindCore/windermere.h index bcbe320..dead660 100644 --- a/WindCore/windermere.h +++ b/WindCore/windermere.h @@ -1,11 +1,11 @@ #pragma once -#include "arm710.h" +#include "emubase.h" #include "wind_defs.h" #include "hardware.h" #include "etna.h" -#include -class Windermere : public ARM710 { +namespace Windermere { +class Emulator : public EmuBase { public: uint8_t ROM[0x1000000]; uint8_t ROM2[0x40000]; @@ -26,15 +26,11 @@ private: uint32_t kScan = 0; uint32_t rtc = 0; - int64_t passedCycles = 0; - int64_t nextTickAt = 0; Timer tc1, tc2; UART uart1, uart2; Etna etna; bool halted = false, asleep = false; - std::unordered_set _breakpoints; - uint32_t getRTC(); uint32_t readReg8(uint32_t reg); @@ -43,32 +39,28 @@ private: void writeReg32(uint32_t reg, uint32_t value); public: - bool isPhysAddressValid(uint32_t addr) const; MaybeU32 readPhysical(uint32_t physAddr, ValueSize valueSize) override; bool writePhysical(uint32_t value, uint32_t physAddr, ValueSize valueSize) override; - const uint8_t *getLCDBuffer() const; - private: bool configured = false; void configure(); - void printRegs(); const char *identifyObjectCon(uint32_t ptr); void fetchStr(uint32_t str, char *buf); void fetchName(uint32_t obj, char *buf); void fetchProcessFilename(uint32_t obj, char *buf); void debugPC(uint32_t pc); - - uint8_t readKeyboard(); -public: - bool keyboardKeys[8*7] = {0}; + void diffPorts(uint32_t oldval, uint32_t newval); + void diffInterrupts(uint16_t oldval, uint16_t newval); public: - Windermere(); - void loadROM(const char *path); - void dumpRAM(const char *path); - void executeUntil(int64_t cycles); - std::unordered_set &breakpoints() { return _breakpoints; } - uint64_t currentCycles() const { return passedCycles; } + Emulator(); + void loadROM(uint8_t *buffer, size_t size) override; + void executeUntil(int64_t cycles) override; + int32_t getClockSpeed() const override { return CLOCK_SPEED; } + int getLCDWidth() const override; + int getLCDHeight() const override; + void readLCDIntoBuffer(uint8_t **lines) const override; }; +} diff --git a/WindQt/main.cpp b/WindQt/main.cpp index b48f94e..b0012bc 100644 --- a/WindQt/main.cpp +++ b/WindQt/main.cpp @@ -1,10 +1,58 @@ #include "mainwindow.h" #include +#include +#include +#include "../WindCore/clps7111.h" +#include "../WindCore/windermere.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); - MainWindow w; + auto args = a.arguments(); + + QString romFile; + if (args.length() > 1) + romFile = args.first(); + else + romFile = QFileDialog::getOpenFileName(nullptr, "Select a ROM"); + if (romFile.isNull()) return 0; + + // what do we have? + QFile f(romFile); + f.open(QFile::ReadOnly); + auto buffer = f.readAll(); + f.close(); + + if (buffer.size() < 0x400000) { + QMessageBox::critical(nullptr, "WindEmu", "Invalid ROM file!"); + return 0; + } + + EmuBase *emu = nullptr; + uint8_t *romData = (uint8_t *)buffer.data(); + + // parse this ROM to learn what hardware it's for + int variantFile = *((uint32_t *)&romData[0x80 + 0x4C]) & 0xFFFFFFF; + if (variantFile < (buffer.size() - 8)) { + int variantImg = *((uint32_t *)&romData[variantFile + 4]) & 0xFFFFFFF; + if (variantImg < (buffer.size() - 0x70)) { + int variant = *((uint32_t *)&romData[variantImg + 0x60]); + + if (variant == 0x7060001) { + // 5mx ROM + emu = new Windermere::Emulator; + } else if (variant == 0x5040001) { + // Osaris ROM + emu = new CLPS7111::Emulator; + } else { + QMessageBox::critical(nullptr, "WindEmu", "Unrecognised ROM file!"); + return 0; + } + } + } + + emu->loadROM(romData, buffer.size()); + MainWindow w(emu); w.show(); return a.exec(); diff --git a/WindQt/mainwindow.cpp b/WindQt/mainwindow.cpp index 16085df..01e07a0 100644 --- a/WindQt/mainwindow.cpp +++ b/WindQt/mainwindow.cpp @@ -1,19 +1,17 @@ #include "mainwindow.h" #include "ui_mainwindow.h" -#include "../WindCore/clps7111_defs.h" #include #include #include "../WindCore/decoder.h" -MainWindow::MainWindow(QWidget *parent) : +MainWindow::MainWindow(EmuBase *emu, QWidget *parent) : QMainWindow(parent), - ui(new Ui::MainWindow) + ui(new Ui::MainWindow), + emu(emu) { ui->setupUi(this); ui->logView->setMaximumBlockCount(1000); - emu = new CLPS7111; - emu->loadROM("/Users/ash/src/psion/Osaris.bin"); emu->setLogger([&](const char *str) { ui->logView->appendPlainText(str); }); @@ -102,68 +100,13 @@ void MainWindow::updateScreen() ui->codeLabel->setText(codeLines.join('\n')); // now, the actual screen - const uint8_t *lcdBuf = emu->getLCDBuffer(); - if (lcdBuf) { -#if 0 - QImage img(640, 240, QImage::Format_Grayscale8); + 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); - // fetch palette - int bpp = 1 << (lcdBuf[1] >> 4); - int ppb = 8 / bpp; - uint16_t palette[16]; - for (int i = 0; i < 16; i++) - palette[i] = lcdBuf[i*2] | ((lcdBuf[i*2+1] << 8) & 0xF00); - - // build our image out - int lineWidth = (img.width() * bpp) / 8; - for (int y = 0; y < img.height(); y++) { - uint8_t *scanline = img.scanLine(y); - int lineOffs = 0x20 + (lineWidth * y); - for (int x = 0; x < img.width(); x++) { - uint8_t byte = lcdBuf[lineOffs + (x / ppb)]; - int shift = (x & (ppb - 1)) * bpp; - int mask = (1 << bpp) - 1; - int palIdx = (byte >> shift) & mask; - int palValue = palette[palIdx]; - - palValue |= (palValue << 4); - scanline[x] = palValue ^ 0xFF; - } - } -#else - QImage img(320, 200, QImage::Format_Grayscale8); - - uint32_t lcdControl = emu->getLCDControl(); - uint64_t lcdPalette = emu->getLCDPalette(); - int bpp = 1; - if (lcdControl & 0x40000000) bpp = 2; - if (lcdControl & 0x80000000) bpp = 4; - int ppb = 8 / bpp; - - // build our image out - int lineWidth = (img.width() * bpp) / 8; - for (int y = 0; y < img.height(); y++) { - uint8_t *scanline = img.scanLine(y); - int lineOffs = lineWidth * y; - for (int x = 0; x < img.width(); x++) { - uint8_t byte = lcdBuf[lineOffs + (x / ppb)]; - int shift = (x & (ppb - 1)) * bpp; - int mask = (1 << bpp) - 1; - int palIdx = (byte >> shift) & mask; - int palValue; - if (bpp == 1) - palValue = palIdx * 255; - else - palValue = (lcdPalette >> (palIdx * 4)) & 0xF; - - palValue |= (palValue << 4); - scanline[x] = palValue ^ 0xFF; - } - } -#endif - - ui->screen->setPixmap(QPixmap::fromImage(std::move(img))); - } + ui->screen->setPixmap(QPixmap::fromImage(std::move(img))); } @@ -296,8 +239,10 @@ void MainWindow::on_stepInsnButton_clicked() void MainWindow::execTimer() { - emu->executeUntil(emu->currentCycles() + (CLOCK_SPEED / 64)); - updateScreen(); + if (emu) { + emu->executeUntil(emu->currentCycles() + (emu->getClockSpeed() / 64)); + updateScreen(); + } } void MainWindow::on_addBreakButton_clicked() @@ -332,7 +277,7 @@ void MainWindow::updateMemory() uint32_t virtBase = ui->memoryViewAddress->text().toUInt(nullptr, 16) & ~0xFF; auto physBaseOpt = emu->virtToPhys(virtBase); auto physBase = physBaseOpt.value_or(0xFFFFFFFF); - bool ok = physBaseOpt.has_value() && emu->isPhysAddressValid(physBase); + bool ok = physBaseOpt.has_value(); if (ok && (virtBase != physBase)) ui->physicalAddressLabel->setText(QStringLiteral("Physical: %1").arg(physBase, 8, 16, QLatin1Char('0'))); diff --git a/WindQt/mainwindow.h b/WindQt/mainwindow.h index 34071df..781caad 100644 --- a/WindQt/mainwindow.h +++ b/WindQt/mainwindow.h @@ -2,7 +2,7 @@ #define MAINWINDOW_H #include -#include "../WindCore/clps7111.h" +#include "../WindCore/emubase.h" namespace Ui { class MainWindow; @@ -13,7 +13,7 @@ class MainWindow : public QMainWindow Q_OBJECT public: - explicit MainWindow(QWidget *parent = nullptr); + explicit MainWindow(EmuBase *emu, QWidget *parent = nullptr); ~MainWindow() override; private slots: @@ -44,7 +44,7 @@ private slots: private: Ui::MainWindow *ui; - CLPS7111 *emu; + EmuBase *emu; QTimer *timer; void updateScreen(); void updateBreakpointsList();