diff --git a/src/cdrom/cdriso.cc b/src/cdrom/cdriso.cc index cf6e7550f..46ff24dbf 100644 --- a/src/cdrom/cdriso.cc +++ b/src/cdrom/cdriso.cc @@ -248,10 +248,12 @@ uint8_t *PCSX::CDRIso::getBuffer() { void PCSX::CDRIso::printTracks() { for (int i = 1; i <= m_numtracks; i++) { - PCSX::g_system->printf( - _("Track %.2d (%s) - Start %.2d:%.2d:%.2d, Length %.2d:%.2d:%.2d\n"), i, - (m_ti[i].type == TrackType::DATA ? "DATA" : m_ti[i].cddatype == trackinfo::CCDDA ? "CZDA" : "CDDA"), - m_ti[i].start.m, m_ti[i].start.s, m_ti[i].start.f, m_ti[i].length.m, m_ti[i].length.s, m_ti[i].length.f); + PCSX::g_system->printf(_("Track %.2d (%s) - Start %.2d:%.2d:%.2d, Length %.2d:%.2d:%.2d\n"), i, + (m_ti[i].type == TrackType::DATA ? "DATA" + : m_ti[i].cddatype == trackinfo::CCDDA ? "CZDA" + : "CDDA"), + m_ti[i].start.m, m_ti[i].start.s, m_ti[i].start.f, m_ti[i].length.m, m_ti[i].length.s, + m_ti[i].length.f); } } diff --git a/src/core/DynaRec_aa64/gte_aa64.cc b/src/core/DynaRec_aa64/gte_aa64.cc index c6a1bdac8..af325923b 100644 --- a/src/core/DynaRec_aa64/gte_aa64.cc +++ b/src/core/DynaRec_aa64/gte_aa64.cc @@ -21,8 +21,8 @@ #if defined(DYNAREC_AA64) #include "core/gte.h" -#define COP2_CONTROL_OFFSET(reg) ((uintptr_t)&m_regs.CP2C.r[(reg)] - (uintptr_t)this) -#define COP2_DATA_OFFSET(reg) ((uintptr_t)&m_regs.CP2D.r[(reg)] - (uintptr_t)this) +#define COP2_CONTROL_OFFSET(reg) ((uintptr_t) & m_regs.CP2C.r[(reg)] - (uintptr_t)this) +#define COP2_DATA_OFFSET(reg) ((uintptr_t) & m_regs.CP2D.r[(reg)] - (uintptr_t)this) void DynaRecCPU::recCOP2(uint32_t code) { const auto func = m_recGTE[code & 0x3f]; // Look up the opcode in our decoding LUT diff --git a/src/core/DynaRec_aa64/recompiler.cc b/src/core/DynaRec_aa64/recompiler.cc index 2814d2e0f..0402b8b88 100644 --- a/src/core/DynaRec_aa64/recompiler.cc +++ b/src/core/DynaRec_aa64/recompiler.cc @@ -304,9 +304,9 @@ DynarecCallback DynaRecCPU::recompile(DynarecCallback* callback, uint32_t pc, bo m_linkedPC = std::nullopt; } - gen.Ldr(w0, MemOperand(contextPointer, CYCLE_OFFSET)); // Fetch cycle count from memory - gen.Add(w0, w0, count * PCSX::Emulator::BIAS); // Add block cycles - gen.Str(w0, MemOperand(contextPointer, CYCLE_OFFSET)); // Store cycles back to memory + gen.Ldr(x0, MemOperand(contextPointer, CYCLE_OFFSET)); // Fetch cycle count from memory + gen.Add(x0, x0, count * PCSX::Emulator::BIAS); // Add block cycles + gen.Str(x0, MemOperand(contextPointer, CYCLE_OFFSET)); // Store cycles back to memory // Link block else return to dispatcher if (m_linkedPC && ENABLE_BLOCK_LINKING && m_linkedPC.value() != startingPC) { diff --git a/src/core/DynaRec_aa64/recompiler.h b/src/core/DynaRec_aa64/recompiler.h index cf7d184a0..8cef44117 100644 --- a/src/core/DynaRec_aa64/recompiler.h +++ b/src/core/DynaRec_aa64/recompiler.h @@ -33,13 +33,13 @@ #include "spu/interface.h" #include "tracy/public/tracy/Tracy.hpp" -#define HOST_REG_CACHE_OFFSET(x) ((uintptr_t)&m_hostRegisterCache[(x)] - (uintptr_t)this) -#define GPR_OFFSET(x) ((uintptr_t)&m_regs.GPR.r[(x)] - (uintptr_t)this) -#define COP0_OFFSET(x) ((uintptr_t)&m_regs.CP0.r[(x)] - (uintptr_t)this) -#define PC_OFFSET ((uintptr_t)&m_regs.pc - (uintptr_t)this) -#define LO_OFFSET ((uintptr_t)&m_regs.GPR.n.lo - (uintptr_t)this) -#define HI_OFFSET ((uintptr_t)&m_regs.GPR.n.hi - (uintptr_t)this) -#define CYCLE_OFFSET ((uintptr_t)&m_regs.cycle - (uintptr_t)this) +#define HOST_REG_CACHE_OFFSET(x) ((uintptr_t) & m_hostRegisterCache[(x)] - (uintptr_t)this) +#define GPR_OFFSET(x) ((uintptr_t) & m_regs.GPR.r[(x)] - (uintptr_t)this) +#define COP0_OFFSET(x) ((uintptr_t) & m_regs.CP0.r[(x)] - (uintptr_t)this) +#define PC_OFFSET ((uintptr_t) & m_regs.pc - (uintptr_t)this) +#define LO_OFFSET ((uintptr_t) & m_regs.GPR.n.lo - (uintptr_t)this) +#define HI_OFFSET ((uintptr_t) & m_regs.GPR.n.hi - (uintptr_t)this) +#define CYCLE_OFFSET ((uintptr_t) & m_regs.cycle - (uintptr_t)this) #undef _PC_ #undef _Op_ diff --git a/src/core/DynaRec_x64/gte_x64.cc b/src/core/DynaRec_x64/gte_x64.cc index 70865339c..a61d3920c 100644 --- a/src/core/DynaRec_x64/gte_x64.cc +++ b/src/core/DynaRec_x64/gte_x64.cc @@ -21,8 +21,8 @@ #if defined(DYNAREC_X86_64) #include "core/gte.h" -#define COP2_CONTROL_OFFSET(reg) ((uintptr_t)&m_regs.CP2C.r[(reg)] - (uintptr_t)this) -#define COP2_DATA_OFFSET(reg) ((uintptr_t)&m_regs.CP2D.r[(reg)] - (uintptr_t)this) +#define COP2_CONTROL_OFFSET(reg) ((uintptr_t) & m_regs.CP2C.r[(reg)] - (uintptr_t)this) +#define COP2_DATA_OFFSET(reg) ((uintptr_t) & m_regs.CP2D.r[(reg)] - (uintptr_t)this) void DynaRecCPU::recCOP2(uint32_t code) { const auto func = m_recGTE[m_regs.code & 0x3F]; // Look up the opcode in our decoding LUT diff --git a/src/core/DynaRec_x64/recompiler.cc b/src/core/DynaRec_x64/recompiler.cc index a630df200..4e2bff32d 100644 --- a/src/core/DynaRec_x64/recompiler.cc +++ b/src/core/DynaRec_x64/recompiler.cc @@ -450,7 +450,7 @@ DynarecCallback DynaRecCPU::recompile(uint32_t pc, bool fullLoadDelayEmulation, endProfiling(); } - gen.add(dword[contextPointer + CYCLE_OFFSET], count * PCSX::Emulator::BIAS); // Add block cycles; + gen.add(qword[contextPointer + CYCLE_OFFSET], count * PCSX::Emulator::BIAS); // Add block cycles; if (m_linkedPC && ENABLE_BLOCK_LINKING && m_linkedPC.value() != startingPC) { handleLinking(); } else { @@ -476,7 +476,7 @@ void DynaRecCPU::handleKernelCall() { return; } - const uint32_t pc = m_pc & 0x1fffff; + const uint32_t pc = m_pc & PCSX::g_emulator->getRamMask(); const uint32_t base = (m_pc >> 20) & 0xffc; if ((base != 0x000) && (base != 0x800) && (base != 0xa00)) return; // Mask out the segment, return if not a kernel call vector diff --git a/src/core/DynaRec_x64/recompiler.h b/src/core/DynaRec_x64/recompiler.h index 407659686..6ae789702 100644 --- a/src/core/DynaRec_x64/recompiler.h +++ b/src/core/DynaRec_x64/recompiler.h @@ -36,13 +36,13 @@ #include "spu/interface.h" #include "tracy/public/tracy/Tracy.hpp" -#define HOST_REG_CACHE_OFFSET(x) ((uintptr_t)&m_hostRegisterCache[(x)] - (uintptr_t)this) -#define GPR_OFFSET(x) ((uintptr_t)&m_regs.GPR.r[(x)] - (uintptr_t)this) -#define COP0_OFFSET(x) ((uintptr_t)&m_regs.CP0.r[(x)] - (uintptr_t)this) -#define PC_OFFSET ((uintptr_t)&m_regs.pc - (uintptr_t)this) -#define LO_OFFSET ((uintptr_t)&m_regs.GPR.n.lo - (uintptr_t)this) -#define HI_OFFSET ((uintptr_t)&m_regs.GPR.n.hi - (uintptr_t)this) -#define CYCLE_OFFSET ((uintptr_t)&m_regs.cycle - (uintptr_t)this) +#define HOST_REG_CACHE_OFFSET(x) ((uintptr_t) & m_hostRegisterCache[(x)] - (uintptr_t)this) +#define GPR_OFFSET(x) ((uintptr_t) & m_regs.GPR.r[(x)] - (uintptr_t)this) +#define COP0_OFFSET(x) ((uintptr_t) & m_regs.CP0.r[(x)] - (uintptr_t)this) +#define PC_OFFSET ((uintptr_t) & m_regs.pc - (uintptr_t)this) +#define LO_OFFSET ((uintptr_t) & m_regs.GPR.n.lo - (uintptr_t)this) +#define HI_OFFSET ((uintptr_t) & m_regs.GPR.n.hi - (uintptr_t)this) +#define CYCLE_OFFSET ((uintptr_t) & m_regs.cycle - (uintptr_t)this) #undef _PC_ #undef _Op_ diff --git a/src/core/DynaRec_x64/symbols.cc b/src/core/DynaRec_x64/symbols.cc index cace05b6f..3897ff67a 100644 --- a/src/core/DynaRec_x64/symbols.cc +++ b/src/core/DynaRec_x64/symbols.cc @@ -85,7 +85,7 @@ void DynaRecCPU::makeSymbols() { REGISTER_VARIABLE(m_regs.CP2C.r[i], COP2_controlRegs[i], 4); } - REGISTER_VARIABLE(m_regs.cycle, "m_cycles", 4); + REGISTER_VARIABLE(m_regs.cycle, "m_cycles", 8); REGISTER_VARIABLE(m_regs.pc, "m_pc", 4); for (int i = 0; i < 16; i++) { // Register host register cache diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 456475557..eaac186fc 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -580,7 +580,9 @@ class CDRomImpl : public PCSX::CDRom { if (m_irqRepeated) { m_irqRepeated = 0; - if (m_eCycle > PCSX::g_emulator->m_cpu->m_regs.cycle) { + auto ®s = PCSX::g_emulator->m_cpu->m_regs; + auto diff = regs.intTargets[PCSX::PSXINT_CDR] - regs.cycle; + if (m_eCycle > diff) { scheduleCDIRQ(m_eCycle); goto finish; } diff --git a/src/core/decode_xa.cc b/src/core/decode_xa.cc index ebde9554e..a7bcbf145 100644 --- a/src/core/decode_xa.cc +++ b/src/core/decode_xa.cc @@ -23,7 +23,7 @@ #include "core/decode_xa.h" -//#define FIXED +// #define FIXED #define NOT(_X_) (!(_X_)) #define XACLAMP(_X_, _MI_, _MA_) \ @@ -274,7 +274,7 @@ typedef struct { #define SUB_SUB_VIDEO (1 << 1) // contains video #define SUB_SUB_EOR (1 << 0) // end of record -#define AUDIO_CODING_GET_STEREO(_X_) ((_X_)&3) +#define AUDIO_CODING_GET_STEREO(_X_) ((_X_) & 3) #define AUDIO_CODING_GET_FREQ(_X_) (((_X_) >> 2) & 3) #define AUDIO_CODING_GET_BPS(_X_) (((_X_) >> 4) & 3) #define AUDIO_CODING_GET_EMPHASIS(_X_) (((_X_) >> 6) & 1) diff --git a/src/core/disr3000a.cc b/src/core/disr3000a.cc index 2d1db7c99..05b886ccd 100644 --- a/src/core/disr3000a.cc +++ b/src/core/disr3000a.cc @@ -68,7 +68,7 @@ const char *PCSX::Disasm::s_disRNameCP0[] = { #define declare(n) \ void PCSX::Disasm::n(uint32_t code, uint32_t nextCode, uint32_t pc, bool *skipNext, bool *delaySlotNext) -#define _Funct_ ((code)&0x3F) // The funct part of the instruction register +#define _Funct_ ((code) & 0x3F) // The funct part of the instruction register #define _Rd_ ((code >> 11) & 0x1F) // The rd part of the instruction register #define _Rt_ ((code >> 16) & 0x1F) // The rt part of the instruction register #define _Rs_ ((code >> 21) & 0x1F) // The rs part of the instruction register diff --git a/src/core/gpu.cc b/src/core/gpu.cc index 01ffeaa5e..dc283fc21 100644 --- a/src/core/gpu.cc +++ b/src/core/gpu.cc @@ -533,7 +533,7 @@ void PCSX::GPU::dma(uint32_t madr, uint32_t bcr, uint32_t chcr) { // GPU PSXDMA_LOG("*** DMA 2 - GPU dma chain *** %8.8lx addr = %lx size = %lx\n", chcr, madr, bcr); size = gpuDmaChainSize(madr); - chainedDMAWrite((uint32_t *)PCSX::g_emulator->m_mem->m_wram, madr & 0x1fffff); + chainedDMAWrite((uint32_t *)PCSX::g_emulator->m_mem->m_wram, madr); // Tekken 3 = use 1.0 only (not 1.5x) @@ -685,10 +685,8 @@ void PCSX::GPU::chainedDMAWrite(const uint32_t *memory, uint32_t hwAddr) { s_usedAddr[0] = s_usedAddr[1] = s_usedAddr[2] = 0xffffff; - const bool ramExpansion = PCSX::g_emulator->settings.get(); - do { - addr &= ramExpansion ? 0x7ffffc : 0x1ffffc; + addr &= g_emulator->getRamMask<4>(); if (DMACommandCounter++ > 2000000) break; if (CheckForEndlessLoop(addr)) break; diff --git a/src/core/gte.h b/src/core/gte.h index 887640a88..d367d095e 100644 --- a/src/core/gte.h +++ b/src/core/gte.h @@ -27,7 +27,7 @@ #undef NCCS #define gteoB (PCSX::g_emulator->m_cpu->m_regs.GPR.r[_Rs_] + _Imm_) -#define gteop(instruction) ((instruction)&0x1ffffff) +#define gteop(instruction) ((instruction) & 0x1ffffff) namespace PCSX { diff --git a/src/core/logger.h b/src/core/logger.h index b725c5275..66817b100 100644 --- a/src/core/logger.h +++ b/src/core/logger.h @@ -54,7 +54,7 @@ enum class LogClass : unsigned { template struct Logger { template - static void Log(const char *format, const Args &... args) { + static void Log(const char *format, const Args &...args) { if (!enabled) return; std::string s = fmt::sprintf(format, args...); g_system->log(logClass, std::move(s)); diff --git a/src/core/mdec.cc b/src/core/mdec.cc index 9e3916997..fffd09b26 100644 --- a/src/core/mdec.cc +++ b/src/core/mdec.cc @@ -248,7 +248,7 @@ unsigned short *PCSX::MDEC::rl2blk(int *blk, unsigned short *mdec_rl) { // B = 1.000 * (Y) + 1.765 * (Cb - 128) #define MULR(a) ((1434 * (a))) #define MULB(a) ((1807 * (a))) -#define MULG2(a, b) ((-351 * (a)-728 * (b))) +#define MULG2(a, b) ((-351 * (a) - 728 * (b))) #define MULY(a) ((a) << 10) #define MAKERGB15(r, g, b, a) (SWAP_LE16(a | ((b) << 10) | ((g) << 5) | (r))) diff --git a/src/core/patchmanager.cc b/src/core/patchmanager.cc index 10edf4cf8..cba311454 100644 --- a/src/core/patchmanager.cc +++ b/src/core/patchmanager.cc @@ -18,8 +18,9 @@ ***************************************************************************/ #include "core/patchmanager.h" -#include "core/psxmem.h" + #include "core/psxemulator.h" +#include "core/psxmem.h" #include "core/r3000a.h" int PCSX::PatchManager::registerPatch(uint32_t address, Patch::Type type) { @@ -71,13 +72,14 @@ void PCSX::PatchManager::undoPatch(Patch& patch) { patch.active = false; } -PCSX::PatchManager::Patch::Type PCSX::PatchManager::findPatch(uint32_t address) const { +int PCSX::PatchManager::findPatch(uint32_t address) const { + int idx = 0; for (const Patch& patch : m_patches) { if (patch.addr == address) { - return patch.type; + return idx; } } - return PCSX::PatchManager::Patch::Type::None; + return -1; } void PCSX::PatchManager::deletePatch(uint32_t index) { diff --git a/src/core/patchmanager.h b/src/core/patchmanager.h index a397a8e67..d81f402d2 100644 --- a/src/core/patchmanager.h +++ b/src/core/patchmanager.h @@ -20,6 +20,7 @@ #pragma once #include + #include namespace PCSX { @@ -47,7 +48,7 @@ class PatchManager { Patch& getPatch(int index) { return m_patches[index]; } int registerPatch(uint32_t address, Patch::Type type); - PatchManager::Patch::Type findPatch(uint32_t address) const; + int findPatch(uint32_t address) const; void deletePatch(uint32_t index); void deleteAllPatches(); void deactivateAll(); diff --git a/src/core/pcsxffi.lua b/src/core/pcsxffi.lua index e7739c923..79ebee5bb 100644 --- a/src/core/pcsxffi.lua +++ b/src/core/pcsxffi.lua @@ -50,6 +50,7 @@ typedef struct { enum BreakpointType { Exec, Read, Write }; typedef struct { uint8_t opaque[?]; } Breakpoint; +uint64_t getCPUCycles(); uint8_t* getMemPtr(); uint8_t* getParPtr(); uint8_t* getRomPtr(); @@ -172,6 +173,7 @@ local function jumpToMemory(address, width) end PCSX = { + getCPUCycles = function() return C.getCPUCycles() end, getMemPtr = function() return C.getMemPtr() end, getParPtr = function() return C.getParPtr() end, getRomPtr = function() return C.getRomPtr() end, diff --git a/src/core/pcsxlua.cc b/src/core/pcsxlua.cc index c2c0777af..1c9b50a37 100644 --- a/src/core/pcsxlua.cc +++ b/src/core/pcsxlua.cc @@ -34,6 +34,7 @@ struct LuaBreakpoint { PCSX::Debug::BreakpointUserListType wrapper; }; +uint64_t getCPUCycles() { return PCSX::g_emulator->m_cpu->m_regs.cycle; } void* getMemPtr() { return PCSX::g_emulator->m_mem->m_wram; } void* getParPtr() { return PCSX::g_emulator->m_mem->m_exp1; } void* getRomPtr() { return PCSX::g_emulator->m_mem->m_bios; } @@ -137,6 +138,7 @@ static void registerAllSymbols(PCSX::Lua L) { L.getfieldtable("_CLIBS", LUA_REGISTRYINDEX); L.push("PCSX"); L.newtable(); + REGISTER(L, getCPUCycles); REGISTER(L, getMemPtr); REGISTER(L, getParPtr); REGISTER(L, getRomPtr); diff --git a/src/core/pgxp_cpu.cc b/src/core/pgxp_cpu.cc index 6bdd90710..bf6aab798 100644 --- a/src/core/pgxp_cpu.cc +++ b/src/core/pgxp_cpu.cc @@ -15,7 +15,7 @@ PGXP_value* const g_CP0_reg = s_CP0_reg_mem; // Instruction register decoding #define op(_instr) (_instr >> 26) // The op part of the instruction register -#define func(_instr) ((_instr)&0x3F) // The funct part of the instruction register +#define func(_instr) ((_instr) & 0x3F) // The funct part of the instruction register #define sa(_instr) ((_instr >> 6) & 0x1F) // The sa part of the instruction register #define rd(_instr) ((_instr >> 11) & 0x1F) // The rd part of the instruction register #define rt(_instr) ((_instr >> 16) & 0x1F) // The rt part of the instruction register @@ -427,9 +427,9 @@ void PGXP_CPU_SLT(uint32_t instr, uint32_t rdVal, uint32_t rsVal, uint32_t rtVal ret.y = 0.f; ret.compFlags[1] = VALID; - ret.x = (g_CPU_reg[rs(instr)].y < g_CPU_reg[rt(instr)].y) - ? 1.f - : (f16Unsign(g_CPU_reg[rs(instr)].x) < f16Unsign(g_CPU_reg[rt(instr)].x)) ? 1.f : 0.f; + ret.x = (g_CPU_reg[rs(instr)].y < g_CPU_reg[rt(instr)].y) ? 1.f + : (f16Unsign(g_CPU_reg[rs(instr)].x) < f16Unsign(g_CPU_reg[rt(instr)].x)) ? 1.f + : 0.f; ret.value = rdVal; g_CPU_reg[rd(instr)] = ret; @@ -452,9 +452,9 @@ void PGXP_CPU_SLTU(uint32_t instr, uint32_t rdVal, uint32_t rsVal, uint32_t rtVa ret.y = 0.f; ret.compFlags[1] = VALID; - ret.x = (f16Unsign(g_CPU_reg[rs(instr)].y) < f16Unsign(g_CPU_reg[rt(instr)].y)) - ? 1.f - : (f16Unsign(g_CPU_reg[rs(instr)].x) < f16Unsign(g_CPU_reg[rt(instr)].x)) ? 1.f : 0.f; + ret.x = (f16Unsign(g_CPU_reg[rs(instr)].y) < f16Unsign(g_CPU_reg[rt(instr)].y)) ? 1.f + : (f16Unsign(g_CPU_reg[rs(instr)].x) < f16Unsign(g_CPU_reg[rt(instr)].x)) ? 1.f + : 0.f; ret.value = rdVal; g_CPU_reg[rd(instr)] = ret; diff --git a/src/core/pgxp_debug.cc b/src/core/pgxp_debug.cc index 623be30b9..de6743ac9 100644 --- a/src/core/pgxp_debug.cc +++ b/src/core/pgxp_debug.cc @@ -9,7 +9,7 @@ unsigned int g_pgxp_debug = 0; // Instruction register decoding #define op(_instr) (_instr >> 26) // The op part of the instruction register -#define func(_instr) ((_instr)&0x3F) // The funct part of the instruction register +#define func(_instr) ((_instr) & 0x3F) // The funct part of the instruction register #define sa(_instr) ((_instr >> 6) & 0x1F) // The sa part of the instruction register #define rd(_instr) ((_instr >> 11) & 0x1F) // The rd part of the instruction register #define rt(_instr) ((_instr >> 16) & 0x1F) // The rt part of the instruction register diff --git a/src/core/pgxp_debug.h b/src/core/pgxp_debug.h index 2a7805d29..9a21a0cfe 100644 --- a/src/core/pgxp_debug.h +++ b/src/core/pgxp_debug.h @@ -30,10 +30,10 @@ #include "psxemulator.h" -//#define PGXP_CPU_DEBUG -//#define PGXP_OUTPUT_ALL -//#define PGXP_FORCE_INPUT_VALUES -//#define PGXP_TEST_OUTPUT_VALUES +// #define PGXP_CPU_DEBUG +// #define PGXP_OUTPUT_ALL +// #define PGXP_FORCE_INPUT_VALUES +// #define PGXP_TEST_OUTPUT_VALUES #define PGXP_DEBUG_TOLERANCE 2.f diff --git a/src/core/pgxp_gte.cc b/src/core/pgxp_gte.cc index 9fef57d09..210d78420 100644 --- a/src/core/pgxp_gte.cc +++ b/src/core/pgxp_gte.cc @@ -57,7 +57,7 @@ void PGXP_InitGTE() { // Instruction register decoding #define op(_instr) (_instr >> 26) // The op part of the instruction register -#define func(_instr) ((_instr)&0x3F) // The funct part of the instruction register +#define func(_instr) ((_instr) & 0x3F) // The funct part of the instruction register #define sa(_instr) ((_instr >> 6) & 0x1F) // The sa part of the instruction register #define rd(_instr) ((_instr >> 11) & 0x1F) // The rd part of the instruction register #define rt(_instr) ((_instr >> 16) & 0x1F) // The rt part of the instruction register diff --git a/src/core/pgxp_value.h b/src/core/pgxp_value.h index 4a8b30df6..2c7d9b8ed 100644 --- a/src/core/pgxp_value.h +++ b/src/core/pgxp_value.h @@ -93,7 +93,7 @@ typedef enum { VALID_HALF = (1 << 0) } PGXP_half_flags; // typedef enum //{ -//#define NONE 0 +// #define NONE 0 #define ALL 0xFFFFFFFF #define VALID 1 #define VALID_0 (VALID << 0) diff --git a/src/core/psxcounters.cc b/src/core/psxcounters.cc index ae4f20934..1c4ba9bae 100644 --- a/src/core/psxcounters.cc +++ b/src/core/psxcounters.cc @@ -30,7 +30,7 @@ #include "spu/interface.h" template -void verboseLog(int32_t level, const char *str, const Args &... args) { +void verboseLog(int32_t level, const char *str, const Args &...args) { PSXHW_LOG(str, args...); } @@ -55,7 +55,7 @@ inline void PCSX::Counters::writeCounterInternal(uint32_t index, uint32_t value) } inline uint32_t PCSX::Counters::readCounterInternal(uint32_t index) { - uint32_t count; + uint64_t count; count = PCSX::g_emulator->m_cpu->m_regs.cycle; count -= m_rcnts[index].cycleStart; @@ -71,17 +71,17 @@ inline uint32_t PCSX::Counters::readCounterInternal(uint32_t index) { void PCSX::Counters::set() { m_psxNextCounter = PCSX::g_emulator->m_cpu->m_regs.cycle; - uint32_t next = 0x7fffffff; + uint64_t next = 0x7fffffffffffffff; for (int i = 0; i < CounterQuantity; ++i) { - int32_t countToUpdate = m_rcnts[i].cycle - (m_psxNextCounter - m_rcnts[i].cycleStart); + int64_t countToUpdate = m_rcnts[i].cycle - (m_psxNextCounter - m_rcnts[i].cycleStart); if (countToUpdate < 0) { next = 0; break; } - if (countToUpdate < (int32_t)next) { + if (countToUpdate < (int64_t)next) { next = countToUpdate; } } @@ -90,7 +90,7 @@ void PCSX::Counters::set() { } void PCSX::Counters::reset(uint32_t index) { - uint32_t count; + uint64_t count; if (m_rcnts[index].counterState == CountToTarget) { if (m_rcnts[index].mode & RcCountToTarget) { @@ -138,19 +138,11 @@ void PCSX::Counters::reset(uint32_t index) { } void PCSX::Counters::update() { - const uint32_t cycle = PCSX::g_emulator->m_cpu->m_regs.cycle; + const uint64_t cycle = PCSX::g_emulator->m_cpu->m_regs.cycle; { - uint32_t prev = g_emulator->m_cpu->m_regs.previousCycles; - uint64_t diff; - if (cycle > prev) { - diff = cycle - prev; - } else { - diff = std::numeric_limits::max(); - diff += cycle + 1; - diff -= prev; - diff &= 0xffffffff; - } + uint64_t prev = g_emulator->m_cpu->m_regs.previousCycles; + uint64_t diff = cycle - prev; diff *= 4410000; diff /= g_emulator->settings.get(); diff /= g_emulator->m_psxClockSpeed; @@ -297,8 +289,8 @@ uint32_t PCSX::Counters::readCounter(uint32_t index) { *affected). */ static uint32_t clast = 0xffff; - static uint32_t cylast = 0; - uint32_t count1 = count; + static uint64_t cylast = 0; + uint64_t count1 = count; count /= PCSX::Emulator::BIAS; verboseLog(4, "[RCNT %i] rcountpe2: %x %x %x (%u)\n", index, count, count1, clast, (PCSX::g_emulator->m_cpu->m_regs.cycle - cylast)); diff --git a/src/core/psxcounters.h b/src/core/psxcounters.h index 6ac986afc..b8c1b3b3f 100644 --- a/src/core/psxcounters.h +++ b/src/core/psxcounters.h @@ -40,7 +40,7 @@ class Counters { struct Rcnt { uint16_t mode, target; uint32_t rate, irq, counterState, irqState; - uint32_t cycle, cycleStart; + uint64_t cycle, cycleStart; }; enum { @@ -86,7 +86,7 @@ class Counters { uint32_t m_HSyncTotal[PCSX::Emulator::PSX_TYPE_PAL + 1]; // 2 public: - uint32_t m_psxNextCounter; + uint64_t m_psxNextCounter; bool m_pollSIO1 = false; void init(); void update(); diff --git a/src/core/psxemulator.cc b/src/core/psxemulator.cc index 10e30db20..6276328f5 100644 --- a/src/core/psxemulator.cc +++ b/src/core/psxemulator.cc @@ -30,6 +30,7 @@ #include "core/luaiso.h" #include "core/mdec.h" #include "core/pad.h" +#include "core/patchmanager.h" #include "core/pcsxlua.h" #include "core/pio-cart.h" #include "core/r3000a.h" @@ -37,7 +38,6 @@ #include "core/sio1-server.h" #include "core/sio1.h" #include "core/web-server.h" -#include "core/patchmanager.h" #include "gpu/soft/interface.h" #include "lua/extra.h" #include "lua/luafile.h" @@ -120,6 +120,15 @@ void PCSX::Emulator::setLua() { L.pop(); L.pop(); + L.getfieldtable("PCSX", LUA_GLOBALSINDEX); + L.getfieldtable("CONSTS"); + L.getfieldtable("CPU"); + L.push(lua_Number(m_psxClockSpeed)); + L.setfield("CLOCKSPEED"); + L.pop(); + L.pop(); + L.pop(); + m_pads->setLua(L); assert(L.gettop() == 0); diff --git a/src/core/psxemulator.h b/src/core/psxemulator.h index 30d0b74bc..8a4d0eb17 100644 --- a/src/core/psxemulator.h +++ b/src/core/psxemulator.h @@ -24,6 +24,10 @@ #pragma once +// Windows include on top +#include "support/windowswrapper.h" + +// Normal includes #include #include #include @@ -45,7 +49,6 @@ #include "support/strings-helpers.h" #ifndef MAXPATHLEN -#include "support/windowswrapper.h" #if defined(MAX_PATH) #define MAXPATHLEN MAX_PATH #elif defined(PATH_MAX) @@ -186,6 +189,8 @@ class Emulator { typedef SettingPath SettingEXP1Filepath; typedef SettingPath SettingEXP1BrowsePath; typedef Setting SettingPIOConnected; + typedef SettingPath SettingMapBrowsePath; + typedef SettingVector SettingOpenDialogFavorites; Settings + SettingPIOConnected, SettingMapBrowsePath, SettingOpenDialogFavorites> settings; class PcsxConfig { public: @@ -227,6 +232,16 @@ class Emulator { uint32_t m_psxClockSpeed = 33868800 /* 33.8688 MHz */; enum { BIAS = 2 }; + template + requires((alignment == 1) || (alignment == 4)) + constexpr uint32_t getRamMask() { + if constexpr (alignment == 1) { + return settings.get() ? 0x7fffff : 0x1fffff; + } else if constexpr (alignment == 4) { + return settings.get() ? 0x7ffffc : 0x1ffffc; + } + } + int init(); void reset(); void shutdown(); diff --git a/src/core/psxinterpreter.cc b/src/core/psxinterpreter.cc index 55182dd11..ac3931c75 100644 --- a/src/core/psxinterpreter.cc +++ b/src/core/psxinterpreter.cc @@ -1584,10 +1584,8 @@ void InterpretedCPU::Execute() { } } -void InterpretedCPU::Clear(uint32_t Addr, uint32_t Size) -{ - for (auto i = 0; i < Size ; i+=4) - { +void InterpretedCPU::Clear(uint32_t Addr, uint32_t Size) { + for (auto i = 0; i < Size; i += 4) { flushICacheLine(Addr); Addr += 16; } diff --git a/src/core/r3000a.cc b/src/core/r3000a.cc index 9e6ea7e9f..416f7b3a2 100644 --- a/src/core/r3000a.cc +++ b/src/core/r3000a.cc @@ -350,7 +350,7 @@ void PCSX::R3000Acpu::branchTest() { } #endif - const uint32_t cycle = m_regs.cycle; + const uint64_t cycle = m_regs.cycle; if (cycle >= g_emulator->m_counters->m_psxNextCounter) g_emulator->m_counters->update(); @@ -358,17 +358,17 @@ void PCSX::R3000Acpu::branchTest() { const uint32_t interrupts = m_regs.interrupt; - int32_t lowestDistance = std::numeric_limits::max(); - uint32_t lowestTarget = cycle; - uint32_t* targets = m_regs.intTargets; + int32_t lowestDistance = std::numeric_limits::max(); + uint64_t lowestTarget = cycle; + uint64_t* targets = m_regs.intTargets; - if ((interrupts != 0) && (((int32_t)(m_regs.lowestTarget - cycle)) <= 0)) { + if ((interrupts != 0) && (m_regs.lowestTarget < cycle)) { #define checkAndUpdate(irq, act) \ { \ constexpr uint32_t mask = 1 << irq; \ if ((interrupts & mask) != 0) { \ - uint32_t target = targets[irq]; \ - int32_t dist = target - cycle; \ + uint64_t target = targets[irq]; \ + int64_t dist = target - cycle; \ if (dist > 0) { \ if (lowestDistance > dist) { \ lowestDistance = dist; \ diff --git a/src/core/r3000a.h b/src/core/r3000a.h index d9aafd1d7..3bb1cef15 100644 --- a/src/core/r3000a.h +++ b/src/core/r3000a.h @@ -199,12 +199,12 @@ struct psxRegisters { psxCP2Ctrl CP2C; // COP2 control registers uint32_t pc; // Program counter uint32_t code; // The current instruction - uint32_t cycle; - uint32_t previousCycles; + uint64_t cycle; + uint64_t previousCycles; uint32_t interrupt; std::atomic spuInterrupt; - uint32_t intTargets[32]; - uint32_t lowestTarget; + uint64_t intTargets[32]; + uint64_t lowestTarget; uint8_t iCacheAddr[0x1000]; uint8_t iCacheCode[0x1000]; }; @@ -229,7 +229,7 @@ struct psxRegisters { #define _PC_ PCSX::g_emulator->m_cpu->m_regs.pc // The next PC to be executed #define _fOp_(code) ((code >> 26)) // The opcode part of the instruction register -#define _fFunct_(code) ((code)&0x3F) // The funct part of the instruction register +#define _fFunct_(code) ((code) & 0x3F) // The funct part of the instruction register #define _fRd_(code) ((code >> 11) & 0x1F) // The rd part of the instruction register #define _fRt_(code) ((code >> 16) & 0x1F) // The rt part of the instruction register #define _fRs_(code) ((code >> 21) & 0x1F) // The rs part of the instruction register @@ -317,12 +317,12 @@ class R3000Acpu { void scheduleInterrupt(unsigned interrupt, uint32_t eCycle) { PSXIRQ_LOG("Scheduling interrupt %08x at %08x\n", interrupt, eCycle); - const uint32_t cycle = m_regs.cycle; - uint32_t target = uint32_t(cycle + eCycle * m_interruptScales[interrupt]); + const uint64_t cycle = m_regs.cycle; + uint64_t target = uint64_t(cycle + eCycle * m_interruptScales[interrupt]); m_regs.interrupt |= (1 << interrupt); m_regs.intTargets[interrupt] = target; - int32_t lowest = m_regs.lowestTarget - cycle; - int32_t maybeNewLowest = target - cycle; + int64_t lowest = m_regs.lowestTarget - cycle; + int64_t maybeNewLowest = target - cycle; if (maybeNewLowest < lowest) m_regs.lowestTarget = target; } @@ -409,7 +409,7 @@ class R3000Acpu { public: template inline void InterceptBIOS(uint32_t currentPC) { - const uint32_t pc = currentPC & 0x1fffff; + const uint32_t pc = currentPC & g_emulator->getRamMask(); if constexpr (checkPC) { const uint32_t base = (currentPC >> 20) & 0xffc; @@ -461,11 +461,9 @@ Formula One 2001 memset(m_regs.iCacheCode, 0xff, sizeof(m_regs.iCacheCode)); } - inline void flushICacheLine(uint32_t pc) - { + inline void flushICacheLine(uint32_t pc) { uint32_t pcBank = pc >> 24; - if (pcBank == 0x00 || pcBank == 0x80) - { + if (pcBank == 0x00 || pcBank == 0x80) { uint32_t pcCache = pc & 0xfff; pcCache &= ~0xf; diff --git a/src/core/sio.h b/src/core/sio.h index 586e2b43b..8071c4730 100644 --- a/src/core/sio.h +++ b/src/core/sio.h @@ -233,7 +233,7 @@ class SIO { bool isReceiveIRQReady(); bool isTransmitReady(); - static inline void scheduleInterrupt(uint32_t eCycle) { + static inline void scheduleInterrupt(uint64_t eCycle) { g_emulator->m_cpu->scheduleInterrupt(PSXINT_SIO, eCycle); #if 0 // Breaks Twisted Metal 2 intro diff --git a/src/core/sstate.cc b/src/core/sstate.cc index 6aef5dfb1..27107c2a8 100644 --- a/src/core/sstate.cc +++ b/src/core/sstate.cc @@ -182,8 +182,8 @@ std::string PCSX::SaveStates::save() { SaveState state = constructSaveState(); SaveStateWrapper wrapper(state); - state.get().get().value = "PCSX-Redux SaveState v3"; - state.get().get().value = 3; + state.get().get().value = "PCSX-Redux SaveState v4"; + state.get().get().value = 4; g_emulator->m_gpu->serialize(&wrapper); g_emulator->m_spu->save(state.get()); @@ -288,7 +288,7 @@ bool PCSX::SaveStates::load(std::string_view data) { return false; } - if (state.get().get().value != 3) { + if (state.get().get().value != 4) { return false; } diff --git a/src/core/sstate.h b/src/core/sstate.h index 910f2e1b3..317b51685 100644 --- a/src/core/sstate.h +++ b/src/core/sstate.h @@ -55,7 +55,7 @@ typedef Protobuf::RepeatedFieldRef typedef Protobuf::RepeatedFieldRef CP2C; typedef Protobuf::FieldRef PC; typedef Protobuf::FieldRef Code; -typedef Protobuf::FieldRef Cycle; +typedef Protobuf::FieldRef Cycle; typedef Protobuf::FieldRef Interrupt; // skip id 9 typedef Protobuf::FieldPtr, TYPESTRING("icache_addr"), 10> ICacheAddr; @@ -75,7 +75,7 @@ typedef Protobuf::Message DelaySlotInfo1; typedef Protobuf::MessageField DelaySlotInfo2; typedef Protobuf::FieldRef CurrentDelayedLoad; -typedef Protobuf::RepeatedFieldRef IntTargetsField; +typedef Protobuf::RepeatedFieldRef IntTargetsField; typedef Protobuf::FieldRef InISR; typedef Protobuf::Message RcntRate; typedef Protobuf::Field RcntIRQ; typedef Protobuf::Field RcntCounterState; typedef Protobuf::Field RcntIRQState; -typedef Protobuf::Field RcntCycle; -typedef Protobuf::Field RcntCycleStart; +typedef Protobuf::Field RcntCycle; +typedef Protobuf::Field RcntCycleStart; typedef Protobuf::Message Rcnt; typedef Protobuf::RepeatedField Rcnts; typedef Protobuf::Field HSyncCount; typedef Protobuf::Field SPUSyncCountdown; -typedef Protobuf::Field PSXNextCounter; +typedef Protobuf::Field PSXNextCounter; typedef Protobuf::Message Counters; typedef Protobuf::MessageField CountersField; diff --git a/src/core/web-server.cc b/src/core/web-server.cc index b047b1c55..d928cb03c 100644 --- a/src/core/web-server.cc +++ b/src/core/web-server.cc @@ -595,8 +595,8 @@ class StateExecutor : public PCSX::WebExecutor { message = fmt::format("HTTP/1.1 200 OK\r\n\r\nState slot index {} {} successful.", slot, path); } else { - message = fmt::format("HTTP/1.1 500 Internal Server Error\r\n\r\nState slot index {} {} failed.", - slot, path); + message = fmt::format( + "HTTP/1.1 500 Internal Server Error\r\n\r\nState slot index {} {} failed.", slot, path); } } client->write(std::move(message)); @@ -634,8 +634,9 @@ class StateExecutor : public PCSX::WebExecutor { message = fmt::format("HTTP/1.1 200 OK\r\n\r\nState slot name \"{}\" {} successful.", name, path); } else { - message = fmt::format("HTTP/1.1 500 Internal Server Error\r\n\r\nState slot name \"{}\" {} failed.", - name, path); + message = fmt::format( + "HTTP/1.1 500 Internal Server Error\r\n\r\nState slot name \"{}\" {} failed.", name, + path); } } client->write(std::move(message)); @@ -683,8 +684,9 @@ class ScreenExecutor : public PCSX::WebExecutor { message = fmt::format("HTTP/1.1 200 OK\r\n\r\nScreenshot saved successfully to \"{}\".", path.string()); } else { - message = fmt::format("HTTP/1.1 500 Internal Server Error\r\n\r\nFailed to save screenshot to \"{}\".", - path.string()); + message = + fmt::format("HTTP/1.1 500 Internal Server Error\r\n\r\nFailed to save screenshot to \"{}\".", + path.string()); } client->write(std::move(message)); return true; diff --git a/src/gui/gui.cc b/src/gui/gui.cc index e034d7bef..3f313671f 100644 --- a/src/gui/gui.cc +++ b/src/gui/gui.cc @@ -114,6 +114,22 @@ void PCSX::GUI::openUrl(std::string_view url) { } #endif +PCSX::GUI::GUI(std::vector& favorites) + : m_listener(g_system->m_eventBus), + m_typedDebugger(settings.get().value, favorites), + m_memcardManager(settings.get().value, favorites), + m_assembly(settings.get().value, favorites), + m_openIsoFileDialog(l_("Open Disk Image"), favorites), + m_openBinaryDialog(l_("Open Binary"), favorites), + m_openArchiveDialog(l_("Open Archive"), favorites), + m_selectBiosDialog(l_("Select BIOS"), favorites), + m_selectEXP1Dialog(l_("Select EXP1"), favorites), + m_isoBrowser(settings.get().value, favorites), + m_pioCart(settings.get().value, favorites) { + assert(g_gui == nullptr); + g_gui = this; +} + using json = nlohmann::json; static std::function s_imguiUserErrorFunctor = nullptr; @@ -1052,7 +1068,7 @@ void PCSX::GUI::endFrame() { m_outputShaderEditor.configure(this); if (m_fullWindowRender) { - ImTextureID texture = reinterpret_cast(m_offscreenTextures[m_currentTexture]); + ImTextureID texture = m_offscreenTextures[m_currentTexture]; const auto basePos = ImGui::GetMainViewport()->Pos; const auto displayFramebufferScale = ImGui::GetIO().DisplayFramebufferScale; const auto logicalRenderSize = @@ -1086,7 +1102,7 @@ void PCSX::GUI::endFrame() { m_setupScreenSize = true; } ImGuiHelpers::normalizeDimensions(textureSize, renderRatio); - ImTextureID texture = reinterpret_cast(m_offscreenTextures[m_currentTexture]); + ImTextureID texture = m_offscreenTextures[m_currentTexture]; if (g_system->getArgs().isShadersDisabled()) { ImGui::Image(texture, textureSize, ImVec2(0, 0), ImVec2(1, 1)); } else { @@ -1557,7 +1573,7 @@ in Configuration->Emulation, restart PCSX-Redux, then try again.)")); } if (m_assembly.m_show) { - m_assembly.draw(this, &g_emulator->m_cpu->m_regs, g_emulator->m_mem.get(), _("Assembly")); + changed |= m_assembly.draw(this, &g_emulator->m_cpu->m_regs, g_emulator->m_mem.get(), _("Assembly")); } if (m_disassembly.m_show && g_emulator->m_cpu->isDynarec()) { diff --git a/src/gui/gui.h b/src/gui/gui.h index 77fc60ee0..41c0d99b0 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -153,15 +153,15 @@ class GUI final : public UI { Settings + ShowPatches, ShowMemcardManager, ShowRegisters, ShowAssembly, ShowDisassembly, ShowBreakpoints, + ShowNamedSaveStates, ShowEvents, ShowHandlers, ShowKernelLog, ShowCallstacks, ShowSIO1, ShowIsoBrowser, + ShowGPULogger, MainFontSize, MonoFontSize, GUITheme, AllowMouseCaptureToggle, EnableRawMouseMotion, + WidescreenRatio, ShowPIOCartConfig, ShowMemoryEditor1, ShowMemoryEditor2, ShowMemoryEditor3, + ShowMemoryEditor4, ShowMemoryEditor5, ShowMemoryEditor6, ShowMemoryEditor7, ShowMemoryEditor8, + ShowParallelPortEditor, ShowScratchpadEditor, ShowHWRegsEditor, ShowBiosEditor, ShowVRAMEditor, + MemoryEditor1Addr, MemoryEditor2Addr, MemoryEditor3Addr, MemoryEditor4Addr, MemoryEditor5Addr, + MemoryEditor6Addr, MemoryEditor7Addr, MemoryEditor8Addr, ParallelPortEditorAddr, ScratchpadEditorAddr, + HWRegsEditorAddr, BiosEditorAddr, VRAMEditorAddr> settings; // imgui can't handle more than one "instance", so... @@ -213,10 +213,7 @@ class GUI final : public UI { GUI *m_gui = nullptr; }; std::vector getGLerrors() { return std::move(m_glErrors); } - GUI() : m_listener(g_system->m_eventBus) { - assert(g_gui == nullptr); - g_gui = this; - } + GUI(std::vector &favorites); ~GUI() { assert(g_gui == this); g_gui = nullptr; @@ -374,20 +371,20 @@ class GUI final : public UI { MemoryEditorWrapper m_vramEditor = {this, settings.get().value, settings.get().value}; Widgets::MemoryObserver m_memoryObserver = {settings.get().value}; - Widgets::TypedDebugger m_typedDebugger = {settings.get().value}; + Widgets::TypedDebugger m_typedDebugger; Widgets::Patches m_patches = {settings.get().value}; - Widgets::MemcardManager m_memcardManager = {settings.get().value}; + Widgets::MemcardManager m_memcardManager; Widgets::Registers m_registers = {settings.get().value}; - Widgets::Assembly m_assembly = {settings.get().value}; + Widgets::Assembly m_assembly; Widgets::Disassembly m_disassembly = {settings.get().value}; - Widgets::FileDialog<> m_openIsoFileDialog = {l_("Open Disk Image")}; - Widgets::FileDialog<> m_openBinaryDialog = {l_("Open Binary")}; - Widgets::FileDialog<> m_openArchiveDialog = {l_("Open Archive")}; - Widgets::FileDialog<> m_selectBiosDialog = {l_("Select BIOS")}; - Widgets::FileDialog<> m_selectEXP1Dialog = {l_("Select EXP1")}; + Widgets::FileDialog<> m_openIsoFileDialog; + Widgets::FileDialog<> m_openBinaryDialog; + Widgets::FileDialog<> m_openArchiveDialog; + Widgets::FileDialog<> m_selectBiosDialog; + Widgets::FileDialog<> m_selectEXP1Dialog; Widgets::NamedSaveStates m_namedSaveStates = {settings.get().value}; Widgets::Breakpoints m_breakpoints = {settings.get().value}; - Widgets::IsoBrowser m_isoBrowser = {settings.get().value}; + Widgets::IsoBrowser m_isoBrowser; bool m_showCfg = false; bool m_showUiCfg = false; @@ -408,7 +405,7 @@ class GUI final : public UI { Widgets::CallStacks m_callstacks = {settings.get().value}; - Widgets::PIOCart m_pioCart = {settings.get().value}; + Widgets::PIOCart m_pioCart; Widgets::SIO1 m_sio1 = {settings.get().value}; Widgets::GPULogger m_gpuLogger{settings.get().value}; diff --git a/src/gui/widgets/assembly.cc b/src/gui/widgets/assembly.cc index 59718a122..81513bf87 100644 --- a/src/gui/widgets/assembly.cc +++ b/src/gui/widgets/assembly.cc @@ -459,7 +459,8 @@ void PCSX::Widgets::Assembly::Offset(uint32_t addr, int size) { } } -void PCSX::Widgets::Assembly::draw(GUI* gui, psxRegisters* registers, Memory* memory, const char* title) { +bool PCSX::Widgets::Assembly::draw(GUI* gui, psxRegisters* registers, Memory* memory, const char* title) { + bool changed = false; auto& cpu = g_emulator->m_cpu; m_registers = registers; m_memory = memory; @@ -467,7 +468,7 @@ void PCSX::Widgets::Assembly::draw(GUI* gui, psxRegisters* registers, Memory* me ImGui::SetNextWindowSize(ImVec2(500, 500), ImGuiCond_FirstUseEver); if (!ImGui::Begin(title, &m_show, ImGuiWindowFlags_MenuBar)) { ImGui::End(); - return; + return changed; } float glyphWidth = ImGui::GetFontSize(); @@ -638,8 +639,7 @@ settings, otherwise debugging features may not work.)"); }; if (clipper.DisplayStart != 0) { uint32_t addr = clipper.DisplayStart * 4 - 4; - process( - addr, [](uint32_t, const char*, uint32_t, uint32_t, uint32_t) {}, &dummy); + process(addr, [](uint32_t, const char*, uint32_t, uint32_t, uint32_t) {}, &dummy); } auto& tree = g_emulator->m_debug->getTree(); for (int x = clipper.DisplayStart; x < clipper.DisplayEnd; x++) { @@ -789,28 +789,29 @@ settings, otherwise debugging features may not work.)"); } if (absAddr < 0x00800000) { PatchManager& pm = *g_emulator->m_patchManager; - PatchManager::Patch::Type patchType = pm.findPatch(dispAddr); - switch (patchType) { - case PatchManager::Patch::Type::None: - if (ImGui::MenuItem(_("Patch in Return"))) { - pm.registerPatch(dispAddr, PatchManager::Patch::Type::Return); - } - if (ImGui::MenuItem(_("Patch in NOP"))) { - pm.registerPatch(dispAddr, PatchManager::Patch::Type::NOP); - } - break; - - case PatchManager::Patch::Type::Return: - if (ImGui::MenuItem(_("Remove Return Patch"))) { - pm.undoPatch(dispAddr); - } - break; + int patchIdx = pm.findPatch(dispAddr); + if (patchIdx == -1) { + if (ImGui::MenuItem(_("Patch in Return"))) { + pm.registerPatch(dispAddr, PatchManager::Patch::Type::Return); + } + if (ImGui::MenuItem(_("Patch in NOP"))) { + pm.registerPatch(dispAddr, PatchManager::Patch::Type::NOP); + } + } else { + PatchManager::Patch& patch = pm.getPatch(patchIdx); + switch (patch.type) { + case PatchManager::Patch::Type::Return: + if (ImGui::MenuItem(_("Delete Return Patch"))) { + pm.deletePatch(patchIdx); + } + break; - case PatchManager::Patch::Type::NOP: - if (ImGui::MenuItem(_("Remove NOP Patch"))) { - pm.undoPatch(dispAddr); - } - break; + case PatchManager::Patch::Type::NOP: + if (ImGui::MenuItem(_("Delete NOP Patch"))) { + pm.deletePatch(patchIdx); + } + break; + } } if (ImGui::MenuItem(_("Assemble"))) { @@ -1045,8 +1046,17 @@ if not success then return msg else return nil end } ImGui::End(); - if (openSymbolsDialog) m_symbolsFileDialog.openDialog(); + auto& mapPath = g_emulator->settings.get(); + + if (openSymbolsDialog) { + if (!mapPath.empty()) { + m_symbolsFileDialog.m_currentPath = mapPath.value; + } + m_symbolsFileDialog.openDialog(); + } if (m_symbolsFileDialog.draw()) { + mapPath.value = m_symbolsFileDialog.m_currentPath; + changed = true; std::vector filesToOpen = m_symbolsFileDialog.selected(); for (auto fileName : filesToOpen) { std::ifstream file; @@ -1101,6 +1111,7 @@ if not success then return msg else return nil end } ImGui::End(); } + return changed; } std::list PCSX::Widgets::Assembly::findSymbol(uint32_t addr) { diff --git a/src/gui/widgets/assembly.h b/src/gui/widgets/assembly.h index b2e3c91a9..edd2bd849 100644 --- a/src/gui/widgets/assembly.h +++ b/src/gui/widgets/assembly.h @@ -26,6 +26,7 @@ #include #include #include +#include #include "core/disr3000a.h" #include "core/r3000a.h" @@ -42,11 +43,12 @@ namespace Widgets { class Assembly : private Disasm { public: - Assembly(bool& show) : m_show(show), m_listener(g_system->m_eventBus) { + Assembly(bool& show, std::vector& favorites) + : m_show(show), m_listener(g_system->m_eventBus), m_symbolsFileDialog(l_("Load Symbols"), favorites) { m_listener.listen([this](const auto& event) { m_jumpToPC = event.pc; }); memset(m_jumpAddressString, 0, sizeof(m_jumpAddressString)); } - void draw(GUI* gui, psxRegisters* registers, Memory* memory, const char* title); + bool draw(GUI* gui, psxRegisters* registers, Memory* memory, const char* title); bool& m_show; @@ -60,7 +62,7 @@ class Assembly : private Disasm { int m_numColumns = 4; char m_jumpAddressString[20]; uint32_t m_previousPC = 0; - FileDialog<> m_symbolsFileDialog = {l_("Load Symbols")}; + FileDialog<> m_symbolsFileDialog; std::vector> m_arrows; // Disasm section diff --git a/src/gui/widgets/filedialog.cc b/src/gui/widgets/filedialog.cc index d35d76933..fe826336d 100644 --- a/src/gui/widgets/filedialog.cc +++ b/src/gui/widgets/filedialog.cc @@ -43,3 +43,16 @@ void PCSX::Widgets::FileDialogBase::setDeleteTexture() { glDeleteTextures(1, &texID); }; } + +void PCSX::Widgets::FileDialogBase::restoreFavorites() { + for (const auto& fav : m_favorites) { + AddFavorite(fav); + } +} + +void PCSX::Widgets::FileDialogBase::saveFavorites() { + m_favorites.clear(); + for (const auto& fav : GetFavorites()) { + m_favorites.push_back(fav); + } +} diff --git a/src/gui/widgets/filedialog.h b/src/gui/widgets/filedialog.h index 8e86431fe..6558160ee 100644 --- a/src/gui/widgets/filedialog.h +++ b/src/gui/widgets/filedialog.h @@ -33,9 +33,15 @@ namespace Widgets { class FileDialogBase : protected ifd::FileDialog { public: virtual void* CreateTexture(uint8_t* data, int w, int h, char fmt) override; + FileDialogBase(std::vector& favorites) : ifd::FileDialog(), m_favorites(favorites) {} protected: void setDeleteTexture(); + void restoreFavorites(); + void saveFavorites(); + + private: + std::vector& m_favorites; }; enum class FileDialogMode { Open, MultiSelect, Save }; @@ -43,13 +49,15 @@ enum class FileDialogMode { Open, MultiSelect, Save }; template class FileDialog : public FileDialogBase { public: - FileDialog(std::function title) : m_title(title) { + FileDialog(std::function title, std::vector& favorites) + : FileDialogBase(favorites), m_title(title) { setToCurrentPath(); setDeleteTexture(); } virtual ~FileDialog() = default; void setToCurrentPath() { m_currentPath = std::filesystem::current_path(); } void openDialog() { + restoreFavorites(); if constexpr (mode == FileDialogMode::Open) { Open(m_title(), m_title(), "*.*", mode == FileDialogMode::MultiSelect, reinterpret_cast(m_currentPath.u8string().c_str())); @@ -67,6 +75,7 @@ class FileDialog : public FileDialogBase { m_results.reserve(results.size()); for (auto& result : results) m_results.push_back(result.u8string()); Close(); + saveFavorites(); } return done; } diff --git a/src/gui/widgets/isobrowser.h b/src/gui/widgets/isobrowser.h index 42dc99110..cff66374c 100644 --- a/src/gui/widgets/isobrowser.h +++ b/src/gui/widgets/isobrowser.h @@ -22,6 +22,8 @@ #include #include +#include +#include #include "gui/widgets/filedialog.h" #include "support/coroutine.h" @@ -35,7 +37,8 @@ namespace Widgets { class IsoBrowser { public: - IsoBrowser(bool& show) : m_show(show) {} + IsoBrowser(bool& show, std::vector& favorites) + : m_show(show), m_openIsoFileDialog(l_("Open Disk Image"), favorites) {} void draw(CDRom* cdrom, const char* title); bool& m_show; @@ -47,7 +50,7 @@ class IsoBrowser { float m_crcProgress = 0.0f; Coroutine<> computeCRC(CDRIso*); - FileDialog<> m_openIsoFileDialog = {l_("Open Disk Image")}; + FileDialog<> m_openIsoFileDialog; }; } // namespace Widgets diff --git a/src/gui/widgets/memcard_manager.cc b/src/gui/widgets/memcard_manager.cc index 9db4264a3..1cac21a9c 100644 --- a/src/gui/widgets/memcard_manager.cc +++ b/src/gui/widgets/memcard_manager.cc @@ -352,7 +352,7 @@ void PCSX::Widgets::MemcardManager::drawIcon(const PCSX::SIO::McdBlock& block) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 32, 32, GL_RGBA, GL_UNSIGNED_BYTE, pixels); } - ImGui::Image(reinterpret_cast(texture), ImVec2(m_iconSize, m_iconSize)); + ImGui::Image(texture, ImVec2(m_iconSize, m_iconSize)); } // Extract the pocketstation icon from the block indicated by blockNumber into the pixels array (In RGBA8888) diff --git a/src/gui/widgets/memcard_manager.h b/src/gui/widgets/memcard_manager.h index dff8f4f60..db74f0740 100644 --- a/src/gui/widgets/memcard_manager.h +++ b/src/gui/widgets/memcard_manager.h @@ -38,7 +38,10 @@ namespace Widgets { class MemcardManager { public: - MemcardManager(bool& show) : m_show(show) {} + MemcardManager(bool& show, std::vector& favorites) + : m_show(show), + m_importMemoryCardDialog(l_("Import Memory Card file"), favorites), + m_exportMemoryCardDialog(l_("Export Memory Card file"), favorites) {} bool draw(GUI* gui, const char* title); bool& m_show; // The framecount from 0 to 59 inclusive. We need it to know which frame of multi-animation @@ -73,8 +76,8 @@ class MemcardManager { int m_undoIndex = 0; std::unique_ptr m_latest; - Widgets::FileDialog<> m_importMemoryCardDialog = {l_("Import Memory Card file")}; - Widgets::FileDialog m_exportMemoryCardDialog = {l_("Export Memory Card file")}; + Widgets::FileDialog<> m_importMemoryCardDialog; + Widgets::FileDialog m_exportMemoryCardDialog; unsigned m_memoryCardImportExportIndex = 0; void clearUndoBuffer() { diff --git a/src/gui/widgets/memory_observer.cc b/src/gui/widgets/memory_observer.cc index 485b1e369..b9670ea38 100644 --- a/src/gui/widgets/memory_observer.cc +++ b/src/gui/widgets/memory_observer.cc @@ -334,9 +334,9 @@ void PCSX::Widgets::MemoryObserver::draw(const char* title) { ImGui::TableHeadersRow(); bool as_uint = (m_scanValueType == ScanValueType::Uint); - const auto valueDisplayFormat = - m_hex ? "%x" - : (m_fixedPoint && stride > 1) ? (as_uint ? "%u.%u" : "%i.%i") : (as_uint ? "%u" : "%i"); + const auto valueDisplayFormat = m_hex ? "%x" + : (m_fixedPoint && stride > 1) ? (as_uint ? "%u.%u" : "%i.%i") + : (as_uint ? "%u" : "%i"); ImGuiListClipper clipper; clipper.Begin(m_addressValuePairs.size()); diff --git a/src/gui/widgets/patches.cc b/src/gui/widgets/patches.cc index b561fec86..f4945f8bc 100644 --- a/src/gui/widgets/patches.cc +++ b/src/gui/widgets/patches.cc @@ -17,9 +17,10 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ +#include "gui/widgets/patches.h" + #include "core/patchmanager.h" #include "core/r3000a.h" -#include "gui/widgets/patches.h" #include "imgui.h" void PCSX::Widgets::Patches::draw(const char* title) { @@ -37,8 +38,8 @@ void PCSX::Widgets::Patches::draw(const char* title) { } static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | - ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | - ImGuiTableFlags_ContextMenuInBody; + ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | + ImGuiTableFlags_ContextMenuInBody; if (ImGui::BeginTable("Patches", 4, flags)) { ImGui::TableSetupColumn("#"); @@ -74,14 +75,10 @@ void PCSX::Widgets::Patches::draw(const char* title) { ImGui::TableSetColumnIndex(2); ImGui::PushID(row); - if (ImGui::Checkbox("", &patch.active)) - { - if (patch.active) - { + if (ImGui::Checkbox("", &patch.active)) { + if (patch.active) { patchManager.doPatch(row); - } - else - { + } else { patchManager.undoPatch(row); } } @@ -105,11 +102,20 @@ void PCSX::Widgets::Patches::draw(const char* title) { patchManager.deactivateAll(); } - ImGui::SameLine(); - if (ImGui::Button(_("Delete All"))) { - patchManager.deleteAllPatches(); + if (patchManager.getNumPatches() > 0) { + ImGui::SameLine(); + if (ImGui::Button(_("Delete All"))) { + ImGui::OpenPopup("delpatches_popup"); + } + if (ImGui::BeginPopup("delpatches_popup")) { + ImGui::TextUnformatted(_("Delete all Patches?")); + if (ImGui::Button(_("Delete##patches"))) { + patchManager.deleteAllPatches(); + } + ImGui::EndPopup(); + } } } - + ImGui::End(); } diff --git a/src/gui/widgets/pio-cart.h b/src/gui/widgets/pio-cart.h index 1e7a15055..85ec84e5e 100644 --- a/src/gui/widgets/pio-cart.h +++ b/src/gui/widgets/pio-cart.h @@ -19,7 +19,8 @@ #pragma once -#include +#include +#include #include "gui/widgets/filedialog.h" @@ -28,12 +29,13 @@ namespace PCSX { namespace Widgets { class PIOCart { public: - PIOCart(bool& show) : m_show(show) {} + PIOCart(bool& show, std::vector& favorites) + : m_show(show), m_selectEXP1Dialog(l_("Select EXP1"), favorites) {} bool draw(const char* title); bool& m_show; private: - Widgets::FileDialog<> m_selectEXP1Dialog = {l_("Select EXP1")}; + Widgets::FileDialog<> m_selectEXP1Dialog; int m_flashSizeIndex; bool m_switchOn = 1; }; diff --git a/src/gui/widgets/shader-editor.cc b/src/gui/widgets/shader-editor.cc index 349822711..9ef9e2fe1 100644 --- a/src/gui/widgets/shader-editor.cc +++ b/src/gui/widgets/shader-editor.cc @@ -711,7 +711,7 @@ void PCSX::Widgets::ShaderEditor::renderWithImgui(GUI *gui, ImTextureID textureI if (L.isfunction()) { L.copy(-2); L.setfenv(); - L.push(static_cast(reinterpret_cast(textureID))); + L.push(static_cast(textureID)); L.push(srcSize.x); L.push(srcSize.y); L.push(dstSize.x); @@ -752,7 +752,7 @@ void PCSX::Widgets::ShaderEditor::renderWithImgui(GUI *gui, ImTextureID textureI } void PCSX::Widgets::ShaderEditor::imguiCB(const ImDrawList *parentList, const ImDrawCmd *cmd) { - GLuint textureID = static_cast(reinterpret_cast(cmd->TextureId)); + GLuint textureID = static_cast(cmd->TextureId); GLfloat projMtx[4][4]; if (m_imguiProjMtxLoc == -1) { diff --git a/src/gui/widgets/sio1.cc b/src/gui/widgets/sio1.cc index ac8261625..77a1e6c00 100644 --- a/src/gui/widgets/sio1.cc +++ b/src/gui/widgets/sio1.cc @@ -132,8 +132,7 @@ void PCSX::Widgets::SIO1::DrawRegisterEditor(T* reg, const char* regname, SIO1Re } else if constexpr (sizeof(T) == 4) { displayFormat = "%08x"; } else { - []() { static_assert(f, "No known formatter"); } - (); + []() { static_assert(f, "No known formatter"); }(); } snprintf(currentValue, 11, displayFormat, *reg); diff --git a/src/gui/widgets/typed_debugger.cc b/src/gui/widgets/typed_debugger.cc index 1281d5afc..55e68357e 100644 --- a/src/gui/widgets/typed_debugger.cc +++ b/src/gui/widgets/typed_debugger.cc @@ -138,7 +138,11 @@ void PCSX::Widgets::TypedDebugger::import(std::string_view fileContents, ImportT } } -PCSX::Widgets::TypedDebugger::TypedDebugger(bool& show) : m_show(show), m_listener(g_system->m_eventBus) { +PCSX::Widgets::TypedDebugger::TypedDebugger(bool& show, std::vector& favorites) + : m_show(show), + m_listener(g_system->m_eventBus), + m_importDataTypesFileDialog(l_("Import data types"), favorites), + m_importFunctionsFileDialog(l_("Import functions"), favorites) { m_listener.listen([this](const auto& event) { m_displayedWatchData.clear(); for (const auto* bp : m_watchBreakpoints) { diff --git a/src/gui/widgets/typed_debugger.h b/src/gui/widgets/typed_debugger.h index 4b20e302e..7de667393 100644 --- a/src/gui/widgets/typed_debugger.h +++ b/src/gui/widgets/typed_debugger.h @@ -38,16 +38,16 @@ class TypedDebugger { public: void draw(const char* title, GUI* gui); bool& m_show; - TypedDebugger(bool& show); + TypedDebugger(bool& show, std::vector& favorites); private: /** * Data importation. */ std::vector m_dataTypesFile; - Widgets::FileDialog<> m_importDataTypesFileDialog = {l_("Import data types")}; + Widgets::FileDialog<> m_importDataTypesFileDialog; std::vector m_functionsFile; - Widgets::FileDialog<> m_importFunctionsFileDialog = {l_("Import functions")}; + Widgets::FileDialog<> m_importFunctionsFileDialog; enum class ImportType { DataTypes, Functions }; void import(std::string_view filename, ImportType importType); diff --git a/src/gui/widgets/vram-viewer.cc b/src/gui/widgets/vram-viewer.cc index f14503a57..e3611f14d 100644 --- a/src/gui/widgets/vram-viewer.cc +++ b/src/gui/widgets/vram-viewer.cc @@ -422,7 +422,7 @@ void PCSX::Widgets::VRAMViewer::drawVRAM(GUI *gui, GLuint textureID) { ImVec2 texTL = ImVec2(0.0f, 0.0f) - m_cornerTL / dimensions; ImVec2 texBR = ImVec2(1.0f, 1.0f) - (m_cornerBR - m_resolution) / dimensions; ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); - ImGui::ImageButton("vram", reinterpret_cast(textureID), m_resolution, texTL, texBR); + ImGui::ImageButton("vram", textureID, m_resolution, texTL, texBR); ImGui::PopStyleVar(); if (m_clutDestination && m_selectingClut) { m_clutDestination->m_clut = m_mouseUV; diff --git a/src/lua/luafile.cc b/src/lua/luafile.cc index d51c5bf12..69dc287c9 100644 --- a/src/lua/luafile.cc +++ b/src/lua/luafile.cc @@ -59,8 +59,8 @@ LuaFile* openFile(const char* filename, FileOps type) { } LuaFile* openFileWithCallback(const char* url, void (*callback)()) { - return new LuaFile(new PCSX::UvFile( - url, [callback]() { callback(); }, PCSX::g_system->getLoop(), PCSX::UvFile::DOWNLOAD_URL)); + return new LuaFile( + new PCSX::UvFile(url, [callback]() { callback(); }, PCSX::g_system->getLoop(), PCSX::UvFile::DOWNLOAD_URL)); } LuaFile* bufferFileReadOnly(void* data, uint64_t size) { return new LuaFile(new PCSX::BufferFile(data, size)); } diff --git a/src/main/main.cc b/src/main/main.cc index 110ab8bf4..36591940d 100644 --- a/src/main/main.cc +++ b/src/main/main.cc @@ -220,9 +220,10 @@ int pcsxMain(int argc, char **argv) { // At this point, we're committed to run the emulator, so we first create it, and the UI next. PCSX::Emulator *emulator = new PCSX::Emulator(); PCSX::g_emulator = emulator; + auto &favorites = emulator->settings.get().value; s_ui = args.get("no-ui") || args.get("cli") ? reinterpret_cast(new PCSX::TUI()) - : reinterpret_cast(new PCSX::GUI()); + : reinterpret_cast(new PCSX::GUI(favorites)); // Settings will be loaded after this initialization. s_ui->init([&emulator, &args, &system]() { // Start tweaking / sanitizing settings a bit, while continuing to parse the command line diff --git a/src/mips/common/crt0/cxxglue.c b/src/mips/common/crt0/cxxglue.c index d3124eba0..80610b742 100644 --- a/src/mips/common/crt0/cxxglue.c +++ b/src/mips/common/crt0/cxxglue.c @@ -43,9 +43,9 @@ extern fptr __preinit_array_end[] __attribute__((weak)); extern fptr __init_array_start[] __attribute__((weak)); extern fptr __init_array_end[] __attribute__((weak)); -void main(); +int main(int argc, char ** argv); -void cxxmain() { +void cxxmain(int argc, char ** argv) { size_t count, i; count = __preinit_array_end - __preinit_array_start; @@ -64,14 +64,42 @@ void cxxmain() { } } - main(); + pcsx_exit(main(argc, argv)); +} + +// These two technically aren't part of the standard library requirements, but can +// be invoked by the freestanding libstdc++, so might as well. +__attribute__((weak)) size_t strlen(const char * s) { + size_t r = 0; + + while (*s++) r++; + + return r; +} + +__attribute__((weak)) const void * memchr(const void * _s, int c, size_t n) { + const uint8_t * s = (uint8_t *) _s; + size_t i; + + for (i = 0; i < n; i++, s++) { + if (*s == c) return s; + } + + return NULL; +} + +// std::terminate(), called by the freestanding libstdc++ instead of +// throwing exceptions, when they are disabled. +__attribute__((weak)) void _ZSt9terminatev() { + pcsx_exit(-1); + while (1) asm(""); } __attribute__((weak)) void abort() { pcsx_debugbreak(); + pcsx_exit(-1); // TODO: make this better - while (1) - ; + while (1) asm(""); } // This will be called if a pure virtual function is called, usually mistakenly calling diff --git a/src/mips/common/hardware/gpu.h b/src/mips/common/hardware/gpu.h index 46d2e7bbb..309b81c88 100644 --- a/src/mips/common/hardware/gpu.h +++ b/src/mips/common/hardware/gpu.h @@ -72,10 +72,7 @@ struct DisplayModeConfig { enum HResolutionExtended hResolutionExtended; }; -static inline void waitGPU() { - while ((GPU_STATUS & 0x04000000) == 0) - ; -} +static inline void waitGPU() { while ((GPU_STATUS & 0x04000000) == 0); } static inline void sendGPUData(uint32_t data) { waitGPU(); diff --git a/src/mips/common/hardware/sio1.c b/src/mips/common/hardware/sio1.c index c09409bc0..cfb3e8ca8 100644 --- a/src/mips/common/hardware/sio1.c +++ b/src/mips/common/hardware/sio1.c @@ -44,7 +44,6 @@ void sio1_init() { } void sio1_putc(uint8_t byte) { - while ((SIO1_STAT & 1) == 0) - ; + while ((SIO1_STAT & 1) == 0); SIO1_DATA = byte; } diff --git a/src/mips/common/syscalls/syscalls.h b/src/mips/common/syscalls/syscalls.h index 22fab25d0..f2dc1ebc8 100644 --- a/src/mips/common/syscalls/syscalls.h +++ b/src/mips/common/syscalls/syscalls.h @@ -60,13 +60,13 @@ static __attribute__((always_inline)) int changeThreadSubFunction(uint32_t addre static __attribute__((always_inline)) size_t syscall_write(int fd, const void *buf, size_t size) { register int n asm("t1") = 0x03; __asm__ volatile("" : "=r"(n) : "r"(n)); - return ((size_t (*)(int, const void *, size_t))0xa0)(fd, buf, size); + return ((size_t(*)(int, const void *, size_t))0xa0)(fd, buf, size); } static __attribute__((always_inline, returns_twice)) int syscall_setjmp(struct JmpBuf *buf) { register int n asm("t1") = 0x13; __asm__ volatile("" : "=r"(n) : "r"(n)); - return ((int (*)(struct JmpBuf * buf))0xa0)(buf); + return ((int (*)(struct JmpBuf *buf))0xa0)(buf); } static __attribute__((always_inline, noreturn)) void syscall_longjmp(struct JmpBuf *buf, int ret) { diff --git a/src/mips/cxxhello/main.cpp b/src/mips/cxxhello/main.cpp index 842e11c4d..adfe29393 100644 --- a/src/mips/cxxhello/main.cpp +++ b/src/mips/cxxhello/main.cpp @@ -57,6 +57,5 @@ std::string_view HelloWorld::getName() { return "World"; } int main() { HelloWorld hw; hw.print(); - while (1) - ; + while (1); } diff --git a/src/mips/helloworld/main/main.c b/src/mips/helloworld/main/main.c index 3170a00c6..1f5c214e7 100644 --- a/src/mips/helloworld/main/main.c +++ b/src/mips/helloworld/main/main.c @@ -28,6 +28,5 @@ SOFTWARE. int main() { ramsyscall_printf("Hello world\n"); - while (1) - ; + while (1); } diff --git a/src/mips/openbios/cdrom/cdrom.c b/src/mips/openbios/cdrom/cdrom.c index 4d39a8a7b..2f3698dfa 100644 --- a/src/mips/openbios/cdrom/cdrom.c +++ b/src/mips/openbios/cdrom/cdrom.c @@ -53,8 +53,7 @@ void initializeCDRomHandlersAndEvents() { static void initializeSoftwareAndHardware() { initializeCDRomHandlersAndEvents(); - while (!syscall_cdromInnerInit()) - ; + while (!syscall_cdromInnerInit()); } void initCDRom() { @@ -78,8 +77,7 @@ int cdromBlockGetStatus() { uint8_t status; int cyclesToWait = 9; - while (!syscall_cdromGetStatus(&status) && (--cyclesToWait > 0)) - ; + while (!syscall_cdromGetStatus(&status) && (--cyclesToWait > 0)); if (cyclesToWait < 1) { syscall_exception(0x44, 0x1f); return -1; diff --git a/src/mips/openbios/cdrom/filesystem.c b/src/mips/openbios/cdrom/filesystem.c index 6db415e98..c5260db6a 100644 --- a/src/mips/openbios/cdrom/filesystem.c +++ b/src/mips/openbios/cdrom/filesystem.c @@ -238,13 +238,11 @@ int dev_cd_open(struct File *file, const char *filename, int mode) { char canonicalFilename[32]; char *ptr = canonicalFilename; - while ((*ptr++ = toupper(*filename++))) - ; + while ((*ptr++ = toupper(*filename++))); ptr = canonicalFilename; char c; - while (((c = *ptr++) != 0) && (c != ';')) - ; + while (((c = *ptr++) != 0) && (c != ';')); if (c == 0) strcat(canonicalFilename, ";1"); int id; diff --git a/src/mips/openbios/cdrom/helpers.c b/src/mips/openbios/cdrom/helpers.c index 4bc9cd692..53343c910 100644 --- a/src/mips/openbios/cdrom/helpers.c +++ b/src/mips/openbios/cdrom/helpers.c @@ -47,8 +47,7 @@ int cdromBlockReading(int count, int sector, char* buffer) { for (retries = 0; retries < 10; retries++) { int cyclesToWait = 99999; - while (!syscall_cdromSeekL(msf) && (--cyclesToWait > 0)) - ; + while (!syscall_cdromSeekL(msf) && (--cyclesToWait > 0)); if (cyclesToWait < 1) { syscall_exception(0x44, 0x0b); @@ -63,8 +62,7 @@ int cdromBlockReading(int count, int sector, char* buffer) { } cyclesToWait = 99999; - while (!syscall_cdromRead(count, buffer, 0x80) && (--cyclesToWait > 0)) - ; + while (!syscall_cdromRead(count, buffer, 0x80) && (--cyclesToWait > 0)); if (cyclesToWait < 1) { syscall_exception(0x44, 0x0c); return -1; diff --git a/src/mips/openbios/fileio/filesystem.c b/src/mips/openbios/fileio/filesystem.c index c43625895..a5b51ba01 100644 --- a/src/mips/openbios/fileio/filesystem.c +++ b/src/mips/openbios/fileio/filesystem.c @@ -55,9 +55,7 @@ struct DirEntry *firstFile(const char *filepath, struct DirEntry *entry) { } } -struct DirEntry *nextFile(struct DirEntry *entry) { - return g_firstFile->device->nextFile(g_firstFile, entry); -} +struct DirEntry *nextFile(struct DirEntry *entry) { return g_firstFile->device->nextFile(g_firstFile, entry); } int format(const char *deviceName) { struct File *file = findEmptyFile(); diff --git a/src/mips/openbios/gpu/gpu.c b/src/mips/openbios/gpu/gpu.c index 7f112e3a9..01aacd6eb 100644 --- a/src/mips/openbios/gpu/gpu.c +++ b/src/mips/openbios/gpu/gpu.c @@ -113,8 +113,7 @@ int GPU_sync() { return -1; } } - while ((GPU_STATUS & 0x4000000) == 0) - ; + while ((GPU_STATUS & 0x4000000) == 0); GPU_STATUS = 0x4000000; } return 0; diff --git a/src/mips/openbios/kernel/globals.h b/src/mips/openbios/kernel/globals.h index 66d06a14c..b37724ae8 100644 --- a/src/mips/openbios/kernel/globals.h +++ b/src/mips/openbios/kernel/globals.h @@ -33,7 +33,9 @@ SOFTWARE. #include "openbios/kernel/events.h" #include "openbios/kernel/threads.h" -extern struct { uint32_t ramsize, unk1, unk2; } __globals60; +extern struct { + uint32_t ramsize, unk1, unk2; +} __globals60; extern struct { /* 100 */ struct HandlersStorage* handlersArray; diff --git a/src/mips/openbios/kernel/handlers.c b/src/mips/openbios/kernel/handlers.c index 2dc941cb3..f9ef6daf3 100644 --- a/src/mips/openbios/kernel/handlers.c +++ b/src/mips/openbios/kernel/handlers.c @@ -107,8 +107,7 @@ void unimplemented(uint32_t table, uint32_t call, uint32_t ra) { osDbgPrintf("hi = %p - lo = %p\r\n", regs->GPR.r[32], regs->GPR.r[33]); osDbgPrintf("=== halting ===\r\n"); pcsx_debugbreak(); - while (1) - ; + while (1); } static void installExceptionHandler() { installHandler((uint32_t *)exceptionVector, (uint32_t *)0x80); } diff --git a/src/mips/openbios/kernel/psxexe.c b/src/mips/openbios/kernel/psxexe.c index 1a94ced56..7f28b03ba 100644 --- a/src/mips/openbios/kernel/psxexe.c +++ b/src/mips/openbios/kernel/psxexe.c @@ -80,8 +80,7 @@ void loadAndExec(const char *filename, uint32_t stackStart, uint32_t stackSize) filename++; } - while ((*ptr++ = toupper(*filename++)) != 0) - ; + while ((*ptr++ = toupper(*filename++)) != 0); ptr = localFilename; while (((c = *ptr) != 0) && (c != ';')) ptr++; @@ -107,6 +106,5 @@ void loadAndExec(const char *filename, uint32_t stackStart, uint32_t stackSize) exec(&binaryHeader, 1, NULL); } psxprintf("No boot file !\n"); - while (1) - ; + while (1); } diff --git a/src/mips/openbios/patches/patches.c b/src/mips/openbios/patches/patches.c index 8f3cd57cc..0582aab52 100644 --- a/src/mips/openbios/patches/patches.c +++ b/src/mips/openbios/patches/patches.c @@ -213,7 +213,6 @@ void patch_hook(uint32_t* ra, enum patch_table table) { romsyscall_printf("Stopping.\n", t, h); enterCriticalSection(); pcsx_debugbreak(); - while (1) - ; + while (1); } } diff --git a/src/mips/openbios/sio0/card.c b/src/mips/openbios/sio0/card.c index 295746005..a08ea55b6 100644 --- a/src/mips/openbios/sio0/card.c +++ b/src/mips/openbios/sio0/card.c @@ -195,8 +195,7 @@ int __attribute__((section(".ramtext"))) mcReadHandler() { SIOS[0].ctrl |= 0x0010; IREG = ~IRQ_CONTROLLER; if (b != g_mcChecksum[port]) return -1; - while ((SIOS[0].stat & 2) == 0) - ; + while ((SIOS[0].stat & 2) == 0); return SIOS[0].fifo == 0x47 ? 1 : -1; default: return -1; @@ -292,8 +291,7 @@ int __attribute__((section(".ramtext"))) mcWriteHandler() { SIOS[0].ctrl |= 0x0010; IREG = ~IRQ_CONTROLLER; if (b != 0x5d) return -1; - while ((SIOS[0].stat & 2) == 0) - ; + while ((SIOS[0].stat & 2) == 0); if (!g_skipErrorOnNewCard && ((s_mcFlagByte[port] & 4) != 0)) { g_mcLastPort = g_mcPortFlipping; g_skipErrorOnNewCard = 0; // whyyyy diff --git a/src/mips/openbios/sio0/driver.c b/src/mips/openbios/sio0/driver.c index 1bbe28987..e33dba5f3 100644 --- a/src/mips/openbios/sio0/driver.c +++ b/src/mips/openbios/sio0/driver.c @@ -113,15 +113,13 @@ static uint32_t __attribute__((section(".ramtext"))) readPad(int pad) { SIOS[0].fifo; // throw away busyloop(40); SIOS[0].ctrl = mask | 0x1003; - while (!(SIOS[0].stat & 1)) - ; + while (!(SIOS[0].stat & 1)); g_sio0Mask = mask; SIOS[0].fifo = 1; busyloop(20); SIOS[0].ctrl |= 0x10; IREG = ~IRQ_CONTROLLER; - while (!(SIOS[0].stat & 2)) - ; + while (!(SIOS[0].stat & 2)); SIOS[0].fifo; // throw away busyloop(40); @@ -138,8 +136,7 @@ static uint32_t __attribute__((section(".ramtext"))) readPad(int pad) { SIOS[0].ctrl |= 0x10; IREG = ~IRQ_CONTROLLER; - while (!(SIOS[0].stat & 2)) - ; + while (!(SIOS[0].stat & 2)); uint32_t fifoBytes = SIOS[0].fifo; padBuffer[1] = fifoBytes & 0xff; fifoBytes &= 0x0f; @@ -159,8 +156,7 @@ static uint32_t __attribute__((section(".ramtext"))) readPad(int pad) { SIOS[0].ctrl |= 0x10; IREG = ~IRQ_CONTROLLER; - while (!(SIOS[0].stat & 2)) - ; + while (!(SIOS[0].stat & 2)); if (SIOS[0].fifo != 0x5a) { padAbort(pad); @@ -186,8 +182,7 @@ static uint32_t __attribute__((section(".ramtext"))) readPad(int pad) { cyclesWaited = 0; while (!(SIOS[0].stat & 2)) { if (!(IREG & IRQ_CONTROLLER)) continue; - while (!(SIOS[0].stat & 2)) - ; + while (!(SIOS[0].stat & 2)); padAbort(pad); return 0xffff; } @@ -209,8 +204,7 @@ static uint32_t __attribute__((section(".ramtext"))) readPad(int pad) { SIOS[0].ctrl |= 0x10; IREG = ~IRQ_CONTROLLER; - while (!(SIOS[0].stat & 2)) - ; + while (!(SIOS[0].stat & 2)); padBuffer[3] = SIOS[0].fifo; padBuffer += 2; @@ -364,8 +358,8 @@ static void __attribute__((section(".ramtext"))) setupBasicSio0Handler() { g_sio0HandlerInfo.padding = 0; } -int __attribute__((section(".ramtext"))) -initPad(uint8_t* pad1Buffer, size_t pad1BufferSize, uint8_t* pad2Buffer, size_t pad2BufferSize) { +int __attribute__((section(".ramtext"))) initPad(uint8_t* pad1Buffer, size_t pad1BufferSize, uint8_t* pad2Buffer, + size_t pad2BufferSize) { // *sigh* ramsyscall_printf("%s\n", "PS-X Control PAD Driver"); g_userPadBuffer = NULL; diff --git a/src/mips/openbios/uC-sdk-glue/BoardInit.c b/src/mips/openbios/uC-sdk-glue/BoardInit.c index 4eba268ef..37a1820ba 100644 --- a/src/mips/openbios/uC-sdk-glue/BoardInit.c +++ b/src/mips/openbios/uC-sdk-glue/BoardInit.c @@ -32,7 +32,4 @@ void BoardLateInit() {} void BoardShutdown() {} -void BoardExceptionHandler(int code) { - while (1) - ; -} +void BoardExceptionHandler(int code) { while (1); } diff --git a/src/mips/psyqo-paths/examples/cdrom-loader/cdrom-loader.cpp b/src/mips/psyqo-paths/examples/cdrom-loader/cdrom-loader.cpp index a2e4568f8..9367dee53 100644 --- a/src/mips/psyqo-paths/examples/cdrom-loader/cdrom-loader.cpp +++ b/src/mips/psyqo-paths/examples/cdrom-loader/cdrom-loader.cpp @@ -24,13 +24,14 @@ SOFTWARE. */ +#include "psyqo-paths/cdrom-loader.hh" + #include "psyqo/application.hh" #include "psyqo/cdrom-device.hh" #include "psyqo/font.hh" #include "psyqo/gpu.hh" #include "psyqo/iso9660-parser.hh" #include "psyqo/scene.hh" -#include "psyqo-paths/cdrom-loader.hh" namespace { @@ -71,9 +72,9 @@ void CDRomLoaderExample::createScene() { pushScene(&cdromLoaderExampleScene); m_cdromLoader.readFile("SYSTEM.CNF;1", cdromLoaderExample.gpu(), cdromLoaderExample.m_isoParser, [this](eastl::vector&& buffer) { - m_buffer = eastl::move(buffer); - m_callbackCalled = true; - }); + m_buffer = eastl::move(buffer); + m_callbackCalled = true; + }); } void CDRomLoaderExampleScene::frame() { diff --git a/src/mips/psyqo-paths/src/cdrom-loader.cpp b/src/mips/psyqo-paths/src/cdrom-loader.cpp index 764b775cb..7831b73ac 100644 --- a/src/mips/psyqo-paths/src/cdrom-loader.cpp +++ b/src/mips/psyqo-paths/src/cdrom-loader.cpp @@ -29,7 +29,7 @@ SOFTWARE. #include "psyqo/kernel.hh" void psyqo::paths::CDRomLoader::setupQueue(eastl::string_view path, GPU& gpu, psyqo::ISO9660Parser& parser, - eastl::function&&)>&& callback) { + eastl::function&&)>&& callback) { Kernel::assert(!m_pending, "Only one file can be read at a time"); m_queue.reset(); m_pending = true; @@ -46,9 +46,7 @@ void psyqo::paths::CDRomLoader::setupQueue(eastl::string_view path, GPU& gpu, ps task->resolve(); }) .then(parser.scheduleReadRequest(&m_request)) - .butCatch([this](auto task) { - m_request.entry.size = 0; - }) + .butCatch([this](auto task) { m_request.entry.size = 0; }) .finally([this](auto task) { m_pending = false; m_data.resize(m_request.entry.size); diff --git a/src/mips/psyqo/advancedpad.hh b/src/mips/psyqo/advancedpad.hh index 0095ee530..0488eb41f 100644 --- a/src/mips/psyqo/advancedpad.hh +++ b/src/mips/psyqo/advancedpad.hh @@ -29,8 +29,6 @@ SOFTWARE. #include #include -#include "psyqo/application.hh" - namespace psyqo { /** diff --git a/src/mips/psyqo/bump-allocator.h b/src/mips/psyqo/bump-allocator.h index 7fb6eb8e6..074c9fa93 100644 --- a/src/mips/psyqo/bump-allocator.h +++ b/src/mips/psyqo/bump-allocator.h @@ -28,7 +28,6 @@ SOFTWARE. #include -#include "psyqo/fragment-concept.hh" #include "psyqo/fragments.hh" #include "psyqo/primitive-concept.hh" @@ -53,19 +52,25 @@ namespace psyqo { template class BumpAllocator { public: - template - Fragments::SimpleFragment

&allocate() { - constexpr size_t size = sizeof(Fragments::SimpleFragment

); - auto *ptr = m_current; + template + Fragments::SimpleFragment

&allocateFragment(Args ...args) { + static constexpr size_t size = sizeof(Fragments::SimpleFragment

); + uint8_t *ptr = m_current; m_current += size; - return *new (ptr) Fragments::SimpleFragment

(); + return *new (ptr) Fragments::SimpleFragment

(args...); } - template - F &allocate() { - constexpr size_t size = sizeof(F); - auto *ptr = m_current; + template + T &allocate(Args ...args) { + size_t size = sizeof(T); + uint8_t *ptr = m_current; + if constexpr (alignof(T) > 1) { + static constexpr size_t a = alignof(T) - 1; + auto alignedptr = reinterpret_cast((reinterpret_cast(ptr) + a) & ~a); + size += alignedptr - ptr; + ptr = alignedptr; + } m_current += size; - return *new (ptr) F(); + return *new (ptr) T(args...); } void reset() { m_current = m_memory; } diff --git a/src/mips/psyqo/cdrom-device.hh b/src/mips/psyqo/cdrom-device.hh index c38fbccae..c3027c742 100644 --- a/src/mips/psyqo/cdrom-device.hh +++ b/src/mips/psyqo/cdrom-device.hh @@ -325,9 +325,7 @@ class CDRomDevice final : public CDRom { * @brief Checks if the CDROM device is in idle state. * */ - [[nodiscard]] bool isIdle() const { - return m_state == 0; - } + [[nodiscard]] bool isIdle() const { return m_state == 0; } private: void switchAction(ActionBase *action); diff --git a/src/mips/psyqo/examples/bezier/bezier.cpp b/src/mips/psyqo/examples/bezier/bezier.cpp index 33fc5306e..0b682f089 100644 --- a/src/mips/psyqo/examples/bezier/bezier.cpp +++ b/src/mips/psyqo/examples/bezier/bezier.cpp @@ -73,8 +73,8 @@ class BezierScene final : public psyqo::Scene { // point, which is always the end point of the curve. for (unsigned i = 0; i < 20; i++) { m_quads[i].setColor({.r = 0xff, .g = 0x80, .b = 0x33}); - m_quads[i].pointC = psyqo::Vertex{{ .x = int16_t(i * 32), .y = 480}}; - m_quads[i].pointD = psyqo::Vertex{{ .x = int16_t(i * 32 + 32), .y = 480}}; + m_quads[i].pointC = psyqo::Vertex{{.x = int16_t(i * 32), .y = 480}}; + m_quads[i].pointD = psyqo::Vertex{{.x = int16_t(i * 32 + 32), .y = 480}}; } m_quads[19].pointB = b; } @@ -148,7 +148,6 @@ void BezierScene::frame() { // Draw the Quad fan. gpu().sendPrimitive(m_quads); - #ifdef DEBUG_BEZIER // Draw the control points. psyqo::Prim::Line line; diff --git a/src/mips/psyqo/examples/cube/cube.cpp b/src/mips/psyqo/examples/cube/cube.cpp index 9f42e6515..395f9fe04 100644 --- a/src/mips/psyqo/examples/cube/cube.cpp +++ b/src/mips/psyqo/examples/cube/cube.cpp @@ -25,17 +25,17 @@ SOFTWARE. */ #include "psyqo/application.hh" -#include "psyqo/gpu.hh" -#include "psyqo/trigonometry.hh" -#include "psyqo/gte-registers.hh" -#include "psyqo/gte-kernels.hh" #include "psyqo/fixed-point.hh" #include "psyqo/fragments.hh" +#include "psyqo/gpu.hh" +#include "psyqo/gte-kernels.hh" +#include "psyqo/gte-registers.hh" #include "psyqo/primitives/common.hh" #include "psyqo/primitives/quads.hh" -#include "psyqo/vector.hh" -#include "psyqo/soft-math.hh" #include "psyqo/scene.hh" +#include "psyqo/soft-math.hh" +#include "psyqo/trigonometry.hh" +#include "psyqo/vector.hh" using namespace psyqo::fixed_point_literals; using namespace psyqo::trig_literals; @@ -45,27 +45,25 @@ static constexpr unsigned NUM_CUBE_FACES = 6; static constexpr unsigned ORDERING_TABLE_SIZE = 240; typedef struct { - uint8_t vertices[4]; - psyqo::Color color; + uint8_t vertices[4]; + psyqo::Color color; } Face; - static constexpr psyqo::Matrix33 identity = {{ - {1.0_fp, 0.0_fp, 0.0_fp}, - {0.0_fp, 1.0_fp, 0.0_fp}, - {0.0_fp, 0.0_fp, 1.0_fp}, + {1.0_fp, 0.0_fp, 0.0_fp}, + {0.0_fp, 1.0_fp, 0.0_fp}, + {0.0_fp, 0.0_fp, 1.0_fp}, }}; class Cube final : public psyqo::Application { void prepare() override; void createScene() override; - public: - psyqo::Trig<> m_trig; + public: + psyqo::Trig<> m_trig; }; class CubeScene final : public psyqo::Scene { - void start(StartReason reason) override; void frame() override; @@ -74,8 +72,8 @@ class CubeScene final : public psyqo::Scene { // We need to create 2 OrderingTable objects since we can't reuse a single one for both // framebuffers, as the previous one may not finish transfering in time. psyqo::OrderingTable m_ots[2]; - - // Since we're using an ordering table, we need to sort fill commands as well, + + // Since we're using an ordering table, we need to sort fill commands as well, // otherwise they'll draw over our beautiful cube. psyqo::Fragments::SimpleFragment m_clear[2]; @@ -83,71 +81,51 @@ class CubeScene final : public psyqo::Scene { static constexpr psyqo::Color c_bg = {.r = 63, .g = 63, .b = 63}; - static constexpr psyqo::Vec3 c_cubeVertices[NUM_CUBE_VERTICES] = { - { .x = -0.05, .y = -0.05, .z = -0.05 }, - { .x = 0.05, .y = -0.05, .z = -0.05 }, - { .x = -0.05, .y = 0.05, .z = -0.05 }, - { .x = 0.05, .y = 0.05, .z = -0.05 }, - { .x = -0.05, .y = -0.05, .z = 0.05 }, - { .x = 0.05, .y = -0.05, .z = 0.05 }, - { .x = -0.05, .y = 0.05, .z = 0.05 }, - { .x = 0.05, .y = 0.05, .z = 0.05 } - }; - + {.x = -0.05, .y = -0.05, .z = -0.05}, {.x = 0.05, .y = -0.05, .z = -0.05}, {.x = -0.05, .y = 0.05, .z = -0.05}, + {.x = 0.05, .y = 0.05, .z = -0.05}, {.x = -0.05, .y = -0.05, .z = 0.05}, {.x = 0.05, .y = -0.05, .z = 0.05}, + {.x = -0.05, .y = 0.05, .z = 0.05}, {.x = 0.05, .y = 0.05, .z = 0.05}}; static constexpr Face c_cubeFaces[NUM_CUBE_FACES] = { - { .vertices = { 0, 1, 2, 3 }, .color = {0,0,255} }, - { .vertices = { 6, 7, 4, 5 }, .color = {0,255,0} }, - { .vertices = { 4, 5, 0, 1 }, .color = {0,255,255} }, - { .vertices = { 7, 6, 3, 2 }, .color = {255,0,0} }, - { .vertices = { 6, 4, 2, 0 }, .color = {255,0,255}}, - { .vertices = { 5, 7, 1, 3 }, .color = {255,255,0} } - }; + {.vertices = {0, 1, 2, 3}, .color = {0, 0, 255}}, {.vertices = {6, 7, 4, 5}, .color = {0, 255, 0}}, + {.vertices = {4, 5, 0, 1}, .color = {0, 255, 255}}, {.vertices = {7, 6, 3, 2}, .color = {255, 0, 0}}, + {.vertices = {6, 4, 2, 0}, .color = {255, 0, 255}}, {.vertices = {5, 7, 1, 3}, .color = {255, 255, 0}}}; }; static Cube cube; static CubeScene cubeScene; void Cube::prepare() { - psyqo::GPU::Configuration config; - config.set(psyqo::GPU::Resolution::W320) - .set(psyqo::GPU::VideoMode::AUTO) - .set(psyqo::GPU::ColorMode::C15BITS) - .set(psyqo::GPU::Interlace::PROGRESSIVE); + psyqo::GPU::Configuration config; + config.set(psyqo::GPU::Resolution::W320) + .set(psyqo::GPU::VideoMode::AUTO) + .set(psyqo::GPU::ColorMode::C15BITS) + .set(psyqo::GPU::Interlace::PROGRESSIVE); - gpu().initialize(config); + gpu().initialize(config); } -void Cube::createScene() { - pushScene(&cubeScene); -} +void Cube::createScene() { pushScene(&cubeScene); } void CubeScene::start(StartReason reason) { - // Clear the translation registers psyqo::GTE::clear(); psyqo::GTE::clear(); psyqo::GTE::clear(); - // Set the screen offset in the GTE. (this is half the X and Y resolutions as standard) psyqo::GTE::write(psyqo::FixedPoint<16>(160.0).raw()); psyqo::GTE::write(psyqo::FixedPoint<16>(120.0).raw()); - // Write the projection plane distance. psyqo::GTE::write(120); - // Set the scaling for Z averaging. psyqo::GTE::write(ORDERING_TABLE_SIZE / 3); psyqo::GTE::write(ORDERING_TABLE_SIZE / 4); - } void CubeScene::frame() { - eastl::array projected; // Get which frame we're currently drawing @@ -160,11 +138,10 @@ void CubeScene::frame() { // Chain the fill command accordingly to clear the buffer gpu().getNextClear(clear.primitive, c_bg); gpu().chain(clear); - // We want the cube to appear slightly further away, so we translate it by 512 on the Z-axis. psyqo::GTE::write(512); - + // Here we're setting up the rotation for the spinning cube // First, generate a rotation matrix for the X-axis and Y-axis auto transform = psyqo::SoftMath::generateRotationMatrix33(m_rot, psyqo::SoftMath::Axis::X, cube.m_trig); @@ -179,19 +156,16 @@ void CubeScene::frame() { // Apply the combined rotation and write it to the pseudo register for the cube's rotation psyqo::SoftMath::multiplyMatrix33(transform, rot, &transform); psyqo::GTE::writeUnsafe(transform); - - int faceNum = 0; - for(auto face : c_cubeFaces) { - - // We load the first 3 vertices into the GTE. We can't do all 4 at once because the GTE + for (auto face : c_cubeFaces) { + // We load the first 3 vertices into the GTE. We can't do all 4 at once because the GTE // handles only 3 at a time... psyqo::GTE::writeUnsafe(c_cubeVertices[face.vertices[0]]); psyqo::GTE::writeUnsafe(c_cubeVertices[face.vertices[1]]); psyqo::GTE::writeUnsafe(c_cubeVertices[face.vertices[2]]); - + // We perform rtpt (Perspective transformation) to the three verticies. psyqo::GTE::Kernels::rtpt(); @@ -200,12 +174,11 @@ void CubeScene::frame() { psyqo::GTE::Kernels::nclip(); // Read the result of nclip and skip rendering this face if it's not facing us - uint32_t mac0 = 0; - psyqo::GTE::read(&mac0); - if(mac0 <= 0) - continue; + int32_t mac0 = 0; + psyqo::GTE::read(reinterpret_cast(&mac0)); + if (mac0 <= 0) continue; - // Since the GTE can only handle 3 vertices at a time, we need to store our first vertex + // Since the GTE can only handle 3 vertices at a time, we need to store our first vertex // so we can write our last one. psyqo::GTE::read(&projected[0].packed); @@ -214,17 +187,15 @@ void CubeScene::frame() { // Perform rtps (Perspective transformation) to the last vertice (rtpS - single, rtpT - triple). psyqo::GTE::Kernels::rtps(); - + // Calculate the average Z for the z-Index to be put in the ordering table psyqo::GTE::Kernels::avsz4(); - uint32_t zIndex = 0; - psyqo::GTE::read(&zIndex); - + int32_t zIndex = 0; + psyqo::GTE::read(reinterpret_cast(&zIndex)); // If the Z-index is out of bounds for our ordering table, we skip rendering this face. - if(zIndex < 0 || zIndex >= ORDERING_TABLE_SIZE) - continue; - + if (zIndex < 0 || zIndex >= ORDERING_TABLE_SIZE) continue; + // Read the 3 remaining vertices from the GTE psyqo::GTE::read(&projected[1].packed); psyqo::GTE::read(&projected[2].packed); @@ -243,12 +214,10 @@ void CubeScene::frame() { ot.insert(quad, zIndex); faceNum++; } - - // Send the entire ordering table as a DMA chain to the GPU. + + // Send the entire ordering table as a DMA chain to the GPU. gpu().chain(ot); m_rot += 0.005_pi; } - -int main() {return cube.run();} - +int main() { return cube.run(); } diff --git a/src/mips/psyqo/examples/hello/hello.cpp b/src/mips/psyqo/examples/hello/hello.cpp index a63289981..4bb86eb3f 100644 --- a/src/mips/psyqo/examples/hello/hello.cpp +++ b/src/mips/psyqo/examples/hello/hello.cpp @@ -34,7 +34,6 @@ namespace { // A PSYQo software needs to declare one `Application` object. // This is the one we're going to do for our hello world. class Hello final : public psyqo::Application { - void prepare() override; void createScene() override; diff --git a/src/mips/psyqo/examples/tetris/gameover.cpp b/src/mips/psyqo/examples/tetris/gameover.cpp index 51c2c8e32..e9c6c5971 100644 --- a/src/mips/psyqo/examples/tetris/gameover.cpp +++ b/src/mips/psyqo/examples/tetris/gameover.cpp @@ -48,8 +48,7 @@ void GameOver::frame() { // The main difference with the Pause scene is we pop all the scenes, // not just the current one. This will force the application to // re-create the root scene. - while (popScene()) - ; + while (popScene()); } } diff --git a/src/mips/psyqo/examples/tetris/pieces.cpp b/src/mips/psyqo/examples/tetris/pieces.cpp index 3dbcee0fe..0e3c771ea 100644 --- a/src/mips/psyqo/examples/tetris/pieces.cpp +++ b/src/mips/psyqo/examples/tetris/pieces.cpp @@ -212,4 +212,3 @@ const uint8_t PIECES[7][4][4][4] = { }, }, }; - diff --git a/src/mips/psyqo/examples/tetris/sound.cpp b/src/mips/psyqo/examples/tetris/sound.cpp index 22bbc0c82..02fc47b88 100644 --- a/src/mips/psyqo/examples/tetris/sound.cpp +++ b/src/mips/psyqo/examples/tetris/sound.cpp @@ -30,13 +30,9 @@ extern "C" { #include "modplayer/modplayer.h" } -void Sound::playClick() { - MOD_PlaySoundEffect(4, 28, 30, m_volume); -} +void Sound::playClick() { MOD_PlaySoundEffect(4, 28, 30, m_volume); } -void Sound::playFlip(int pitch) { - MOD_PlaySoundEffect(5, 27, 30 + pitch, m_volume); -} +void Sound::playFlip(int pitch) { MOD_PlaySoundEffect(5, 27, 30 + pitch, m_volume); } void Sound::playDrop(unsigned int volume) { auto vol = m_volume; diff --git a/src/mips/psyqo/fragment-concept.hh b/src/mips/psyqo/fragment-concept.hh index 9c125baca..f025dd5ee 100644 --- a/src/mips/psyqo/fragment-concept.hh +++ b/src/mips/psyqo/fragment-concept.hh @@ -26,8 +26,9 @@ SOFTWARE. #pragma once +#include + #include -#include #include namespace psyqo { diff --git a/src/mips/psyqo/gte-registers.hh b/src/mips/psyqo/gte-registers.hh index 35376a959..b210559e1 100644 --- a/src/mips/psyqo/gte-registers.hh +++ b/src/mips/psyqo/gte-registers.hh @@ -69,72 +69,72 @@ struct PackedVec3 { /** * @brief The list of available GTE registers. - */ + */ enum class Register { - VXY0, /* Vector 0 (X,Y) */ - VZ0, /* Vector 0 (Z) */ - VXY1, /* Vector 1 (X,Y) */ - VZ1, /* Vector 1 (Z) */ - VXY2, /* Vector 2 (X,Y) */ - VZ2, /* Vector 2 (Z) */ - RGB, /* Color/code value */ - OTZ, /* Average Z value (for Ordering Table) */ - IR0, /* 16bit Accumulator 0 (Interpolate) */ - IR1, /* 16bit Accumulator 1 (Vector) */ - IR2, /* 16bit Accumulator 2 (Vector) */ - IR3, /* 16bit Accumulator 3 (Vector) */ - SXY0, /* Screen XY-coordinate 0 FIFO */ - SXY1, /* Screen XY-coordinate 1 FIFO */ - SXY2, /* Screen XY-coordinate 2 FIFO */ - SXYP, /* Screen XY-coordinate P FIFO */ - SZ0, /* Screen Z-coordinate 0 FIFO */ - SZ1, /* Screen Z-coordinate 1 FIFO */ - SZ2, /* Screen Z-coordinate 2 FIFO */ - SZ3, /* Screen Z-coordinate 3 FIFO */ - RGB0, /* Color CRGB-code/color 0 FIFO */ - RGB1, /* Color CRGB-code/color 1 FIFO */ - RGB2, /* Color CRGB-code/color 2 FIFO */ - RES1, /* Prohibited */ - MAC0, /* 32bit Maths Accumulators 0 (Value) */ - MAC1, /* 32bit Maths Accumulators 1 (Vector) */ - MAC2, /* 32bit Maths Accumulators 2 (Vector) */ - MAC3, /* 32bit Maths Accumulators 3 (Vector) */ - IRGB, /* Convert RGB Color (48bit vs 15bit) */ - ORGB, /* Convert RGB Color (48bit vs 15bit) */ - LZCS, /* Count Leading-Zeroes/Ones (sign bits) */ - LZCR, /* Count Leading-Zeroes/Ones (sign bits) */ + VXY0, /* Vector 0 (X,Y) */ + VZ0, /* Vector 0 (Z) */ + VXY1, /* Vector 1 (X,Y) */ + VZ1, /* Vector 1 (Z) */ + VXY2, /* Vector 2 (X,Y) */ + VZ2, /* Vector 2 (Z) */ + RGB, /* Color/code value */ + OTZ, /* Average Z value (for Ordering Table) */ + IR0, /* 16bit Accumulator 0 (Interpolate) */ + IR1, /* 16bit Accumulator 1 (Vector) */ + IR2, /* 16bit Accumulator 2 (Vector) */ + IR3, /* 16bit Accumulator 3 (Vector) */ + SXY0, /* Screen XY-coordinate 0 FIFO */ + SXY1, /* Screen XY-coordinate 1 FIFO */ + SXY2, /* Screen XY-coordinate 2 FIFO */ + SXYP, /* Screen XY-coordinate P FIFO */ + SZ0, /* Screen Z-coordinate 0 FIFO */ + SZ1, /* Screen Z-coordinate 1 FIFO */ + SZ2, /* Screen Z-coordinate 2 FIFO */ + SZ3, /* Screen Z-coordinate 3 FIFO */ + RGB0, /* Color CRGB-code/color 0 FIFO */ + RGB1, /* Color CRGB-code/color 1 FIFO */ + RGB2, /* Color CRGB-code/color 2 FIFO */ + RES1, /* Prohibited */ + MAC0, /* 32bit Maths Accumulators 0 (Value) */ + MAC1, /* 32bit Maths Accumulators 1 (Vector) */ + MAC2, /* 32bit Maths Accumulators 2 (Vector) */ + MAC3, /* 32bit Maths Accumulators 3 (Vector) */ + IRGB, /* Convert RGB Color (48bit vs 15bit) */ + ORGB, /* Convert RGB Color (48bit vs 15bit) */ + LZCS, /* Count Leading-Zeroes/Ones (sign bits) */ + LZCR, /* Count Leading-Zeroes/Ones (sign bits) */ R11R12, /* Rotation matrix (3x3) */ R13R21, /* Rotation matrix (3x3) */ R22R23, /* Rotation matrix (3x3) */ R31R32, /* Rotation matrix (3x3) */ - R33, /* Rotation matrix (3x3) */ - TRX, /* Translation vector (X) */ - TRY, /* Translation vector (Y) */ - TRZ, /* Translation vector (Z) */ + R33, /* Rotation matrix (3x3) */ + TRX, /* Translation vector (X) */ + TRY, /* Translation vector (Y) */ + TRZ, /* Translation vector (Z) */ L11L12, /* Light source matrix (3x3) */ L13L21, /* Light source matrix (3x3) */ L22L23, /* Light source matrix (3x3) */ L31L32, /* Light source matrix (3x3) */ - L33, /* Light source matrix (3x3) */ - RBK, /* Background color(R) */ - GBK, /* Background color(G) */ - BBK, /* Background color(B) */ + L33, /* Light source matrix (3x3) */ + RBK, /* Background color(R) */ + GBK, /* Background color(G) */ + BBK, /* Background color(B) */ LR1LR2, /* Light color matrix source (3x3) */ LR3LG1, /* Light color matrix source (3x3) */ LG2LG3, /* Light color matrix source (3x3) */ LB1LB2, /* Light color matrix source (3x3) */ - LB3, /* Light color matrix source (3x3) */ - RFC, /* Far color (R) */ - GFC, /* Far color (G) */ - BFC, /* Far color (B) */ - OFX, /* Screen offset (X) */ - OFY, /* Screen offset (Y) */ - H, /* Projection plane distance. */ - DQA, /* Depth queing parameter A (coeff) */ - DQB, /* Depth queing parameter B (offset) */ - ZSF3, /* Average Z scale factors */ - ZSF4, /* Average Z scale factors */ - FLAG, /* Returns any calculation errors */ + LB3, /* Light color matrix source (3x3) */ + RFC, /* Far color (R) */ + GFC, /* Far color (G) */ + BFC, /* Far color (B) */ + OFX, /* Screen offset (X) */ + OFY, /* Screen offset (Y) */ + H, /* Projection plane distance. */ + DQA, /* Depth queing parameter A (coeff) */ + DQB, /* Depth queing parameter B (offset) */ + ZSF3, /* Average Z scale factors */ + ZSF4, /* Average Z scale factors */ + FLAG, /* Returns any calculation errors */ }; /** @@ -150,7 +150,7 @@ enum class Register { */ enum Safety { Unsafe, /* avoid nops */ - Safe, /* insert nops */ + Safe, /* insert nops */ }; /** @@ -247,15 +247,15 @@ static inline void writeUnsafe(Short low, Short hi) { * @brief The list of available GTE pseudo registers. */ enum class PseudoRegister { - Rotation, /* pseudo register for full rotation matrix, mapped to registers R11R12-R33 */ - Light, /* pseudo register for full light matrix, mapped to registers L11L12-L33 */ - Color, /* pseudo register for full light color matrix, mapped to registers LR1LR2-LB3 */ - V0, /* pseudo register for full Vector 0, mapped to registers VXY0 and VZ0 */ - V1, /* pseudo register for full Vector 1, mapped to registers VXY1 and VZ1 */ - V2, /* pseudo register for full Vector 2, mapped to registers VXY2 and VZ2 */ - SV, /* pseudo register for full 16bit Accumulator Vector, mapped to registers IR1-IR3 */ - LV, /* pseudo register for full 32bit Maths Accumulator Vector, mapped to registers MAC1-MAC3 */ - Translation, /* pseudo register for full Translation vector, mapped to registers TRX-TRZ */ + Rotation, /* pseudo register for full rotation matrix, mapped to registers R11R12-R33 */ + Light, /* pseudo register for full light matrix, mapped to registers L11L12-L33 */ + Color, /* pseudo register for full light color matrix, mapped to registers LR1LR2-LB3 */ + V0, /* pseudo register for full Vector 0, mapped to registers VXY0 and VZ0 */ + V1, /* pseudo register for full Vector 1, mapped to registers VXY1 and VZ1 */ + V2, /* pseudo register for full Vector 2, mapped to registers VXY2 and VZ2 */ + SV, /* pseudo register for full 16bit Accumulator Vector, mapped to registers IR1-IR3 */ + LV, /* pseudo register for full 32bit Maths Accumulator Vector, mapped to registers MAC1-MAC3 */ + Translation, /* pseudo register for full Translation vector, mapped to registers TRX-TRZ */ ScreenOffset, /* pseudo register for full Screen offset, mapped to registers OFX and OFY */ }; @@ -386,7 +386,7 @@ template static inline void read(uint32_t* ptr) { static_assert(reg < Register::R11R12, "Unable to read from register to memory directly"); if constexpr (reg < Register::R11R12) { - asm volatile("swc2 $%1, 0(%0)" ::"r"(ptr), "i"(static_cast(reg))); + asm volatile("swc2 $%2, 0(%1)" : "=m"(*ptr) : "r"(ptr), "i"(static_cast(reg))); } } @@ -843,7 +843,7 @@ inline void writeSafe(const Vec3& in) { template <> inline void writeSafe(const Vec3& in) { write(in.x.raw()); - write(in.y.raw()); + write(in.y.raw()); write(in.z.raw()); } diff --git a/src/mips/psyqo/kernel.hh b/src/mips/psyqo/kernel.hh index bec3b5166..b91377754 100644 --- a/src/mips/psyqo/kernel.hh +++ b/src/mips/psyqo/kernel.hh @@ -262,10 +262,10 @@ void setBreakHandler(unsigned category, eastl::function&& handle /** * @brief Queues a break handler for psyqo's reserved category. - * + * * @param handler The handler to call when a break occurs. */ -void queuePsyqoBreakHandler(eastl::function && handler); +void queuePsyqoBreakHandler(eastl::function&& handler); namespace Internal { void pumpCallbacks(); diff --git a/src/mips/psyqo/primitive-concept.hh b/src/mips/psyqo/primitive-concept.hh index 883b7d7f7..ee16beb8c 100644 --- a/src/mips/psyqo/primitive-concept.hh +++ b/src/mips/psyqo/primitive-concept.hh @@ -26,9 +26,6 @@ SOFTWARE. #pragma once -#include -#include - namespace psyqo { /** @@ -41,7 +38,9 @@ template concept Primitive = requires { { (alignof(Prim) & 3) == 0 }; { (sizeof(Prim) & 3) == 0 }; - { !requires { typename Prim::head; } }; + { + !requires { typename Prim::head; } + }; }; } // namespace psyqo diff --git a/src/mips/psyqo/primitives/common.hh b/src/mips/psyqo/primitives/common.hh index cc79bc558..993ff1fbd 100644 --- a/src/mips/psyqo/primitives/common.hh +++ b/src/mips/psyqo/primitives/common.hh @@ -101,6 +101,10 @@ enum SemiTrans { HalfBackAndHalfFront, FullBackAndFullFront, FullBackSubFullFron enum ColorMode { Tex4Bits, Tex8Bits, Tex16Bits }; } // namespace Prim::TPageAttr +namespace Prim { + enum class Transparency { Auto, Opaque, SemiTransparent }; +} + namespace PrimPieces { /** diff --git a/src/mips/psyqo/primitives/lines.hh b/src/mips/psyqo/primitives/lines.hh index 29e8cef2c..9cd63cfbe 100644 --- a/src/mips/psyqo/primitives/lines.hh +++ b/src/mips/psyqo/primitives/lines.hh @@ -46,7 +46,7 @@ struct Line { Line(Color c) : command(0x40000000 | c.packed) {} Line& setColor(Color c) { uint32_t wasSemiTrans = command & 0x02000000; - command = 0x40000000 | c.packed | wasSemiTrans; + command = 0x40000000 | (c.packed & 0xffffff) | wasSemiTrans; return *this; } Line& setOpaque() { @@ -81,7 +81,7 @@ struct GouraudLine { GouraudLine(Color c) : command(0x50000000 | c.packed) {} GouraudLine& setColorA(Color c) { uint32_t wasSemiTrans = command & 0x02000000; - command = 0x50000000 | c.packed | wasSemiTrans; + command = 0x50000000 | (c.packed & 0xffffff) | wasSemiTrans; return *this; } GouraudLine& setColorB(Color c) { @@ -125,7 +125,7 @@ struct PolyLineBegin { PolyLineBegin(Color c) : command(0x48000000 | c.packed) {} PolyLineBegin& setColor(Color c) { uint32_t wasSemiTrans = command & 0x02000000; - command = 0x48000000 | c.packed | wasSemiTrans; + command = 0x48000000 | (c.packed & 0xffffff) | wasSemiTrans; return *this; } PolyLineBegin& setOpaque() { @@ -166,7 +166,7 @@ struct PolyLine { PolyLine(Color c) : command(0x48000000 | c.packed) {} PolyLine& setColor(Color c) { uint32_t wasSemiTrans = command & 0x02000000; - command = 0x48000000 | c.packed | wasSemiTrans; + command = 0x48000000 | (c.packed & 0xffffff) | wasSemiTrans; return *this; } PolyLine& setOpaque() { diff --git a/src/mips/psyqo/primitives/quads.hh b/src/mips/psyqo/primitives/quads.hh index ecef146fb..cb7e552c7 100644 --- a/src/mips/psyqo/primitives/quads.hh +++ b/src/mips/psyqo/primitives/quads.hh @@ -28,6 +28,8 @@ SOFTWARE. #include +#include "psyqo/gte-kernels.hh" +#include "psyqo/gte-registers.hh" #include "psyqo/primitives/common.hh" namespace psyqo { @@ -52,7 +54,7 @@ struct Quad { Quad(Color c) : command(0x28000000 | c.packed) {} Quad& setColor(Color c) { uint32_t wasSemiTrans = command & 0x02000000; - command = 0x28000000 | c.packed | wasSemiTrans; + command = 0x28000000 | (c.packed & 0xffffff) | wasSemiTrans; return *this; } Quad& setOpaque() { @@ -107,7 +109,7 @@ struct TexturedQuad { TexturedQuad(Color c) : command(0x2c000000 | c.packed) {} TexturedQuad& setColor(Color c) { uint32_t wasSemiTrans = command & 0x02000000; - command = 0x2c000000 | c.packed | wasSemiTrans; + command = 0x2c000000 | (c.packed & 0xffffff) | wasSemiTrans; return *this; } TexturedQuad& setOpaque() { @@ -149,7 +151,7 @@ struct GouraudQuad { GouraudQuad(Color c) : command(0x38000000 | c.packed) {} GouraudQuad& setColorA(Color c) { uint32_t wasSemiTrans = command & 0x02000000; - command = 0x38000000 | c.packed | wasSemiTrans; + command = 0x38000000 | (c.packed & 0xffffff) | wasSemiTrans; return *this; } GouraudQuad& setColorB(Color c) { @@ -188,6 +190,48 @@ struct GouraudQuad { pointD = v; return *this; } + template + void interpolateColors(const Color* a, const Color* b, const Color* c, const Color* d) { + uint32_t rgb; + if constexpr (transparency == Transparency::Auto) { + rgb = (a->packed & 0xffffff) | (command & 0xff000000); + } else if constexpr (transparency == Transparency::Opaque) { + rgb = (a->packed & 0xffffff) | 0x38000000; + } else if constexpr (transparency == Transparency::SemiTransparent) { + rgb = (a->packed & 0xffffff) | 0x3a000000; + } + GTE::write(rgb); + GTE::Kernels::dpcs(); + GTE::read(&command); + GTE::write(&b->packed); + GTE::write(&c->packed); + GTE::write(&d->packed); + GTE::Kernels::dpct(); + GTE::read(&colorB.packed); + GTE::read(&colorC.packed); + GTE::read(&colorD.packed); + } + template + void interpolateColors(Color a, Color b, Color c, Color d) { + uint32_t rgb; + if constexpr (transparency == Transparency::Auto) { + rgb = (a.packed & 0xffffff) | (command & 0xff000000); + } else if constexpr (transparency == Transparency::Opaque) { + rgb = (a.packed & 0xffffff) | 0x38000000; + } else if constexpr (transparency == Transparency::SemiTransparent) { + rgb = (a.packed & 0xffffff) | 0x3a000000; + } + GTE::write(rgb); + GTE::Kernels::dpcs(); + GTE::read(&command); + GTE::write(b.packed); + GTE::write(c.packed); + GTE::write(d.packed); + GTE::Kernels::dpct(); + GTE::read(&colorB.packed); + GTE::read(&colorC.packed); + GTE::read(&colorD.packed); + } private: uint32_t command; @@ -223,7 +267,7 @@ struct GouraudTexturedQuad { GouraudTexturedQuad(Color c) : command(0x3c000000 | c.packed) {} GouraudTexturedQuad& setColorA(Color c) { uint32_t wasSemiTrans = command & 0x02000000; - command = 0x3c000000 | c.packed | wasSemiTrans; + command = 0x3c000000 | (c.packed & 0xffffff) | wasSemiTrans; return *this; } GouraudTexturedQuad& setColorB(Color c) { @@ -246,6 +290,48 @@ struct GouraudTexturedQuad { command |= 0x02000000; return *this; } + template + void interpolateColors(const Color* a, const Color* b, const Color* c, const Color* d) { + uint32_t rgb; + if constexpr (transparency == Transparency::Auto) { + rgb = (a->packed & 0xffffff) | (command & 0xff000000); + } else if constexpr (transparency == Transparency::Opaque) { + rgb = (a->packed & 0xffffff) | 0x3c000000; + } else if constexpr (transparency == Transparency::SemiTransparent) { + rgb = (a->packed & 0xffffff) | 0x3e000000; + } + GTE::write(rgb); + GTE::Kernels::dpcs(); + GTE::read(&command); + GTE::write(&b->packed); + GTE::write(&c->packed); + GTE::write(&d->packed); + GTE::Kernels::dpct(); + GTE::read(&colorB.packed); + GTE::read(&colorC.packed); + GTE::read(&colorD.packed); + } + template + void interpolateColors(Color a, Color b, Color c, Color d) { + uint32_t rgb; + if constexpr (transparency == Transparency::Auto) { + rgb = (a.packed & 0xffffff) | (command & 0xff000000); + } else if constexpr (transparency == Transparency::Opaque) { + rgb = (a.packed & 0xffffff) | 0x3c000000; + } else if constexpr (transparency == Transparency::SemiTransparent) { + rgb = (a.packed & 0xffffff) | 0x3e000000; + } + GTE::write(rgb); + GTE::Kernels::dpcs(); + GTE::read(&command); + GTE::write(b.packed); + GTE::write(c.packed); + GTE::write(d.packed); + GTE::Kernels::dpct(); + GTE::read(&colorB.packed); + GTE::read(&colorC.packed); + GTE::read(&colorD.packed); + } private: uint32_t command; diff --git a/src/mips/psyqo/primitives/rectangles.hh b/src/mips/psyqo/primitives/rectangles.hh index bb28f9e77..aaae9d50f 100644 --- a/src/mips/psyqo/primitives/rectangles.hh +++ b/src/mips/psyqo/primitives/rectangles.hh @@ -49,7 +49,7 @@ struct Rectangle { Rectangle(Color c) : command(BASE | c.packed) {} Rectangle& setColor(Color c) { uint32_t wasSemiTrans = command & 0x02000000; - command = BASE | c.packed | wasSemiTrans; + command = BASE | (c.packed & 0xffffff) | wasSemiTrans; return *this; } Rectangle& setOpaque() { @@ -84,7 +84,7 @@ struct Pixel { Pixel(Color c) : command(BASE | c.packed) {} Pixel& setColor(Color c) { uint32_t wasSemiTrans = command & 0x02000000; - command = BASE | c.packed | wasSemiTrans; + command = BASE | (c.packed & 0xffffff) | wasSemiTrans; return *this; } Pixel& setOpaque() { @@ -118,7 +118,7 @@ struct Rectangle8x8 { Rectangle8x8(Color c) : command(BASE | c.packed) {} Rectangle8x8& setColor(Color c) { uint32_t wasSemiTrans = command & 0x02000000; - command = BASE | c.packed | wasSemiTrans; + command = BASE | (c.packed & 0xffffff) | wasSemiTrans; return *this; } Rectangle8x8& setOpaque() { @@ -152,7 +152,7 @@ struct Rectangle16x16 { Rectangle16x16(Color c) : command(BASE | c.packed) {} Rectangle16x16& setColor(Color c) { uint32_t wasSemiTrans = command & 0x02000000; - command = BASE | c.packed | wasSemiTrans; + command = BASE | (c.packed & 0xffffff) | wasSemiTrans; return *this; } Rectangle16x16& setOpaque() { diff --git a/src/mips/psyqo/primitives/sprites.hh b/src/mips/psyqo/primitives/sprites.hh index 02fe1674d..22dac4a17 100644 --- a/src/mips/psyqo/primitives/sprites.hh +++ b/src/mips/psyqo/primitives/sprites.hh @@ -50,7 +50,7 @@ struct Sprite { Sprite(Color c) : command(BASE | c.packed) {} Sprite& setColor(Color c) { uint32_t wasSemiTrans = command & 0x02000000; - command = BASE | c.packed | wasSemiTrans; + command = BASE | (c.packed & 0xffffff) | wasSemiTrans; return *this; } Sprite& setOpaque() { @@ -87,7 +87,7 @@ struct Sprite1x1 { Sprite1x1(Color c) : command(BASE | c.packed) {} Sprite1x1& setColor(Color c) { uint32_t wasSemiTrans = command & 0x02000000; - command = BASE | c.packed | wasSemiTrans; + command = BASE | (c.packed & 0xffffff) | wasSemiTrans; return *this; } Sprite1x1& setOpaque() { @@ -123,7 +123,7 @@ struct Sprite8x8 { Sprite8x8(Color c) : command(BASE | c.packed) {} Sprite8x8& setColor(Color c) { uint32_t wasSemiTrans = command & 0x02000000; - command = BASE | c.packed | wasSemiTrans; + command = BASE | (c.packed & 0xffffff) | wasSemiTrans; return *this; } Sprite8x8& setOpaque() { @@ -159,7 +159,7 @@ struct Sprite16x16 { Sprite16x16(Color c) : command(BASE | c.packed) {} Sprite16x16& setColor(Color c) { uint32_t wasSemiTrans = command & 0x02000000; - command = BASE | c.packed | wasSemiTrans; + command = BASE | (c.packed & 0xffffff) | wasSemiTrans; return *this; } Sprite16x16& setOpaque() { diff --git a/src/mips/psyqo/primitives/triangles.hh b/src/mips/psyqo/primitives/triangles.hh index fe2266cc1..c0fa73a71 100644 --- a/src/mips/psyqo/primitives/triangles.hh +++ b/src/mips/psyqo/primitives/triangles.hh @@ -28,6 +28,8 @@ SOFTWARE. #include +#include "psyqo/gte-kernels.hh" +#include "psyqo/gte-registers.hh" #include "psyqo/primitives/common.hh" namespace psyqo { @@ -45,7 +47,7 @@ struct Triangle { Triangle(Color c) : command(0x20000000 | c.packed) {} Triangle& setColor(Color c) { uint32_t wasSemiTrans = command & 0x02000000; - command = 0x20000000 | c.packed | wasSemiTrans; + command = 0x20000000 | (c.packed & 0xffffff) | wasSemiTrans; return *this; } Triangle& setOpaque() { @@ -96,7 +98,7 @@ struct TexturedTriangle { TexturedTriangle(Color c) : command(0x24000000 | c.packed) {} TexturedTriangle& setColor(Color c) { uint32_t wasSemiTrans = command & 0x02000000; - command = 0x24000000 | c.packed | wasSemiTrans; + command = 0x24000000 | (c.packed & 0xffffff) | wasSemiTrans; return *this; } TexturedTriangle& setOpaque() { @@ -136,7 +138,7 @@ struct GouraudTriangle { GouraudTriangle(Color c) : command(0x30000000 | c.packed) {} GouraudTriangle& setColorA(Color c) { uint32_t wasSemiTrans = command & 0x02000000; - command = 0x30000000 | c.packed | wasSemiTrans; + command = 0x30000000 | (c.packed & 0xffffff) | wasSemiTrans; return *this; } GouraudTriangle& setColorB(Color c) { @@ -167,6 +169,40 @@ struct GouraudTriangle { pointC = v; return *this; } + template + void interpolateColors(const Color* a, const Color* b, const Color* c) { + GTE::write(&a->packed); + GTE::write(&b->packed); + GTE::write(&c->packed); + if constexpr (transparency == Transparency::Auto) { + GTE::write(&command); + } else if constexpr (transparency == Transparency::Opaque) { + GTE::write(0x30000000); + } else if constexpr (transparency == Transparency::SemiTransparent) { + GTE::write(0x32000000); + } + GTE::Kernels::dpct(); + GTE::read(&command); + GTE::read(&colorB.packed); + GTE::read(&colorC.packed); + } + template + void interpolateColors(Color a, Color b, Color c) { + GTE::write(a.packed); + GTE::write(b.packed); + GTE::write(c.packed); + if constexpr (transparency == Transparency::Auto) { + GTE::write(&command); + } else if constexpr (transparency == Transparency::Opaque) { + GTE::write(0x30000000); + } else if constexpr (transparency == Transparency::SemiTransparent) { + GTE::write(0x32000000); + } + GTE::Kernels::dpct(); + GTE::read(&command); + GTE::read(&colorB.packed); + GTE::read(&colorC.packed); + } private: uint32_t command; @@ -199,7 +235,7 @@ struct GouraudTexturedTriangle { GouraudTexturedTriangle(Color c) : command(0x34000000 | c.packed) {} GouraudTexturedTriangle& setColorA(Color c) { uint32_t wasSemiTrans = command & 0x02000000; - command = 0x34000000 | c.packed | wasSemiTrans; + command = 0x34000000 | (c.packed & 0xffffff) | wasSemiTrans; return *this; } GouraudTexturedTriangle& setColorB(Color c) { @@ -218,6 +254,40 @@ struct GouraudTexturedTriangle { command |= 0x02000000; return *this; } + template + void interpolateColors(const Color* a, const Color* b, const Color* c) { + GTE::write(&a->packed); + GTE::write(&b->packed); + GTE::write(&c->packed); + if constexpr (transparency == Transparency::Auto) { + GTE::write(&command); + } else if constexpr (transparency == Transparency::Opaque) { + GTE::write(0x34000000); + } else if constexpr (transparency == Transparency::SemiTransparent) { + GTE::write(0x36000000); + } + GTE::Kernels::dpct(); + GTE::read(&command); + GTE::read(&colorB.packed); + GTE::read(&colorC.packed); + } + template + void interpolateColors(Color a, Color b, Color c) { + GTE::write(a.packed); + GTE::write(b.packed); + GTE::write(c.packed); + if constexpr (transparency == Transparency::Auto) { + GTE::write(&command); + } else if constexpr (transparency == Transparency::Opaque) { + GTE::write(0x34000000); + } else if constexpr (transparency == Transparency::SemiTransparent) { + GTE::write(0x36000000); + } + GTE::Kernels::dpct(); + GTE::read(&command); + GTE::read(&colorB.packed); + GTE::read(&colorC.packed); + } private: uint32_t command; diff --git a/src/mips/psyqo/src/cdrom-device-cdda.cpp b/src/mips/psyqo/src/cdrom-device-cdda.cpp index 4d9d2abdd..f4f1434e2 100644 --- a/src/mips/psyqo/src/cdrom-device-cdda.cpp +++ b/src/mips/psyqo/src/cdrom-device-cdda.cpp @@ -53,8 +53,7 @@ class PlayCDDAAction : public psyqo::CDRomDevice::Action { PlayCDDAAction() : Action("PlayCDDAAction") {} void start(psyqo::CDRomDevice *device, unsigned track, bool stopAtEndOfTrack, eastl::function &&callback) { - psyqo::Kernel::assert(device->isIdle(), - "CDRomDevice::playCDDA() called while another action is in progress"); + psyqo::Kernel::assert(device->isIdle(), "CDRomDevice::playCDDA() called while another action is in progress"); registerMe(device); setCallback(eastl::move(callback)); setState(PlayCDDAActionState::GETTD); @@ -64,8 +63,7 @@ class PlayCDDAAction : public psyqo::CDRomDevice::Action { } void start(psyqo::CDRomDevice *device, psyqo::MSF msf, bool stopAtEndOfTrack, eastl::function &&callback) { - psyqo::Kernel::assert(device->isIdle(), - "CDRomDevice::playCDDA() called while another action is in progress"); + psyqo::Kernel::assert(device->isIdle(), "CDRomDevice::playCDDA() called while another action is in progress"); registerMe(device); setCallback(eastl::move(callback)); setState(PlayCDDAActionState::SEEK); @@ -74,8 +72,7 @@ class PlayCDDAAction : public psyqo::CDRomDevice::Action { psyqo::Hardware::CDRom::Command.send(psyqo::Hardware::CDRom::CDL::SETMODE, stopAtEndOfTrack ? 3 : 1); } void start(psyqo::CDRomDevice *device, eastl::function &&callback) { - psyqo::Kernel::assert(device->isIdle(), - "CDRomDevice::playCDDA() called while another action is in progress"); + psyqo::Kernel::assert(device->isIdle(), "CDRomDevice::playCDDA() called while another action is in progress"); registerMe(device); setCallback(eastl::move(callback)); setState(PlayCDDAActionState::PLAY); diff --git a/src/mips/psyqo/src/cdrom-device-muteunmute.cpp b/src/mips/psyqo/src/cdrom-device-muteunmute.cpp index bbdf2a351..91b1df6bd 100644 --- a/src/mips/psyqo/src/cdrom-device-muteunmute.cpp +++ b/src/mips/psyqo/src/cdrom-device-muteunmute.cpp @@ -41,8 +41,7 @@ class MuteAction : public psyqo::CDRomDevice::Action { public: MuteAction() : Action("MuteAction") {} void start(psyqo::CDRomDevice *device, eastl::function &&callback) { - psyqo::Kernel::assert(device->isIdle(), - "CDRomDevice::mute() called while another action is in progress"); + psyqo::Kernel::assert(device->isIdle(), "CDRomDevice::mute() called while another action is in progress"); registerMe(device); setCallback(eastl::move(callback)); setState(MuteActionState::MUTE); @@ -79,8 +78,7 @@ class UnmuteAction : public psyqo::CDRomDevice::Action { public: UnmuteAction() : Action("UnmuteAction") {} void start(psyqo::CDRomDevice *device, eastl::function &&callback) { - psyqo::Kernel::assert(device->isIdle(), - "CDRomDevice::unmute() called while another action is in progress"); + psyqo::Kernel::assert(device->isIdle(), "CDRomDevice::unmute() called while another action is in progress"); registerMe(device); setCallback(eastl::move(callback)); setState(UnmuteActionState::UNMUTE); diff --git a/src/mips/psyqo/src/cdrom-device-reset.cpp b/src/mips/psyqo/src/cdrom-device-reset.cpp index a5f935687..c03ff341d 100644 --- a/src/mips/psyqo/src/cdrom-device-reset.cpp +++ b/src/mips/psyqo/src/cdrom-device-reset.cpp @@ -42,8 +42,7 @@ class ResetAction : public psyqo::CDRomDevice::Action { public: ResetAction() : Action("ResetAction") {} void start(psyqo::CDRomDevice *device, eastl::function &&callback) { - psyqo::Kernel::assert(device->isIdle(), - "CDRomDevice::reset() called while another action is in progress"); + psyqo::Kernel::assert(device->isIdle(), "CDRomDevice::reset() called while another action is in progress"); registerMe(device); setCallback(eastl::move(callback)); setState(ResetActionState::RESET); diff --git a/src/mips/psyqo/src/cdrom-device-toc.cpp b/src/mips/psyqo/src/cdrom-device-toc.cpp index 6dd04caa0..f6725f9c5 100644 --- a/src/mips/psyqo/src/cdrom-device-toc.cpp +++ b/src/mips/psyqo/src/cdrom-device-toc.cpp @@ -43,8 +43,7 @@ class GetTNAction : public psyqo::CDRomDevice::Action { public: GetTNAction() : Action("GetTNAction") {} void start(psyqo::CDRomDevice *device, unsigned *size, eastl::function &&callback) { - psyqo::Kernel::assert(device->isIdle(), - "CDRomDevice::getTOCSize() called while another action is in progress"); + psyqo::Kernel::assert(device->isIdle(), "CDRomDevice::getTOCSize() called while another action is in progress"); registerMe(device); setCallback(eastl::move(callback)); setState(GetTNActionEnum::GETTN); @@ -100,8 +99,7 @@ class ReadTOCAction : public psyqo::CDRomDevice::Action { public: ReadTOCAction() : Action("ReadTOCAction") {} void start(psyqo::CDRomDevice *device, psyqo::MSF *toc, unsigned size, eastl::function &&callback) { - psyqo::Kernel::assert(device->isIdle(), - "CDRomDevice::readTOC() called while another action is in progress"); + psyqo::Kernel::assert(device->isIdle(), "CDRomDevice::readTOC() called while another action is in progress"); registerMe(device); setCallback(eastl::move(callback)); setState(ReadTOCActionState::GETTN); diff --git a/src/mips/psyqo/src/ordering-table.cpp b/src/mips/psyqo/src/ordering-table.cpp index e4457eecc..dfb0d9632 100644 --- a/src/mips/psyqo/src/ordering-table.cpp +++ b/src/mips/psyqo/src/ordering-table.cpp @@ -35,7 +35,8 @@ void psyqo::OrderingTableBase::clear(uint32_t* table, size_t size) { } } -void psyqo::OrderingTableBase::insert(uint32_t* table, int32_t size, uint32_t* head, uint32_t shiftedFragmentSize, int32_t z) { +void psyqo::OrderingTableBase::insert(uint32_t* table, int32_t size, uint32_t* head, uint32_t shiftedFragmentSize, + int32_t z) { z = eastl::clamp(z, int32_t(0), size) + 1; *head = shiftedFragmentSize | table[z]; table[z] = reinterpret_cast(head) & 0xffffff; diff --git a/src/mips/psyqo/src/xprintf.c b/src/mips/psyqo/src/xprintf.c index b3ce6c687..8fbed5443 100644 --- a/src/mips/psyqo/src/xprintf.c +++ b/src/mips/psyqo/src/xprintf.c @@ -109,13 +109,13 @@ enum e_type { /* The type of the format field */ ** Each builtin conversion character (ex: the 'd' in "%d") is described ** by an instance of the following structure */ -typedef struct s_info { /* Information about each format field */ - int fmttype; /* The format field code letter */ - int base; /* The base for radix conversion, or the scale in fixed-point mode */ - const char *charset; /* The character set for conversion */ - int flag_signed; /* Is the quantity signed? */ - const char *prefix; /* Prefix on non-zero values in alt format */ - enum e_type type; /* Conversion paradigm */ +typedef struct s_info { /* Information about each format field */ + int fmttype; /* The format field code letter */ + int base; /* The base for radix conversion, or the scale in fixed-point mode */ + const char *charset; /* The character set for conversion */ + int flag_signed; /* Is the quantity signed? */ + const char *prefix; /* Prefix on non-zero values in alt format */ + enum e_type type; /* Conversion paradigm */ } info; /* diff --git a/src/mips/tests/cop0/exceptions.cpp b/src/mips/tests/cop0/exceptions.cpp index 803eb8af1..0fac532c5 100644 --- a/src/mips/tests/cop0/exceptions.cpp +++ b/src/mips/tests/cop0/exceptions.cpp @@ -68,8 +68,8 @@ static Handler<0x40> s_handler40; static Handler<0x80> s_handler80; extern "C" void installExceptionHandlers(uint32_t (*handler)(uint32_t *regs, uint32_t from)) { - uint32_t (*wrapper)(uint32_t * regs, uint32_t from, uint32_t(*handler)(uint32_t * regs, uint32_t from)) = - [](uint32_t *regs, uint32_t from, uint32_t (*handler)(uint32_t * regs, uint32_t from)) -> uint32_t { + uint32_t (*wrapper)(uint32_t *regs, uint32_t from, uint32_t (*handler)(uint32_t *regs, uint32_t from)) = + [](uint32_t *regs, uint32_t from, uint32_t (*handler)(uint32_t *regs, uint32_t from)) -> uint32_t { return handler(regs, from); }; __asm__ volatile( diff --git a/src/mips/ucl-demo/ucl-demo.cpp b/src/mips/ucl-demo/ucl-demo.cpp index afc9e9449..dc77c4237 100644 --- a/src/mips/ucl-demo/ucl-demo.cpp +++ b/src/mips/ucl-demo/ucl-demo.cpp @@ -97,7 +97,7 @@ int main() { // to overlap the decompressed data by 16 bytes, in order to be able to safely decompress // in-place. In practice, it only requires about 4 bytes, but we will use 16 bytes here // as documented in the UCL library. - uint8_t * compressed = buffer + header.decompsize - header.compsize + 16; + uint8_t* compressed = buffer + header.decompsize - header.compsize + 16; r = PCread(fd, compressed, header.compsize); if (r != header.compsize) { diff --git a/src/support/opengl.h b/src/support/opengl.h index 4797eb4ee..14a01a5b6 100644 --- a/src/support/opengl.h +++ b/src/support/opengl.h @@ -43,7 +43,7 @@ namespace OpenGL { class [[nodiscard]] Status : private std::optional { public: Status(const Status&) = default; - Status(Status &&) = default; + Status(Status&&) = default; Status& operator=(const Status&) = default; Status& operator=(Status&&) = default; bool isOk() const { return !has_value(); } diff --git a/src/support/protobuf.h b/src/support/protobuf.h index b6dccd902..a14069b6f 100644 --- a/src/support/protobuf.h +++ b/src/support/protobuf.h @@ -701,9 +701,9 @@ struct MessageField, fieldNumberValue> : pu MessageField(const MessageType &value) : MessageType(value) {} MessageField(MessageType &value) : MessageType(value) {} template - MessageField(const fields &... values) : MessageType(values...) {} + MessageField(const fields &...values) : MessageType(values...) {} template - MessageField(fields &&... values) : MessageType(std::move(values)...) {} + MessageField(fields &&...values) : MessageType(std::move(values)...) {} static constexpr bool matches(unsigned wireType) { return wireType == 2; } static constexpr unsigned wireType = 2; static constexpr uint64_t fieldNumber = fieldNumberValue; @@ -739,8 +739,8 @@ class Message, fields...> : private std::tuple(); } - Message(const fields &... values) : base(values...) { verifyIntegrity<0, fields...>(); } - Message(fields &&... values) : base(std::move(values)...) { verifyIntegrity<0, fields...>(); } + Message(const fields &...values) : base(values...) { verifyIntegrity<0, fields...>(); } + Message(fields &&...values) : base(std::move(values)...) { verifyIntegrity<0, fields...>(); } using name = irqus::typestring; static constexpr char const typeName[sizeof...(C) + 1] = {C..., '\0'}; static constexpr void dumpSchema(std::ostream &stream) { diff --git a/src/support/settings.h b/src/support/settings.h index a954267c0..9e3e964b2 100644 --- a/src/support/settings.h +++ b/src/support/settings.h @@ -37,6 +37,7 @@ SOFTWARE. #include #include #include +#include #include "core/system.h" #include "json.hpp" @@ -47,6 +48,36 @@ SOFTWARE. namespace PCSX { +namespace concepts { +template +concept Setting = requires(S s) { + { s.serialize() } -> std::same_as; + { s.deserialize(std::declval()) } -> std::same_as; + { s.reset() } -> std::same_as; + { s.pushLuaClosures(std::declval()) } -> std::same_as; +}; +template +concept Settings = requires(S s) { + { s.reset() } -> std::same_as; + { s.serialize() } -> std::same_as; + { s.deserialize(std::declval()) } -> std::same_as; + { s.pushValue(std::declval()) } -> std::same_as; +}; +} // namespace concepts + +template +struct SettingVector; +template +struct SettingVector> { + using json = nlohmann::json; + typedef irqus::typestring name; + json serialize() const { return value; } + void deserialize(const json &j) { value = j.template get>(); } + void reset() { value.clear(); } + std::vector value; + void pushLuaClosures(Lua L) {} +}; + template struct Setting; template @@ -275,9 +306,9 @@ struct SettingFloat, defaultValue, divisor> { float value = (float)defaultValue / (float)divisor; }; -template +template struct SettingNested; -template +template struct SettingNested, nestedSettings> : public nestedSettings { typedef irqus::typestring name; @@ -294,8 +325,7 @@ struct SettingNested, nestedSettings> : public nestedSet return 1; }, -1); - L.declareFunc( - "newindex", [](Lua L) -> int { return 0; }, -1); + L.declareFunc("newindex", [](Lua L) -> int { return 0; }, -1); L.declareFunc( "reset", [this](Lua L) -> int { @@ -307,7 +337,7 @@ struct SettingNested, nestedSettings> : public nestedSet } }; -template +template struct Settings : private std::tuple { using json = nlohmann::json; template @@ -337,6 +367,8 @@ struct Settings : private std::tuple { L.declareFunc("__pairs", lua_pairswrapper, -1); L.setmetatable(); } + + private: static int lua_index(lua_State *L_) { Lua L(L_); int r = L.getmetatable(-2); @@ -385,10 +417,9 @@ struct Settings : private std::tuple { return 3; } - private: template constexpr void reset() {} - template + template constexpr void reset() { settingType &setting = std::get(*this); setting.reset(); @@ -396,7 +427,7 @@ struct Settings : private std::tuple { } template constexpr void serialize(json &j) const {} - template + template constexpr void serialize(json &j) const { const settingType &setting = std::get(*this); j[settingType::name::data()] = setting.serialize(); @@ -404,7 +435,7 @@ struct Settings : private std::tuple { } template constexpr void deserialize(const json &j, bool doReset = true) {} - template + template constexpr void deserialize(const json &j, bool doReset = true) { settingType &setting = std::get(*this); try { @@ -420,7 +451,7 @@ struct Settings : private std::tuple { } template void pushValue(Lua L) {} - template + template void pushValue(Lua L) { settingType &setting = std::get(*this); setting.pushLuaClosures(L); diff --git a/src/support/uvfile.cc b/src/support/uvfile.cc index 867e7ebbe..2a14a6e97 100644 --- a/src/support/uvfile.cc +++ b/src/support/uvfile.cc @@ -481,8 +481,7 @@ ssize_t PCSX::UvFile::read(void *dest, size_t size) { ssize_t PCSX::UvFile::write(const void *src, size_t size) { if (!writable()) return -1; if (m_cache) { - while (m_cacheProgress.load(std::memory_order_relaxed) != 1.0) - ; + while (m_cacheProgress.load(std::memory_order_relaxed) != 1.0); size_t newSize = m_ptrW + size; if (newSize > m_size) { m_cache = reinterpret_cast(realloc(m_cache, newSize)); @@ -529,8 +528,7 @@ ssize_t PCSX::UvFile::write(const void *src, size_t size) { void PCSX::UvFile::write(Slice &&slice) { if (!writable()) return; if (m_cache) { - while (m_cacheProgress.load(std::memory_order_relaxed) != 1.0) - ; + while (m_cacheProgress.load(std::memory_order_relaxed) != 1.0); size_t newSize = m_ptrW + slice.size(); if (newSize > m_size) { m_cache = reinterpret_cast(realloc(m_cache, newSize)); @@ -629,8 +627,7 @@ ssize_t PCSX::UvFile::readAt(void *dest, size_t size, size_t ptr) { ssize_t PCSX::UvFile::writeAt(const void *src, size_t size, size_t ptr) { if (!writable()) return -1; if (m_cache) { - while (m_cacheProgress.load(std::memory_order_acquire) != 1.0) - ; + while (m_cacheProgress.load(std::memory_order_acquire) != 1.0); size_t newSize = ptr + size; if (newSize > m_size) { m_cache = reinterpret_cast(realloc(m_cache, newSize)); @@ -673,8 +670,7 @@ ssize_t PCSX::UvFile::writeAt(const void *src, size_t size, size_t ptr) { void PCSX::UvFile::writeAt(Slice &&slice, size_t ptr) { if (!writable()) return; if (m_cache) { - while (m_cacheProgress.load(std::memory_order_acquire) != 1.0) - ; + while (m_cacheProgress.load(std::memory_order_acquire) != 1.0); size_t newSize = ptr + slice.size(); if (newSize > m_size) { m_cache = reinterpret_cast(realloc(m_cache, newSize)); @@ -874,8 +870,7 @@ ssize_t PCSX::UvFifo::read(void *dest_, size_t size) { if (m_size.load() == 0) { return ret == 0 ? -1 : ret; } - while (!m_queue.Dequeue(m_slice)) - ; + while (!m_queue.Dequeue(m_slice)); } auto toRead = std::min(size, static_cast(m_slice.size()) - m_currentPtr); memcpy(dest, m_slice.data() + m_currentPtr, toRead); diff --git a/src/support/uvfile.h b/src/support/uvfile.h index 609b1ba6c..a2b8e871a 100644 --- a/src/support/uvfile.h +++ b/src/support/uvfile.h @@ -152,8 +152,9 @@ class UvFile : public File, public UvThreadOp { virtual bool eof() final override; virtual std::filesystem::path filename() final override { return m_filename; } virtual File* dup() final override { - return m_download ? new UvFile(m_filename.string(), DOWNLOAD_URL) - : writable() ? new UvFile(m_filename, FileOps::READWRITE) : new UvFile(m_filename); + return m_download ? new UvFile(m_filename.string(), DOWNLOAD_URL) + : writable() ? new UvFile(m_filename, FileOps::READWRITE) + : new UvFile(m_filename); } // Open the file in read-only mode. diff --git a/src/support/version-windows.cc b/src/support/version-windows.cc index 3427c5f19..87e1765df 100644 --- a/src/support/version-windows.cc +++ b/src/support/version-windows.cc @@ -150,8 +150,7 @@ bool PCSX::Update::applyUpdate(const std::filesystem::path& binDir) { _freea(str); #endif - while (!std::filesystem::exists(tmp / "pcsx-redux-update.started")) - ; + while (!std::filesystem::exists(tmp / "pcsx-redux-update.started")); return true; } diff --git a/third_party/ImFileDialog/ImFileDialog.cpp b/third_party/ImFileDialog/ImFileDialog.cpp index e6143bfa1..5d0255969 100644 --- a/third_party/ImFileDialog/ImFileDialog.cpp +++ b/third_party/ImFileDialog/ImFileDialog.cpp @@ -1187,7 +1187,7 @@ namespace ifd { bool isSelected = std::count(m_selections.begin(), m_selections.end(), entry.Path); - if (FileIcon(filename.c_str(), isSelected, entry.HasIconPreview ? entry.IconPreview : (ImTextureID)m_getIcon(entry.Path), ImVec2(32 + 16 * m_zoom, 32 + 16 * m_zoom), entry.HasIconPreview, entry.IconPreviewWidth, entry.IconPreviewHeight)) { + if (FileIcon(filename.c_str(), isSelected, entry.HasIconPreview ? (ImTextureID)entry.IconPreview : (ImTextureID)m_getIcon(entry.Path), ImVec2(32 + 16 * m_zoom, 32 + 16 * m_zoom), entry.HasIconPreview, entry.IconPreviewWidth, entry.IconPreviewHeight)) { std::error_code ec; bool isDir = std::filesystem::is_directory(entry.Path, ec); diff --git a/third_party/imgui b/third_party/imgui index f63c95a07..368123ab0 160000 --- a/third_party/imgui +++ b/third_party/imgui @@ -1 +1 @@ -Subproject commit f63c95a076a401721ceaf21f30d4f12e8c40cb2c +Subproject commit 368123ab06b2b573d585e52f84cd782c5c006697 diff --git a/tools/ghidra_scripts/OverlayReduxSymbols.java b/tools/ghidra_scripts/OverlayReduxSymbols.java new file mode 100644 index 000000000..b6958e959 --- /dev/null +++ b/tools/ghidra_scripts/OverlayReduxSymbols.java @@ -0,0 +1,55 @@ +// Exports symbols to PCSX-Redux's symbols map including Overlays filtering +//@author acemon33 +//@category PSX + +import ghidra.app.script.GhidraScript; +import ghidra.program.model.symbol.*; +import ghidra.program.model.address.*; +import ghidra.program.model.mem.*; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.*; + +public class OverlayReduxSymbols extends GhidraScript { + + public void run() throws Exception { + MemoryBlock[] MemoryBlockList = state.getCurrentProgram().getMemory().getBlocks(); + List choices = new ArrayList(); + for (int i = 0; i < MemoryBlockList.length; i++) { if (MemoryBlockList[i].isOverlay()) choices.add(MemoryBlockList[i].getName()); } + List filterList = askChoices("Title", "Message", choices); + List choiceList = new ArrayList(); + for (String e : choices) { choiceList.add(e + "::"); choiceList.add(e + "__"); } + + List symbols = new ArrayList(); + SymbolTable st = state.getCurrentProgram().getSymbolTable(); + SymbolIterator iter = st.getSymbolIterator(true); + while (iter.hasNext() && !monitor.isCancelled()) { + Symbol sym = iter.next(); + Address add = sym.getAddress(); + String name = sym.getName(true); + + boolean hasFilter = true; + for (String s : filterList) { if (add.toString().contains(s)) { hasFilter = false; break; } } + if (hasFilter) + { + boolean isNext = false; + for (String s : choiceList) { if (add.toString().contains(s)) { isNext = true; break; } } + if (isNext) continue; + } + + symbols.add(String.format("%08x %s", add.getOffset(), name)); + } + + HttpClient client = HttpClient.newHttpClient(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:8080/api/v1/assembly/symbols?function=upload")) + .POST(HttpRequest.BodyPublishers.ofString(String.join("\n", symbols))) + .build(); + + client.send(request, HttpResponse.BodyHandlers.ofString()); + + println("size: " + symbols.size()); + } +} diff --git a/tools/vscode-extension/README.md b/tools/vscode-extension/README.md index ea4e6aaed..242b1b72c 100644 --- a/tools/vscode-extension/README.md +++ b/tools/vscode-extension/README.md @@ -13,12 +13,16 @@ The panel will have the ability to install the tools on the most popular platfor - The extension is currently only targeting Windows, Linux Ubuntu, Arch Linux, and MacOS. It may work on more platforms, but it's not guaranteed, and won't be as automated as it is on the supported platforms. - Only Windows and Linux Ubuntu have been thoroughly tested for now. - The extension will not work from the browser as it requires running external tools. It may work in a remote SSH session, but it's not been tested. -- The PCSX-Redux dependency is currently only available on x86_64 platforms, and may possibly work on M1/M2 Macs. - Linux requires libfuse2 to be installed, for AppImages like the PCSX-Redux dependency to work. - The PCSX-Redux workflow won't check for system-wide installations, and will always install the dependency locally. ### Changelog +- 0.3.8 + - Added automatic setup of Python virtual environments in order to reflect the changes in ps1-bare-metal. + - Fixed compile_flags.txt in template file. + - Added psyqo cube example. + - Added download support for Darwin ARM64 (M1/M2/etc) for PCSX-Redux. - 0.3.7 - Bumping gcc to 14.2.0 - Bumping binutils to 2.43 diff --git a/tools/vscode-extension/extension.js b/tools/vscode-extension/extension.js index 583150f18..50bacb802 100644 --- a/tools/vscode-extension/extension.js +++ b/tools/vscode-extension/extension.js @@ -110,6 +110,9 @@ class PSXDevPanel { case 'restorePsyq': restorePsyq() break + case 'restorePythonEnv': + restorePythonEnv() + break case 'updateModules': updateModules() break @@ -219,8 +222,8 @@ class PSXDevPanel {

Before debugging a PlayStation 1 application, you'll need to have a target able to run PlayStation 1 code accessible through the gdb protocol. You can connect to a real PlayStation 1, or you can run an emulator with a gdb server. You can click the button below to launch the PCSX-Redux PlayStation 1 emulator in debugger mode.


Open Settings folder Launch PCSX-Redux

-

After cloning a project that uses the Psy-Q library, it'll be necessary to restore it. You can press the button below in order to restore the library into the current workspace.


- Restore Psy-Q
+

After cloning a project that uses Psy-Q libraries or a Python virtual environment, it'll be necessary to restore them. Use the buttons below in order to restore the appropriate dependencies into the current workspace.


+ Restore Psy-Q Restore Python environment

The templates will create git repositories with submodules. These submodules may update frequently with bug fixes and new features. The updates should not break backward compatibility in general, and should be safe to do. Press the button below to update the submodules in the current workspace.


Update modules
@@ -287,6 +290,12 @@ exports.activate = (context) => { }) ) + context.subscriptions.push( + vscode.commands.registerCommand('psxDev.restorePythonEnv', () => { + restorePythonEnv() + }) + ) + context.subscriptions.push( vscode.commands.registerCommand('psxDev.updateModules', () => { updateModules() @@ -363,6 +372,29 @@ function restorePsyq () { } } +function restorePythonEnv () { + if (vscode.workspace.workspaceFolders) { + templates + .createPythonEnv({ + path: vscode.workspace.workspaceFolders[0].uri.fsPath, + name: 'env', + requirementsFiles: [ + vscode.Uri.joinPath( + vscode.workspace.workspaceFolders[0].uri, + 'ps1-bare-metal', + 'tools', + 'requirements.txt' + ).fsPath + ] + }) + .catch((err) => { + vscode.window.showErrorMessage(err.message) + }) + } else { + vscode.window.showErrorMessage('Please open a project first.') + } +} + function showReduxSettings () { const pathToOpen = vscode.Uri.joinPath( globalStorageUri, diff --git a/tools/vscode-extension/media/main.js b/tools/vscode-extension/media/main.js index 2b682ed3f..8d7d6756a 100644 --- a/tools/vscode-extension/media/main.js +++ b/tools/vscode-extension/media/main.js @@ -87,6 +87,7 @@ import { const panelTab = document.createElement('vscode-panel-tab') panelTab.textContent = category panels.appendChild(panelTab) + templateKeys // Suppress unused variable warning } for (const [category, templateKeys] of Object.entries(categories)) { const panel = document.createElement('vscode-panel-view') @@ -295,6 +296,11 @@ import { document.getElementById('restore-psyq').addEventListener('click', () => { vscode.postMessage({ command: 'restorePsyq' }) }) + document + .getElementById('restore-python-env') + .addEventListener('click', () => { + vscode.postMessage({ command: 'restorePythonEnv' }) + }) document.getElementById('update-modules').addEventListener('click', () => { vscode.postMessage({ command: 'updateModules' }) }) diff --git a/tools/vscode-extension/package.json b/tools/vscode-extension/package.json index b1cd63f03..ab96b49c3 100644 --- a/tools/vscode-extension/package.json +++ b/tools/vscode-extension/package.json @@ -2,7 +2,7 @@ "name": "psx-dev", "displayName": "PSX.Dev", "description": "PlayStation 1 development made easy", - "version": "0.3.7", + "version": "0.3.8", "engines": { "vscode": "^1.75.0" }, @@ -72,6 +72,11 @@ "title": "Restore Psy-Q", "category": "PSX.Dev" }, + { + "command": "psxDev.restorePythonEnv", + "title": "Restore Python environment", + "category": "PSX.Dev" + }, { "command": "psxDev.showReduxSettings", "title": "Show PCSX-Redux Settings", @@ -111,6 +116,6 @@ "open-file-explorer": "^1.0.2", "simple-git": "^3.16.1", "unzipper": "^0.10.11", - "which": "^3.0.0" + "which": "^5.0.0" } } diff --git a/tools/vscode-extension/pcsx-redux.js b/tools/vscode-extension/pcsx-redux.js index 36882f0de..5018713da 100644 --- a/tools/vscode-extension/pcsx-redux.js +++ b/tools/vscode-extension/pcsx-redux.js @@ -13,8 +13,8 @@ const dmg = require('dmg') const dmgMount = util.promisify(dmg.mount) const dmgUnmount = util.promisify(dmg.unmount) const terminal = require('./terminal.js') -const execAsync = require('node:child_process').exec -const exec = util.promisify(execAsync) +const execFileAsync = require('node:child_process').execFile +const execFile = util.promisify(execFileAsync) const os = require('node:os') const updateInfo = { @@ -27,9 +27,13 @@ const updateInfo = { infoBase: 'https://distrib.app/storage/manifests/pcsx-redux/dev-linux-x64/', fileType: 'zip' }, - darwin: { + darwin_Intel: { infoBase: 'https://distrib.app/storage/manifests/pcsx-redux/dev-macos-x64/', fileType: 'dmg' + }, + darwin_Arm: { + infoBase: 'https://distrib.app/storage/manifests/pcsx-redux/dev-macos-arm/', + fileType: 'dmg' } } @@ -97,11 +101,13 @@ exports.install = async () => { 'https://aka.ms/vs/17/release/vc_redist.x64.exe', fullPath ) - await exec(fullPath) + await execFile(fullPath) } } - const updateInfoForPlatform = updateInfo[process.platform] + const darwinArch = process.arch === 'arm64' ? 'Arm' : 'Intel' + const platform = process.platform === 'darwin' ? 'darwin_' + darwinArch : process.platform + const updateInfoForPlatform = updateInfo[platform] const outputDir = process.platform === 'win32' ? vscode.Uri.joinPath(globalStorageUri, 'pcsx-redux').fsPath diff --git a/tools/vscode-extension/templates.js b/tools/vscode-extension/templates.js index f131362e9..f9e6436d6 100644 --- a/tools/vscode-extension/templates.js +++ b/tools/vscode-extension/templates.js @@ -4,6 +4,7 @@ const path = require('node:path') const fs = require('fs-extra') const Mustache = require('mustache') const { simpleGit } = require('simple-git') +const terminal = require('./terminal.js') const progressNotification = require('./progressnotification.js') let extensionUri @@ -365,6 +366,7 @@ const baseCMakeTemplate = combine(baseTemplate, { name: '.gitignore', content: [ 'build/', + 'env/', '.cache/', '__pycache__/', '*.pyc', @@ -521,6 +523,27 @@ async function createGitRepository (fullPath, template, progressReporter) { return git } +async function createPythonEnv (fullPath, name, packages, requirementsFiles) { + // On Windows "python" and "python3" are aliased to a script that opens the + // Microsoft Store by default, so the "py" launcher is invoked instead. + const pythonCommand = (process.platform === 'win32') ? 'py' : 'python3' + await terminal.run(pythonCommand, ['-m', 'venv', name], { + cwd: fullPath + }) + const pipCommand = path.join(fullPath, name, 'bin', 'pip') + if (packages && packages.length) { + await terminal.run(pipCommand, ['install', ...packages], { + cwd: fullPath + }) + } + if (requirementsFiles && requirementsFiles.length) { + const options = requirementsFiles.flatMap((file) => ['-r', file]) + await terminal.run(pipCommand, ['install', ...options], { + cwd: fullPath + }) + } +} + async function copyTemplateDirectory (git, fullPath, name, templates, data) { const binaryExtensions = ['.bin', '.dat', '.png', '.tim'] const ignoredFiles = ['PSX.Dev-README.md'] @@ -620,6 +643,20 @@ const templates = { ], { projectName: name, isCMake: true } ) + progressReporter.report({ message: 'Setting up Python environment...' }) + await createPythonEnv( + fullPath, + 'env', + [], + [ + path.join( + fullPath, + 'ps1-bare-metal', + 'tools', + 'requirements.txt' + ) + ] + ) } }, cmake_cube: { @@ -659,6 +696,20 @@ const templates = { ], { projectName: name, isCMake: true } ) + progressReporter.report({ message: 'Setting up Python environment...' }) + await createPythonEnv( + fullPath, + 'env', + [], + [ + path.join( + fullPath, + 'ps1-bare-metal', + 'tools', + 'requirements.txt' + ) + ] + ) } }, psyq_cube: { @@ -716,6 +767,33 @@ const templates = { ) } }, + psyqo_cube: { + name: 'PSYQo Cube', + category: 'PSYQo SDK', + description: 'A project featuring a rotating cube using the PSYQo SDK.', + url: 'https://github.com/pcsx-redux/nugget/tree/main/psyqo#how', + examples: + 'https://github.com/grumpycoders/pcsx-redux/tree/main/src/mips/psyqo/examples', + requiredTools: ['git', 'make', 'toolchain'], + recommendedTools: ['gdb', 'debugger', 'redux'], + create: async function (fullPath, name, progressReporter) { + const git = await createGitRepository( + fullPath, + psyqoTemplate, + progressReporter + ) + await copyTemplateDirectory( + git, + fullPath, + name, + [ + path.join(extensionUri.fsPath, 'templates', 'common'), + path.join(extensionUri.fsPath, 'templates', 'psyqo', 'cube') + ], + { projectName: name, isCMake: false } + ) + } + }, psyq_netyaroze: { name: 'Net Yaroze Sprite', category: 'Psy-Q SDK', @@ -731,7 +809,6 @@ const templates = { netyarozeTemplate, progressReporter ) - await copyTemplateDirectory( git, fullPath, @@ -787,7 +864,7 @@ exports.createProjectFromTemplate = async function (tools, options) { let rejecter const { progressReporter, progressResolver } = await progressNotification.notify( - 'Creating project...', + 'Creating project', 'Creating directories...' ) const ret = new Promise((resolve, reject) => { @@ -806,6 +883,14 @@ exports.createProjectFromTemplate = async function (tools, options) { }) return ret } +exports.createPythonEnv = async function (options) { + await createPythonEnv( + options.path, + options.name, + options.packages, + options.requirementsFiles + ) +} exports.setExtensionUri = (uri) => { extensionUri = uri diff --git a/tools/vscode-extension/templates/bare-metal/cmake-cube/CMakeLists.txt b/tools/vscode-extension/templates/bare-metal/cmake-cube/CMakeLists.txt index 9c0be9d6a..05bef1ee0 100644 --- a/tools/vscode-extension/templates/bare-metal/cmake-cube/CMakeLists.txt +++ b/tools/vscode-extension/templates/bare-metal/cmake-cube/CMakeLists.txt @@ -16,9 +16,10 @@ project( HOMEPAGE_URL "https://github.com/grumpycoders/pcsx-redux" ) -# Locate a working Python installation in order to run the scripts in the tools -# directory. -find_package(Python3 3.10 REQUIRED COMPONENTS Interpreter) +# Set up compiler flags and initialize the Python environment used to run the +# scripts in the tools directory. +include(ps1-bare-metal/cmake/setup.cmake) +include(ps1-bare-metal/cmake/virtualenv.cmake) # Build a "common" library containing basic support code. We are going to link # this library into our executable. @@ -39,40 +40,8 @@ target_include_directories( ps1-bare-metal/src/libc ) -# Define a helper function to embed the contents of a file into the executable. -function(addBinaryFile target name path) - set(_file "${PROJECT_BINARY_DIR}/includes/${target}_${name}.s") - cmake_path(ABSOLUTE_PATH path OUTPUT_VARIABLE _path) - - # Generate an assembly listing that uses the .incbin directive to embed the - # file and add it to the executable's list of source files. This may look - # hacky, but it works and lets us easily customize the symbol name (i.e. the - # name of the "array" that will contain the file's data). - file( - CONFIGURE - OUTPUT "${_file}" - CONTENT [[ -.section .data.${name}, "aw" -.balign 8 - -.global ${name} -.type ${name}, @object -.size ${name}, (${name}_end - ${name}) - -${name}: - .incbin "${_path}" -${name}_end: -]] - ESCAPE_QUOTES - NEWLINE_STYLE LF - ) - - target_sources(${target} PRIVATE "${_file}") - set_source_files_properties("${_file}" PROPERTIES OBJECT_DEPENDS "${_path}") -endfunction() - -# Create the main executable. You may add more source files by listing them -# here, or other images or files by adding calls to addBinaryFile(). +# Compile the main executable. You may add more source files by listing them +# here. add_executable( {{projectName}} src/font.c @@ -82,8 +51,28 @@ add_executable( ) target_link_libraries({{projectName}} PRIVATE common) -addBinaryFile({{projectName}} fontTexture assets/fontTexture.dat) -addBinaryFile({{projectName}} fontPalette assets/fontPalette.dat) +# Define a CMake macro that invokes convertImage.py in order to generate VRAM +# texture data from an image file. +function(convertImage input bpp) + add_custom_command( + OUTPUT ${ARGN} + DEPENDS "${PROJECT_SOURCE_DIR}/${input}" + COMMAND + "${Python3_EXECUTABLE}" + "${PROJECT_SOURCE_DIR}/ps1-bare-metal/tools/convertImage.py" + -b ${bpp} + "${PROJECT_SOURCE_DIR}/${input}" + ${ARGN} + VERBATIM + ) +endfunction() + +# Convert the font spritesheet to a 4bpp texture and palette, then embed them +# into the executable. The addBinaryFile() macro is defined in setup.cmake; you +# may call it multiple times to embed other data into the binary. +convertImage(assets/font.png 4 fontTexture.dat fontPalette.dat) +addBinaryFile({{projectName}} fontTexture "${PROJECT_BINARY_DIR}/fontTexture.dat") +addBinaryFile({{projectName}} fontPalette "${PROJECT_BINARY_DIR}/fontPalette.dat") # Add a step to run convertExecutable.py after the executable is compiled in # order to convert it into a PS1 executable. By default all custom commands run @@ -95,6 +84,7 @@ add_custom_command( COMMAND "${Python3_EXECUTABLE}" "${PROJECT_SOURCE_DIR}/ps1-bare-metal/tools/convertExecutable.py" - "$" {{projectName}}.psexe + "$" + {{projectName}}.psexe VERBATIM ) diff --git a/tools/vscode-extension/templates/bare-metal/cmake-cube/assets/fontPalette.dat b/tools/vscode-extension/templates/bare-metal/cmake-cube/assets/fontPalette.dat deleted file mode 100644 index aeefa9ad7..000000000 Binary files a/tools/vscode-extension/templates/bare-metal/cmake-cube/assets/fontPalette.dat and /dev/null differ diff --git a/tools/vscode-extension/templates/bare-metal/cmake-cube/assets/fontTexture.dat b/tools/vscode-extension/templates/bare-metal/cmake-cube/assets/fontTexture.dat deleted file mode 100644 index 48f9cfc28..000000000 Binary files a/tools/vscode-extension/templates/bare-metal/cmake-cube/assets/fontTexture.dat and /dev/null differ diff --git a/tools/vscode-extension/templates/bare-metal/cmake-cube/src/gpu.h b/tools/vscode-extension/templates/bare-metal/cmake-cube/src/gpu.h index 47cf3fce8..14b95636d 100644 --- a/tools/vscode-extension/templates/bare-metal/cmake-cube/src/gpu.h +++ b/tools/vscode-extension/templates/bare-metal/cmake-cube/src/gpu.h @@ -4,9 +4,13 @@ #include #include "ps1/gpucmd.h" +// In order for Z averaging to work properly, ORDERING_TABLE_SIZE should be set +// to either a relatively high value (1024 or more) or a multiple of 12; see +// setupGTE() for more details. Higher values will take up more memory but are +// required to render more complex scenes with wide depth ranges correctly. #define DMA_MAX_CHUNK_SIZE 16 #define CHAIN_BUFFER_SIZE 1024 -#define ORDERING_TABLE_SIZE 32 +#define ORDERING_TABLE_SIZE 240 typedef struct { uint32_t data[CHAIN_BUFFER_SIZE]; diff --git a/tools/vscode-extension/templates/bare-metal/cmake-cube/src/main.c b/tools/vscode-extension/templates/bare-metal/cmake-cube/src/main.c index 1782973b7..673864427 100644 --- a/tools/vscode-extension/templates/bare-metal/cmake-cube/src/main.c +++ b/tools/vscode-extension/templates/bare-metal/cmake-cube/src/main.c @@ -1,45 +1,57 @@ /* - * This template is based on the following examples: + * This program is a simple demo that displays a 3D cube and some text (using + * the font spritesheet in the assets directory), based on the following + * examples: * https://github.com/spicyjpeg/ps1-bare-metal/blob/main/src/06_fonts/main.c * https://github.com/spicyjpeg/ps1-bare-metal/blob/main/src/08_spinningCube/main.c * - * If you wish to modify the font image in the assets directory or add more - * images, you may use the ps1-bare-metal/tools/convertImage.py script to - * generate the texture and palette files to embed into the executable. Note - * that the script requires additional dependencies to run; see - * ps1-bare-metal/tools/requirements.txt for information on how to install them. + * For further information on the contents of the ps1-bare-metal submodule, see: + * https://github.com/spicyjpeg/ps1-bare-metal */ #include #include +#include #include "font.h" #include "gpu.h" -#include "ps1/cop0gte.h" +#include "ps1/cop0.h" #include "ps1/gpucmd.h" +#include "ps1/gte.h" #include "ps1/registers.h" #include "trig.h" -// The GTE uses a 4.12 fixed-point format for most values. What this means is -// that most fractional values will be stored as integers by multiplying them by -// a fixed unit, in this case 4096 or 1 << 12 (hence making the fractional part -// 12 bits long). We'll define this unit value to make their handling easier. +// The GTE uses a 20.12 fixed-point format for most values. What this means is +// that fractional values will be stored as integers by multiplying them by a +// fixed unit, in this case 4096 or 1 << 12 (hence making the fractional part 12 +// bits long). We'll define this unit value to make their handling easier. #define ONE (1 << 12) static void setupGTE(int width, int height) { // Ensure the GTE, which is coprocessor 2, is enabled. MIPS coprocessors are - // enabled through a register in coprocessor 0, which is always accessible. - cop0_setSR(cop0_getSR() | COP0_SR_CU2); + // enabled through the status register in coprocessor 0, which is always + // accessible. + cop0_setReg(COP0_SR, cop0_getReg(COP0_SR) | COP0_SR_CU2); - // Set the offset to be added to all calculated coordinates (we want our - // cube to appear at the center of the screen) as well as the field of view. - gte_setXYOrigin(width / 2, height / 2); - gte_setFieldOfView(width); + // Set the offset to be added to all calculated screen space coordinates (we + // want our cube to appear at the center of the screen) Note that OFX and + // OFY are 16.16 fixed-point rather than 20.12. + gte_setControlReg(GTE_OFX, (width << 16) / 2); + gte_setControlReg(GTE_OFY, (height << 16) / 2); + + // Set the distance of the perspective projection plane (i.e. the camera's + // focal length), which affects the field of view. + int focalLength = (width < height) ? width : height; + + gte_setControlReg(GTE_H, focalLength / 2); // Set the scaling factor for Z averaging. For each polygon drawn, the GTE // will sum the transformed Z coordinates of its vertices multiplied by this // value in order to derive the ordering table bucket index the polygon will - // be sorted into. - gte_setZScaleFactor(ONE / ORDERING_TABLE_SIZE); + // be sorted into. This will work best if the ordering table length is a + // multiple of 12 (i.e. both 3 and 4) or high enough to make any rounding + // error negligible. + gte_setControlReg(GTE_ZSF3, ORDERING_TABLE_SIZE / 3); + gte_setControlReg(GTE_ZSF4, ORDERING_TABLE_SIZE / 4); } // When transforming vertices, the GTE will multiply their vectors by a 3x3 @@ -52,19 +64,19 @@ static void multiplyCurrentMatrixByVectors(GTEMatrix *output) { // done one column at a time, as the GTE only supports multiplying a matrix // by a vector using the MVMVA command. gte_command(GTE_CMD_MVMVA | GTE_SF | GTE_MX_RT | GTE_V_V0 | GTE_CV_NONE); - output->values[0][0] = gte_getIR1(); - output->values[1][0] = gte_getIR2(); - output->values[2][0] = gte_getIR3(); + output->values[0][0] = gte_getDataReg(GTE_IR1); + output->values[1][0] = gte_getDataReg(GTE_IR2); + output->values[2][0] = gte_getDataReg(GTE_IR3); gte_command(GTE_CMD_MVMVA | GTE_SF | GTE_MX_RT | GTE_V_V1 | GTE_CV_NONE); - output->values[0][1] = gte_getIR1(); - output->values[1][1] = gte_getIR2(); - output->values[2][1] = gte_getIR3(); + output->values[0][1] = gte_getDataReg(GTE_IR1); + output->values[1][1] = gte_getDataReg(GTE_IR2); + output->values[2][1] = gte_getDataReg(GTE_IR3); gte_command(GTE_CMD_MVMVA | GTE_SF | GTE_MX_RT | GTE_V_V2 | GTE_CV_NONE); - output->values[0][2] = gte_getIR1(); - output->values[1][2] = gte_getIR2(); - output->values[2][2] = gte_getIR3(); + output->values[0][2] = gte_getDataReg(GTE_IR1); + output->values[1][2] = gte_getDataReg(GTE_IR2); + output->values[2][2] = gte_getDataReg(GTE_IR3); } static void rotateCurrentMatrix(int yaw, int pitch, int roll) { @@ -168,10 +180,15 @@ static const Face cubeFaces[NUM_CUBE_FACES] = { extern const uint8_t fontTexture[], fontPalette[]; int main(int argc, const char **argv) { - if ((GPU_GP1 & GP1_STAT_MODE_BITMASK) == GP1_STAT_MODE_PAL) + initSerialIO(115200); + + if ((GPU_GP1 & GP1_STAT_FB_MODE_BITMASK) == GP1_STAT_FB_MODE_PAL) { + puts("Using PAL mode"); setupGPU(GP1_MODE_PAL, SCREEN_WIDTH, SCREEN_HEIGHT); - else + } else { + puts("Using NTSC mode"); setupGPU(GP1_MODE_NTSC, SCREEN_WIDTH, SCREEN_HEIGHT); + } setupGTE(SCREEN_WIDTH, SCREEN_HEIGHT); @@ -181,7 +198,7 @@ int main(int argc, const char **argv) { GPU_GP1 = gp1_dmaRequestMode(GP1_DREQ_GP0_WRITE); GPU_GP1 = gp1_dispBlank(false); - // Upload the font texture into VRAM. + // Upload the font texture to VRAM. TextureInfo font; uploadIndexedTexture( @@ -211,7 +228,9 @@ int main(int argc, const char **argv) { // transformation matrix, then modify the matrix to rotate the cube. The // translation vector is used here to move the cube away from the camera // so it can be seen. - gte_setTranslationVector(0, 0, 256); + gte_setControlReg(GTE_TRX, 0); + gte_setControlReg(GTE_TRY, 0); + gte_setControlReg(GTE_TRZ, 128); gte_setRotationMatrix( ONE, 0, 0, 0, ONE, 0, @@ -238,14 +257,14 @@ int main(int argc, const char **argv) { // be skipped as it is not facing the camera. gte_command(GTE_CMD_NCLIP); - if (gte_getMAC0() <= 0) + if (gte_getDataReg(GTE_MAC0) <= 0) continue; // Save the first transformed vertex (the GTE only keeps the X/Y // coordinates of the last 3 vertices processed and Z coordinates of // the last 4 vertices processed) and apply projection to the last // vertex. - uint32_t xy0 = gte_getSXY0(); + uint32_t xy0 = gte_getDataReg(GTE_SXY0); gte_loadV0(&cubeVertices[face->vertices[3]]); gte_command(GTE_CMD_RTPS | GTE_SF); @@ -253,7 +272,7 @@ int main(int argc, const char **argv) { // Calculate the average Z coordinate of all vertices and use it to // determine the ordering table bucket index for this face. gte_command(GTE_CMD_AVSZ4 | GTE_SF); - int zIndex = gte_getOTZ(); + int zIndex = gte_getDataReg(GTE_OTZ); if ((zIndex < 0) || (zIndex >= ORDERING_TABLE_SIZE)) continue; @@ -263,7 +282,9 @@ int main(int argc, const char **argv) { ptr = allocatePacket(chain, zIndex, 5); ptr[0] = face->color | gp0_shadedQuad(false, false, false); ptr[1] = xy0; - gte_storeSXY012(&ptr[2]); + gte_storeDataReg(GTE_SXY0, 2 * 4, ptr); + gte_storeDataReg(GTE_SXY1, 3 * 4, ptr); + gte_storeDataReg(GTE_SXY2, 4 * 4, ptr); } ptr = allocatePacket(chain, ORDERING_TABLE_SIZE - 1, 3); diff --git a/tools/vscode-extension/templates/bare-metal/empty-cmake/CMakeLists.txt b/tools/vscode-extension/templates/bare-metal/empty-cmake/CMakeLists.txt index ab362d3f2..7e9e4a340 100644 --- a/tools/vscode-extension/templates/bare-metal/empty-cmake/CMakeLists.txt +++ b/tools/vscode-extension/templates/bare-metal/empty-cmake/CMakeLists.txt @@ -16,9 +16,10 @@ project( HOMEPAGE_URL "https://github.com/grumpycoders/pcsx-redux" ) -# Locate a working Python installation in order to run the scripts in the tools -# directory. -find_package(Python3 3.10 REQUIRED COMPONENTS Interpreter) +# Set up compiler flags and initialize the Python environment used to run the +# scripts in the tools directory. +include(ps1-bare-metal/cmake/setup.cmake) +include(ps1-bare-metal/cmake/virtualenv.cmake) # Build a "common" library containing basic support code. We are going to link # this library into our executable. diff --git a/tools/vscode-extension/templates/bare-metal/empty-cmake/src/main.c b/tools/vscode-extension/templates/bare-metal/empty-cmake/src/main.c index f956df06e..9de349546 100644 --- a/tools/vscode-extension/templates/bare-metal/empty-cmake/src/main.c +++ b/tools/vscode-extension/templates/bare-metal/empty-cmake/src/main.c @@ -6,9 +6,12 @@ * back of the console or to another interface. Additionally, most emulators can * log calls to printf() and display the output in their log window. * - * For a variant of this project that prints directly to the PS1's serial port - * instead of using the kernel, see: + * A variant of this project that prints directly to the PS1's serial port + * instead of using the kernel is available here: * https://github.com/spicyjpeg/ps1-bare-metal/blob/main/src/00_helloWorld/main.c + * + * For further information on the contents of the ps1-bare-metal submodule, see: + * https://github.com/spicyjpeg/ps1-bare-metal */ #define BIOS_API_TABLE ((void **) 0x80000200) diff --git a/tools/vscode-extension/templates/psyqo/cube/Makefile b/tools/vscode-extension/templates/psyqo/cube/Makefile new file mode 100644 index 000000000..7936fcd0c --- /dev/null +++ b/tools/vscode-extension/templates/psyqo/cube/Makefile @@ -0,0 +1,7 @@ +TARGET = {{projectName}} +TYPE = ps-exe + +SRCS = \ +main.cpp + +include third_party/nugget/psyqo/psyqo.mk diff --git a/tools/vscode-extension/templates/psyqo/cube/compile_flags.txt b/tools/vscode-extension/templates/psyqo/cube/compile_flags.txt new file mode 100644 index 000000000..a0d792fec --- /dev/null +++ b/tools/vscode-extension/templates/psyqo/cube/compile_flags.txt @@ -0,0 +1,7 @@ +-m32 +-std=c++20 +-fcoroutines-ts +-I. +-Ithird_party/nugget +-Ithird_party/nugget/third_party/EASTL/include +-Ithird_party/nugget/third_party/EABase/include/Common diff --git a/tools/vscode-extension/templates/psyqo/cube/main.cpp b/tools/vscode-extension/templates/psyqo/cube/main.cpp new file mode 100644 index 000000000..2a439c2f4 --- /dev/null +++ b/tools/vscode-extension/templates/psyqo/cube/main.cpp @@ -0,0 +1,197 @@ +{{=<% %>=}}#include "psyqo/application.hh" +#include "psyqo/fixed-point.hh" +#include "psyqo/fragments.hh" +#include "psyqo/gpu.hh" +#include "psyqo/gte-kernels.hh" +#include "psyqo/gte-registers.hh" +#include "psyqo/primitives/common.hh" +#include "psyqo/primitives/quads.hh" +#include "psyqo/scene.hh" +#include "psyqo/soft-math.hh" +#include "psyqo/trigonometry.hh" +#include "psyqo/vector.hh" + +using namespace psyqo::fixed_point_literals; +using namespace psyqo::trig_literals; + +static constexpr unsigned NUM_CUBE_VERTICES = 8; +static constexpr unsigned NUM_CUBE_FACES = 6; +static constexpr unsigned ORDERING_TABLE_SIZE = 240; + +typedef struct { + uint8_t vertices[4]; + psyqo::Color color; +} Face; + +static constexpr psyqo::Matrix33 identity = {{ + {1.0_fp, 0.0_fp, 0.0_fp}, + {0.0_fp, 1.0_fp, 0.0_fp}, + {0.0_fp, 0.0_fp, 1.0_fp}, +}}; + +class Cube final : public psyqo::Application { + void prepare() override; + void createScene() override; + + public: + psyqo::Trig<> m_trig; +}; + +class CubeScene final : public psyqo::Scene { + void start(StartReason reason) override; + void frame() override; + + psyqo::Angle m_rot = 0; + + // We need to create 2 OrderingTable objects since we can't reuse a single one for both + // framebuffers, as the previous one may not finish transfering in time. + psyqo::OrderingTable m_ots[2]; + + // Since we're using an ordering table, we need to sort fill commands as well, + // otherwise they'll draw over our beautiful cube. + psyqo::Fragments::SimpleFragment m_clear[2]; + + eastl::array, 6> m_quads; + + static constexpr psyqo::Color c_bg = {.r = 63, .g = 63, .b = 63}; + + static constexpr psyqo::Vec3 c_cubeVertices[NUM_CUBE_VERTICES] = { + {.x = -0.05, .y = -0.05, .z = -0.05}, {.x = 0.05, .y = -0.05, .z = -0.05}, {.x = -0.05, .y = 0.05, .z = -0.05}, + {.x = 0.05, .y = 0.05, .z = -0.05}, {.x = -0.05, .y = -0.05, .z = 0.05}, {.x = 0.05, .y = -0.05, .z = 0.05}, + {.x = -0.05, .y = 0.05, .z = 0.05}, {.x = 0.05, .y = 0.05, .z = 0.05}}; + + static constexpr Face c_cubeFaces[NUM_CUBE_FACES] = { + {.vertices = {0, 1, 2, 3}, .color = {0, 0, 255}}, {.vertices = {6, 7, 4, 5}, .color = {0, 255, 0}}, + {.vertices = {4, 5, 0, 1}, .color = {0, 255, 255}}, {.vertices = {7, 6, 3, 2}, .color = {255, 0, 0}}, + {.vertices = {6, 4, 2, 0}, .color = {255, 0, 255}}, {.vertices = {5, 7, 1, 3}, .color = {255, 255, 0}}}; +}; + +static Cube cube; +static CubeScene cubeScene; + +void Cube::prepare() { + psyqo::GPU::Configuration config; + config.set(psyqo::GPU::Resolution::W320) + .set(psyqo::GPU::VideoMode::AUTO) + .set(psyqo::GPU::ColorMode::C15BITS) + .set(psyqo::GPU::Interlace::PROGRESSIVE); + + gpu().initialize(config); +} + +void Cube::createScene() { pushScene(&cubeScene); } + +void CubeScene::start(StartReason reason) { + // Clear the translation registers + psyqo::GTE::clear(); + psyqo::GTE::clear(); + psyqo::GTE::clear(); + + // Set the screen offset in the GTE. (this is half the X and Y resolutions as standard) + psyqo::GTE::write(psyqo::FixedPoint<16>(160.0).raw()); + psyqo::GTE::write(psyqo::FixedPoint<16>(120.0).raw()); + + // Write the projection plane distance. + psyqo::GTE::write(120); + + // Set the scaling for Z averaging. + psyqo::GTE::write(ORDERING_TABLE_SIZE / 3); + psyqo::GTE::write(ORDERING_TABLE_SIZE / 4); +} + +void CubeScene::frame() { + eastl::array projected; + + // Get which frame we're currently drawing + int parity = gpu().getParity(); + + // Get our current ordering table and fill command + auto& ot = m_ots[parity]; + auto& clear = m_clear[parity]; + + // Chain the fill command accordingly to clear the buffer + gpu().getNextClear(clear.primitive, c_bg); + gpu().chain(clear); + + // We want the cube to appear slightly further away, so we translate it by 512 on the Z-axis. + psyqo::GTE::write(512); + + // Here we're setting up the rotation for the spinning cube + // First, generate a rotation matrix for the X-axis and Y-axis + auto transform = psyqo::SoftMath::generateRotationMatrix33(m_rot, psyqo::SoftMath::Axis::X, cube.m_trig); + auto rot = psyqo::SoftMath::generateRotationMatrix33(m_rot, psyqo::SoftMath::Axis::Y, cube.m_trig); + + // Multiply the X and Y rotation matrices together + psyqo::SoftMath::multiplyMatrix33(transform, rot, &transform); + + // Generate a Z-axis rotation matrix (Empty, but it's here for your use) + psyqo::SoftMath::generateRotationMatrix33(0, 0, psyqo::SoftMath::Axis::Z, cube.m_trig); + + // Apply the combined rotation and write it to the pseudo register for the cube's rotation + psyqo::SoftMath::multiplyMatrix33(transform, rot, &transform); + psyqo::GTE::writeUnsafe(transform); + + int faceNum = 0; + + for (auto face : c_cubeFaces) { + // We load the first 3 vertices into the GTE. We can't do all 4 at once because the GTE + // handles only 3 at a time... + psyqo::GTE::writeUnsafe(c_cubeVertices[face.vertices[0]]); + psyqo::GTE::writeUnsafe(c_cubeVertices[face.vertices[1]]); + psyqo::GTE::writeUnsafe(c_cubeVertices[face.vertices[2]]); + + // We perform rtpt (Perspective transformation) to the three verticies. + psyqo::GTE::Kernels::rtpt(); + + // Nclip determines the winding of the vertices, used to check which direction the face is pointing. + // Clockwise winding means the face is oriented towards us. + psyqo::GTE::Kernels::nclip(); + + // Read the result of nclip and skip rendering this face if it's not facing us + int32_t mac0 = 0; + psyqo::GTE::read(reinterpret_cast(&mac0)); + if (mac0 <= 0) continue; + + // Since the GTE can only handle 3 vertices at a time, we need to store our first vertex + // so we can write our last one. + psyqo::GTE::read(&projected[0].packed); + + // Write the last vertex + psyqo::GTE::writeSafe(c_cubeVertices[face.vertices[3]]); + + // Perform rtps (Perspective transformation) to the last vertice (rtpS - single, rtpT - triple). + psyqo::GTE::Kernels::rtps(); + + // Calculate the average Z for the z-Index to be put in the ordering table + psyqo::GTE::Kernels::avsz4(); + int32_t zIndex = 0; + psyqo::GTE::read(reinterpret_cast(&zIndex)); + + // If the Z-index is out of bounds for our ordering table, we skip rendering this face. + if (zIndex < 0 || zIndex >= ORDERING_TABLE_SIZE) continue; + + // Read the 3 remaining vertices from the GTE + psyqo::GTE::read(&projected[1].packed); + psyqo::GTE::read(&projected[2].packed); + psyqo::GTE::read(&projected[3].packed); + + // Take a Quad fragment from our array, set its vertices, color and make it opaque + auto& quad = m_quads[faceNum]; + quad.primitive.setPointA(projected[0]); + quad.primitive.setPointB(projected[1]); + quad.primitive.setPointC(projected[2]); + quad.primitive.setPointD(projected[3]); + quad.primitive.setColor(face.color); + quad.primitive.setOpaque(); + + // Insert the Quad fragment into the ordering table at the calculated Z-index. + ot.insert(quad, zIndex); + faceNum++; + } + + // Send the entire ordering table as a DMA chain to the GPU. + gpu().chain(ot); + m_rot += 0.005_pi; +} + +int main() { return cube.run(); } diff --git a/tools/vscode-extension/tools.js b/tools/vscode-extension/tools.js index f69a671b2..d2149de5c 100644 --- a/tools/vscode-extension/tools.js +++ b/tools/vscode-extension/tools.js @@ -2,11 +2,12 @@ const vscode = require('vscode') const util = require('node:util') -const execAsync = require('node:child_process').exec -const exec = util.promisify(execAsync) +const execFileAsync = require('node:child_process').execFile +const execFile = util.promisify(execFileAsync) const terminal = require('./terminal.js') const pcsxRedux = require('./pcsx-redux.js') const fs = require('fs-extra') +const which = require('which') const downloader = require('./downloader.js') const unzipper = require('unzipper') const path = require('node:path') @@ -26,16 +27,16 @@ async function checkInstalled (name) { return tools[name].installed } -function checkSimpleCommand (command) { - return new Promise((resolve) => { - execAsync(command, (error) => { - if (error) { - resolve(false) - } else { - resolve(true) - } - }) - }) +async function checkCommands (commands, args) { + for (const command of commands) { + try { + await execFile(command, args) + } catch (error) { + continue + } + return true + } + return false } let mipsInstalling = false @@ -46,7 +47,8 @@ async function installMips () { mipsInstalling = true try { await terminal.run('powershell', [ - '-c "& { iwr -UseBasicParsing https://bit.ly/mips-ps1 | iex }"' + '-c', + '& { iwr -UseBasicParsing https://raw.githubusercontent.com/grumpycoders/pcsx-redux/main/mips.ps1 | iex }' ]) requiresReboot = true vscode.window.showInformationMessage( @@ -103,10 +105,11 @@ async function installToolchain () { const gccScriptPath = vscode.Uri.joinPath( extensionUri, 'scripts', - 'mipsel-none-elf-binutils.rb' + 'mipsel-none-elf-gcc.rb' ).fsPath await terminal.run('brew', [ 'install', + '--formula', binutilsScriptPath, gccScriptPath ]) @@ -134,10 +137,11 @@ async function installToolchain () { const gccScriptPath = vscode.Uri.joinPath( extensionUri, 'scripts', - 'mipsel-none-elf-binutils.rb' + 'mipsel-none-elf-gcc.rb' ).fsPath await terminal.run('brew', [ 'install', + '--formula', binutilsScriptPath, gccScriptPath ]) @@ -166,13 +170,6 @@ async function installToolchain () { } } -function checkToolchain () { - return Promise.any([ - exec('mipsel-linux-gnu-g++ --version'), - exec('mipsel-none-elf-g++ --version') - ]) -} - async function installGDB () { switch (process.platform) { case 'win32': @@ -309,7 +306,7 @@ async function installCMake () { asset.browser_download_url.split('/').pop() ) await downloader.downloadFile(asset.browser_download_url, filename) - await exec(`start ${filename}`) + await execFile('start', [filename]) requiresReboot = true break case 'linux': @@ -385,7 +382,7 @@ async function installGit () { asset.browser_download_url.split('/').pop() ) await downloader.downloadFile(asset.browser_download_url, filename) - await exec(filename) + await execFile(filename) requiresReboot = true break } @@ -428,7 +425,7 @@ async function installPython () { url.split('/').pop() ) await downloader.downloadFile(url, filename) - await exec(filename) + await execFile(filename) requiresReboot = true break case 'linux': @@ -460,20 +457,56 @@ async function installPython () { } } -function checkPython () { +async function checkPython () { switch (process.platform) { case 'win32': - // On Windows "python" and "python3" are aliased to a script that opens - // the Microsoft Store by default, so we must check for the "py" launcher - // provided by the official installers instead. - // TODO: try to detect other Python installations that do not come with - // the py launcher (e.g. ones from MSys2) - return checkSimpleCommand('py -3 --version') + /* + * We cannot simply run 'python --version' here as Windows ships by + * default with fake (zero-byte) 'python' and 'python3' executables in its + * PATH. These files are actually links to UWP apps, implemented using a + * specific NTFS reparse tag. If Python is installed from the Microsoft + * Store they behave as if they were symlinks to the actual executables; + * if not, however, attempting to run them will result in the store + * popping up and prompting the user to install Python. + * + * A kludge is thus needed here in order to prevent this from happening. + * We'll first check for any UWP Python installations, then search PATH + * manually and skip the fake binaries if none was found. This ensures + * both UWP and non-UWP installs will be detected somewhat reliably. + * + * IMPORTANT: this assumes that the project's build system will also be + * able to detect and ignore the fake executables (rather than e.g. + * blindly executing 'python'). This is currently the case for the + * CMake-based templates. + */ + let hasUWPPython + try { + const result = await execFile('powershell', [ + '-c', + 'Get-AppxPackage -Name PythonSoftwareFoundation.Python.*' + ]) + hasUWPPython = (result.stdout.trim() !== '') + } catch (error) { + hasUWPPython = false + } + for (const command of ['python3', 'python', 'py']) { + const matches = await which(command, { all: true }) + for (const fullPath of matches) { + const stats = await fs.stat(fullPath) + if (!stats.size && !hasUWPPython) { + continue + } + try { + await execFile(fullPath, ['--version']) + } catch (error) { + continue + } + return true + } + } + return false default: - return Promise.any([ - exec('python --version'), - exec('python3 --version') - ]) + return checkCommands(['python3', 'python'], ['--version']) } } @@ -504,20 +537,20 @@ const tools = { mips: { type: 'internal', install: installMips, - check: () => checkSimpleCommand('mips --version') + check: () => checkCommands(['mips'], ['--version']) }, apt: { type: 'internal', - check: () => checkSimpleCommand('apt-get --version') + check: () => checkCommands(['apt-get'], ['--version']) }, trizen: { type: 'internal', - check: () => checkSimpleCommand('trizen --version') + check: () => checkCommands(['trizen'], ['--version']) }, brew: { type: 'internal', install: 'https://brew.sh/', - check: () => checkSimpleCommand('brew --version') + check: () => checkCommands(['brew'], ['--version']) }, toolchain: { type: 'package', @@ -525,7 +558,10 @@ const tools = { description: 'The toolchain used to compile code for the PlayStation 1', homepage: 'https://gcc.gnu.org/', install: installToolchain, - check: checkToolchain + check: () => checkCommands( + ['mipsel-none-elf-g++', 'mipsel-linux-gnu-g++'], + ['--version'] + ) }, gdb: { type: 'package', @@ -533,7 +569,10 @@ const tools = { description: 'The tool to debug code for the PlayStation 1', homepage: 'https://www.sourceware.org/gdb/', install: installGDB, - check: () => checkGDB() + check: () => checkCommands( + [(process.platform === 'darwin') ? 'gdb' : 'gdb-multiarch'], + ['--version'] + ) }, make: { type: 'package', @@ -541,7 +580,7 @@ const tools = { description: 'Build code and various targets with this tool', homepage: 'https://www.gnu.org/software/make/', install: installMake, - check: () => checkSimpleCommand('make --version') + check: () => checkCommands(['make'], ['--version']) }, cmake: { type: 'package', @@ -549,7 +588,7 @@ const tools = { description: 'A more advanced building tool for projects that require it', homepage: 'https://cmake.org/', install: installCMake, - check: () => checkSimpleCommand('cmake --version') + check: () => checkCommands(['cmake'], ['--version']) }, git: { type: 'package', @@ -558,7 +597,7 @@ const tools = { 'Tool to maintain your code, and initialize your project templates', homepage: 'https://git-scm.com/', install: installGit, - check: () => checkSimpleCommand('git --version') + check: () => checkCommands(['git'], ['--version']) }, python: { type: 'package', @@ -636,11 +675,6 @@ function checkLocalFile (filename) { }) } -function checkGDB () { - if (process.platform === 'darwin') return checkSimpleCommand('gdb --version') - return checkSimpleCommand('gdb-multiarch --version') -} - exports.refreshAll = async () => { for (const [, tool] of Object.entries(tools)) { if (tool.check) {