mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-09 15:45:40 +12:00
commit
52314c188c
7 changed files with 103 additions and 68 deletions
|
@ -1,12 +1,15 @@
|
|||
#pragma once
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <vector>
|
||||
|
||||
#include "helpers.hpp"
|
||||
#include "memory.hpp"
|
||||
#include "services/hid.hpp"
|
||||
|
||||
class ActionReplay {
|
||||
using Cheat = std::vector<u32>; // 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,10 +18,14 @@ 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;
|
||||
HIDService& hid;
|
||||
|
||||
// Has the cheat ended?
|
||||
bool running = false;
|
||||
|
@ -36,8 +43,10 @@ class ActionReplay {
|
|||
void write16(u32 addr, u16 value);
|
||||
void write32(u32 addr, u32 value);
|
||||
|
||||
void pushConditionBlock(bool condition);
|
||||
|
||||
public:
|
||||
ActionReplay(Memory& mem);
|
||||
ActionReplay(Memory& mem, HIDService& hid);
|
||||
void runCheat(const Cheat& cheat);
|
||||
void reset();
|
||||
};
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "action_replay.hpp"
|
||||
#include "helpers.hpp"
|
||||
#include "services/hid.hpp"
|
||||
|
||||
// Forward-declare this since it's just passed and we don't want to include memory.hpp and increase compile time
|
||||
class Memory;
|
||||
|
@ -20,12 +21,12 @@ class Cheats {
|
|||
std::vector<u32> instructions;
|
||||
};
|
||||
|
||||
Cheats(Memory& mem);
|
||||
Cheats(Memory& mem, HIDService& hid);
|
||||
void addCheat(const Cheat& cheat);
|
||||
void reset();
|
||||
void run();
|
||||
|
||||
private:
|
||||
ActionReplay ar; // An ActionReplay cheat machine for executing CTRPF codes
|
||||
ActionReplay ar; // An ActionReplay cheat machine for executing CTRPF codes
|
||||
std::vector<Cheat> cheats;
|
||||
};
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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; }
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "action_replay.hpp"
|
||||
|
||||
ActionReplay::ActionReplay(Memory& mem) : mem(mem) { reset(); }
|
||||
ActionReplay::ActionReplay(Memory& mem, HIDService& hid) : mem(mem), hid(hid) { reset(); }
|
||||
|
||||
void ActionReplay::reset() {
|
||||
// Default value of storage regs is 0
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -110,6 +119,9 @@ void ActionReplay::executeDType(const Cheat& cheat, u32 instruction) {
|
|||
// DD000000 XXXXXXXX - if KEYPAD has value XXXXXXXX execute next block
|
||||
case 0xDD000000: {
|
||||
const u32 mask = cheat[pc++];
|
||||
const u32 buttons = hid.getOldButtons();
|
||||
|
||||
pushConditionBlock((buttons & mask) == mask);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -162,13 +174,37 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
void ActionReplay::pushConditionBlock(bool condition) {
|
||||
if (ifStackIndex >= 32) {
|
||||
Helpers::warn("ActionReplay if stack overflowed");
|
||||
running = false;
|
||||
return;
|
||||
}
|
||||
|
||||
ifStack[ifStackIndex++] = condition;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
#include "cheats.hpp"
|
||||
|
||||
Cheats::Cheats(Memory& mem) : ar(mem) { reset(); }
|
||||
Cheats::Cheats(Memory& mem, HIDService& hid) : ar(mem, hid) { reset(); }
|
||||
|
||||
void Cheats::reset() {
|
||||
cheats.clear(); // Unload loaded cheats
|
||||
|
|
|
@ -16,7 +16,7 @@ __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 1;
|
|||
|
||||
Emulator::Emulator()
|
||||
: config(std::filesystem::current_path() / "config.toml"), kernel(cpu, memory, gpu), cpu(memory, kernel), gpu(memory, config),
|
||||
memory(cpu.getTicksRef()), cheats(memory) {
|
||||
memory(cpu.getTicksRef()), cheats(memory, kernel.getServiceManager().getHID()) {
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0) {
|
||||
Helpers::panic("Failed to initialize SDL2");
|
||||
}
|
||||
|
@ -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<u16>(x) - 40;
|
||||
u16 y_converted = static_cast<u16>(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;
|
||||
|
|
Loading…
Add table
Reference in a new issue