From 25c715688ff546e78097762684313fa95b79512a Mon Sep 17 00:00:00 2001 From: George Wright Date: Tue, 3 Dec 2024 09:18:37 -0800 Subject: [PATCH] initial impl --- WindCore/WindCore.pro | 21 +- WindCore/arm710.cpp | 156 +++++++--- WindCore/arm710.h | 7 +- WindCore/clps7111.cpp | 9 +- WindCore/clps7111.h | 4 +- WindCore/emubase.h | 5 +- WindCore/sa1100.cpp | 589 +++++++++++++++++++++++++++++++------ WindCore/sa1100.h | 35 ++- WindCore/sa1100_defs.h | 3 +- WindCore/windermere.cpp | 7 +- WindCore/windermere.h | 4 +- WindQt/main.cpp | 44 +-- WindQt/mainwindow.cpp | 15 +- WindQt/pdascreenwindow.cpp | 1 + 14 files changed, 718 insertions(+), 182 deletions(-) diff --git a/WindCore/WindCore.pro b/WindCore/WindCore.pro index b0b2353..6c67c42 100644 --- a/WindCore/WindCore.pro +++ b/WindCore/WindCore.pro @@ -33,7 +33,15 @@ SOURCES += \ decoder-arm.c \ windermere.cpp \ sa1100.cpp \ - sa1100/memory_conf.cpp + sa1100/asic14.cpp \ + sa1100/gpio_controller.cpp \ + sa1100/interrupt_controller.cpp \ + sa1100/lcd_controller.cpp \ + sa1100/memory_conf.cpp \ + sa1100/power_manager.cpp \ + sa1100/os_timer.cpp \ + sa1100/reset_controller.cpp \ + sa1100/uart.cpp HEADERS += \ arm710.h \ @@ -54,7 +62,16 @@ HEADERS += \ common.h \ windermere.h \ sa1100.h \ - sa1100/memory_conf.h + sa1100/asic14.h \ + sa1100/gpio_controller.h \ + sa1100/interrupt_controller.h \ + sa1100/lcd_controller.h \ + sa1100/memory_conf.h \ + sa1100/power_manager.h \ + sa1100/os_timer.h \ + sa1100/reset_controller.h \ + sa1100/serial_3.h \ + sa1100/uart.h unix { target.path = /usr/lib INSTALLS += target diff --git a/WindCore/arm710.cpp b/WindCore/arm710.cpp index 807c8cb..dbb4812 100644 --- a/WindCore/arm710.cpp +++ b/WindCore/arm710.cpp @@ -35,9 +35,9 @@ void ARM710::switchBank(BankIndex newBank) { void ARM710::switchMode(Mode newMode) { + //printf("Switching mode\n"); auto oldMode = currentMode(); if (newMode != oldMode) { - 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); + //printf("Raising exception mode %x, saving PC %08x, CPSR %08x\n", mode, savedPC, CPSR); SPSRs[bankIndex] = CPSR; switchMode(mode); @@ -73,6 +73,12 @@ void ARM710::reset() { #ifdef ARM710T_CACHE clearCache(); #endif + cp15_control = 0; + // cp15_translationTableBase = 0; + cp15_domainAccessControl = 0; + cp15_faultStatus = 0; + cp15_faultAddress = 0; + prefetchCount = 0; raiseException(Supervisor32, 0, 0); } @@ -140,7 +146,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! @@ -163,11 +169,15 @@ uint32_t ARM710::executeInstruction(uint32_t i) { cycles += execMultiply(extract(i,21,20), extract(i,19,16), extract(i,15,12), extract(i,11,8), extract(i,3,0)); else if ((i & 0x0F8000F0) == 0x00800090 && isTVersion) cycles += execMultiplyLong(extract(i,22,20), extract(i,19,16), extract(i,15,12), extract(i,11,8), extract(i,3,0)); - else if ((i & 0x0C000000) == 0x00000000) + else if ((i & 0x0E000090) == 0x00000090) { + //printf("Decoding %08x\n", i); + cycles += execSingleHalfWordDataTransfer(extract(i, 24, 20), extract(i, 19, 16), extract(i, 15, 12), extract(i, 11, 8), extract(i, 6, 5), extract(i, 3, 0)); + } else if ((i & 0x0C000000) == 0x00000000) cycles += execDataProcessing(extract1(i,25), extract(i,24,21), extract1(i,20), extract(i,19,16), extract(i,15,12), extract(i,11,0)); - else + else { + printf("Unknown instruction %08x\n", i); raiseException(Undefined32, GPRs[15] - 8, 0x04); - + } return cycles; } @@ -317,11 +327,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 +339,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 +383,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); } } @@ -449,6 +459,89 @@ uint32_t ARM710::execSingleDataSwap(bool B, uint32_t Rn, uint32_t Rd, uint32_t R return 1; } +uint32_t ARM710::execSingleHalfWordDataTransfer(uint32_t PUIWL, uint32_t Rn, uint32_t Rd, uint32_t addrMode1, uint32_t SH, uint32_t addrMode2) +{ + bool load = extract1(PUIWL, 0); + bool writeback = extract1(PUIWL, 1); + bool immediate = extract1(PUIWL, 3); + bool up = extract1(PUIWL, 4); + bool preIndex = extract1(PUIWL, 5); + + uint32_t LSH = ((PUIWL << 2) | SH) & 0x7; + ValueSize valueSize; + bool isSigned; + + switch (LSH) { + case 0x1: + valueSize = V16; + isSigned = false; + break; + case 0x5: + valueSize = V16; + isSigned = false; + break; + case 0x6: + valueSize = V8; + isSigned = true; + break; + case 0x7: + valueSize = V16; + isSigned = true; + break; + default: + // Invalid instruction on ARMv4 as it doesn't support double word ldr/str + return 2; + } + + // calculate the offset + uint32_t calcOffset; + if (!immediate) { + // addrMode1 should be zero (SBZ) + // addrMode2 is Rm + calcOffset = GPRs[addrMode2]; + } else { + // IMMEDIATE + // No rotation or anything here + // addrMode1 is the high 4 bits + // addrMode2 is the low 4 bits + calcOffset = (addrMode1 << 4) & addrMode2; + } + + uint32_t base = GPRs[Rn]; + if (Rn == 15) base -= 4; // prefetch adjustment + uint32_t modifiedBase = up ? (base + calcOffset) : (base - calcOffset); + uint32_t transferAddr = preIndex ? modifiedBase : base; + + bool changeModes = !preIndex && writeback && isPrivileged(); + auto saveMode = currentMode(); + + MMUFault fault; + + if (load) { + if (changeModes) switchMode(User32); + auto readResult = readVirtual(transferAddr, valueSize); + if (changeModes) switchMode(saveMode); + if (readResult.first.has_value()) { + GPRs[Rd] = readResult.first.value(); + if (Rd == 15) prefetchCount = 0; + } + fault = readResult.second; + } else { + uint32_t value = GPRs[Rd]; + if (changeModes) switchMode(User32); + fault = writeVirtual(value, transferAddr, valueSize); + if (changeModes) switchMode(saveMode); + } + + if ((preIndex && writeback) || !preIndex) + GPRs[Rn] = modifiedBase; + + if (fault != NoFault) + reportFault(fault); + + return 2; +} + uint32_t ARM710::execSingleDataTransfer(uint32_t IPUBWL, uint32_t Rn, uint32_t Rd, uint32_t offset) { bool load = extract1(IPUBWL, 0); @@ -641,6 +734,7 @@ uint32_t ARM710::execCP15RegisterTransfer(uint32_t CPOpc, bool L, uint32_t CRn, return 0; if (L) { + printf("Reading coprocessor reg %d\n", CRn); // read a value uint32_t what = 0; @@ -658,32 +752,16 @@ uint32_t ARM710::execCP15RegisterTransfer(uint32_t CPOpc, bool L, uint32_t CRn, // store a value uint32_t what = GPRs[Rd]; + if (CRn == 1 || CRn == 2) + printf("Setting coprocessor reg %d to %08x\n", CRn, what); + switch (CRn) { - case 1: cp15_control = what; log("setting cp15_control to %08x", what); break; - case 2: cp15_translationTableBase = what; break; + case 1: cp15_control = what; break; + case 2: cp15_translationTableBase = what & 0xFFFFC000; break; case 3: cp15_domainAccessControl = what; break; - 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(); - log("cache cleared"); -#endif - break; + case 5: cp15_faultStatus = what; break; + case 6: cp15_faultAddress = what; break; + case 7: break; case 8: { #ifdef ARM710T_TLB if (isTVersion) { diff --git a/WindCore/arm710.h b/WindCore/arm710.h index 76be1dd..21d01ef 100644 --- a/WindCore/arm710.h +++ b/WindCore/arm710.h @@ -18,14 +18,14 @@ using namespace std; // Speedhacks: //#define ARM710T_CACHE -//#define ARM710T_TLB +#define ARM710T_TLB typedef optional MaybeU32; class ARM710 { public: - enum ValueSize { V8 = 0, V32 = 1 }; + enum ValueSize { V8 = 0, V16 = 1, V32 = 2 }; enum MMUFault : uint64_t { // ref: datasheet 9-13 (p111) @@ -60,7 +60,7 @@ public: ARM710(bool _isTVersion) { isTVersion = _isTVersion; - cp15_id = 0x4401A111;// _isTVersion ? 0x41807100 : 0x41047100; + cp15_id = /*0x4401A111;*/ _isTVersion ? 0x41807100 : 0x41047100; clearAllValues(); } virtual ~ARM710() { } @@ -296,6 +296,7 @@ private: uint32_t execMultiply(uint32_t AS, uint32_t Rd, uint32_t Rn, uint32_t Rs, uint32_t Rm); uint32_t execMultiplyLong(uint32_t UAS, uint32_t RdHi, uint32_t RdLo, uint32_t Rs, uint32_t Rm); uint32_t execSingleDataSwap(bool B, uint32_t Rn, uint32_t Rd, uint32_t Rm); + uint32_t execSingleHalfWordDataTransfer(uint32_t PUIWL, uint32_t Rn, uint32_t Rd, uint32_t addrMode1, uint32_t SH, uint32_t addrMode2); uint32_t execSingleDataTransfer(uint32_t IPUBWL, uint32_t Rn, uint32_t Rd, uint32_t offset); uint32_t execBlockDataTransfer(uint32_t PUSWL, uint32_t Rn, uint32_t registerList); uint32_t execBranch(bool L, uint32_t offset); diff --git a/WindCore/clps7111.cpp b/WindCore/clps7111.cpp index bfc1922..57a4ca0 100644 --- a/WindCore/clps7111.cpp +++ b/WindCore/clps7111.cpp @@ -296,7 +296,7 @@ void Emulator::loadROM(uint8_t *buffer, size_t size, uint8_t*, size_t) { memcpy(ROM, buffer, min(size, sizeof(ROM))); } -void Emulator::executeUntil(int64_t cycles) { +bool Emulator::executeUntil(int64_t cycles) { if (!configured) configure(); @@ -339,15 +339,16 @@ void Emulator::executeUntil(int64_t cycles) { uint32_t new_pc = getGPR(15) - 0xC; if (_breakpoints.find(new_pc) != _breakpoints.end()) { log("⚠️ Breakpoint triggered at %08x!", new_pc); - return; + return false; } if (new_pc >= 0x80000000 && new_pc <= 0x90000000) { log("BAD PC %08x!!", new_pc); logPcHistory(); - return; + return false; } } } + return true; } @@ -473,7 +474,7 @@ int Emulator::getLCDOffsetY() const { return 0; } int Emulator::getLCDWidth() const { return 320; } int Emulator::getLCDHeight() const { return 200; } -void Emulator::readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) const { +void Emulator::readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) { if (lcdAddress == 0xC0000000) { int width = 320, height = 200; int bpp = 1; diff --git a/WindCore/clps7111.h b/WindCore/clps7111.h index fda94dc..9e1fc83 100644 --- a/WindCore/clps7111.h +++ b/WindCore/clps7111.h @@ -64,7 +64,7 @@ public: uint8_t *getROMBuffer() override; size_t getROMSize() override; void loadROM(uint8_t *buffer, size_t size, uint8_t *bootloader, size_t bootloader_size) override; - void executeUntil(int64_t cycles) override; + bool executeUntil(int64_t cycles) override; int32_t getClockSpeed() const override { return CLOCK_SPEED; } const char *getDeviceName() const override; int getDigitiserWidth() const override; @@ -73,7 +73,7 @@ public: int getLCDOffsetY() const override; int getLCDWidth() const override; int getLCDHeight() const override; - void readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) const override; + void readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) override; void setKeyboardKey(EpocKey key, bool value) override; void updateTouchInput(int32_t x, int32_t y, bool down) override; }; diff --git a/WindCore/emubase.h b/WindCore/emubase.h index 58469b9..e11ac76 100644 --- a/WindCore/emubase.h +++ b/WindCore/emubase.h @@ -112,11 +112,12 @@ protected: public: EmuBase(bool isTVersion) : ARM710(isTVersion) { } + virtual ~EmuBase() = default; virtual uint8_t *getROMBuffer() = 0; virtual size_t getROMSize() = 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 bool executeUntil(int64_t cycles) = 0; virtual int32_t getClockSpeed() const = 0; virtual const char *getDeviceName() const = 0; virtual int getDigitiserWidth() const = 0; @@ -125,7 +126,7 @@ public: virtual int getLCDOffsetY() const = 0; virtual int getLCDWidth() const = 0; virtual int getLCDHeight() const = 0; - virtual void readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) const = 0; + virtual void readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) = 0; virtual void setKeyboardKey(EpocKey key, bool value) = 0; virtual void updateTouchInput(int32_t x, int32_t y, bool down) = 0; diff --git a/WindCore/sa1100.cpp b/WindCore/sa1100.cpp index 81def25..3e204ac 100644 --- a/WindCore/sa1100.cpp +++ b/WindCore/sa1100.cpp @@ -6,6 +6,34 @@ namespace SA1100 { Emulator::Emulator() : EmuBase(true) { + osTimer = new OsTimer(); + lcdController = new LCDController(); + gpioController = new GPIOController(); + serial3 = new Serial3(); + resetController = new ResetController(); + intController = new IntController(lcdController, osTimer, gpioController, serial3); + powerManager = new PowerManager(); + MemoryBlockC0 = new uint8_t[memoryMask+1]; + MemoryBlockC8 = new uint8_t[memoryMask+1]; + // MemoryBlockD0 = new uint8_t[memoryMask+1]; + // MemoryBlockD8 = new uint8_t[memoryMask+1]; + ROM = new uint8_t[0x1000000]; + asic14 = new ASIC14(); +} + +Emulator::~Emulator() { + delete osTimer; + delete lcdController; + delete gpioController; + delete intController; + delete powerManager; + delete resetController; + delete[] MemoryBlockC0; + delete[] MemoryBlockC8; + // delete[] MemoryBlockD0; + // delete[] MemoryBlockD8; + delete[] ROM; + delete[] asic14; } uint32_t Emulator::getRTC() { @@ -16,27 +44,152 @@ 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 if (valueSize == V16) { + return readPhysical16(physAddr); } else { return readPhysical32(physAddr); } } +// Peripheral Control Modules +// 0x80000000 address space uint8_t Emulator::readPCM8(uint32_t physAddr) { - // Peripheral Control Modules + printf("Read PCM8 at 0x%08x\n", physAddr); return 0x0; } +bool Emulator::writePCM8(uint8_t value, uint32_t physAddr) { + printf("Write PCM8 0x%08x at 0x%08x\n", value, physAddr); + return true; +} + +uint32_t Emulator::readPCM32(uint32_t physAddr) { + uint16_t region = (physAddr >> 16) & 0xFFFF; + + switch (region) { + case 0x8005: + // Serial 3 + printf("Getting serial 3 at 0x%08x\n", physAddr); + return serial3->get_data(physAddr); + default: + printf("Read PCM32 at 0x%08x\n", physAddr); + return 0x0; + } +} + +bool Emulator::writePCM32(uint32_t value, uint32_t physAddr) { + uint16_t region = (physAddr >> 16) & 0xFFFF; + + switch (region) { + case 0x8005: + // Serial 3 + printf("Serial 3 write 0x%08x at 0x%08x\n", value, physAddr); + serial3->put_data(physAddr, value); + return true; + default: + printf("Write PCM32 0x%08x at 0x%08x\n", value, physAddr); + return true; + } +} + +// System Control Modules +// 0x90000000 address space uint8_t Emulator::readSCM8(uint32_t physAddr) { - // System Control Modules + printf("Read SCM8 at 0x%08x\n", physAddr); return 0x0; } +bool Emulator::writeSCM8(uint8_t value, uint32_t physAddr) { + printf("Write SCM8 0x%08x at 0x%08x\n", value, physAddr); + return true; +} + +uint32_t Emulator::readSCM32(uint32_t physAddr) { + uint16_t region = (physAddr >> 16) & 0xFFFF; + + switch (region) { + case 0x9000: + // OS Timer + //printf("Getting timer at 0x%08x\n", physAddr); + return osTimer->get_data(physAddr); + case 0x9001: + // RTC + printf("Getting RTC at 0x%08x\n", physAddr); + return 0x0; + case 0x9002: + // Power manager + printf("Getting power manager at 0x%08x\n", physAddr); + return powerManager->get_data(physAddr); + case 0x9003: + // Reset controller + printf("Getting reset controller at 0x%08x\n", physAddr); + return resetController->get_data(physAddr); + case 0x9004: + // GPIO + printf("GPIO read at 0x%08x\n", physAddr); + return gpioController->get_data(physAddr); + case 0x9005: + // Interrupt Controller + printf("Interrupt controller read at 0x%08x\n", physAddr); + return intController->get_data(physAddr); + default: + printf("Read SCM32 at 0x%08x\n", physAddr); + return 0x0; + } +} + +bool Emulator::writeSCM32(uint32_t value, uint32_t physAddr) { + uint16_t region = (physAddr >> 16) & 0xFFFF; + + switch (region) { + case 0x9000: + // OS Timer + printf("OS timer write 0x%08x at 0x%08x\n", value, physAddr); + osTimer->put_data(physAddr, value); + return true; + case 0x9001: + // RTC + printf("RTC write 0x%08x at 0x%08x\n", value, physAddr); + return true; + case 0x9002: + // Power manager + printf("Power manager write 0x%08x at 0x%08x\n", value, physAddr); + powerManager->put_data(physAddr, value); + return true; + case 0x9003: + // Reset controller + printf("Reset controller write 0x%08x at 0x%08x\n", value, physAddr); + resetController->put_data(physAddr, value); + return true; + case 0x9004: + // GPIO + printf("GPIO write 0x%08x at 0x%08x\n", value, physAddr); + gpioController->put_data(physAddr, value); + return true; + case 0x9005: + // Interrupt Controller + printf("Interrupt controller write 0x%08x at 0x%08x\n", value, physAddr); + intController->put_data(physAddr, value); + return true; + default: + printf("Write SCM32 0x%08x at 0x%08x\n", value, physAddr); + return true; + } +} + + + uint8_t Emulator::readPhysical8(uint32_t physAddr) { uint8_t region = (physAddr >> 24) & 0xFF; switch (region) { case 0x00: + printf("Read8 ROM %02x from %08x\n", ROM[physAddr & 0xFFFFFF], physAddr); return ROM[physAddr & 0xFFFFFF]; + case 0x10: + // Should not reach here + printf("Reading from ASIC14 in byte mode?\n"); + return 0; case 0x20: case 0x21: case 0x22: @@ -54,6 +207,7 @@ uint8_t Emulator::readPhysical8(uint32_t physAddr) { case 0x2E: case 0x2F: // PCMCIA slot 0 + printf("Read8 PCMCIA0 %08x\n", physAddr); return 0x0; case 0x30: case 0x31: @@ -72,6 +226,7 @@ uint8_t Emulator::readPhysical8(uint32_t physAddr) { case 0x3E: case 0x3F: // PCMCIA slot 1 + printf("Read8 PCMCIA1 %08x\n", physAddr); return 0x0; case 0x40: case 0x41: @@ -138,6 +293,7 @@ uint8_t Emulator::readPhysical8(uint32_t physAddr) { case 0x7E: case 0x7F: // Reserved, causes a data abort exception + printf("Read8 Reserved %08x\n", physAddr); return 0x0; case 0x80: // Peripheral Control Modules @@ -148,9 +304,11 @@ uint8_t Emulator::readPhysical8(uint32_t physAddr) { case 0xA0: // Memory Control Registers // Not valid in byte access + printf("Read8 Memory Controller %08x\n", physAddr); return 0x0; case 0xB0: // LCD/DMA Control Registers + printf("Read physical 8 LCD access 0x%08x\n", physAddr); return 0x0; case 0xC0: case 0xC1: @@ -160,7 +318,7 @@ uint8_t Emulator::readPhysical8(uint32_t physAddr) { case 0xC5: case 0xC6: case 0xC7: - return MemoryBlockC0[physAddr & MemoryBlockMask]; + return MemoryBlockC0[physAddr & memoryMask]; case 0xC8: case 0xC9: case 0xCA: @@ -169,19 +327,30 @@ uint8_t Emulator::readPhysical8(uint32_t physAddr) { case 0xCD: case 0xCE: case 0xCF: - return MemoryBlockC8[physAddr & MemoryBlockMask]; + return MemoryBlockC8[physAddr & memoryMask]; + // case 0xD0: + // case 0xD1: + // case 0xD2: + // case 0xD3: + // case 0xD4: + // case 0xD5: + // case 0xD6: + // case 0xD7: + // return MemoryBlockD0[physAddr & memoryMask]; + // case 0xD8: + // case 0xD9: + // case 0xDA: + // case 0xDB: + // case 0xDC: + // case 0xDD: + // case 0xDE: + // case 0xDF: + // return MemoryBlockD8[physAddr & memoryMask]; default: + printf("Read8 from %08x\n", physAddr); 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; } @@ -192,6 +361,12 @@ uint32_t Emulator::readPhysical32(uint32_t physAddr) { switch (region) { case 0x00: LOAD_32LE(result, physAddr & 0xFFFFFF, ROM); + printf("Reading %08x from %08x\n", result, physAddr); + break; + case 0x10: + // Should not reach here + printf("Reading from ASIC14 in word mode?\n"); + result = 0; break; case 0x20: case 0x21: @@ -211,6 +386,7 @@ uint32_t Emulator::readPhysical32(uint32_t physAddr) { case 0x2F: // PCMCIA slot 0 result = 0x0; + printf("Reading PCMCIA0 from %08x\n", physAddr); break; case 0x30: case 0x31: @@ -230,6 +406,7 @@ uint32_t Emulator::readPhysical32(uint32_t physAddr) { case 0x3F: // PCMCIA slot 1 result = 0x0; + printf("Reading PCMCIA1 from %08x\n", physAddr); break; case 0x40: case 0x41: @@ -297,6 +474,7 @@ uint32_t Emulator::readPhysical32(uint32_t physAddr) { case 0x7F: // Reserved, causes a data abort exception result = 0x0; + printf("Reading Reserved from %08x\n", physAddr); break; case 0x80: // Peripheral Control Modules @@ -309,10 +487,12 @@ uint32_t Emulator::readPhysical32(uint32_t physAddr) { case 0xA0: // Memory Control Registers result = memoryConfig.get_data(physAddr); + printf("Memory controller read from %08x of %08x\n", physAddr, result); break; case 0xB0: // LCD/DMA Control Registers - result = 0x0; + result = lcdController->get_data32(physAddr); + printf("LCD controller get %08x from %08x\n", result, physAddr); break; case 0xC0: case 0xC1: @@ -322,7 +502,7 @@ uint32_t Emulator::readPhysical32(uint32_t physAddr) { case 0xC5: case 0xC6: case 0xC7: - LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockC0); + LOAD_32LE(result, physAddr & memoryMask, MemoryBlockC0); break; case 0xC8: case 0xC9: @@ -332,9 +512,32 @@ uint32_t Emulator::readPhysical32(uint32_t physAddr) { case 0xCD: case 0xCE: case 0xCF: - LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockC8); + LOAD_32LE(result, physAddr & memoryMask, MemoryBlockC8); break; + // case 0xD0: + // case 0xD1: + // case 0xD2: + // case 0xD3: + // case 0xD4: + // case 0xD5: + // case 0xD6: + // case 0xD7: + // LOAD_32LE(result, physAddr & memoryMask, MemoryBlockD0); + // break; + // case 0xD8: + // case 0xD9: + // case 0xDA: + // case 0xDB: + // case 0xDC: + // case 0xDD: + // case 0xDE: + // case 0xDF: + // LOAD_32LE(result, physAddr & memoryMask, MemoryBlockD8); + // break; + case 0xE0: + return 0x0; default: + printf("Reading from %08x\n", physAddr); return 0x0; // just throw accesses to unmapped RAM away } @@ -342,21 +545,38 @@ uint32_t Emulator::readPhysical32(uint32_t physAddr) { } 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); + //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 if (valueSize == V16) { + return writePhysical16((uint16_t)value, physAddr); } else { return writePhysical32(value, physAddr); } } -bool Emulator::writePCM8(uint8_t value, uint32_t physAddr) { - return true; +bool Emulator::writePhysical16(uint16_t value, uint32_t physAddr) { + uint8_t region = (physAddr >> 24) & 0xFF; + switch (region) { + case 0x10: + asic14->put_data(physAddr, value); + return true; + default: + printf("Write16 %08x to %08x\n", value, physAddr); + return false; + } } -bool Emulator::writeSCM8(uint8_t value, uint32_t physAddr) { - return true; +uint16_t Emulator::readPhysical16(uint32_t physAddr) { + uint8_t region = (physAddr >> 24) & 0xFF; + switch (region) { + case 0x10: + return asic14->get_data(physAddr); + default: + printf("Load16 %08x\n", physAddr); + return 0; + } } bool Emulator::writePhysical8(uint8_t value, uint32_t physAddr) { @@ -364,9 +584,12 @@ bool Emulator::writePhysical8(uint8_t value, uint32_t physAddr) { switch (region) { case 0x00: + printf("Write8 %08x to %08x\n", value, physAddr); // Read-only return false; - break; + case 0x10: + printf("Write8 %08x to %08x\n", value, physAddr); + return true; case 0x20: case 0x21: case 0x22: @@ -384,6 +607,7 @@ bool Emulator::writePhysical8(uint8_t value, uint32_t physAddr) { case 0x2E: case 0x2F: // PCMCIA slot 0 + printf("Write8 PCMCIA0 %08x to %08x\n", value, physAddr); return true; case 0x30: case 0x31: @@ -402,6 +626,7 @@ bool Emulator::writePhysical8(uint8_t value, uint32_t physAddr) { case 0x3E: case 0x3F: // PCMCIA slot 1 + printf("Write8 PCMCIA1 %08x to %08x\n", value, physAddr); return true; case 0x40: case 0x41: @@ -468,6 +693,7 @@ bool Emulator::writePhysical8(uint8_t value, uint32_t physAddr) { case 0x7E: case 0x7F: // Reserved, causes a data abort exception + printf("Write8 Reserved %08x to %08x\n", value, physAddr); return false; case 0x80: // Peripheral Control Modules @@ -478,9 +704,11 @@ bool Emulator::writePhysical8(uint8_t value, uint32_t physAddr) { case 0xA0: // Memory Control Registers // Invalid to write to with bytes + printf("Write8 Memory Controller %08x to %08x\n", value, physAddr); return false; case 0xB0: // LCD/DMA Control Registers + printf("Write LCD physical8 0x%08x to 0x%08x\n", value, physAddr); return true; case 0xC0: case 0xC1: @@ -490,7 +718,11 @@ bool Emulator::writePhysical8(uint8_t value, uint32_t physAddr) { case 0xC5: case 0xC6: case 0xC7: - MemoryBlockC0[physAddr & MemoryBlockMask] = value; + //printf("Memory C0 write8 to %08x of %08x\n", physAddr, value); + if (physAddr == 0xC0000000) { + printf ("Writing palette %02x\n", value); + } + MemoryBlockC0[physAddr & memoryMask] = value; return true; case 0xC8: case 0xC9: @@ -500,30 +732,44 @@ bool Emulator::writePhysical8(uint8_t value, uint32_t physAddr) { case 0xCD: case 0xCE: case 0xCF: - MemoryBlockC8[physAddr & MemoryBlockMask] = value; + //printf("Memory C8 write8 to %08x of %08x\n", physAddr, value); + MemoryBlockC8[physAddr & memoryMask] = value; return true; + // case 0xD0: + // case 0xD1: + // case 0xD2: + // case 0xD3: + // case 0xD4: + // case 0xD5: + // case 0xD6: + // case 0xD7: + // MemoryBlockD0[physAddr & memoryMask] = value; + // return true; + // case 0xD8: + // case 0xD9: + // case 0xDA: + // case 0xDB: + // case 0xDC: + // case 0xDD: + // case 0xDE: + // case 0xDF: + // MemoryBlockD8[physAddr & memoryMask] = value; + // return true; default: // just throw accesses to unmapped RAM away + printf("Write8 %08x to %08x\n", value, physAddr); 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 + printf("Attempting write to %08x of %08x\n", physAddr, value); return false; - break; case 0x20: case 0x21: case 0x22: @@ -540,6 +786,7 @@ bool Emulator::writePhysical32(uint32_t value, uint32_t physAddr) { case 0x2D: case 0x2E: case 0x2F: + printf("Write32 PCMCIA0 %08x to %08x\n", value, physAddr); // PCMCIA slot 0 return true; case 0x30: @@ -559,6 +806,7 @@ bool Emulator::writePhysical32(uint32_t value, uint32_t physAddr) { case 0x3E: case 0x3F: // PCMCIA slot 1 + printf("Write32 PCMCIA1 %08x to %08x\n", value, physAddr); return true; case 0x40: case 0x41: @@ -625,6 +873,7 @@ bool Emulator::writePhysical32(uint32_t value, uint32_t physAddr) { case 0x7E: case 0x7F: // Reserved, causes a data abort exception + printf("Write32 reserved %08x to %08x\n", value, physAddr); return false; case 0x80: // Peripheral Control Modules @@ -634,10 +883,13 @@ bool Emulator::writePhysical32(uint32_t value, uint32_t physAddr) { return writeSCM32(value, physAddr); case 0xA0: // Memory Control Registers + printf("Memory controller write to %08x of %08x\n", physAddr, value); memoryConfig.put_data(physAddr, value); - return false; + return true; case 0xB0: // LCD/DMA Control Registers + printf("LCD controller write %08x to %08x\n", value, physAddr); + lcdController->put_data32(physAddr, value); return true; case 0xC0: case 0xC1: @@ -647,7 +899,10 @@ bool Emulator::writePhysical32(uint32_t value, uint32_t physAddr) { case 0xC5: case 0xC6: case 0xC7: - STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockC0); + if (physAddr == 0xC0000000 && value == 0x0fff1fff) { + printf ("Writing palette %08x\n", value); + } + STORE_32LE(value, physAddr & memoryMask, MemoryBlockC0); return true; case 0xC8: case 0xC9: @@ -657,10 +912,31 @@ bool Emulator::writePhysical32(uint32_t value, uint32_t physAddr) { case 0xCD: case 0xCE: case 0xCF: - STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockC8); + STORE_32LE(value, physAddr & memoryMask, MemoryBlockC8); return true; + // case 0xD0: + // case 0xD1: + // case 0xD2: + // case 0xD3: + // case 0xD4: + // case 0xD5: + // case 0xD6: + // case 0xD7: + // STORE_32LE(value, physAddr & memoryMask, MemoryBlockD0); + // return true; + // case 0xD8: + // case 0xD9: + // case 0xDA: + // case 0xDB: + // case 0xDC: + // case 0xDD: + // case 0xDE: + // case 0xDF: + // STORE_32LE(value, physAddr & memoryMask, MemoryBlockD8); + // return true; default: // just throw accesses to unmapped RAM away + printf("Write32 %08x to %08x\n", value, physAddr); return true; } } @@ -673,35 +949,48 @@ void Emulator::configure() { 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(); - + setProcessorID(0x4401A111); + powerManager->reset(); + osTimer->reset(); + lcdController->reset(); + intController->reset(); + gpioController->reset(); + asic14->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))); + memcpy(ROM, bootloader, bootloaderSize); + memcpy(MemoryBlockC8, osimg, osimgSize); } -void Emulator::executeUntil(int64_t cycles) { +bool Emulator::executeUntil(int64_t cycles) { if (!configured) configure(); + if (resetController->resetRequested()) { + resetController->reset(); + memoryConfig.reset(); + powerManager->reset(); + osTimer->reset(); + lcdController->reset(); + intController->reset(); + gpioController->reset(); + reset(); + } + while (!asleep && passedCycles < cycles) { if (passedCycles >= nextTickAt) { // increment RTCDIV @@ -715,16 +1004,20 @@ void Emulator::executeUntil(int64_t cycles) { nextTickAt += TICK_INTERVAL; pendingInterrupts |= (1<tick(); + } + gpioController->run(); + serial3->run(); + intController->run(); + + if (intController->have_pending_fiq() && canAcceptFIQ()) { + printf("Triggering FIQ\n"); requestFIQ(); halted = false; } - if ((pendingInterrupts & interruptMask & IRQ_INTERRUPTS) != 0 && canAcceptIRQ()) { + if (intController->have_pending_irq() && canAcceptIRQ()) { + printf("Triggering IRQ\n"); requestIRQ(); halted = false; } @@ -740,19 +1033,21 @@ void Emulator::executeUntil(int64_t cycles) { if (cycles < nextEvent) nextEvent = cycles; passedCycles = nextEvent; } else { - if (auto v = virtToPhys(getGPR(15) - 0xC); v.has_value() && instructionReady()) - debugPC(v.value()); + // 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; + return false; } #endif + } } + return true; } @@ -874,49 +1169,155 @@ int Emulator::getLCDHeight() const { return 480; } 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; - } +uint8_t getByteIdx(uint32_t word, int idx) { + return word >> (24-(idx*8)) & 0xFF; +} + +uint16_t getHWordIdx(uint32_t word, int idx) { + return word >> (16-(idx*16)) & 0xFFFF; +} + +void Emulator::readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) { + if (!lcdController->isLCDEnabled()) { + return; } - 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; - } - } + uint32_t paletteBase = lcdController->get_data32(LCDController::DBAR1); + // The palette is 512 bytes long + uint32_t framebufferTopHalfBase = paletteBase + 512; + uint32_t framebufferBottomHalfBase = + lcdController->get_data32(LCDController::DBAR2); + + uint32_t test; + std::vector palette; + for (int i = 0; i < 128; i++) { + LOAD_32LE(test, (paletteBase + (4*i)) & memoryMask, MemoryBlockC0); + palette.emplace_back(test & 0xFFFF); + palette.emplace_back(test >> 16); + } + + std::vector pixels; + for (int i = 0; i < 640*240; i += 4) { + LOAD_32LE(test, (framebufferTopHalfBase + (4*i)) & memoryMask, MemoryBlockC0); + for (int j = 0; j < 4; j++) { + pixels.emplace_back(getByteIdx(test, 3-j)); + } + } + for (int i = 0; i < 640*240; i += 4) { + LOAD_32LE(test, (framebufferBottomHalfBase + (4*i)) & memoryMask, MemoryBlockC0); + for (int j = 0; j < 4; j++) { + pixels.emplace_back(getByteIdx(test, 3-j)); } } + + gpioController->flip_gpio(); + + // printf("Palette:\n"); + // int newline = 0; + // for (uint16_t pal : palette) { + // newline++; + // printf("%04x ", pal); + // if (newline % 32 == 0) { + // printf("\n"); + // } + // } + // printf("\n"); + + // printf("Pixels:\n"); + // newline = 0; + // for (uint8_t pix : pixels) { + // newline++; + // printf("%02x ", pix); + // if (newline % 64 == 0) { + // printf("\n"); + // } + // } + // printf("\n"); + + printf("Pixel count %d\n", pixels.size()); + + printf("PBS: %x\n", (palette[0] >> 12) & 0x3); + + uint8_t* framebufferTopHalf = &MemoryBlockC0[framebufferTopHalfBase]; + uint8_t* framebufferBottomHalf = &MemoryBlockC0[framebufferBottomHalfBase]; + + printf("Display Size %dx%d\n", lcdController->getWidth(), lcdController->getHeight()); + + for (int i = 0; i < 480; i++) { + uint8_t* line = reinterpret_cast(lines[i]); + for (int j = 0; j < 640; j++) { + //line[j] = palette[pixels[(480*i)+j]]; + uint8_t pixel = pixels[(480*i)+j]; + // if (pixel != 0) { + // printf("Pixel data is %02x\n", pixel); + // } + line[j] = pixel; + //printf("Pixel %08x\n", line[j]); + } + } + + lcdController->finish_one_frame(); + + // int wordsPerRow = lcdController->getWidth() / 4; + // for (int i = 0; i < lcdController->getHeight(); i++) { + // line1 = reinterpret_cast(lines[i]); + // line2 = reinterpret_cast(lines[240+i]); + + // for (int j = 0; j < wordsPerRow; j++) { + // LOAD_32LE(pixels1, (framebufferTopHalfBase + 4 * (j + (i*wordsPerRow))) & 0xFFFFFF, MemoryBlockC0); + // LOAD_32LE(pixels2, (framebufferBottomHalfBase + 4 * (j + (i*wordsPerRow))) & 0xFFFFFF, MemoryBlockC0); + // for (int k = 0; k < 4; k++) { + // line1[(4*j)+k] = palette[getByteIdx(pixels1, 3-k)] & 0xFFF; + // line2[(4*j)+k] = palette[getByteIdx(pixels2, 3-k)] & 0xFFF; + // } + // } + // } + //for (int i = 0; i < 256; i++) { +// printf("%02x%02x \n", MemoryBlockC0[paletteBase+i], MemoryBlockC0[paletteBase+i+1]); +// }//printf("Palette: %d\n", palette->PBS); + + // 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 - 0xC0000000]; + // 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; + // } + // } + // } + // } } diff --git a/WindCore/sa1100.h b/WindCore/sa1100.h index d101985..9de390e 100644 --- a/WindCore/sa1100.h +++ b/WindCore/sa1100.h @@ -4,7 +4,16 @@ #include "emubase.h" #include "sa1100_defs.h" #include "hardware.h" + +#include "sa1100/asic14.h" +#include "sa1100/gpio_controller.h" +#include "sa1100/interrupt_controller.h" +#include "sa1100/lcd_controller.h" #include "sa1100/memory_conf.h" +#include "sa1100/power_manager.h" +#include "sa1100/os_timer.h" +#include "sa1100/reset_controller.h" +#include "sa1100/serial_3.h" namespace SA1100 { @@ -20,14 +29,16 @@ namespace SA1100 { class Emulator : public EmuBase { public: // 16MB ROM file - uint8_t ROM[0x1000000]; + uint8_t* ROM; // 16MB RAM/bank0, mapped at base addr 0xC0000000 - uint8_t MemoryBlockC0[0x1000000]; + uint8_t* MemoryBlockC0; // 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 }; + uint8_t* MemoryBlockC8; + // uint8_t* MemoryBlockD0; + // uint8_t* MemoryBlockD8; + int memoryMask = 0xFFFFFF; private: uint16_t pendingInterrupts = 0; @@ -47,7 +58,16 @@ private: Timer tc1, tc2; UART uart1, uart2; + MemoryConf memoryConfig; + GPIOController* gpioController; + LCDController* lcdController; + OsTimer* osTimer; + IntController* intController; + PowerManager* powerManager; + ResetController* resetController; + Serial3* serial3; + ASIC14* asic14; bool halted = false, asleep = false; @@ -59,9 +79,11 @@ public: private: uint8_t readPhysical8(uint32_t physAddr); + uint16_t readPhysical16(uint32_t physAddr); uint32_t readPhysical32(uint32_t physAddr); bool writePhysical8(uint8_t value, uint32_t physAddr); + bool writePhysical16(uint16_t value, uint32_t physAddr); bool writePhysical32(uint32_t value, uint32_t physAddr); uint8_t readPCM8(uint32_t physAddr); @@ -90,10 +112,11 @@ private: public: Emulator(); + virtual ~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; + bool executeUntil(int64_t cycles) override; int32_t getClockSpeed() const override { return CLOCK_SPEED; } const char *getDeviceName() const override; int getDigitiserWidth() const override; @@ -102,7 +125,7 @@ public: int getLCDOffsetY() const override; int getLCDWidth() const override; int getLCDHeight() const override; - void readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) const override; + void readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) override; void setKeyboardKey(EpocKey key, bool value) override; void updateTouchInput(int32_t x, int32_t y, bool down) override; }; diff --git a/WindCore/sa1100_defs.h b/WindCore/sa1100_defs.h index 52533f9..bf5c0df 100644 --- a/WindCore/sa1100_defs.h +++ b/WindCore/sa1100_defs.h @@ -5,7 +5,8 @@ namespace SA1100 { enum { - CLOCK_SPEED = 0x9000*1000, + CLOCK_SPEED = 190*1000*1000, // 190MHz + TICKS_3_6864_MHZ = CLOCK_SPEED / 3686400, TICK_INTERVAL = CLOCK_SPEED / 64 }; diff --git a/WindCore/windermere.cpp b/WindCore/windermere.cpp index adf5342..81ed10f 100644 --- a/WindCore/windermere.cpp +++ b/WindCore/windermere.cpp @@ -381,7 +381,7 @@ void Emulator::loadROM(uint8_t *buffer, size_t size, uint8_t*, size_t) { memcpy(ROM, buffer, min(size, sizeof(ROM))); } -void Emulator::executeUntil(int64_t cycles) { +bool Emulator::executeUntil(int64_t cycles) { if (!configured) configure(); @@ -431,11 +431,12 @@ void Emulator::executeUntil(int64_t cycles) { uint32_t new_pc = getGPR(15) - 0xC; if (_breakpoints.find(new_pc) != _breakpoints.end()) { log("⚠️ Breakpoint triggered at %08x!", new_pc); - return; + return false; } #endif } } + return true; } @@ -557,7 +558,7 @@ int Emulator::getLCDHeight() const { return 240; } static bool initRgbValues = false; static uint32_t rgbValues[16]; -void Emulator::readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) const { +void Emulator::readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) { if (!initRgbValues) { initRgbValues = true; for (int i = 0; i < 16; i++) { diff --git a/WindCore/windermere.h b/WindCore/windermere.h index 10cf24d..975f2c5 100644 --- a/WindCore/windermere.h +++ b/WindCore/windermere.h @@ -65,7 +65,7 @@ public: uint8_t *getROMBuffer() override; size_t getROMSize() override; void loadROM(uint8_t *buffer, size_t size, uint8_t*, size_t) override; - void executeUntil(int64_t cycles) override; + bool executeUntil(int64_t cycles) override; int32_t getClockSpeed() const override { return CLOCK_SPEED; } const char *getDeviceName() const override; int getDigitiserWidth() const override; @@ -74,7 +74,7 @@ public: int getLCDOffsetY() const override; int getLCDWidth() const override; int getLCDHeight() const override; - void readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) const override; + void readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) override; void setKeyboardKey(EpocKey key, bool value) override; void updateTouchInput(int32_t x, int32_t y, bool down) override; }; diff --git a/WindQt/main.cpp b/WindQt/main.cpp index 97f4d85..9027719 100644 --- a/WindQt/main.cpp +++ b/WindQt/main.cpp @@ -26,10 +26,10 @@ int main(int argc, char *argv[]) auto buffer = f.readAll(); f.close(); - if (buffer.size() < 0x400000) { - QMessageBox::critical(nullptr, "WindEmu", "Invalid ROM file!"); - return 0; - } + // if (buffer.size() < 0x400000) { + // QMessageBox::critical(nullptr, "WindEmu", "Invalid ROM file!"); + // return 0; + // } // what do we have? QFile f2(bootloader); @@ -42,25 +42,25 @@ int main(int argc, char *argv[]) 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; - if (variantFile < (buffer.size() - 8)) { - int variantImg = *((uint32_t *)&romData[variantFile + 4]) & 0xFFFFFFF; - if (variantImg < (buffer.size() - 0x70)) { - int variant = *((uint32_t *)&romData[variantImg + 0x60]); - - if (variant == 0x7060001) { - // 5mx ROM - emu = new Windermere::Emulator; - } else if (variant == 0x5040001) { - // Osaris ROM - emu = new CLPS7111::Emulator; - } else { - // Netbook ROM - emu = new SA1100::Emulator; - } - } - } + // int variantFile = *((uint32_t *)&romData[0x80 + 0x4C]) & 0xFFFFFFF; + // if (variantFile < (buffer.size() - 8)) { + // int variantImg = *((uint32_t *)&romData[variantFile + 4]) & 0xFFFFFFF; + // if (variantImg < (buffer.size() - 0x70)) { + // int variant = *((uint32_t *)&romData[variantImg + 0x60]); + // if (variant == 0x7060001) { + // // 5mx ROM + // emu = new Windermere::Emulator; + // } else if (variant == 0x5040001) { + // // Osaris ROM + // emu = new CLPS7111::Emulator; + // } else { + // // Netbook ROM + // emu = new SA1100::Emulator; + // } + // } + // } +emu = new SA1100::Emulator; 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 eeb38e1..3176ea1 100644 --- a/WindQt/mainwindow.cpp +++ b/WindQt/mainwindow.cpp @@ -23,6 +23,11 @@ MainWindow::MainWindow(EmuBase *emu, QWidget *parent) : timer->setInterval(1000/64); connect(timer, SIGNAL(timeout()), SLOT(execTimer())); + // // 100ms frame times for now (10Hz) + // timer_vsync = new QTimer(this); + // timer_vsync->setInterval(100); + // connect(timer_vsync, SIGNAL(timeout()), SLOT(vsync())); + pdaScreen.show(); updateScreen(); @@ -131,7 +136,7 @@ void MainWindow::on_stopButton_clicked() void MainWindow::on_stepTickButton_clicked() { // emu->executeUntil(emu->currentCycles() + (CLOCK_SPEED * 2)); - emu->executeUntil(emu->currentCycles() + 25000000); + emu->executeUntil(emu->currentCycles() + 43373290); updateScreen(); } @@ -144,7 +149,13 @@ void MainWindow::on_stepInsnButton_clicked() void MainWindow::execTimer() { if (emu) { - emu->executeUntil(emu->currentCycles() + (emu->getClockSpeed() / 64)); + if (!emu->executeUntil(emu->currentCycles() + (emu->getClockSpeed() / 64))) { + timer->stop(); + ui->startButton->setEnabled(true); + ui->stopButton->setEnabled(false); + ui->stepInsnButton->setEnabled(true); + ui->stepTickButton->setEnabled(true); + } updateScreen(); } } diff --git a/WindQt/pdascreenwindow.cpp b/WindQt/pdascreenwindow.cpp index 4531c5b..ca8558b 100644 --- a/WindQt/pdascreenwindow.cpp +++ b/WindQt/pdascreenwindow.cpp @@ -60,6 +60,7 @@ void PDAScreenWindow::updateScreen() { emu->readLCDIntoBuffer(lines, false); lcd->setPixmap(QPixmap::fromImage(std::move(img))); + //emu->finishOneFrame(); } #ifdef Q_OS_MAC -- 2.45.2