From 36f3daff0fc1222b839b9126827d11f130517515 Mon Sep 17 00:00:00 2001 From: google0101-ryan Date: Sun, 28 Jan 2024 19:56:54 -0500 Subject: [PATCH] Started work on IOP BIOS disassembly --- BIOS/README.md | 11 + BIOS/iop/btconf.c | 24 ++ BIOS/iop/btconf.h | 3 + BIOS/iop/intrman/global.h | 7 + BIOS/iop/iopboot.c | 131 +++++++ BIOS/iop/loadcore/global.h | 18 + BIOS/iop/romdir.c | 82 +++++ BIOS/iop/romdir.h | 20 + BIOS/iop/sifman/exports.c | 102 ++++++ BIOS/iop/sifman/global.h | 3 + BIOS/iop/sifman/sifman.c | 25 ++ BIOS/iop/string.h | 64 ++++ BIOS/iop/types.h | 11 + BIOS/prime.cpp | 43 +++ src/emu/System.cpp | 6 +- src/emu/cpu/ee/EEJit.cpp | 153 +++++++- src/emu/cpu/ee/EEJit.h | 6 +- src/emu/cpu/ee/EmotionEngine.cpp | 82 +---- src/emu/cpu/ee/EmotionEngine.h | 6 +- src/emu/cpu/ee/x64/EEJitx64.cpp | 114 ++++-- src/emu/sched/scheduler.cpp | 2 - util/.gitignore | 1 + util/DMACMAN | Bin 14069 -> 0 bytes util/EESYNC | Bin 1177 -> 0 bytes util/LOADCORE | Bin 9597 -> 0 bytes util/SIFMAN | Bin 5529 -> 0 bytes util/dump | 601 +++++++++++++++++++++++++++++++ util/romdumper | Bin 17176 -> 17176 bytes util/romdumper.cpp | 2 +- 29 files changed, 1416 insertions(+), 101 deletions(-) create mode 100644 BIOS/README.md create mode 100644 BIOS/iop/btconf.c create mode 100644 BIOS/iop/btconf.h create mode 100644 BIOS/iop/intrman/global.h create mode 100644 BIOS/iop/iopboot.c create mode 100644 BIOS/iop/loadcore/global.h create mode 100644 BIOS/iop/romdir.c create mode 100644 BIOS/iop/romdir.h create mode 100644 BIOS/iop/sifman/exports.c create mode 100644 BIOS/iop/sifman/global.h create mode 100644 BIOS/iop/sifman/sifman.c create mode 100644 BIOS/iop/string.h create mode 100644 BIOS/iop/types.h create mode 100644 BIOS/prime.cpp create mode 100644 util/.gitignore delete mode 100644 util/DMACMAN delete mode 100644 util/EESYNC delete mode 100644 util/LOADCORE delete mode 100644 util/SIFMAN create mode 100644 util/dump diff --git a/BIOS/README.md b/BIOS/README.md new file mode 100644 index 0000000..83ea5ae --- /dev/null +++ b/BIOS/README.md @@ -0,0 +1,11 @@ +# WHAT IS THIS? + +This is my attempt at reverse engineering the PS2 BIOS in psuedo-C + +# WHY? + +To better understand how the PS2's BIOS functions, and to aid and abet bug hunting + +# CAN I COMPILE THIS? + +As of right now? No. But maybe someday in the future... \ No newline at end of file diff --git a/BIOS/iop/btconf.c b/BIOS/iop/btconf.c new file mode 100644 index 0000000..d61388f --- /dev/null +++ b/BIOS/iop/btconf.c @@ -0,0 +1,24 @@ +#include "btconf.h" + +int ParseLoadAddr(char** str) +{ + char* buf = *str; + int ret = 0; + while ('/' < *buf) + { + int i; + char c = *buf; + buf++; + if (c <= '9') + i = c - '0'; + else if (c <= 'f') + i = c - 'a'; + else if (c <= 'F') + i = c - 'A'; + + ret = ret * 16 + i; + } + + *str = buf; + return ret; +} \ No newline at end of file diff --git a/BIOS/iop/btconf.h b/BIOS/iop/btconf.h new file mode 100644 index 0000000..03dda8f --- /dev/null +++ b/BIOS/iop/btconf.h @@ -0,0 +1,3 @@ +#pragma once + +int ParseLoadAddr(char** str); \ No newline at end of file diff --git a/BIOS/iop/intrman/global.h b/BIOS/iop/intrman/global.h new file mode 100644 index 0000000..2e119d7 --- /dev/null +++ b/BIOS/iop/intrman/global.h @@ -0,0 +1,7 @@ +#pragma once + +extern int CpuSuspendIntr(int* state); +extern int RegisterIntrHandler(int irq, int mode, int (*func)(void*), void* arg); +extern int EnableIntr(int irq); +extern int CpuResumeIntr(int state); +extern int CpuEnableIntr(); \ No newline at end of file diff --git a/BIOS/iop/iopboot.c b/BIOS/iop/iopboot.c new file mode 100644 index 0000000..214723e --- /dev/null +++ b/BIOS/iop/iopboot.c @@ -0,0 +1,131 @@ +#include "types.h" +#include "string.h" +#include "romdir.h" +#include "btconf.h" + +IopBootInfo* gBootInfo = (IopBootInfo*)0x20000; + +/** + * @brief The entrypoint of the IOPBOOT module, which bootstraps the IOP kernel + * @param ram_size The size of the IOP's RAM, in megabytes. + * @param boot_info This gets used to load IOPBTCONFx, where x is boot_info's value + * @param udnl_cmd The command line, usually NULL on retail PS2s +*/ +void _entry(int ram_size, int boot_info, char* udnl_cmd, int unk) +{ + // Disable interrupts + asm volatile("mtc0 $0,$12"); + + // The IOP kernel can only access a maximum of 2MBs of RAM + if (ram_size > 2) + ram_size = 2; + + // In the real IOPBOOT, the stack pointer is set to the end of RAM here + + // This structure is used to pass around some boot info + gBootInfo->cmd_ptr = 0; + gBootInfo->structEnd = 0x20020; + gBootInfo->ram_size = ram_size; + gBootInfo->boot_info = boot_info; + if (udnl_cmd) + { + // Copy the command line to just past the structure + gBootInfo->cmd_ptr = ((char*)gBootInfo+sizeof(IopBootInfo)); + strcpy(((char*)gBootInfo+sizeof(IopBootInfo)), udnl_cmd); + size_t cmdlen = strlen(udnl_cmd); + // 8 byte align the struct's end + gBootInfo->structEnd += ((cmdlen + 8) & 0xfffffffc); + } + + RomDir romDir; + if (!SearchForRomDir((void*)0xbfc00000, (void*)0xbfc10000, &romDir)) + { + // If we can't find any ROMDIR entries, just crash + do {} while(1); + } + + // One of IOPBTCONF entries + char configName[48]; + strcpy(configName, "IOPBTCONF"); + configName[9] = boot_info + '0'; // This means we load IOPBTCONFx, where x is boot_info + RomDirEnt btconf; + if (!FindRomDirEnt(&romDir, configName, &btconf)) + { + // If IOPBTCONFx doesn't exist, load IOPBTCONF + configName[9] = 0; + strcpy(configName, "IOPBTCONF"); + if (!FindRomDirEnt(&romDir, configName, &btconf)) + do {} while (1); + } + + int moduleCount = 0; + + // Now we parse this list, which tells us which modules to load + // The name ptr is 10 bytes, followed by 2 bytes for ext_info_size + // At 0xC is the file size, so we can dereference that and add it to the file ptr to get the end + char* end = btconf.filePtr + *(unsigned int*)((char*)btconf.name + 0xc); + char* buf = (char*)btconf.filePtr; + while (buf < end) + { + // skip whitespace + while (*buf < ' ') buf++; + // New entry, non-whitespace + moduleCount++; + } + gBootInfo->numModules = moduleCount; + int moduleLoadAddr = 0; + + buf = (char*)btconf.filePtr; + + // Following the IopBootInfo struct is a list of addresses to be loaded + unsigned int* endOfStructPtr = (unsigned int*)gBootInfo->structEnd; + RomDirEnt toLoad; + + while (buf < end) + { + char c = *buf; + // '@' characters are used to specify the module load offset + if (c == '@') + { + buf++; + moduleLoadAddr = ParseLoadAddr(&buf); + } + // Either used to include other BTCONF files + // Or used to call a function somewhere in memory + else if (c == '!') + { + // BUG: The PS2 BIOS doesn't support !includes, at least on scph10000 + if (strncmp(buf, "!addr", 6) == 0) + { + buf += 6; + *endOfStructPtr = ParseLoadAddr(&buf) * 4 + 1; + endOfStructPtr++; + *endOfStructPtr = 0; + } + } + else if (c != '#') + { + // Find the module to be loaded + void* ret = FindRomDirEnt(&romDir, buf, &toLoad); + if (!ret) + return 1; + *endOfStructPtr = toLoad.filePtr; + endOfStructPtr++; + *endOfStructPtr = 0; + } + if (buf > end) break; + // Skip trailing whitespace + do + { + if (*buf < ' ') break; + buf++; + } while (buf < end); + do + { + if (0x1f < *buf) break; + buf++; + } while (buf < end); + } + // Now we've got a list of addresses following IopBootInfo, terminated with a 0 word + // Load them, in order +} \ No newline at end of file diff --git a/BIOS/iop/loadcore/global.h b/BIOS/iop/loadcore/global.h new file mode 100644 index 0000000..cb16560 --- /dev/null +++ b/BIOS/iop/loadcore/global.h @@ -0,0 +1,18 @@ +#pragma once + +typedef struct ExportTable_t +{ + unsigned int magic; + struct ExportTable_t* next; + unsigned short version; + unsigned short mode; + char name[8]; + void* exports[]; +} ExportTable_t; + +void RegisterLibraryEntries(ExportTable_t* table); + +static void ExportStub() +{ + // Do nothing export stub for placeholder slots +} \ No newline at end of file diff --git a/BIOS/iop/romdir.c b/BIOS/iop/romdir.c new file mode 100644 index 0000000..4bdd5a6 --- /dev/null +++ b/BIOS/iop/romdir.c @@ -0,0 +1,82 @@ +#include "romdir.h" + +RomDir *SearchForRomDir(void *start, void *end, RomDir *out) +{ + if (start >= end) + return NULL; + + unsigned int* offsPtr = (unsigned int*)((char*)start + 0x1c); // Offset from 'RESET' string to ROMDIR offset + unsigned int* magicPtr = (unsigned int*)(start); + + do + { + if (*magicPtr == 0x45534552) + { + out->searchBegin = start; + out->firstEntry = magicPtr; + out->romDirSize = *offsPtr; + return out; + } + + offsPtr++; + magicPtr++; + } while (magicPtr < end); + + out->searchBegin = NULL; + return NULL; +} + +/** + * @brief The actual structure found within the ROM +*/ +typedef struct +{ + char name[10]; + unsigned short ext_info_size; + unsigned int file_size; +} RomEnt; + +/** + * @brief This finds a ROMDIR entry with the name `name` + * @param dir Pointer to the ROM directory info structure + * @param name The name of the entry (E.X. IOPBTCONF) + * @param out Output info on the ROM entry +*/ +RomDirEnt *FindRomDirEnt(RomDir *dir, char *name, RomDirEnt *out) +{ + RomEnt* entry = (RomEnt*)dir->firstEntry; + char fname[12]; + for (int i = 0; i < 12; i++) + { + if (*name < '!') break; + fname[i] = *name; + name++; + } + + unsigned int fileOffs = 0; + unsigned int infoOffs = 0; + while (entry->name[0]) + { + if (*(unsigned int*)&fname[0] == *(unsigned int*)&entry->name[0] + && *(unsigned int*)&fname[4] == *(unsigned int*)&entry->name[4] + && fname[8] == entry->name[8] + && fname[9] == entry->name[9]) + { + out->name = entry->name; + out->extInfo = NULL; + out->filePtr = (void*)((char*)dir->searchBegin + fileOffs); + if (entry->ext_info_size) + { + out->extInfo = (void*)((char*)dir->searchBegin + infoOffs); + } + + return out; + } + + fileOffs += entry->file_size; + infoOffs += entry->ext_info_size; + entry++; + } + + return NULL; +} diff --git a/BIOS/iop/romdir.h b/BIOS/iop/romdir.h new file mode 100644 index 0000000..ad35a7d --- /dev/null +++ b/BIOS/iop/romdir.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +typedef struct +{ + void* searchBegin; // The beginning of the search range (TODO: why does the BIOS save this?) + void* firstEntry; + size_t romDirSize; +} RomDir; + +typedef struct +{ + char* name; + void* filePtr; + void* extInfo; +} RomDirEnt; + +RomDir* SearchForRomDir(void* start, void* end, RomDir* out); +RomDirEnt* FindRomDirEnt(RomDir* dir, char* name, RomDirEnt* out); \ No newline at end of file diff --git a/BIOS/iop/sifman/exports.c b/BIOS/iop/sifman/exports.c new file mode 100644 index 0000000..2fddd23 --- /dev/null +++ b/BIOS/iop/sifman/exports.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include + +typedef volatile uint32_t vu32; + +#define DMA_DPCR (*(vu32*)0xbf8010f0) +#define DMA_DPCR2 (*(vu32*)0xbf801570) +#define DMA_SIF0_CTRL (*(vu32*)0xbf801528) +#define DMA_SIF1_CTRL (*(vu32*)0xbf801538) +#define DMA_SIF1_BCR (*(vu32*)0xbf801534) +#define DMA_SIF2_CTRL (*(vu32*)0xbf8010A8) +#define SIF_SMCOM (*(vu32*)0xbd000010) +#define SIF_MSFLG (*(vu32*)0xbd000020) +#define SIF_SMFLG (*(vu32*)0xbd000030) +#define SIF_CTRL (*(vu32*)0xbd000040) + +bool sifCmdInited = false; +bool sif2Inited = false; + +void sifInitSif2() +{ + if (!sif2Inited) + { + DMA_SIF2_CTRL = 0; + DMA_DPCR |= 0x800; + sif2Inited = true; + } +} + +uint32_t transferBufOffs = 0; +uint32_t* transferBufBase; +uint32_t curTransferId; + +int HandleInterrupt(void* arg) +{ + +} + +void InitInterrupts() +{ + int int_state; + + transferBufOffs = 0; + transferBufBase = (uint32_t*)0xf8c; // TODO: This probably gets patched + CpuSuspendIntr(&int_state); + RegisterIntrHandler(0x2a, 1, HandleInterrupt, &curTransferId); + EnableIntr(0x2a); + CpuEnableIntr(int_state); +} + +void SetupSIF1() +{ + if (!(SIF_CTRL & 0x40)) + SIF_CTRL = 0x40; + DMA_SIF1_BCR = 0x20; + // Sets up the mode and stuff, but leaves the channel disabled + DMA_SIF1_CTRL = 0x41000300; +} + +void sifCmdInit() +{ + if (!sifCmdInited) + { + int int_state; + + // This sets SIF0 and SIF1 to max priority + DMA_DPCR2 = DMA_DPCR2 | 0x8800; + DMA_SIF0_CTRL = 0; + DMA_SIF1_CTRL = 0; + + // Setup SIF2. Afaik, this is exclusively used for PSX mode + sifInitSif2(); + + InitInterrupts(); + + CpuSuspendIntr(&int_state); + CpuEnableIntr(); + // Here, we poll MSFLG and check for bit 0x10000, which means the EE DMAC is ready + uint32_t msflg; + while (!(msflg & 0x10000)) + { + int nested_int_disable; + CpuSuspendIntr(&nested_int_disable); + msflg = SIF_MSFLG; + CpuResumeIntr(nested_int_disable); + } + CpuResumeIntr(int_state); + + SetupSIF1(); + + // TODO: This might get patched on module load + // Tell the EE where our recv buffer is + SIF_SMCOM = 0; + + // Let the EE know that SIF has been initialized + SIF_SMFLG = 0x10000; + + sifCmdInited = true; + } +} \ No newline at end of file diff --git a/BIOS/iop/sifman/global.h b/BIOS/iop/sifman/global.h new file mode 100644 index 0000000..8e3641f --- /dev/null +++ b/BIOS/iop/sifman/global.h @@ -0,0 +1,3 @@ +#pragma once + +extern void sifCmdInit(); \ No newline at end of file diff --git a/BIOS/iop/sifman/sifman.c b/BIOS/iop/sifman/sifman.c new file mode 100644 index 0000000..683b60d --- /dev/null +++ b/BIOS/iop/sifman/sifman.c @@ -0,0 +1,25 @@ +#include +#include +#include + +ExportTable_t table = +{ + .magic = 0x41C00000, + .next = NULL, + .version = 0x101, + .mode = 0, + .name = "sifman", + .exports = { + ExportStub, + ExportStub, + ExportStub, + ExportStub, + sifCmdInit, + } +}; + +int main(int argc, char** argv) +{ + RegisterLibraryEntries(&table); + return 0; +} \ No newline at end of file diff --git a/BIOS/iop/string.h b/BIOS/iop/string.h new file mode 100644 index 0000000..2c3d709 --- /dev/null +++ b/BIOS/iop/string.h @@ -0,0 +1,64 @@ +#pragma once + +#include + +char* strcpy(char* dst, char* src) +{ + char c; + char* curDst = dst; + char* curSrc = src; + + if (dst && src) + { + c = *curSrc; + while (c) + { + c = *curSrc; + *curDst = c; + curSrc++; + curDst++; + } + return src; + } + return NULL; +} + +size_t strlen(char* str) +{ + if (!str) + return NULL; + + size_t s; + while (*str++) + s++; + + return s; +} + +int strncmp(char* s1, char* s2, int len) +{ + int ret = 0; + if (!s1 || !s2) + { + if (s1 != s2 && (ret = -1, s1 != NULL)) + return 1; + } + else + { + while (len) + { + char c2 = *s2; + char c1 = *s1; + if (c1 != c2) break; + s1++; + if (c1 == '\0') + return 0; + len--; + s2++; + } + if (len) + return *s1 - *s2; + ret = 0; + } + return ret; +} \ No newline at end of file diff --git a/BIOS/iop/types.h b/BIOS/iop/types.h new file mode 100644 index 0000000..20a9d6b --- /dev/null +++ b/BIOS/iop/types.h @@ -0,0 +1,11 @@ +#pragma once + +typedef struct +{ + unsigned int ram_size; + unsigned int boot_info; + unsigned int cmd_ptr; + unsigned int unk2[3]; + unsigned int numModules; + unsigned int structEnd; +} IopBootInfo; \ No newline at end of file diff --git a/BIOS/prime.cpp b/BIOS/prime.cpp new file mode 100644 index 0000000..4e7eb55 --- /dev/null +++ b/BIOS/prime.cpp @@ -0,0 +1,43 @@ +#include + +std::string primeCalc(int digits) +{ + bool isPrime = false; + std::string ret; + ret.clear(); + + int x = 0; + while (ret.length() < digits) + { + printf("Checking %d\n", x); + if (x == 0 || x == 1) + { + x++; + continue; + } + + isPrime = true; + + for (int y = 2; y <= x / 2; y++) + { + if (x % y == 0) + { + isPrime = false; + break; + } + } + + if (isPrime) + ret += std::to_string(x); + x++; + } + + return ret; +} + +int main() +{ + std::string s = primeCalc(10005).c_str(); + printf("%s\n", s.substr(0, 5).c_str()); + return s.size(); +} \ No newline at end of file diff --git a/src/emu/System.cpp b/src/emu/System.cpp index 6e300a3..8c3d89b 100644 --- a/src/emu/System.cpp +++ b/src/emu/System.cpp @@ -130,8 +130,12 @@ void System::Run() { size_t cycles = Scheduler::GetNextTimestamp(); + printf("Running for a max of %ld cycles\n", cycles); + int true_cycles = EmotionEngine::Clock(cycles); - IOP_MANAGEMENT::Clock(true_cycles / 2); + IOP_MANAGEMENT::Clock(true_cycles / 8); + + printf("Actual block took %ld cycles\n", true_cycles); Scheduler::CheckScheduler(true_cycles); } diff --git a/src/emu/cpu/ee/EEJit.cpp b/src/emu/cpu/ee/EEJit.cpp index ad550e2..e070546 100644 --- a/src/emu/cpu/ee/EEJit.cpp +++ b/src/emu/cpu/ee/EEJit.cpp @@ -52,6 +52,26 @@ void EmitSLL(Opcode op) printf("sll %s,%s,%d\n", EmotionEngine::Reg(op.r_type.rd), EmotionEngine::Reg(op.r_type.rt), op.r_type.sa); } +// 0x02 +void EmitSRL(Opcode op) +{ + IRValue rd(IRValue::Reg); + rd.SetReg(op.r_type.rd); + + IRValue rt(IRValue::Reg); + rt.SetReg(op.r_type.rt); + + IRValue sa(IRValue::Imm); + sa.SetImm32Unsigned(op.r_type.sa); + + IRInstruction instr = IRInstruction::Build({rd, rt, sa}, SHIFT); + instr.is_logical = true; + instr.direction = IRInstruction::Direction::Right; + curBlock->instructions.push_back(instr); + + printf("srl %s,%s,%d\n", EmotionEngine::Reg(op.r_type.rd), EmotionEngine::Reg(op.r_type.rt), op.r_type.sa); +} + void EmitJR(Opcode op) { IRValue reg(IRValue::Reg); @@ -64,6 +84,7 @@ void EmitJR(Opcode op) printf("jr %s\n", EmotionEngine::Reg(reg.GetReg())); } +// 0x09 void EmitJalr(Opcode op) { IRValue rd(IRValue::Reg); @@ -78,11 +99,35 @@ void EmitJalr(Opcode op) printf("jalr %s,%s\n", EmotionEngine::Reg(op.r_type.rd), EmotionEngine::Reg(op.r_type.rs)); } +// 0x0d +void EmitBreak() +{ + auto instr = IRInstruction::Build({}, BREAK); + curBlock->instructions.push_back(instr); + + printf("break\n"); +} + +void EmitMFLO(Opcode op) +{ + IRValue rd(IRValue::Reg); + rd.SetReg(op.r_type.rd); + + IRValue lo(IRValue::Special); + lo.SetReg(LO); + + IRInstruction instr = IRInstruction::Build({rd, lo}, MOVE); + instr.is_mmi_divmul = false; + curBlock->instructions.push_back(instr); + + printf("mflo %s\n", EmotionEngine::Reg(op.r_type.rd)); +} + // 0x18 void EmitMULT(Opcode op) { IRValue rd(IRValue::Reg); - rd.SetReg(op.r_type.rt); + rd.SetReg(op.r_type.rd); IRValue rt(IRValue::Reg); rt.SetReg(op.r_type.rt); IRValue rs(IRValue::Reg); @@ -97,6 +142,25 @@ void EmitMULT(Opcode op) printf("mult %s,%s,%s\n", EmotionEngine::Reg(op.r_type.rd), EmotionEngine::Reg(op.r_type.rs), EmotionEngine::Reg(op.r_type.rt)); } +// 0x1B +void EmitDIVU(Opcode op) +{ + IRValue rd(IRValue::Reg); + rd.SetReg(op.r_type.rt); + IRValue rt(IRValue::Reg); + rt.SetReg(op.r_type.rt); + IRValue rs(IRValue::Reg); + rs.SetReg(op.r_type.rs); + + auto instr = IRInstruction::Build({rd, rs, rt}, DIV); + instr.is_unsigned = true; + instr.size = IRInstruction::InstrSize::Size32; + instr.is_mmi_divmul = false; + curBlock->instructions.push_back(instr); + + printf("divu %s,%s,%s\n", EmotionEngine::Reg(op.r_type.rd), EmotionEngine::Reg(op.r_type.rs), EmotionEngine::Reg(op.r_type.rt)); +} + // 0x25 void EmitOR(Opcode op) { @@ -143,18 +207,30 @@ void EmitSpecial(Opcode op) case 0x00: EmitSLL(op); break; + case 0x02: + EmitSRL(op); + break; case 0x08: EmitJR(op); break; case 0x09: EmitJalr(op); break; + case 0x0d: + EmitBreak(); + break; case 0x0f: printf("sync\n"); break; + case 0x12: + EmitMFLO(op); + break; case 0x18: EmitMULT(op); break; + case 0x1b: + EmitDIVU(op); + break; case 0x25: EmitOR(op); break; @@ -260,6 +336,25 @@ void EmitSLTI(Opcode op) printf("slti %s,%s,0x%08lx\n", EmotionEngine::Reg(op.i_type.rt), EmotionEngine::Reg(op.i_type.rs), (int64_t)(int16_t)op.i_type.imm); } +// 0x0B +void EmitSLTIU(Opcode op) +{ + IRValue imm(IRValue::Imm); + imm.SetImm64(op.i_type.imm); + + IRValue src(IRValue::Reg); + src.SetReg(op.i_type.rs); + + IRValue dst(IRValue::Reg); + dst.SetReg(op.i_type.rt); + + auto instr = IRInstruction::Build({dst, src, imm}, IRInstrs::SLT); + instr.is_unsigned = true; + curBlock->instructions.push_back(instr); + + printf("sltiu %s,%s,0x%08lx\n", EmotionEngine::Reg(op.i_type.rt), EmotionEngine::Reg(op.i_type.rs), (int64_t)(int16_t)op.i_type.imm); +} + // 0x0C void EmitANDI(Opcode op) { @@ -377,6 +472,49 @@ void EmitCOP0(Opcode op) } } +// 0x14 +void EmitBEQL(Opcode op) +{ + IRValue imm(IRValue::Imm); + imm.SetImm32(op.i_type.imm << 2); + + IRValue rt(IRValue::Reg); + rt.SetReg(op.i_type.rt); + + IRValue rs(IRValue::Reg); + rs.SetReg(op.i_type.rs); + + auto instr = IRInstruction::Build({rs, rt, imm}, IRInstrs::BRANCH); + if (op.i_type.rt == 0 && op.i_type.rs == 0) + instr.b_type = IRInstruction::BranchType::AL; + else + instr.b_type = IRInstruction::BranchType::EQ; + instr.is_likely = true; + curBlock->instructions.push_back(instr); + + printf("beql %s,%s,pc+%d\n", EmotionEngine::Reg(op.i_type.rs), EmotionEngine::Reg(op.i_type.rt), (int32_t)imm.GetImm()); +} + +// 0x15 +void EmitBNEL(Opcode op) +{ + IRValue imm(IRValue::Imm); + imm.SetImm32(op.i_type.imm << 2); + + IRValue rt(IRValue::Reg); + rt.SetReg(op.i_type.rt); + + IRValue rs(IRValue::Reg); + rs.SetReg(op.i_type.rs); + + auto instr = IRInstruction::Build({rs, rt, imm}, IRInstrs::BRANCH); + instr.b_type = IRInstruction::BranchType::NE; + instr.is_likely = true; + curBlock->instructions.push_back(instr); + + printf("bnel %s,%s,pc+%d\n", EmotionEngine::Reg(op.i_type.rs), EmotionEngine::Reg(op.i_type.rt), (int32_t)imm.GetImm()); +} + // 0x2B void EmitSW(Opcode op) { @@ -431,6 +569,8 @@ bool IsBranch(Opcode op) break; case 0x03: case 0x05: + case 0x14: + case 0x15: return true; } @@ -502,6 +642,9 @@ int EEJit::Clock(int cycles) break; case 0x0A: EmitSLTI(op); + break; + case 0x0B: + EmitSLTIU(op); break; case 0x0C: EmitANDI(op); @@ -515,6 +658,12 @@ int EEJit::Clock(int cycles) case 0x10: EmitCOP0(op); break; + case 0x14: + EmitBEQL(op); + break; + case 0x15: + EmitBNEL(op); + break; case 0x2B: EmitSW(op); break; @@ -547,6 +696,8 @@ int EEJit::Clock(int cycles) // Run it curBlock->entryPoint(EmotionEngine::GetState(), curBlock->addr); + printf("Block returned at pc = 0x%08x\n", EmotionEngine::GetState()->pc); + return curBlock->cycles; } diff --git a/src/emu/cpu/ee/EEJit.h b/src/emu/cpu/ee/EEJit.h index 00ee14f..f2cdc42 100644 --- a/src/emu/cpu/ee/EEJit.h +++ b/src/emu/cpu/ee/EEJit.h @@ -18,6 +18,8 @@ enum IRInstrs AND, // Bitwise AND SHIFT, // Shift logical, arithmetic, left, right, etc... MULT, // Multiply + DIV, // Divide + BREAK, // We make this translate to ud2 to prevent BREAK from being executed, as it's purely used for asserts and the like, which we should never hit }; struct IRValue @@ -29,7 +31,8 @@ public: Reg, Cop0Reg, Cop1Reg, - Float + Float, + Special // Used for LO, HI, LO1, HI1 }; private: union @@ -50,6 +53,7 @@ public: bool IsCop1() {return type == Cop1Reg;} bool IsReg() {return type == Reg;} bool IsFloat() {return type == Float;} + bool IsSpecial() {return type == Special;} // Can be used for guest, COP0, and COP1 registers void SetReg(uint32_t reg) {value.register_num = reg;} void SetImm(uint16_t imm) {value.imm = (int32_t)(int16_t)imm;} diff --git a/src/emu/cpu/ee/EmotionEngine.cpp b/src/emu/cpu/ee/EmotionEngine.cpp index 3ac40a2..f43d82b 100644 --- a/src/emu/cpu/ee/EmotionEngine.cpp +++ b/src/emu/cpu/ee/EmotionEngine.cpp @@ -40,71 +40,6 @@ int Clock(int cycles) #endif } -bool IsBranch(uint32_t instr) -{ - uint8_t opcode = (instr >> 26) & 0x3F; - - switch (opcode) - { - case 0x00: - { - opcode = instr & 0x3F; - switch (opcode) - { - case 0x08: - case 0x09: - case 0x0C: - return true; - default: - return false; - } - break; - } - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x14: - case 0x15: - return true; - case 0x10: - opcode = (instr >> 21) & 0x3F; - switch (opcode) - { - case 0x10: - { - opcode = instr & 0x3F; - switch (opcode) - { - case 0x18: - return true; - default: - return false; - } - } - default: - return false; - } - break; - case 0x11: - opcode = (instr >> 21) & 0x1F; - switch (opcode) - { - case 0x8: - return true; - } - break; - default: - return false; - } - - return false; -} -#define BLOCKCACHE_ENABLE - void Dump() { for (int i = 0; i < 32; i++) @@ -300,12 +235,29 @@ void ClearIp1Pending() EmotionEngine::GetState()->cop0_regs[13] = cause.value; } +void CheckForInterrupt() +{ + +} + void SetIp0Pending() { COP0CAUSE cause; cause.value = EmotionEngine::GetState()->cop0_regs[13]; cause.ip0_pending = true; EmotionEngine::GetState()->cop0_regs[13] = cause.value; + // We try and do an exception here + COP0Status status; + status.value = EmotionEngine::GetState()->cop0_regs[12]; + bool int_enabled = status.eie && status.ie && !status.erl && !status.exl; + + bool pending = (cause.ip0_pending && status.im0) + || (cause.ip1_pending && status.im1); + + if (int_enabled && pending) + { + Exception(0x00); + } } } // namespace EmotionEngine diff --git a/src/emu/cpu/ee/EmotionEngine.h b/src/emu/cpu/ee/EmotionEngine.h index 9485de7..998006b 100644 --- a/src/emu/cpu/ee/EmotionEngine.h +++ b/src/emu/cpu/ee/EmotionEngine.h @@ -43,21 +43,17 @@ int Clock(int cycles); void Dump(); ProcessorState* GetState(); void MarkDirty(uint32_t address, uint32_t size); -void EmitPrequel(); void Exception(uint8_t code); void SetIp1Pending(); // Set IP1 to pending, signalling a DMA interrupt void ClearIp1Pending(); // Clear a DMA interrupt void SetIp0Pending(); +void CheckForInterrupt(); extern bool can_dump; -void CheckCacheFull(); -bool DoesBlockExit(uint32_t addr); -void EmitIR(uint32_t instr); bool IsBranch(uint32_t instr); -uint64_t GetExistingBlockCycles(uint32_t addr); inline const char* Reg(int index) { diff --git a/src/emu/cpu/ee/x64/EEJitx64.cpp b/src/emu/cpu/ee/x64/EEJitx64.cpp index 9206483..51f4a0a 100644 --- a/src/emu/cpu/ee/x64/EEJitx64.cpp +++ b/src/emu/cpu/ee/x64/EEJitx64.cpp @@ -10,6 +10,9 @@ #include #include #include +#include + +std::unordered_map blockMap; Xbyak::CodeGenerator* generator; uint8_t* base; @@ -117,6 +120,20 @@ void JitMov(IRInstruction& i) MOV(dst, i.args[1].GetImm64()); } } + else if (i.args[0].IsReg() && i.args[1].IsSpecial()) + { + if (i.args[0].GetReg() == 0) + { + printf("WARNING: Mov imm -> $zero\n"); + return; + } + else + { + auto dst = Xbyak::Reg64(reg_alloc.GetHostReg((GuestRegister)(i.args[0].GetReg()), true)); + auto src = Xbyak::Reg64(reg_alloc.GetHostReg((GuestRegister)(i.args[1].GetReg()))); + MOV(dst, src); + } + } else { printf("[EEJIT_X64]: Unknown src/dst combo for move\n"); @@ -129,31 +146,29 @@ void JitSlt(IRInstruction& i) // Args[0] = dst, Args[1] = op1, Args[2] = op2 if (i.args[2].IsImm()) { - if (i.is_unsigned) + auto dst = Xbyak::Reg8(reg_alloc.GetHostReg((GuestRegister)i.args[0].GetReg(), true)); + if (i.args[1].GetReg() == 0) { - printf("TODO: SLTIU\n"); - exit(1); + int32_t imm = i.args[2].GetImm(); + MOV(generator->rdi, 0); + generator->cmp(generator->rdi, imm); + if (i.is_unsigned) + generator->seta(dst); + else + generator->setl(dst); + generator->movzx(Xbyak::Reg64(reg_alloc.GetHostReg((GuestRegister)i.args[0].GetReg(), true)), dst); } else { - auto dst = Xbyak::Reg8(reg_alloc.GetHostReg((GuestRegister)i.args[0].GetReg(), true)); - if (i.args[1].GetReg() == 0) - { - int32_t imm = i.args[2].GetImm(); - MOV(generator->rdi, 0); - generator->cmp(generator->rdi, imm); - generator->setl(dst); - generator->movzx(Xbyak::Reg64(reg_alloc.GetHostReg((GuestRegister)i.args[0].GetReg(), true)), dst); - } - else - { - auto src = Xbyak::Reg64(reg_alloc.GetHostReg((GuestRegister)i.args[1].GetReg())); - int32_t imm = i.args[2].GetImm(); + auto src = Xbyak::Reg64(reg_alloc.GetHostReg((GuestRegister)i.args[1].GetReg())); + int32_t imm = i.args[2].GetImm(); - generator->cmp(src, imm); - generator->setl(dst); - generator->movzx(Xbyak::Reg64(reg_alloc.GetHostReg((GuestRegister)i.args[0].GetReg(), true)), dst); - } + generator->cmp(src, imm); + if (i.is_unsigned) + generator->seta(dst); + else + generator->setl(dst); + generator->movzx(Xbyak::Reg64(reg_alloc.GetHostReg((GuestRegister)i.args[0].GetReg(), true)), dst); } } else @@ -169,7 +184,7 @@ void JitBranch(IRInstruction& i) Xbyak::Label cond_failed; - switch (i.b_type) + switch (i.b_type) { case IRInstruction::BranchType::EQ: { @@ -181,8 +196,7 @@ void JitBranch(IRInstruction& i) else if (i.args[0].GetReg() == 0) { auto op2 = Xbyak::Reg64(reg_alloc.GetHostReg((GuestRegister)i.args[1].GetReg())); - MOV(generator->rdi, 0); - generator->cmp(generator->rdi, i.args[1].GetImm()); + generator->cmp(op2, 0); generator->jne(cond_failed); } else @@ -228,6 +242,11 @@ void JitBranch(IRInstruction& i) generator->jmp(done); generator->L(cond_failed); ADD(generator->r8, 4); + if (i.is_likely) + { + ADD(generator->r8, 4); + JitEpilogue(); + } generator->L(done); } @@ -443,6 +462,15 @@ void JitShift(IRInstruction i) generator->shl(src, generator->cl); generator->mov(dst, src); } + else if (i.args[2].IsImm() && i.is_logical && i.direction == IRInstruction::Direction::Right) + { + auto src = Xbyak::Reg32(reg_alloc.GetHostReg((GuestRegister)i.args[1].GetReg())); + auto dst = Xbyak::Reg32(reg_alloc.GetHostReg((GuestRegister)i.args[0].GetReg(), true)); + + MOV(generator->cl, i.args[2].GetImm()); + generator->shr(src, generator->cl); + generator->mov(dst, src); + } else { printf("Invalid shift combo %d/%d/%d\n", i.args[2].type, i.is_logical, i.direction); @@ -464,6 +492,7 @@ void JitMULT(IRInstruction i) if (i.is_unsigned) { + generator->xor_(generator->rdx, generator->rdx); generator->movsxd(generator->rax, src); generator->mul(src2); generator->movsxd(lo, generator->eax); @@ -482,6 +511,33 @@ void JitMULT(IRInstruction i) } } +void JitDIV(IRInstruction i) +{ + GuestRegister lo_reg = i.is_mmi_divmul ? GuestRegister::LO1 : GuestRegister::LO; + GuestRegister hi_reg = i.is_mmi_divmul ? GuestRegister::HI1 : GuestRegister::HI; + + auto src = Xbyak::Reg32(reg_alloc.GetHostReg((GuestRegister)i.args[1].GetReg())); + auto src2 = Xbyak::Reg32(reg_alloc.GetHostReg((GuestRegister)i.args[2].GetReg())); + auto lo = Xbyak::Reg64(reg_alloc.GetHostReg(lo_reg)); + auto hi = Xbyak::Reg64(reg_alloc.GetHostReg(hi_reg)); + + reg_alloc.InvalidateRegister(HostRegisters::RDX); + + if (i.is_unsigned) + { + generator->xor_(generator->rdx, generator->rdx); + MOV(generator->rax, src); + generator->div(src2); + MOV(lo, generator->rax); + MOV(hi, generator->rdx); + } + else + { + printf("TODO: DIV"); + assert(0); + } +} + void JitIncPC() { ADD(generator->r8, 4); @@ -542,8 +598,14 @@ void EEJitX64::TranslateBlock(Block *block) case MULT: JitMULT(i); break; + case DIV: + JitDIV(i); + break; + case BREAK: + generator->ud2(); + break; default: - printf("[EEJIT_X64]: Cannot emit unknown IR instruction 0x%02x\n", i.instr); + printf("[EEJIT_X64]: Cannot emit unknown IR instruction %d\n", i.instr); exit(1); } @@ -554,17 +616,19 @@ void EEJitX64::TranslateBlock(Block *block) void EEJitX64::CacheBlock(Block *block) { // TODO: Actually cache the block + blockMap[block->addr] = block; if ((generator->getCurr() - generator->getCode()) >= (128*1024*1024)) { delete[] generator; generator = new Xbyak::CodeGenerator(0xffffffff, (void*)base); + blockMap.clear(); } } Block *EEJitX64::GetBlockForAddr(uint32_t addr) { - return nullptr; + return blockMap[addr]; } void EEJitX64::Initialize() diff --git a/src/emu/sched/scheduler.cpp b/src/emu/sched/scheduler.cpp index ff7855f..0dde0dc 100644 --- a/src/emu/sched/scheduler.cpp +++ b/src/emu/sched/scheduler.cpp @@ -42,8 +42,6 @@ void CheckScheduler(uint64_t cycles) { global_cycles += cycles; - IOP_MANAGEMENT::Clock(cycles / 4); - if (!next_tp && !event_queue.empty()) { next_tp = event_queue.front().cycles_from_now; diff --git a/util/.gitignore b/util/.gitignore new file mode 100644 index 0000000..a351a29 --- /dev/null +++ b/util/.gitignore @@ -0,0 +1 @@ +.bios diff --git a/util/DMACMAN b/util/DMACMAN deleted file mode 100644 index 5e317d115f50f675045443da7fd36d9ff80a7833..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14069 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 D*O$gm diff --git a/util/dump b/util/dump new file mode 100644 index 0000000..d63fb24 --- /dev/null +++ b/util/dump @@ -0,0 +1,601 @@ +00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +00000020 00 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 |..ELF...........| +00000030 00 80 ff 08 00 01 00 00 00 00 00 00 00 34 00 00 |.............4..| +00000040 00 6c 1d 00 00 01 00 00 00 34 00 20 00 02 00 28 |.l.......4. ...(| +00000050 00 0c 00 09 00 80 00 00 70 74 00 00 00 00 00 00 |........pt......| +00000060 00 00 00 00 00 29 00 00 00 00 00 00 00 04 00 00 |.....)..........| +00000070 00 04 00 00 00 01 00 00 00 a0 00 00 00 00 00 00 |................| +00000080 00 00 00 00 00 70 1c 00 00 d4 1c 00 00 07 00 00 |.....p..........| +00000090 00 10 00 00 00 60 1c 00 00 00 00 00 00 60 9c 00 |.....`.......`..| +000000a0 00 30 1c 00 00 40 00 00 00 64 00 00 00 01 01 4d |.0...@...d.....M| +000000b0 6f 64 75 6c 65 5f 4d 61 6e 61 67 65 72 00 00 00 |odule_Manager...| +000000c0 00 00 60 80 40 00 00 82 8c 00 00 00 00 00 ed 02 |..`.@...........| +000000d0 00 c0 ff bd 27 21 f0 a0 03 01 00 1c 3c 0c 00 00 |....'!......<...| +000000e0 08 60 9c 9c 27 00 00 00 00 00 00 00 00 00 00 00 |.`..'...........| +000000f0 00 80 ff bd 27 78 00 bf af 74 00 be af 70 00 b4 |....'x...t...p..| +00000100 af 6c 00 b3 af 68 00 b2 af 64 00 b1 af 60 00 b0 |.l...h...d...`..| +00000110 af 00 00 82 8c 21 f0 a0 03 38 00 c2 af 04 00 82 |.....!...8......| +00000120 8c 00 00 00 00 3c 00 c2 af 08 00 82 8c 00 00 00 |.....<..........| +00000130 00 40 00 c2 af 0c 00 85 8c 00 00 00 00 44 00 c5 |.@...........D..| +00000140 af 10 00 82 8c 00 00 00 00 48 00 c2 af 14 00 82 |.........H......| +00000150 8c 00 00 00 00 4c 00 c2 af 18 00 82 8c 00 00 00 |.....L..........| +00000160 00 50 00 c2 af 1c 00 86 8c 00 00 03 3c 74 1c 63 |.P..........o|Xb&OaO|W@)uHn8leU zP&QfVTp~xUc6&@J{v%SM2#R&g0(H8cm@il5;i4GU@2yW`Y9{q(qC4}j9HY&W$=1c->G@YYmb>38@ zY|-ot$K$DFUw?cko5*D2hZ4y&iO2hg6Y+s$I+02qd668>B-7aeGL+4v`wtyfSIzfX zM!3H%Oo(H15BbZnX?YOeZ)uTpJ}^-+MPJj5-?MZg*A?L2PX*SNpM zXW5B{Ck*!r?1zRGI<3w(iq!lDoP@FbId-zi)%BzedjE1RPs%g51X-Dp$MQGO^s=m6 z8q0qUePv#`Adj2Q!hXrh>{l=>DcacIO}iYWWzO^8IPw=ERUOgEQcdgaPuG^d#d6M8 z^Se-5E!ofu1E0o$VXiq0<2Hjlp1*}%vG-g%C{e$6mCUC+i!b|! z#LylwGVG7+9B%Veqm}G?C6|7|;^n+mkNf5*44?c z8;zF*s3c?~r0+nRW)J%O_Nls$MKW$_JS~zdqDdX~eQ0HY&@%?ftsW0e8Qih zn(ND@v$^Q87-)OI6OFN+h(~=s5~OsHDbX;M)H6{Br3>szY%BeTm11EW!q;(=(nXc- z=(N(`SXX!0D!E~5xFk2rbnl~fcBVTlYQNS}cc*y3TP-=jqCK5rsadwxjp@z zcXIB#_rARG5js9XKXXvmjGc&U#ty4#$a&mS;c}dK1Z5U*g2;MAP~bhvM2mI@X`oj>Zy6GLY_1#*d~*YA`*3xA9K=h!#J5MC*+u z`berjkxcjMPwX2V!zI?#5+=m`Ecw&jP(I9`xHNZGBWwK=QQt-Z%w{z@)u972UZ`T zo;!GqSNPFg<>yi02T^PF=)u zQrrWoZ>zfn?`5vJGn1IgWxj^|8Xt`Lyw$_YOK-q=U!(n2nXyXAx@h)#Zj`r;<}w8y z=wx&>bC>_i{)jUazrk7~GgZ8e95eZkj!H8HdgL14Cr=pria!^xTH<}CiqyLTz7oL9uyA|)lukse%vv$D_sg+$H`tQSnzhN7#vv%M+LHG;mpJ!}{#|6gD zVT@qpOZP7_)`QVmV$6dZH1RiM1@tA@r?jlQh*i&_$S%8whejNmah!v^;%na8+}0T2 z=~^5IaSY)kqK+r=;`ua=6ih2Jy$N$l^Y*F+Lh9;P*&Smz8}G-*BF=NxMu@EgvAfzc zVtJuzMf5$Z^|TEu30aTnzi^y@?m$!Z@6x=3{A92F*+FtnNzVtyUAXLe*c5!lQjqm` zgAy8d4JOlr>N~Bip~&Wty2-Dqus!0}dm;{)JTkfFbG51i`oz>QA7^XaE?v9sM7RVqbM bP`lcl2gUB--ss1=rYH?UUaEnYcHaCKOimF2 diff --git a/util/romdumper.cpp b/util/romdumper.cpp index 26d694e..1e973f0 100644 --- a/util/romdumper.cpp +++ b/util/romdumper.cpp @@ -66,7 +66,7 @@ int main(int argc, char** argv) for (int i = 0; i < entryCount; i++) { - printf("0x%08x\n", pos); + printf("%s\t->\t0x%08x, 0x%08x\n", entries[i].name, pos, entries[i].file_size); if (!strncmp(entries[i].name, argv[2], 10)) { printf("Found \"%s\" at 0x%08x\n", entries[i].name, pos);