]> localhost Git - WindEmu.git/commitdiff
add skeleton support for the Etna chip, including PROM support
authorAsh Wolf <ninji@wuffs.org>
Fri, 20 Dec 2019 23:46:22 +0000 (23:46 +0000)
committerAsh Wolf <ninji@wuffs.org>
Fri, 20 Dec 2019 23:46:22 +0000 (23:46 +0000)
README.md
WindCore/WindCore.pro
WindCore/emu.cpp
WindCore/emu.h
WindCore/etna.cpp [new file with mode: 0644]
WindCore/etna.h [new file with mode: 0644]
WindCore/wind.cpp
WindCore/wind.h

index afe5db431e57f2ba1465c0364c13b13b17079dc5..50c353927a7250316e604364262c226b56bcdfde 100644 (file)
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ Hardware features:
 - ❌ Touch panel: not implemented
 - ❌ Audio: not implemented
 - ❌ Serial/UART support: stubbed out
-- ❌ ETNA (CompactFlash): not implemented
+- ❌ ETNA (PCMCIA/CompactFlash): mostly stubbed out
 - ✅ RTC: implemented
 - ❌ RTC alarm: not implemented
 - ❌ Standby mode: not implemented
index 23b825aa1c6d001e4c0a310144501c641d025668..74c4a850fc02e4862eeb49c01f882b0b88e7b65f 100644 (file)
@@ -22,6 +22,7 @@ DEFINES += QT_DEPRECATED_WARNINGS
 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
 
 SOURCES += \
+    etna.cpp \
     wind.cpp \
     isa-arm.c \
     decoder.c \
@@ -30,6 +31,7 @@ SOURCES += \
     emu.cpp
 
 HEADERS += \
+    etna.h \
     wind_hw.h \
     wind.h \
     macros.h \
index dd861cf525772c84a6261cf2a4009da54908b744..a37fb1448f91b93157f7c326631aecdae1b242f9 100644 (file)
@@ -108,7 +108,13 @@ void Emu::writeReg8(uint32_t reg, uint8_t value) {
                uint32_t oldPorts = portValues;
                portValues &= 0xFF00FFFF;
                portValues |= (uint32_t)value << 16;
-               diffPorts(oldPorts, portValues);
+        if ((portValues & 0x10000) && !(oldPorts & 0x10000))
+            etna.setPromBit0High();
+        else if (!(portValues & 0x10000) && (oldPorts & 0x10000))
+            etna.setPromBit0Low();
+        if ((portValues & 0x20000) && !(oldPorts & 0x20000))
+            etna.setPromBit1High();
+        diffPorts(oldPorts, portValues);
        } else if (reg == PCDR) {
                uint32_t oldPorts = portValues;
                portValues &= 0xFFFF00FF;
@@ -200,6 +206,8 @@ uint32_t Emu::readPhys8(uint32_t physAddress) {
     uint8_t region = (physAddress >> 24) & 0xF1;
        if (region == 0)
                result = ROM[physAddress & 0xFFFFFF];
+    else if (region == 0x20 && physAddress <= 0x20000FFF)
+        result = etna.readReg8(physAddress & 0xFFF);
     else if (region == 0x80 && physAddress <= 0x80000FFF)
                result = readReg8(physAddress & 0xFFF);
     else if (region == 0xC0)
@@ -244,6 +252,8 @@ uint32_t Emu::readPhys32(uint32_t physAddress) {
     uint8_t region = (physAddress >> 24) & 0xF1;
        if (region == 0)
                LOAD_32LE(result, physAddress & 0xFFFFFF, ROM);
+    else if (region == 0x20 && physAddress <= 0x20000FFF)
+        result = etna.readReg32(physAddress & 0xFFF);
     else if (region == 0x80 && physAddress <= 0x80000FFF)
                result = readReg32(physAddress & 0xFFF);
     else if (region == 0xC0)
@@ -277,8 +287,10 @@ void Emu::writePhys8(uint32_t physAddress, uint8_t value) {
     else if (region == 0xD1)
         MemoryBlockD1[physAddress & MemoryBlockMask] = (uint8_t)value;
 #endif
+    else if (region == 0x20 && physAddress <= 0x20000FFF)
+        etna.writeReg8(physAddress & 0xFFF, value);
     else if (region == 0x80 && physAddress <= 0x80000FFF)
-               writeReg8(physAddress & 0xFFF, value);
+        writeReg8(physAddress & 0xFFF, value);
 //     else
 //             printf("<%08x> unmapped write8 addr p:%08x :: %02x\n", cpu.gprs[ARM_PC] - 4, physAddress, value);
 }
@@ -313,6 +325,8 @@ void Emu::writePhys32(uint32_t physAddress, uint32_t value) {
     else if (region == 0xD1)
         STORE_32LE(value, physAddress & MemoryBlockMask, MemoryBlockD1);
 #endif
+    else if (region == 0x20 && physAddress <= 0x20000FFF)
+        etna.writeReg32(physAddress & 0xFFF, value);
     else if (region == 0x80 && physAddress <= 0x80000FFF)
                writeReg32(physAddress & 0xFFF, value);
 //     else
index 5a96df6ea876befc1f6551d1a6ff77fc174577d9..0962fc7f6874b5bb15b88bba4753883742d34bb8 100644 (file)
@@ -1,6 +1,7 @@
 #pragma once
 #include "arm.h"
 #include "wind_hw.h"
+#include "etna.h"
 #include <unordered_set>
 
 class Emu {
@@ -27,6 +28,7 @@ class Emu {
     int64_t nextTickAt = 0;
     Timer tc1, tc2;
     UART uart1, uart2;
+    Etna etna;
     bool asleep = false;
 
     std::unordered_set<uint32_t> _breakpoints;
diff --git a/WindCore/etna.cpp b/WindCore/etna.cpp
new file mode 100644 (file)
index 0000000..5e15d2f
--- /dev/null
@@ -0,0 +1,145 @@
+#include "etna.h"
+#include <stdio.h>
+#include <string.h>
+
+enum EtnaReg {
+    regUnk0 = 0,
+    regUnk1 = 1,
+    regUartIntStatus = 2,
+    regUartIntMask = 3,
+    regUartBaudRateLo8 = 4,
+    regUartBaudRateHi4 = 5,
+    regPcCdIntStatus = 6,
+    regPcCdIntMask = 7,
+    regIntClear = 8,
+    regSktVarA0 = 9,
+    regSktVarA1 = 0xA,
+    regSktCtrl = 0xB,
+    regWake1 = 0xC,
+    regSktVarB0 = 0xD,
+    regSktVarB1 = 0xE,
+    regWake2 = 0xF
+};
+
+static const char *nameReg(uint32_t reg) {
+    switch (reg) {
+    case regUnk0: return "unk0";
+    case regUnk1: return "unk1";
+    case regUartIntStatus: return "UartIntStatus";
+    case regUartIntMask: return "UartIntMask";
+    case regUartBaudRateLo8: return "UartBaudRateLo8";
+    case regUartBaudRateHi4: return "UartBaudRateHi4";
+    case regPcCdIntStatus: return "PcCdIntStatus";
+    case regPcCdIntMask: return "PcCdIntMask";
+    case regIntClear: return "IntClear";
+    case regSktVarA0: return "SktVarA0";
+    case regSktVarA1: return "SktVarA1";
+    case regSktCtrl: return "SktCtrl";
+    case regWake1: return "wake1";
+    case regSktVarB0: return "SktVarB0";
+    case regSktVarB1: return "SktVarB1";
+    case regWake2: return "wake2";
+    }
+    return nullptr;
+}
+
+
+Etna::Etna() {
+    for (int i = 0; i < 0x80; i++)
+        prom[i] = 0;
+
+    // some basic stuff to begin with
+    // set up the Psion's unique ID
+    prom[0x1B] = 0xDE;
+    prom[0x1A] = 0xAD;
+    prom[0x19] = 0xBE;
+    prom[0x18] = 0xEF;
+
+    // give ourselves a neat custom device name
+    const char *key = "PSIONPSIONPSION";
+    const char *name = "WindEmu!";
+    prom[0x28] = strlen(name);
+    if (prom[0x28] > 15)
+        prom[0x28] = 15;
+    for (int i = 0; i < prom[0x28]; i++)
+        prom[0x29 + i] = name[i] ^ key[i];
+
+    // calculate the checksum
+    uint8_t chk = 0;
+    for (int i = 0; i < 0x7F; i++)
+        chk ^= prom[i];
+
+    // EPOC is expecting 66
+    prom[0x7F] = chk ^ 66;
+}
+
+
+uint32_t Etna::readReg8(uint32_t reg)
+{
+    if (!promReadActive)
+        printf("ETNA readReg8: reg=%s\n", nameReg(reg));
+    switch (reg) {
+    case regSktVarA0: return 0; // will store some status flags
+    case regSktVarA1: return 0; // will store some more status flags
+    case regWake1: return wake1;
+    case regWake2: return wake2;
+    }
+    return 0xFF;
+}
+
+uint32_t Etna::readReg32(uint32_t reg)
+{
+    // may be able to remove this, p. sure Etna is byte addressing only
+    printf("ETNA readReg32: reg=%x\n", reg);
+    return 0xFFFFFFFF;
+}
+
+void Etna::writeReg8(uint32_t reg, uint8_t value)
+{
+    if (!promReadActive)
+        printf("ETNA writeReg8: reg=%s value=%02x\n", nameReg(reg), value);
+    switch (reg) {
+    case regWake1: wake1 = value; break;
+    case regWake2: wake2 = value; break;
+    }
+}
+
+void Etna::writeReg32(uint32_t reg, uint32_t value)
+{
+    // may be able to remove this, p. sure Etna is byte addressing only
+    printf("ETNA writeReg32: reg=%x value=%08x\n", reg, value);
+}
+
+void Etna::setPromBit0High()
+{
+    // begin reading a word
+    promReadAddress = 0;
+    promReadValue = 0;
+    promAddressBitsReceived = 0;
+    promReadActive = true;
+}
+
+void Etna::setPromBit0Low()
+{
+    promReadActive = false;
+}
+
+void Etna::setPromBit1High()
+{
+    if (promAddressBitsReceived < 10) {
+        // we're still receiving the address
+        promReadAddress <<= 1;
+        promReadAddress |= ((wake1 & 4) >> 2);
+        if (++promAddressBitsReceived == 10) {
+            // we can fetch the value now
+            int addressInBytes = promReadAddress * 2;
+            addressInBytes %= sizeof(prom);
+            promReadValue = prom[addressInBytes] | (prom[addressInBytes + 1] << 8);
+        }
+    } else {
+        wake1 &= ~8;
+        if (promReadValue & 0x8000)
+            wake1 |= 8;
+        promReadValue <<= 1;
+    }
+}
diff --git a/WindCore/etna.h b/WindCore/etna.h
new file mode 100644 (file)
index 0000000..7e83a4f
--- /dev/null
@@ -0,0 +1,24 @@
+#pragma once
+#include <stdint.h>
+
+class Etna {
+    uint8_t prom[0x80] = {};
+    uint16_t promReadAddress = 0, promReadValue = 0;
+    bool promReadActive = false;
+    int promAddressBitsReceived = 0;
+
+    uint8_t wake1 = 0, wake2 = 0;
+
+public:
+    Etna();
+
+    uint32_t readReg8(uint32_t reg);
+    uint32_t readReg32(uint32_t reg);
+    void writeReg8(uint32_t reg, uint8_t value);
+    void writeReg32(uint32_t reg, uint32_t value);
+
+    // PROM
+    void setPromBit0High(); // port B, bit 0
+    void setPromBit0Low(); // port B, bit 0
+    void setPromBit1High(); // port B, bit 1
+};
index d8cbbe309c161d851c88ac38c4ef5c5c476b0aa0..851e4f23e57cbbf80dd2d14bc3df8d4db5f305b8 100644 (file)
@@ -18,8 +18,9 @@ void diffPorts(uint32_t oldval, uint32_t newval) {
        if (changes & 0x1000) printf("PRT lcd backlight: %d\n", newval&0x1000);
        if (changes & 0x2000) printf("PRT enable uart0: %d\n", newval&0x2000);
        if (changes & 0x4000) printf("PRT dictaphone: %d\n", newval&0x4000);
-       if (changes & 0x10000) printf("PRT EECS: %d\n", newval&0x10000);
-       if (changes & 0x20000) printf("PRT EECLK: %d\n", newval&0x20000);
+// PROM read process makes this super spammy in stdout
+//     if (changes & 0x10000) printf("PRT EECS: %d\n", newval&0x10000);
+//     if (changes & 0x20000) printf("PRT EECLK: %d\n", newval&0x20000);
        if (changes & 0x40000) printf("PRT contrast0: %d\n", newval&0x40000);
        if (changes & 0x80000) printf("PRT contrast1: %d\n", newval&0x80000);
        if (changes & 0x100000) printf("PRT contrast2: %d\n", newval&0x100000);
index 18fe7ab089bfb11a11d4f292c93a73015658383c..593d87d46835eafe10c14d9aa31b7fd2caf45bbc 100644 (file)
@@ -1,5 +1,5 @@
-#include <stdint.h>
 #pragma once
+#include <stdint.h>
 
 const int CLOCK_SPEED = 0x9000*1000;
 const int TICK_INTERVAL = CLOCK_SPEED / 64;