Controller + avoid disassembling if in Release build + minor things
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,3 +10,4 @@ roms/
|
||||
.vscode/
|
||||
vgcore.*
|
||||
*.txt
|
||||
*.data
|
||||
@@ -4,6 +4,7 @@ set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED true)
|
||||
|
||||
add_compile_definitions(VULKAN_DEBUG)
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/../resources DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_subdirectory(n64)
|
||||
add_subdirectory(frontend)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
void App::Run() {
|
||||
// Main loop
|
||||
bool done = false;
|
||||
const u8* state = SDL_GetKeyboardState(nullptr);
|
||||
while (!done) {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
@@ -14,6 +15,15 @@ void App::Run() {
|
||||
case SDL_WINDOWEVENT:
|
||||
done = window.gotClosed(event);
|
||||
break;
|
||||
case SDL_CONTROLLERDEVICEADDED: {
|
||||
const int index = event.cdevice.which;
|
||||
core.gamepad = SDL_GameControllerOpen(index);
|
||||
core.gamepadConnected = true;
|
||||
} break;
|
||||
case SDL_CONTROLLERDEVICEREMOVED:
|
||||
SDL_GameControllerClose(core.gamepad);
|
||||
core.gamepadConnected = false;
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
switch(event.key.keysym.sym) {
|
||||
case SDLK_o: {
|
||||
@@ -28,7 +38,7 @@ void App::Run() {
|
||||
} break;
|
||||
}
|
||||
|
||||
core.PollInputs(event);
|
||||
core.UpdateController(state);
|
||||
}
|
||||
|
||||
core.Run(window);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
struct App {
|
||||
App() : window(core) {};
|
||||
~App() = default;
|
||||
void Run();
|
||||
inline void LoadROM(const std::string& path) {
|
||||
core.LoadROM(path);
|
||||
|
||||
@@ -174,6 +174,9 @@ Window::~Window() {
|
||||
vkDestroyDescriptorPool(device, descriptorPool, nullptr);
|
||||
vkDestroyDevice(device, nullptr);
|
||||
vkDestroyInstance(instance, nullptr);
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_DestroyWindow(g_Window);
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
ImDrawData* Window::Present(n64::Core& core) {
|
||||
|
||||
106
src/n64/Core.cpp
106
src/n64/Core.cpp
@@ -1,6 +1,8 @@
|
||||
#include <Core.hpp>
|
||||
#include <ParallelRDPWrapper.hpp>
|
||||
#include <Window.hpp>
|
||||
#include <algorithm>
|
||||
#include <util.hpp>
|
||||
|
||||
namespace n64 {
|
||||
Core::Core() {
|
||||
@@ -21,14 +23,24 @@ void Core::LoadROM(const std::string& rom) {
|
||||
|
||||
void Core::Run(Window& window) {
|
||||
MMIO& mmio = mem.mmio;
|
||||
for(mmio.vi.current = 0; mmio.vi.current < 262; mmio.vi.current++) {
|
||||
int cycles = 0;
|
||||
for(int field = 0; field < mmio.vi.numFields; field++) {
|
||||
if(romLoaded) {
|
||||
for (int i = 0; i < 6000; i++) {
|
||||
cpu.Step(mem);
|
||||
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
|
||||
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
|
||||
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
|
||||
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
|
||||
//timerInstructions.Start();
|
||||
for (int i = 0; i < mmio.vi.numHalflines; i++) {
|
||||
if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) {
|
||||
InterruptRaise(mmio.mi, cpu.regs, Interrupt::VI);
|
||||
}
|
||||
|
||||
for(;cycles <= mmio.vi.cyclesPerHalfline; cycles++) {
|
||||
cpu.Step(mem);
|
||||
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
|
||||
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
|
||||
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
|
||||
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
|
||||
}
|
||||
|
||||
cycles -= mmio.vi.cyclesPerHalfline;
|
||||
}
|
||||
|
||||
if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) {
|
||||
@@ -42,7 +54,85 @@ void Core::Run(Window& window) {
|
||||
}
|
||||
}
|
||||
|
||||
void Core::PollInputs(SDL_Event e) {
|
||||
#define GET_BUTTON(gamepad, i) SDL_GameControllerGetButton(gamepad, i)
|
||||
#define GET_AXIS(gamepad, axis) SDL_GameControllerGetAxis(gamepad, axis)
|
||||
|
||||
void Core::UpdateController(const u8* state) {
|
||||
Controller& controller = mem.mmio.si.controller;
|
||||
if(gamepadConnected) {
|
||||
controller.b1 = 0;
|
||||
controller.b2 = 0;
|
||||
controller.b3 = 0;
|
||||
controller.b4 = 0;
|
||||
|
||||
bool A = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_A);
|
||||
bool B = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_X);
|
||||
bool Z = GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_TRIGGERLEFT) == 32767;
|
||||
bool START = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_START);
|
||||
bool DUP = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_DPAD_UP);
|
||||
bool DDOWN = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_DPAD_DOWN);
|
||||
bool DLEFT = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_DPAD_LEFT);
|
||||
bool DRIGHT = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
|
||||
bool L = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
|
||||
bool R = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
|
||||
bool CUP = GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_RIGHTY) == 32767;
|
||||
bool CDOWN = GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_RIGHTY) == -32768;
|
||||
bool CLEFT = GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_RIGHTX) == -32768;
|
||||
bool CRIGHT = GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_RIGHTX) == 32767;
|
||||
|
||||
controller.b1 = (A << 7) | (B << 6) | (Z << 5) | (START << 4) |
|
||||
(DUP << 3) | (DDOWN << 2) | (DLEFT << 1) | DRIGHT;
|
||||
|
||||
controller.b2 = ((START && L && R) << 7) | (0 << 6) | (L << 5) | (R << 4) |
|
||||
(CUP << 3) | (CDOWN << 2) | (CLEFT << 1) | CRIGHT;
|
||||
|
||||
s8 xaxis = (s8)std::clamp((GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_LEFTX) >> 8), -127, 127);
|
||||
s8 yaxis = (s8)std::clamp(-(GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_LEFTY) >> 8), -127, 127);
|
||||
|
||||
controller.b3 = xaxis;
|
||||
controller.b4 = yaxis;
|
||||
|
||||
if((controller.b2 >> 7) & 1) {
|
||||
controller.b1 &= ~0x10;
|
||||
controller.b3 = 0;
|
||||
controller.b4 = 0;
|
||||
}
|
||||
} else {
|
||||
controller.b1 = 0;
|
||||
controller.b2 = 0;
|
||||
controller.b3 = 0;
|
||||
controller.b4 = 0;
|
||||
|
||||
controller.b1 =
|
||||
(state[SDL_SCANCODE_X] << 7) |
|
||||
(state[SDL_SCANCODE_C] << 6) |
|
||||
(state[SDL_SCANCODE_Z] << 5) |
|
||||
(state[SDL_SCANCODE_RETURN] << 4) |
|
||||
(state[SDL_SCANCODE_KP_8] << 3) |
|
||||
(state[SDL_SCANCODE_KP_5] << 2) |
|
||||
(state[SDL_SCANCODE_KP_4] << 1) |
|
||||
(state[SDL_SCANCODE_KP_6]);
|
||||
controller.b2 =
|
||||
((state[SDL_SCANCODE_RETURN] && state[SDL_SCANCODE_A] && state[SDL_SCANCODE_S]) << 7) |
|
||||
(0 << 6) |
|
||||
(state[SDL_SCANCODE_A] << 5) |
|
||||
(state[SDL_SCANCODE_S] << 4) |
|
||||
(state[SDL_SCANCODE_I] << 3) |
|
||||
(state[SDL_SCANCODE_J] << 2) |
|
||||
(state[SDL_SCANCODE_K] << 1) |
|
||||
(state[SDL_SCANCODE_L]);
|
||||
|
||||
s8 xaxis = state[SDL_SCANCODE_LEFT] ? -128 : (state[SDL_SCANCODE_RIGHT] ? 127 : 0);
|
||||
s8 yaxis = state[SDL_SCANCODE_DOWN] ? -128 : (state[SDL_SCANCODE_UP] ? 127 : 0);
|
||||
|
||||
controller.b3 = xaxis;
|
||||
controller.b4 = yaxis;
|
||||
|
||||
if((controller.b2 >> 7) & 1) {
|
||||
controller.b1 &= ~0x10;
|
||||
controller.b3 = 0;
|
||||
controller.b4 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,11 @@ struct Core {
|
||||
void Reset();
|
||||
void LoadROM(const std::string&);
|
||||
void Run(Window&);
|
||||
void PollInputs(SDL_Event);
|
||||
void UpdateController(const u8*);
|
||||
VI& GetVI() { return mem.mmio.vi; }
|
||||
bool romLoaded = false;
|
||||
SDL_GameController* gamepad;
|
||||
bool gamepadConnected = false;
|
||||
private:
|
||||
friend struct ::Window;
|
||||
Mem mem;
|
||||
|
||||
@@ -99,7 +99,9 @@ inline void HandleInterrupt(Registers& regs) {
|
||||
}
|
||||
|
||||
void Cpu::LogInstruction(u32 instruction) {
|
||||
#ifndef NDEBUG
|
||||
count = cs_disasm(handle, reinterpret_cast<u8*>(&instruction), 4, regs.pc, 0, &insn);
|
||||
#endif
|
||||
|
||||
if (count > 0) {
|
||||
for(auto j = 0; j < count; j++) {
|
||||
@@ -113,13 +115,14 @@ void Cpu::LogInstruction(u32 instruction) {
|
||||
|
||||
void Cpu::Step(Mem& mem) {
|
||||
regs.gpr[0] = 0;
|
||||
|
||||
regs.prevDelaySlot = regs.delaySlot;
|
||||
regs.delaySlot = false;
|
||||
|
||||
CheckCompareInterrupt(mem.mmio.mi, regs);
|
||||
|
||||
u32 instruction = mem.Read<u32>(regs, regs.pc, regs.pc);
|
||||
LogInstruction(instruction);
|
||||
//LogInstruction(instruction);
|
||||
|
||||
HandleInterrupt(regs);
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ inline void special(RSP& rsp, u32 instr) {
|
||||
//case 0x24: rsp.and_(instr); break;
|
||||
//case 0x25: rsp.or_(instr); break;
|
||||
//case 0x27: rsp.nor(instr); break;
|
||||
default: util::panic("Unhandled RSP special instruction %d %d\n", (mask >> 3) & 7, mask & 7);
|
||||
default: util::panic("Unhandled RSP special instruction {} {}\n", (mask >> 3) & 7, mask & 7);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ inline void regimm(RSP& rsp, u32 instr) {
|
||||
switch(mask) {
|
||||
//case 0x00: rsp.b(instr, (s32)rsp.gpr[RS(instr)] < 0); break;
|
||||
//case 0x01: rsp.b(instr, (s32)rsp.gpr[RS(instr)] >= 0); break;
|
||||
default: util::panic("Unhandled RSP regimm instruction %d %d\n", (mask >> 3) & 3, mask & 7);
|
||||
default: util::panic("Unhandled RSP regimm instruction {} {}\n", (mask >> 3) & 3, mask & 7);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ inline void lwc2(RSP& rsp, u32 instr) {
|
||||
u8 mask = (instr >> 11) & 0x1F;
|
||||
switch(mask) {
|
||||
//case 0x04: rsp.lqv(instr); break;
|
||||
default: util::panic("Unhandled RSP LWC2 %d %d\n", (mask >> 3) & 3, mask & 7);
|
||||
default: util::panic("Unhandled RSP LWC2 {} {}\n", (mask >> 3) & 3, mask & 7);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ inline void swc2(RSP& rsp, u32 instr) {
|
||||
u8 mask = (instr >> 11) & 0x1F;
|
||||
switch(mask) {
|
||||
//case 0x04: rsp.sqv(instr); break;
|
||||
default: util::panic("Unhandled RSP SWC2 %d %d\n", (mask >> 3) & 3, mask & 7);
|
||||
default: util::panic("Unhandled RSP SWC2 {} {}\n", (mask >> 3) & 3, mask & 7);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ inline void cop2(RSP& rsp, u32 instr) {
|
||||
case 0x00:
|
||||
switch(mask_sub) {
|
||||
//case 0x02: rsp.cfc2(instr); break;
|
||||
default: util::panic("Unhandled RSP COP2 sub %d %d\n", (mask_sub >> 3) & 3, mask_sub & 3);
|
||||
default: util::panic("Unhandled RSP COP2 sub {} {}\n", (mask_sub >> 3) & 3, mask_sub & 3);
|
||||
}
|
||||
break;
|
||||
//case 0x13: rsp.vabs(instr); break;
|
||||
@@ -64,7 +64,7 @@ inline void cop2(RSP& rsp, u32 instr) {
|
||||
//case 0x21: rsp.veq(instr); break;
|
||||
//case 0x22: rsp.vne(instr); break;
|
||||
//case 0x33: rsp.vmov(instr); break;
|
||||
default: util::panic("Unhandled RSP COP2 %d %d\n", (mask >> 3) & 7, mask & 7);
|
||||
default: util::panic("Unhandled RSP COP2 {} {}\n", (mask >> 3) & 7, mask & 7);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ inline void cop0(MI& mi, Registers& regs, RSP& rsp, RDP& rdp, u32 instr) {
|
||||
switch(mask) {
|
||||
//case 0x00: rsp.mfc0(rdp, instr); break;
|
||||
//case 0x04: rsp.mtc0(mi, regs, rdp, instr); break;
|
||||
default: util::panic("Unhandled RSP COP0 %d %d\n", (mask >> 3) & 3, mask & 7);
|
||||
default: util::panic("Unhandled RSP COP0 {} {}\n", (mask >> 3) & 3, mask & 7);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ void RSP::Exec(MI &mi, Registers ®s, RDP &rdp, u32 instr) {
|
||||
//case 0x2B: sw(instr); break;
|
||||
//case 0x32: lwc2(*this, instr); break;
|
||||
//case 0x3A: swc2(*this, instr); break;
|
||||
default: util::panic("Unhandled RSP instruction %d %d\n", (mask >> 3) & 7, mask & 7);
|
||||
default: util::panic("Unhandled RSP instruction {} {}\n", (mask >> 3) & 7, mask & 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src/util.hpp
24
src/util.hpp
@@ -6,8 +6,13 @@
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
|
||||
namespace util {
|
||||
using SteadyClock = std::chrono::steady_clock;
|
||||
using DurationMillis = std::chrono::duration<double, std::milli>;
|
||||
using TimePoint = std::chrono::time_point<SteadyClock, DurationMillis>;
|
||||
|
||||
enum MessageType : u8 {
|
||||
Info, Warn, Error
|
||||
};
|
||||
@@ -46,6 +51,25 @@ constexpr void logdebug(const std::string& fmt, Args... args) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#define TIMER(name) \
|
||||
struct Timer##name { \
|
||||
util::TimePoint start, end; \
|
||||
Timer##name() {} \
|
||||
~Timer##name() {} \
|
||||
void Start() { \
|
||||
start = util::SteadyClock::now(); \
|
||||
} \
|
||||
\
|
||||
void End() { \
|
||||
end = util::SteadyClock::now(); \
|
||||
} \
|
||||
\
|
||||
void PrintDuration() { \
|
||||
auto diff = end - start; \
|
||||
util::info(#name + std::string(" took {:.3f}ms to run\n"), diff.count()); \
|
||||
} \
|
||||
}
|
||||
|
||||
template <typename T, bool HToBE = false>
|
||||
[[maybe_unused]] auto GetSwapFunc(T num) -> T {
|
||||
static_assert(sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "GetSwapFunc used with invalid size!");
|
||||
|
||||
Reference in New Issue
Block a user