From d007b2d7807965e6ba1ff81db471af29ef396ff8 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Fri, 21 Jul 2023 00:55:08 +0300 Subject: [PATCH] Emulator cleanup, add AR conditionals --- include/action_replay.hpp | 7 ++- include/services/hid.hpp | 1 + include/services/service_manager.hpp | 14 +---- src/core/action_replay.cpp | 27 +++++++- src/emulator.cpp | 92 ++++++++++++++-------------- 5 files changed, 79 insertions(+), 62 deletions(-) diff --git a/include/action_replay.hpp b/include/action_replay.hpp index a7cce230..d9499cee 100644 --- a/include/action_replay.hpp +++ b/include/action_replay.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include "helpers.hpp" @@ -7,6 +8,7 @@ class ActionReplay { using Cheat = std::vector; // A cheat is really just a bunch of 64-bit opcodes neatly encoded into 32-bit chunks + static constexpr size_t ifStackSize = 32; // TODO: How big is this, really? u32 offset1, offset2; // Memory offset registers. Non-persistent. u32 data1, data2; // Data offset registers. Non-persistent. @@ -15,7 +17,10 @@ class ActionReplay { // When an instruction does not specify which offset or data register to use, we use the "active" one // Which is by default #1 and may be changed by certain AR operations u32 *activeOffset, *activeData, *activeStorage; - + u32 ifStackIndex; // Our index in the if stack. Shows how many entries we have at the moment. + u32 loopStackIndex; // Same but for loops + std::bitset<32> ifStack; + // Program counter u32 pc = 0; Memory& mem; diff --git a/include/services/hid.hpp b/include/services/hid.hpp index 6a3aab95..23a36ec6 100644 --- a/include/services/hid.hpp +++ b/include/services/hid.hpp @@ -91,6 +91,7 @@ class HIDService { void pressKey(u32 mask) { newButtons |= mask; } void releaseKey(u32 mask) { newButtons &= ~mask; } + u32 getOldButtons() { return oldButtons; } s16 getCirclepadX() { return circlePadX; } s16 getCirclepadY() { return circlePadY; } diff --git a/include/services/service_manager.hpp b/include/services/service_manager.hpp index 1d93641c..51d6d554 100644 --- a/include/services/service_manager.hpp +++ b/include/services/service_manager.hpp @@ -90,17 +90,5 @@ class ServiceManager { void signalDSPEvents() { dsp.signalEvents(); } // Input function wrappers - void pressKey(u32 key) { hid.pressKey(key); } - void releaseKey(u32 key) { hid.releaseKey(key); } - s16 getCirclepadX() { return hid.getCirclepadX(); } - s16 getCirclepadY() { return hid.getCirclepadY(); } - void setCirclepadX(s16 x) { hid.setCirclepadX(x); } - void setCirclepadY(s16 y) { hid.setCirclepadY(y); } - void updateInputs(u64 currentTimestamp) { hid.updateInputs(currentTimestamp); } - void setTouchScreenPress(u16 x, u16 y) { hid.setTouchScreenPress(x, y); } - void releaseTouchScreen() { hid.releaseTouchScreen(); } - - void setRoll(s16 roll) { hid.setRoll(roll); } - void setPitch(s16 pitch) { hid.setPitch(pitch); } - void setYaw(s16 yaw) { hid.setYaw(yaw); } + HIDService& getHID() { return hid; } }; diff --git a/src/core/action_replay.cpp b/src/core/action_replay.cpp index cc3f6d20..2db0ace3 100644 --- a/src/core/action_replay.cpp +++ b/src/core/action_replay.cpp @@ -15,6 +15,8 @@ void ActionReplay::runCheat(const Cheat& cheat) { // Set offset and data registers to 0 at the start of a cheat data1 = data2 = offset1 = offset2 = 0; pc = 0; + ifStackIndex = 0; + loopStackIndex = 0; running = true; activeOffset = &offset1; @@ -25,9 +27,16 @@ void ActionReplay::runCheat(const Cheat& cheat) { if (pc + 1 >= cheat.size()) { return; } - // Fetch instruction const u32 instruction = cheat[pc++]; + + // Instructions D0000000 00000000 and D2000000 00000000 are unconditional + bool isUnconditional = cheat[pc] == 0 && (instruction == 0xD0000000 || instruction == 0xD2000000); + if (ifStackIndex > 0 && !isUnconditional && !ifStack[ifStackIndex - 1]) { + pc++; // Eat up dummy word + continue; // Skip conditional instructions where the condition is false + } + runInstruction(cheat, instruction); } } @@ -162,13 +171,27 @@ void ActionReplay::executeDType(const Cheat& cheat, u32 instruction) { case 0x00020000: storage1 = data1; break; case 0x00020001: storage2 = data2; break; default: - Helpers::warn("Unknown ActionReplay data operation"); + Helpers::warn("Unknown ActionReplay data operation: %08X", subopcode); running = false; break; } break; } + // Control flow block operations + case 0xD2000000: { + const u32 subopcode = cheat[pc++]; + switch (subopcode) { + // Ends all loop/execute blocks + case 0: + loopStackIndex = 0; + ifStackIndex = 0; + break; + default: Helpers::panic("Unknown ActionReplay control flow operation: %08X", subopcode); break; + } + break; + } + default: Helpers::panic("ActionReplay: Unimplemented d-type opcode: %08X", instruction); break; } } \ No newline at end of file diff --git a/src/emulator.cpp b/src/emulator.cpp index ff9fc22f..39ab022c 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -105,7 +105,7 @@ void Emulator::run() { while (running) { runFrame(); - ServiceManager& srv = kernel.getServiceManager(); + HIDService& hid = kernel.getServiceManager().getHID(); SDL_Event event; while (SDL_PollEvent(&event)) { @@ -121,41 +121,41 @@ void Emulator::run() { if (romType == ROMType::None) break; switch (event.key.keysym.sym) { - case SDLK_l: srv.pressKey(Keys::A); break; - case SDLK_k: srv.pressKey(Keys::B); break; - case SDLK_o: srv.pressKey(Keys::X); break; - case SDLK_i: srv.pressKey(Keys::Y); break; + case SDLK_l: hid.pressKey(Keys::A); break; + case SDLK_k: hid.pressKey(Keys::B); break; + case SDLK_o: hid.pressKey(Keys::X); break; + case SDLK_i: hid.pressKey(Keys::Y); break; - case SDLK_q: srv.pressKey(Keys::L); break; - case SDLK_p: srv.pressKey(Keys::R); break; + case SDLK_q: hid.pressKey(Keys::L); break; + case SDLK_p: hid.pressKey(Keys::R); break; - case SDLK_RIGHT: srv.pressKey(Keys::Right); break; - case SDLK_LEFT: srv.pressKey(Keys::Left); break; - case SDLK_UP: srv.pressKey(Keys::Up); break; - case SDLK_DOWN: srv.pressKey(Keys::Down); break; + case SDLK_RIGHT: hid.pressKey(Keys::Right); break; + case SDLK_LEFT: hid.pressKey(Keys::Left); break; + case SDLK_UP: hid.pressKey(Keys::Up); break; + case SDLK_DOWN: hid.pressKey(Keys::Down); break; case SDLK_w: - srv.setCirclepadY(0x9C); + hid.setCirclepadY(0x9C); keyboardAnalogY = true; break; case SDLK_a: - srv.setCirclepadX(-0x9C); + hid.setCirclepadX(-0x9C); keyboardAnalogX = true; break; case SDLK_s: - srv.setCirclepadY(-0x9C); + hid.setCirclepadY(-0x9C); keyboardAnalogY = true; break; case SDLK_d: - srv.setCirclepadX(0x9C); + hid.setCirclepadX(0x9C); keyboardAnalogX = true; break; - case SDLK_RETURN: srv.pressKey(Keys::Start); break; - case SDLK_BACKSPACE: srv.pressKey(Keys::Select); break; + case SDLK_RETURN: hid.pressKey(Keys::Start); break; + case SDLK_BACKSPACE: hid.pressKey(Keys::Select); break; } break; @@ -163,34 +163,34 @@ void Emulator::run() { if (romType == ROMType::None) break; switch (event.key.keysym.sym) { - case SDLK_l: srv.releaseKey(Keys::A); break; - case SDLK_k: srv.releaseKey(Keys::B); break; - case SDLK_o: srv.releaseKey(Keys::X); break; - case SDLK_i: srv.releaseKey(Keys::Y); break; + case SDLK_l: hid.releaseKey(Keys::A); break; + case SDLK_k: hid.releaseKey(Keys::B); break; + case SDLK_o: hid.releaseKey(Keys::X); break; + case SDLK_i: hid.releaseKey(Keys::Y); break; - case SDLK_q: srv.releaseKey(Keys::L); break; - case SDLK_p: srv.releaseKey(Keys::R); break; + case SDLK_q: hid.releaseKey(Keys::L); break; + case SDLK_p: hid.releaseKey(Keys::R); break; - case SDLK_RIGHT: srv.releaseKey(Keys::Right); break; - case SDLK_LEFT: srv.releaseKey(Keys::Left); break; - case SDLK_UP: srv.releaseKey(Keys::Up); break; - case SDLK_DOWN: srv.releaseKey(Keys::Down); break; + case SDLK_RIGHT: hid.releaseKey(Keys::Right); break; + case SDLK_LEFT: hid.releaseKey(Keys::Left); break; + case SDLK_UP: hid.releaseKey(Keys::Up); break; + case SDLK_DOWN: hid.releaseKey(Keys::Down); break; // Err this is probably not ideal case SDLK_w: case SDLK_s: - srv.setCirclepadY(0); + hid.setCirclepadY(0); keyboardAnalogY = false; break; case SDLK_a: case SDLK_d: - srv.setCirclepadX(0); + hid.setCirclepadX(0); keyboardAnalogX = false; break; - case SDLK_RETURN: srv.releaseKey(Keys::Start); break; - case SDLK_BACKSPACE: srv.releaseKey(Keys::Select); break; + case SDLK_RETURN: hid.releaseKey(Keys::Start); break; + case SDLK_BACKSPACE: hid.releaseKey(Keys::Select); break; } break; @@ -207,9 +207,9 @@ void Emulator::run() { u16 x_converted = static_cast(x) - 40; u16 y_converted = static_cast(y) - 240; - srv.setTouchScreenPress(x_converted, y_converted); + hid.setTouchScreenPress(x_converted, y_converted); } else { - srv.releaseTouchScreen(); + hid.releaseTouchScreen(); } } else if (event.button.button == SDL_BUTTON_RIGHT) { holdingRightClick = true; @@ -221,7 +221,7 @@ void Emulator::run() { if (romType == ROMType::None) break; if (event.button.button == SDL_BUTTON_LEFT) { - srv.releaseTouchScreen(); + hid.releaseTouchScreen(); } else if (event.button.button == SDL_BUTTON_RIGHT) { holdingRightClick = false; } @@ -264,9 +264,9 @@ void Emulator::run() { if (key != 0) { if (event.cbutton.state == SDL_PRESSED) { - srv.pressKey(key); + hid.pressKey(key); } else { - srv.releaseKey(key); + hid.releaseKey(key); } } break; @@ -285,8 +285,8 @@ void Emulator::run() { // So up until then, we will set the gyroscope euler angles to fixed values based on the direction of the relative motion const s32 roll = motionX > 0 ? 0x7f : -0x7f; const s32 pitch = motionY > 0 ? 0x7f : -0x7f; - srv.setRoll(roll); - srv.setPitch(pitch); + hid.setRoll(roll); + hid.setPitch(pitch); break; } @@ -313,19 +313,19 @@ void Emulator::run() { // Avoid overriding the keyboard's circlepad input if (abs(stickX) < deadzone && !keyboardAnalogX) { - srv.setCirclepadX(0); + hid.setCirclepadX(0); } else { - srv.setCirclepadX(stickX / div); + hid.setCirclepadX(stickX / div); } if (abs(stickY) < deadzone && !keyboardAnalogY) { - srv.setCirclepadY(0); + hid.setCirclepadY(0); } else { - srv.setCirclepadY(-(stickY / div)); + hid.setCirclepadY(-(stickY / div)); } } - srv.updateInputs(cpu.getTicks()); + hid.updateInputs(cpu.getTicks()); } // Update inputs in the HID module @@ -452,7 +452,7 @@ void Emulator::initGraphicsContext() { gpu.initGraphicsContext(); } void Emulator::pollHttpServer() { std::scoped_lock lock(httpServer.actionMutex); - ServiceManager& srv = kernel.getServiceManager(); + HIDService& hid = kernel.getServiceManager().getHID(); if (httpServer.pendingAction) { switch (httpServer.action) { @@ -460,14 +460,14 @@ void Emulator::pollHttpServer() { case HttpAction::PressKey: if (httpServer.pendingKey != 0) { - srv.pressKey(httpServer.pendingKey); + hid.pressKey(httpServer.pendingKey); httpServer.pendingKey = 0; } break; case HttpAction::ReleaseKey: if (httpServer.pendingKey != 0) { - srv.releaseKey(httpServer.pendingKey); + hid.releaseKey(httpServer.pendingKey); httpServer.pendingKey = 0; } break;