add draft Osaris/ER4 emulation

This commit is contained in:
Ash Wolf 2019-12-24 23:34:02 +00:00
parent 0336426236
commit bf71b18d27
17 changed files with 1019 additions and 138 deletions

View File

@ -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

View File

@ -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);

View File

@ -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; }

497
WindCore/clps7111.cpp Normal file
View File

@ -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);
}

76
WindCore/clps7111.h Normal file
View File

@ -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; }
};

81
WindCore/clps7111_defs.h Normal file
View File

@ -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
};

133
WindCore/clps7600.cpp Normal file
View File

@ -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!!");
}
}

33
WindCore/clps7600.h Normal file
View File

@ -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);
};

View File

@ -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++)

View File

@ -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);

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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();
}

View File

@ -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();