make some things a bit more optimised for web usage

This commit is contained in:
Ash Wolf 2019-12-26 00:19:37 +00:00
parent 015f6c94d4
commit 621d21abe7
8 changed files with 63 additions and 31 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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