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:
|
case 5:
|
||||||
if (isTVersion)
|
if (isTVersion)
|
||||||
cp15_faultStatus = what;
|
cp15_faultStatus = what;
|
||||||
|
#ifdef ARM710T_TLB
|
||||||
else
|
else
|
||||||
flushTlb();
|
flushTlb();
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
if (isTVersion)
|
if (isTVersion)
|
||||||
cp15_faultAddress = what;
|
cp15_faultAddress = what;
|
||||||
|
#ifdef ARM710T_TLB
|
||||||
else
|
else
|
||||||
flushTlb(what);
|
flushTlb(what);
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
case 7:
|
case 7:
|
||||||
#ifdef ARM710T_CACHE
|
#ifdef ARM710T_CACHE
|
||||||
clearCache();
|
clearCache();
|
||||||
|
@ -680,12 +684,14 @@ uint32_t ARM710::execCP15RegisterTransfer(uint32_t CPOpc, bool L, uint32_t CRn,
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case 8: {
|
case 8: {
|
||||||
|
#ifdef ARM710T_TLB
|
||||||
if (isTVersion) {
|
if (isTVersion) {
|
||||||
if (CPOpc == 1)
|
if (CPOpc == 1)
|
||||||
flushTlb(what);
|
flushTlb(what);
|
||||||
else
|
else
|
||||||
flushTlb();
|
flushTlb();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -900,6 +906,7 @@ ARM710::MMUFault ARM710::writeVirtual(uint32_t value, uint32_t virtAddr, ValueSi
|
||||||
|
|
||||||
|
|
||||||
// TLB
|
// TLB
|
||||||
|
#ifdef ARM710T_TLB
|
||||||
void ARM710::flushTlb() {
|
void ARM710::flushTlb() {
|
||||||
for (TlbEntry &e : tlb)
|
for (TlbEntry &e : tlb)
|
||||||
e = {0, 0, 0, 0};
|
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) {
|
ARM710::TlbEntry *ARM710::_allocateTlbEntry(uint32_t addrMask, uint32_t addr) {
|
||||||
|
#ifdef ARM710T_TLB
|
||||||
TlbEntry *entry = &tlb[nextTlbIndex];
|
TlbEntry *entry = &tlb[nextTlbIndex];
|
||||||
|
nextTlbIndex = (nextTlbIndex + 1) % TlbSize;
|
||||||
|
#else
|
||||||
|
TlbEntry *entry = &singleTlbEntry;
|
||||||
|
#endif
|
||||||
entry->addrMask = addrMask;
|
entry->addrMask = addrMask;
|
||||||
entry->addr = addr & addrMask;
|
entry->addr = addr & addrMask;
|
||||||
nextTlbIndex = (nextTlbIndex + 1) % TlbSize;
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
variant<ARM710::TlbEntry *, ARM710::MMUFault> ARM710::translateAddressUsingTlb(uint32_t virtAddr, TlbEntry *useMe) {
|
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?
|
// first things first, do we have a matching entry in the TLB?
|
||||||
for (TlbEntry &e : tlb) {
|
for (TlbEntry &e : tlb) {
|
||||||
if (e.addrMask && (virtAddr & e.addrMask) == e.addr)
|
if (e.addrMask && (virtAddr & e.addrMask) == e.addr)
|
||||||
return &e;
|
return &e;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// no, so do a page table walk
|
// no, so do a page table walk
|
||||||
TlbEntry *entry;
|
TlbEntry *entry;
|
||||||
|
|
|
@ -18,6 +18,7 @@ using namespace std;
|
||||||
|
|
||||||
// Speedhacks:
|
// Speedhacks:
|
||||||
//#define ARM710T_CACHE
|
//#define ARM710T_CACHE
|
||||||
|
//#define ARM710T_TLB
|
||||||
|
|
||||||
typedef optional<uint32_t> MaybeU32;
|
typedef optional<uint32_t> MaybeU32;
|
||||||
|
|
||||||
|
@ -87,7 +88,9 @@ public:
|
||||||
#ifdef ARM710T_CACHE
|
#ifdef ARM710T_CACHE
|
||||||
clearCache();
|
clearCache();
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef ARM710T_TLB
|
||||||
flushTlb();
|
flushTlb();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void setProcessorID(uint32_t v) { cp15_id = v; }
|
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));
|
return (MMUFault)(baseFault | (isPage ? 2 : 0) | (domain << 4) | ((uint64_t)virtAddr << 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
enum { TlbSize = 64 };
|
|
||||||
struct TlbEntry { uint32_t addrMask, addr, lv1Entry, lv2Entry; };
|
struct TlbEntry { uint32_t addrMask, addr, lv1Entry, lv2Entry; };
|
||||||
|
#ifdef ARM710T_TLB
|
||||||
|
enum { TlbSize = 64 };
|
||||||
TlbEntry tlb[TlbSize];
|
TlbEntry tlb[TlbSize];
|
||||||
int nextTlbIndex = 0;
|
int nextTlbIndex = 0;
|
||||||
|
|
||||||
void flushTlb();
|
void flushTlb();
|
||||||
void flushTlb(uint32_t virtAddr);
|
void flushTlb(uint32_t virtAddr);
|
||||||
variant<TlbEntry *, MMUFault> translateAddressUsingTlb(uint32_t virtAddr, TlbEntry *useMe=nullptr);
|
#else
|
||||||
TlbEntry *_allocateTlbEntry(uint32_t addrMask, uint32_t addr);
|
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);
|
static uint32_t physAddrFromTlbEntry(TlbEntry *tlbEntry, uint32_t virtAddr);
|
||||||
MMUFault checkAccessPermissions(TlbEntry *entry, uint32_t virtAddr, bool isWrite) const;
|
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) {
|
void Emulator::writeReg32(uint32_t reg, uint32_t value) {
|
||||||
if (reg == SYSCON1) {
|
if (reg == SYSCON1) {
|
||||||
kScan = value & 0xF;
|
kScan = value & 0xF;
|
||||||
tc1.config = Timer::ENABLED; // always on with PS-7111!
|
uint8_t tc1cfg = Timer::ENABLED; // always on with PS-7111!
|
||||||
if (value & 0x10) tc1.config |= Timer::PERIODIC;
|
if (value & 0x10) tc1cfg |= Timer::PERIODIC;
|
||||||
if (value & 0x20) tc1.config |= Timer::MODE_512KHZ;
|
if (value & 0x20) tc1cfg |= Timer::MODE_512KHZ;
|
||||||
tc2.config = Timer::ENABLED;
|
uint8_t tc2cfg = Timer::ENABLED;
|
||||||
if (value & 0x40) tc2.config |= Timer::PERIODIC;
|
if (value & 0x40) tc2cfg |= Timer::PERIODIC;
|
||||||
if (value & 0x80) tc2.config |= Timer::MODE_512KHZ;
|
if (value & 0x80) tc2cfg |= Timer::MODE_512KHZ;
|
||||||
|
tc1.setConfig(tc1cfg);
|
||||||
|
tc2.setConfig(tc2cfg);
|
||||||
} else if (reg == INTMR1) {
|
} else if (reg == INTMR1) {
|
||||||
interruptMask &= 0xFFFF0000;;
|
interruptMask &= 0xFFFF0000;;
|
||||||
interruptMask |= (value & 0xFFFF);
|
interruptMask |= (value & 0xFFFF);
|
||||||
|
@ -277,6 +279,8 @@ void Emulator::configure() {
|
||||||
tc2.clockSpeed = CLOCK_SPEED;
|
tc2.clockSpeed = CLOCK_SPEED;
|
||||||
|
|
||||||
nextTickAt = TICK_INTERVAL;
|
nextTickAt = TICK_INTERVAL;
|
||||||
|
tc1.nextTickAt = tc1.tickInterval();
|
||||||
|
tc2.nextTickAt = tc2.tickInterval();
|
||||||
rtc = getRTC();
|
rtc = getRTC();
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
|
|
|
@ -103,7 +103,9 @@ enum EpocKey {
|
||||||
class EmuBase : public ARM710
|
class EmuBase : public ARM710
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
std::unordered_set<uint32_t> _breakpoints;
|
std::unordered_set<uint32_t> _breakpoints;
|
||||||
|
#endif
|
||||||
int64_t passedCycles = 0;
|
int64_t passedCycles = 0;
|
||||||
int64_t nextTickAt = 0;
|
int64_t nextTickAt = 0;
|
||||||
uint8_t readKeyboard(int kScan);
|
uint8_t readKeyboard(int kScan);
|
||||||
|
@ -127,7 +129,9 @@ public:
|
||||||
virtual void setKeyboardKey(EpocKey key, bool value) = 0;
|
virtual void setKeyboardKey(EpocKey key, bool value) = 0;
|
||||||
virtual void updateTouchInput(int32_t x, int32_t y, bool down) = 0;
|
virtual void updateTouchInput(int32_t x, int32_t y, bool down) = 0;
|
||||||
|
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
std::unordered_set<uint32_t> &breakpoints() { return _breakpoints; }
|
std::unordered_set<uint32_t> &breakpoints() { return _breakpoints; }
|
||||||
|
#endif
|
||||||
uint64_t currentCycles() const { return passedCycles; }
|
uint64_t currentCycles() const { return passedCycles; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ struct Timer {
|
||||||
PERIODIC = 1<<6,
|
PERIODIC = 1<<6,
|
||||||
ENABLED = 1<<7
|
ENABLED = 1<<7
|
||||||
};
|
};
|
||||||
int64_t lastTicked;
|
int64_t nextTickAt;
|
||||||
uint8_t config;
|
uint8_t config;
|
||||||
uint32_t interval;
|
uint32_t interval;
|
||||||
int32_t value;
|
int32_t value;
|
||||||
|
@ -23,9 +23,14 @@ struct Timer {
|
||||||
interval = lval;
|
interval = lval;
|
||||||
value = lval;
|
value = lval;
|
||||||
}
|
}
|
||||||
|
void setConfig(uint8_t cval) {
|
||||||
|
nextTickAt -= tickInterval();
|
||||||
|
config = cval;
|
||||||
|
nextTickAt += tickInterval();
|
||||||
|
}
|
||||||
bool tick(int64_t cycles) {
|
bool tick(int64_t cycles) {
|
||||||
if (cycles >= (lastTicked + tickInterval())) {
|
if (cycles >= nextTickAt) {
|
||||||
lastTicked += tickInterval();
|
nextTickAt += tickInterval();
|
||||||
|
|
||||||
if (config & ENABLED) {
|
if (config & ENABLED) {
|
||||||
--value;
|
--value;
|
||||||
|
|
|
@ -115,9 +115,9 @@ void Emulator::writeReg8(uint32_t reg, uint8_t value) {
|
||||||
} else if ((reg & 0xF00) == 0x700) {
|
} else if ((reg & 0xF00) == 0x700) {
|
||||||
uart2.writeReg8(reg & 0xFF, value);
|
uart2.writeReg8(reg & 0xFF, value);
|
||||||
} else if (reg == TC1CTRL) {
|
} else if (reg == TC1CTRL) {
|
||||||
tc1.config = value;
|
tc1.setConfig(value);
|
||||||
} else if (reg == TC2CTRL) {
|
} else if (reg == TC2CTRL) {
|
||||||
tc2.config = value;
|
tc2.setConfig(value);
|
||||||
} else if (reg == PADR) {
|
} else if (reg == PADR) {
|
||||||
uint32_t oldPorts = portValues;
|
uint32_t oldPorts = portValues;
|
||||||
portValues &= 0x00FFFFFF;
|
portValues &= 0x00FFFFFF;
|
||||||
|
@ -364,6 +364,8 @@ void Emulator::configure() {
|
||||||
tc2.clockSpeed = CLOCK_SPEED;
|
tc2.clockSpeed = CLOCK_SPEED;
|
||||||
|
|
||||||
nextTickAt = TICK_INTERVAL;
|
nextTickAt = TICK_INTERVAL;
|
||||||
|
tc1.nextTickAt = tc1.tickInterval();
|
||||||
|
tc2.nextTickAt = tc2.tickInterval();
|
||||||
rtc = getRTC();
|
rtc = getRTC();
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
|
@ -413,22 +415,25 @@ void Emulator::executeUntil(int64_t cycles) {
|
||||||
// what's running?
|
// what's running?
|
||||||
if (halted) {
|
if (halted) {
|
||||||
// keep the clock moving
|
// 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 {
|
} else {
|
||||||
if (auto v = virtToPhys(getGPR(15) - 0xC); v.has_value() && instructionReady())
|
if (auto v = virtToPhys(getGPR(15) - 0xC); v.has_value() && instructionReady())
|
||||||
debugPC(v.value());
|
debugPC(v.value());
|
||||||
passedCycles += tick();
|
passedCycles += tick();
|
||||||
|
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
uint32_t new_pc = getGPR(15) - 0xC;
|
uint32_t new_pc = getGPR(15) - 0xC;
|
||||||
if (_breakpoints.find(new_pc) != _breakpoints.end()) {
|
if (_breakpoints.find(new_pc) != _breakpoints.end()) {
|
||||||
log("⚠️ Breakpoint triggered at %08x!", new_pc);
|
log("⚠️ Breakpoint triggered at %08x!", new_pc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (new_pc >= 0x80000000 && new_pc <= 0x90000000) {
|
#endif
|
||||||
log("BAD PC %08x!!", new_pc);
|
|
||||||
logPcHistory();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/sh
|
#!/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
|
mkdir -p obj
|
||||||
for i in arm710 emubase etna windermere; do emcc -c $FLAGS -o obj/$i.o ../WindCore/$i.cpp; done
|
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());
|
printf("SDL_SetVideoMode failed: %s\n", SDL_GetError());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// window = SDL_CreateWindow(
|
|
||||||
// "WindEmu",
|
EM_ASM("SDL.defaults.copyOnLock = false; SDL.defaults.discardOnLock = true; SDL.defaults.opaqueFrontBuffer = false;");
|
||||||
// SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
|
||||||
// emu->getDigitiserWidth(), emu->getDigitiserHeight(),
|
|
||||||
// 0);
|
|
||||||
// if (window == NULL) {
|
|
||||||
// printf("SDL_CreateWindow failed: %s\n", SDL_GetError());
|
|
||||||
// return 1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
emscripten_set_main_loop(&emuEventLoop, 64, 1);
|
emscripten_set_main_loop(&emuEventLoop, 64, 1);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue