WindCore/osaris/clps7600.cpp
WindCore/series5mx/etna.cpp
WindCore/series5mx/windermere.cpp
+ WindCore/series7/sa1100.cpp
+ WindCore/series7/sa1100_memory.cpp
)
add_library(WindCore STATIC ${WIND_CORE_SOURCES})
--- /dev/null
+#include "sa1100.h"
+
+#include "common.h"
+
+#include <cstdint>
+
+namespace SA1100 {
+
+Emulator::Emulator() : EmuBase(false) {}
+
+uint32_t Emulator::getRTC() { return 0; }
+
+void Emulator::configure() {
+ if (configured)
+ return;
+
+ configured = true;
+ srand(1000);
+ nextTickAt = Series7::TICK_INTERVAL;
+ reset();
+}
+
+uint8_t* Emulator::getROMBuffer() { return ROM; }
+size_t Emulator::getROMSize() { return sizeof(ROM); }
+void Emulator::loadROM(uint8_t* buffer, size_t size) {
+ memcpy(ROM, buffer, size);
+}
+
+void Emulator::executeUntil(int64_t cycles) {
+ if (!configured)
+ configure();
+
+ while (!asleep && passedCycles < cycles) {
+ if (passedCycles >= nextTickAt) {
+ // increment RTCDIV
+ if ((pwrsr & 0x3F) == 0x3F) {
+ pwrsr &= ~0x3F;
+ } else {
+ pwrsr++;
+ }
+
+ nextTickAt += Series7::TICK_INTERVAL;
+ }
+
+ // what's running?
+ if (halted) {
+ // keep the clock moving
+ // when does the next earliest thing happen?
+ // this stops us from spinning needlessly
+ int64_t nextEvent = 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();
+ }
+ }
+}
+
+const char* Emulator::identifyObjectCon(uint32_t ptr) { return NULL; }
+
+void Emulator::fetchStr(uint32_t str, char* buf) {}
+
+void Emulator::fetchName(uint32_t obj, char* buf) {}
+
+void Emulator::fetchProcessFilename(uint32_t obj, char* buf) {}
+
+void Emulator::debugPC(uint32_t pc) {}
+
+const char* Emulator::getDeviceName() const { return "Series 7"; }
+int Emulator::getDigitiserWidth() const { return 783; }
+int Emulator::getDigitiserHeight() const { return 480; }
+int Emulator::getLCDOffsetX() const { return 71; }
+int Emulator::getLCDOffsetY() const { return 0; }
+int Emulator::getLCDWidth() const { return 640; }
+int Emulator::getLCDHeight() const { return 480; }
+
+void Emulator::readLCDIntoBuffer(uint8_t** lines, bool is32BitOutput) const {}
+
+void Emulator::diffPorts(uint32_t oldval, uint32_t newval) {}
+
+void Emulator::diffInterrupts(uint16_t oldval, uint16_t newval) {}
+
+uint32_t Emulator::readKeyboard() {}
+
+void Emulator::setKeyboardKey(EpocKey key, bool value) {}
+
+void Emulator::updateTouchInput(int32_t x, int32_t y, bool down) {}
+
+} // namespace SA1100
--- /dev/null
+#ifndef SA1100_H
+#define SA1100_H
+
+#include "emubase.h"
+#include "series7_defs.h"
+
+namespace SA1100 {
+
+// Relatively simple implementation of a StrongARM SA-1100 CPU
+//
+// The following resources are invaluable to determining how the SA-1100
+// operates:
+//
+// SA-1100 Technical documentation:
+// https://courses.cs.washington.edu/courses/cse466/00au/sa1100dev.pdf
+// Address space layout:
+// https://people.kth.se/~maguire/badge3/memorymap.html
+// ARMware emulator:
+// https://github.com/Halajohn/ARMware
+// bookboot:
+// https://web.archive.org/web/20060716045807/http://linux-7110.sourceforge.net/files/People/Klaasjan/netbook/
+
+class Emulator : public EmuBase {
+public:
+ // 16MB ROM
+ uint8_t ROM[0x1000000];
+ // 16MB RAM/bank0, mapped at base addr 0xC0000000
+ uint8_t MemoryBlockC0[0x1000000];
+ // 16MB RAM/bank1, mapped at base addr 0xC8000000
+ // On the netBook, the OS.img minus the 256-byte wrapper is copied to this RAM
+ // See the bookboot README file (linked above)
+ uint8_t MemoryBlockC8[0x1000000];
+ enum { MemoryBlockMask = 0x0FFFFFF };
+
+private:
+ uint32_t pwrsr = 0x00002000; // cold start flag
+ bool halted = false, asleep = false;
+ uint32_t getRTC();
+
+public:
+ MaybeU32 readPhysical(uint32_t physAddr, ValueSize valueSize) override;
+ bool writePhysical(uint32_t value, uint32_t physAddr,
+ ValueSize valueSize) override;
+
+private:
+ uint8_t readPhysical8(uint32_t physAddr);
+ uint32_t readPhysical32(uint32_t physAddr);
+
+ bool writePhysical8(uint8_t value, uint32_t physAddr);
+ bool writePhysical32(uint32_t value, uint32_t physAddr);
+
+ uint8_t readPCM8(uint32_t physAddr);
+ uint32_t readPCM32(uint32_t physAddr);
+
+ uint8_t readSCM8(uint32_t physAddr);
+ uint32_t readSCM32(uint32_t physAddr);
+
+ bool writePCM8(uint8_t value, uint32_t physAddr);
+ bool writePCM32(uint32_t value, uint32_t physAddr);
+
+ bool writeSCM8(uint8_t value, uint32_t physAddr);
+ bool writeSCM32(uint32_t value, uint32_t physAddr);
+
+ bool configured = false;
+ void configure();
+
+ const char* identifyObjectCon(uint32_t ptr);
+ void fetchStr(uint32_t str, char* buf);
+ void fetchName(uint32_t obj, char* buf);
+ void fetchProcessFilename(uint32_t obj, char* buf);
+ void debugPC(uint32_t pc);
+ void diffPorts(uint32_t oldval, uint32_t newval);
+ void diffInterrupts(uint16_t oldval, uint16_t newval);
+ uint32_t readKeyboard();
+
+public:
+ Emulator();
+ uint8_t* getROMBuffer() override;
+ size_t getROMSize() override;
+ void loadROM(uint8_t* buffer, size_t size) override;
+ void executeUntil(int64_t cycles) override;
+ int32_t getClockSpeed() const override { return Series7::CLOCK_SPEED; }
+ const char* getDeviceName() const override;
+ int getDigitiserWidth() const override;
+ int getDigitiserHeight() const override;
+ int getLCDOffsetX() const override;
+ int getLCDOffsetY() const override;
+ int getLCDWidth() const override;
+ int getLCDHeight() const override;
+ void readLCDIntoBuffer(uint8_t** lines, bool is32BitOutput) const override;
+ void setKeyboardKey(EpocKey key, bool value) override;
+ void updateTouchInput(int32_t x, int32_t y, bool down) override;
+};
+
+} // namespace SA1100
+
+#endif // SA1100_H
--- /dev/null
+#include "sa1100.h"
+
+#include "common.h"
+
+namespace SA1100 {
+
+MaybeU32 Emulator::readPhysical(uint32_t physAddr, ValueSize valueSize) {
+ if (valueSize == V8) {
+ return readPhysical8(physAddr);
+ } else {
+ return readPhysical32(physAddr);
+ }
+}
+
+bool Emulator::writePhysical(uint32_t value, uint32_t physAddr,
+ ValueSize valueSize) {
+ uint8_t region = (physAddr >> 24) & 0xFF;
+ if (valueSize == V8) {
+ return writePhysical8((uint8_t)value, physAddr);
+ } else {
+ return writePhysical32(value, physAddr);
+ }
+}
+
+uint8_t Emulator::readPCM8(uint32_t physAddr) {
+ // Peripheral Control Modules
+ return 0x0;
+}
+
+bool Emulator::writePCM8(uint8_t value, uint32_t physAddr) { return true; }
+
+uint32_t Emulator::readPCM32(uint32_t physAddr) {
+ // Peripheral Control Modules
+ return 0x0;
+}
+
+bool Emulator::writePCM32(uint32_t value, uint32_t physAddr) { return true; }
+
+uint8_t Emulator::readSCM8(uint32_t physAddr) {
+ // System Control Modules
+ return 0x0;
+}
+
+bool Emulator::writeSCM8(uint8_t value, uint32_t physAddr) { return true; }
+
+uint32_t Emulator::readSCM32(uint32_t physAddr) {
+ // System Control Modules
+ return 0x0;
+}
+
+bool Emulator::writeSCM32(uint32_t value, uint32_t physAddr) { return true; }
+
+uint8_t Emulator::readPhysical8(uint32_t physAddr) {
+ uint8_t region = (physAddr >> 24) & 0xFF;
+
+ switch (region) {
+ case 0x00:
+ return ROM[physAddr & 0xFFFFFF];
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2A:
+ case 0x2B:
+ case 0x2C:
+ case 0x2D:
+ case 0x2E:
+ case 0x2F:
+ // PCMCIA slot 0
+ return 0x0;
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x3A:
+ case 0x3B:
+ case 0x3C:
+ case 0x3D:
+ case 0x3E:
+ case 0x3F:
+ // PCMCIA slot 1
+ return 0x0;
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x44:
+ case 0x45:
+ case 0x46:
+ case 0x47:
+ case 0x48:
+ case 0x49:
+ case 0x4A:
+ case 0x4B:
+ case 0x4C:
+ case 0x4D:
+ case 0x4E:
+ case 0x4F:
+ case 0x50:
+ case 0x51:
+ case 0x52:
+ case 0x53:
+ case 0x54:
+ case 0x55:
+ case 0x56:
+ case 0x57:
+ case 0x58:
+ case 0x59:
+ case 0x5A:
+ case 0x5B:
+ case 0x5C:
+ case 0x5D:
+ case 0x5E:
+ case 0x5F:
+ case 0x60:
+ case 0x61:
+ case 0x62:
+ case 0x63:
+ case 0x64:
+ case 0x65:
+ case 0x66:
+ case 0x67:
+ case 0x68:
+ case 0x69:
+ case 0x6A:
+ case 0x6B:
+ case 0x6C:
+ case 0x6D:
+ case 0x6E:
+ case 0x6F:
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ case 0x74:
+ case 0x75:
+ case 0x76:
+ case 0x77:
+ case 0x78:
+ case 0x79:
+ case 0x7A:
+ case 0x7B:
+ case 0x7C:
+ case 0x7D:
+ case 0x7E:
+ case 0x7F:
+ // Reserved, causes a data abort exception
+ return 0x0;
+ case 0x80:
+ // Peripheral Control Modules
+ return readPCM8(physAddr);
+ case 0x90:
+ // System Control Modules
+ return readSCM8(physAddr);
+ case 0xA0:
+ // Memory Control Registers
+ // Not valid in byte access
+ return 0x0;
+ case 0xB0:
+ // LCD/DMA Control Registers
+ return 0x0;
+ case 0xC0:
+ case 0xC1:
+ case 0xC2:
+ case 0xC3:
+ case 0xC4:
+ case 0xC5:
+ case 0xC6:
+ case 0xC7:
+ return MemoryBlockC0[physAddr & MemoryBlockMask];
+ case 0xC8:
+ case 0xC9:
+ case 0xCA:
+ case 0xCB:
+ case 0xCC:
+ case 0xCD:
+ case 0xCE:
+ case 0xCF:
+ return MemoryBlockC8[physAddr & MemoryBlockMask];
+ default:
+ return 0x0; // just throw accesses to unmapped RAM away
+ }
+}
+
+bool Emulator::writePhysical8(uint8_t value, uint32_t physAddr) {
+ uint8_t region = (physAddr >> 24) & 0xFF;
+
+ switch (region) {
+ case 0x00:
+ // Read-only
+ return false;
+ break;
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2A:
+ case 0x2B:
+ case 0x2C:
+ case 0x2D:
+ case 0x2E:
+ case 0x2F:
+ // PCMCIA slot 0
+ return true;
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x3A:
+ case 0x3B:
+ case 0x3C:
+ case 0x3D:
+ case 0x3E:
+ case 0x3F:
+ // PCMCIA slot 1
+ return true;
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x44:
+ case 0x45:
+ case 0x46:
+ case 0x47:
+ case 0x48:
+ case 0x49:
+ case 0x4A:
+ case 0x4B:
+ case 0x4C:
+ case 0x4D:
+ case 0x4E:
+ case 0x4F:
+ case 0x50:
+ case 0x51:
+ case 0x52:
+ case 0x53:
+ case 0x54:
+ case 0x55:
+ case 0x56:
+ case 0x57:
+ case 0x58:
+ case 0x59:
+ case 0x5A:
+ case 0x5B:
+ case 0x5C:
+ case 0x5D:
+ case 0x5E:
+ case 0x5F:
+ case 0x60:
+ case 0x61:
+ case 0x62:
+ case 0x63:
+ case 0x64:
+ case 0x65:
+ case 0x66:
+ case 0x67:
+ case 0x68:
+ case 0x69:
+ case 0x6A:
+ case 0x6B:
+ case 0x6C:
+ case 0x6D:
+ case 0x6E:
+ case 0x6F:
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ case 0x74:
+ case 0x75:
+ case 0x76:
+ case 0x77:
+ case 0x78:
+ case 0x79:
+ case 0x7A:
+ case 0x7B:
+ case 0x7C:
+ case 0x7D:
+ case 0x7E:
+ case 0x7F:
+ // Reserved, causes a data abort exception
+ return false;
+ case 0x80:
+ // Peripheral Control Modules
+ return writePCM8(value, physAddr);
+ case 0x90:
+ // System Control Modules
+ return writeSCM8(value, physAddr);
+ case 0xA0:
+ // Memory Control Registers
+ // Invalid to write to with bytes
+ return false;
+ case 0xB0:
+ // LCD/DMA Control Registers
+ return true;
+ case 0xC0:
+ case 0xC1:
+ case 0xC2:
+ case 0xC3:
+ case 0xC4:
+ case 0xC5:
+ case 0xC6:
+ case 0xC7:
+ MemoryBlockC0[physAddr & MemoryBlockMask] = value;
+ return true;
+ case 0xC8:
+ case 0xC9:
+ case 0xCA:
+ case 0xCB:
+ case 0xCC:
+ case 0xCD:
+ case 0xCE:
+ case 0xCF:
+ MemoryBlockC8[physAddr & MemoryBlockMask] = value;
+ return true;
+ default:
+ // just throw accesses to unmapped RAM away
+ return true;
+ }
+}
+
+uint32_t Emulator::readPhysical32(uint32_t physAddr) {
+ uint8_t region = (physAddr >> 24) & 0xFF;
+ uint32_t result;
+
+ switch (region) {
+ case 0x00:
+ LOAD_32LE(result, physAddr & 0xFFFFFF, ROM);
+ break;
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2A:
+ case 0x2B:
+ case 0x2C:
+ case 0x2D:
+ case 0x2E:
+ case 0x2F:
+ // PCMCIA slot 0
+ result = 0x0;
+ break;
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x3A:
+ case 0x3B:
+ case 0x3C:
+ case 0x3D:
+ case 0x3E:
+ case 0x3F:
+ // PCMCIA slot 1
+ result = 0x0;
+ break;
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x44:
+ case 0x45:
+ case 0x46:
+ case 0x47:
+ case 0x48:
+ case 0x49:
+ case 0x4A:
+ case 0x4B:
+ case 0x4C:
+ case 0x4D:
+ case 0x4E:
+ case 0x4F:
+ case 0x50:
+ case 0x51:
+ case 0x52:
+ case 0x53:
+ case 0x54:
+ case 0x55:
+ case 0x56:
+ case 0x57:
+ case 0x58:
+ case 0x59:
+ case 0x5A:
+ case 0x5B:
+ case 0x5C:
+ case 0x5D:
+ case 0x5E:
+ case 0x5F:
+ case 0x60:
+ case 0x61:
+ case 0x62:
+ case 0x63:
+ case 0x64:
+ case 0x65:
+ case 0x66:
+ case 0x67:
+ case 0x68:
+ case 0x69:
+ case 0x6A:
+ case 0x6B:
+ case 0x6C:
+ case 0x6D:
+ case 0x6E:
+ case 0x6F:
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ case 0x74:
+ case 0x75:
+ case 0x76:
+ case 0x77:
+ case 0x78:
+ case 0x79:
+ case 0x7A:
+ case 0x7B:
+ case 0x7C:
+ case 0x7D:
+ case 0x7E:
+ case 0x7F:
+ // Reserved, causes a data abort exception
+ result = 0x0;
+ break;
+ case 0x80:
+ // Peripheral Control Modules
+ result = readPCM32(physAddr);
+ break;
+ case 0x90:
+ // System Control Modules
+ result = readSCM32(physAddr);
+ break;
+ case 0xA0:
+ // Memory Control Registers
+ result = 0x0;
+ break;
+ case 0xB0:
+ // LCD/DMA Control Registers
+ result = 0x0;
+ break;
+ case 0xC0:
+ case 0xC1:
+ case 0xC2:
+ case 0xC3:
+ case 0xC4:
+ case 0xC5:
+ case 0xC6:
+ case 0xC7:
+ LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockC0);
+ break;
+ case 0xC8:
+ case 0xC9:
+ case 0xCA:
+ case 0xCB:
+ case 0xCC:
+ case 0xCD:
+ case 0xCE:
+ case 0xCF:
+ LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockC8);
+ break;
+ default:
+ return 0x0; // just throw accesses to unmapped RAM away
+ }
+
+ return result;
+}
+
+bool Emulator::writePhysical32(uint32_t value, uint32_t physAddr) {
+ uint8_t region = (physAddr >> 24) & 0xFF;
+
+ switch (region) {
+ case 0x00:
+ // Read-only
+ return false;
+ break;
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2A:
+ case 0x2B:
+ case 0x2C:
+ case 0x2D:
+ case 0x2E:
+ case 0x2F:
+ // PCMCIA slot 0
+ return true;
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x3A:
+ case 0x3B:
+ case 0x3C:
+ case 0x3D:
+ case 0x3E:
+ case 0x3F:
+ // PCMCIA slot 1
+ return true;
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x44:
+ case 0x45:
+ case 0x46:
+ case 0x47:
+ case 0x48:
+ case 0x49:
+ case 0x4A:
+ case 0x4B:
+ case 0x4C:
+ case 0x4D:
+ case 0x4E:
+ case 0x4F:
+ case 0x50:
+ case 0x51:
+ case 0x52:
+ case 0x53:
+ case 0x54:
+ case 0x55:
+ case 0x56:
+ case 0x57:
+ case 0x58:
+ case 0x59:
+ case 0x5A:
+ case 0x5B:
+ case 0x5C:
+ case 0x5D:
+ case 0x5E:
+ case 0x5F:
+ case 0x60:
+ case 0x61:
+ case 0x62:
+ case 0x63:
+ case 0x64:
+ case 0x65:
+ case 0x66:
+ case 0x67:
+ case 0x68:
+ case 0x69:
+ case 0x6A:
+ case 0x6B:
+ case 0x6C:
+ case 0x6D:
+ case 0x6E:
+ case 0x6F:
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ case 0x74:
+ case 0x75:
+ case 0x76:
+ case 0x77:
+ case 0x78:
+ case 0x79:
+ case 0x7A:
+ case 0x7B:
+ case 0x7C:
+ case 0x7D:
+ case 0x7E:
+ case 0x7F:
+ // Reserved, causes a data abort exception
+ return false;
+ case 0x80:
+ // Peripheral Control Modules
+ return writePCM32(value, physAddr);
+ case 0x90:
+ // System Control Modules
+ return writeSCM32(value, physAddr);
+ case 0xA0:
+ // Memory Control Registers
+ return false;
+ case 0xB0:
+ // LCD/DMA Control Registers
+ return true;
+ case 0xC0:
+ case 0xC1:
+ case 0xC2:
+ case 0xC3:
+ case 0xC4:
+ case 0xC5:
+ case 0xC6:
+ case 0xC7:
+ STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockC0);
+ return true;
+ case 0xC8:
+ case 0xC9:
+ case 0xCA:
+ case 0xCB:
+ case 0xCC:
+ case 0xCD:
+ case 0xCE:
+ case 0xCF:
+ STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockC8);
+ return true;
+ default:
+ // just throw accesses to unmapped RAM away
+ return true;
+ }
+}
+
+} // namespace SA1100
--- /dev/null
+#ifndef PSION7_DEFS_H
+#define PSION7_DEFS_H
+
+namespace Series7 {
+
+enum {
+ CLOCK_SPEED = 132710000, // 132.71 MHz
+ TICKS_3_6864_MHZ = CLOCK_SPEED / 3686400,
+ TICKS_1_HZ = CLOCK_SPEED / 1,
+ TICK_INTERVAL = CLOCK_SPEED / 64
+};
+
+} // namespace Series7
+
+#endif // PSION7_DEFS_H