diff --git a/CMakeLists.txt b/CMakeLists.txt index 36714d7..ca958ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED True) project(ChonkyStation) add_subdirectory(external) +add_subdirectory(test) add_subdirectory(src) include_directories(src/common) @@ -14,14 +15,17 @@ include_directories(src/gpu) include_directories(src/cdrom) include_directories(src/scheduler) +include_directories(test) + include_directories(external/Dolphin) include_directories(external/Panda3DS) +source_group("Header Files/Test" FILES ${TEST_HEADER_FILES}) source_group("Header Files/External/Dolphin" FILES ${DOLPHIN_HEADER_FILES}) source_group("Header Files/External/Panda3DS" FILES ${PANDA3DS_HEADER_FILES}) add_compile_definitions(SDL_MAIN_HANDLED) -add_executable(ChonkyStation ${SOURCE_FILES} ${HEADER_FILES} ${DOLPHIN_HEADER_FILES} ${PANDA3DS_HEADER_FILES}) +add_executable(ChonkyStation ${SOURCE_FILES} ${HEADER_FILES} ${TEST_SOURCE_FILES} ${TEST_HEADER_FILES} ${DOLPHIN_HEADER_FILES} ${PANDA3DS_HEADER_FILES}) target_include_directories(ChonkyStation PRIVATE ${SDL2_INCLUDE_DIR}) target_link_libraries(ChonkyStation PRIVATE fmt SDL2-static) \ No newline at end of file diff --git a/src/cpu/backends/interpreter/interpreter.cpp b/src/cpu/backends/interpreter/interpreter.cpp index 766dc3e..3db77a9 100644 --- a/src/cpu/backends/interpreter/interpreter.cpp +++ b/src/cpu/backends/interpreter/interpreter.cpp @@ -1,8 +1,8 @@ #include "interpreter.hpp" -//#define DONT_CRASH_ON_BAD_READWRITE -//#define DONT_CRASH_ON_BAD_JUMP +#define DONT_CRASH_ON_BAD_READWRITE +#define DONT_CRASH_ON_BAD_JUMP void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) { // Handle interrupts diff --git a/src/cpu/backends/old_interpreter/old_interpreter.cpp b/src/cpu/backends/old_interpreter/old_interpreter.cpp index 6265010..61312ce 100644 --- a/src/cpu/backends/old_interpreter/old_interpreter.cpp +++ b/src/cpu/backends/old_interpreter/old_interpreter.cpp @@ -68,6 +68,7 @@ void OldInterpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler if (delay) { // branch delay slot core->pc = jump - 4; delay = false; + core->isDelaySlot = false; } // Quick and dirty hack. TODO: Replace this with a bitfield @@ -125,6 +126,7 @@ void OldInterpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler jump = addr; debug_log("jr %s\n", reg[rs].c_str()); delay = true; + core->isDelaySlot = true; break; } case 0x09: { @@ -137,6 +139,7 @@ void OldInterpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler jump = addr; debug_log("jalr %s\n", reg[rs].c_str()); delay = true; + core->isDelaySlot = true; break; } case 0x0C: { @@ -304,6 +307,7 @@ void OldInterpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler if (signed_rs < 0) { jump = (core->pc + 4) + (sign_extended_imm << 2); delay = true; + core->isDelaySlot = true; debug_log(" branched\n"); } else { debug_log("\n"); } @@ -315,6 +319,7 @@ void OldInterpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler if (signed_rs >= 0) { jump = (core->pc + 4) + (sign_extended_imm << 2); delay = true; + core->isDelaySlot = true; debug_log(" branched\n"); } else { debug_log("\n"); } @@ -326,6 +331,7 @@ void OldInterpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler jump = (core->pc & 0xf0000000) | (jump_imm << 2); debug_log("j 0x%.8x\n", jump_imm); delay = true; + core->isDelaySlot = true; break; } case 0x03: { @@ -333,6 +339,7 @@ void OldInterpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler debug_log("jal 0x%.8x\n", jump_imm); regs[0x1f] = core->pc + 8; delay = true; + core->isDelaySlot = true; break; } case 0x04: { @@ -340,6 +347,7 @@ void OldInterpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler if (regs[rs] == regs[rt]) { jump = (core->pc + 4) + (sign_extended_imm << 2); delay = true; + core->isDelaySlot = true; debug_log(" branched\n"); } else { debug_log("\n"); } @@ -350,6 +358,7 @@ void OldInterpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler if (regs[rs] != regs[rt]) { jump = (core->pc + 4) + (sign_extended_imm << 2); delay = true; + core->isDelaySlot = true; debug_log(" branched\n"); } else { debug_log("\n"); } @@ -360,6 +369,7 @@ void OldInterpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler if (signed_rs <= 0) { jump = (core->pc + 4) + (sign_extended_imm << 2); delay = true; + core->isDelaySlot = true; debug_log(" branched\n"); } else { debug_log("\n"); } @@ -370,6 +380,7 @@ void OldInterpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler if (signed_rs > 0) { jump = (core->pc + 4) + (sign_extended_imm << 2); delay = true; + core->isDelaySlot = true; debug_log(" branched\n"); } else { debug_log("\n"); } diff --git a/src/gpu/gpu.cpp b/src/gpu/gpu.cpp index f931462..b1e57ca 100644 --- a/src/gpu/gpu.cpp +++ b/src/gpu/gpu.cpp @@ -54,6 +54,11 @@ void GPU::writeGp0(u32 data) { if (paramsLeft == 0) { if (!uploadingTexture) { switch (fifo[0] >> 24) { + case (u32)GP0Command::FillVRAM: { + // TODO + hasCommand = false; + break; + } case (u32)GP0Command::UploadTexture: { uploadingTexture = true; // Calculate size @@ -145,17 +150,23 @@ void GPU::writeGp0(u32 data) { vert.u = fifo[idx] & 0xff; vert.v = (fifo[idx++] >> 8) & 0xff; } - // TODO: variable size - Helpers::debugAssert(rect.size != 0, "[FATAL] Unimplemented variable size rectangle\n"); + // TODO: textured Helpers::debugAssert(!rect.textured, "[FATAL] Unimplemented textured rectangle\n"); u16 width = 0; u16 height = 0; - switch (rect.size) { - case 1: width = 1; height = 1; break; - case 2: width = 8; height = 8; break; - case 3: width = 16; height = 16; break; + + if (rect.size == 0) { + width = fifo[idx] & 0xffff; + height = (fifo[idx++] >> 8) & 0xffff; + } + else { + switch (rect.size) { + case 1: width = 1; height = 1; break; + case 2: width = 8; height = 8; break; + case 3: width = 16; height = 16; break; + } } backend->drawRectUntextured(vert, width, height); @@ -248,6 +259,12 @@ void GPU::startCommand(u32 rawCommand) { // Stubbed break; } + case (u32)GP0Command::FillVRAM: { + log("FillVRAM\n"); + paramsLeft = 2; + hasCommand = true; + break; + } case (u32)GP0Command::UploadTexture: { log("UploadTexture\n"); paramsLeft = 2; diff --git a/src/gpu/gpu.hpp b/src/gpu/gpu.hpp index 53ec81c..0196536 100644 --- a/src/gpu/gpu.hpp +++ b/src/gpu/gpu.hpp @@ -42,6 +42,7 @@ public: enum class GP0Command { NOP = 0x00, ClearCache = 0x01, + FillVRAM = 0x02, UploadTexture = 0xA0, ReadVRAM = 0xC0, DrawModeSetting = 0xE1, diff --git a/src/main.cpp b/src/main.cpp index 936a60d..9e51cfe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,6 +2,8 @@ #include #include "playstation.hpp" +#include + int main(int argc, char** argv) { if (argc < 2) Helpers::panic("Usage: ChonkyStation [bios path]\n"); @@ -14,6 +16,10 @@ int main(int argc, char** argv) { playstation.sideloadExecutable(argv[2]); } + // Testing + //Test::Diff diffTest = Test::Diff(argv[1]); + //diffTest.doTest(); + // SDL Window SDL_Init(SDL_INIT_VIDEO); SDL_Window* window = SDL_CreateWindow("ChonkyStation", 100, 100, 1024, 512, 0); diff --git a/src/memory/memory.cpp b/src/memory/memory.cpp index a95bcda..36c00f9 100644 --- a/src/memory/memory.cpp +++ b/src/memory/memory.cpp @@ -157,6 +157,9 @@ u32 Memory::read(u32 vaddr) { else if (paddr == 0x1f8010f4) return dma->dicr; // Timers else if (Helpers::inRangeSized(paddr, (u32)MemoryBase::Timer, (u32)MemorySize::Timer)) return 0; + + else if (paddr == 0x1f80101C) return 0x00070777; // Expansion 2 Delay/Size (usually 00070777h) (128 bytes, 8bit bus) + else Helpers::dump("ramdump.bin", ram, 2_MB); Helpers::panic("[ FATAL ] Unhandled read32 0x%08x (virtual 0x%08x) @ pc 0x%08x\n", paddr, vaddr, core->pc); diff --git a/src/playstation.hpp b/src/playstation.hpp index 554d195..44726d5 100644 --- a/src/playstation.hpp +++ b/src/playstation.hpp @@ -16,7 +16,7 @@ public: mem.core = &cpu.core; mem.loadBios(biosPath); - cpu.switchBackend(Cpu::Backend::Interpreter); + cpu.switchBackend(Cpu::Backend::OldInterpreter); // Setup GPU scheduler events scheduler.push(&gpu.scanlineEvent, scheduler.time + GPUConstants::cyclesPerScanline, &gpu); @@ -47,6 +47,7 @@ public: u32 getPC() { return cpu.core.pc; } u8* getRAM() { return mem.ram; } u8* getVRAM() { return gpu.getVRAM(); } + u32* getGPRS() { return cpu.core.gprs; } bool getVBLANKAndClear() { bool temp = gpu.vblank; gpu.vblank = false; @@ -55,6 +56,8 @@ public: void VBLANK() { interrupt.raiseInterrupt(Interrupt::InterruptType::VBLANK); } bool isInBIOS() { return Helpers::inRangeSized(cpu.core.pc, (u32)Memory::MemoryBase::BIOS, (u32)Memory::MemorySize::BIOS); } + void switchCpuBackend(Cpu::Backend backend) { cpu.switchBackend(backend); } + void loadExecutable(const fs::path path) { auto binary = Helpers::readBinary(path); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..6bb9360 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,7 @@ +set(TEST_SOURCE_FILES +"${CMAKE_CURRENT_SOURCE_DIR}/diff/diff.cpp" +PARENT_SCOPE) + +set(TEST_HEADER_FILES +"${CMAKE_CURRENT_SOURCE_DIR}/diff/diff.hpp" +PARENT_SCOPE) \ No newline at end of file diff --git a/test/diff/diff.cpp b/test/diff/diff.cpp new file mode 100644 index 0000000..e10ccdc --- /dev/null +++ b/test/diff/diff.cpp @@ -0,0 +1,38 @@ +#include "diff.hpp" + + +using namespace Test; + +Diff::Diff(const fs::path& biosPath) : p1(biosPath), p2(biosPath) { + p1.switchCpuBackend(Cpu::Backend::Interpreter); + p2.switchCpuBackend(Cpu::Backend::OldInterpreter); +} + +void Diff::doTest() { + u32* gprs1 = p1.getGPRS(); + u32* gprs2 = p2.getGPRS(); + + while (true) { + while (!p1.getVBLANKAndClear()) { + p1.step(); + p2.step(); + + for (int i = 0; i < 32; i++) { + if (gprs1[i] != gprs2[i]) { + printf("r%d | 0x%08x != 0x%08x\n", i, gprs1[i], gprs2[i]); + exit(0); + } + } + + if (p1.getPC() != p2.getPC()) { + printf("pc | 0x%08x != 0x%08x\n", p1.getPC(), p2.getPC()); + + Helpers::dump("ramp1.bin", p1.getRAM(), 2_MB); + Helpers::dump("ramp2.bin", p2.getRAM(), 2_MB); + exit(0); + } + } + p1.VBLANK(); + p2.VBLANK(); + } +} \ No newline at end of file diff --git a/test/diff/diff.hpp b/test/diff/diff.hpp new file mode 100644 index 0000000..9d77151 --- /dev/null +++ b/test/diff/diff.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include "../../src/playstation.hpp" + + +namespace Test { + class Diff { + public: + Diff(const fs::path& biosPath); + void doTest(); + private: + PlayStation p1; + PlayStation p2; + }; +} // End namespace test \ No newline at end of file