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;
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);
#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);
}
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!
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;
}
// 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);
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()]);
}
}
}
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);
}
}
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);
return 0;
if (L) {
+ printf("Reading coprocessor reg %d\n", CRn);
// read a value
uint32_t what = 0;
// 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) {
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() {
//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:
case 0x2E:
case 0x2F:
// PCMCIA slot 0
+ printf("Read8 PCMCIA0 %08x\n", physAddr);
return 0x0;
case 0x30:
case 0x31:
case 0x3E:
case 0x3F:
// PCMCIA slot 1
+ printf("Read8 PCMCIA1 %08x\n", physAddr);
return 0x0;
case 0x40:
case 0x41:
case 0x7E:
case 0x7F:
// Reserved, causes a data abort exception
+ printf("Read8 Reserved %08x\n", physAddr);
return 0x0;
case 0x80:
// Peripheral Control Modules
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:
case 0xC5:
case 0xC6:
case 0xC7:
- return MemoryBlockC0[physAddr & MemoryBlockMask];
+ return MemoryBlockC0[physAddr & memoryMask];
case 0xC8:
case 0xC9:
case 0xCA:
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;
}
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:
case 0x2F:
// PCMCIA slot 0
result = 0x0;
+ printf("Reading PCMCIA0 from %08x\n", physAddr);
break;
case 0x30:
case 0x31:
case 0x3F:
// PCMCIA slot 1
result = 0x0;
+ printf("Reading PCMCIA1 from %08x\n", physAddr);
break;
case 0x40:
case 0x41:
case 0x7F:
// Reserved, causes a data abort exception
result = 0x0;
+ printf("Reading Reserved from %08x\n", physAddr);
break;
case 0x80:
// Peripheral Control Modules
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:
case 0xC5:
case 0xC6:
case 0xC7:
- LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockC0);
+ LOAD_32LE(result, physAddr & memoryMask, MemoryBlockC0);
break;
case 0xC8:
case 0xC9:
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
}
}
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) {
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:
case 0x2E:
case 0x2F:
// PCMCIA slot 0
+ printf("Write8 PCMCIA0 %08x to %08x\n", value, physAddr);
return true;
case 0x30:
case 0x31:
case 0x3E:
case 0x3F:
// PCMCIA slot 1
+ printf("Write8 PCMCIA1 %08x to %08x\n", value, physAddr);
return true;
case 0x40:
case 0x41:
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
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:
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:
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:
case 0x2D:
case 0x2E:
case 0x2F:
+ printf("Write32 PCMCIA0 %08x to %08x\n", value, physAddr);
// PCMCIA slot 0
return true;
case 0x30:
case 0x3E:
case 0x3F:
// PCMCIA slot 1
+ printf("Write32 PCMCIA1 %08x to %08x\n", value, physAddr);
return true;
case 0x40:
case 0x41:
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
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:
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:
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;
}
}
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
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;
}
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;
}
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;
+ // }
+ // }
+ // }
+ // }
}