diff --git a/WindCore/WindCore.pro b/WindCore/WindCore.pro index b935136..5d13113 100644 --- a/WindCore/WindCore.pro +++ b/WindCore/WindCore.pro @@ -23,20 +23,25 @@ DEFINES += QT_DEPRECATED_WARNINGS #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ - arm710t.cpp \ + arm710.cpp \ + clps7111.cpp \ + clps7600.cpp \ etna.cpp \ - wind.cpp \ isa-arm.c \ decoder.c \ decoder-arm.c \ arm.c \ - emu.cpp + wind_defs.cpp \ + windermere.cpp HEADERS += \ - arm710t.h \ + arm710.h \ + clps7111.h \ + clps7111_defs.h \ + clps7600.h \ etna.h \ - wind_hw.h \ - wind.h \ + hardware.h \ + wind_defs.h \ macros.h \ isa-inlines.h \ isa-arm.h \ @@ -46,7 +51,7 @@ HEADERS += \ decoder-inlines.h \ common.h \ arm.h \ - emu.h + windermere.h unix { target.path = /usr/lib INSTALLS += target diff --git a/WindCore/arm710t.cpp b/WindCore/arm710.cpp similarity index 92% rename from WindCore/arm710t.cpp rename to WindCore/arm710.cpp index e344da3..bbb6401 100644 --- a/WindCore/arm710t.cpp +++ b/WindCore/arm710.cpp @@ -1,4 +1,4 @@ -#include "arm710t.h" +#include "arm710.h" #include "common.h" // this will need changing if this code ever compiles on big-endian procs @@ -10,7 +10,7 @@ inline void write32LE(uint8_t *p, uint32_t v) { } -void ARM710T::switchBank(BankIndex newBank) { +void ARM710::switchBank(BankIndex newBank) { if (newBank != bank) { // R13 and R14 need saving/loading for all banks allModesBankedRegisters[bank][0] = GPRs[13]; @@ -34,7 +34,7 @@ void ARM710T::switchBank(BankIndex newBank) { } -void ARM710T::switchMode(Mode newMode) { +void ARM710::switchMode(Mode newMode) { auto oldMode = currentMode(); if (newMode != oldMode) { // log("Switching mode! %x", newMode); @@ -45,7 +45,7 @@ void ARM710T::switchMode(Mode newMode) { } } -void ARM710T::raiseException(Mode mode, uint32_t savedPC, uint32_t newPC) { +void ARM710::raiseException(Mode mode, uint32_t savedPC, uint32_t newPC) { auto bankIndex = modeToBank[mode & 0xF]; // log("Raising exception mode %x, saving PC %08x, CPSR %08x", mode, savedPC, CPSR); SPSRs[bankIndex] = CPSR; @@ -57,19 +57,19 @@ void ARM710T::raiseException(Mode mode, uint32_t savedPC, uint32_t newPC) { GPRs[15] = newPC; } -void ARM710T::requestFIQ() { +void ARM710::requestFIQ() { raiseException(FIQ32, getRealPC() + 4, 0x1C); CPSR |= CPSR_FIQDisable; CPSR |= CPSR_IRQDisable; } -void ARM710T::requestIRQ() { +void ARM710::requestIRQ() { // log("Requesting IRQ: Last exec = %08x, setting LR = %08x", lastPcExecuted(), getRealPC() + 4); raiseException(IRQ32, getRealPC() + 4, 0x18); CPSR |= CPSR_IRQDisable; } -void ARM710T::reset() { +void ARM710::reset() { #ifdef ARM710T_CACHE clearCache(); #endif @@ -78,7 +78,7 @@ void ARM710T::reset() { -uint32_t ARM710T::tick() { +uint32_t ARM710::tick() { // pop an instruction off the end of the pipeline bool haveInsn = false; uint32_t insn; @@ -138,7 +138,7 @@ static inline bool extract1(uint32_t value, uint32_t bit) { } -uint32_t ARM710T::executeInstruction(uint32_t i) { +uint32_t ARM710::executeInstruction(uint32_t i) { uint32_t cycles = 1; // log("executing insn %08x @ %08x", i, GPRs[15] - 0xC); @@ -169,7 +169,7 @@ uint32_t ARM710T::executeInstruction(uint32_t i) { return cycles; } -uint32_t ARM710T::execDataProcessing(bool I, uint32_t Opcode, bool S, uint32_t Rn, uint32_t Rd, uint32_t Operand2) +uint32_t ARM710::execDataProcessing(bool I, uint32_t Opcode, bool S, uint32_t Rn, uint32_t Rd, uint32_t Operand2) { uint32_t cycles = 0; // TODO increment me semi-accurately bool shifterCarryOutput; @@ -381,7 +381,7 @@ uint32_t ARM710T::execDataProcessing(bool I, uint32_t Opcode, bool S, uint32_t R return cycles; } -uint32_t ARM710T::execMultiply(uint32_t AS, uint32_t Rd, uint32_t Rn, uint32_t Rs, uint32_t Rm) +uint32_t ARM710::execMultiply(uint32_t AS, uint32_t Rd, uint32_t Rn, uint32_t Rs, uint32_t Rm) { // no need for R15 fuckery // datasheet says it's not allowed here @@ -399,7 +399,7 @@ uint32_t ARM710T::execMultiply(uint32_t AS, uint32_t Rd, uint32_t Rn, uint32_t R return 0; } -uint32_t ARM710T::execSingleDataSwap(bool B, uint32_t Rn, uint32_t Rd, uint32_t Rm) +uint32_t ARM710::execSingleDataSwap(bool B, uint32_t Rn, uint32_t Rd, uint32_t Rm) { auto valueSize = B ? V8 : V32; auto readResult = readVirtual(GPRs[Rn], valueSize); @@ -417,7 +417,7 @@ uint32_t ARM710T::execSingleDataSwap(bool B, uint32_t Rn, uint32_t Rd, uint32_t return 1; } -uint32_t ARM710T::execSingleDataTransfer(uint32_t IPUBWL, uint32_t Rn, uint32_t Rd, uint32_t offset) +uint32_t ARM710::execSingleDataTransfer(uint32_t IPUBWL, uint32_t Rn, uint32_t Rd, uint32_t offset) { bool load = extract1(IPUBWL, 0); bool writeback = extract1(IPUBWL, 1); @@ -501,7 +501,7 @@ uint32_t ARM710T::execSingleDataTransfer(uint32_t IPUBWL, uint32_t Rn, uint32_t return 2; } -uint32_t ARM710T::execBlockDataTransfer(uint32_t PUSWL, uint32_t Rn, uint32_t registerList) +uint32_t ARM710::execBlockDataTransfer(uint32_t PUSWL, uint32_t Rn, uint32_t registerList) { bool load = extract1(PUSWL, 0); bool store = !load; @@ -586,7 +586,7 @@ uint32_t ARM710T::execBlockDataTransfer(uint32_t PUSWL, uint32_t Rn, uint32_t re return 0; // fixme } -uint32_t ARM710T::execBranch(bool L, uint32_t offset) +uint32_t ARM710::execBranch(bool L, uint32_t offset) { if (L) GPRs[14] = GPRs[15] - 8; @@ -600,7 +600,7 @@ uint32_t ARM710T::execBranch(bool L, uint32_t offset) return 0; } -uint32_t ARM710T::execCP15RegisterTransfer(uint32_t CPOpc, bool L, uint32_t CRn, uint32_t Rd, uint32_t CP, uint32_t CRm) +uint32_t ARM710::execCP15RegisterTransfer(uint32_t CPOpc, bool L, uint32_t CRn, uint32_t Rd, uint32_t CP, uint32_t CRm) { (void)CP; (void)CRm; @@ -630,17 +630,32 @@ uint32_t ARM710T::execCP15RegisterTransfer(uint32_t CPOpc, bool L, uint32_t CRn, case 1: cp15_control = what; log("setting cp15_control to %08x", what); break; case 2: cp15_translationTableBase = what; break; case 3: cp15_domainAccessControl = what; break; - case 5: cp15_faultStatus = what; break; - case 6: cp15_faultAddress = what; break; -#ifdef ARM710T_CACHE - case 7: clearCache(); log("cache cleared"); break; -#endif - case 8: { - if (CPOpc == 1) - flushTlb(what); + case 5: + if (isTVersion) + cp15_faultStatus = what; else flushTlb(); break; + case 6: + if (isTVersion) + cp15_faultAddress = what; + else + flushTlb(what); + break; + case 7: +#ifdef ARM710T_CACHE + clearCache(); + log("cache cleared"); +#endif + break; + case 8: { + if (isTVersion) { + if (CPOpc == 1) + flushTlb(what); + else + flushTlb(); + } + break; } } } @@ -735,7 +750,7 @@ bool ARM710T::writeCached(uint32_t value, uint32_t virtAddr, ValueSize valueSize #endif -uint32_t ARM710T::physAddrFromTlbEntry(TlbEntry *tlbEntry, uint32_t virtAddr) { +uint32_t ARM710::physAddrFromTlbEntry(TlbEntry *tlbEntry, uint32_t virtAddr) { if ((tlbEntry->lv2Entry & 3) == 2) { // Smøl page return (tlbEntry->lv2Entry & 0xFFFFF000) | (virtAddr & 0xFFF); @@ -749,7 +764,7 @@ uint32_t ARM710T::physAddrFromTlbEntry(TlbEntry *tlbEntry, uint32_t virtAddr) { } -MaybeU32 ARM710T::virtToPhys(uint32_t virtAddr) { +MaybeU32 ARM710::virtToPhys(uint32_t virtAddr) { if (!isMMUEnabled()) return virtAddr; @@ -764,7 +779,7 @@ MaybeU32 ARM710T::virtToPhys(uint32_t virtAddr) { } -MaybeU32 ARM710T::readVirtualDebug(uint32_t virtAddr, ValueSize valueSize) { +MaybeU32 ARM710::readVirtualDebug(uint32_t virtAddr, ValueSize valueSize) { if (auto v = virtToPhys(virtAddr); v.has_value()) return readPhysical(v.value(), valueSize); else @@ -772,7 +787,7 @@ MaybeU32 ARM710T::readVirtualDebug(uint32_t virtAddr, ValueSize valueSize) { } -pair ARM710T::readVirtual(uint32_t virtAddr, ValueSize valueSize) { +pair ARM710::readVirtual(uint32_t virtAddr, ValueSize valueSize) { if (isAlignmentFaultEnabled() && valueSize == V32 && virtAddr & 3) return make_pair(MaybeU32(), encodeFault(AlignmentFault, 0, virtAddr)); @@ -817,7 +832,7 @@ pair ARM710T::readVirtual(uint32_t virtAddr, ValueS return make_pair(result, encodeFaultSorP(SorPOtherBusError, isPage, domain, virtAddr)); } -ARM710T::MMUFault ARM710T::writeVirtual(uint32_t value, uint32_t virtAddr, ValueSize valueSize) { +ARM710::MMUFault ARM710::writeVirtual(uint32_t value, uint32_t virtAddr, ValueSize valueSize) { if (isAlignmentFaultEnabled() && valueSize == V32 && virtAddr & 3) return encodeFault(AlignmentFault, 0, virtAddr); @@ -854,11 +869,11 @@ ARM710T::MMUFault ARM710T::writeVirtual(uint32_t value, uint32_t virtAddr, Value // TLB -void ARM710T::flushTlb() { +void ARM710::flushTlb() { for (TlbEntry &e : tlb) e = {0, 0, 0, 0}; } -void ARM710T::flushTlb(uint32_t virtAddr) { +void ARM710::flushTlb(uint32_t virtAddr) { for (TlbEntry &e : tlb) { if (e.addrMask && (virtAddr & e.addrMask) == e.addr) { e = {0, 0, 0, 0}; @@ -867,7 +882,7 @@ void ARM710T::flushTlb(uint32_t virtAddr) { } } -ARM710T::TlbEntry *ARM710T::_allocateTlbEntry(uint32_t addrMask, uint32_t addr) { +ARM710::TlbEntry *ARM710::_allocateTlbEntry(uint32_t addrMask, uint32_t addr) { TlbEntry *entry = &tlb[nextTlbIndex]; entry->addrMask = addrMask; entry->addr = addr & addrMask; @@ -875,7 +890,7 @@ ARM710T::TlbEntry *ARM710T::_allocateTlbEntry(uint32_t addrMask, uint32_t addr) return entry; } -variant ARM710T::translateAddressUsingTlb(uint32_t virtAddr, TlbEntry *useMe) { +variant ARM710::translateAddressUsingTlb(uint32_t virtAddr, TlbEntry *useMe) { // first things first, do we have a matching entry in the TLB? for (TlbEntry &e : tlb) { if (e.addrMask && (virtAddr & e.addrMask) == e.addr) @@ -942,7 +957,7 @@ variant ARM710T::translateAddressUsingTl -ARM710T::MMUFault ARM710T::checkAccessPermissions(ARM710T::TlbEntry *entry, uint32_t virtAddr, bool isWrite) const { +ARM710::MMUFault ARM710::checkAccessPermissions(ARM710::TlbEntry *entry, uint32_t virtAddr, bool isWrite) const { int domain; int accessPerms; bool isPage; @@ -1013,7 +1028,7 @@ ARM710T::MMUFault ARM710T::checkAccessPermissions(ARM710T::TlbEntry *entry, uint } -void ARM710T::reportFault(MMUFault fault) { +void ARM710::reportFault(MMUFault fault) { if (fault != NoFault) { if ((fault & 0xF) != NonMMUError) { cp15_faultStatus = fault & (MMUFaultTypeMask | MMUFaultDomainMask); @@ -1051,7 +1066,7 @@ void ARM710T::reportFault(MMUFault fault) { } -void ARM710T::log(const char *format, ...) { +void ARM710::log(const char *format, ...) { if (logger) { char buffer[1024]; @@ -1064,7 +1079,7 @@ void ARM710T::log(const char *format, ...) { } } -void ARM710T::logPcHistory() { +void ARM710::logPcHistory() { for (int i = 0; i < PcHistoryCount; i++) { pcHistoryIndex = (pcHistoryIndex + 1) % PcHistoryCount; log("%03d: %08x %08x", i, pcHistory[pcHistoryIndex].addr, pcHistory[pcHistoryIndex].insn); diff --git a/WindCore/arm710t.h b/WindCore/arm710.h similarity index 97% rename from WindCore/arm710t.h rename to WindCore/arm710.h index 7852877..c8179c6 100644 --- a/WindCore/arm710t.h +++ b/WindCore/arm710.h @@ -21,7 +21,7 @@ using namespace std; typedef optional MaybeU32; -class ARM710T +class ARM710 { public: enum ValueSize { V8 = 0, V32 = 1 }; @@ -57,11 +57,12 @@ public: - ARM710T() { - cp15_id = 0x41807100; + ARM710(bool _isTVersion) { + isTVersion = _isTVersion; + cp15_id = _isTVersion ? 0x41807100 : 0x41047100; clearAllValues(); } - virtual ~ARM710T() { } + virtual ~ARM710() { } void clearAllValues() { bank = MainBank; @@ -104,8 +105,8 @@ public: pair readVirtual(uint32_t virtAddr, ValueSize valueSize); virtual MaybeU32 readPhysical(uint32_t physAddr, ValueSize valueSize) = 0; - MMUFault writeVirtual(uint32_t value, uint32_t virtAddr, ARM710T::ValueSize valueSize); - virtual bool writePhysical(uint32_t value, uint32_t physAddr, ARM710T::ValueSize valueSize) = 0; + MMUFault writeVirtual(uint32_t value, uint32_t virtAddr, ARM710::ValueSize valueSize); + virtual bool writePhysical(uint32_t value, uint32_t physAddr, ARM710::ValueSize valueSize) = 0; uint32_t getGPR(int index) const { return GPRs[index]; } uint32_t getCPSR() const { return CPSR; } @@ -115,7 +116,7 @@ public: void setLogger(std::function newLogger) { logger = newLogger; } uint32_t lastPcExecuted() const { return pcHistory[(pcHistoryIndex - 1) % PcHistoryCount].addr; } -protected: +public: void log(const char *format, ...); void logPcHistory(); private: @@ -181,6 +182,8 @@ private: uint8_t cp15_faultStatus; // 5: read-only (writing has unrelated effects) uint32_t cp15_faultAddress; // 6: read-only (writing has unrelated effects) + bool isTVersion; + bool flagV() const { return CPSR & CPSR_V; } bool flagC() const { return CPSR & CPSR_C; } bool flagZ() const { return CPSR & CPSR_Z; } diff --git a/WindCore/clps7111.cpp b/WindCore/clps7111.cpp new file mode 100644 index 0000000..17f864d --- /dev/null +++ b/WindCore/clps7111.cpp @@ -0,0 +1,497 @@ +#include "clps7111.h" +#include "clps7111_defs.h" +#include "hardware.h" +#include +#include "common.h" + + +CLPS7111::CLPS7111() : ARM710(false), pcCardController(this) { +} + + +uint32_t CLPS7111::getRTC() { + return time(nullptr) - 946684800; +} + + +uint32_t CLPS7111::readReg8(uint32_t reg) { + if (reg == PADR) { + return readKeyboard(); + } else if (reg == PBDR) { + return (portValues >> 16) & 0xFF; + } else if (reg == PDDR) { + return (portValues >> 8) & 0xFF; + } else if (reg == PEDR) { + return portValues & 0xFF; + } else if (reg == PADDR) { + return (portDirections >> 24) & 0xFF; + } else if (reg == PBDDR) { + return (portDirections >> 16) & 0xFF; + } else if (reg == PDDDR) { + return (portDirections >> 8) & 0xFF; + } else if (reg == PEDDR) { + return portDirections & 0xFF; + } else { + log("RegRead8 unknown:: pc=%08x lr=%08x reg=%03x", getRealPC(), getGPR(14), reg); + return 0xFF; + } +} +uint32_t CLPS7111::readReg32(uint32_t reg) { + if (reg == SYSCON1) { + uint32_t flg = 0; + if (tc1.config & Timer::PERIODIC) flg |= 0x10; + if (tc1.config & Timer::MODE_512KHZ) flg |= 0x20; + if (tc2.config & Timer::PERIODIC) flg |= 0x40; + if (tc2.config & Timer::MODE_512KHZ) flg |= 0x80; + flg |= (kScan & 0xF); + return flg; + } else if (reg == SYSFLG1) { + uint32_t flg = sysFlg1; + flg |= (rtcDiv << 16); + // maybe set more stuff? + return flg; + } else if (reg == INTSR1) { + return pendingInterrupts & 0xFFFF; + } else if (reg == INTMR1) { + return interruptMask & 0xFFFF; + } else if (reg == LCDCON) { + return lcdControl; + } else if (reg == TC1D) { + return tc1.value; + } else if (reg == TC2D) { + return tc2.value; + } else if (reg == RTCDR) { + return rtc; + } else if (reg == PALLSW) { + return lcdPalette & 0xFFFFFFFF; + } else if (reg == PALMSW) { + return lcdPalette >> 32; + } else if (reg == SYSCON2) { + return 0; + } else if (reg == SYSFLG2) { + return 0; + } else if (reg == INTSR2) { + return pendingInterrupts >> 16; + } else if (reg == INTMR2) { + return interruptMask >> 16; + } else { + log("RegRead32 unknown:: pc=%08x lr=%08x reg=%03x", getRealPC(), getGPR(14), reg); + return 0xFFFFFFFF; + } +} + +void CLPS7111::writeReg8(uint32_t reg, uint8_t value) { + if (reg == PADR) { + uint32_t oldPorts = portValues; + portValues &= 0x00FFFFFF; + portValues |= (uint32_t)value << 24; + diffPorts(oldPorts, portValues); + } else if (reg == PBDR) { + uint32_t oldPorts = portValues; + portValues &= 0xFF00FFFF; + portValues |= (uint32_t)value << 16; +// if ((portValues & 0x10000) && !(oldPorts & 0x10000)) +// etna.setPromBit0High(); +// else if (!(portValues & 0x10000) && (oldPorts & 0x10000)) +// etna.setPromBit0Low(); +// if ((portValues & 0x20000) && !(oldPorts & 0x20000)) +// etna.setPromBit1High(); + diffPorts(oldPorts, portValues); + } else if (reg == PDDR) { + uint32_t oldPorts = portValues; + portValues &= 0xFFFF00FF; + portValues |= (uint32_t)value << 8; + diffPorts(oldPorts, portValues); + } else if (reg == PEDR) { + uint32_t oldPorts = portValues; + portValues &= 0xFFFFFF00; + portValues |= (uint32_t)value; + diffPorts(oldPorts, portValues); + } else if (reg == PADDR) { + portDirections &= 0x00FFFFFF; + portDirections |= (uint32_t)value << 24; + } else if (reg == PBDDR) { + portDirections &= 0xFF00FFFF; + portDirections |= (uint32_t)value << 16; + } else if (reg == PDDDR) { + portDirections &= 0xFFFF00FF; + portDirections |= (uint32_t)value << 8; + } else if (reg == PEDDR) { + portDirections &= 0xFFFFFF00; + portDirections |= (uint32_t)value; + } else if (reg == FRBADDR) { + log("LCD: address write %08x", value << 28); + lcdAddress = value << 28; + } else { + log("RegWrite8 unknown:: pc=%08x reg=%03x value=%02x", getRealPC(), reg, value); + } +} +void CLPS7111::writeReg32(uint32_t reg, uint32_t value) { + if (reg == SYSCON1) { + kScan = value & 0xF; + tc1.config = Timer::ENABLED; // always on with PS-7111! + if (value & 0x10) tc1.config |= Timer::PERIODIC; + if (value & 0x20) tc1.config |= Timer::MODE_512KHZ; + tc2.config = Timer::ENABLED; + if (value & 0x40) tc2.config |= Timer::PERIODIC; + if (value & 0x80) tc2.config |= Timer::MODE_512KHZ; + } else if (reg == INTMR1) { + interruptMask &= 0xFFFF0000;; + interruptMask |= (value & 0xFFFF); + } else if (reg == LCDCON) { + log("LCD: ctl write %08x", value); + lcdControl = value; + } else if (reg == TC1D) { + tc1.load(value); + } else if (reg == TC2D) { + tc2.load(value); + } else if (reg == RTCDR) { + rtc = value; + } else if (reg == PALLSW) { + lcdPalette &= 0xFFFFFFFF00000000; + lcdPalette |= value; + } else if (reg == PALMSW) { + lcdPalette &= 0x00000000FFFFFFFF; + lcdPalette |= (uint64_t)value << 32; + } else if (reg == HALT) { + halted = true; + // BLEOI = 0x410, + // MCEOI = 0x414, + } else if (reg == TEOI) { + pendingInterrupts &= ~(1 << TINT); + // TEOI = 0x418, + // STFCLR = 0x41C, + // E2EOI = 0x420, + } else if (reg == TC1EOI) { + pendingInterrupts &= ~(1 << TC1OI); + } else if (reg == TC2EOI) { + pendingInterrupts &= ~(1 << TC2OI); + } else if (reg == SYSCON2) { + log("SysCon2 write: %08x", value); + } else if (reg == INTMR2) { + interruptMask &= 0xFFFF; + interruptMask |= (value << 16); + } else if (reg == KBDEOI) { + pendingInterrupts &= ~(1 << KBDINT); + } else { + log("RegWrite32 unknown:: pc=%08x reg=%03x value=%08x", getRealPC(), reg, 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) { + uint8_t region = (physAddr >> 28); + if (valueSize == V8) { + if (region == 0) + return ROM[physAddr & 0xFFFFFF]; + else if (region == 1) + return ROM2[physAddr & 0x3FFFF]; + else if (region == 4) + return pcCardController.read(physAddr & 0xFFFFFFF, V8); + else if (region == 8 && physAddr <= 0x80001FFF) + return readReg8(physAddr & 0x1FFF); + else if (region == 0xC) + return MemoryBlockC0[physAddr & MemoryBlockMask]; + else if (region > 0xC) + return 0xFF; // just throw accesses to unmapped RAM away + } else { + uint32_t result; + if (region == 0) + LOAD_32LE(result, physAddr & 0xFFFFFF, ROM); + else if (region == 1) + LOAD_32LE(result, physAddr & 0x3FFFF, ROM2); + else if (region == 4) + result = pcCardController.read(physAddr & 0xFFFFFFF, V32); + else if (region == 8 && physAddr <= 0x80001FFF) + result = readReg32(physAddr & 0x1FFF); + else if (region == 0xC) + LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockC0); + else if (region > 0xC) + return 0xFFFFFFFF; // just throw accesses to unmapped RAM away + else + return {}; + return result; + } + + return {}; +} + +bool CLPS7111::writePhysical(uint32_t value, uint32_t physAddr, ValueSize valueSize) { + uint8_t region = (physAddr >> 28); + if (valueSize == V8) { + if (region == 0xC) + MemoryBlockC0[physAddr & MemoryBlockMask] = (uint8_t)value; + else if (region > 0xC) + return true; // just throw accesses to unmapped RAM away + else if (region == 4) + pcCardController.write(value, physAddr & 0xFFFFFFF, V8); + else if (region == 8 && physAddr <= 0x80001FFF) + writeReg8(physAddr & 0x1FFF, value); + else + return false; + } else { + if (region == 0xC) + STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockC0); + else if (region > 0xC) + return true; // just throw accesses to unmapped RAM away + else if (region == 4) + pcCardController.write(value, physAddr & 0xFFFFFFF, V32); + else if (region == 8 && physAddr <= 0x80001FFF) + writeReg32(physAddr & 0x1FFF, value); + else + return false; + } + return true; +} + + + +void CLPS7111::configure() { + if (configured) return; + configured = true; + + srand(1000); + + memset(&tc1, 0, sizeof(tc1)); + memset(&tc2, 0, sizeof(tc1)); + tc1.clockSpeed = CLOCK_SPEED; + tc2.clockSpeed = CLOCK_SPEED; + + nextTickAt = TICK_INTERVAL; + rtc = getRTC(); + + reset(); +} + +void CLPS7111::loadROM(const char *path) { + FILE *f = fopen(path, "rb"); + fread(ROM, 1, sizeof(ROM), f); + fclose(f); +} + +void CLPS7111::executeUntil(int64_t cycles) { + if (!configured) + configure(); + + while (!asleep && passedCycles < cycles) { + if (passedCycles >= nextTickAt) { + // increment RTCDIV + if (rtcDiv == 0x3F) { + rtc++; + rtcDiv = 0; + } else { + rtcDiv++; + } + + nextTickAt += TICK_INTERVAL; + pendingInterrupts |= (1<= 0x80000000 && new_pc <= 0x90000000) { + log("BAD PC %08x!!", new_pc); + logPcHistory(); + return; + } + } + } +} + +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) { + if (ptr == readVirtualDebug(0x80000880, V32).value()) return "process"; + if (ptr == readVirtualDebug(0x80000884, V32).value()) return "thread"; + if (ptr == readVirtualDebug(0x80000888, V32).value()) return "chunk"; +// if (ptr == readVirtualDebug(0x8000088C, V32).value()) return "semaphore"; +// if (ptr == readVirtualDebug(0x80000890, V32).value()) return "mutex"; + if (ptr == readVirtualDebug(0x80000894, V32).value()) return "logicaldevice"; + if (ptr == readVirtualDebug(0x80000898, V32).value()) return "physicaldevice"; + if (ptr == readVirtualDebug(0x8000089C, V32).value()) return "channel"; + if (ptr == readVirtualDebug(0x800008A0, V32).value()) return "server"; +// if (ptr == readVirtualDebug(0x800008A4, V32).value()) return "unk8A4"; // name always null + 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 "???"; +} + +void CLPS7111::fetchStr(uint32_t str, char *buf) { + if (str == 0) { + strcpy(buf, ""); + return; + } + int size = readVirtualDebug(str, V32).value(); + for (int i = 0; i < size; i++) { + buf[i] = readVirtualDebug(str + 4 + i, V8).value(); + } + buf[size] = 0; +} + +void CLPS7111::fetchName(uint32_t obj, char *buf) { + fetchStr(readVirtualDebug(obj + 0x10, V32).value(), buf); +} + +void CLPS7111::fetchProcessFilename(uint32_t obj, char *buf) { + fetchStr(readVirtualDebug(obj + 0x3C, V32).value(), buf); +} + +void CLPS7111::debugPC(uint32_t pc) { + char objName[1000]; + if (pc == 0x32304) { + // CObjectCon::AddL() + uint32_t container = getGPR(0); + uint32_t obj = getGPR(1); + const char *wut = identifyObjectCon(container); + if (wut) { + fetchName(obj, objName); + if (strcmp(wut, "process") == 0) { + char procName[1000]; + fetchProcessFilename(obj, procName); + log("OBJS: added %s at %08x <%s> <%s>", wut, obj, objName, procName); + } else { + log("OBJS: added %s at %08x <%s>", wut, obj, objName); + } + } + } + + if (pc == 0x634) { + uint32_t virtAddr = getGPR(0); + uint32_t physAddr = getGPR(1); + uint32_t btIndex = getGPR(2); + uint32_t regionSize = getGPR(3); + log("KERNEL MMU SECTION: v:%08x p:%08x size:%08x idx:%02x", + virtAddr, physAddr, regionSize, btIndex); + } + if (pc == 0x66C) { + uint32_t virtAddr = getGPR(0); + uint32_t physAddr = getGPR(1); + uint32_t btIndex = getGPR(2); + uint32_t regionSize = getGPR(3); + uint32_t pageTableA = getGPR(4); + uint32_t pageTableB = getGPR(5); + log("KERNEL MMU PAGES: v:%08x p:%08x size:%08x idx:%02x tableA:%08x tableB:%08x", + virtAddr, physAddr, regionSize, btIndex, pageTableA, pageTableB); + } + if (pc == 0x15070) { + uint32_t virtAddr = getGPR(0); + uint32_t physAddr = getGPR(1); + uint32_t regionSize = getGPR(2); + uint32_t a = getGPR(3); + 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; +} + + +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)); + } + return val; +} + + + +void CLPS7111::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); + if (changes & 4) log("PRT E2: %d", newval&4); + if (changes & 0x100) log("PRT D0: %d", newval&0x100); + if (changes & 0x200) log("PRT D1: %d", newval&0x200); + if (changes & 0x400) log("PRT D2: %d", newval&0x400); + if (changes & 0x800) log("PRT D3: %d", newval&0x800); + if (changes & 0x1000) log("PRT D4: %d", newval&0x1000); + if (changes & 0x2000) log("PRT D5: %d", newval&0x2000); + if (changes & 0x4000) log("PRT D6: %d", newval&0x4000); + if (changes & 0x8000) log("PRT D7: %d", newval&0x8000); + if (changes & 0x10000) log("PRT B0: %d", newval&0x10000); + if (changes & 0x20000) log("PRT B1: %d", newval&0x20000); + if (changes & 0x40000) log("PRT B2: %d", newval&0x40000); + if (changes & 0x80000) log("PRT B3: %d", newval&0x80000); + if (changes & 0x100000) log("PRT B4: %d", newval&0x100000); + 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 new file mode 100644 index 0000000..3ab514a --- /dev/null +++ b/WindCore/clps7111.h @@ -0,0 +1,76 @@ +#pragma once +#include "arm710.h" +#include "clps7111_defs.h" +#include "clps7600.h" +#include "hardware.h" +#include "etna.h" +#include + +class CLPS7111 : public ARM710 { +public: + uint8_t ROM[0x800000]; + uint8_t ROM2[0x40000]; + uint8_t MemoryBlockC0[0x400000]; + enum { MemoryBlockMask = 0x3FFFFF }; + +private: + uint16_t pendingInterrupts = 0; + uint16_t interruptMask = 0; + uint32_t portValues = 0; + uint32_t portDirections = 0; + uint32_t sysFlg1 = 0x20008000; // constant CL-PS7111 flag and cold start flag + uint32_t lcdControl = 0; + uint32_t lcdAddress = 0xC0000000; + uint32_t kScan = 0; + uint32_t rtc = 0; + 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(); + + uint32_t readReg8(uint32_t reg); + uint32_t readReg32(uint32_t reg); + void writeReg8(uint32_t reg, uint8_t value); + 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); + void fetchProcessFilename(uint32_t obj, char *buf); + 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; } +}; diff --git a/WindCore/clps7111_defs.h b/WindCore/clps7111_defs.h new file mode 100644 index 0000000..86db239 --- /dev/null +++ b/WindCore/clps7111_defs.h @@ -0,0 +1,81 @@ +#pragma once +#include + +enum { + CLOCK_SPEED = 0x4800*1000, + TICK_INTERVAL = CLOCK_SPEED / 64 +}; + +enum Interrupt { + EXTFIQ = 0, // FiqExternal + BLINT = 1, // FiqBatLow + WEINT = 2, // FiqWatchDog + MCINT = 3, // FiqMediaChg + CSINT = 4, // IrqCodec + EINT1 = 5, // IrqExt1 + EINT2 = 6, // IrqExt2 + EINT3 = 7, // IrqExt3 + TC1OI = 8, // IrqTimer1 + TC2OI = 9, // IrqTimer2 + RTCMI = 10, // IrqRtcMatch + TINT = 11, // IrqTick + UTXINT = 12, // IrqUartTx? + URXINT1 = 13, // IrqUartRx? + UMSINT = 14, // IrqUartModem? + SSEOTI = 15, // IrqSpi + KBDINT = 16, // IrqKeyPress? + UTXINT2 = 28, // IrqSpi2Tx? + URXINT2 = 29, // IrqSpi2Rx? + FIQ_INTERRUPTS = 0x000F, + IRQ_INTERRUPTS = 0xFFF0 +}; + +enum Clps7111Reg { + PADR = 0, + PBDR = 1, + PDDR = 3, + PADDR = 0x40, + PBDDR = 0x41, + PDDDR = 0x43, + PEDR = 0x80, + PEDDR = 0xC0, + SYSCON1 = 0x100, + SYSFLG1 = 0x140, + MEMCFG1 = 0x180, + MEMCFG2 = 0x1C0, + DRFPR = 0x200, + INTSR1 = 0x240, + INTMR1 = 0x280, + LCDCON = 0x2C0, + TC1D = 0x300, + TC2D = 0x340, + RTCDR = 0x380, + RTCMR = 0x3C0, + PMPCON = 0x400, + CODR = 0x440, + UARTDR1 = 0x480, + UBRLCR1 = 0x4C0, + SYNCIO = 0x500, + PALLSW = 0x540, + PALMSW = 0x580, + STFCLR = 0x5C0, + BLEOI = 0x600, + MCEOI = 0x640, + TEOI = 0x680, + TC1EOI = 0x6C0, + TC2EOI = 0x700, + RTCEOI = 0x740, + UMSEOI = 0x780, + COEOI = 0x7C0, + HALT = 0x800, + STDBY = 0x840, + FRBADDR = 0x1000, + SYSCON2 = 0x1100, + SYSFLG2 = 0x1140, + INTSR2 = 0x1240, + INTMR2 = 0x1280, + UARTDR2 = 0x1480, + UBRLCR2 = 0x14C0, + KBDEOI = 0x1700 +}; + diff --git a/WindCore/clps7600.cpp b/WindCore/clps7600.cpp new file mode 100644 index 0000000..3b2d36a --- /dev/null +++ b/WindCore/clps7600.cpp @@ -0,0 +1,133 @@ +#include "clps7600.h" +#include "arm710.h" + +CLPS7600::CLPS7600(ARM710 *_cpu) +{ + cpu = _cpu; +} + +enum { + PCM_BVD1 = 1, + PCM_BVD2 = 2, + PCM_CD1 = 4, + PCM_CD2 = 8, + PCM_VS1 = 0x10, + PCM_VS2 = 0x20, + PDREQ_L = 0x40, + PCTL = 0x100, + PCM_WP = 0x200, + PCM_RDY = 0x400, + FIFOTHLD = 0x800, + IDLE = 0x1000, + WR_FAIL = 0x2000, + RD_FAIL = 0x4000, + RESERVED = 0x8000 +}; + +uint32_t CLPS7600::getInputLevel() const { + uint32_t v = 0; + + if (isMemoryMode()) + v |= PCM_RDY; // we are ALWAYS ready + + return v; +} + +uint32_t CLPS7600::read(uint32_t addr, ARM710::ValueSize valueSize) +{ + cpu->log("CLPS7600 read: addr=%07x size=%d pc=%08x lr=%08x", addr, (valueSize == ARM710::V32) ? 32 : 8, cpu->getRealPC(), cpu->getGPR(14)); + if (valueSize == ARM710::V32) { + switch (addr) { + case 0xC000000: // Interrupt Status + return interruptStatus; + case 0xC000400: // Interrupt Mask + return interruptMask; + case 0xC001C00: // Interrupt Input Level + return getInputLevel(); + case 0xC002000: // System Interface Configuration + return systemInterfaceConfig; + case 0xC002400: // Card Interface Configuration + return cardInterfaceConfig; + case 0xC002800: // Power Management + return powerManagement; + case 0xC002C00: // Card Power Control + return cardPowerControl; + case 0xC003000: // Card Interface Timing 0A + return cardInterfaceTiming0A; + case 0xC003400: // Card Interface Timing 0B + return cardInterfaceTiming0B; + case 0xC003800: // Card Interface Timing 1A + return cardInterfaceTiming1A; + case 0xC003C00: // Card Interface Timing 1B + return cardInterfaceTiming1B; + case 0xC004000: // DMA Control + return dmaControl; + case 0xC004400: // Device Information + return deviceInformation; + default: + cpu->log("CLPS7600 unknown register read: addr=%07x pc=%08x lr=%08x", addr, cpu->getRealPC(), cpu->getGPR(14)); + return 0xFFFFFFFF; + } + } + cpu->log("unknown!!"); + return 0xFF; +} + +void CLPS7600::write(uint32_t value, uint32_t addr, ARM710::ValueSize valueSize) +{ + cpu->log("CLPS7600 write: addr=%07x size=%d value=%08x pc=%08x lr=%08x", addr, (valueSize == ARM710::V32) ? 32 : 8, value, cpu->getRealPC(), cpu->getGPR(14)); + if (valueSize == ARM710::V32) { + switch (addr) { + case 0xC000400: // Interrupt Mask + interruptMask = value; + break; + case 0xC000800: // Interrupt Clear + break; + case 0xC000C00: // Interrupt Output Select + break; + case 0xC001000: // Interrupt Reserved Register 1 + break; + case 0xC001400: // Interrupt Reserved Register 2 + break; + case 0xC001800: // Interrupt Reserved Register 3 + break; + case 0xC002000: // System Interface Configuration + systemInterfaceConfig = value; + break; + case 0xC002400: // Card Interface Configuration + cardInterfaceConfig = value; + cpu->log("PC card enabled: %s", (value & 0x400) ? "yes" : "no"); + cpu->log("PC card write protect: %s", (value & 0x200) ? "yes" : "no"); + cpu->log("PC card mode: %s", (value & 0x100) ? "i/o" : "memory"); + break; + case 0xC002800: // Power Management + powerManagement = value; + break; + case 0xC002C00: // Card Power Control + cardPowerControl = value; + break; + case 0xC003000: // Card Interface Timing 0A + cardInterfaceTiming0A = value; + break; + case 0xC003400: // Card Interface Timing 0B + cardInterfaceTiming0B = value; + break; + case 0xC003800: // Card Interface Timing 1A + cardInterfaceTiming1A = value; + break; + case 0xC003C00: // Card Interface Timing 1B + cardInterfaceTiming1B = value; + break; + case 0xC004000: // DMA Control + dmaControl = value; + break; + case 0xC004400: // Device Information + deviceInformation = value; + break; + default: + cpu->log("CLPS7600 unknown register write: addr=%07x value=%08x pc=%08x lr=%08x", addr, value, cpu->getRealPC(), cpu->getGPR(14)); + } + } else { + cpu->log("unknown write!!"); + } +} diff --git a/WindCore/clps7600.h b/WindCore/clps7600.h new file mode 100644 index 0000000..e9fe2a9 --- /dev/null +++ b/WindCore/clps7600.h @@ -0,0 +1,33 @@ +#pragma once +#include +#include "arm710.h" + +class CLPS7600 +{ +private: + ARM710 *cpu; + + uint32_t interruptStatus = 0; + uint32_t interruptMask = 0; + uint32_t systemInterfaceConfig = 0x1F8; + uint32_t cardInterfaceConfig = 0; + uint32_t powerManagement = 0; + uint32_t cardPowerControl = 0; + uint32_t cardInterfaceTiming0A = 0x1F00; + uint32_t cardInterfaceTiming0B = 0; + uint32_t cardInterfaceTiming1A = 0x1F00; + uint32_t cardInterfaceTiming1B = 0; + uint32_t dmaControl = 0; + uint32_t deviceInformation = 0x40; + + bool isIOMode() const { return (cardInterfaceConfig & 0x100); } + bool isMemoryMode() const { return !(cardInterfaceConfig & 0x100); } + uint32_t getInputLevel() const; + +public: + CLPS7600(ARM710 *_cpu); + + uint32_t read(uint32_t addr, ARM710::ValueSize valueSize); + void write(uint32_t value, uint32_t addr, ARM710::ValueSize valueSize); +}; + diff --git a/WindCore/etna.cpp b/WindCore/etna.cpp index 0356d52..d79ca82 100644 --- a/WindCore/etna.cpp +++ b/WindCore/etna.cpp @@ -1,5 +1,5 @@ #include "etna.h" -#include "emu.h" +#include "arm710.h" #include #include @@ -45,7 +45,7 @@ static const char *nameReg(uint32_t reg) { } -Etna::Etna(Emu *owner) { +Etna::Etna(ARM710 *owner) { this->owner = owner; for (int i = 0; i < 0x80; i++) diff --git a/WindCore/etna.h b/WindCore/etna.h index ae63b02..ef42e89 100644 --- a/WindCore/etna.h +++ b/WindCore/etna.h @@ -1,7 +1,7 @@ #pragma once #include -class Emu; +class ARM710; class Etna { uint8_t prom[0x80] = {}; @@ -12,10 +12,10 @@ class Etna { uint8_t pendingInterrupts = 0, interruptMask = 0; uint8_t wake1 = 0, wake2 = 0; - Emu *owner; + ARM710 *owner; public: - Etna(Emu *owner); + Etna(ARM710 *owner); uint32_t readReg8(uint32_t reg); uint32_t readReg32(uint32_t reg); diff --git a/WindCore/wind_hw.h b/WindCore/hardware.h similarity index 86% rename from WindCore/wind_hw.h rename to WindCore/hardware.h index 25ae486..c1857ae 100644 --- a/WindCore/wind_hw.h +++ b/WindCore/hardware.h @@ -1,14 +1,11 @@ #pragma once -#include "wind.h" -#include "arm710t.h" +#include "arm710.h" #include struct Timer { - ARM710T *cpu; + ARM710 *cpu; enum { - TICK_INTERVAL_SLOW = CLOCK_SPEED / 2000, - TICK_INTERVAL_FAST = CLOCK_SPEED / 512000, MODE_512KHZ = 1<<3, PERIODIC = 1<<6, ENABLED = 1<<7 @@ -17,9 +14,10 @@ struct Timer { uint8_t config; uint32_t interval; int32_t value; + int clockSpeed; int tickInterval() const { - return (config & MODE_512KHZ) ? TICK_INTERVAL_FAST : TICK_INTERVAL_SLOW; + return (config & MODE_512KHZ) ? (clockSpeed / 512000) : (clockSpeed / 2000); } void load(uint32_t lval) { interval = lval; @@ -49,8 +47,33 @@ struct Timer { } }; +enum UartRegs { + UART0DATA = 0x600, + UART0FCR = 0x604, + UART0LCR = 0x608, + UART0CON = 0x60C, + UART0FLG = 0x610, + UART0INT = 0x614, + UART0INTM = 0x618, + UART0INTR = 0x61C, + UART0TEST1 = 0x620, + UART0TEST2 = 0x624, + UART0TEST3 = 0x628, + UART1DATA = 0x700, + UART1FCR = 0x704, + UART1LCR = 0x708, + UART1CON = 0x70C, + UART1FLG = 0x710, + UART1INT = 0x714, + UART1INTM = 0x718, + UART1INTR = 0x71C, + UART1TEST1 = 0x720, + UART1TEST2 = 0x724, + UART1TEST3 = 0x728, +}; + struct UART { - ARM710T *cpu; + ARM710 *cpu; enum { IntRx = 1, diff --git a/WindCore/wind.cpp b/WindCore/wind_defs.cpp similarity index 96% rename from WindCore/wind.cpp rename to WindCore/wind_defs.cpp index 851e4f2..c6b56d2 100644 --- a/WindCore/wind.cpp +++ b/WindCore/wind_defs.cpp @@ -1,7 +1,7 @@ -#include "wind.h" +#include "wind_defs.h" #include -void diffPorts(uint32_t oldval, uint32_t newval) { +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); @@ -37,7 +37,7 @@ void diffPorts(uint32_t oldval, uint32_t newval) { if (changes & 0x80000000) printf("PRT kb7: %d\n", newval&0x80000000); } -void diffInterrupts(uint16_t oldval, uint16_t newval) { +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); diff --git a/WindCore/wind.h b/WindCore/wind_defs.h similarity index 71% rename from WindCore/wind.h rename to WindCore/wind_defs.h index 593d87d..c616e5f 100644 --- a/WindCore/wind.h +++ b/WindCore/wind_defs.h @@ -1,8 +1,10 @@ #pragma once #include -const int CLOCK_SPEED = 0x9000*1000; -const int TICK_INTERVAL = CLOCK_SPEED / 64; +enum { + CLOCK_SPEED = 0x9000*1000, + TICK_INTERVAL = CLOCK_SPEED / 64 +}; enum Interrupt { EXTFIQ = 0, // FiqExternal @@ -50,28 +52,6 @@ enum WindermereReg { INTENC = 0x50C, INTTEST1 = 0x514, INTTEST2 = 0x518, - UART0DATA = 0x600, - UART0FCR = 0x604, - UART0LCR = 0x608, - UART0CON = 0x60C, - UART0FLG = 0x610, - UART0INT = 0x614, - UART0INTM = 0x618, - UART0INTR = 0x61C, - UART0TEST1 = 0x620, - UART0TEST2 = 0x624, - UART0TEST3 = 0x628, - UART1DATA = 0x700, - UART1FCR = 0x704, - UART1LCR = 0x708, - UART1CON = 0x70C, - UART1FLG = 0x710, - UART1INT = 0x714, - UART1INTM = 0x718, - UART1INTR = 0x71C, - UART1TEST1 = 0x720, - UART1TEST2 = 0x724, - UART1TEST3 = 0x728, PUMPCON = 0x900, CODR = 0xA00, CONFG = 0xA04, @@ -110,5 +90,5 @@ enum WindermereReg { LCDMUX = 0xE2C }; -void diffPorts(uint32_t oldval, uint32_t newval); -void diffInterrupts(uint16_t oldval, uint16_t newval); +void windDiffPorts(uint32_t oldval, uint32_t newval); +void windDiffInterrupts(uint16_t oldval, uint16_t newval); diff --git a/WindCore/emu.cpp b/WindCore/windermere.cpp similarity index 91% rename from WindCore/emu.cpp rename to WindCore/windermere.cpp index c607e92..898598e 100644 --- a/WindCore/emu.cpp +++ b/WindCore/windermere.cpp @@ -1,6 +1,6 @@ -#include "emu.h" -#include "wind.h" -#include "wind_hw.h" +#include "windermere.h" +#include "wind_defs.h" +#include "hardware.h" #include #include "common.h" @@ -8,16 +8,16 @@ //#define INCLUDE_D //#define INCLUDE_BANK1 -Emu::Emu() : etna(this) { +Windermere::Windermere() : ARM710(true), etna(this) { } -uint32_t Emu::getRTC() { +uint32_t Windermere::getRTC() { return time(nullptr) - 946684800; } -uint32_t Emu::readReg8(uint32_t reg) { +uint32_t Windermere::readReg8(uint32_t reg) { if ((reg & 0xF00) == 0x600) { return uart1.readReg8(reg & 0xFF); } else if ((reg & 0xF00) == 0x700) { @@ -47,7 +47,7 @@ uint32_t Emu::readReg8(uint32_t reg) { return 0xFF; } } -uint32_t Emu::readReg32(uint32_t reg) { +uint32_t Windermere::readReg32(uint32_t reg) { if (reg == LCDCTL) { printf("LCD control read pc=%08x lr=%08x !!!\n", getGPR(15), getGPR(14)); return lcdControl; @@ -92,7 +92,7 @@ uint32_t Emu::readReg32(uint32_t reg) { } } -void Emu::writeReg8(uint32_t reg, uint8_t value) { +void Windermere::writeReg8(uint32_t reg, uint8_t value) { if ((reg & 0xF00) == 0x600) { uart1.writeReg8(reg & 0xFF, value); } else if ((reg & 0xF00) == 0x700) { @@ -105,7 +105,7 @@ void Emu::writeReg8(uint32_t reg, uint8_t value) { uint32_t oldPorts = portValues; portValues &= 0x00FFFFFF; portValues |= (uint32_t)value << 24; - diffPorts(oldPorts, portValues); + windDiffPorts(oldPorts, portValues); } else if (reg == PBDR) { uint32_t oldPorts = portValues; portValues &= 0xFF00FFFF; @@ -116,17 +116,17 @@ void Emu::writeReg8(uint32_t reg, uint8_t value) { etna.setPromBit0Low(); if ((portValues & 0x20000) && !(oldPorts & 0x20000)) etna.setPromBit1High(); - diffPorts(oldPorts, portValues); + windDiffPorts(oldPorts, portValues); } else if (reg == PCDR) { uint32_t oldPorts = portValues; portValues &= 0xFFFF00FF; portValues |= (uint32_t)value << 8; - diffPorts(oldPorts, portValues); + windDiffPorts(oldPorts, portValues); } else if (reg == PDDR) { uint32_t oldPorts = portValues; portValues &= 0xFFFFFF00; portValues |= (uint32_t)value; - diffPorts(oldPorts, portValues); + windDiffPorts(oldPorts, portValues); } else if (reg == PADDR) { portDirections &= 0x00FFFFFF; portDirections |= (uint32_t)value << 24; @@ -145,7 +145,7 @@ void Emu::writeReg8(uint32_t reg, uint8_t value) { // printf("RegWrite8 unknown:: pc=%08x reg=%03x value=%02x\n", getGPR(15)-4, reg, value); } } -void Emu::writeReg32(uint32_t reg, uint32_t value) { +void Windermere::writeReg32(uint32_t reg, uint32_t value) { if (reg == LCDCTL) { printf("LCD: ctl write %08x\n", value); lcdControl = value; @@ -159,10 +159,10 @@ void Emu::writeReg32(uint32_t reg, uint32_t value) { } else if (reg == LCDT2) { printf("LCD: clocks write %08x\n", value); } else if (reg == INTENS) { -// diffInterrupts(interruptMask, interruptMask | value); +// windDiffInterrupts(interruptMask, interruptMask | value); interruptMask |= value; } else if (reg == INTENC) { -// diffInterrupts(interruptMask, interruptMask &~ value); +// windDiffInterrupts(interruptMask, interruptMask &~ value); interruptMask &= ~value; } else if (reg == HALT) { halted = true; @@ -190,7 +190,7 @@ void Emu::writeReg32(uint32_t reg, uint32_t value) { } } -bool Emu::isPhysAddressValid(uint32_t physAddress) const { +bool Windermere::isPhysAddressValid(uint32_t physAddress) const { uint8_t region = (physAddress >> 24) & 0xF1; switch (region) { case 0: return true; @@ -204,7 +204,7 @@ bool Emu::isPhysAddressValid(uint32_t physAddress) const { } -MaybeU32 Emu::readPhysical(uint32_t physAddr, ValueSize valueSize) { +MaybeU32 Windermere::readPhysical(uint32_t physAddr, ValueSize valueSize) { uint8_t region = (physAddr >> 24) & 0xF1; if (valueSize == V8) { if (region == 0) @@ -273,7 +273,7 @@ MaybeU32 Emu::readPhysical(uint32_t physAddr, ValueSize valueSize) { return {}; } -bool Emu::writePhysical(uint32_t value, uint32_t physAddr, ValueSize valueSize) { +bool Windermere::writePhysical(uint32_t value, uint32_t physAddr, ValueSize valueSize) { uint8_t region = (physAddr >> 24) & 0xF1; if (valueSize == V8) { #if defined(INCLUDE_BANK1) @@ -336,7 +336,7 @@ bool Emu::writePhysical(uint32_t value, uint32_t physAddr, ValueSize valueSize) -void Emu::configure() { +void Windermere::configure() { if (configured) return; configured = true; @@ -346,6 +346,8 @@ void Emu::configure() { uart2.cpu = this; memset(&tc1, 0, sizeof(tc1)); memset(&tc2, 0, sizeof(tc1)); + tc1.clockSpeed = CLOCK_SPEED; + tc2.clockSpeed = CLOCK_SPEED; nextTickAt = TICK_INTERVAL; rtc = getRTC(); @@ -353,13 +355,13 @@ void Emu::configure() { reset(); } -void Emu::loadROM(const char *path) { +void Windermere::loadROM(const char *path) { FILE *f = fopen(path, "rb"); fread(ROM, 1, sizeof(ROM), f); fclose(f); } -void Emu::executeUntil(int64_t cycles) { +void Windermere::executeUntil(int64_t cycles) { if (!configured) configure(); @@ -413,7 +415,7 @@ void Emu::executeUntil(int64_t cycles) { } } -void Emu::dumpRAM(const char *path) { +void Windermere::dumpRAM(const char *path) { FILE *f = fopen(path, "wb"); fwrite(MemoryBlockC0, 1, sizeof(MemoryBlockC0), f); fwrite(MemoryBlockC1, 1, sizeof(MemoryBlockC1), f); @@ -424,7 +426,7 @@ void Emu::dumpRAM(const char *path) { -void Emu::printRegs() { +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)); @@ -432,7 +434,7 @@ void Emu::printRegs() { // printf("cpsr=%08x spsr=%08x\n", cpu.cpsr.packed, cpu.spsr.packed); } -const char *Emu::identifyObjectCon(uint32_t ptr) { +const char *Windermere::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"; @@ -449,7 +451,7 @@ const char *Emu::identifyObjectCon(uint32_t ptr) { return NULL; } -void Emu::fetchStr(uint32_t str, char *buf) { +void Windermere::fetchStr(uint32_t str, char *buf) { if (str == 0) { strcpy(buf, ""); return; @@ -461,15 +463,15 @@ void Emu::fetchStr(uint32_t str, char *buf) { buf[size] = 0; } -void Emu::fetchName(uint32_t obj, char *buf) { +void Windermere::fetchName(uint32_t obj, char *buf) { fetchStr(readVirtualDebug(obj + 0x10, V32).value(), buf); } -void Emu::fetchProcessFilename(uint32_t obj, char *buf) { +void Windermere::fetchProcessFilename(uint32_t obj, char *buf) { fetchStr(readVirtualDebug(obj + 0x3C, V32).value(), buf); } -void Emu::debugPC(uint32_t pc) { +void Windermere::debugPC(uint32_t pc) { char objName[1000]; if (pc == 0x2CBC4) { // CObjectCon::AddL() @@ -509,7 +511,7 @@ void Emu::debugPC(uint32_t pc) { } -const uint8_t *Emu::getLCDBuffer() const { +const uint8_t *Windermere::getLCDBuffer() const { if ((lcdAddress >> 24) == 0xC0) return &MemoryBlockC0[lcdAddress & MemoryBlockMask]; else @@ -517,7 +519,7 @@ const uint8_t *Emu::getLCDBuffer() const { } -uint8_t Emu::readKeyboard() { +uint8_t Windermere::readKeyboard() { uint8_t val = 0; if (kScan & 8) { // Select one keyboard diff --git a/WindCore/emu.h b/WindCore/windermere.h similarity index 94% rename from WindCore/emu.h rename to WindCore/windermere.h index 17402c6..bcbe320 100644 --- a/WindCore/emu.h +++ b/WindCore/windermere.h @@ -1,10 +1,11 @@ #pragma once -#include "arm710t.h" -#include "wind_hw.h" +#include "arm710.h" +#include "wind_defs.h" +#include "hardware.h" #include "etna.h" #include -class Emu : public ARM710T { +class Windermere : public ARM710 { public: uint8_t ROM[0x1000000]; uint8_t ROM2[0x40000]; @@ -64,7 +65,7 @@ public: bool keyboardKeys[8*7] = {0}; public: - Emu(); + Windermere(); void loadROM(const char *path); void dumpRAM(const char *path); void executeUntil(int64_t cycles); diff --git a/WindQt/mainwindow.cpp b/WindQt/mainwindow.cpp index b9c4fe3..16085df 100644 --- a/WindQt/mainwindow.cpp +++ b/WindQt/mainwindow.cpp @@ -1,6 +1,6 @@ #include "mainwindow.h" #include "ui_mainwindow.h" -#include "../WindCore/wind.h" +#include "../WindCore/clps7111_defs.h" #include #include #include "../WindCore/decoder.h" @@ -12,8 +12,8 @@ MainWindow::MainWindow(QWidget *parent) : ui->setupUi(this); ui->logView->setMaximumBlockCount(1000); - emu = new Emu; - emu->loadROM("/Users/ash/src/psion/Sys$rom.bin"); + emu = new CLPS7111; + emu->loadROM("/Users/ash/src/psion/Osaris.bin"); emu->setLogger([&](const char *str) { ui->logView->appendPlainText(str); }); @@ -91,7 +91,7 @@ void MainWindow::updateScreen() struct ARMInstructionInfo info; char buffer[512]; - auto result = emu->readVirtual(addr, ARM710T::V32); + auto result = emu->readVirtual(addr, ARM710::V32); if (result.first.has_value()) { uint32_t opcode = result.first.value(); ARMDecodeARM(opcode, &info); @@ -104,9 +104,10 @@ void MainWindow::updateScreen() // now, the actual screen const uint8_t *lcdBuf = emu->getLCDBuffer(); if (lcdBuf) { - QImage img(640, 240, QImage::Format_Grayscale8); +#if 0 + QImage img(640, 240, QImage::Format_Grayscale8); - // fetch palette + // fetch palette int bpp = 1 << (lcdBuf[1] >> 4); int ppb = 8 / bpp; uint16_t palette[16]; @@ -129,6 +130,37 @@ void MainWindow::updateScreen() 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))); } @@ -252,7 +284,7 @@ void MainWindow::on_stopButton_clicked() void MainWindow::on_stepTickButton_clicked() { // emu->executeUntil(emu->currentCycles() + (CLOCK_SPEED * 2)); - emu->executeUntil(emu->currentCycles() + 2500000); + emu->executeUntil(emu->currentCycles() + 25000000); updateScreen(); } @@ -307,7 +339,7 @@ void MainWindow::updateMemory() uint8_t block[0x100]; if (ok) { for (int i = 0; i < 0x100; i++) { - block[i] = emu->readPhysical(physBase + i, ARM710T::V8).value(); + block[i] = emu->readPhysical(physBase + i, ARM710::V8).value(); } } @@ -358,7 +390,7 @@ void MainWindow::on_writeByteButton_clicked() { uint32_t address = ui->memoryViewAddress->text().toUInt(nullptr, 16); uint8_t value = (uint8_t)ui->memoryWriteValue->text().toUInt(nullptr, 16); - emu->writeVirtual(value, address, ARM710T::V8); + emu->writeVirtual(value, address, ARM710::V8); updateMemory(); } @@ -366,6 +398,6 @@ void MainWindow::on_writeDwordButton_clicked() { uint32_t address = ui->memoryViewAddress->text().toUInt(nullptr, 16); uint32_t value = ui->memoryWriteValue->text().toUInt(nullptr, 16); - emu->writeVirtual(value, address, ARM710T::V32); + emu->writeVirtual(value, address, ARM710::V32); updateMemory(); } diff --git a/WindQt/mainwindow.h b/WindQt/mainwindow.h index a127ade..34071df 100644 --- a/WindQt/mainwindow.h +++ b/WindQt/mainwindow.h @@ -2,7 +2,7 @@ #define MAINWINDOW_H #include -#include "../WindCore/emu.h" +#include "../WindCore/clps7111.h" namespace Ui { class MainWindow; @@ -44,7 +44,7 @@ private slots: private: Ui::MainWindow *ui; - Emu *emu; + CLPS7111 *emu; QTimer *timer; void updateScreen(); void updateBreakpointsList();