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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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