]> localhost Git - WindEmu.git/commitdiff
initial impl
authorGeorge Wright <gw@gwright.org.uk>
Tue, 3 Dec 2024 17:18:37 +0000 (09:18 -0800)
committerGeorge Wright <gw@gwright.org.uk>
Tue, 3 Dec 2024 17:18:37 +0000 (09:18 -0800)
14 files changed:
WindCore/WindCore.pro
WindCore/arm710.cpp
WindCore/arm710.h
WindCore/clps7111.cpp
WindCore/clps7111.h
WindCore/emubase.h
WindCore/sa1100.cpp
WindCore/sa1100.h
WindCore/sa1100_defs.h
WindCore/windermere.cpp
WindCore/windermere.h
WindQt/main.cpp
WindQt/mainwindow.cpp
WindQt/pdascreenwindow.cpp

index b0b2353f478c533d1e03405167876f1744c3a036..6c67c42cbb149c9c851af7a524687b5aadf94885 100644 (file)
@@ -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
index 807c8cbc3ca9dabd4dd359dc66b9f11ebc41248b..dbb481270c6599deb6c2b6287762911989fce269 100644 (file)
@@ -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) {
index 76be1dd0900ca157fa33a66390eaa3a1d09fde2a..21d01ef93f122f17d97fb5520700fdd5c631ce62 100644 (file)
@@ -18,14 +18,14 @@ using namespace std;
 
 // Speedhacks:
 //#define ARM710T_CACHE
-//#define ARM710T_TLB
+#define ARM710T_TLB
 
 typedef optional<uint32_t> 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);
index bfc192255ca478c1b91d0ed5f7a42be504d924f3..57a4ca02a6ef42bb51918e3bb38a636b70a08aec 100644 (file)
@@ -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;
index fda94dcc7efb73261311ded64ae8db86e16c7e44..9e1fc8347cbfc2e107a89722b1f6c57f4efc61cb 100644 (file)
@@ -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;
 };
index 58469b9deae176c3f8b2d0283af572e34ff8cad4..e11ac76b0182484e59f0cf730f5d6da2c49d9763 100644 (file)
@@ -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;
 
index 81def25ac5a1152b01b945edc1cabb84e28c0a40..3e204ac4f7fae03332825d929e4be02e5e4b3460 100644 (file)
@@ -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<<TINT);
                }
-               if (tc1.tick(passedCycles))
-                       pendingInterrupts |= (1<<TC1OI);
-               if (tc2.tick(passedCycles))
-                       pendingInterrupts |= (1<<TC2OI);
-
-               if ((pendingInterrupts & interruptMask & FIQ_INTERRUPTS) != 0 && canAcceptFIQ()) {
+               if (passedCycles % TICKS_3_6864_MHZ == 0) {
+                       osTimer->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<uint16_t> 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<uint8_t> 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<uint8_t*>(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<uint16_t*>(lines[i]);
+       //      line2 = reinterpret_cast<uint16_t*>(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;
+       //                      }
+       //              }
+       //      }
+       // }
 }
 
 
index d101985a5557bd0c61a3a528d192a088bddc3196..9de390eed2ca6e0ae011c8aeba99fcb62f4bf0a7 100644 (file)
@@ -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;
 };
index 52533f9e62270fdc0bf2527b554ec8f8df55e27d..bf5c0dfa23ce91bdd5d14fe679f70c3fba5c1a0a 100644 (file)
@@ -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
 };
 
index adf5342e6b9588652ee5cf39080dcd79ff1a8b65..81ed10f452dd217c5b9f7320a5c4ea219438f470 100644 (file)
@@ -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++) {
index 10cf24d215700a5dcb123b33527522cdff40484a..975f2c5ca3f95555b68db8be6f62efd3fcd27466 100644 (file)
@@ -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;
 };
index 97f4d85ac4d8c1963af53e7842a80e2436579889..9027719cb40ed6c68bcb0ca2181d52b348239f5e 100644 (file)
@@ -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();
index eeb38e1a109bb652e2d5622ca8594fced7229ff4..3176ea113e35b8363cc68e7272d1e3f8259a100e 100644 (file)
@@ -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();
        }
 }
index 4531c5ba352e9357210289057d7ad499f50a2209..ca8558b2ab7a86fd6f79e60b505e6473727f7a3b 100644 (file)
@@ -60,6 +60,7 @@ void PDAScreenWindow::updateScreen() {
        emu->readLCDIntoBuffer(lines, false);
 
        lcd->setPixmap(QPixmap::fromImage(std::move(img)));
+       //emu->finishOneFrame();
 }
 
 #ifdef Q_OS_MAC