case 5:
if (isTVersion)
cp15_faultStatus = what;
+#ifdef ARM710T_TLB
else
flushTlb();
+#endif
break;
case 6:
if (isTVersion)
cp15_faultAddress = what;
+#ifdef ARM710T_TLB
else
flushTlb(what);
break;
+#endif
case 7:
#ifdef ARM710T_CACHE
clearCache();
#endif
break;
case 8: {
+#ifdef ARM710T_TLB
if (isTVersion) {
if (CPOpc == 1)
flushTlb(what);
else
flushTlb();
}
+#endif
break;
}
}
// TLB
+#ifdef ARM710T_TLB
void ARM710::flushTlb() {
for (TlbEntry &e : tlb)
e = {0, 0, 0, 0};
}
}
}
+#endif
ARM710::TlbEntry *ARM710::_allocateTlbEntry(uint32_t addrMask, uint32_t addr) {
+#ifdef ARM710T_TLB
TlbEntry *entry = &tlb[nextTlbIndex];
+ nextTlbIndex = (nextTlbIndex + 1) % TlbSize;
+#else
+ TlbEntry *entry = &singleTlbEntry;
+#endif
entry->addrMask = addrMask;
entry->addr = addr & addrMask;
- nextTlbIndex = (nextTlbIndex + 1) % TlbSize;
return entry;
}
variant<ARM710::TlbEntry *, ARM710::MMUFault> ARM710::translateAddressUsingTlb(uint32_t virtAddr, TlbEntry *useMe) {
+#ifdef ARM710T_TLB
// first things first, do we have a matching entry in the TLB?
for (TlbEntry &e : tlb) {
if (e.addrMask && (virtAddr & e.addrMask) == e.addr)
return &e;
}
+#endif
// no, so do a page table walk
TlbEntry *entry;
// Speedhacks:
//#define ARM710T_CACHE
+//#define ARM710T_TLB
typedef optional<uint32_t> MaybeU32;
#ifdef ARM710T_CACHE
clearCache();
#endif
+#ifdef ARM710T_TLB
flushTlb();
+#endif
}
void setProcessorID(uint32_t v) { cp15_id = v; }
return (MMUFault)(baseFault | (isPage ? 2 : 0) | (domain << 4) | ((uint64_t)virtAddr << 32));
}
- enum { TlbSize = 64 };
struct TlbEntry { uint32_t addrMask, addr, lv1Entry, lv2Entry; };
+#ifdef ARM710T_TLB
+ enum { TlbSize = 64 };
TlbEntry tlb[TlbSize];
int nextTlbIndex = 0;
void flushTlb();
void flushTlb(uint32_t virtAddr);
- variant<TlbEntry *, MMUFault> translateAddressUsingTlb(uint32_t virtAddr, TlbEntry *useMe=nullptr);
- TlbEntry *_allocateTlbEntry(uint32_t addrMask, uint32_t addr);
+#else
+ TlbEntry singleTlbEntry;
+#endif
+ TlbEntry *_allocateTlbEntry(uint32_t addrMask, uint32_t addr);
+ variant<TlbEntry *, MMUFault> translateAddressUsingTlb(uint32_t virtAddr, TlbEntry *useMe=nullptr);
static uint32_t physAddrFromTlbEntry(TlbEntry *tlbEntry, uint32_t virtAddr);
MMUFault checkAccessPermissions(TlbEntry *entry, uint32_t virtAddr, bool isWrite) const;
void Emulator::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;
+ uint8_t tc1cfg = Timer::ENABLED; // always on with PS-7111!
+ if (value & 0x10) tc1cfg |= Timer::PERIODIC;
+ if (value & 0x20) tc1cfg |= Timer::MODE_512KHZ;
+ uint8_t tc2cfg = Timer::ENABLED;
+ if (value & 0x40) tc2cfg |= Timer::PERIODIC;
+ if (value & 0x80) tc2cfg |= Timer::MODE_512KHZ;
+ tc1.setConfig(tc1cfg);
+ tc2.setConfig(tc2cfg);
} else if (reg == INTMR1) {
interruptMask &= 0xFFFF0000;;
interruptMask |= (value & 0xFFFF);
tc2.clockSpeed = CLOCK_SPEED;
nextTickAt = TICK_INTERVAL;
+ tc1.nextTickAt = tc1.tickInterval();
+ tc2.nextTickAt = tc2.tickInterval();
rtc = getRTC();
reset();
class EmuBase : public ARM710
{
protected:
+#ifndef __EMSCRIPTEN__
std::unordered_set<uint32_t> _breakpoints;
+#endif
int64_t passedCycles = 0;
int64_t nextTickAt = 0;
uint8_t readKeyboard(int kScan);
virtual void setKeyboardKey(EpocKey key, bool value) = 0;
virtual void updateTouchInput(int32_t x, int32_t y, bool down) = 0;
+#ifndef __EMSCRIPTEN__
std::unordered_set<uint32_t> &breakpoints() { return _breakpoints; }
+#endif
uint64_t currentCycles() const { return passedCycles; }
};
PERIODIC = 1<<6,
ENABLED = 1<<7
};
- int64_t lastTicked;
+ int64_t nextTickAt;
uint8_t config;
uint32_t interval;
int32_t value;
interval = lval;
value = lval;
}
+ void setConfig(uint8_t cval) {
+ nextTickAt -= tickInterval();
+ config = cval;
+ nextTickAt += tickInterval();
+ }
bool tick(int64_t cycles) {
- if (cycles >= (lastTicked + tickInterval())) {
- lastTicked += tickInterval();
+ if (cycles >= nextTickAt) {
+ nextTickAt += tickInterval();
if (config & ENABLED) {
--value;
} else if ((reg & 0xF00) == 0x700) {
uart2.writeReg8(reg & 0xFF, value);
} else if (reg == TC1CTRL) {
- tc1.config = value;
+ tc1.setConfig(value);
} else if (reg == TC2CTRL) {
- tc2.config = value;
+ tc2.setConfig(value);
} else if (reg == PADR) {
uint32_t oldPorts = portValues;
portValues &= 0x00FFFFFF;
tc2.clockSpeed = CLOCK_SPEED;
nextTickAt = TICK_INTERVAL;
+ tc1.nextTickAt = tc1.tickInterval();
+ tc2.nextTickAt = tc2.tickInterval();
rtc = getRTC();
reset();
// what's running?
if (halted) {
// keep the clock moving
- passedCycles++;
+ // when does the next earliest thing happen?
+ // this stops us from spinning needlessly
+ int64_t nextEvent = nextTickAt;
+ if (tc1.nextTickAt < nextEvent) nextEvent = tc1.nextTickAt;
+ if (tc2.nextTickAt < nextEvent) nextEvent = tc2.nextTickAt;
+ if (cycles < nextEvent) nextEvent = cycles;
+ passedCycles = nextEvent;
} else {
if (auto v = virtToPhys(getGPR(15) - 0xC); v.has_value() && instructionReady())
debugPC(v.value());
passedCycles += tick();
+#ifndef __EMSCRIPTEN__
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;
- }
+#endif
}
}
}
#!/bin/sh
-FLAGS="-O3 --profiling -s WASM_OBJECT_FILES=0 -std=c++17"
+FLAGS="-O3 --profiling -g -s WASM_OBJECT_FILES=0 -std=c++17"
mkdir -p obj
for i in arm710 emubase etna windermere; do emcc -c $FLAGS -o obj/$i.o ../WindCore/$i.cpp; done
printf("SDL_SetVideoMode failed: %s\n", SDL_GetError());
return 1;
}
- // window = SDL_CreateWindow(
- // "WindEmu",
- // SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
- // emu->getDigitiserWidth(), emu->getDigitiserHeight(),
- // 0);
- // if (window == NULL) {
- // printf("SDL_CreateWindow failed: %s\n", SDL_GetError());
- // return 1;
- // }
+
+ EM_ASM("SDL.defaults.copyOnLock = false; SDL.defaults.discardOnLock = true; SDL.defaults.opaqueFrontBuffer = false;");
emscripten_set_main_loop(&emuEventLoop, 64, 1);