From 3d0d97ae2cc0d6f72baba4448e99dfffc3336d14 Mon Sep 17 00:00:00 2001 From: George Wright Date: Sun, 23 Jan 2022 00:25:40 -0800 Subject: [PATCH] Initial stubbed implementation of an SA-1100 core --- WindCore/WindCore.pro | 11 +- WindCore/arm710.cpp | 35 +- WindCore/arm710.h | 2 +- WindCore/clps7111.cpp | 2 +- WindCore/clps7111.h | 2 +- WindCore/emubase.h | 2 +- WindCore/sa1100.cpp | 1073 +++++++++++++++++++++++++++++++ WindCore/sa1100.h | 112 ++++ WindCore/sa1100/memory_conf.cpp | 99 +++ WindCore/sa1100/memory_conf.h | 93 +++ WindCore/sa1100_defs.h | 97 +++ WindCore/windermere.cpp | 2 +- WindCore/windermere.h | 2 +- WindEmu.pro | 2 + WindQt/main.cpp | 20 +- WindQt/mainwindow.cpp | 2 +- 16 files changed, 1521 insertions(+), 35 deletions(-) create mode 100644 WindCore/sa1100.cpp create mode 100644 WindCore/sa1100.h create mode 100644 WindCore/sa1100/memory_conf.cpp create mode 100644 WindCore/sa1100/memory_conf.h create mode 100644 WindCore/sa1100_defs.h diff --git a/WindCore/WindCore.pro b/WindCore/WindCore.pro index f39561e..b0b2353 100644 --- a/WindCore/WindCore.pro +++ b/WindCore/WindCore.pro @@ -16,6 +16,7 @@ CONFIG += staticlib c++17 # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS +#QMAKE_CXXFLAGS += QMAKE_CXXFLAGS_WARN_OFF # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. @@ -30,7 +31,9 @@ SOURCES += \ etna.cpp \ decoder.c \ decoder-arm.c \ - windermere.cpp + windermere.cpp \ + sa1100.cpp \ + sa1100/memory_conf.cpp HEADERS += \ arm710.h \ @@ -49,8 +52,10 @@ HEADERS += \ decoder.h \ decoder-inlines.h \ common.h \ - windermere.h + windermere.h \ + sa1100.h \ + sa1100/memory_conf.h unix { target.path = /usr/lib INSTALLS += target -} +} \ No newline at end of file diff --git a/WindCore/arm710.cpp b/WindCore/arm710.cpp index eaa6a01..807c8cb 100644 --- a/WindCore/arm710.cpp +++ b/WindCore/arm710.cpp @@ -37,7 +37,7 @@ void ARM710::switchBank(BankIndex newBank) { void ARM710::switchMode(Mode newMode) { auto oldMode = currentMode(); if (newMode != oldMode) { -// log("Switching mode! %x", newMode); + log("Switching mode! %x", newMode); switchBank(modeToBank[newMode & 0xF]); CPSR &= ~CPSR_ModeMask; @@ -47,7 +47,7 @@ void ARM710::switchMode(Mode newMode) { void ARM710::raiseException(Mode mode, uint32_t savedPC, uint32_t newPC) { auto bankIndex = modeToBank[mode & 0xF]; -// log("Raising exception mode %x, saving PC %08x, CPSR %08x", mode, savedPC, CPSR); + log("Raising exception mode %x, saving PC %08x, CPSR %08x", mode, savedPC, CPSR); SPSRs[bankIndex] = CPSR; switchMode(mode); @@ -140,7 +140,7 @@ static inline bool extract1(uint32_t value, uint32_t bit) { uint32_t ARM710::executeInstruction(uint32_t i) { uint32_t cycles = 1; -// log("executing insn %08x @ %08x", i, GPRs[15] - 0xC); + log("executing insn %08x @ %08x", i, GPRs[15] - 0xC); // a big old dispatch thing here // but first, conditions! @@ -317,11 +317,11 @@ uint32_t ARM710::execDataProcessing(bool I, uint32_t Opcode, bool S, uint32_t Rn // Output-less opcodes: special behaviour if (S) { CPSR = (CPSR & ~CPSR_FlagMask) | flags; -// log("CPSR setflags=%08x results in CPSR=%08x", flags, CPSR); + log("CPSR setflags=%08x results in CPSR=%08x", flags, CPSR); } else if (Opcode == 8) { // MRS, CPSR -> Reg GPRs[Rd] = CPSR; -// log("r%d <- CPSR(%08x)", Rd, GPRs[Rd]); + log("r%d <- CPSR(%08x)", Rd, GPRs[Rd]); } else if (Opcode == 9) { // MSR, Reg -> CPSR bool canChangeMode = extract1(Rn, 0); @@ -329,33 +329,33 @@ uint32_t ARM710::execDataProcessing(bool I, uint32_t Opcode, bool S, uint32_t Rn auto newCPSR = GPRs[extract(Operand2, 3, 0)]; switchMode(modeFromCPSR(newCPSR)); CPSR = newCPSR; -// log("CPSR change privileged: %08x", CPSR); + log("CPSR change privileged: %08x", CPSR); } else { // for the flag-only version, immediates are allowed // so we just re-use what was calculated earlier... auto newFlag = I ? op2 : GPRs[extract(Operand2, 3, 0)]; CPSR &= ~CPSR_FlagMask; CPSR |= (newFlag & CPSR_FlagMask); -// log("CPSR change unprivileged: new=%08x result=%08x", newFlag, CPSR); + log("CPSR change unprivileged: new=%08x result=%08x", newFlag, CPSR); } } else if (Opcode == 0xA) { // MRS, SPSR -> Reg if (isPrivileged()) { GPRs[Rd] = SPSRs[currentBank()]; -// log("r%d <- SPSR(%08x)", Rd, GPRs[Rd]); + log("r%d <- SPSR(%08x)", Rd, GPRs[Rd]); } } else /*if (Opcode == 0xB)*/ { bool canChangeMode = extract1(Rn, 0); if (isPrivileged()) { if (canChangeMode) { SPSRs[currentBank()] = GPRs[extract(Operand2, 3, 0)]; -// log("SPSR change privileged: %08x", SPSRs[currentBank()]); + log("SPSR change privileged: %08x", SPSRs[currentBank()]); } else { // same hat auto newFlag = I ? op2 : GPRs[extract(Operand2, 3, 0)]; SPSRs[currentBank()] &= ~CPSR_FlagMask; SPSRs[currentBank()] |= (newFlag & CPSR_FlagMask); -// log("SPSR change unprivileged: new=%08x result=%08x", newFlag, SPSRs[currentBank()]); + log("SPSR change unprivileged: new=%08x result=%08x", newFlag, SPSRs[currentBank()]); } } } @@ -373,11 +373,11 @@ uint32_t ARM710::execDataProcessing(bool I, uint32_t Opcode, bool S, uint32_t Rn auto saved = SPSRs[currentBank()]; switchMode(modeFromCPSR(saved)); CPSR = saved; -// log("dataproc restore CPSR: %08x", saved); + log("dataproc restore CPSR: %08x", saved); } } else if (S) { CPSR = (CPSR & ~CPSR_FlagMask) | flags; -// log("dataproc flag change: flags=%08x CPSR=%08x", flags, CPSR); + log("dataproc flag change: flags=%08x CPSR=%08x", flags, CPSR); } } @@ -608,7 +608,7 @@ uint32_t ARM710::execBlockDataTransfer(uint32_t PUSWL, uint32_t Rn, uint32_t reg auto saved = SPSRs[currentBank()]; switchMode(modeFromCPSR(saved)); CPSR = saved; -// log("reloading saved SPSR: %08x", saved); + log("reloading saved SPSR: %08x", saved); } } @@ -1113,16 +1113,11 @@ void ARM710::reportFault(MMUFault fault) { void ARM710::log(const char *format, ...) { - if (logger) { - char buffer[1024]; - va_list vaList; va_start(vaList, format); - vsnprintf(buffer, sizeof(buffer), format, vaList); + printf(format, vaList); va_end(vaList); - - logger(buffer); - } + printf("\n"); } void ARM710::logPcHistory() { diff --git a/WindCore/arm710.h b/WindCore/arm710.h index cb85566..76be1dd 100644 --- a/WindCore/arm710.h +++ b/WindCore/arm710.h @@ -60,7 +60,7 @@ public: ARM710(bool _isTVersion) { isTVersion = _isTVersion; - cp15_id = _isTVersion ? 0x41807100 : 0x41047100; + cp15_id = 0x4401A111;// _isTVersion ? 0x41807100 : 0x41047100; clearAllValues(); } virtual ~ARM710() { } diff --git a/WindCore/clps7111.cpp b/WindCore/clps7111.cpp index 618e546..bfc1922 100644 --- a/WindCore/clps7111.cpp +++ b/WindCore/clps7111.cpp @@ -292,7 +292,7 @@ uint8_t *Emulator::getROMBuffer() { size_t Emulator::getROMSize() { return sizeof(ROM); } -void Emulator::loadROM(uint8_t *buffer, size_t size) { +void Emulator::loadROM(uint8_t *buffer, size_t size, uint8_t*, size_t) { memcpy(ROM, buffer, min(size, sizeof(ROM))); } diff --git a/WindCore/clps7111.h b/WindCore/clps7111.h index 47dae14..fda94dc 100644 --- a/WindCore/clps7111.h +++ b/WindCore/clps7111.h @@ -63,7 +63,7 @@ public: Emulator(); uint8_t *getROMBuffer() override; size_t getROMSize() override; - void loadROM(uint8_t *buffer, size_t size) override; + void loadROM(uint8_t *buffer, size_t size, uint8_t *bootloader, size_t bootloader_size) override; void executeUntil(int64_t cycles) override; int32_t getClockSpeed() const override { return CLOCK_SPEED; } const char *getDeviceName() const override; diff --git a/WindCore/emubase.h b/WindCore/emubase.h index ae35d9d..58469b9 100644 --- a/WindCore/emubase.h +++ b/WindCore/emubase.h @@ -115,7 +115,7 @@ public: virtual uint8_t *getROMBuffer() = 0; virtual size_t getROMSize() = 0; - virtual void loadROM(uint8_t *buffer, size_t size) = 0; + virtual void loadROM(uint8_t *buffer, size_t size, uint8_t *bootloader, size_t bootloader_size) = 0; virtual void executeUntil(int64_t cycles) = 0; virtual int32_t getClockSpeed() const = 0; virtual const char *getDeviceName() const = 0; diff --git a/WindCore/sa1100.cpp b/WindCore/sa1100.cpp new file mode 100644 index 0000000..81def25 --- /dev/null +++ b/WindCore/sa1100.cpp @@ -0,0 +1,1073 @@ +#include "sa1100.h" +#include "hardware.h" +#include +#include "common.h" + +namespace SA1100 { + +Emulator::Emulator() : EmuBase(true) { +} + +uint32_t Emulator::getRTC() { + return time(nullptr) - 946684800; +} + +MaybeU32 Emulator::readPhysical(uint32_t physAddr, ValueSize valueSize) { + //printf("readPhysical:: pc=%08x addr=%03x\n", getGPR(15)-4, physAddr); + if (valueSize == V8) { + return readPhysical8(physAddr); + } else { + return readPhysical32(physAddr); + } +} + +uint8_t Emulator::readPCM8(uint32_t physAddr) { + // Peripheral Control Modules + return 0x0; +} + +uint8_t Emulator::readSCM8(uint32_t physAddr) { + // System Control Modules + return 0x0; +} + +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 + } +} + +uint32_t Emulator::readPCM32(uint32_t physAddr) { + // Peripheral Control Modules + return 0x0; +} + +uint32_t Emulator::readSCM32(uint32_t physAddr) { + // System Control Modules + return 0x0; +} + +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 = memoryConfig.get_data(physAddr); + 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::writePhysical(uint32_t value, uint32_t physAddr, ValueSize valueSize) { + printf("writePhysical:: pc=%08x addr=%03x value=%08x\n", getGPR(15)-4, physAddr, value); + uint8_t region = (physAddr >> 24) & 0xFF; + if (valueSize == V8) { + return writePhysical8((uint8_t)value, physAddr); + } else { + return writePhysical32(value, physAddr); + } +} + +bool Emulator::writePCM8(uint8_t value, uint32_t physAddr) { + return true; +} + +bool Emulator::writeSCM8(uint8_t value, uint32_t physAddr) { + return true; +} + +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; + } +} + +bool Emulator::writePCM32(uint32_t value, uint32_t physAddr) { + return true; +} + +bool Emulator::writeSCM32(uint32_t value, uint32_t physAddr) { + return true; +} + +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 + memoryConfig.put_data(physAddr, value); + 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; + } +} + +void Emulator::configure() { + if (configured) return; + configured = true; + + srand(1000); + + uart1.cpu = this; + uart2.cpu = this; + memset(&tc1, 0, sizeof(tc1)); + memset(&tc2, 0, sizeof(tc1)); + tc1.clockSpeed = CLOCK_SPEED; + tc2.clockSpeed = CLOCK_SPEED; + + nextTickAt = TICK_INTERVAL; + tc1.nextTickAt = tc1.tickInterval(); + tc2.nextTickAt = tc2.tickInterval(); + rtc = getRTC(); + memoryConfig.reset(); + + reset(); +} + +uint8_t *Emulator::getROMBuffer() { + return ROM; +} +size_t Emulator::getROMSize() { + return sizeof(ROM); +} +void Emulator::loadROM(uint8_t *osimg, size_t osimgSize, uint8_t *bootloader, size_t bootloaderSize) { + memcpy(ROM, bootloader, min(bootloaderSize, sizeof(ROM))); + memcpy(MemoryBlockC8, osimg, min(osimgSize, sizeof(MemoryBlockC8))); +} + +void Emulator::executeUntil(int64_t cycles) { + if (!configured) + configure(); + + while (!asleep && passedCycles < cycles) { + if (passedCycles >= nextTickAt) { + // increment RTCDIV + if ((pwrsr & 0x3F) == 0x3F) { + rtc++; + pwrsr &= ~0x3F; + } else { + pwrsr++; + } + + nextTickAt += TICK_INTERVAL; + pendingInterrupts |= (1<"); + return; + } + int size = readVirtualDebug(str, V32).value(); + for (int i = 0; i < size; i++) { + buf[i] = readVirtualDebug(str + 4 + i, V8).value(); + } + buf[size] = 0; +} + +void Emulator::fetchName(uint32_t obj, char *buf) { + fetchStr(readVirtualDebug(obj + 0x10, V32).value(), buf); +} + +void Emulator::fetchProcessFilename(uint32_t obj, char *buf) { + fetchStr(readVirtualDebug(obj + 0x3C, V32).value(), buf); +} + +void Emulator::debugPC(uint32_t pc) { + char objName[1000]; + if (pc == 0x2CBC4) { + // CObjectCon::AddL() + uint32_t container = getGPR(0); + uint32_t obj = getGPR(1); + const char *wut = identifyObjectCon(container); + if (wut) { + fetchName(obj, objName); + if (strcmp(wut, "process") == 0) { + char procName[1000]; + fetchProcessFilename(obj, procName); + log("OBJS: added %s at %08x <%s> <%s>", wut, obj, objName, procName); + } else { + log("OBJS: added %s at %08x <%s>", wut, obj, objName); + } + } + } + + if (pc == 0x6D8) { + uint32_t virtAddr = getGPR(0); + uint32_t physAddr = getGPR(1); + uint32_t btIndex = getGPR(2); + uint32_t regionSize = getGPR(3); + log("KERNEL MMU SECTION: v:%08x p:%08x size:%08x idx:%02x", + virtAddr, physAddr, regionSize, btIndex); + } + if (pc == 0x710) { + uint32_t virtAddr = getGPR(0); + uint32_t physAddr = getGPR(1); + uint32_t btIndex = getGPR(2); + uint32_t regionSize = getGPR(3); + uint32_t pageTableA = getGPR(4); + uint32_t pageTableB = getGPR(5); + log("KERNEL MMU PAGES: v:%08x p:%08x size:%08x idx:%02x tableA:%08x tableB:%08x", + virtAddr, physAddr, regionSize, btIndex, pageTableA, pageTableB); + } + + if (pc == 0x1576C) { + uint32_t rawEvent = getGPR(0); + uint32_t evtType = readVirtualDebug(rawEvent, V32).value_or(0); + uint32_t evtTick = readVirtualDebug(rawEvent + 4, V32).value_or(0); + uint32_t evtParamA = readVirtualDebug(rawEvent + 8, V32).value_or(0); + uint32_t evtParamB = readVirtualDebug(rawEvent + 0xC, V32).value_or(0); + const char *n = "???"; + switch (evtType) { + case 0: n = "ENone"; break; + case 1: n = "EPointerMove"; break; + case 2: n = "EPointerSwitchOn"; break; + case 3: n = "EKeyDown"; break; + case 4: n = "EKeyUp"; break; + case 5: n = "ERedraw"; break; + case 6: n = "ESwitchOn"; break; + case 7: n = "EActive"; break; + case 8: n = "EInactive"; break; + case 9: n = "EUpdateModifiers"; break; + case 10: n = "EButton1Down"; break; + case 11: n = "EButton1Up"; break; + case 12: n = "EButton2Down"; break; + case 13: n = "EButton2Up"; break; + case 14: n = "EButton3Down"; break; + case 15: n = "EButton3Up"; break; + case 16: n = "ESwitchOff"; break; + } + log("EVENT %s: tick=%d params=%d,%d", n, evtTick, evtParamA, evtParamB); + } +} + + +const char *Emulator::getDeviceName() const { return "Series 5mx"; } +int Emulator::getDigitiserWidth() const { return 695; } +int Emulator::getDigitiserHeight() const { return 520; } +int Emulator::getLCDOffsetX() const { return 45; } +int Emulator::getLCDOffsetY() const { return 5; } +int Emulator::getLCDWidth() const { return 640; } +int Emulator::getLCDHeight() const { return 480; } + +// TODO move this elsewhere +static bool initRgbValues = false; +static uint32_t rgbValues[16]; + +void Emulator::readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) const { + if (!initRgbValues) { + initRgbValues = true; + for (int i = 0; i < 16; i++) { + int r = (0x99 * i) / 15; + int g = (0xAA * i) / 15; + int b = (0x88 * i) / 15; + rgbValues[15 - i] = r | (g << 8) | (b << 16) | 0xFF000000; + } + } + + if ((lcdAddress >> 24) == 0xC0) { + const uint8_t *lcdBuf = &MemoryBlockC0[lcdAddress & MemoryBlockMask]; + int width = 640, height = 480; + + // fetch palette + int bpp = 1 << (lcdBuf[1] >> 4); + int ppb = 8 / bpp; + uint16_t palette[16]; + for (int i = 0; i < 16; i++) + palette[i] = lcdBuf[i*2] | ((lcdBuf[i*2+1] << 8) & 0xF00); + + // build our image out + int lineWidth = (width * bpp) / 8; + for (int y = 0; y < height; y++) { + int lineOffs = 0x20 + (lineWidth * y); + for (int x = 0; x < width; x++) { + uint8_t byte = lcdBuf[lineOffs + (x / ppb)]; + int shift = (x & (ppb - 1)) * bpp; + int mask = (1 << bpp) - 1; + int palIdx = (byte >> shift) & mask; + int palValue = palette[palIdx]; + + if (is32BitOutput) { + auto line = (uint32_t *)lines[y]; + line[x] = rgbValues[palValue]; + } else { + palValue |= (palValue << 4); + lines[y][x] = palValue ^ 0xFF; + } + } + } + } +} + + +void Emulator::diffPorts(uint32_t oldval, uint32_t newval) { + uint32_t changes = oldval ^ newval; + if (changes & 1) log("PRT codec enable: %d", newval&1); + if (changes & 2) log("PRT audio amp enable: %d", newval&2); + if (changes & 4) log("PRT lcd power: %d", newval&4); + if (changes & 8) log("PRT etna door: %d", newval&8); + if (changes & 0x10) log("PRT sled: %d", newval&0x10); + if (changes & 0x20) log("PRT pump pwr2: %d", newval&0x20); + if (changes & 0x40) log("PRT pump pwr1: %d", newval&0x40); + if (changes & 0x80) log("PRT etna err: %d", newval&0x80); + if (changes & 0x100) log("PRT rs-232 rts: %d", newval&0x100); + if (changes & 0x200) log("PRT rs-232 dtr toggle: %d", newval&0x200); + if (changes & 0x400) log("PRT disable power led: %d", newval&0x400); + if (changes & 0x800) log("PRT enable uart1: %d", newval&0x800); + if (changes & 0x1000) log("PRT lcd backlight: %d", newval&0x1000); + if (changes & 0x2000) log("PRT enable uart0: %d", newval&0x2000); + if (changes & 0x4000) log("PRT dictaphone: %d", newval&0x4000); +// PROM read process makes this super spammy in stdout +// if (changes & 0x10000) log("PRT EECS: %d", newval&0x10000); +// if (changes & 0x20000) log("PRT EECLK: %d", newval&0x20000); + if (changes & 0x40000) log("PRT contrast0: %d", newval&0x40000); + if (changes & 0x80000) log("PRT contrast1: %d", newval&0x80000); + if (changes & 0x100000) log("PRT contrast2: %d", newval&0x100000); + if (changes & 0x200000) log("PRT contrast3: %d", newval&0x200000); + if (changes & 0x400000) log("PRT case open: %d", newval&0x400000); + if (changes & 0x800000) log("PRT etna cf power: %d", newval&0x800000); +} + +void Emulator::diffInterrupts(uint16_t oldval, uint16_t newval) { + uint16_t changes = oldval ^ newval; + if (changes & 1) log("INTCHG external=%d", newval & 1); + if (changes & 2) log("INTCHG lowbat=%d", newval & 2); + if (changes & 4) log("INTCHG watchdog=%d", newval & 4); + if (changes & 8) log("INTCHG mediachg=%d", newval & 8); + if (changes & 0x10) log("INTCHG codec=%d", newval & 0x10); + if (changes & 0x20) log("INTCHG ext1=%d", newval & 0x20); + if (changes & 0x40) log("INTCHG ext2=%d", newval & 0x40); + if (changes & 0x80) log("INTCHG ext3=%d", newval & 0x80); + if (changes & 0x100) log("INTCHG timer1=%d", newval & 0x100); + if (changes & 0x200) log("INTCHG timer2=%d", newval & 0x200); + if (changes & 0x400) log("INTCHG rtcmatch=%d", newval & 0x400); + if (changes & 0x800) log("INTCHG tick=%d", newval & 0x800); + if (changes & 0x1000) log("INTCHG uart1=%d", newval & 0x1000); + if (changes & 0x2000) log("INTCHG uart2=%d", newval & 0x2000); + if (changes & 0x4000) log("INTCHG lcd=%d", newval & 0x4000); + if (changes & 0x8000) log("INTCHG spi=%d", newval & 0x8000); +} + + +uint32_t Emulator::readKeyboard() { + if (kScan & 8) { + // Select one keyboard + return keyboardColumns[kScan & 7]; + } else if (kScan == 0) { + // Report all columns combined + uint8_t val = 0; + for (int i = 0; i < 8; i++) + val |= keyboardColumns[i]; + return val; + } else { + return 0; + } +} + +void Emulator::setKeyboardKey(EpocKey key, bool value) { + int idx = -1; +#define KEY(column, bit) idx = (column << 8) | (1 << bit); break + + switch ((int)key) { + case EStdKeyDictaphoneRecord: KEY(0, 6); + case '1': KEY(0, 5); + case '2': KEY(0, 4); + case '3': KEY(0, 3); + case '4': KEY(0, 2); + case '5': KEY(0, 1); + case '6': KEY(0, 0); + + case EStdKeyDictaphonePlay: KEY(1, 6); + case '7': KEY(1, 5); + case '8': KEY(1, 4); + case '9': KEY(1, 3); + case '0': KEY(1, 2); + case EStdKeyBackspace: KEY(1, 1); + case EStdKeySingleQuote: KEY(1, 0); + + case EStdKeyEscape: KEY(2, 6); + case 'Q': KEY(2, 5); + case 'W': KEY(2, 4); + case 'E': KEY(2, 3); + case 'R': KEY(2, 2); + case 'T': KEY(2, 1); + case 'Y': KEY(2, 0); + + case EStdKeyMenu: KEY(3, 6); + case 'U': KEY(3, 5); + case 'I': KEY(3, 4); + case 'O': KEY(3, 3); + case 'P': KEY(3, 2); + case 'L': KEY(3, 1); + case EStdKeyEnter: KEY(3, 0); + + case EStdKeyLeftCtrl: KEY(4, 6); + case EStdKeyTab: KEY(4, 5); + case 'A': KEY(4, 4); + case 'S': KEY(4, 3); + case 'D': KEY(4, 2); + case 'F': KEY(4, 1); + case 'G': KEY(4, 0); + + case EStdKeyLeftFunc: KEY(5, 6); + case 'H': KEY(5, 5); + case 'J': KEY(5, 4); + case 'K': KEY(5, 3); + case 'M': KEY(5, 2); + case EStdKeyFullStop: KEY(5, 1); + case EStdKeyDownArrow: KEY(5, 0); + + case EStdKeyRightShift: KEY(6, 6); + case 'Z': KEY(6, 5); + case 'X': KEY(6, 4); + case 'C': KEY(6, 3); + case 'V': KEY(6, 2); + case 'B': KEY(6, 1); + case 'N': KEY(6, 0); + + case EStdKeyLeftShift: KEY(7, 6); + case EStdKeyDictaphoneStop: KEY(7, 5); + case EStdKeySpace: KEY(7, 4); + case EStdKeyUpArrow: KEY(7, 3); + case EStdKeyComma: KEY(7, 2); + case EStdKeyLeftArrow: KEY(7, 1); + case EStdKeyRightArrow: KEY(7, 0); + } + + if (idx >= 0) { + if (value) + keyboardColumns[idx >> 8] |= (idx & 0xFF); + else + keyboardColumns[idx >> 8] &= ~(idx & 0xFF); + } +} + +void Emulator::updateTouchInput(int32_t x, int32_t y, bool down) { + pendingInterrupts &= ~(1 << EINT3); + if (down) + pendingInterrupts |= (1 << EINT3); + touchX = x; + touchY = y; +} + +} diff --git a/WindCore/sa1100.h b/WindCore/sa1100.h new file mode 100644 index 0000000..d101985 --- /dev/null +++ b/WindCore/sa1100.h @@ -0,0 +1,112 @@ +#ifndef SA1100_H +#define SA1100_H + +#include "emubase.h" +#include "sa1100_defs.h" +#include "hardware.h" +#include "sa1100/memory_conf.h" + +namespace SA1100 { + +// Relatively simple implementation of a StrongARM SA-1100 CPU +// +// The following resources are invaluable to determining how the SA-1100 operates: +// +// 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 file + 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: + uint16_t pendingInterrupts = 0; + uint16_t interruptMask = 0; + uint32_t portValues = 0; + uint32_t portDirections = 0; + uint32_t pwrsr = 0x00002000; // cold start flag + uint32_t lcdControl = 0; + uint32_t lcdAddress = 0; + uint32_t rtc = 0; + uint16_t lastSSIRequest = 0; + int ssiReadCounter = 0; + + uint32_t kScan = 0; + uint8_t keyboardColumns[8] = {0,0,0,0,0,0,0}; + int32_t touchX = 0, touchY = 0; + + Timer tc1, tc2; + UART uart1, uart2; + MemoryConf memoryConfig; + + 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 *osimg, size_t osimgSize, uint8_t *bootloader, size_t bootloaderSize) override; + void executeUntil(int64_t cycles) override; + int32_t getClockSpeed() const override { return 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 diff --git a/WindCore/sa1100/memory_conf.cpp b/WindCore/sa1100/memory_conf.cpp new file mode 100644 index 0000000..5d6af7a --- /dev/null +++ b/WindCore/sa1100/memory_conf.cpp @@ -0,0 +1,99 @@ +// ARMware - an ARM emulator +// Copyright (C) <2007> Wei Hu +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "memory_conf.h" + +namespace SA1100 { + +void MemoryConf::reset() { + // :NOTE: Wei 2004-Jan-18: + // + // Bits 0, 1, 16, 17 will reset to 0 when reset. + mMDCNFG &= ~((1 << 0) | (1 << 1) | (1 << 16) | (1 << 17)); + + // :NOTE: Wei 2003-Dec-11: + // + // I assume all of the bits which have unknown values when reset have value 0. + mMDREFR = static_cast((1 << 31) | (1 << 26) | (1 << 22) | (1 << 18)); + + // :NOTE: Wei 2003-Dec-11: + // + // I assume all of the bits which have unknown values when reset have value 0. + mMDCAS00 = (1 << 10) | (1 << 8) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | 1; + mMDCAS01 = mMDCAS00; + mMDCAS02 = mMDCAS00; + mMDCAS20 = mMDCAS00; + mMDCAS21 = mMDCAS00; + mMDCAS22 = mMDCAS00; + + // :NOTE: Wei 2003-Dec-11: + // + // I assume all of the bits which have unknown values when reset have value 0. + // + // :SA-1110 Developer's Manual: p.141: Wei 2004-Jun-09: + // + // On iPaq H3600, RBW0 have to be 0 to indicate 32-bit 'ROM bus width'. + mMSC0 = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 12) | (1 << 11) | (1 << 10) + | (1 << 9) | (1 << 8) | (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3); + + // :NOTE: Wei 2003-Dec-11: + // + // I assume all of the bits which have unknown values when reset have value 0. + mSMCNFG = (1 << 15) | (1 << 14) | (1 << 6); +} + +uint32_t MemoryConf::get_data(uint32_t const address) const { + switch (address) { + case MDCNFG: return mMDCNFG; + case MDCAS00: return mMDCAS00; + case MDCAS01: return mMDCAS01; + case MDCAS02: return mMDCAS02; + case MSC0: return mMSC0; + case MSC1: return mMSC1; + case MECR: return mMECR; + case MDREFR: return mMDREFR; + case MDCAS20: return mMDCAS20; + case MDCAS21: return mMDCAS21; + case MDCAS22: return mMDCAS22; + case MSC2: return mMSC2; + case SMCNFG: return mSMCNFG; + + default: + return 0; + } +} + +void MemoryConf::put_data(uint32_t const address, uint32_t const value) { + switch (address) { + case MDCNFG: mMDCNFG = value; break; + case MDCAS00: mMDCAS00 = value; break; + case MDCAS01: mMDCAS01 = value; break; + case MDCAS02: mMDCAS02 = value; break; + case MSC0: mMSC0 = value; break; + case MSC1: mMSC1 = value; break; + case MECR: mMECR = value; break; + case MDREFR: mMDREFR = value; break; + case MDCAS20: mMDCAS20 = value; break; + case MDCAS21: mMDCAS21 = value; break; + case MDCAS22: mMDCAS22 = value; break; + case MSC2: mMSC2 = value; break; + case SMCNFG: mSMCNFG = value; break; + default: break; + } +} + +} // namespace SA1100 \ No newline at end of file diff --git a/WindCore/sa1100/memory_conf.h b/WindCore/sa1100/memory_conf.h new file mode 100644 index 0000000..5aa6a07 --- /dev/null +++ b/WindCore/sa1100/memory_conf.h @@ -0,0 +1,93 @@ +// ARMware - an ARM emulator +// Copyright (C) <2007> Wei Hu +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#ifndef MEMORY_CONF_H +#define MEMORY_CONF_H + +#include + +namespace SA1100 { + +class MemoryConf { +public: + MemoryConf() { + init_register(); + } + + void reset(); + + // :SA-1110 Developer's Manual: Wei 2003-Dec-11: + // + // These registers are readable and writable only as full words. + uint32_t get_data(uint32_t const address) const; + + void put_data(uint32_t const address, uint32_t const value); +private: + enum { + MDCNFG = 0xA0000000, + MDCAS00 = 0xA0000004, + MDCAS01 = 0xA0000008, + MDCAS02 = 0xA000000C, + MSC0 = 0xA0000010, + MSC1 = 0xA0000014, + MECR = 0xA0000018, + MDREFR = 0xA000001C, + MDCAS20 = 0xA0000020, + MDCAS21 = 0xA0000024, + MDCAS22 = 0xA0000028, + MSC2 = 0xA000002C, + SMCNFG = 0xA0000030 + }; + + // Attribute + + uint32_t mMDCNFG; // DRAM Configuration register + uint32_t mMDCAS00; // CAS waveform rotate register 0 for DRAM bank pair 0/1 + uint32_t mMDCAS01; // CAS waveform rotate register 1 for DRAM bank pair 0/1 + uint32_t mMDCAS02; // CAS waveform rotate register 2 for DRAM bank pair 0/1 + uint32_t mMSC0; // Static memory control register 0 + uint32_t mMSC1; // Static memory control register 1 + uint32_t mMECR; // Expansion memory (PC-Card) bus configuration register + uint32_t mMDREFR; // DRAM refresh control register + uint32_t mMDCAS20; // CAS waveform rotate register 0 for DRAM bank pair 2/3 + uint32_t mMDCAS21; // CAS waveform rotate register 1 for DRAM bank pair 2/3 + uint32_t mMDCAS22; // CAS waveform rotate register 2 for DRAM bank pair 2/3 + uint32_t mMSC2; // Static memory control register 2 + uint32_t mSMCNFG; // SMROM configuration register + + // Operation + + void init_register() { + mMDCNFG = 0; + mMDCAS00 = 0; + mMDCAS01 = 0; + mMDCAS02 = 0; + mMSC0 = 0; + mMSC1 = 0; + mMECR = 0; + mMDREFR = 0; + mMDCAS20 = 0; + mMDCAS21 = 0; + mMDCAS22 = 0; + mMSC2 = 0; + mSMCNFG = 0; + } +}; + +} // namespace SA1100 + +#endif // MEMORY_CONF_H diff --git a/WindCore/sa1100_defs.h b/WindCore/sa1100_defs.h new file mode 100644 index 0000000..52533f9 --- /dev/null +++ b/WindCore/sa1100_defs.h @@ -0,0 +1,97 @@ +#ifndef SA1100_DEFS_H +#define SA1100_DEFS_H + +#include + +namespace SA1100 { +enum { + CLOCK_SPEED = 0x9000*1000, + TICK_INTERVAL = CLOCK_SPEED / 64 +}; + +enum Interrupt { + EXTFIQ = 0, // FiqExternal + BLINT = 1, // FiqBatLow + WEINT = 2, // FiqWatchDog + MCINT = 3, // FiqMediaChg + CSINT = 4, // IrqCodec + EINT1 = 5, // IrqExt1 + EINT2 = 6, // IrqExt2 + EINT3 = 7, // IrqExt3 + TC1OI = 8, // IrqTimer1 + TC2OI = 9, // IrqTimer2 + RTCMI = 10, // IrqRtcMatch + TINT = 11, // IrqTick + UART1 = 12, // IrqUart1 + UART2 = 13, // IrqUart1 + LCDINT = 14, // IrqLcd + SSEOTI = 15, // IrqSpi + FIQ_INTERRUPTS = 0x000F, + IRQ_INTERRUPTS = 0xFFF0 +}; + +enum Register { + MEMCFG1 = 0, + MEMCFG2 = 4, + DRAM_CFG = 0x100, + LCDCTL = 0x200, + LCDST = 0x204, + LCD_DBAR1 = 0x210, + LCDT0 = 0x220, + LCDT1 = 0x224, + LCDT2 = 0x228, + PWRSR = 0x400, + PWRCNT = 0x404, + HALT = 0x408, + STBY = 0x40C, + BLEOI = 0x410, + MCEOI = 0x414, + TEOI = 0x418, + STFCLR = 0x41C, + E2EOI = 0x420, + INTSR = 0x500, + INTRSR = 0x504, + INTENS = 0x508, + INTENC = 0x50C, + INTTEST1 = 0x514, + INTTEST2 = 0x518, + PUMPCON = 0x900, + CODR = 0xA00, + CONFG = 0xA04, + COLFG = 0xA08, + COEOI = 0xA0C, + COTEST = 0xA10, + SSCR0 = 0xB00, + SSCR1 = 0xB04, + SSDR = 0xB0C, + SSSR = 0xB14, + TC1LOAD = 0xC00, + TC1VAL = 0xC04, + TC1CTRL = 0xC08, + TC1EOI = 0xC0C, + TC2LOAD = 0xC20, + TC2VAL = 0xC24, + TC2CTRL = 0xC28, + TC2EOI = 0xC2C, + BZCONT = 0xC40, + RTCDRL = 0xD00, + RTCDRU = 0xD04, + RTCMRL = 0xD08, + RTCMRU = 0xD0C, + RTCEOI = 0xD10, + PADR = 0xE00, + PBDR = 0xE04, + PCDR = 0xE08, + PDDR = 0xE0C, + PADDR = 0xE10, + PBDDR = 0xE14, + PCDDR = 0xE18, + PDDDR = 0xE1C, + PEDR = 0xE20, + PEDDR = 0xE24, + KSCAN = 0xE28, + LCDMUX = 0xE2C +}; +} + +#endif // SA1100_DEFS_H diff --git a/WindCore/windermere.cpp b/WindCore/windermere.cpp index 41bbe70..adf5342 100644 --- a/WindCore/windermere.cpp +++ b/WindCore/windermere.cpp @@ -377,7 +377,7 @@ uint8_t *Emulator::getROMBuffer() { size_t Emulator::getROMSize() { return sizeof(ROM); } -void Emulator::loadROM(uint8_t *buffer, size_t size) { +void Emulator::loadROM(uint8_t *buffer, size_t size, uint8_t*, size_t) { memcpy(ROM, buffer, min(size, sizeof(ROM))); } diff --git a/WindCore/windermere.h b/WindCore/windermere.h index defe545..10cf24d 100644 --- a/WindCore/windermere.h +++ b/WindCore/windermere.h @@ -64,7 +64,7 @@ public: Emulator(); uint8_t *getROMBuffer() override; size_t getROMSize() override; - void loadROM(uint8_t *buffer, size_t size) override; + void loadROM(uint8_t *buffer, size_t size, uint8_t*, size_t) override; void executeUntil(int64_t cycles) override; int32_t getClockSpeed() const override { return CLOCK_SPEED; } const char *getDeviceName() const override; diff --git a/WindEmu.pro b/WindEmu.pro index 7cc6ae7..06d7ce5 100644 --- a/WindEmu.pro +++ b/WindEmu.pro @@ -1,5 +1,7 @@ TEMPLATE = subdirs +CONFIG += console + SUBDIRS += \ WindQt \ WindCore diff --git a/WindQt/main.cpp b/WindQt/main.cpp index 3d9b87d..97f4d85 100644 --- a/WindQt/main.cpp +++ b/WindQt/main.cpp @@ -4,6 +4,7 @@ #include #include "../WindCore/clps7111.h" #include "../WindCore/windermere.h" +#include "../WindCore/sa1100.h" int main(int argc, char *argv[]) { @@ -17,6 +18,8 @@ int main(int argc, char *argv[]) romFile = QFileDialog::getOpenFileName(nullptr, "Select a ROM"); if (romFile.isNull()) return 0; + QString bootloader = "/Users/george/BootLoader.bin"; + printf("Hello\n"); // what do we have? QFile f(romFile); f.open(QFile::ReadOnly); @@ -28,8 +31,15 @@ int main(int argc, char *argv[]) return 0; } + // what do we have? + QFile f2(bootloader); + f2.open(QFile::ReadOnly); + auto bootloader_buffer = f2.readAll(); + f2.close(); + EmuBase *emu = nullptr; uint8_t *romData = (uint8_t *)buffer.data(); + uint8_t *bootloader_data = (uint8_t *)bootloader_buffer.data(); // parse this ROM to learn what hardware it's for int variantFile = *((uint32_t *)&romData[0x80 + 0x4C]) & 0xFFFFFFF; @@ -44,14 +54,14 @@ int main(int argc, char *argv[]) } else if (variant == 0x5040001) { // Osaris ROM emu = new CLPS7111::Emulator; - } else { - QMessageBox::critical(nullptr, "WindEmu", "Unrecognised ROM file!"); - return 0; - } + } else { + // Netbook ROM + emu = new SA1100::Emulator; + } } } - emu->loadROM(romData, buffer.size()); + emu->loadROM(romData, buffer.size(), bootloader_data, bootloader_buffer.size()); MainWindow w(emu); w.show(); diff --git a/WindQt/mainwindow.cpp b/WindQt/mainwindow.cpp index deb706c..eeb38e1 100644 --- a/WindQt/mainwindow.cpp +++ b/WindQt/mainwindow.cpp @@ -209,7 +209,7 @@ void MainWindow::updateMemory() if (!ok) outLine.append('?'); else if (byte >= 0x20 && byte <= 0x7E) - outLine.append(byte); + outLine.append((QChar)byte); else outLine.append('.'); } -- 2.45.2