diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b776bc64..5ef690cf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,7 +17,7 @@ jobs: cmake -B build cd build sudo make install - - name: Build natsukashii + - name: Build Gadolinium run: | cmake \ -G Ninja \ @@ -31,11 +31,11 @@ jobs: - name: Collect artifacts run: | mkdir upload - cp -r build/{natsukashii,resources} upload + cp -r build/{gadolinium,resources} upload - name: Upload artifacts uses: actions/upload-artifact@master with: - name: natsukashii-linux + name: gadolinium-linux path: upload if-no-files-found: error build-windows: @@ -49,14 +49,14 @@ jobs: vcpkg install sdl2[vulkan]:x64-windows vcpkg install fmt:x64-windows vcpkg install nlohmann-json:x64-windows - - name: Build natsukashii + - name: Build Gadolinium run: | cmake -B build -T clangcl -DCAPSTONE_ARCHITECTURE_DEFAULT=OFF -DCAPSTONE_BUILD_TESTS=OFF -DCAPSTONE_MIPS_SUPPORT=ON -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE=Release -S src cmake --build build --config Release - name: Collect artifacts run: | mkdir upload - cp build/Release/natsukashii.exe upload + cp build/Release/gadolinium.exe upload mkdir upload/resources cp build/resources/* upload/resources cp build/Release/SDL2.dll upload @@ -64,6 +64,6 @@ jobs: - name: Upload artifacts uses: actions/upload-artifact@master with: - name: natsukashii-windows + name: gadolinium-windows path: upload if-no-files-found: error \ No newline at end of file diff --git a/README.md b/README.md index 51f71696..90a373a3 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,7 @@ -# natsukashii -### _"Joyful nostalgia"_ +# Gadolinium -[![CodeFactor](https://www.codefactor.io/repository/github/cocosimone/natsukashii/badge/master)](https://www.codefactor.io/repository/github/cocosimone/natsukashii/overview/master) -[![build](https://github.com/CocoSimone/natsukashii/actions/workflows/build.yml/badge.svg)](https://github.com/CocoSimone/natsukashii/actions/workflows/build.yml) +[![CodeFactor](https://www.codefactor.io/repository/github/cocosimone/Gadolinium/badge/master)](https://www.codefactor.io/repository/github/cocosimone/Gadolinium/overview/master) +[![build](https://github.com/CocoSimone/Gadolinium/actions/workflows/build.yml/badge.svg)](https://github.com/CocoSimone/Gadolinium/actions/workflows/build.yml) Rewrite of my Nintendo 64 emulator "[shibumi](https://github.com/CocoSimone/shibumi)". diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a078aceb..4e4e2c1a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.20) -project(natsukashii) +project(gadolinium) set(BUILD_SHARED_LIBS OFF) set(CMAKE_CXX_STANDARD 17) @@ -18,7 +18,7 @@ add_subdirectory(../external/parallel-rdp prdp) add_subdirectory(../external/imgui imgui) add_subdirectory(../external/nativefiledialog-extended nfd) -add_executable(natsukashii +add_executable(gadolinium ${CORE_SOURCES} ${CORE_HEADERS} ${FRONTEND_SOURCES} @@ -29,7 +29,7 @@ add_executable(natsukashii n64/Scheduler.cpp n64/Scheduler.hpp) -target_include_directories(natsukashii PRIVATE +target_include_directories(gadolinium PRIVATE . n64 n64/core @@ -58,4 +58,4 @@ if(WIN32) add_compile_options(/EHa) endif() -target_link_libraries(natsukashii PRIVATE SDL2::SDL2main SDL2::SDL2 capstone-static nfd parallel-rdp fmt::fmt imgui nlohmann_json::nlohmann_json) \ No newline at end of file +target_link_libraries(gadolinium PRIVATE SDL2::SDL2main SDL2::SDL2 capstone-static nfd parallel-rdp fmt::fmt imgui nlohmann_json::nlohmann_json) \ No newline at end of file diff --git a/src/frontend/imgui/Window.cpp b/src/frontend/imgui/Window.cpp index fff8821a..4d549f8b 100644 --- a/src/frontend/imgui/Window.cpp +++ b/src/frontend/imgui/Window.cpp @@ -25,9 +25,9 @@ void Window::InitSDL() { SDL_Init(SDL_INIT_EVERYTHING); n64::InitAudio(); - windowTitle = "natsukashii"; + windowTitle = "Gadolinium"; window = SDL_CreateWindow( - "natsukashii", + "Gadolinium", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, @@ -158,7 +158,7 @@ void Window::LoadROM(n64::Core& core, const std::string &path) { name = std::filesystem::path(path).stem().string(); } - windowTitle = "natsukashii - " + name; + windowTitle = "Gadolinium - " + name; shadowWindowTitle = windowTitle; SDL_SetWindowTitle(window, windowTitle.c_str()); @@ -210,7 +210,7 @@ void Window::Render(n64::Core& core) { LoadROM(core, core.rom); } if (ImGui::MenuItem("Stop")) { - windowTitle = "natsukashii"; + windowTitle = "Gadolinium"; SDL_SetWindowTitle(window, windowTitle.c_str()); core.Stop(); } diff --git a/src/n64/core/Cpu.hpp b/src/n64/core/Cpu.hpp index 134034c7..25761b7b 100644 --- a/src/n64/core/Cpu.hpp +++ b/src/n64/core/Cpu.hpp @@ -20,11 +20,13 @@ struct Cpu { void Step(Mem&); Registers regs; private: + u64 cop2Latch{}; csh handle; void disassembly(u32 instr); friend struct Cop1; + void cop2Decode(u32); void special(Mem&, u32); void regimm(u32); void Exec(Mem&, u32); @@ -113,5 +115,12 @@ private: void ori(u32); void xor_(u32); void xori(u32); + + void mtc2(u32); + void mfc2(u32); + void dmtc2(u32); + void dmfc2(u32); + void ctc2(u32); + void cfc2(u32); }; } diff --git a/src/n64/core/RDP.hpp b/src/n64/core/RDP.hpp index 4fd39dc8..11e0a8d9 100644 --- a/src/n64/core/RDP.hpp +++ b/src/n64/core/RDP.hpp @@ -80,4 +80,4 @@ struct RDP { RunCommand(mi, regs, rsp); } }; -} // natsukashii +} // n64 diff --git a/src/n64/core/cpu/decode.cpp b/src/n64/core/cpu/decode.cpp index 577bf027..bc25b682 100644 --- a/src/n64/core/cpu/decode.cpp +++ b/src/n64/core/cpu/decode.cpp @@ -90,6 +90,23 @@ void Cpu::regimm(u32 instr) { } } +void Cpu::cop2Decode(u32 instr) { + if(!regs.cop0.status.cu2) { + FireException(regs, ExceptionCode::CoprocessorUnusable, 2, regs.oldPC); + return; + } + switch(RS(instr)) { + case 0x00: mfc2(instr); break; + case 0x01: dmfc2(instr); break; + case 0x02: cfc2(instr); break; + case 0x04: mtc2(instr); break; + case 0x05: dmtc2(instr); break; + case 0x06: ctc2(instr); break; + default: + FireException(regs, ExceptionCode::ReservedInstruction, 2, regs.oldPC); + } +} + void Cpu::Exec(Mem& mem, u32 instr) { u8 mask = (instr >> 26) & 0x3f; // 00rr_rccc @@ -115,6 +132,7 @@ void Cpu::Exec(Mem& mem, u32 instr) { case 0x0F: lui(instr); break; case 0x10: regs.cop0.decode(regs, mem, instr); break; case 0x11: regs.cop1.decode(*this, instr); break; + case 0x12: cop2Decode(instr); break; case 0x14: bl(instr, regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); break; case 0x15: bl(instr, regs.gpr[RS(instr)] != regs.gpr[RT(instr)]); break; case 0x16: bl(instr, regs.gpr[RS(instr)] <= 0); break; diff --git a/src/n64/core/cpu/instructions.cpp b/src/n64/core/cpu/instructions.cpp index 595be6e5..3541527e 100644 --- a/src/n64/core/cpu/instructions.cpp +++ b/src/n64/core/cpu/instructions.cpp @@ -777,4 +777,30 @@ void Cpu::trap(bool cond) { FireException(regs, ExceptionCode::Trap, 0, regs.oldPC); } } + +void Cpu::mtc2(u32 instr) { + cop2Latch = regs.gpr[RT(instr)]; +} + +void Cpu::mfc2(u32 instr) { + s32 value = cop2Latch; + regs.gpr[RT(instr)] = value; +} + +void Cpu::dmtc2(u32 instr) { + cop2Latch = regs.gpr[RT(instr)]; +} + +void Cpu::dmfc2(u32 instr) { + regs.gpr[RT(instr)] = cop2Latch; +} + +void Cpu::ctc2(u32) { + +} + +void Cpu::cfc2(u32) { + +} + } \ No newline at end of file diff --git a/src/n64/core/cpu/registers/Cop1.cpp b/src/n64/core/cpu/registers/Cop1.cpp index 01153d93..8bc233e1 100644 --- a/src/n64/core/cpu/registers/Cop1.cpp +++ b/src/n64/core/cpu/registers/Cop1.cpp @@ -61,6 +61,7 @@ void Cop1::decode(Cpu& cpu, u32 instr) { case 0x0D: truncws(regs, instr); break; case 0x0E: ceilws(regs, instr); break; case 0x0F: floorws(regs, instr); break; + case 0x20: FireException(regs, ExceptionCode::FloatingPointError, 2, regs.oldPC); break; case 0x21: cvtds(regs, instr); break; case 0x24: cvtws(regs, instr); break; case 0x25: cvtls(regs, instr); break; @@ -80,7 +81,7 @@ void Cop1::decode(Cpu& cpu, u32 instr) { case 0x3D: ccond(regs, instr, NGE); break; case 0x3E: ccond(regs, instr, LE); break; case 0x3F: ccond(regs, instr, NGT); break; - default: util::panic("Unimplemented COP1 function S[{} {}] ({:08X}) ({:016lX})", mask_fun >> 3, mask_fun & 7, instr, regs.oldPC); + default: util::panic("Unimplemented COP1 function S[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC); } break; case 0x11: // d @@ -102,6 +103,7 @@ void Cop1::decode(Cpu& cpu, u32 instr) { case 0x0E: ceilwd(regs, instr); break; case 0x0F: floorwd(regs, instr); break; case 0x20: cvtsd(regs, instr); break; + case 0x21: FireException(regs, ExceptionCode::FloatingPointError, 2, regs.oldPC); break; case 0x24: cvtwd(regs, instr); break; case 0x25: cvtld(regs, instr); break; case 0x30: ccond(regs, instr, F); break; @@ -120,7 +122,7 @@ void Cop1::decode(Cpu& cpu, u32 instr) { case 0x3D: ccond(regs, instr, NGE); break; case 0x3E: ccond(regs, instr, LE); break; case 0x3F: ccond(regs, instr, NGT); break; - default: util::panic("Unimplemented COP1 function D[{} {}] ({:08X}) ({:016lX})", mask_fun >> 3, mask_fun & 7, instr, regs.oldPC); + default: util::panic("Unimplemented COP1 function D[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC); } break; case 0x14: // w @@ -131,7 +133,8 @@ void Cop1::decode(Cpu& cpu, u32 instr) { case 0x06: movw(regs, instr); break; case 0x20: cvtsw(regs, instr); break; case 0x21: cvtdw(regs, instr); break; - default: util::panic("Unimplemented COP1 function W[{} {}] ({:08X}) ({:016lX})", mask_fun >> 3, mask_fun & 7, instr, regs.oldPC); + case 0x24: FireException(regs, ExceptionCode::FloatingPointError, 2, regs.oldPC); break; + default: util::panic("Unimplemented COP1 function W[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC); } break; case 0x15: // l @@ -142,7 +145,8 @@ void Cop1::decode(Cpu& cpu, u32 instr) { case 0x06: movl(regs, instr); break; case 0x20: cvtsl(regs, instr); break; case 0x21: cvtdl(regs, instr); break; - default: util::panic("Unimplemented COP1 function L[{} {}] ({:08X}) ({:016lX})", mask_fun >> 3, mask_fun & 7, instr, regs.oldPC); + case 0x24: FireException(regs, ExceptionCode::FloatingPointError, 2, regs.oldPC); break; + default: util::panic("Unimplemented COP1 function L[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC); } break; default: util::panic("Unimplemented COP1 instruction {} {}", mask_sub >> 3, mask_sub & 7); diff --git a/src/n64/core/cpu/registers/cop1instructions.cpp b/src/n64/core/cpu/registers/cop1instructions.cpp index a79d398b..a8cb860d 100644 --- a/src/n64/core/cpu/registers/cop1instructions.cpp +++ b/src/n64/core/cpu/registers/cop1instructions.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include @@ -228,7 +227,7 @@ inline bool CalculateCondition(Registers& regs, T fs, T ft, CompConds cond) { if(std::isnan(fs) || std::isnan(ft)) { regs.cop1.fcr31.flag_invalid_operation = true; regs.cop1.fcr31.cause_invalid_operation = true; - FireException(regs, ExceptionCode::FloatingPointError, 0, regs.oldPC); + FireException(regs, ExceptionCode::FloatingPointError, 1, regs.oldPC); } return CalculateCondition(regs, fs, ft, static_cast(cond - 8)); diff --git a/src/n64/core/mmio/SI.cpp b/src/n64/core/mmio/SI.cpp index 097c9def..4244cd86 100644 --- a/src/n64/core/mmio/SI.cpp +++ b/src/n64/core/mmio/SI.cpp @@ -36,9 +36,6 @@ void DMA(Mem& mem, Registers& regs) { MMIO& mmio = mem.mmio; SI& si = mmio.si; si.status.dmaBusy = false; - if(si.status.dmaBusy) { - return; - } if(si.toDram) { ProcessPIFCommands(mem.pifRam, si.controller, mem); for(int i = 0; i < 64; i++) {