mirror of https://github.com/Treeki/WindEmu.git
add draft Osaris/ER4 emulation
This commit is contained in:
parent
0336426236
commit
bf71b18d27
|
@ -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
|
||||
|
|
|
@ -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<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));
|
||||
|
||||
|
@ -817,7 +832,7 @@ pair<MaybeU32, ARM710T::MMUFault> 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::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)
|
||||
|
@ -942,7 +957,7 @@ variant<ARM710T::TlbEntry *, ARM710T::MMUFault> 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);
|
|
@ -21,7 +21,7 @@ using namespace std;
|
|||
|
||||
typedef optional<uint32_t> 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<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; }
|
||||
|
@ -115,7 +116,7 @@ public:
|
|||
|
||||
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:
|
||||
|
@ -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; }
|
|
@ -0,0 +1,497 @@
|
|||
#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);
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
#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; }
|
||||
};
|
|
@ -0,0 +1,81 @@
|
|||
#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
|
||||
};
|
||||
|
|
@ -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!!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#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);
|
||||
};
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
#include "etna.h"
|
||||
#include "emu.h"
|
||||
#include "arm710.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -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++)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
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);
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
#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
|
||||
|
@ -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,
|
|
@ -1,7 +1,7 @@
|
|||
#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);
|
||||
|
@ -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);
|
|
@ -1,8 +1,10 @@
|
|||
#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
|
||||
|
@ -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);
|
|
@ -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 <time.h>
|
||||
#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, "<NULL>");
|
||||
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
|
|
@ -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 <unordered_set>
|
||||
|
||||
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);
|
|
@ -1,6 +1,6 @@
|
|||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
#include "../WindCore/wind.h"
|
||||
#include "../WindCore/clps7111_defs.h"
|
||||
#include <QTimer>
|
||||
#include <QKeyEvent>
|
||||
#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();
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#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();
|
||||
|
|
Loading…
Reference in New Issue