#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 \
decoder-inlines.h \
common.h \
arm.h \
- emu.h
+ windermere.h
unix {
target.path = /usr/lib
INSTALLS += target
-#include "arm710t.h"
+#include "arm710.h"
#include "common.h"
// this will need changing if this code ever compiles on big-endian procs
}
-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];
}
-void ARM710T::switchMode(Mode newMode) {
+void ARM710::switchMode(Mode newMode) {
auto oldMode = currentMode();
if (newMode != oldMode) {
// log("Switching mode! %x", 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;
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
-uint32_t ARM710T::tick() {
+uint32_t ARM710::tick() {
// pop an instruction off the end of the pipeline
bool haveInsn = false;
uint32_t insn;
}
-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);
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;
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
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);
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);
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;
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;
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;
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;
+ 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
- case 7: clearCache(); log("cache cleared"); break;
+ clearCache();
+ log("cache cleared");
#endif
+ break;
case 8: {
- if (CPOpc == 1)
- flushTlb(what);
- else
- flushTlb();
+ if (isTVersion) {
+ if (CPOpc == 1)
+ flushTlb(what);
+ else
+ flushTlb();
+ }
break;
}
}
#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);
}
-MaybeU32 ARM710T::virtToPhys(uint32_t virtAddr) {
+MaybeU32 ARM710::virtToPhys(uint32_t virtAddr) {
if (!isMMUEnabled())
return 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
}
-pair<MaybeU32, ARM710T::MMUFault> ARM710T::readVirtual(uint32_t virtAddr, ValueSize valueSize) {
+pair<MaybeU32, ARM710::MMUFault> ARM710::readVirtual(uint32_t virtAddr, ValueSize valueSize) {
if (isAlignmentFaultEnabled() && valueSize == V32 && virtAddr & 3)
return make_pair(MaybeU32(), encodeFault(AlignmentFault, 0, virtAddr));
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);
// 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};
}
}
-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;
return entry;
}
-variant<ARM710T::TlbEntry *, ARM710T::MMUFault> ARM710T::translateAddressUsingTlb(uint32_t virtAddr, TlbEntry *useMe) {
+variant<ARM710::TlbEntry *, ARM710::MMUFault> 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)
-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;
}
-void ARM710T::reportFault(MMUFault fault) {
+void ARM710::reportFault(MMUFault fault) {
if (fault != NoFault) {
if ((fault & 0xF) != NonMMUError) {
cp15_faultStatus = fault & (MMUFaultTypeMask | MMUFaultDomainMask);
}
-void ARM710T::log(const char *format, ...) {
+void ARM710::log(const char *format, ...) {
if (logger) {
char buffer[1024];
}
}
-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);
typedef optional<uint32_t> MaybeU32;
-class ARM710T
+class ARM710
{
public:
enum ValueSize { V8 = 0, V32 = 1 };
- ARM710T() {
- cp15_id = 0x41807100;
+ ARM710(bool _isTVersion) {
+ isTVersion = _isTVersion;
+ cp15_id = _isTVersion ? 0x41807100 : 0x41047100;
clearAllValues();
}
- virtual ~ARM710T() { }
+ virtual ~ARM710() { }
void clearAllValues() {
bank = MainBank;
pair<MaybeU32, MMUFault> 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; }
void setLogger(std::function<void(const char *)> newLogger) { logger = newLogger; }
uint32_t lastPcExecuted() const { return pcHistory[(pcHistoryIndex - 1) % PcHistoryCount].addr; }
-protected:
+public:
void log(const char *format, ...);
void logPcHistory();
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; }
--- /dev/null
+#include "clps7111.h"
+#include "clps7111_defs.h"
+#include "hardware.h"
+#include <time.h>
+#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<<TINT);
+ }
+ if (tc1.tick(passedCycles))
+ pendingInterrupts |= (1<<TC1OI);
+ if (tc2.tick(passedCycles))
+ pendingInterrupts |= (1<<TC2OI);
+
+ if ((pendingInterrupts & interruptMask & FIQ_INTERRUPTS) != 0 && canAcceptFIQ()) {
+ requestFIQ();
+ halted = false;
+ }
+ if ((pendingInterrupts & interruptMask & IRQ_INTERRUPTS) != 0 && canAcceptIRQ()) {
+ requestIRQ();
+ halted = false;
+ }
+
+ // what's running?
+ if (halted) {
+ // keep the clock moving
+ passedCycles++;
+ } else {
+ if (auto v = virtToPhys(getGPR(15) - 0xC); v.has_value() && instructionReady())
+ debugPC(v.value());
+ passedCycles += tick();
+
+ uint32_t new_pc = getGPR(15) - 0xC;
+ if (_breakpoints.find(new_pc) != _breakpoints.end()) {
+ log("⚠️ Breakpoint triggered at %08x!", new_pc);
+ return;
+ }
+ if (new_pc >= 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, "<NULL>");
+ 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);
+}
--- /dev/null
+#pragma once
+#include "arm710.h"
+#include "clps7111_defs.h"
+#include "clps7600.h"
+#include "hardware.h"
+#include "etna.h"
+#include <unordered_set>
+
+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<uint32_t> _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<uint32_t> &breakpoints() { return _breakpoints; }
+ uint64_t currentCycles() const { return passedCycles; }
+};
--- /dev/null
+#pragma once
+#include <stdint.h>
+
+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
+};
+
--- /dev/null
+#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!!");
+ }
+}
--- /dev/null
+#pragma once
+#include <stdint.h>
+#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);
+};
+
#include "etna.h"
-#include "emu.h"
+#include "arm710.h"
#include <stdio.h>
#include <string.h>
}
-Etna::Etna(Emu *owner) {
+Etna::Etna(ARM710 *owner) {
this->owner = owner;
for (int i = 0; i < 0x80; i++)
#pragma once
#include <stdint.h>
-class Emu;
+class ARM710;
class Etna {
uint8_t prom[0x80] = {};
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);
#pragma once
-#include "wind.h"
-#include "arm710t.h"
+#include "arm710.h"
#include <stdio.h>
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
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;
}
};
+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,
-#include "wind.h"
+#include "wind_defs.h"
#include <stdio.h>
-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);
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);
#pragma once
#include <stdint.h>
-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
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,
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);
-#include "emu.h"
-#include "wind.h"
-#include "wind_hw.h"
+#include "windermere.h"
+#include "wind_defs.h"
+#include "hardware.h"
#include <time.h>
#include "common.h"
//#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) {
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;
}
}
-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) {
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;
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;
// 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;
} 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;
}
}
-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;
}
-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)
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)
-void Emu::configure() {
+void Windermere::configure() {
if (configured) return;
configured = true;
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();
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();
}
}
-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);
-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));
// 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";
return NULL;
}
-void Emu::fetchStr(uint32_t str, char *buf) {
+void Windermere::fetchStr(uint32_t str, char *buf) {
if (str == 0) {
strcpy(buf, "<NULL>");
return;
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()
}
-const uint8_t *Emu::getLCDBuffer() const {
+const uint8_t *Windermere::getLCDBuffer() const {
if ((lcdAddress >> 24) == 0xC0)
return &MemoryBlockC0[lcdAddress & MemoryBlockMask];
else
}
-uint8_t Emu::readKeyboard() {
+uint8_t Windermere::readKeyboard() {
uint8_t val = 0;
if (kScan & 8) {
// Select one keyboard
#pragma once
-#include "arm710t.h"
-#include "wind_hw.h"
+#include "arm710.h"
+#include "wind_defs.h"
+#include "hardware.h"
#include "etna.h"
#include <unordered_set>
-class Emu : public ARM710T {
+class Windermere : public ARM710 {
public:
uint8_t ROM[0x1000000];
uint8_t ROM2[0x40000];
bool keyboardKeys[8*7] = {0};
public:
- Emu();
+ Windermere();
void loadROM(const char *path);
void dumpRAM(const char *path);
void executeUntil(int64_t cycles);
#include "mainwindow.h"
#include "ui_mainwindow.h"
-#include "../WindCore/wind.h"
+#include "../WindCore/clps7111_defs.h"
#include <QTimer>
#include <QKeyEvent>
#include "../WindCore/decoder.h"
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);
});
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);
// 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];
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)));
}
void MainWindow::on_stepTickButton_clicked()
{
// emu->executeUntil(emu->currentCycles() + (CLOCK_SPEED * 2));
- emu->executeUntil(emu->currentCycles() + 2500000);
+ emu->executeUntil(emu->currentCycles() + 25000000);
updateScreen();
}
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();
}
}
{
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();
}
{
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();
}
#define MAINWINDOW_H
#include <QMainWindow>
-#include "../WindCore/emu.h"
+#include "../WindCore/clps7111.h"
namespace Ui {
class MainWindow;
private:
Ui::MainWindow *ui;
- Emu *emu;
+ CLPS7111 *emu;
QTimer *timer;
void updateScreen();
void updateBreakpointsList();