mirror of https://github.com/Treeki/WindEmu.git
make some things a bit more optimised for web usage
This commit is contained in:
parent
015f6c94d4
commit
621d21abe7
|
@ -664,15 +664,19 @@ uint32_t ARM710::execCP15RegisterTransfer(uint32_t CPOpc, bool L, uint32_t CRn,
|
|||
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();
|
||||
|
@ -680,12 +684,14 @@ uint32_t ARM710::execCP15RegisterTransfer(uint32_t CPOpc, bool L, uint32_t CRn,
|
|||
#endif
|
||||
break;
|
||||
case 8: {
|
||||
#ifdef ARM710T_TLB
|
||||
if (isTVersion) {
|
||||
if (CPOpc == 1)
|
||||
flushTlb(what);
|
||||
else
|
||||
flushTlb();
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -900,6 +906,7 @@ ARM710::MMUFault ARM710::writeVirtual(uint32_t value, uint32_t virtAddr, ValueSi
|
|||
|
||||
|
||||
// TLB
|
||||
#ifdef ARM710T_TLB
|
||||
void ARM710::flushTlb() {
|
||||
for (TlbEntry &e : tlb)
|
||||
e = {0, 0, 0, 0};
|
||||
|
@ -912,21 +919,28 @@ void ARM710::flushTlb(uint32_t virtAddr) {
|
|||
}
|
||||
}
|
||||
}
|
||||
#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;
|
||||
|
|
|
@ -18,6 +18,7 @@ using namespace std;
|
|||
|
||||
// Speedhacks:
|
||||
//#define ARM710T_CACHE
|
||||
//#define ARM710T_TLB
|
||||
|
||||
typedef optional<uint32_t> MaybeU32;
|
||||
|
||||
|
@ -87,7 +88,9 @@ public:
|
|||
#ifdef ARM710T_CACHE
|
||||
clearCache();
|
||||
#endif
|
||||
#ifdef ARM710T_TLB
|
||||
flushTlb();
|
||||
#endif
|
||||
}
|
||||
|
||||
void setProcessorID(uint32_t v) { cp15_id = v; }
|
||||
|
@ -239,16 +242,20 @@ private:
|
|||
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;
|
||||
|
||||
|
|
|
@ -147,12 +147,14 @@ void Emulator::writeReg8(uint32_t reg, uint8_t value) {
|
|||
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);
|
||||
|
@ -277,6 +279,8 @@ void Emulator::configure() {
|
|||
tc2.clockSpeed = CLOCK_SPEED;
|
||||
|
||||
nextTickAt = TICK_INTERVAL;
|
||||
tc1.nextTickAt = tc1.tickInterval();
|
||||
tc2.nextTickAt = tc2.tickInterval();
|
||||
rtc = getRTC();
|
||||
|
||||
reset();
|
||||
|
|
|
@ -103,7 +103,9 @@ enum EpocKey {
|
|||
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);
|
||||
|
@ -127,7 +129,9 @@ public:
|
|||
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; }
|
||||
};
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ struct Timer {
|
|||
PERIODIC = 1<<6,
|
||||
ENABLED = 1<<7
|
||||
};
|
||||
int64_t lastTicked;
|
||||
int64_t nextTickAt;
|
||||
uint8_t config;
|
||||
uint32_t interval;
|
||||
int32_t value;
|
||||
|
@ -23,9 +23,14 @@ struct Timer {
|
|||
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;
|
||||
|
|
|
@ -115,9 +115,9 @@ void Emulator::writeReg8(uint32_t reg, uint8_t 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;
|
||||
|
@ -364,6 +364,8 @@ void Emulator::configure() {
|
|||
tc2.clockSpeed = CLOCK_SPEED;
|
||||
|
||||
nextTickAt = TICK_INTERVAL;
|
||||
tc1.nextTickAt = tc1.tickInterval();
|
||||
tc2.nextTickAt = tc2.tickInterval();
|
||||
rtc = getRTC();
|
||||
|
||||
reset();
|
||||
|
@ -413,22 +415,25 @@ void Emulator::executeUntil(int64_t cycles) {
|
|||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/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
|
||||
|
|
|
@ -120,15 +120,8 @@ int main(int argc, char **argv) {
|
|||
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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue