]> localhost Git - WindEmu.git/commitdiff
Initial stubbed implementation of an SA-1100 core
authorGeorge Wright <gw@gwright.org.uk>
Sun, 23 Jan 2022 08:25:40 +0000 (00:25 -0800)
committerGeorge Wright <gw@gwright.org.uk>
Sun, 23 Jan 2022 08:25:40 +0000 (00:25 -0800)
16 files changed:
WindCore/WindCore.pro
WindCore/arm710.cpp
WindCore/arm710.h
WindCore/clps7111.cpp
WindCore/clps7111.h
WindCore/emubase.h
WindCore/sa1100.cpp [new file with mode: 0644]
WindCore/sa1100.h [new file with mode: 0644]
WindCore/sa1100/memory_conf.cpp [new file with mode: 0644]
WindCore/sa1100/memory_conf.h [new file with mode: 0644]
WindCore/sa1100_defs.h [new file with mode: 0644]
WindCore/windermere.cpp
WindCore/windermere.h
WindEmu.pro
WindQt/main.cpp
WindQt/mainwindow.cpp

index f39561e48e3cb57d8216cf85d5c50a11c136366a..b0b2353f478c533d1e03405167876f1744c3a036 100644 (file)
@@ -16,6 +16,7 @@ CONFIG += staticlib c++17
 # depend on your compiler). Please consult the documentation of the
 # deprecated API in order to know how to port your code away from it.
 DEFINES += QT_DEPRECATED_WARNINGS
+#QMAKE_CXXFLAGS += QMAKE_CXXFLAGS_WARN_OFF
 
 # You can also make your code fail to compile if you use deprecated APIs.
 # In order to do so, uncomment the following line.
@@ -30,7 +31,9 @@ SOURCES += \
     etna.cpp \
     decoder.c \
     decoder-arm.c \
-    windermere.cpp
+    windermere.cpp \
+    sa1100.cpp \
+    sa1100/memory_conf.cpp
 
 HEADERS += \
     arm710.h \
@@ -49,8 +52,10 @@ HEADERS += \
     decoder.h \
     decoder-inlines.h \
     common.h \
-    windermere.h
+    windermere.h \
+    sa1100.h \
+    sa1100/memory_conf.h
 unix {
     target.path = /usr/lib
     INSTALLS += target
-}
+}
\ No newline at end of file
index eaa6a015939ddd49e5d8849ebb956797ae691c2b..807c8cbc3ca9dabd4dd359dc66b9f11ebc41248b 100644 (file)
@@ -37,7 +37,7 @@ void ARM710::switchBank(BankIndex newBank) {
 void ARM710::switchMode(Mode newMode) {
        auto oldMode = currentMode();
        if (newMode != oldMode) {
-//             log("Switching mode! %x", newMode);
+               log("Switching mode! %x", newMode);
                switchBank(modeToBank[newMode & 0xF]);
 
                CPSR &= ~CPSR_ModeMask;
@@ -47,7 +47,7 @@ void ARM710::switchMode(Mode newMode) {
 
 void ARM710::raiseException(Mode mode, uint32_t savedPC, uint32_t newPC) {
        auto bankIndex = modeToBank[mode & 0xF];
-//     log("Raising exception mode %x, saving PC %08x, CPSR %08x", mode, savedPC, CPSR);
+       log("Raising exception mode %x, saving PC %08x, CPSR %08x", mode, savedPC, CPSR);
        SPSRs[bankIndex] = CPSR;
 
        switchMode(mode);
@@ -140,7 +140,7 @@ static inline bool extract1(uint32_t value, uint32_t bit) {
 
 uint32_t ARM710::executeInstruction(uint32_t i) {
        uint32_t cycles = 1;
-//     log("executing insn %08x @ %08x", i, GPRs[15] - 0xC);
+       log("executing insn %08x @ %08x", i, GPRs[15] - 0xC);
 
        // a big old dispatch thing here
        // but first, conditions!
@@ -317,11 +317,11 @@ uint32_t ARM710::execDataProcessing(bool I, uint32_t Opcode, bool S, uint32_t Rn
                // Output-less opcodes: special behaviour
                if (S) {
                        CPSR = (CPSR & ~CPSR_FlagMask) | flags;
-//                     log("CPSR setflags=%08x results in CPSR=%08x", flags, CPSR);
+                       log("CPSR setflags=%08x results in CPSR=%08x", flags, CPSR);
                } else if (Opcode == 8) {
                        // MRS, CPSR -> Reg
                        GPRs[Rd] = CPSR;
-//                     log("r%d <- CPSR(%08x)", Rd, GPRs[Rd]);
+                       log("r%d <- CPSR(%08x)", Rd, GPRs[Rd]);
                } else if (Opcode == 9) {
                        // MSR, Reg -> CPSR
                        bool canChangeMode = extract1(Rn, 0);
@@ -329,33 +329,33 @@ uint32_t ARM710::execDataProcessing(bool I, uint32_t Opcode, bool S, uint32_t Rn
                                auto newCPSR = GPRs[extract(Operand2, 3, 0)];
                                switchMode(modeFromCPSR(newCPSR));
                                CPSR = newCPSR;
-//                             log("CPSR change privileged: %08x", CPSR);
+                               log("CPSR change privileged: %08x", CPSR);
                        } else {
                                // for the flag-only version, immediates are allowed
                                // so we just re-use what was calculated earlier...
                                auto newFlag = I ? op2 : GPRs[extract(Operand2, 3, 0)];
                                CPSR &= ~CPSR_FlagMask;
                                CPSR |= (newFlag & CPSR_FlagMask);
-//                             log("CPSR change unprivileged: new=%08x result=%08x", newFlag, CPSR);
+                               log("CPSR change unprivileged: new=%08x result=%08x", newFlag, CPSR);
                        }
                } else if (Opcode == 0xA) {
                        // MRS, SPSR -> Reg
                        if (isPrivileged()) {
                                GPRs[Rd] = SPSRs[currentBank()];
-//                             log("r%d <- SPSR(%08x)", Rd, GPRs[Rd]);
+                               log("r%d <- SPSR(%08x)", Rd, GPRs[Rd]);
                        }
                } else /*if (Opcode == 0xB)*/ {
                        bool canChangeMode = extract1(Rn, 0);
                        if (isPrivileged()) {
                                if (canChangeMode) {
                                        SPSRs[currentBank()] = GPRs[extract(Operand2, 3, 0)];
-//                                     log("SPSR change privileged: %08x", SPSRs[currentBank()]);
+                                       log("SPSR change privileged: %08x", SPSRs[currentBank()]);
                                } else {
                                        // same hat
                                        auto newFlag = I ? op2 : GPRs[extract(Operand2, 3, 0)];
                                        SPSRs[currentBank()] &= ~CPSR_FlagMask;
                                        SPSRs[currentBank()] |= (newFlag & CPSR_FlagMask);
-//                                     log("SPSR change unprivileged: new=%08x result=%08x", newFlag, SPSRs[currentBank()]);
+                                       log("SPSR change unprivileged: new=%08x result=%08x", newFlag, SPSRs[currentBank()]);
                                }
                        }
                }
@@ -373,11 +373,11 @@ uint32_t ARM710::execDataProcessing(bool I, uint32_t Opcode, bool S, uint32_t Rn
                                auto saved = SPSRs[currentBank()];
                                switchMode(modeFromCPSR(saved));
                                CPSR = saved;
-//                             log("dataproc restore CPSR: %08x", saved);
+                               log("dataproc restore CPSR: %08x", saved);
                        }
                } else if (S) {
                        CPSR = (CPSR & ~CPSR_FlagMask) | flags;
-//                     log("dataproc flag change: flags=%08x CPSR=%08x", flags, CPSR);
+                       log("dataproc flag change: flags=%08x CPSR=%08x", flags, CPSR);
                }
        }
 
@@ -608,7 +608,7 @@ uint32_t ARM710::execBlockDataTransfer(uint32_t PUSWL, uint32_t Rn, uint32_t reg
                        auto saved = SPSRs[currentBank()];
                        switchMode(modeFromCPSR(saved));
                        CPSR = saved;
-//                     log("reloading saved SPSR: %08x", saved);
+                       log("reloading saved SPSR: %08x", saved);
                }
        }
 
@@ -1113,16 +1113,11 @@ void ARM710::reportFault(MMUFault fault) {
 
 
 void ARM710::log(const char *format, ...) {
-       if (logger) {
-               char buffer[1024];
-
                va_list vaList;
                va_start(vaList, format);
-               vsnprintf(buffer, sizeof(buffer), format, vaList);
+               printf(format, vaList);
                va_end(vaList);
-
-               logger(buffer);
-       }
+               printf("\n");
 }
 
 void ARM710::logPcHistory() {
index cb85566824d76cc3c1bf4b4e706b0565610c4a21..76be1dd0900ca157fa33a66390eaa3a1d09fde2a 100644 (file)
@@ -60,7 +60,7 @@ public:
 
        ARM710(bool _isTVersion) {
                isTVersion = _isTVersion;
-               cp15_id = _isTVersion ? 0x41807100 : 0x41047100;
+               cp15_id = 0x4401A111;// _isTVersion ? 0x41807100 : 0x41047100;
                clearAllValues();
        }
        virtual ~ARM710() { }
index 618e54606aeece8657a4ab0d0b6c39030f0cedb7..bfc192255ca478c1b91d0ed5f7a42be504d924f3 100644 (file)
@@ -292,7 +292,7 @@ uint8_t *Emulator::getROMBuffer() {
 size_t Emulator::getROMSize() {
        return sizeof(ROM);
 }
-void Emulator::loadROM(uint8_t *buffer, size_t size) {
+void Emulator::loadROM(uint8_t *buffer, size_t size, uint8_t*, size_t) {
        memcpy(ROM, buffer, min(size, sizeof(ROM)));
 }
 
index 47dae14ef53d1c389395fb998b5a09fe5764fbd2..fda94dcc7efb73261311ded64ae8db86e16c7e44 100644 (file)
@@ -63,7 +63,7 @@ public:
        Emulator();
        uint8_t *getROMBuffer() override;
        size_t getROMSize() override;
-       void loadROM(uint8_t *buffer, size_t size) override;
+       void loadROM(uint8_t *buffer, size_t size, uint8_t *bootloader, size_t bootloader_size) override;
        void executeUntil(int64_t cycles) override;
        int32_t getClockSpeed() const override { return CLOCK_SPEED; }
        const char *getDeviceName() const override;
index ae35d9d8434642a142d2f9c6ca6ad6bbed9ddee7..58469b9deae176c3f8b2d0283af572e34ff8cad4 100644 (file)
@@ -115,7 +115,7 @@ public:
 
        virtual uint8_t *getROMBuffer() = 0;
        virtual size_t getROMSize() = 0;
-       virtual void loadROM(uint8_t *buffer, size_t size) = 0;
+       virtual void loadROM(uint8_t *buffer, size_t size, uint8_t *bootloader, size_t bootloader_size) = 0;
        virtual void executeUntil(int64_t cycles) = 0;
        virtual int32_t getClockSpeed() const = 0;
        virtual const char *getDeviceName() const = 0;
diff --git a/WindCore/sa1100.cpp b/WindCore/sa1100.cpp
new file mode 100644 (file)
index 0000000..81def25
--- /dev/null
@@ -0,0 +1,1073 @@
+#include "sa1100.h"
+#include "hardware.h"
+#include <time.h>
+#include "common.h"
+
+namespace SA1100 {
+
+Emulator::Emulator() : EmuBase(true) {
+}
+
+uint32_t Emulator::getRTC() {
+    return time(nullptr) - 946684800;
+}
+
+MaybeU32 Emulator::readPhysical(uint32_t physAddr, ValueSize valueSize) {
+       //printf("readPhysical:: pc=%08x addr=%03x\n", getGPR(15)-4, physAddr);
+       if (valueSize == V8) {
+               return readPhysical8(physAddr);
+       } else {
+               return readPhysical32(physAddr);
+       }
+}
+
+uint8_t Emulator::readPCM8(uint32_t physAddr) {
+       // Peripheral Control Modules
+       return 0x0;
+}
+
+uint8_t Emulator::readSCM8(uint32_t physAddr) {
+       // System Control Modules
+       return 0x0;
+}
+
+uint8_t Emulator::readPhysical8(uint32_t physAddr) {
+    uint8_t region = (physAddr >> 24) & 0xFF;
+
+       switch (region) {
+       case 0x00:
+               return ROM[physAddr & 0xFFFFFF];
+       case 0x20:
+       case 0x21:
+       case 0x22:
+       case 0x23:
+       case 0x24:
+       case 0x25:
+       case 0x26:
+       case 0x27:
+       case 0x28:
+       case 0x29:
+       case 0x2A:
+       case 0x2B:
+       case 0x2C:
+       case 0x2D:
+       case 0x2E:
+       case 0x2F:
+               // PCMCIA slot 0
+               return 0x0;
+       case 0x30:
+       case 0x31:
+       case 0x32:
+       case 0x33:
+       case 0x34:
+       case 0x35:
+       case 0x36:
+       case 0x37:
+       case 0x38:
+       case 0x39:
+       case 0x3A:
+       case 0x3B:
+       case 0x3C:
+       case 0x3D:
+       case 0x3E:
+       case 0x3F:
+               // PCMCIA slot 1
+               return 0x0;
+       case 0x40:
+       case 0x41:
+       case 0x42:
+       case 0x43:
+       case 0x44:
+       case 0x45:
+       case 0x46:
+       case 0x47:
+       case 0x48:
+       case 0x49:
+       case 0x4A:
+       case 0x4B:
+       case 0x4C:
+       case 0x4D:
+       case 0x4E:
+       case 0x4F:
+       case 0x50:
+       case 0x51:
+       case 0x52:
+       case 0x53:
+       case 0x54:
+       case 0x55:
+       case 0x56:
+       case 0x57:
+       case 0x58:
+       case 0x59:
+       case 0x5A:
+       case 0x5B:
+       case 0x5C:
+       case 0x5D:
+       case 0x5E:
+       case 0x5F:
+       case 0x60:
+       case 0x61:
+       case 0x62:
+       case 0x63:
+       case 0x64:
+       case 0x65:
+       case 0x66:
+       case 0x67:
+       case 0x68:
+       case 0x69:
+       case 0x6A:
+       case 0x6B:
+       case 0x6C:
+       case 0x6D:
+       case 0x6E:
+       case 0x6F:
+       case 0x70:
+       case 0x71:
+       case 0x72:
+       case 0x73:
+       case 0x74:
+       case 0x75:
+       case 0x76:
+       case 0x77:
+       case 0x78:
+       case 0x79:
+       case 0x7A:
+       case 0x7B:
+       case 0x7C:
+       case 0x7D:
+       case 0x7E:
+       case 0x7F:
+               // Reserved, causes a data abort exception
+               return 0x0;
+       case 0x80:
+               // Peripheral Control Modules
+               return readPCM8(physAddr);
+       case 0x90:
+               // System Control Modules
+               return readSCM8(physAddr);
+       case 0xA0:
+               // Memory Control Registers
+               // Not valid in byte access
+               return 0x0;
+       case 0xB0:
+               // LCD/DMA Control Registers
+               return 0x0;
+       case 0xC0:
+       case 0xC1:
+       case 0xC2:
+       case 0xC3:
+       case 0xC4:
+       case 0xC5:
+       case 0xC6:
+       case 0xC7:
+               return MemoryBlockC0[physAddr & MemoryBlockMask];
+       case 0xC8:
+       case 0xC9:
+       case 0xCA:
+       case 0xCB:
+       case 0xCC:
+       case 0xCD:
+       case 0xCE:
+       case 0xCF:
+               return MemoryBlockC8[physAddr & MemoryBlockMask];
+       default:
+               return 0x0; // just throw accesses to unmapped RAM away
+       }
+}
+
+uint32_t Emulator::readPCM32(uint32_t physAddr) {
+       // Peripheral Control Modules
+       return 0x0;
+}
+
+uint32_t Emulator::readSCM32(uint32_t physAddr) {
+       // System Control Modules
+       return 0x0;
+}
+
+uint32_t Emulator::readPhysical32(uint32_t physAddr) {
+    uint8_t region = (physAddr >> 24) & 0xFF;
+       uint32_t result;
+
+       switch (region) {
+       case 0x00:
+               LOAD_32LE(result, physAddr & 0xFFFFFF, ROM);
+               break;
+       case 0x20:
+       case 0x21:
+       case 0x22:
+       case 0x23:
+       case 0x24:
+       case 0x25:
+       case 0x26:
+       case 0x27:
+       case 0x28:
+       case 0x29:
+       case 0x2A:
+       case 0x2B:
+       case 0x2C:
+       case 0x2D:
+       case 0x2E:
+       case 0x2F:
+               // PCMCIA slot 0
+               result = 0x0;
+               break;
+       case 0x30:
+       case 0x31:
+       case 0x32:
+       case 0x33:
+       case 0x34:
+       case 0x35:
+       case 0x36:
+       case 0x37:
+       case 0x38:
+       case 0x39:
+       case 0x3A:
+       case 0x3B:
+       case 0x3C:
+       case 0x3D:
+       case 0x3E:
+       case 0x3F:
+               // PCMCIA slot 1
+               result = 0x0;
+               break;
+       case 0x40:
+       case 0x41:
+       case 0x42:
+       case 0x43:
+       case 0x44:
+       case 0x45:
+       case 0x46:
+       case 0x47:
+       case 0x48:
+       case 0x49:
+       case 0x4A:
+       case 0x4B:
+       case 0x4C:
+       case 0x4D:
+       case 0x4E:
+       case 0x4F:
+       case 0x50:
+       case 0x51:
+       case 0x52:
+       case 0x53:
+       case 0x54:
+       case 0x55:
+       case 0x56:
+       case 0x57:
+       case 0x58:
+       case 0x59:
+       case 0x5A:
+       case 0x5B:
+       case 0x5C:
+       case 0x5D:
+       case 0x5E:
+       case 0x5F:
+       case 0x60:
+       case 0x61:
+       case 0x62:
+       case 0x63:
+       case 0x64:
+       case 0x65:
+       case 0x66:
+       case 0x67:
+       case 0x68:
+       case 0x69:
+       case 0x6A:
+       case 0x6B:
+       case 0x6C:
+       case 0x6D:
+       case 0x6E:
+       case 0x6F:
+       case 0x70:
+       case 0x71:
+       case 0x72:
+       case 0x73:
+       case 0x74:
+       case 0x75:
+       case 0x76:
+       case 0x77:
+       case 0x78:
+       case 0x79:
+       case 0x7A:
+       case 0x7B:
+       case 0x7C:
+       case 0x7D:
+       case 0x7E:
+       case 0x7F:
+               // Reserved, causes a data abort exception
+               result = 0x0;
+               break;
+       case 0x80:
+               // Peripheral Control Modules
+               result = readPCM32(physAddr);
+               break;
+       case 0x90:
+               // System Control Modules
+               result = readSCM32(physAddr);
+               break;
+       case 0xA0:
+               // Memory Control Registers
+               result = memoryConfig.get_data(physAddr);
+               break;
+       case 0xB0:
+               // LCD/DMA Control Registers
+               result = 0x0;
+               break;
+       case 0xC0:
+       case 0xC1:
+       case 0xC2:
+       case 0xC3:
+       case 0xC4:
+       case 0xC5:
+       case 0xC6:
+       case 0xC7:
+               LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockC0);
+               break;
+       case 0xC8:
+       case 0xC9:
+       case 0xCA:
+       case 0xCB:
+       case 0xCC:
+       case 0xCD:
+       case 0xCE:
+       case 0xCF:
+               LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockC8);
+               break;
+       default:
+               return 0x0; // just throw accesses to unmapped RAM away
+       }
+
+       return result;
+}
+
+bool Emulator::writePhysical(uint32_t value, uint32_t physAddr, ValueSize valueSize) {
+       printf("writePhysical:: pc=%08x addr=%03x value=%08x\n", getGPR(15)-4, physAddr, value);
+       uint8_t region = (physAddr >> 24) & 0xFF;
+       if (valueSize == V8) {
+               return writePhysical8((uint8_t)value, physAddr);
+       } else {
+               return writePhysical32(value, physAddr);
+       }
+}
+
+bool Emulator::writePCM8(uint8_t value, uint32_t physAddr) {
+       return true;
+}
+
+bool Emulator::writeSCM8(uint8_t value, uint32_t physAddr) {
+       return true;
+}
+
+bool Emulator::writePhysical8(uint8_t value, uint32_t physAddr) {
+       uint8_t region = (physAddr >> 24) & 0xFF;
+
+       switch (region) {
+       case 0x00:
+               // Read-only
+               return false;
+               break;
+       case 0x20:
+       case 0x21:
+       case 0x22:
+       case 0x23:
+       case 0x24:
+       case 0x25:
+       case 0x26:
+       case 0x27:
+       case 0x28:
+       case 0x29:
+       case 0x2A:
+       case 0x2B:
+       case 0x2C:
+       case 0x2D:
+       case 0x2E:
+       case 0x2F:
+               // PCMCIA slot 0
+               return true;
+       case 0x30:
+       case 0x31:
+       case 0x32:
+       case 0x33:
+       case 0x34:
+       case 0x35:
+       case 0x36:
+       case 0x37:
+       case 0x38:
+       case 0x39:
+       case 0x3A:
+       case 0x3B:
+       case 0x3C:
+       case 0x3D:
+       case 0x3E:
+       case 0x3F:
+               // PCMCIA slot 1
+               return true;
+       case 0x40:
+       case 0x41:
+       case 0x42:
+       case 0x43:
+       case 0x44:
+       case 0x45:
+       case 0x46:
+       case 0x47:
+       case 0x48:
+       case 0x49:
+       case 0x4A:
+       case 0x4B:
+       case 0x4C:
+       case 0x4D:
+       case 0x4E:
+       case 0x4F:
+       case 0x50:
+       case 0x51:
+       case 0x52:
+       case 0x53:
+       case 0x54:
+       case 0x55:
+       case 0x56:
+       case 0x57:
+       case 0x58:
+       case 0x59:
+       case 0x5A:
+       case 0x5B:
+       case 0x5C:
+       case 0x5D:
+       case 0x5E:
+       case 0x5F:
+       case 0x60:
+       case 0x61:
+       case 0x62:
+       case 0x63:
+       case 0x64:
+       case 0x65:
+       case 0x66:
+       case 0x67:
+       case 0x68:
+       case 0x69:
+       case 0x6A:
+       case 0x6B:
+       case 0x6C:
+       case 0x6D:
+       case 0x6E:
+       case 0x6F:
+       case 0x70:
+       case 0x71:
+       case 0x72:
+       case 0x73:
+       case 0x74:
+       case 0x75:
+       case 0x76:
+       case 0x77:
+       case 0x78:
+       case 0x79:
+       case 0x7A:
+       case 0x7B:
+       case 0x7C:
+       case 0x7D:
+       case 0x7E:
+       case 0x7F:
+               // Reserved, causes a data abort exception
+               return false;
+       case 0x80:
+               // Peripheral Control Modules
+               return writePCM8(value, physAddr);
+       case 0x90:
+               // System Control Modules
+               return writeSCM8(value, physAddr);
+       case 0xA0:
+               // Memory Control Registers
+               // Invalid to write to with bytes
+               return false;
+       case 0xB0:
+               // LCD/DMA Control Registers
+               return true;
+       case 0xC0:
+       case 0xC1:
+       case 0xC2:
+       case 0xC3:
+       case 0xC4:
+       case 0xC5:
+       case 0xC6:
+       case 0xC7:
+               MemoryBlockC0[physAddr & MemoryBlockMask] = value;
+               return true;
+       case 0xC8:
+       case 0xC9:
+       case 0xCA:
+       case 0xCB:
+       case 0xCC:
+       case 0xCD:
+       case 0xCE:
+       case 0xCF:
+               MemoryBlockC8[physAddr & MemoryBlockMask] = value;
+               return true;
+       default:
+               // just throw accesses to unmapped RAM away
+               return true;
+       }
+}
+
+bool Emulator::writePCM32(uint32_t value, uint32_t physAddr) {
+       return true;
+}
+
+bool Emulator::writeSCM32(uint32_t value, uint32_t physAddr) {
+       return true;
+}
+
+bool Emulator::writePhysical32(uint32_t value, uint32_t physAddr) {
+       uint8_t region = (physAddr >> 24) & 0xFF;
+
+       switch (region) {
+       case 0x00:
+               // Read-only
+               return false;
+               break;
+       case 0x20:
+       case 0x21:
+       case 0x22:
+       case 0x23:
+       case 0x24:
+       case 0x25:
+       case 0x26:
+       case 0x27:
+       case 0x28:
+       case 0x29:
+       case 0x2A:
+       case 0x2B:
+       case 0x2C:
+       case 0x2D:
+       case 0x2E:
+       case 0x2F:
+               // PCMCIA slot 0
+               return true;
+       case 0x30:
+       case 0x31:
+       case 0x32:
+       case 0x33:
+       case 0x34:
+       case 0x35:
+       case 0x36:
+       case 0x37:
+       case 0x38:
+       case 0x39:
+       case 0x3A:
+       case 0x3B:
+       case 0x3C:
+       case 0x3D:
+       case 0x3E:
+       case 0x3F:
+               // PCMCIA slot 1
+               return true;
+       case 0x40:
+       case 0x41:
+       case 0x42:
+       case 0x43:
+       case 0x44:
+       case 0x45:
+       case 0x46:
+       case 0x47:
+       case 0x48:
+       case 0x49:
+       case 0x4A:
+       case 0x4B:
+       case 0x4C:
+       case 0x4D:
+       case 0x4E:
+       case 0x4F:
+       case 0x50:
+       case 0x51:
+       case 0x52:
+       case 0x53:
+       case 0x54:
+       case 0x55:
+       case 0x56:
+       case 0x57:
+       case 0x58:
+       case 0x59:
+       case 0x5A:
+       case 0x5B:
+       case 0x5C:
+       case 0x5D:
+       case 0x5E:
+       case 0x5F:
+       case 0x60:
+       case 0x61:
+       case 0x62:
+       case 0x63:
+       case 0x64:
+       case 0x65:
+       case 0x66:
+       case 0x67:
+       case 0x68:
+       case 0x69:
+       case 0x6A:
+       case 0x6B:
+       case 0x6C:
+       case 0x6D:
+       case 0x6E:
+       case 0x6F:
+       case 0x70:
+       case 0x71:
+       case 0x72:
+       case 0x73:
+       case 0x74:
+       case 0x75:
+       case 0x76:
+       case 0x77:
+       case 0x78:
+       case 0x79:
+       case 0x7A:
+       case 0x7B:
+       case 0x7C:
+       case 0x7D:
+       case 0x7E:
+       case 0x7F:
+               // Reserved, causes a data abort exception
+               return false;
+       case 0x80:
+               // Peripheral Control Modules
+               return writePCM32(value, physAddr);
+       case 0x90:
+               // System Control Modules
+               return writeSCM32(value, physAddr);
+       case 0xA0:
+               // Memory Control Registers
+               memoryConfig.put_data(physAddr, value);
+               return false;
+       case 0xB0:
+               // LCD/DMA Control Registers
+               return true;
+       case 0xC0:
+       case 0xC1:
+       case 0xC2:
+       case 0xC3:
+       case 0xC4:
+       case 0xC5:
+       case 0xC6:
+       case 0xC7:
+               STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockC0);
+               return true;
+       case 0xC8:
+       case 0xC9:
+       case 0xCA:
+       case 0xCB:
+       case 0xCC:
+       case 0xCD:
+       case 0xCE:
+       case 0xCF:
+               STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockC8);
+               return true;
+       default:
+               // just throw accesses to unmapped RAM away
+               return true;
+       }
+}
+
+void Emulator::configure() {
+       if (configured) return;
+       configured = true;
+
+       srand(1000);
+
+       uart1.cpu = this;
+       uart2.cpu = this;
+       memset(&tc1, 0, sizeof(tc1));
+       memset(&tc2, 0, sizeof(tc1));
+       tc1.clockSpeed = CLOCK_SPEED;
+       tc2.clockSpeed = CLOCK_SPEED;
+
+       nextTickAt = TICK_INTERVAL;
+       tc1.nextTickAt = tc1.tickInterval();
+       tc2.nextTickAt = tc2.tickInterval();
+       rtc = getRTC();
+       memoryConfig.reset();
+
+       reset();
+}
+
+uint8_t *Emulator::getROMBuffer() {
+       return ROM;
+}
+size_t Emulator::getROMSize() {
+       return sizeof(ROM);
+}
+void Emulator::loadROM(uint8_t *osimg, size_t osimgSize, uint8_t *bootloader, size_t bootloaderSize) {
+       memcpy(ROM, bootloader, min(bootloaderSize, sizeof(ROM)));
+       memcpy(MemoryBlockC8, osimg, min(osimgSize, sizeof(MemoryBlockC8)));
+}
+
+void Emulator::executeUntil(int64_t cycles) {
+       if (!configured)
+               configure();
+
+       while (!asleep && passedCycles < cycles) {
+               if (passedCycles >= nextTickAt) {
+                       // increment RTCDIV
+                       if ((pwrsr & 0x3F) == 0x3F) {
+                               rtc++;
+                               pwrsr &= ~0x3F;
+                       } else {
+                               pwrsr++;
+                       }
+
+                       nextTickAt += TICK_INTERVAL;
+                       pendingInterrupts |= (1<<TINT);
+               }
+               if (tc1.tick(passedCycles))
+                       pendingInterrupts |= (1<<TC1OI);
+               if (tc2.tick(passedCycles))
+                       pendingInterrupts |= (1<<TC2OI);
+
+               if ((pendingInterrupts & interruptMask & FIQ_INTERRUPTS) != 0 && canAcceptFIQ()) {
+                       requestFIQ();
+                       halted = false;
+               }
+               if ((pendingInterrupts & interruptMask & IRQ_INTERRUPTS) != 0 && canAcceptIRQ()) {
+                       requestIRQ();
+                       halted = false;
+               }
+
+               // what's running?
+               if (halted) {
+                       // keep the clock moving
+                       // when does the next earliest thing happen?
+                       // this stops us from spinning needlessly
+                       int64_t nextEvent = nextTickAt;
+                       if (tc1.nextTickAt < nextEvent) nextEvent = tc1.nextTickAt;
+                       if (tc2.nextTickAt < nextEvent) nextEvent = tc2.nextTickAt;
+                       if (cycles < nextEvent) nextEvent = cycles;
+                       passedCycles = nextEvent;
+               } else {
+                       if (auto v = virtToPhys(getGPR(15) - 0xC); v.has_value() && instructionReady())
+                               debugPC(v.value());
+                       passedCycles += tick();
+
+#ifndef __EMSCRIPTEN__
+                       uint32_t new_pc = getGPR(15) - 0xC;
+                       if (_breakpoints.find(new_pc) != _breakpoints.end()) {
+                               log("⚠️ Breakpoint triggered at %08x!", new_pc);
+                               return;
+                       }
+#endif
+               }
+       }
+}
+
+
+const char *Emulator::identifyObjectCon(uint32_t ptr) {
+       if (ptr == readVirtualDebug(0x80000980, V32).value()) return "process";
+       if (ptr == readVirtualDebug(0x80000984, V32).value()) return "thread";
+       if (ptr == readVirtualDebug(0x80000988, V32).value()) return "chunk";
+//     if (ptr == readVirtualDebug(0x8000098C, V32).value()) return "semaphore";
+//     if (ptr == readVirtualDebug(0x80000990, V32).value()) return "mutex";
+       if (ptr == readVirtualDebug(0x80000994, V32).value()) return "logicaldevice";
+       if (ptr == readVirtualDebug(0x80000998, V32).value()) return "physicaldevice";
+       if (ptr == readVirtualDebug(0x8000099C, V32).value()) return "channel";
+       if (ptr == readVirtualDebug(0x800009A0, V32).value()) return "server";
+//     if (ptr == readVirtualDebug(0x800009A4, V32).value()) return "unk9A4"; // name always null
+       if (ptr == readVirtualDebug(0x800009AC, V32).value()) return "library";
+//     if (ptr == readVirtualDebug(0x800009B0, V32).value()) return "unk9B0"; // name always null
+//     if (ptr == readVirtualDebug(0x800009B4, V32).value()) return "unk9B4"; // name always null
+       return NULL;
+}
+
+void Emulator::fetchStr(uint32_t str, char *buf) {
+       if (str == 0) {
+               strcpy(buf, "<NULL>");
+               return;
+       }
+       int size = readVirtualDebug(str, V32).value();
+       for (int i = 0; i < size; i++) {
+               buf[i] = readVirtualDebug(str + 4 + i, V8).value();
+       }
+       buf[size] = 0;
+}
+
+void Emulator::fetchName(uint32_t obj, char *buf) {
+       fetchStr(readVirtualDebug(obj + 0x10, V32).value(), buf);
+}
+
+void Emulator::fetchProcessFilename(uint32_t obj, char *buf) {
+       fetchStr(readVirtualDebug(obj + 0x3C, V32).value(), buf);
+}
+
+void Emulator::debugPC(uint32_t pc) {
+       char objName[1000];
+       if (pc == 0x2CBC4) {
+               // CObjectCon::AddL()
+               uint32_t container = getGPR(0);
+               uint32_t obj = getGPR(1);
+               const char *wut = identifyObjectCon(container);
+               if (wut) {
+                       fetchName(obj, objName);
+                       if (strcmp(wut, "process") == 0) {
+                               char procName[1000];
+                               fetchProcessFilename(obj, procName);
+                               log("OBJS: added %s at %08x <%s> <%s>", wut, obj, objName, procName);
+                       } else {
+                               log("OBJS: added %s at %08x <%s>", wut, obj, objName);
+                       }
+               }
+       }
+
+       if (pc == 0x6D8) {
+               uint32_t virtAddr = getGPR(0);
+               uint32_t physAddr = getGPR(1);
+               uint32_t btIndex = getGPR(2);
+               uint32_t regionSize = getGPR(3);
+               log("KERNEL MMU SECTION: v:%08x p:%08x size:%08x idx:%02x",
+                       virtAddr, physAddr, regionSize, btIndex);
+       }
+       if (pc == 0x710) {
+               uint32_t virtAddr = getGPR(0);
+               uint32_t physAddr = getGPR(1);
+               uint32_t btIndex = getGPR(2);
+               uint32_t regionSize = getGPR(3);
+               uint32_t pageTableA = getGPR(4);
+               uint32_t pageTableB = getGPR(5);
+               log("KERNEL MMU PAGES: v:%08x p:%08x size:%08x idx:%02x tableA:%08x tableB:%08x",
+                       virtAddr, physAddr, regionSize, btIndex, pageTableA, pageTableB);
+       }
+
+       if (pc == 0x1576C) {
+               uint32_t rawEvent = getGPR(0);
+               uint32_t evtType = readVirtualDebug(rawEvent, V32).value_or(0);
+               uint32_t evtTick = readVirtualDebug(rawEvent + 4, V32).value_or(0);
+               uint32_t evtParamA = readVirtualDebug(rawEvent + 8, V32).value_or(0);
+               uint32_t evtParamB = readVirtualDebug(rawEvent + 0xC, V32).value_or(0);
+               const char *n = "???";
+               switch (evtType) {
+               case 0: n = "ENone"; break;
+               case 1: n = "EPointerMove"; break;
+               case 2: n = "EPointerSwitchOn"; break;
+               case 3: n = "EKeyDown"; break;
+               case 4: n = "EKeyUp"; break;
+               case 5: n = "ERedraw"; break;
+               case 6: n = "ESwitchOn"; break;
+               case 7: n = "EActive"; break;
+               case 8: n = "EInactive"; break;
+               case 9: n = "EUpdateModifiers"; break;
+               case 10: n = "EButton1Down"; break;
+               case 11: n = "EButton1Up"; break;
+               case 12: n = "EButton2Down"; break;
+               case 13: n = "EButton2Up"; break;
+               case 14: n = "EButton3Down"; break;
+               case 15: n = "EButton3Up"; break;
+               case 16: n = "ESwitchOff"; break;
+               }
+               log("EVENT %s: tick=%d params=%d,%d", n, evtTick, evtParamA, evtParamB);
+       }
+}
+
+
+const char *Emulator::getDeviceName() const { return "Series 5mx"; }
+int Emulator::getDigitiserWidth()  const { return 695; }
+int Emulator::getDigitiserHeight() const { return 520; }
+int Emulator::getLCDOffsetX()      const { return 45; }
+int Emulator::getLCDOffsetY()      const { return 5; }
+int Emulator::getLCDWidth()        const { return 640; }
+int Emulator::getLCDHeight()       const { return 480; }
+
+// TODO move this elsewhere
+static bool initRgbValues = false;
+static uint32_t rgbValues[16];
+
+void Emulator::readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) const {
+       if (!initRgbValues) {
+               initRgbValues = true;
+               for (int i = 0; i < 16; i++) {
+                       int r = (0x99 * i) / 15;
+                       int g = (0xAA * i) / 15;
+                       int b = (0x88 * i) / 15;
+                       rgbValues[15 - i] = r | (g << 8) | (b << 16) | 0xFF000000;
+               }
+       }
+
+       if ((lcdAddress >> 24) == 0xC0) {
+               const uint8_t *lcdBuf = &MemoryBlockC0[lcdAddress & MemoryBlockMask];
+               int width = 640, height = 480;
+
+               // fetch palette
+               int bpp = 1 << (lcdBuf[1] >> 4);
+               int ppb = 8 / bpp;
+               uint16_t palette[16];
+               for (int i = 0; i < 16; i++)
+                       palette[i] = lcdBuf[i*2] | ((lcdBuf[i*2+1] << 8) & 0xF00);
+
+               // build our image out
+               int lineWidth = (width * bpp) / 8;
+               for (int y = 0; y < height; y++) {
+                       int lineOffs = 0x20 + (lineWidth * y);
+                       for (int x = 0; x < width; x++) {
+                               uint8_t byte = lcdBuf[lineOffs + (x / ppb)];
+                               int shift = (x & (ppb - 1)) * bpp;
+                               int mask = (1 << bpp) - 1;
+                               int palIdx = (byte >> shift) & mask;
+                               int palValue = palette[palIdx];
+
+                               if (is32BitOutput) {
+                                       auto line = (uint32_t *)lines[y];
+                                       line[x] = rgbValues[palValue];
+                               } else {
+                                       palValue |= (palValue << 4);
+                                       lines[y][x] = palValue ^ 0xFF;
+                               }
+                       }
+               }
+       }
+}
+
+
+void Emulator::diffPorts(uint32_t oldval, uint32_t newval) {
+       uint32_t changes = oldval ^ newval;
+       if (changes & 1) log("PRT codec enable: %d", newval&1);
+       if (changes & 2) log("PRT audio amp enable: %d", newval&2);
+       if (changes & 4) log("PRT lcd power: %d", newval&4);
+       if (changes & 8) log("PRT etna door: %d", newval&8);
+       if (changes & 0x10) log("PRT sled: %d", newval&0x10);
+       if (changes & 0x20) log("PRT pump pwr2: %d", newval&0x20);
+       if (changes & 0x40) log("PRT pump pwr1: %d", newval&0x40);
+       if (changes & 0x80) log("PRT etna err: %d", newval&0x80);
+       if (changes & 0x100) log("PRT rs-232 rts: %d", newval&0x100);
+       if (changes & 0x200) log("PRT rs-232 dtr toggle: %d", newval&0x200);
+       if (changes & 0x400) log("PRT disable power led: %d", newval&0x400);
+       if (changes & 0x800) log("PRT enable uart1: %d", newval&0x800);
+       if (changes & 0x1000) log("PRT lcd backlight: %d", newval&0x1000);
+       if (changes & 0x2000) log("PRT enable uart0: %d", newval&0x2000);
+       if (changes & 0x4000) log("PRT dictaphone: %d", newval&0x4000);
+// PROM read process makes this super spammy in stdout
+//     if (changes & 0x10000) log("PRT EECS: %d", newval&0x10000);
+//     if (changes & 0x20000) log("PRT EECLK: %d", newval&0x20000);
+       if (changes & 0x40000) log("PRT contrast0: %d", newval&0x40000);
+       if (changes & 0x80000) log("PRT contrast1: %d", newval&0x80000);
+       if (changes & 0x100000) log("PRT contrast2: %d", newval&0x100000);
+       if (changes & 0x200000) log("PRT contrast3: %d", newval&0x200000);
+       if (changes & 0x400000) log("PRT case open: %d", newval&0x400000);
+       if (changes & 0x800000) log("PRT etna cf power: %d", newval&0x800000);
+}
+
+void Emulator::diffInterrupts(uint16_t oldval, uint16_t newval) {
+       uint16_t changes = oldval ^ newval;
+       if (changes & 1) log("INTCHG external=%d", newval & 1);
+       if (changes & 2) log("INTCHG lowbat=%d", newval & 2);
+       if (changes & 4) log("INTCHG watchdog=%d", newval & 4);
+       if (changes & 8) log("INTCHG mediachg=%d", newval & 8);
+       if (changes & 0x10) log("INTCHG codec=%d", newval & 0x10);
+       if (changes & 0x20) log("INTCHG ext1=%d", newval & 0x20);
+       if (changes & 0x40) log("INTCHG ext2=%d", newval & 0x40);
+       if (changes & 0x80) log("INTCHG ext3=%d", newval & 0x80);
+       if (changes & 0x100) log("INTCHG timer1=%d", newval & 0x100);
+       if (changes & 0x200) log("INTCHG timer2=%d", newval & 0x200);
+       if (changes & 0x400) log("INTCHG rtcmatch=%d", newval & 0x400);
+       if (changes & 0x800) log("INTCHG tick=%d", newval & 0x800);
+       if (changes & 0x1000) log("INTCHG uart1=%d", newval & 0x1000);
+       if (changes & 0x2000) log("INTCHG uart2=%d", newval & 0x2000);
+       if (changes & 0x4000) log("INTCHG lcd=%d", newval & 0x4000);
+       if (changes & 0x8000) log("INTCHG spi=%d", newval & 0x8000);
+}
+
+
+uint32_t Emulator::readKeyboard() {
+       if (kScan & 8) {
+               // Select one keyboard
+               return keyboardColumns[kScan & 7];
+       } else if (kScan == 0) {
+               // Report all columns combined
+               uint8_t val = 0;
+               for (int i = 0; i < 8; i++)
+                       val |= keyboardColumns[i];
+               return val;
+       } else {
+               return 0;
+       }
+}
+
+void Emulator::setKeyboardKey(EpocKey key, bool value) {
+       int idx = -1;
+#define KEY(column, bit) idx = (column << 8) | (1 << bit); break
+
+       switch ((int)key) {
+       case EStdKeyDictaphoneRecord: KEY(0, 6);
+       case '1':                     KEY(0, 5);
+       case '2':                     KEY(0, 4);
+       case '3':                     KEY(0, 3);
+       case '4':                     KEY(0, 2);
+       case '5':                     KEY(0, 1);
+       case '6':                     KEY(0, 0);
+
+       case EStdKeyDictaphonePlay:   KEY(1, 6);
+       case '7':                     KEY(1, 5);
+       case '8':                     KEY(1, 4);
+       case '9':                     KEY(1, 3);
+       case '0':                     KEY(1, 2);
+       case EStdKeyBackspace:        KEY(1, 1);
+       case EStdKeySingleQuote:      KEY(1, 0);
+
+       case EStdKeyEscape:           KEY(2, 6);
+       case 'Q':                     KEY(2, 5);
+       case 'W':                     KEY(2, 4);
+       case 'E':                     KEY(2, 3);
+       case 'R':                     KEY(2, 2);
+       case 'T':                     KEY(2, 1);
+       case 'Y':                     KEY(2, 0);
+
+       case EStdKeyMenu:             KEY(3, 6);
+       case 'U':                     KEY(3, 5);
+       case 'I':                     KEY(3, 4);
+       case 'O':                     KEY(3, 3);
+       case 'P':                     KEY(3, 2);
+       case 'L':                     KEY(3, 1);
+       case EStdKeyEnter:            KEY(3, 0);
+
+       case EStdKeyLeftCtrl:         KEY(4, 6);
+       case EStdKeyTab:              KEY(4, 5);
+       case 'A':                     KEY(4, 4);
+       case 'S':                     KEY(4, 3);
+       case 'D':                     KEY(4, 2);
+       case 'F':                     KEY(4, 1);
+       case 'G':                     KEY(4, 0);
+
+       case EStdKeyLeftFunc:         KEY(5, 6);
+       case 'H':                     KEY(5, 5);
+       case 'J':                     KEY(5, 4);
+       case 'K':                     KEY(5, 3);
+       case 'M':                     KEY(5, 2);
+       case EStdKeyFullStop:         KEY(5, 1);
+       case EStdKeyDownArrow:        KEY(5, 0);
+
+       case EStdKeyRightShift:       KEY(6, 6);
+       case 'Z':                     KEY(6, 5);
+       case 'X':                     KEY(6, 4);
+       case 'C':                     KEY(6, 3);
+       case 'V':                     KEY(6, 2);
+       case 'B':                     KEY(6, 1);
+       case 'N':                     KEY(6, 0);
+
+       case EStdKeyLeftShift:        KEY(7, 6);
+       case EStdKeyDictaphoneStop:   KEY(7, 5);
+       case EStdKeySpace:            KEY(7, 4);
+       case EStdKeyUpArrow:          KEY(7, 3);
+       case EStdKeyComma:            KEY(7, 2);
+       case EStdKeyLeftArrow:        KEY(7, 1);
+       case EStdKeyRightArrow:       KEY(7, 0);
+       }
+
+       if (idx >= 0) {
+               if (value)
+                       keyboardColumns[idx >> 8] |= (idx & 0xFF);
+               else
+                       keyboardColumns[idx >> 8] &= ~(idx & 0xFF);
+       }
+}
+
+void Emulator::updateTouchInput(int32_t x, int32_t y, bool down) {
+       pendingInterrupts &= ~(1 << EINT3);
+       if (down)
+               pendingInterrupts |= (1 << EINT3);
+       touchX = x;
+       touchY = y;
+}
+
+}
diff --git a/WindCore/sa1100.h b/WindCore/sa1100.h
new file mode 100644 (file)
index 0000000..d101985
--- /dev/null
@@ -0,0 +1,112 @@
+#ifndef SA1100_H
+#define SA1100_H
+
+#include "emubase.h"
+#include "sa1100_defs.h"
+#include "hardware.h"
+#include "sa1100/memory_conf.h"
+
+namespace SA1100 {
+
+// Relatively simple implementation of a StrongARM SA-1100 CPU
+//
+// The following resources are invaluable to determining how the SA-1100 operates:
+//
+// Technical documentation: https://courses.cs.washington.edu/courses/cse466/00au/sa1100dev.pdf
+// Address space layout: https://people.kth.se/~maguire/badge3/memorymap.html
+// ARMware emulator: https://github.com/Halajohn/ARMware
+// bookboot: https://web.archive.org/web/20060716045807/http://linux-7110.sourceforge.net/files/People/Klaasjan/netbook/
+
+class Emulator : public EmuBase {
+public:
+       // 16MB ROM file
+    uint8_t ROM[0x1000000];
+       // 16MB RAM/bank0, mapped at base addr 0xC0000000
+    uint8_t MemoryBlockC0[0x1000000];
+       // 16MB RAM/bank1, mapped at base addr 0xC8000000
+       // On the netBook, the OS.img minus the 256-byte wrapper is copied to this RAM
+       // See the bookboot README file (linked above)
+    uint8_t MemoryBlockC8[0x1000000];
+    enum { MemoryBlockMask = 0x0FFFFFF };
+
+private:
+    uint16_t pendingInterrupts = 0;
+    uint16_t interruptMask = 0;
+    uint32_t portValues = 0;
+    uint32_t portDirections = 0;
+    uint32_t pwrsr = 0x00002000; // cold start flag
+    uint32_t lcdControl = 0;
+    uint32_t lcdAddress = 0;
+    uint32_t rtc = 0;
+       uint16_t lastSSIRequest = 0;
+       int ssiReadCounter = 0;
+
+       uint32_t kScan = 0;
+       uint8_t keyboardColumns[8] = {0,0,0,0,0,0,0};
+       int32_t touchX = 0, touchY = 0;
+
+    Timer tc1, tc2;
+    UART uart1, uart2;
+       MemoryConf memoryConfig;
+
+       bool halted = false, asleep = false;
+
+    uint32_t getRTC();
+
+public:
+       MaybeU32 readPhysical(uint32_t physAddr, ValueSize valueSize) override;
+       bool writePhysical(uint32_t value, uint32_t physAddr, ValueSize valueSize) override;
+
+private:
+       uint8_t readPhysical8(uint32_t physAddr);
+       uint32_t readPhysical32(uint32_t physAddr);
+
+       bool writePhysical8(uint8_t value, uint32_t physAddr);
+       bool writePhysical32(uint32_t value, uint32_t physAddr);
+
+       uint8_t readPCM8(uint32_t physAddr);
+       uint32_t readPCM32(uint32_t physAddr);
+
+       uint8_t readSCM8(uint32_t physAddr);
+       uint32_t readSCM32(uint32_t physAddr);
+
+       bool writePCM8(uint8_t value, uint32_t physAddr);
+       bool writePCM32(uint32_t value, uint32_t physAddr);
+
+       bool writeSCM8(uint8_t value, uint32_t physAddr);
+       bool writeSCM32(uint32_t value, uint32_t physAddr);
+
+    bool configured = false;
+    void configure();
+
+    const char *identifyObjectCon(uint32_t ptr);
+    void fetchStr(uint32_t str, char *buf);
+    void fetchName(uint32_t obj, char *buf);
+    void fetchProcessFilename(uint32_t obj, char *buf);
+    void debugPC(uint32_t pc);
+       void diffPorts(uint32_t oldval, uint32_t newval);
+       void diffInterrupts(uint16_t oldval, uint16_t newval);
+       uint32_t readKeyboard();
+
+public:
+       Emulator();
+       uint8_t *getROMBuffer() override;
+       size_t getROMSize() override;
+       void loadROM(uint8_t *osimg, size_t osimgSize, uint8_t *bootloader, size_t bootloaderSize) override;
+       void executeUntil(int64_t cycles) override;
+       int32_t getClockSpeed() const override { return CLOCK_SPEED; }
+       const char *getDeviceName() const override;
+       int getDigitiserWidth() const override;
+       int getDigitiserHeight() const override;
+       int getLCDOffsetX() const override;
+       int getLCDOffsetY() const override;
+       int getLCDWidth() const override;
+       int getLCDHeight() const override;
+       void readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) const override;
+       void setKeyboardKey(EpocKey key, bool value) override;
+       void updateTouchInput(int32_t x, int32_t y, bool down) override;
+};
+
+} // namespace SA1100
+
+#endif // SA1100_H
diff --git a/WindCore/sa1100/memory_conf.cpp b/WindCore/sa1100/memory_conf.cpp
new file mode 100644 (file)
index 0000000..5d6af7a
--- /dev/null
@@ -0,0 +1,99 @@
+// ARMware - an ARM emulator
+// Copyright (C) <2007>  Wei Hu <wei.hu.tw@gmail.com>
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "memory_conf.h"
+
+namespace SA1100 {
+
+void MemoryConf::reset() {
+    // :NOTE: Wei 2004-Jan-18:
+    //
+    // Bits 0, 1, 16, 17 will reset to 0 when reset.
+    mMDCNFG &= ~((1 << 0) | (1 << 1) | (1 << 16) | (1 << 17));
+    
+    // :NOTE: Wei 2003-Dec-11:
+    //
+    // I assume all of the bits which have unknown values when reset have value 0.
+    mMDREFR = static_cast<uint32_t>((1 << 31) | (1 << 26) | (1 << 22) | (1 << 18));
+    
+    // :NOTE: Wei 2003-Dec-11:
+    //
+    // I assume all of the bits which have unknown values when reset have value 0.
+    mMDCAS00 = (1 << 10) | (1 << 8) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | 1;
+    mMDCAS01 = mMDCAS00;
+    mMDCAS02 = mMDCAS00;
+    mMDCAS20 = mMDCAS00;
+    mMDCAS21 = mMDCAS00;
+    mMDCAS22 = mMDCAS00;
+    
+    // :NOTE: Wei 2003-Dec-11:
+    //
+    // I assume all of the bits which have unknown values when reset have value 0.
+    //
+    // :SA-1110 Developer's Manual: p.141: Wei 2004-Jun-09:
+    //
+    // On iPaq H3600, RBW0 have to be 0 to indicate 32-bit 'ROM bus width'.
+    mMSC0 = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 12) | (1 << 11) | (1 << 10)
+      | (1 << 9) | (1 << 8) | (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3);
+    
+    // :NOTE: Wei 2003-Dec-11:
+    //
+    // I assume all of the bits which have unknown values when reset have value 0.
+    mSMCNFG = (1 << 15) | (1 << 14) | (1 << 6);
+}
+  
+uint32_t MemoryConf::get_data(uint32_t const address) const {
+    switch (address) {
+        case MDCNFG:  return mMDCNFG;
+        case MDCAS00: return mMDCAS00;
+        case MDCAS01: return mMDCAS01;
+        case MDCAS02: return mMDCAS02;
+        case MSC0:    return mMSC0;
+        case MSC1:    return mMSC1;
+        case MECR:    return mMECR;
+        case MDREFR:  return mMDREFR;
+        case MDCAS20: return mMDCAS20;
+        case MDCAS21: return mMDCAS21;
+        case MDCAS22: return mMDCAS22;
+        case MSC2:    return mMSC2;
+        case SMCNFG:  return mSMCNFG;
+            
+        default:
+            return 0;
+    }
+}
+  
+void MemoryConf::put_data(uint32_t const address, uint32_t const value) {
+    switch (address) {
+        case MDCNFG:  mMDCNFG = value; break;
+        case MDCAS00: mMDCAS00 = value; break;
+        case MDCAS01: mMDCAS01 = value; break;
+        case MDCAS02: mMDCAS02 = value; break;
+        case MSC0:    mMSC0 = value; break;
+        case MSC1:    mMSC1 = value; break;
+        case MECR:    mMECR = value; break;
+        case MDREFR:  mMDREFR = value; break;
+        case MDCAS20: mMDCAS20 = value; break;
+        case MDCAS21: mMDCAS21 = value; break;
+        case MDCAS22: mMDCAS22 = value; break;
+        case MSC2:    mMSC2 = value; break;
+        case SMCNFG:  mSMCNFG = value; break;
+        default:  break;
+    }
+}
+
+} // namespace SA1100
\ No newline at end of file
diff --git a/WindCore/sa1100/memory_conf.h b/WindCore/sa1100/memory_conf.h
new file mode 100644 (file)
index 0000000..5aa6a07
--- /dev/null
@@ -0,0 +1,93 @@
+// ARMware - an ARM emulator
+// Copyright (C) <2007>  Wei Hu <wei.hu.tw@gmail.com>
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef MEMORY_CONF_H
+#define MEMORY_CONF_H
+
+#include <stdint.h>
+
+namespace SA1100 {
+
+class MemoryConf {
+public:
+    MemoryConf() {
+        init_register();
+    }
+
+    void reset();
+
+    // :SA-1110 Developer's Manual: Wei 2003-Dec-11:
+    //
+    // These registers are readable and writable only as full words.
+    uint32_t get_data(uint32_t const address) const;
+
+    void put_data(uint32_t const address, uint32_t const value);
+private:
+    enum {
+        MDCNFG  = 0xA0000000,
+        MDCAS00 = 0xA0000004,
+        MDCAS01 = 0xA0000008,
+        MDCAS02 = 0xA000000C,
+        MSC0    = 0xA0000010,
+        MSC1    = 0xA0000014,
+        MECR    = 0xA0000018,
+        MDREFR  = 0xA000001C,
+        MDCAS20 = 0xA0000020,
+        MDCAS21 = 0xA0000024,
+        MDCAS22 = 0xA0000028,
+        MSC2    = 0xA000002C,
+        SMCNFG  = 0xA0000030
+    };
+
+    // Attribute
+
+    uint32_t mMDCNFG;  // DRAM Configuration register
+    uint32_t mMDCAS00; // CAS waveform rotate register 0 for DRAM bank pair 0/1
+    uint32_t mMDCAS01; // CAS waveform rotate register 1 for DRAM bank pair 0/1
+    uint32_t mMDCAS02; // CAS waveform rotate register 2 for DRAM bank pair 0/1
+    uint32_t mMSC0;    // Static memory control register 0
+    uint32_t mMSC1;    // Static memory control register 1
+    uint32_t mMECR;    // Expansion memory (PC-Card) bus configuration register
+    uint32_t mMDREFR;  // DRAM refresh control register
+    uint32_t mMDCAS20; // CAS waveform rotate register 0 for DRAM bank pair 2/3
+    uint32_t mMDCAS21; // CAS waveform rotate register 1 for DRAM bank pair 2/3
+    uint32_t mMDCAS22; // CAS waveform rotate register 2 for DRAM bank pair 2/3
+    uint32_t mMSC2;    // Static memory control register 2
+    uint32_t mSMCNFG;  // SMROM configuration register
+
+    // Operation
+
+    void init_register() {
+        mMDCNFG = 0;
+        mMDCAS00 = 0;
+        mMDCAS01 = 0;
+        mMDCAS02 = 0;
+        mMSC0 = 0;
+        mMSC1 = 0;
+        mMECR = 0;
+        mMDREFR = 0;
+        mMDCAS20 = 0;
+        mMDCAS21 = 0;
+        mMDCAS22 = 0;
+        mMSC2 = 0;
+        mSMCNFG = 0;
+    }
+};
+
+} // namespace SA1100
+
+#endif // MEMORY_CONF_H
diff --git a/WindCore/sa1100_defs.h b/WindCore/sa1100_defs.h
new file mode 100644 (file)
index 0000000..52533f9
--- /dev/null
@@ -0,0 +1,97 @@
+#ifndef SA1100_DEFS_H
+#define SA1100_DEFS_H
+
+#include <stdint.h>
+
+namespace SA1100 {
+enum {
+       CLOCK_SPEED = 0x9000*1000,
+       TICK_INTERVAL = CLOCK_SPEED / 64
+};
+
+enum Interrupt {
+       EXTFIQ = 0,  // FiqExternal
+       BLINT = 1,   // FiqBatLow
+       WEINT = 2,   // FiqWatchDog
+       MCINT = 3,   // FiqMediaChg
+       CSINT = 4,   // IrqCodec
+       EINT1 = 5,   // IrqExt1
+       EINT2 = 6,   // IrqExt2
+       EINT3 = 7,   // IrqExt3
+       TC1OI = 8,   // IrqTimer1
+       TC2OI = 9,   // IrqTimer2
+       RTCMI = 10,  // IrqRtcMatch
+       TINT = 11,   // IrqTick
+       UART1 = 12,  // IrqUart1
+       UART2 = 13,  // IrqUart1
+       LCDINT = 14, // IrqLcd
+       SSEOTI = 15,  // IrqSpi
+       FIQ_INTERRUPTS = 0x000F,
+       IRQ_INTERRUPTS = 0xFFF0
+};
+
+enum Register {
+       MEMCFG1 = 0,
+       MEMCFG2 = 4,
+       DRAM_CFG = 0x100,
+       LCDCTL = 0x200,
+       LCDST = 0x204,
+       LCD_DBAR1 = 0x210,
+       LCDT0 = 0x220,
+       LCDT1 = 0x224,
+       LCDT2 = 0x228,
+       PWRSR = 0x400,
+       PWRCNT = 0x404,
+       HALT = 0x408,
+       STBY = 0x40C,
+       BLEOI = 0x410,
+       MCEOI = 0x414,
+       TEOI = 0x418,
+       STFCLR = 0x41C,
+       E2EOI = 0x420,
+       INTSR = 0x500,
+       INTRSR = 0x504,
+       INTENS = 0x508,
+       INTENC = 0x50C,
+       INTTEST1 = 0x514,
+       INTTEST2 = 0x518,
+       PUMPCON = 0x900,
+       CODR = 0xA00,
+       CONFG = 0xA04,
+       COLFG = 0xA08,
+       COEOI = 0xA0C,
+       COTEST = 0xA10,
+       SSCR0 = 0xB00,
+       SSCR1 = 0xB04,
+       SSDR = 0xB0C,
+       SSSR = 0xB14,
+       TC1LOAD = 0xC00,
+       TC1VAL = 0xC04,
+       TC1CTRL = 0xC08,
+       TC1EOI = 0xC0C,
+       TC2LOAD = 0xC20,
+       TC2VAL = 0xC24,
+       TC2CTRL = 0xC28,
+       TC2EOI = 0xC2C,
+       BZCONT = 0xC40,
+       RTCDRL = 0xD00,
+       RTCDRU = 0xD04,
+       RTCMRL = 0xD08,
+       RTCMRU = 0xD0C,
+       RTCEOI = 0xD10,
+       PADR = 0xE00,
+       PBDR = 0xE04,
+       PCDR = 0xE08,
+       PDDR = 0xE0C,
+       PADDR = 0xE10,
+       PBDDR = 0xE14,
+       PCDDR = 0xE18,
+       PDDDR = 0xE1C,
+       PEDR = 0xE20,
+       PEDDR = 0xE24,
+       KSCAN = 0xE28,
+       LCDMUX = 0xE2C
+};
+}
+
+#endif // SA1100_DEFS_H
index 41bbe708a04151ed6844f5946707a5df43d1cd2d..adf5342e6b9588652ee5cf39080dcd79ff1a8b65 100644 (file)
@@ -377,7 +377,7 @@ uint8_t *Emulator::getROMBuffer() {
 size_t Emulator::getROMSize() {
        return sizeof(ROM);
 }
-void Emulator::loadROM(uint8_t *buffer, size_t size) {
+void Emulator::loadROM(uint8_t *buffer, size_t size, uint8_t*, size_t) {
        memcpy(ROM, buffer, min(size, sizeof(ROM)));
 }
 
index defe545ce5d270f8c3e44cc192cafb448d22c9c6..10cf24d215700a5dcb123b33527522cdff40484a 100644 (file)
@@ -64,7 +64,7 @@ public:
        Emulator();
        uint8_t *getROMBuffer() override;
        size_t getROMSize() override;
-       void loadROM(uint8_t *buffer, size_t size) override;
+       void loadROM(uint8_t *buffer, size_t size, uint8_t*, size_t) override;
        void executeUntil(int64_t cycles) override;
        int32_t getClockSpeed() const override { return CLOCK_SPEED; }
        const char *getDeviceName() const override;
index 7cc6ae703ad79c120bca59d3cd8bb2b7e5edf59e..06d7ce5c5df44e2296bc085f0488f7ead387ba7a 100644 (file)
@@ -1,5 +1,7 @@
 TEMPLATE = subdirs
 
+CONFIG += console
+
 SUBDIRS += \
     WindQt \
     WindCore
index 3d9b87d27f74e44791c1fa4092f0fe25c25bb394..97f4d85ac4d8c1963af53e7842a80e2436579889 100644 (file)
@@ -4,6 +4,7 @@
 #include <QMessageBox>
 #include "../WindCore/clps7111.h"
 #include "../WindCore/windermere.h"
+#include "../WindCore/sa1100.h"
 
 int main(int argc, char *argv[])
 {
@@ -17,6 +18,8 @@ int main(int argc, char *argv[])
                romFile = QFileDialog::getOpenFileName(nullptr, "Select a ROM");
        if (romFile.isNull()) return 0;
 
+       QString bootloader = "/Users/george/BootLoader.bin";
+       printf("Hello\n");
        // what do we have?
        QFile f(romFile);
        f.open(QFile::ReadOnly);
@@ -28,8 +31,15 @@ int main(int argc, char *argv[])
                return 0;
        }
 
+       // what do we have?
+       QFile f2(bootloader);
+       f2.open(QFile::ReadOnly);
+       auto bootloader_buffer = f2.readAll();
+       f2.close();
+
        EmuBase *emu = nullptr;
        uint8_t *romData = (uint8_t *)buffer.data();
+       uint8_t *bootloader_data = (uint8_t *)bootloader_buffer.data();
 
        // parse this ROM to learn what hardware it's for
        int variantFile = *((uint32_t *)&romData[0x80 + 0x4C]) & 0xFFFFFFF;
@@ -44,14 +54,14 @@ int main(int argc, char *argv[])
                        } else if (variant == 0x5040001) {
                                // Osaris ROM
                                emu = new CLPS7111::Emulator;
-                       } else {
-                               QMessageBox::critical(nullptr, "WindEmu", "Unrecognised ROM file!");
-                               return 0;
-                       }
+            } else {
+                // Netbook ROM
+                emu = new SA1100::Emulator;
+            }
                }
        }
 
-       emu->loadROM(romData, buffer.size());
+       emu->loadROM(romData, buffer.size(), bootloader_data, bootloader_buffer.size());
        MainWindow w(emu);
     w.show();
 
index deb706c8cd8e8a06f8df982925954c0b74838732..eeb38e1a109bb652e2d5622ca8594fced7229ff4 100644 (file)
@@ -209,7 +209,7 @@ void MainWindow::updateMemory()
                        if (!ok)
                                outLine.append('?');
                        else if (byte >= 0x20 && byte <= 0x7E)
-                               outLine.append(byte);
+                outLine.append((QChar)byte);
                        else
                                outLine.append('.');
                }