Merge branch 'dev' into jit
# Conflicts: # src/backend/core/registers/Registers.hpp
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -13,7 +13,7 @@ vgcore.*
|
||||
*.dump
|
||||
*.data
|
||||
disasm.txt
|
||||
*log.txt
|
||||
*log*.txt
|
||||
.vs/
|
||||
CMakeSettings.json
|
||||
out/
|
||||
|
||||
@@ -69,7 +69,7 @@ Your GPU needs to support Vulkan 1.1+, because the RDP is implemented via [ParaL
|
||||
This list will probably grow with time!
|
||||
|
||||
## Special thanks:
|
||||
|
||||
- [ares](https://github.com/ares-emulator/ares) for being the cleanest and most accurate Nintendo 64 emulator out there. It served as a reference time and time again. Especially regarding FPU accuracy.
|
||||
- [Dillonb](https://github.com/Dillonb) and [KieronJ](https://github.com/KieronJ) for bearing with me and my recurring brainfarts, and for the support :heart:
|
||||
- [WhoBrokeTheBuild](https://github.com/WhoBrokeTheBuild) for the shader that allows letterboxing :rocket:
|
||||
- [Kelpsy](https://github.com/kelpsyberry), [fleroviux](https://github.com/fleroviux), [Kim-Dewelski](https://github.com/Kim-Dewelski), [Peach](https://github.com/wheremyfoodat/),
|
||||
|
||||
1
external/nativefiledialog-extended
vendored
1
external/nativefiledialog-extended
vendored
Submodule external/nativefiledialog-extended deleted from 17b6e8ce21
20
external/parallel-rdp/ParallelRDPWrapper.cpp
vendored
20
external/parallel-rdp/ParallelRDPWrapper.cpp
vendored
@@ -20,21 +20,21 @@ void ParallelRDP::SetFramerateUnlocked(bool unlocked) {
|
||||
|
||||
Program* fullscreen_quad_program;
|
||||
|
||||
void ParallelRDP::LoadWSIPlatform(Vulkan::InstanceFactory* instanceFactory, std::unique_ptr<Vulkan::WSIPlatform>&& wsi_platform, std::unique_ptr<ParallelRDP::WindowInfo>&& newWindowInfo) {
|
||||
wsi = std::make_unique<WSI>();
|
||||
void ParallelRDP::LoadWSIPlatform(const std::shared_ptr<Vulkan::InstanceFactory>& instanceFactory, const std::shared_ptr<Vulkan::WSIPlatform>& wsi_platform, const std::shared_ptr<ParallelRDP::WindowInfo>& newWindowInfo) {
|
||||
wsi = std::make_shared<WSI>();
|
||||
wsi->set_backbuffer_srgb(false);
|
||||
wsi->set_platform(wsi_platform.get());
|
||||
wsi->set_present_mode(PresentMode::SyncToVBlank);
|
||||
Context::SystemHandles handles;
|
||||
if (!wsi->init_simple(instanceFactory, 1, handles)) {
|
||||
if (!wsi->init_simple(instanceFactory.get(), 1, handles)) {
|
||||
Util::panic("Failed to initialize WSI!");
|
||||
}
|
||||
|
||||
windowInfo = std::move(newWindowInfo);
|
||||
windowInfo = newWindowInfo;
|
||||
}
|
||||
|
||||
void ParallelRDP::Init(Vulkan::InstanceFactory* factory, std::unique_ptr<Vulkan::WSIPlatform>&& wsiPlatform, std::unique_ptr<WindowInfo>&& newWindowInfo, const u8* rdram) {
|
||||
LoadWSIPlatform(factory, std::move(wsiPlatform), std::move(newWindowInfo));
|
||||
void ParallelRDP::Init(const std::shared_ptr<Vulkan::InstanceFactory>& factory, const std::shared_ptr<Vulkan::WSIPlatform>& wsiPlatform, const std::shared_ptr<WindowInfo>& newWindowInfo, const u8* rdram) {
|
||||
LoadWSIPlatform(factory, wsiPlatform, newWindowInfo);
|
||||
|
||||
ResourceLayout vertLayout;
|
||||
ResourceLayout fragLayout;
|
||||
@@ -63,8 +63,7 @@ void ParallelRDP::Init(Vulkan::InstanceFactory* factory, std::unique_ptr<Vulkan:
|
||||
auto aligned_rdram = reinterpret_cast<uintptr_t>(rdram);
|
||||
uintptr_t offset = 0;
|
||||
|
||||
if (wsi->get_device().get_device_features().supports_external_memory_host)
|
||||
{
|
||||
if (wsi->get_device().get_device_features().supports_external_memory_host) {
|
||||
size_t align = wsi->get_device().get_device_features().host_memory_properties.minImportedHostPointerAlignment;
|
||||
offset = aligned_rdram & (align - 1);
|
||||
aligned_rdram -= offset;
|
||||
@@ -72,7 +71,7 @@ void ParallelRDP::Init(Vulkan::InstanceFactory* factory, std::unique_ptr<Vulkan:
|
||||
|
||||
CommandProcessorFlags flags = 0;
|
||||
|
||||
command_processor = std::make_unique<CommandProcessor>(wsi->get_device(), reinterpret_cast<void*>(aligned_rdram),
|
||||
command_processor = std::make_shared<CommandProcessor>(wsi->get_device(), reinterpret_cast<void*>(aligned_rdram),
|
||||
offset, 8 * 1024 * 1024, 4 * 1024 * 1024, flags);
|
||||
|
||||
if (!command_processor->device_is_supported()) {
|
||||
@@ -179,8 +178,7 @@ void ParallelRDP::UpdateScreen(n64::VI& vi, bool noGame) {
|
||||
Util::IntrusivePtr<Image> image = command_processor->scanout(opts);
|
||||
UpdateScreen(image);
|
||||
command_processor->begin_frame_context();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
UpdateScreen(static_cast<Util::IntrusivePtr<Image>>(nullptr));
|
||||
command_processor->begin_frame_context();
|
||||
}
|
||||
|
||||
10
external/parallel-rdp/ParallelRDPWrapper.hpp
vendored
10
external/parallel-rdp/ParallelRDPWrapper.hpp
vendored
@@ -15,7 +15,7 @@ public:
|
||||
virtual ~WindowInfo() = default;
|
||||
};
|
||||
|
||||
void Init(Vulkan::InstanceFactory*, std::unique_ptr<Vulkan::WSIPlatform>&&, std::unique_ptr<WindowInfo>&&, const u8*);
|
||||
void Init(const std::shared_ptr<Vulkan::InstanceFactory>&, const std::shared_ptr<Vulkan::WSIPlatform>&, const std::shared_ptr<WindowInfo>&, const u8*);
|
||||
ParallelRDP() = default;
|
||||
|
||||
void UpdateScreen(n64::VI&, bool = false);
|
||||
@@ -24,11 +24,11 @@ public:
|
||||
bool IsFramerateUnlocked();
|
||||
void SetFramerateUnlocked(bool);
|
||||
private:
|
||||
void LoadWSIPlatform(Vulkan::InstanceFactory*, std::unique_ptr<Vulkan::WSIPlatform>&&, std::unique_ptr<WindowInfo>&&);
|
||||
void LoadWSIPlatform(const std::shared_ptr<Vulkan::InstanceFactory>&, const std::shared_ptr<Vulkan::WSIPlatform>&, const std::shared_ptr<WindowInfo>&);
|
||||
void DrawFullscreenTexturedQuad(Util::IntrusivePtr<Vulkan::Image>, Util::IntrusivePtr<Vulkan::CommandBuffer>);
|
||||
void UpdateScreen(Util::IntrusivePtr<Vulkan::Image>);
|
||||
|
||||
std::unique_ptr<Vulkan::WSI> wsi;
|
||||
std::unique_ptr<RDP::CommandProcessor> command_processor;
|
||||
std::unique_ptr<WindowInfo> windowInfo;
|
||||
std::shared_ptr<Vulkan::WSI> wsi;
|
||||
std::shared_ptr<RDP::CommandProcessor> command_processor;
|
||||
std::shared_ptr<WindowInfo> windowInfo;
|
||||
};
|
||||
|
||||
Submodule external/parallel-rdp/parallel-rdp-standalone updated: 1504f3007e...896f8ca226
@@ -12,7 +12,7 @@ void Core::Stop() {
|
||||
cpu->Reset();
|
||||
}
|
||||
|
||||
bool Core::LoadTAS(const fs::path &path) {
|
||||
bool Core::LoadTAS(const fs::path &path) const {
|
||||
return cpu->GetMem().mmio.si.pif.movie.Load(path);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,9 @@ void Core::LoadROM(const std::string& rom_) {
|
||||
|
||||
cpu->GetMem().LoadROM(isArchive, rom);
|
||||
GameDB::match(cpu->GetMem());
|
||||
if(cpu->GetMem().rom.gameNameDB.empty()) {
|
||||
cpu->GetMem().rom.gameNameDB = fs::path(rom).stem();
|
||||
}
|
||||
cpu->GetMem().mmio.vi.isPal = cpu->GetMem().IsROMPAL();
|
||||
cpu->GetMem().mmio.si.pif.InitDevices(cpu->GetMem().saveType);
|
||||
cpu->GetMem().mmio.si.pif.mempakPath = rom;
|
||||
|
||||
@@ -11,7 +11,7 @@ struct Core {
|
||||
Core(ParallelRDP&);
|
||||
void Stop();
|
||||
void LoadROM(const std::string&);
|
||||
bool LoadTAS(const fs::path&);
|
||||
bool LoadTAS(const fs::path&) const;
|
||||
void Run(float volumeL, float volumeR);
|
||||
void Serialize();
|
||||
void Deserialize();
|
||||
|
||||
@@ -12,6 +12,7 @@ struct Interpreter : BaseCPU {
|
||||
void Reset() override {
|
||||
regs.Reset();
|
||||
mem.Reset();
|
||||
cop2Latch = {};
|
||||
}
|
||||
|
||||
Mem& GetMem() override {
|
||||
|
||||
@@ -15,7 +15,9 @@ struct Mem;
|
||||
struct Registers;
|
||||
|
||||
struct MMIO {
|
||||
MMIO(Mem& mem, Registers& regs, ParallelRDP& parallel) : vi(mem, regs), mi(regs), ai(mem, regs), pi(mem, regs), si(mem, regs), rsp(mem, regs), rdp(mem, parallel) {}
|
||||
MMIO(Mem& mem, Registers& regs, ParallelRDP& parallel) : vi(mem, regs), mi(regs), ai(mem, regs), pi(mem, regs), si(mem, regs), rsp(mem, regs), rdp(mem, parallel) {
|
||||
Reset();
|
||||
}
|
||||
void Reset();
|
||||
|
||||
VI vi;
|
||||
|
||||
@@ -9,16 +9,6 @@
|
||||
|
||||
namespace n64 {
|
||||
Mem::Mem(Registers& regs, ParallelRDP& parallel) : flash(saveData), mmio(*this, regs, parallel) {
|
||||
memset(readPages, 0, PAGE_COUNT);
|
||||
memset(writePages, 0, PAGE_COUNT);
|
||||
|
||||
for(u64 i = 0; i < RDRAM_SIZE / PAGE_SIZE; i++) {
|
||||
const auto addr = (i * PAGE_SIZE) & RDRAM_DSIZE;
|
||||
const auto pointer = (uintptr_t) &mmio.rdp.rdram[addr];
|
||||
readPages[i] = pointer;
|
||||
writePages[i] = pointer;
|
||||
}
|
||||
|
||||
rom.cart.resize(CART_SIZE);
|
||||
std::fill(rom.cart.begin(), rom.cart.end(), 0);
|
||||
}
|
||||
@@ -178,17 +168,11 @@ void Mem::LoadROM(bool isArchive, const std::string& filename) {
|
||||
}
|
||||
|
||||
template<> u8 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
const auto page = paddr >> 12;
|
||||
const auto offset = paddr & 0xFFF;
|
||||
const auto pointer = readPages[page];
|
||||
SI& si = mmio.si;
|
||||
|
||||
if(pointer) {
|
||||
return ((u8*)pointer)[BYTE_ADDRESS(offset)];
|
||||
} else {
|
||||
switch (paddr) {
|
||||
case RDRAM_REGION:
|
||||
return mmio.rdp.rdram[BYTE_ADDRESS(paddr)];
|
||||
return mmio.rdp.ReadRDRAM<u8>(paddr);
|
||||
case RSP_MEM_REGION: {
|
||||
auto& src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
return src[BYTE_ADDRESS(paddr & 0xfff)];
|
||||
@@ -218,20 +202,13 @@ template<> u8 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
Util::panic("Unimplemented 8-bit read at address {:08X} (PC = {:016X})", paddr, (u64) regs.pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<> u16 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
const auto page = paddr >> 12;
|
||||
const auto offset = paddr & 0xFFF;
|
||||
const auto pointer = readPages[page];
|
||||
SI& si = mmio.si;
|
||||
|
||||
if(pointer) {
|
||||
return Util::ReadAccess<u16>((u8*)pointer, HALF_ADDRESS(offset));
|
||||
} else {
|
||||
switch (paddr) {
|
||||
case RDRAM_REGION:
|
||||
return Util::ReadAccess<u16>(mmio.rdp.rdram, HALF_ADDRESS(paddr));
|
||||
return mmio.rdp.ReadRDRAM<u16>(paddr);
|
||||
case RSP_MEM_REGION: {
|
||||
auto& src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
return Util::ReadAccess<u16>(src, HALF_ADDRESS(paddr & 0xfff));
|
||||
@@ -253,20 +230,13 @@ template<> u16 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
Util::panic("Unimplemented 16-bit read at address {:08X} (PC = {:016X})", paddr, (u64) regs.pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<> u32 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
const auto page = paddr >> 12;
|
||||
const auto offset = paddr & 0xFFF;
|
||||
const auto pointer = readPages[page];
|
||||
SI& si = mmio.si;
|
||||
|
||||
if(pointer) {
|
||||
return Util::ReadAccess<u32>((u8*)pointer, offset);
|
||||
} else {
|
||||
switch(paddr) {
|
||||
case RDRAM_REGION:
|
||||
return Util::ReadAccess<u32>(mmio.rdp.rdram, paddr);
|
||||
return mmio.rdp.ReadRDRAM<u32>(paddr);
|
||||
case RSP_MEM_REGION: {
|
||||
auto& src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
return Util::ReadAccess<u32>(src, paddr & 0xfff);
|
||||
@@ -279,26 +249,19 @@ template<> u32 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
return Util::ReadAccess<u32>(si.pif.bootrom, paddr - PIF_ROM_REGION_START);
|
||||
case PIF_RAM_REGION:
|
||||
return be32toh(Util::ReadAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
||||
case 0x00800000 ... 0x03EFFFFF: case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x04900000 ... 0x04FFFFFF: case 0x1FC00800 ... 0xFFFFFFFF: return 0;
|
||||
default:
|
||||
Util::panic("Unimplemented 32-bit read at address {:08X} (PC = {:016X})", paddr, (u64) regs.pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<> u64 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
const auto page = paddr >> 12;
|
||||
const auto offset = paddr & 0xFFF;
|
||||
const auto pointer = readPages[page];
|
||||
SI& si = mmio.si;
|
||||
|
||||
if(pointer) {
|
||||
return Util::ReadAccess<u64>((u8*)pointer, offset);
|
||||
} else {
|
||||
switch (paddr) {
|
||||
case RDRAM_REGION:
|
||||
return Util::ReadAccess<u64>(mmio.rdp.rdram, paddr);
|
||||
return mmio.rdp.ReadRDRAM<u64>(paddr);
|
||||
case RSP_MEM_REGION: {
|
||||
auto& src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
return Util::ReadAccess<u64>(src, paddr & 0xfff);
|
||||
@@ -320,20 +283,13 @@ template<> u64 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
Util::panic("Unimplemented 32-bit read at address {:08X} (PC = {:016X})", paddr, (u64) regs.pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<> void Mem::Write<u8>(Registers& regs, u32 paddr, u32 val) {
|
||||
const auto page = paddr >> 12;
|
||||
const auto offset = paddr & 0xFFF;
|
||||
const auto pointer = writePages[page];
|
||||
SI& si = mmio.si;
|
||||
|
||||
if(pointer) {
|
||||
((u8*)pointer)[BYTE_ADDRESS(offset)] = val;
|
||||
} else {
|
||||
switch (paddr) {
|
||||
case RDRAM_REGION:
|
||||
mmio.rdp.rdram[BYTE_ADDRESS(paddr)] = val;
|
||||
mmio.rdp.WriteRDRAM<u8>(paddr, val);
|
||||
break;
|
||||
case RSP_MEM_REGION: {
|
||||
val = val << (8 * (3 - (paddr & 3)));
|
||||
@@ -365,20 +321,13 @@ template<> void Mem::Write<u8>(Registers& regs, u32 paddr, u32 val) {
|
||||
(u64) regs.pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<> void Mem::Write<u16>(Registers& regs, u32 paddr, u32 val) {
|
||||
const auto page = paddr >> 12;
|
||||
const auto offset = paddr & 0xFFF;
|
||||
const auto pointer = writePages[page];
|
||||
SI& si = mmio.si;
|
||||
|
||||
if(pointer) {
|
||||
Util::WriteAccess<u16>((u8*)pointer, HALF_ADDRESS(offset), val);
|
||||
} else {
|
||||
switch (paddr) {
|
||||
case RDRAM_REGION:
|
||||
Util::WriteAccess<u16>(mmio.rdp.rdram, HALF_ADDRESS(paddr), val);
|
||||
mmio.rdp.WriteRDRAM<u16>(paddr, val);
|
||||
break;
|
||||
case RSP_MEM_REGION: {
|
||||
val = val << (16 * !(paddr & 2));
|
||||
@@ -410,20 +359,13 @@ template<> void Mem::Write<u16>(Registers& regs, u32 paddr, u32 val) {
|
||||
(u64) regs.pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<> void Mem::Write<u32>(Registers& regs, u32 paddr, u32 val) {
|
||||
const auto page = paddr >> 12;
|
||||
const auto offset = paddr & 0xFFF;
|
||||
const auto pointer = writePages[page];
|
||||
SI& si = mmio.si;
|
||||
|
||||
if(pointer) {
|
||||
Util::WriteAccess<u32>((u8*)pointer, offset, val);
|
||||
} else {
|
||||
switch(paddr) {
|
||||
case RDRAM_REGION:
|
||||
Util::WriteAccess<u32>(mmio.rdp.rdram, paddr, val);
|
||||
mmio.rdp.WriteRDRAM<u32>(paddr, val);
|
||||
break;
|
||||
case RSP_MEM_REGION: {
|
||||
auto& dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
@@ -449,20 +391,13 @@ template<> void Mem::Write<u32>(Registers& regs, u32 paddr, u32 val) {
|
||||
default: Util::panic("Unimplemented 32-bit write at address {:08X} with value {:0X} (PC = {:016X})", paddr, val, (u64)regs.pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Mem::Write(Registers& regs, u32 paddr, u64 val) {
|
||||
const auto page = paddr >> 12;
|
||||
const auto offset = paddr & 0xFFF;
|
||||
const auto pointer = writePages[page];
|
||||
SI& si = mmio.si;
|
||||
|
||||
if(pointer) {
|
||||
Util::WriteAccess<u64>((u8*)pointer, offset, val);
|
||||
} else {
|
||||
switch (paddr) {
|
||||
case RDRAM_REGION:
|
||||
Util::WriteAccess<u64>(mmio.rdp.rdram, paddr, val);
|
||||
mmio.rdp.WriteRDRAM<u64>(paddr, val);
|
||||
break;
|
||||
case RSP_MEM_REGION: {
|
||||
auto& dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
@@ -490,7 +425,6 @@ void Mem::Write(Registers& regs, u32 paddr, u64 val) {
|
||||
(u64) regs.pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <> u32 Mem::BackupRead<u32>(u32 addr) {
|
||||
switch(saveType) {
|
||||
|
||||
@@ -132,7 +132,6 @@ struct Mem {
|
||||
Util::SwapBuffer32(temp);
|
||||
Util::WriteFileBinary(temp, "dmem.bin");
|
||||
}
|
||||
uintptr_t writePages[PAGE_COUNT]{}, readPages[PAGE_COUNT]{};
|
||||
ROM rom;
|
||||
SaveType saveType = SAVE_NONE;
|
||||
Flash flash;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include <log.hpp>
|
||||
#include <core/RSP.hpp>
|
||||
#include <parallel-rdp/ParallelRDPWrapper.hpp>
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
|
||||
namespace n64 {
|
||||
RDP::RDP(Mem& mem, ParallelRDP& parallel) : mem(mem), parallel(parallel) {
|
||||
@@ -13,11 +12,60 @@ RDP::RDP(Mem& mem, ParallelRDP& parallel) : mem(mem), parallel(parallel) {
|
||||
}
|
||||
|
||||
void RDP::Reset() {
|
||||
dpc = {};
|
||||
dpc.status.raw = 0x80;
|
||||
std::fill(rdram.begin(), rdram.end(), 0);
|
||||
memset(cmd_buf, 0, 0x100000);
|
||||
}
|
||||
|
||||
template<> void RDP::WriteRDRAM<u8>(size_t idx, u8 v) {
|
||||
size_t real = BYTE_ADDRESS(idx);
|
||||
if(real < RDRAM_SIZE) {
|
||||
rdram[real] = v;
|
||||
}
|
||||
}
|
||||
|
||||
template<> void RDP::WriteRDRAM<u16>(size_t idx, u16 v) {
|
||||
size_t real = HALF_ADDRESS(idx);
|
||||
if(real < RDRAM_SIZE) {
|
||||
Util::WriteAccess<u16>(rdram, real, v);
|
||||
}
|
||||
}
|
||||
|
||||
template<> void RDP::WriteRDRAM<u32>(size_t idx, u32 v) {
|
||||
if(idx < RDRAM_SIZE) {
|
||||
Util::WriteAccess<u32>(rdram, idx, v);
|
||||
}
|
||||
}
|
||||
|
||||
template<> void RDP::WriteRDRAM<u64>(size_t idx, u64 v) {
|
||||
if(idx < RDRAM_SIZE) {
|
||||
Util::WriteAccess<u64>(rdram, idx, v);
|
||||
}
|
||||
}
|
||||
|
||||
template<> u8 RDP::ReadRDRAM<u8>(size_t idx) {
|
||||
size_t real = BYTE_ADDRESS(idx);
|
||||
if(real >= RDRAM_SIZE) return 0;
|
||||
return rdram[real];
|
||||
}
|
||||
|
||||
template<> u16 RDP::ReadRDRAM<u16>(size_t idx) {
|
||||
size_t real = HALF_ADDRESS(idx);
|
||||
if(real >= RDRAM_SIZE) return 0;
|
||||
return Util::ReadAccess<u16>(rdram, real);
|
||||
}
|
||||
|
||||
template<> u32 RDP::ReadRDRAM<u32>(size_t idx) {
|
||||
if(idx >= RDRAM_SIZE) return 0;
|
||||
return Util::ReadAccess<u32>(rdram, idx);
|
||||
}
|
||||
|
||||
template<> u64 RDP::ReadRDRAM<u64>(size_t idx) {
|
||||
if(idx >= RDRAM_SIZE) return 0;
|
||||
return Util::ReadAccess<u64>(rdram, idx);
|
||||
}
|
||||
|
||||
static const int cmd_lens[64] = {
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 8, 12, 24, 28, 24, 28, 40, 44,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
|
||||
@@ -59,7 +59,6 @@ struct RDP {
|
||||
RDP(Mem&, ParallelRDP&);
|
||||
void Reset();
|
||||
|
||||
std::vector<u8> rdram{};
|
||||
[[nodiscard]] auto Read(u32 addr) const -> u32;
|
||||
void Write(u32 addr, u32 val);
|
||||
void WriteStatus(u32 val);
|
||||
@@ -81,7 +80,16 @@ struct RDP {
|
||||
}
|
||||
RunCommand();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void WriteRDRAM(size_t, T);
|
||||
template<typename T>
|
||||
T ReadRDRAM(size_t);
|
||||
private:
|
||||
friend struct Mem;
|
||||
friend struct MMIO;
|
||||
std::vector<u8> rdram{};
|
||||
|
||||
Mem& mem;
|
||||
ParallelRDP& parallel;
|
||||
};
|
||||
|
||||
@@ -31,6 +31,7 @@ void RSP::Reset() {
|
||||
divIn = 0;
|
||||
divOut = 0;
|
||||
divInLoaded = false;
|
||||
steps = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -69,7 +70,7 @@ FORCE_INLINE void logRSP(const RSP& rsp, const u32 instr) {
|
||||
auto RSP::Read(u32 addr) -> u32 {
|
||||
switch (addr) {
|
||||
case 0x04040000: return lastSuccessfulSPAddr.raw & 0x1FF8;
|
||||
case 0x04040004: return lastSuccessfulDRAMAddr.raw & 0xFFFFF8;
|
||||
case 0x04040004: return lastSuccessfulDRAMAddr.raw & 0xFFFFFC;
|
||||
case 0x04040008:
|
||||
case 0x0404000C: return spDMALen.raw;
|
||||
case 0x04040010: return spStatus.raw;
|
||||
@@ -110,17 +111,79 @@ void RSP::WriteStatus(u32 value) {
|
||||
CLEAR_SET(spStatus.signal7, write.clearSignal7, write.setSignal7);
|
||||
}
|
||||
|
||||
template <> void RSP::DMA<true>() {
|
||||
u32 length = spDMALen.len + 1;
|
||||
|
||||
length = (length + 0x7) & ~0x7;
|
||||
|
||||
std::array<u8, DMEM_SIZE>& src = spDMASPAddr.bank ? imem : dmem;
|
||||
|
||||
u32 mem_address = spDMASPAddr.address & 0xFF8;
|
||||
u32 dram_address = spDMADRAMAddr.address & 0xFFFFFC;
|
||||
Util::trace("SP DMA from RSP to RDRAM (size: {} B, {:08X} to {:08X})", length, mem_address, dram_address);
|
||||
|
||||
for (u32 i = 0; i < spDMALen.count + 1; i++) {
|
||||
for(u32 j = 0; j < length; j++) {
|
||||
mem.mmio.rdp.WriteRDRAM<u8>(BYTE_ADDRESS(dram_address + j), src[(mem_address + j) & DMEM_DSIZE]);
|
||||
}
|
||||
|
||||
int skip = i == spDMALen.count ? 0 : spDMALen.skip;
|
||||
|
||||
dram_address += (length + skip);
|
||||
dram_address &= 0xFFFFFC;
|
||||
mem_address += length;
|
||||
mem_address &= 0xFF8;
|
||||
}
|
||||
Util::trace("Addresses after: RSP: 0x{:08X}, Dram: 0x{:08X}", mem_address, dram_address);
|
||||
|
||||
lastSuccessfulSPAddr.address = mem_address;
|
||||
lastSuccessfulSPAddr.bank = spDMASPAddr.bank;
|
||||
lastSuccessfulDRAMAddr.address = dram_address;
|
||||
spDMALen.raw = 0xFF8 | (spDMALen.skip << 20);
|
||||
}
|
||||
|
||||
template <> void RSP::DMA<false>() {
|
||||
u32 length = spDMALen.len + 1;
|
||||
|
||||
length = (length + 0x7) & ~0x7;
|
||||
|
||||
std::array<u8, DMEM_SIZE>& dst = spDMASPAddr.bank ? imem : dmem;
|
||||
|
||||
u32 mem_address = spDMASPAddr.address & 0xFF8;
|
||||
u32 dram_address = spDMADRAMAddr.address & 0xFFFFFC;
|
||||
Util::trace("SP DMA from RDRAM to RSP (size: {} B, {:08X} to {:08X})", length, dram_address, mem_address);
|
||||
|
||||
for (u32 i = 0; i < spDMALen.count + 1; i++) {
|
||||
for(u32 j = 0; j < length; j++) {
|
||||
dst[(mem_address + j) & DMEM_DSIZE] = mem.mmio.rdp.ReadRDRAM<u8>(BYTE_ADDRESS(dram_address + j));
|
||||
}
|
||||
|
||||
int skip = i == spDMALen.count ? 0 : spDMALen.skip;
|
||||
|
||||
dram_address += (length + skip);
|
||||
dram_address &= 0xFFFFFC;
|
||||
mem_address += length;
|
||||
mem_address &= 0xFF8;
|
||||
}
|
||||
Util::trace("Addresses after: RSP: 0x{:08X}, Dram: 0x{:08X}", mem_address, dram_address);
|
||||
|
||||
lastSuccessfulSPAddr.address = mem_address;
|
||||
lastSuccessfulSPAddr.bank = spDMASPAddr.bank;
|
||||
lastSuccessfulDRAMAddr.address = dram_address;
|
||||
spDMALen.raw = 0xFF8 | (spDMALen.skip << 20);
|
||||
}
|
||||
|
||||
void RSP::Write(u32 addr, u32 val) {
|
||||
switch (addr) {
|
||||
case 0x04040000: spDMASPAddr.raw = val & 0x1FF8; break;
|
||||
case 0x04040004: spDMADRAMAddr.raw = val & 0xFFFFF8; break;
|
||||
case 0x04040004: spDMADRAMAddr.raw = val & 0xFFFFFC; break;
|
||||
case 0x04040008: {
|
||||
spDMALen.raw = val;
|
||||
DMAtoRSP(mem.GetRDRAM());
|
||||
DMA<false>();
|
||||
} break;
|
||||
case 0x0404000C: {
|
||||
spDMALen.raw = val;
|
||||
DMAtoRDRAM(mem.GetRDRAM());
|
||||
DMA<true>();
|
||||
} break;
|
||||
case 0x04040010: WriteStatus(val); break;
|
||||
case 0x0404001C: ReleaseSemaphore(); break;
|
||||
@@ -132,70 +195,4 @@ void RSP::Write(u32 addr, u32 val) {
|
||||
Util::panic("Unimplemented SP register write {:08X}, val: {:08X}", addr, val);
|
||||
}
|
||||
}
|
||||
|
||||
void RSP::DMAtoRDRAM(std::vector<u8>& rdram) {
|
||||
u32 length = spDMALen.len + 1;
|
||||
|
||||
length = (length + 0x7) & ~0x7;
|
||||
|
||||
std::vector<u8>& dst = rdram;
|
||||
std::array<u8, DMEM_SIZE>& src = spDMASPAddr.bank ? imem : dmem;
|
||||
|
||||
u32 mem_address = spDMASPAddr.address & 0xFF8;
|
||||
u32 dram_address = spDMADRAMAddr.address & 0xFFFFF8;
|
||||
|
||||
for (u32 i = 0; i < spDMALen.count + 1; i++) {
|
||||
for(u32 j = 0; j < length; j++) {
|
||||
if((dram_address + j) < RDRAM_SIZE) {
|
||||
dst[dram_address + j] = src[(mem_address + j) & DMEM_DSIZE];
|
||||
}
|
||||
}
|
||||
|
||||
int skip = i == spDMALen.count ? 0 : spDMALen.skip;
|
||||
|
||||
dram_address += (length + skip);
|
||||
dram_address &= 0xFFFFF8;
|
||||
mem_address += length;
|
||||
mem_address &= 0xFF8;
|
||||
}
|
||||
|
||||
lastSuccessfulSPAddr.address = mem_address;
|
||||
lastSuccessfulSPAddr.bank = spDMASPAddr.bank;
|
||||
lastSuccessfulDRAMAddr.address = dram_address;
|
||||
spDMALen.raw = 0xFF8 | (spDMALen.skip << 20);
|
||||
}
|
||||
|
||||
void RSP::DMAtoRSP(std::vector<u8>& rdram) {
|
||||
u32 length = spDMALen.len + 1;
|
||||
|
||||
length = (length + 0x7) & ~0x7;
|
||||
|
||||
std::vector<u8>& src = rdram;
|
||||
std::array<u8, DMEM_SIZE>& dst = spDMASPAddr.bank ? imem : dmem;
|
||||
|
||||
u32 mem_address = spDMASPAddr.address & 0xFF8;
|
||||
u32 dram_address = spDMADRAMAddr.address & 0xFFFFF8;
|
||||
|
||||
for (u32 i = 0; i < spDMALen.count + 1; i++) {
|
||||
for(u32 j = 0; j < length; j++) {
|
||||
if((dram_address + j) < RDRAM_SIZE) {
|
||||
dst[(mem_address + j) & DMEM_DSIZE] = src[dram_address + j];
|
||||
} else {
|
||||
dst[(mem_address + j) & DMEM_DSIZE] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int skip = i == spDMALen.count ? 0 : spDMALen.skip;
|
||||
|
||||
dram_address += (length + skip);
|
||||
dram_address &= 0xFFFFF8;
|
||||
mem_address += length;
|
||||
mem_address &= 0xFF8;
|
||||
}
|
||||
|
||||
lastSuccessfulSPAddr.address = mem_address;
|
||||
lastSuccessfulSPAddr.bank = spDMASPAddr.bank;
|
||||
lastSuccessfulDRAMAddr.address = dram_address;
|
||||
spDMALen.raw = 0xFF8 | (spDMALen.skip << 20);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <core/RDP.hpp>
|
||||
#include <MemoryRegions.hpp>
|
||||
#include <MemoryHelpers.hpp>
|
||||
#include <Interrupt.hpp>
|
||||
#include <array>
|
||||
|
||||
#define RSP_BYTE(addr) (dmem[BYTE_ADDRESS(addr) & 0xFFF])
|
||||
@@ -358,8 +357,8 @@ struct RSP {
|
||||
void mfc2(u32 instr);
|
||||
void mtc2(u32 instr);
|
||||
|
||||
void DMAtoRDRAM(std::vector<u8>& rdram);
|
||||
void DMAtoRSP(std::vector<u8>& rdram);
|
||||
template <bool toRdram>
|
||||
void DMA();
|
||||
void WriteStatus(u32 value);
|
||||
private:
|
||||
Registers& regs;
|
||||
|
||||
@@ -51,12 +51,12 @@ void Interpreter::special(u32 instr) {
|
||||
case DADDU: daddu(instr); break;
|
||||
case DSUB: dsub(instr); break;
|
||||
case DSUBU: dsubu(instr); break;
|
||||
case TGE: trap(regs.gpr[RS(instr)] >= regs.gpr[RT(instr)]); break;
|
||||
case TGEU: trap((u64)regs.gpr[RS(instr)] >= (u64)regs.gpr[RT(instr)]); break;
|
||||
case TLT: trap(regs.gpr[RS(instr)] < regs.gpr[RT(instr)]); break;
|
||||
case TLTU: trap((u64)regs.gpr[RS(instr)] < (u64)regs.gpr[RT(instr)]); break;
|
||||
case TEQ: trap(regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); break;
|
||||
case TNE: trap(regs.gpr[RS(instr)] != regs.gpr[RT(instr)]); break;
|
||||
case TGE: trap(regs.Read<s64>(RS(instr)) >= regs.Read<s64>(RT(instr))); break;
|
||||
case TGEU: trap(regs.Read<u64>(RS(instr)) >= regs.Read<u64>(RT(instr))); break;
|
||||
case TLT: trap(regs.Read<s64>(RS(instr)) < regs.Read<s64>(RT(instr))); break;
|
||||
case TLTU: trap(regs.Read<u64>(RS(instr)) < regs.Read<u64>(RT(instr))); break;
|
||||
case TEQ: trap(regs.Read<s64>(RS(instr)) == regs.Read<s64>(RT(instr))); break;
|
||||
case TNE: trap(regs.Read<s64>(RS(instr)) != regs.Read<s64>(RT(instr))); break;
|
||||
case DSLL: dsll(instr); break;
|
||||
case DSRL: dsrl(instr); break;
|
||||
case DSRA: dsra(instr); break;
|
||||
@@ -72,20 +72,20 @@ void Interpreter::regimm(u32 instr) {
|
||||
u8 mask = ((instr >> 16) & 0x1F);
|
||||
// 000r_rccc
|
||||
switch (mask) { // TODO: named constants for clearer code
|
||||
case BLTZ: b(instr, regs.gpr[RS(instr)] < 0); break;
|
||||
case BGEZ: b(instr, regs.gpr[RS(instr)] >= 0); break;
|
||||
case BLTZL: bl(instr, regs.gpr[RS(instr)] < 0); break;
|
||||
case BGEZL: bl(instr, regs.gpr[RS(instr)] >= 0); break;
|
||||
case TGEI: trap(regs.gpr[RS(instr)] >= s64(s16(instr))); break;
|
||||
case TGEIU: trap(u64(regs.gpr[RS(instr)]) >= u64(s64(s16(instr)))); break;
|
||||
case TLTI: trap(regs.gpr[RS(instr)] < s64(s16(instr))); break;
|
||||
case TLTIU: trap(u64(regs.gpr[RS(instr)]) < u64(s64(s16(instr)))); break;
|
||||
case TEQI: trap(regs.gpr[RS(instr)] == s64(s16(instr))); break;
|
||||
case TNEI: trap(regs.gpr[RS(instr)] != s64(s16(instr))); break;
|
||||
case BLTZAL: blink(instr, regs.gpr[RS(instr)] < 0); break;
|
||||
case BGEZAL: blink(instr, regs.gpr[RS(instr)] >= 0); break;
|
||||
case BLTZALL: bllink(instr, regs.gpr[RS(instr)] < 0); break;
|
||||
case BGEZALL: bllink(instr, regs.gpr[RS(instr)] >= 0); break;
|
||||
case BLTZ: b(instr, regs.Read<s64>(RS(instr)) < 0); break;
|
||||
case BGEZ: b(instr, regs.Read<s64>(RS(instr)) >= 0); break;
|
||||
case BLTZL: bl(instr, regs.Read<s64>(RS(instr)) < 0); break;
|
||||
case BGEZL: bl(instr, regs.Read<s64>(RS(instr)) >= 0); break;
|
||||
case TGEI: trap(regs.Read<s64>(RS(instr)) >= s64(s16(instr))); break;
|
||||
case TGEIU: trap(regs.Read<u64>(RS(instr)) >= u64(s64(s16(instr)))); break;
|
||||
case TLTI: trap(regs.Read<s64>(RS(instr)) < s64(s16(instr))); break;
|
||||
case TLTIU: trap(regs.Read<u64>(RS(instr)) < u64(s64(s16(instr)))); break;
|
||||
case TEQI: trap(regs.Read<s64>(RS(instr)) == s64(s16(instr))); break;
|
||||
case TNEI: trap(regs.Read<s64>(RS(instr)) != s64(s16(instr))); break;
|
||||
case BLTZAL: blink(instr, regs.Read<s64>(RS(instr)) < 0); break;
|
||||
case BGEZAL: blink(instr, regs.Read<s64>(RS(instr)) >= 0); break;
|
||||
case BLTZALL: bllink(instr, regs.Read<s64>(RS(instr)) < 0); break;
|
||||
case BGEZALL: bllink(instr, regs.Read<s64>(RS(instr)) >= 0); break;
|
||||
default:
|
||||
Util::panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})", (mask >> 3) & 3, mask & 7, instr, (u64)regs.oldPC);
|
||||
}
|
||||
@@ -116,13 +116,10 @@ void Interpreter::Exec(u32 instr) {
|
||||
case REGIMM: regimm(instr); break;
|
||||
case J: j(instr); break;
|
||||
case JAL: jal(instr); break;
|
||||
case BEQ: b(instr, regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); break;
|
||||
case BNE: {
|
||||
//fmt::print("RS: {:016X}, RT: {:016X}", (u64)regs.gpr[RS(instr)], (u64)regs.gpr[RT(instr)]);
|
||||
b(instr, regs.gpr[RS(instr)] != regs.gpr[RT(instr)]);
|
||||
} break;
|
||||
case BLEZ: b(instr, regs.gpr[RS(instr)] <= 0); break;
|
||||
case BGTZ: b(instr, regs.gpr[RS(instr)] > 0); break;
|
||||
case BEQ: b(instr, regs.Read<s64>(RS(instr)) == regs.Read<s64>(RT(instr))); break;
|
||||
case BNE: b(instr, regs.Read<s64>(RS(instr)) != regs.Read<s64>(RT(instr))); break;
|
||||
case BLEZ: b(instr, regs.Read<s64>(RS(instr)) <= 0); break;
|
||||
case BGTZ: b(instr, regs.Read<s64>(RS(instr)) > 0); break;
|
||||
case ADDI: addi(instr); break;
|
||||
case ADDIU: addiu(instr); break;
|
||||
case SLTI: slti(instr); break;
|
||||
@@ -134,10 +131,10 @@ void Interpreter::Exec(u32 instr) {
|
||||
case COP0: regs.cop0.decode(*this, instr); break;
|
||||
case COP1: regs.cop1.decode(*this, instr); break;
|
||||
case COP2: cop2Decode(instr); break;
|
||||
case BEQL: bl(instr, regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); break;
|
||||
case BNEL: bl(instr, regs.gpr[RS(instr)] != regs.gpr[RT(instr)]); break;
|
||||
case BLEZL: bl(instr, regs.gpr[RS(instr)] <= 0); break;
|
||||
case BGTZL: bl(instr, regs.gpr[RS(instr)] > 0); break;
|
||||
case BEQL: bl(instr, regs.Read<s64>(RS(instr)) == regs.Read<s64>(RT(instr))); break;
|
||||
case BNEL: bl(instr, regs.Read<s64>(RS(instr)) != regs.Read<s64>(RT(instr))); break;
|
||||
case BLEZL: bl(instr, regs.Read<s64>(RS(instr)) <= 0); break;
|
||||
case BGTZL: bl(instr, regs.Read<s64>(RS(instr)) > 0); break;
|
||||
case DADDI: daddi(instr); break;
|
||||
case DADDIU: daddiu(instr); break;
|
||||
case LDL: ldl(instr); break;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,11 @@ Flash::Flash(mio::mmap_sink &saveData) : saveData(saveData) {}
|
||||
|
||||
void Flash::Reset() {
|
||||
state = FlashState::Idle;
|
||||
writeOffs = {};
|
||||
state = {};
|
||||
status = {};
|
||||
eraseOffs = {};
|
||||
writeBuf = {};
|
||||
}
|
||||
|
||||
void Flash::Load(SaveType saveType, const std::string& path) {
|
||||
|
||||
@@ -13,8 +13,8 @@ void AI::Reset() {
|
||||
dmaCount = 0;
|
||||
dmaAddrCarry = false;
|
||||
cycles = 0;
|
||||
memset(dmaLen, 0, 2);
|
||||
memset(dmaAddr, 0, 2);
|
||||
dmaLen = {};
|
||||
dmaAddr = {};
|
||||
dac = {44100, N64_CPU_FREQ / dac.freq, 16};
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ void AI::Step(u32 cpuCycles, float volumeL, float volumeR) {
|
||||
if(dmaLen[0] && dmaEnable) {
|
||||
u32 addrHi = ((dmaAddr[0] >> 13) + dmaAddrCarry) & 0x7FF;
|
||||
dmaAddr[0] = (addrHi << 13) | (dmaAddr[0] & 0x1FFF);
|
||||
u32 data = Util::ReadAccess<u32>(mem.mmio.rdp.rdram, dmaAddr[0] & RDRAM_DSIZE);
|
||||
u32 data = mem.mmio.rdp.ReadRDRAM<u32>(dmaAddr[0]);
|
||||
s16 l = s16(data >> 16);
|
||||
s16 r = s16(data);
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
#include <core/mmio/Audio.hpp>
|
||||
|
||||
namespace n64 {
|
||||
@@ -17,8 +16,8 @@ struct AI {
|
||||
u16 dacRate{};
|
||||
u8 bitrate{};
|
||||
int dmaCount{};
|
||||
u32 dmaLen[2]{};
|
||||
u32 dmaAddr[2]{};
|
||||
std::array<u32, 2> dmaLen{};
|
||||
std::array<u32, 2> dmaAddr{};
|
||||
bool dmaAddrCarry{};
|
||||
u32 cycles{};
|
||||
AudioDevice device;
|
||||
|
||||
@@ -11,19 +11,13 @@ namespace n64 {
|
||||
void audioCallback(void* user, Uint8* stream, int length) {
|
||||
auto audioDevice = (AudioDevice*)user;
|
||||
int gotten = 0, available = 0;
|
||||
|
||||
if (audioDevice) {
|
||||
audioDevice->LockMutex();
|
||||
available = SDL_AudioStreamAvailable(audioDevice->GetStream());
|
||||
if (available > 0) {
|
||||
gotten = SDL_AudioStreamGet(audioDevice->GetStream(), stream, length);
|
||||
}
|
||||
|
||||
if (audioDevice) {
|
||||
available = SDL_AudioStreamAvailable(audioDevice->GetStream().get());
|
||||
}
|
||||
|
||||
if (available > 0 && audioDevice) {
|
||||
gotten = SDL_AudioStreamGet(audioDevice->GetStream().get(), stream, length);
|
||||
}
|
||||
|
||||
if (audioDevice) {
|
||||
audioDevice->UnlockMutex();
|
||||
}
|
||||
|
||||
@@ -37,11 +31,18 @@ void audioCallback(void* user, Uint8* stream, int length) {
|
||||
}
|
||||
}
|
||||
|
||||
AudioDevice::AudioDevice() : audioStream(SDL_NewAudioStream, SDL_FreeAudioStream, "audioStream", SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE, SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE),
|
||||
audioStreamMutex(SDL_CreateMutex, SDL_DestroyMutex, "audioStreamMutex") {
|
||||
AudioDevice::~AudioDevice() {
|
||||
LockMutex();
|
||||
SDL_FreeAudioStream(GetStream());
|
||||
UnlockMutex();
|
||||
SDL_DestroyMutex(audioStreamMutex);
|
||||
}
|
||||
|
||||
AudioDevice::AudioDevice() : audioStream(SDL_NewAudioStream(SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE, SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE)),
|
||||
audioStreamMutex(SDL_CreateMutex()) {
|
||||
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
||||
|
||||
if(!audioStreamMutex.get()) {
|
||||
if(!audioStreamMutex) {
|
||||
Util::panic("Unable to initialize audio mutex: {}", SDL_GetError());
|
||||
}
|
||||
|
||||
@@ -66,15 +67,16 @@ void AudioDevice::PushSample(float left, float volumeL, float right, float volum
|
||||
float adjustedR = right * volumeR;
|
||||
float samples[2]{ adjustedL, adjustedR };
|
||||
|
||||
auto availableBytes = (float)SDL_AudioStreamAvailable(audioStream.get());
|
||||
auto availableBytes = (float)SDL_AudioStreamAvailable(audioStream);
|
||||
if(availableBytes <= BYTES_PER_HALF_SECOND) {
|
||||
SDL_AudioStreamPut(audioStream.get(), samples, 2 * sizeof(float));
|
||||
SDL_AudioStreamPut(audioStream, samples, 2 * sizeof(float));
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDevice::AdjustSampleRate(int sampleRate) {
|
||||
LockMutex();
|
||||
audioStream.Construct(SDL_NewAudioStream, SYSTEM_SAMPLE_FORMAT, 2, sampleRate, SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE);
|
||||
SDL_FreeAudioStream(audioStream);
|
||||
audioStream = SDL_NewAudioStream(SYSTEM_SAMPLE_FORMAT, 2, sampleRate, SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE);
|
||||
UnlockMutex();
|
||||
}
|
||||
}
|
||||
@@ -5,24 +5,23 @@
|
||||
namespace n64 {
|
||||
struct AudioDevice {
|
||||
AudioDevice();
|
||||
~AudioDevice();
|
||||
|
||||
void PushSample(float, float, float, float);
|
||||
void AdjustSampleRate(int);
|
||||
void LockMutex() {
|
||||
if(audioStreamMutex.get())
|
||||
SDL_LockMutex(audioStreamMutex.get());
|
||||
if(audioStreamMutex)
|
||||
SDL_LockMutex(audioStreamMutex);
|
||||
}
|
||||
void UnlockMutex() {
|
||||
if (audioStreamMutex.get())
|
||||
SDL_UnlockMutex(audioStreamMutex.get());
|
||||
if (audioStreamMutex)
|
||||
SDL_UnlockMutex(audioStreamMutex);
|
||||
}
|
||||
|
||||
Util::AutoRelease<SDL_AudioStream, const SDL_AudioFormat, const Uint8, const int, const SDL_AudioFormat,
|
||||
const Uint8, const int>& GetStream() { return audioStream; }
|
||||
SDL_AudioStream* GetStream() { return audioStream; }
|
||||
private:
|
||||
Util::AutoRelease<SDL_AudioStream, const SDL_AudioFormat, const Uint8, const int, const SDL_AudioFormat,
|
||||
const Uint8, const int> audioStream;
|
||||
Util::AutoRelease<SDL_mutex> audioStreamMutex;
|
||||
SDL_AudioStream* audioStream;
|
||||
SDL_mutex* audioStreamMutex;
|
||||
SDL_AudioSpec audioSpec{};
|
||||
SDL_AudioSpec request{};
|
||||
SDL_AudioDeviceID handle{};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
#include <core/mmio/MI.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
#include <core/mmio/MI.hpp>
|
||||
|
||||
namespace n64 {
|
||||
|
||||
struct Registers;
|
||||
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <core/mmio/MI.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
#include <log.hpp>
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
|
||||
#define MI_VERSION_REG 0x02020102
|
||||
|
||||
@@ -60,7 +59,7 @@ void MI::Write(u32 paddr, u32 val) {
|
||||
miMode |= 1 << 9;
|
||||
}
|
||||
break;
|
||||
case 0x4: break;
|
||||
case 0x4: case 0x8: break;
|
||||
case 0xC:
|
||||
for (int bit = 0; bit < 6; bit++) {
|
||||
int clearbit = bit << 1;
|
||||
|
||||
@@ -14,8 +14,6 @@ void PI::Reset() {
|
||||
latch = 0;
|
||||
dramAddr = 0;
|
||||
cartAddr = 0;
|
||||
dramAddrInternal = 0;
|
||||
cartAddrInternal = 0;
|
||||
rdLen = 0;
|
||||
wrLen = 0;
|
||||
piBsdDom1Lat = 0;
|
||||
@@ -271,7 +269,7 @@ template <> void PI::BusWrite<u32, false>(u32 addr, u32 val) {
|
||||
if (val < CART_ISVIEWER_SIZE) {
|
||||
std::string message(val + 1, 0);
|
||||
std::copy(mem.isviewer.begin(), mem.isviewer.begin() + val, message.begin());
|
||||
Util::always("{}", message);
|
||||
Util::print<Util::Always>("{}", message);
|
||||
} else {
|
||||
Util::panic("ISViewer buffer size is emulated at {} bytes, but received a flush command for {} bytes!", CART_ISVIEWER_SIZE, val);
|
||||
}
|
||||
@@ -353,8 +351,8 @@ template <> void PI::BusWrite<true>(u32 addr, u64 val) {
|
||||
|
||||
auto PI::Read(u32 addr) const -> u32 {
|
||||
switch(addr) {
|
||||
case 0x04600000: return dramAddr;
|
||||
case 0x04600004: return cartAddr;
|
||||
case 0x04600000: return dramAddr & 0x00FFFFFE;
|
||||
case 0x04600004: return cartAddr & 0xFFFFFFFE;
|
||||
case 0x04600008: return rdLen;
|
||||
case 0x0460000C: return wrLen;
|
||||
case 0x04600010: {
|
||||
@@ -425,57 +423,60 @@ u32 PI::AccessTiming(u8 domain, u32 length) const {
|
||||
return cycles * 1.5; // Converting RCP clock speed to CPU clock speed
|
||||
}
|
||||
|
||||
void PI::Write(u32 addr, u32 val) {
|
||||
MI& mi = mem.mmio.mi;
|
||||
switch(addr) {
|
||||
case 0x04600000: dramAddr = val & 0xFFFFFF; break;
|
||||
case 0x04600004: cartAddr = val; break;
|
||||
case 0x04600008: {
|
||||
u32 len = (val & 0x00FFFFFF) + 1;
|
||||
cartAddrInternal = cartAddr & 0xFFFFFFFE;
|
||||
dramAddrInternal = dramAddr & 0x007FFFFE;
|
||||
if (dramAddrInternal & 0x7) {
|
||||
len -= dramAddrInternal & 0x7;
|
||||
// rdram -> cart
|
||||
template <> void PI::DMA<false>() {
|
||||
s32 len = rdLen + 1;
|
||||
Util::trace("PI DMA from RDRAM to CARTRIDGE (size: {} B, {:08X} to {:08X})", len, dramAddr, cartAddr);
|
||||
|
||||
if(mem.saveType == SAVE_FLASH_1m && cartAddr >= SREGION_PI_SRAM && cartAddr < 0x08010000) {
|
||||
cartAddr = SREGION_PI_SRAM | ((cartAddr & 0xFFFFF) << 1);
|
||||
}
|
||||
rdLen = len;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
u32 addr = BYTE_ADDRESS(dramAddrInternal + i) & RDRAM_DSIZE;
|
||||
if (addr < RDRAM_SIZE) {
|
||||
BusWrite<u8, true>(cartAddrInternal + i, mem.mmio.rdp.rdram[addr]);
|
||||
BusWrite<u8, true>(cartAddr + i, mem.mmio.rdp.ReadRDRAM<u8>(dramAddr + i));
|
||||
}
|
||||
else {
|
||||
BusWrite<u8, true>(cartAddrInternal + i, 0);
|
||||
}
|
||||
}
|
||||
Util::trace("PI DMA from RDRAM to CARTRIDGE (size: {} B, {:08X} to {:08X})", len, dramAddr, cartAddr);
|
||||
dmaBusy = true;
|
||||
toCart = true;
|
||||
scheduler.EnqueueRelative(AccessTiming(GetDomain(cartAddr), len), PI_DMA_COMPLETE);
|
||||
} break;
|
||||
case 0x0460000C: {
|
||||
u32 len = (val & 0x00FFFFFF) + 1;
|
||||
cartAddrInternal = cartAddr & 0xFFFFFFFE;
|
||||
dramAddrInternal = dramAddr & 0x007FFFFE;
|
||||
if (dramAddrInternal & 0x7) {
|
||||
len -= (dramAddrInternal & 0x7);
|
||||
}
|
||||
wrLen = len;
|
||||
dramAddr += len;
|
||||
dramAddr = (dramAddr + 7) & ~7;
|
||||
cartAddr += len;
|
||||
if(cartAddr & 1) cartAddr += 1;
|
||||
|
||||
if(mem.saveType == SAVE_FLASH_1m && cartAddrInternal >= SREGION_PI_SRAM && cartAddrInternal < 0x08010000) {
|
||||
cartAddrInternal = SREGION_PI_SRAM | ((cartAddrInternal & 0xFFFFF) << 1);
|
||||
dmaBusy = true;
|
||||
scheduler.EnqueueRelative(AccessTiming(GetDomain(cartAddr), rdLen), PI_DMA_COMPLETE);
|
||||
}
|
||||
|
||||
// cart -> rdram
|
||||
template <> void PI::DMA<true>() {
|
||||
s32 len = wrLen + 1;
|
||||
Util::trace("PI DMA from CARTRIDGE to RDRAM (size: {} B, {:08X} to {:08X})", len, cartAddr, dramAddr);
|
||||
|
||||
if(mem.saveType == SAVE_FLASH_1m && cartAddr >= SREGION_PI_SRAM && cartAddr < 0x08010000) {
|
||||
cartAddr = SREGION_PI_SRAM | ((cartAddr & 0xFFFFF) << 1);
|
||||
}
|
||||
|
||||
for(u32 i = 0; i < len; i++) {
|
||||
u32 addr = BYTE_ADDRESS(dramAddrInternal + i) & RDRAM_DSIZE;
|
||||
if (addr < RDRAM_SIZE) {
|
||||
mem.mmio.rdp.rdram[addr] = BusRead<u8, true>(cartAddrInternal + i);
|
||||
}
|
||||
mem.mmio.rdp.WriteRDRAM<u8>(dramAddr + i, BusRead<u8, true>(cartAddr + i));
|
||||
}
|
||||
dramAddr += len;
|
||||
dramAddr = (dramAddr + 7) & ~7;
|
||||
cartAddr += len;
|
||||
if(cartAddr & 1) cartAddr += 1;
|
||||
|
||||
dmaBusy = true;
|
||||
Util::trace("PI DMA from CARTRIDGE to RDRAM (size: {} B, {:08X} to {:08X})", len, cartAddr, dramAddr);
|
||||
toCart = false;
|
||||
scheduler.EnqueueRelative(AccessTiming(GetDomain(cartAddr), len), PI_DMA_COMPLETE);
|
||||
}
|
||||
|
||||
void PI::Write(u32 addr, u32 val) {
|
||||
MI& mi = mem.mmio.mi;
|
||||
switch(addr) {
|
||||
case 0x04600000: dramAddr = val & 0x00FFFFFE; break;
|
||||
case 0x04600004: cartAddr = val & 0xFFFFFFFE; break;
|
||||
case 0x04600008: {
|
||||
rdLen = val & 0x00FFFFFF;
|
||||
DMA<false>();
|
||||
} break;
|
||||
case 0x0460000C: {
|
||||
wrLen = val & 0x00FFFFFF;
|
||||
DMA<true>();
|
||||
} break;
|
||||
case 0x04600010:
|
||||
if(val & 2) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
|
||||
namespace n64 {
|
||||
|
||||
@@ -26,15 +25,18 @@ struct PI {
|
||||
|
||||
static u8 GetDomain(u32 address);
|
||||
[[nodiscard]] u32 AccessTiming(u8 domain, u32 length) const;
|
||||
bool dmaBusy{}, ioBusy{}, toCart{};
|
||||
bool dmaBusy{}, ioBusy{};
|
||||
u32 latch{};
|
||||
u32 dramAddr{}, cartAddr{}, dramAddrInternal{}, cartAddrInternal{};
|
||||
u32 dramAddr{}, cartAddr{};
|
||||
u32 rdLen{}, wrLen{};
|
||||
u32 piBsdDom1Lat{}, piBsdDom2Lat{};
|
||||
u32 piBsdDom1Pwd{}, piBsdDom2Pwd{};
|
||||
u32 piBsdDom1Pgs{}, piBsdDom2Pgs{};
|
||||
u32 piBsdDom1Rls{}, piBsdDom2Rls{};
|
||||
private:
|
||||
template <bool toDram>
|
||||
void DMA();
|
||||
|
||||
Mem& mem;
|
||||
Registers& regs;
|
||||
};
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
|
||||
namespace n64 {
|
||||
void PIF::Reset() {
|
||||
memset(joybusDevices, 0, sizeof(JoybusDevice) * 6);
|
||||
memset(bootrom, 0, PIF_BOOTROM_SIZE);
|
||||
memset(ram, 0, PIF_RAM_SIZE);
|
||||
movie.Reset();
|
||||
joybusDevices = {};
|
||||
bootrom = {};
|
||||
ram = {};
|
||||
std::error_code error;
|
||||
if(mempak.is_mapped()) {
|
||||
mempak.sync(error);
|
||||
@@ -26,6 +27,7 @@ void PIF::Reset() {
|
||||
}
|
||||
|
||||
mempakOpen = false;
|
||||
channel = 0;
|
||||
}
|
||||
|
||||
void PIF::MaybeLoadMempak() {
|
||||
@@ -341,202 +343,202 @@ void PIF::HLE(bool pal, CICType cicType) {
|
||||
Util::warn("Unknown CIC type!");
|
||||
break;
|
||||
case CIC_NUS_6101:
|
||||
regs.gpr[0] = 0x0000000000000000;
|
||||
regs.gpr[1] = 0x0000000000000000;
|
||||
regs.gpr[2] = 0xFFFFFFFFDF6445CCll;
|
||||
regs.gpr[3] = 0xFFFFFFFFDF6445CCll;
|
||||
regs.gpr[4] = 0x00000000000045CC;
|
||||
regs.gpr[5] = 0x0000000073EE317A;
|
||||
regs.gpr[6] = 0xFFFFFFFFA4001F0Cll;
|
||||
regs.gpr[7] = 0xFFFFFFFFA4001F08ll;
|
||||
regs.gpr[8] = 0x00000000000000C0;
|
||||
regs.gpr[9] = 0x0000000000000000;
|
||||
regs.gpr[10] = 0x0000000000000040;
|
||||
regs.gpr[11] = 0xFFFFFFFFA4000040ll;
|
||||
regs.gpr[12] = 0xFFFFFFFFC7601FACll;
|
||||
regs.gpr[13] = 0xFFFFFFFFC7601FACll;
|
||||
regs.gpr[14] = 0xFFFFFFFFB48E2ED6ll;
|
||||
regs.gpr[15] = 0xFFFFFFFFBA1A7D4Bll;
|
||||
regs.gpr[16] = 0x0000000000000000;
|
||||
regs.gpr[17] = 0x0000000000000000;
|
||||
regs.gpr[18] = 0x0000000000000000;
|
||||
regs.gpr[19] = 0x0000000000000000;
|
||||
regs.gpr[20] = 0x0000000000000001;
|
||||
regs.gpr[21] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000001;
|
||||
regs.gpr[24] = 0x0000000000000002;
|
||||
regs.gpr[25] = 0xFFFFFFFF905F4718ll;
|
||||
regs.gpr[26] = 0x0000000000000000;
|
||||
regs.gpr[27] = 0x0000000000000000;
|
||||
regs.gpr[28] = 0x0000000000000000;
|
||||
regs.gpr[29] = 0xFFFFFFFFA4001FF0ll;
|
||||
regs.gpr[30] = 0x0000000000000000;
|
||||
regs.gpr[31] = 0xFFFFFFFFA4001550ll;
|
||||
regs.Write(0, 0x0000000000000000);
|
||||
regs.Write(1, 0x0000000000000000);
|
||||
regs.Write(2, 0xFFFFFFFFDF6445CC);
|
||||
regs.Write(3, 0xFFFFFFFFDF6445CC);
|
||||
regs.Write(4, 0x00000000000045CC);
|
||||
regs.Write(5, 0x0000000073EE317A);
|
||||
regs.Write(6, 0xFFFFFFFFA4001F0C);
|
||||
regs.Write(7, 0xFFFFFFFFA4001F08);
|
||||
regs.Write(8, 0x00000000000000C0);
|
||||
regs.Write(9, 0x0000000000000000);
|
||||
regs.Write(10, 0x0000000000000040);
|
||||
regs.Write(11, 0xFFFFFFFFA4000040);
|
||||
regs.Write(12, 0xFFFFFFFFC7601FAC);
|
||||
regs.Write(13, 0xFFFFFFFFC7601FAC);
|
||||
regs.Write(14, 0xFFFFFFFFB48E2ED6);
|
||||
regs.Write(15, 0xFFFFFFFFBA1A7D4B);
|
||||
regs.Write(16, 0x0000000000000000);
|
||||
regs.Write(17, 0x0000000000000000);
|
||||
regs.Write(18, 0x0000000000000000);
|
||||
regs.Write(19, 0x0000000000000000);
|
||||
regs.Write(20, 0x0000000000000001);
|
||||
regs.Write(21, 0x0000000000000000);
|
||||
regs.Write(23, 0x0000000000000001);
|
||||
regs.Write(24, 0x0000000000000002);
|
||||
regs.Write(25, 0xFFFFFFFF905F4718);
|
||||
regs.Write(26, 0x0000000000000000);
|
||||
regs.Write(27, 0x0000000000000000);
|
||||
regs.Write(28, 0x0000000000000000);
|
||||
regs.Write(29, 0xFFFFFFFFA4001FF0);
|
||||
regs.Write(30, 0x0000000000000000);
|
||||
regs.Write(31, 0xFFFFFFFFA4001550);
|
||||
|
||||
regs.lo = 0xFFFFFFFFBA1A7D4Bll;
|
||||
regs.hi = 0xFFFFFFFF997EC317ll;
|
||||
break;
|
||||
case CIC_NUS_7102:
|
||||
regs.gpr[0] = 0x0000000000000000;
|
||||
regs.gpr[1] = 0x0000000000000001;
|
||||
regs.gpr[2] = 0x000000001E324416;
|
||||
regs.gpr[3] = 0x000000001E324416;
|
||||
regs.gpr[4] = 0x0000000000004416;
|
||||
regs.gpr[5] = 0x000000000EC5D9AF;
|
||||
regs.gpr[6] = 0xFFFFFFFFA4001F0Cll;
|
||||
regs.gpr[7] = 0xFFFFFFFFA4001F08ll;
|
||||
regs.gpr[8] = 0x00000000000000C0;
|
||||
regs.gpr[9] = 0x0000000000000000;
|
||||
regs.gpr[10] = 0x0000000000000040;
|
||||
regs.gpr[11] = 0xFFFFFFFFA4000040ll;
|
||||
regs.gpr[12] = 0x00000000495D3D7B;
|
||||
regs.gpr[13] = 0xFFFFFFFF8B3DFA1Ell;
|
||||
regs.gpr[14] = 0x000000004798E4D4;
|
||||
regs.gpr[15] = 0xFFFFFFFFF1D30682ll;
|
||||
regs.gpr[16] = 0x0000000000000000;
|
||||
regs.gpr[17] = 0x0000000000000000;
|
||||
regs.gpr[18] = 0x0000000000000000;
|
||||
regs.gpr[19] = 0x0000000000000000;
|
||||
regs.gpr[20] = 0x0000000000000000;
|
||||
regs.gpr[21] = 0x0000000000000000;
|
||||
regs.gpr[22] = 0x000000000000003F;
|
||||
regs.gpr[23] = 0x0000000000000007;
|
||||
regs.gpr[24] = 0x0000000000000000;
|
||||
regs.gpr[25] = 0x0000000013D05CAB;
|
||||
regs.gpr[26] = 0x0000000000000000;
|
||||
regs.gpr[27] = 0x0000000000000000;
|
||||
regs.gpr[28] = 0x0000000000000000;
|
||||
regs.gpr[29] = 0xFFFFFFFFA4001FF0ll;
|
||||
regs.gpr[30] = 0x0000000000000000;
|
||||
regs.gpr[31] = 0xFFFFFFFFA4001554ll;
|
||||
regs.Write(0, 0x0000000000000000);
|
||||
regs.Write(1, 0x0000000000000001);
|
||||
regs.Write(2, 0x000000001E324416);
|
||||
regs.Write(3, 0x000000001E324416);
|
||||
regs.Write(4, 0x0000000000004416);
|
||||
regs.Write(5, 0x000000000EC5D9AF);
|
||||
regs.Write(6, 0xFFFFFFFFA4001F0C);
|
||||
regs.Write(7, 0xFFFFFFFFA4001F08);
|
||||
regs.Write(8, 0x00000000000000C0);
|
||||
regs.Write(9, 0x0000000000000000);
|
||||
regs.Write(10, 0x0000000000000040);
|
||||
regs.Write(11, 0xFFFFFFFFA4000040);
|
||||
regs.Write(12, 0x00000000495D3D7B);
|
||||
regs.Write(13, 0xFFFFFFFF8B3DFA1E);
|
||||
regs.Write(14, 0x000000004798E4D4);
|
||||
regs.Write(15, 0xFFFFFFFFF1D30682);
|
||||
regs.Write(16, 0x0000000000000000);
|
||||
regs.Write(17, 0x0000000000000000);
|
||||
regs.Write(18, 0x0000000000000000);
|
||||
regs.Write(19, 0x0000000000000000);
|
||||
regs.Write(20, 0x0000000000000000);
|
||||
regs.Write(21, 0x0000000000000000);
|
||||
regs.Write(22, 0x000000000000003F);
|
||||
regs.Write(23, 0x0000000000000007);
|
||||
regs.Write(24, 0x0000000000000000);
|
||||
regs.Write(25, 0x0000000013D05CAB);
|
||||
regs.Write(26, 0x0000000000000000);
|
||||
regs.Write(27, 0x0000000000000000);
|
||||
regs.Write(28, 0x0000000000000000);
|
||||
regs.Write(29, 0xFFFFFFFFA4001FF0);
|
||||
regs.Write(30, 0x0000000000000000);
|
||||
regs.Write(31, 0xFFFFFFFFA4001554);
|
||||
|
||||
regs.lo = 0xFFFFFFFFF1D30682ll;
|
||||
regs.hi = 0x0000000010054A98;
|
||||
break;
|
||||
case CIC_NUS_6102_7101:
|
||||
regs.gpr[0] = 0x0000000000000000;
|
||||
regs.gpr[1] = 0x0000000000000001;
|
||||
regs.gpr[2] = 0x000000000EBDA536;
|
||||
regs.gpr[3] = 0x000000000EBDA536;
|
||||
regs.gpr[4] = 0x000000000000A536;
|
||||
regs.gpr[5] = 0xFFFFFFFFC0F1D859ll;
|
||||
regs.gpr[6] = 0xFFFFFFFFA4001F0Cll;
|
||||
regs.gpr[7] = 0xFFFFFFFFA4001F08ll;
|
||||
regs.gpr[8] = 0x00000000000000C0;
|
||||
regs.gpr[9] = 0x0000000000000000;
|
||||
regs.gpr[10] = 0x0000000000000040;
|
||||
regs.gpr[11] = 0xFFFFFFFFA4000040ll;
|
||||
regs.gpr[12] = 0xFFFFFFFFED10D0B3ll;
|
||||
regs.gpr[13] = 0x000000001402A4CC;
|
||||
regs.gpr[14] = 0x000000002DE108EA;
|
||||
regs.gpr[15] = 0x000000003103E121;
|
||||
regs.gpr[16] = 0x0000000000000000;
|
||||
regs.gpr[17] = 0x0000000000000000;
|
||||
regs.gpr[18] = 0x0000000000000000;
|
||||
regs.gpr[19] = 0x0000000000000000;
|
||||
regs.gpr[20] = 0x0000000000000001;
|
||||
regs.gpr[21] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000000;
|
||||
regs.gpr[24] = 0x0000000000000000;
|
||||
regs.gpr[25] = 0xFFFFFFFF9DEBB54Fll;
|
||||
regs.gpr[26] = 0x0000000000000000;
|
||||
regs.gpr[27] = 0x0000000000000000;
|
||||
regs.gpr[28] = 0x0000000000000000;
|
||||
regs.gpr[29] = 0xFFFFFFFFA4001FF0ll;
|
||||
regs.gpr[30] = 0x0000000000000000;
|
||||
regs.gpr[31] = 0xFFFFFFFFA4001550ll;
|
||||
regs.Write(0, 0x0000000000000000);
|
||||
regs.Write(1, 0x0000000000000001);
|
||||
regs.Write(2, 0x000000000EBDA536);
|
||||
regs.Write(3, 0x000000000EBDA536);
|
||||
regs.Write(4, 0x000000000000A536);
|
||||
regs.Write(5, 0xFFFFFFFFC0F1D859);
|
||||
regs.Write(6, 0xFFFFFFFFA4001F0C);
|
||||
regs.Write(7, 0xFFFFFFFFA4001F08);
|
||||
regs.Write(8, 0x00000000000000C0);
|
||||
regs.Write(9, 0x0000000000000000);
|
||||
regs.Write(10, 0x0000000000000040);
|
||||
regs.Write(11, 0xFFFFFFFFA4000040);
|
||||
regs.Write(12, 0xFFFFFFFFED10D0B3);
|
||||
regs.Write(13, 0x000000001402A4CC);
|
||||
regs.Write(14, 0x000000002DE108EA);
|
||||
regs.Write(15, 0x000000003103E121);
|
||||
regs.Write(16, 0x0000000000000000);
|
||||
regs.Write(17, 0x0000000000000000);
|
||||
regs.Write(18, 0x0000000000000000);
|
||||
regs.Write(19, 0x0000000000000000);
|
||||
regs.Write(20, 0x0000000000000001);
|
||||
regs.Write(21, 0x0000000000000000);
|
||||
regs.Write(23, 0x0000000000000000);
|
||||
regs.Write(24, 0x0000000000000000);
|
||||
regs.Write(25, 0xFFFFFFFF9DEBB54F);
|
||||
regs.Write(26, 0x0000000000000000);
|
||||
regs.Write(27, 0x0000000000000000);
|
||||
regs.Write(28, 0x0000000000000000);
|
||||
regs.Write(29, 0xFFFFFFFFA4001FF0);
|
||||
regs.Write(30, 0x0000000000000000);
|
||||
regs.Write(31, 0xFFFFFFFFA4001550);
|
||||
|
||||
regs.hi = 0x000000003FC18657;
|
||||
regs.lo = 0x000000003103E121;
|
||||
|
||||
if (pal) {
|
||||
regs.gpr[20] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000006;
|
||||
regs.gpr[31] = 0xFFFFFFFFA4001554ll;
|
||||
regs.Write(20, 0x0000000000000000);
|
||||
regs.Write(23, 0x0000000000000006);
|
||||
regs.Write(31, 0xFFFFFFFFA4001554);
|
||||
}
|
||||
break;
|
||||
case CIC_NUS_6103_7103:
|
||||
regs.gpr[0] = 0x0000000000000000;
|
||||
regs.gpr[1] = 0x0000000000000001;
|
||||
regs.gpr[2] = 0x0000000049A5EE96;
|
||||
regs.gpr[3] = 0x0000000049A5EE96;
|
||||
regs.gpr[4] = 0x000000000000EE96;
|
||||
regs.gpr[5] = 0xFFFFFFFFD4646273ll;
|
||||
regs.gpr[6] = 0xFFFFFFFFA4001F0Cll;
|
||||
regs.gpr[7] = 0xFFFFFFFFA4001F08ll;
|
||||
regs.gpr[8] = 0x00000000000000C0;
|
||||
regs.gpr[9] = 0x0000000000000000;
|
||||
regs.gpr[10] = 0x0000000000000040;
|
||||
regs.gpr[11] = 0xFFFFFFFFA4000040ll;
|
||||
regs.gpr[12] = 0xFFFFFFFFCE9DFBF7ll;
|
||||
regs.gpr[13] = 0xFFFFFFFFCE9DFBF7ll;
|
||||
regs.gpr[14] = 0x000000001AF99984;
|
||||
regs.gpr[15] = 0x0000000018B63D28;
|
||||
regs.gpr[16] = 0x0000000000000000;
|
||||
regs.gpr[17] = 0x0000000000000000;
|
||||
regs.gpr[18] = 0x0000000000000000;
|
||||
regs.gpr[19] = 0x0000000000000000;
|
||||
regs.gpr[20] = 0x0000000000000001;
|
||||
regs.gpr[21] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000000;
|
||||
regs.gpr[24] = 0x0000000000000000;
|
||||
regs.gpr[25] = 0xFFFFFFFF825B21C9ll;
|
||||
regs.gpr[26] = 0x0000000000000000;
|
||||
regs.gpr[27] = 0x0000000000000000;
|
||||
regs.gpr[28] = 0x0000000000000000;
|
||||
regs.gpr[29] = 0xFFFFFFFFA4001FF0ll;
|
||||
regs.gpr[30] = 0x0000000000000000;
|
||||
regs.gpr[31] = 0xFFFFFFFFA4001550ll;
|
||||
regs.Write(0, 0x0000000000000000);
|
||||
regs.Write(1, 0x0000000000000001);
|
||||
regs.Write(2, 0x0000000049A5EE96);
|
||||
regs.Write(3, 0x0000000049A5EE96);
|
||||
regs.Write(4, 0x000000000000EE96);
|
||||
regs.Write(5, 0xFFFFFFFFD4646273);
|
||||
regs.Write(6, 0xFFFFFFFFA4001F0C);
|
||||
regs.Write(7, 0xFFFFFFFFA4001F08);
|
||||
regs.Write(8, 0x00000000000000C0);
|
||||
regs.Write(9, 0x0000000000000000);
|
||||
regs.Write(10, 0x0000000000000040);
|
||||
regs.Write(11, 0xFFFFFFFFA4000040);
|
||||
regs.Write(12, 0xFFFFFFFFCE9DFBF7);
|
||||
regs.Write(13, 0xFFFFFFFFCE9DFBF7);
|
||||
regs.Write(14, 0x000000001AF99984);
|
||||
regs.Write(15, 0x0000000018B63D28);
|
||||
regs.Write(16, 0x0000000000000000);
|
||||
regs.Write(17, 0x0000000000000000);
|
||||
regs.Write(18, 0x0000000000000000);
|
||||
regs.Write(19, 0x0000000000000000);
|
||||
regs.Write(20, 0x0000000000000001);
|
||||
regs.Write(21, 0x0000000000000000);
|
||||
regs.Write(23, 0x0000000000000000);
|
||||
regs.Write(24, 0x0000000000000000);
|
||||
regs.Write(25, 0xFFFFFFFF825B21C9);
|
||||
regs.Write(26, 0x0000000000000000);
|
||||
regs.Write(27, 0x0000000000000000);
|
||||
regs.Write(28, 0x0000000000000000);
|
||||
regs.Write(29, 0xFFFFFFFFA4001FF0);
|
||||
regs.Write(30, 0x0000000000000000);
|
||||
regs.Write(31, 0xFFFFFFFFA4001550);
|
||||
|
||||
regs.lo = 0x0000000018B63D28;
|
||||
regs.hi = 0x00000000625C2BBE;
|
||||
|
||||
if (pal) {
|
||||
regs.gpr[20] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000006;
|
||||
regs.gpr[31] = 0xFFFFFFFFA4001554ll;
|
||||
regs.Write(20, 0x0000000000000000);
|
||||
regs.Write(23, 0x0000000000000006);
|
||||
regs.Write(31, 0xFFFFFFFFA4001554);
|
||||
}
|
||||
break;
|
||||
case CIC_NUS_6105_7105:
|
||||
regs.gpr[0] = 0x0000000000000000;
|
||||
regs.gpr[1] = 0x0000000000000000;
|
||||
regs.gpr[2] = 0xFFFFFFFFF58B0FBFll;
|
||||
regs.gpr[3] = 0xFFFFFFFFF58B0FBFll;
|
||||
regs.gpr[4] = 0x0000000000000FBF;
|
||||
regs.gpr[5] = 0xFFFFFFFFDECAAAD1ll;
|
||||
regs.gpr[6] = 0xFFFFFFFFA4001F0Cll;
|
||||
regs.gpr[7] = 0xFFFFFFFFA4001F08ll;
|
||||
regs.gpr[8] = 0x00000000000000C0;
|
||||
regs.gpr[9] = 0x0000000000000000;
|
||||
regs.gpr[10] = 0x0000000000000040;
|
||||
regs.gpr[11] = 0xFFFFFFFFA4000040ll;
|
||||
regs.gpr[12] = 0xFFFFFFFF9651F81Ell;
|
||||
regs.gpr[13] = 0x000000002D42AAC5;
|
||||
regs.gpr[14] = 0x00000000489B52CF;
|
||||
regs.gpr[15] = 0x0000000056584D60;
|
||||
regs.gpr[16] = 0x0000000000000000;
|
||||
regs.gpr[17] = 0x0000000000000000;
|
||||
regs.gpr[18] = 0x0000000000000000;
|
||||
regs.gpr[19] = 0x0000000000000000;
|
||||
regs.gpr[20] = 0x0000000000000001;
|
||||
regs.gpr[21] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000000;
|
||||
regs.gpr[24] = 0x0000000000000002;
|
||||
regs.gpr[25] = 0xFFFFFFFFCDCE565Fll;
|
||||
regs.gpr[26] = 0x0000000000000000;
|
||||
regs.gpr[27] = 0x0000000000000000;
|
||||
regs.gpr[28] = 0x0000000000000000;
|
||||
regs.gpr[29] = 0xFFFFFFFFA4001FF0ll;
|
||||
regs.gpr[30] = 0x0000000000000000;
|
||||
regs.gpr[31] = 0xFFFFFFFFA4001550ll;
|
||||
regs.Write(0, 0x0000000000000000);
|
||||
regs.Write(1, 0x0000000000000000);
|
||||
regs.Write(2, 0xFFFFFFFFF58B0FBF);
|
||||
regs.Write(3, 0xFFFFFFFFF58B0FBF);
|
||||
regs.Write(4, 0x0000000000000FBF);
|
||||
regs.Write(5, 0xFFFFFFFFDECAAAD1);
|
||||
regs.Write(6, 0xFFFFFFFFA4001F0C);
|
||||
regs.Write(7, 0xFFFFFFFFA4001F08);
|
||||
regs.Write(8, 0x00000000000000C0);
|
||||
regs.Write(9, 0x0000000000000000);
|
||||
regs.Write(10, 0x0000000000000040);
|
||||
regs.Write(11, 0xFFFFFFFFA4000040);
|
||||
regs.Write(12, 0xFFFFFFFF9651F81E);
|
||||
regs.Write(13, 0x000000002D42AAC5);
|
||||
regs.Write(14, 0x00000000489B52CF);
|
||||
regs.Write(15, 0x0000000056584D60);
|
||||
regs.Write(16, 0x0000000000000000);
|
||||
regs.Write(17, 0x0000000000000000);
|
||||
regs.Write(18, 0x0000000000000000);
|
||||
regs.Write(19, 0x0000000000000000);
|
||||
regs.Write(20, 0x0000000000000001);
|
||||
regs.Write(21, 0x0000000000000000);
|
||||
regs.Write(23, 0x0000000000000000);
|
||||
regs.Write(24, 0x0000000000000002);
|
||||
regs.Write(25, 0xFFFFFFFFCDCE565F);
|
||||
regs.Write(26, 0x0000000000000000);
|
||||
regs.Write(27, 0x0000000000000000);
|
||||
regs.Write(28, 0x0000000000000000);
|
||||
regs.Write(29, 0xFFFFFFFFA4001FF0);
|
||||
regs.Write(30, 0x0000000000000000);
|
||||
regs.Write(31, 0xFFFFFFFFA4001550);
|
||||
|
||||
regs.lo = 0x0000000056584D60;
|
||||
regs.hi = 0x000000004BE35D1F;
|
||||
|
||||
if (pal) {
|
||||
regs.gpr[20] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000006;
|
||||
regs.gpr[31] = 0xFFFFFFFFA4001554ll;
|
||||
regs.Write(20, 0x0000000000000000);
|
||||
regs.Write(23, 0x0000000000000006);
|
||||
regs.Write(31, 0xFFFFFFFFA4001554);
|
||||
}
|
||||
|
||||
mem.Write<u32>(regs, IMEM_REGION_START + 0x00, 0x3C0DBFC0);
|
||||
@@ -549,49 +551,49 @@ void PIF::HLE(bool pal, CICType cicType) {
|
||||
mem.Write<u32>(regs, IMEM_REGION_START + 0x1C, 0x3C0BB000);
|
||||
break;
|
||||
case CIC_NUS_6106_7106:
|
||||
regs.gpr[0] = 0x0000000000000000;
|
||||
regs.gpr[1] = 0x0000000000000000;
|
||||
regs.gpr[2] = 0xFFFFFFFFA95930A4ll;
|
||||
regs.gpr[3] = 0xFFFFFFFFA95930A4ll;
|
||||
regs.gpr[4] = 0x00000000000030A4;
|
||||
regs.gpr[5] = 0xFFFFFFFFB04DC903ll;
|
||||
regs.gpr[6] = 0xFFFFFFFFA4001F0Cll;
|
||||
regs.gpr[7] = 0xFFFFFFFFA4001F08ll;
|
||||
regs.gpr[8] = 0x00000000000000C0;
|
||||
regs.gpr[9] = 0x0000000000000000;
|
||||
regs.gpr[10] = 0x0000000000000040;
|
||||
regs.gpr[11] = 0xFFFFFFFFA4000040ll;
|
||||
regs.gpr[12] = 0xFFFFFFFFBCB59510ll;
|
||||
regs.gpr[13] = 0xFFFFFFFFBCB59510ll;
|
||||
regs.gpr[14] = 0x000000000CF85C13;
|
||||
regs.gpr[15] = 0x000000007A3C07F4;
|
||||
regs.gpr[16] = 0x0000000000000000;
|
||||
regs.gpr[17] = 0x0000000000000000;
|
||||
regs.gpr[18] = 0x0000000000000000;
|
||||
regs.gpr[19] = 0x0000000000000000;
|
||||
regs.gpr[20] = 0x0000000000000001;
|
||||
regs.gpr[21] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000000;
|
||||
regs.gpr[24] = 0x0000000000000002;
|
||||
regs.gpr[25] = 0x00000000465E3F72;
|
||||
regs.gpr[26] = 0x0000000000000000;
|
||||
regs.gpr[27] = 0x0000000000000000;
|
||||
regs.gpr[28] = 0x0000000000000000;
|
||||
regs.gpr[29] = 0xFFFFFFFFA4001FF0ll;
|
||||
regs.gpr[30] = 0x0000000000000000;
|
||||
regs.gpr[31] = 0xFFFFFFFFA4001550ll;
|
||||
regs.Write(0, 0x0000000000000000);
|
||||
regs.Write(1, 0x0000000000000000);
|
||||
regs.Write(2, 0xFFFFFFFFA95930A4);
|
||||
regs.Write(3, 0xFFFFFFFFA95930A4);
|
||||
regs.Write(4, 0x00000000000030A4);
|
||||
regs.Write(5, 0xFFFFFFFFB04DC903);
|
||||
regs.Write(6, 0xFFFFFFFFA4001F0C);
|
||||
regs.Write(7, 0xFFFFFFFFA4001F08);
|
||||
regs.Write(8, 0x00000000000000C0);
|
||||
regs.Write(9, 0x0000000000000000);
|
||||
regs.Write(10, 0x0000000000000040);
|
||||
regs.Write(11, 0xFFFFFFFFA4000040);
|
||||
regs.Write(12, 0xFFFFFFFFBCB59510);
|
||||
regs.Write(13, 0xFFFFFFFFBCB59510);
|
||||
regs.Write(14, 0x000000000CF85C13);
|
||||
regs.Write(15, 0x000000007A3C07F4);
|
||||
regs.Write(16, 0x0000000000000000);
|
||||
regs.Write(17, 0x0000000000000000);
|
||||
regs.Write(18, 0x0000000000000000);
|
||||
regs.Write(19, 0x0000000000000000);
|
||||
regs.Write(20, 0x0000000000000001);
|
||||
regs.Write(21, 0x0000000000000000);
|
||||
regs.Write(23, 0x0000000000000000);
|
||||
regs.Write(24, 0x0000000000000002);
|
||||
regs.Write(25, 0x00000000465E3F72);
|
||||
regs.Write(26, 0x0000000000000000);
|
||||
regs.Write(27, 0x0000000000000000);
|
||||
regs.Write(28, 0x0000000000000000);
|
||||
regs.Write(29, 0xFFFFFFFFA4001FF0);
|
||||
regs.Write(30, 0x0000000000000000);
|
||||
regs.Write(31, 0xFFFFFFFFA4001550);
|
||||
regs.lo = 0x000000007A3C07F4;
|
||||
regs.hi = 0x0000000023953898;
|
||||
|
||||
if (pal) {
|
||||
regs.gpr[20] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000006;
|
||||
regs.gpr[31] = 0xFFFFFFFFA4001554ll;
|
||||
regs.Write(20, 0x0000000000000000);
|
||||
regs.Write(23, 0x0000000000000006);
|
||||
regs.Write(31, 0xFFFFFFFFA4001554);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
regs.gpr[22] = (cicSeeds[cicType] >> 8) & 0xFF;
|
||||
regs.Write(22, (cicSeeds[cicType] >> 8) & 0xFF);
|
||||
regs.cop0.Reset();
|
||||
mem.Write<u32>(regs, 0x04300004, 0x01010101);
|
||||
std::copy(mem.rom.cart.begin(), mem.rom.cart.begin() + 0x1000, mem.mmio.rsp.dmem.begin());
|
||||
@@ -630,11 +632,11 @@ std::vector<u8> PIF::Serialize() {
|
||||
sizeof(int));
|
||||
|
||||
u32 index = 0;
|
||||
memcpy(res.data() + index, joybusDevices, 6*sizeof(JoybusDevice));
|
||||
memcpy(res.data() + index, joybusDevices.data(), 6*sizeof(JoybusDevice));
|
||||
index += 6*sizeof(JoybusDevice);
|
||||
memcpy(res.data() + index, bootrom, PIF_BOOTROM_SIZE);
|
||||
memcpy(res.data() + index, bootrom.data(), PIF_BOOTROM_SIZE);
|
||||
index += PIF_BOOTROM_SIZE;
|
||||
memcpy(res.data() + index, ram, PIF_RAM_SIZE);
|
||||
memcpy(res.data() + index, ram.data(), PIF_RAM_SIZE);
|
||||
index += PIF_RAM_SIZE;
|
||||
memcpy(res.data() + index, mempak.data(), mempak.size());
|
||||
index += mempak.size();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <filesystem>
|
||||
#include <mio/mmap.hpp>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include "MupenMovie.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
@@ -178,8 +179,9 @@ struct PIF {
|
||||
}
|
||||
|
||||
bool mempakOpen = false;
|
||||
JoybusDevice joybusDevices[6]{};
|
||||
u8 bootrom[PIF_BOOTROM_SIZE]{}, ram[PIF_RAM_SIZE]{};
|
||||
std::array<JoybusDevice, 6> joybusDevices{};
|
||||
std::array<u8, PIF_BOOTROM_SIZE> bootrom{};
|
||||
std::array<u8, PIF_RAM_SIZE> ram{};
|
||||
mio::mmap_sink mempak, eeprom;
|
||||
int channel = 0;
|
||||
std::string mempakPath{}, eepromPath{};
|
||||
|
||||
@@ -35,7 +35,7 @@ bool MupenMovie::Load(const fs::path &path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(&loadedTasMovieHeader, loadedTasMovie.data(), loadedTasMovie.size());
|
||||
memcpy(&loadedTasMovieHeader, loadedTasMovie.data(), sizeof(TASMovieHeader));
|
||||
|
||||
if (loadedTasMovieHeader.signature[0] != 0x4D || loadedTasMovieHeader.signature[1] != 0x36 || loadedTasMovieHeader.signature[2] != 0x34 || loadedTasMovieHeader.signature[3] != 0x1A) {
|
||||
Util::error("Failed to load movie: incorrect signature. Are you sure this is a valid movie?");
|
||||
@@ -71,6 +71,12 @@ MupenMovie::MupenMovie(const fs::path &path) {
|
||||
}
|
||||
}
|
||||
|
||||
void MupenMovie::Reset() {
|
||||
if(!IsLoaded()) return;
|
||||
|
||||
loadedTasMovieIndex = sizeof(TASMovieHeader) - 4; // skip header
|
||||
}
|
||||
|
||||
FORCE_INLINE void LogController(const n64::Controller& controller) {
|
||||
Util::debug("c_right: {}", controller.cRight);
|
||||
Util::debug("c_left: {}", controller.cLeft);
|
||||
|
||||
@@ -49,11 +49,10 @@ struct MupenMovie {
|
||||
MupenMovie() = default;
|
||||
MupenMovie(const fs::path&);
|
||||
bool Load(const fs::path&);
|
||||
void Reset();
|
||||
n64::Controller NextInputs();
|
||||
bool IsLoaded() const { return !loadedTasMovie.empty(); }
|
||||
private:
|
||||
std::string filename = "";
|
||||
std::string game = "";
|
||||
std::vector<u8> loadedTasMovie = {};
|
||||
TASMovieHeader loadedTasMovieHeader = {};
|
||||
uint32_t loadedTasMovieIndex = 0;
|
||||
|
||||
@@ -11,6 +11,7 @@ void SI::Reset() {
|
||||
status.raw = 0;
|
||||
dramAddr = 0;
|
||||
pifAddr = 0;
|
||||
toDram = false;
|
||||
pif.Reset();
|
||||
}
|
||||
|
||||
@@ -32,21 +33,27 @@ auto SI::Read(u32 addr) const -> u32 {
|
||||
}
|
||||
}
|
||||
|
||||
void SI::DMA() {
|
||||
status.dmaBusy = false;
|
||||
if (toDram) {
|
||||
// pif -> rdram
|
||||
template <> void SI::DMA<true>() {
|
||||
pif.ProcessCommands(mem);
|
||||
for(int i = 0; i < 64; i++) {
|
||||
mem.mmio.rdp.rdram[BYTE_ADDRESS(dramAddr + i)] = pif.Read(pifAddr + i);
|
||||
mem.mmio.rdp.WriteRDRAM<u8>(dramAddr + i, pif.Read(pifAddr + i));
|
||||
}
|
||||
Util::trace("SI DMA from PIF RAM to RDRAM ({:08X} to {:08X})", pifAddr, dramAddr);
|
||||
} else {
|
||||
}
|
||||
|
||||
// rdram -> pif
|
||||
template <> void SI::DMA<false>() {
|
||||
for(int i = 0; i < 64; i++) {
|
||||
pif.Write(pifAddr + i, mem.mmio.rdp.rdram[BYTE_ADDRESS(dramAddr + i)]);
|
||||
pif.Write(pifAddr + i, mem.mmio.rdp.ReadRDRAM<u8>(dramAddr + i));
|
||||
}
|
||||
Util::trace("SI DMA from RDRAM to PIF RAM ({:08X} to {:08X})", dramAddr, pifAddr);
|
||||
pif.ProcessCommands(mem);
|
||||
}
|
||||
|
||||
void SI::DMA() {
|
||||
status.dmaBusy = false;
|
||||
if (toDram) DMA<true>();
|
||||
else DMA<false>();
|
||||
mem.mmio.mi.InterruptRaise(MI::Interrupt::SI);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
#include <core/mmio/MI.hpp>
|
||||
#include <core/mmio/PIF.hpp>
|
||||
|
||||
@@ -30,6 +29,8 @@ struct SI {
|
||||
|
||||
auto Read(u32) const -> u32;
|
||||
void Write(u32, u32);
|
||||
template <bool toDram>
|
||||
void DMA();
|
||||
void DMA();
|
||||
PIF pif;
|
||||
private:
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include <log.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
#include <core/Mem.hpp>
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
|
||||
namespace n64 {
|
||||
VI::VI (Mem& mem, Registers& regs) : mem(mem), regs(regs) {
|
||||
@@ -20,6 +19,11 @@ void VI::Reset() {
|
||||
numHalflines = 262;
|
||||
numFields = 1;
|
||||
cyclesPerHalfline = 1000;
|
||||
xscale = {}, yscale = {};
|
||||
hsyncLeap = {}, burst = {}, vburst = {};
|
||||
hstart = {}, vstart = {};
|
||||
isPal = false;
|
||||
swaps = {};
|
||||
}
|
||||
|
||||
u32 VI::Read(u32 paddr) const {
|
||||
|
||||
@@ -20,6 +20,29 @@ void Cop0::Reset() {
|
||||
wired = 0;
|
||||
index.raw = 63;
|
||||
badVaddr = 0xFFFFFFFFFFFFFFFF;
|
||||
|
||||
kernelMode = {true};
|
||||
supervisorMode = {false};
|
||||
userMode = {false};
|
||||
is64BitAddressing = {false};
|
||||
llbit = {};
|
||||
|
||||
pageMask = {};
|
||||
entryHi = {};
|
||||
entryLo0 = {}, entryLo1 = {};
|
||||
context = {};
|
||||
wired = {}, r7 = {};
|
||||
count = {};
|
||||
compare = {};
|
||||
LLAddr = {}, WatchLo = {}, WatchHi = {};
|
||||
xcontext = {};
|
||||
r21 = {}, r22 = {}, r23 = {}, r24 = {}, r25 = {};
|
||||
ParityError = {}, CacheError = {}, TagLo = {}, TagHi = {};
|
||||
ErrorEPC = {};
|
||||
r31 = {};
|
||||
memset(tlb, 0, sizeof(TLBEntry)*32);
|
||||
tlbError = NONE;
|
||||
openbus = {};
|
||||
}
|
||||
|
||||
u32 Cop0::GetReg32(u8 addr) {
|
||||
|
||||
@@ -43,10 +43,10 @@ void Cop1::decodeInterp(Interpreter &cpu, u32 instr) {
|
||||
case 0x07: unimplemented(); break;
|
||||
case 0x08:
|
||||
switch(mask_branch) {
|
||||
case 0: CheckFPUUsable(); cpu.b(instr, !fcr31.compare); break;
|
||||
case 1: CheckFPUUsable(); cpu.b(instr, fcr31.compare); break;
|
||||
case 2: CheckFPUUsable(); cpu.bl(instr, !fcr31.compare); break;
|
||||
case 3: CheckFPUUsable(); cpu.bl(instr, fcr31.compare); break;
|
||||
case 0: if(!CheckFPUUsable()) return; cpu.b(instr, !fcr31.compare); break;
|
||||
case 1: if(!CheckFPUUsable()) return; cpu.b(instr, fcr31.compare); break;
|
||||
case 2: if(!CheckFPUUsable()) return; cpu.bl(instr, !fcr31.compare); break;
|
||||
case 3: if(!CheckFPUUsable()) return; cpu.bl(instr, fcr31.compare); break;
|
||||
default: Util::panic("Undefined BC COP1 {:02X}", mask_branch);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -9,46 +9,78 @@ union FCR31 {
|
||||
FCR31() = default;
|
||||
struct {
|
||||
unsigned rounding_mode:2;
|
||||
unsigned flag_inexact_operation:1;
|
||||
unsigned flag_underflow:1;
|
||||
unsigned flag_overflow:1;
|
||||
unsigned flag_division_by_zero:1;
|
||||
unsigned flag_invalid_operation:1;
|
||||
unsigned enable_inexact_operation:1;
|
||||
unsigned enable_underflow:1;
|
||||
unsigned enable_overflow:1;
|
||||
unsigned enable_division_by_zero:1;
|
||||
unsigned enable_invalid_operation:1;
|
||||
unsigned cause_inexact_operation:1;
|
||||
unsigned cause_underflow:1;
|
||||
unsigned cause_overflow:1;
|
||||
unsigned cause_division_by_zero:1;
|
||||
unsigned cause_invalid_operation:1;
|
||||
unsigned cause_unimplemented_operation:1;
|
||||
struct {
|
||||
unsigned inexact_operation:1;
|
||||
unsigned underflow:1;
|
||||
unsigned overflow:1;
|
||||
unsigned division_by_zero:1;
|
||||
unsigned invalid_operation:1;
|
||||
} flag;
|
||||
struct {
|
||||
unsigned inexact_operation:1;
|
||||
unsigned underflow:1;
|
||||
unsigned overflow:1;
|
||||
unsigned division_by_zero:1;
|
||||
unsigned invalid_operation:1;
|
||||
} enable;
|
||||
struct {
|
||||
unsigned inexact_operation:1;
|
||||
unsigned underflow:1;
|
||||
unsigned overflow:1;
|
||||
unsigned division_by_zero:1;
|
||||
unsigned invalid_operation:1;
|
||||
unsigned unimplemented_operation:1;
|
||||
} cause;
|
||||
unsigned:5;
|
||||
unsigned compare:1;
|
||||
unsigned fs:1;
|
||||
unsigned:7;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct {
|
||||
unsigned:2;
|
||||
unsigned flag:5;
|
||||
unsigned enable:5;
|
||||
unsigned cause:6;
|
||||
unsigned:14;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
[[nodiscard]] u32 read() const {
|
||||
return (fs << 24) | (compare << 23) | (cause << 12) | (enable << 7) | (flag << 2) | rounding_mode;
|
||||
u32 ret = 0;
|
||||
ret |= (u32(fs) << 24);
|
||||
ret |= (u32(compare) << 23);
|
||||
ret |= (u32(cause.unimplemented_operation) << 17);
|
||||
ret |= (u32(cause.invalid_operation) << 16);
|
||||
ret |= (u32(cause.division_by_zero) << 15);
|
||||
ret |= (u32(cause.overflow) << 14);
|
||||
ret |= (u32(cause.underflow) << 13);
|
||||
ret |= (u32(cause.inexact_operation) << 12);
|
||||
ret |= (u32(enable.invalid_operation) << 11);
|
||||
ret |= (u32(enable.division_by_zero) << 10);
|
||||
ret |= (u32(enable.overflow) << 9);
|
||||
ret |= (u32(enable.underflow) << 8);
|
||||
ret |= (u32(enable.inexact_operation) << 7);
|
||||
ret |= (u32(flag.invalid_operation) << 6);
|
||||
ret |= (u32(flag.division_by_zero) << 5);
|
||||
ret |= (u32(flag.overflow) << 4);
|
||||
ret |= (u32(flag.underflow) << 3);
|
||||
ret |= (u32(flag.inexact_operation) << 2);
|
||||
ret |= (u32(rounding_mode) & 3);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void write(u32 val) {
|
||||
fs = (val & 0x01000000) >> 24;
|
||||
compare = (val & 0x00800000) >> 23;
|
||||
cause = (val & 0x0003f000) >> 12;
|
||||
enable = (val & 0x00000f80) >> 7;
|
||||
flag = (val & 0x0000007c) >> 2;
|
||||
fs = val >> 24;
|
||||
compare = val >> 23;
|
||||
cause.unimplemented_operation = val >> 17;
|
||||
cause.invalid_operation = val >> 16;
|
||||
cause.division_by_zero = val >> 15;
|
||||
cause.overflow = val >> 14;
|
||||
cause.underflow = val >> 13;
|
||||
cause.inexact_operation = val >> 12;
|
||||
enable.invalid_operation = val >> 11;
|
||||
enable.division_by_zero = val >> 10;
|
||||
enable.overflow = val >> 9;
|
||||
enable.underflow = val >> 8;
|
||||
enable.inexact_operation = val >> 7;
|
||||
flag.invalid_operation = val >> 6;
|
||||
flag.division_by_zero = val >> 5;
|
||||
flag.overflow = val >> 4;
|
||||
flag.underflow = val >> 3;
|
||||
flag.inexact_operation = val >> 2;
|
||||
rounding_mode = val & 3;
|
||||
}
|
||||
};
|
||||
@@ -89,38 +121,50 @@ struct JIT;
|
||||
struct Registers;
|
||||
|
||||
struct Cop1 {
|
||||
#define CheckFPUUsable_PreserveCause() do { if(!regs.cop0.status.cu1) { regs.cop0.FireException(ExceptionCode::CoprocessorUnusable, 1, regs.oldPC); return; } } while(0)
|
||||
#define CheckFPUUsable() do { CheckFPUUsable_PreserveCause(); fcr31.cause = 0; } while(0)
|
||||
Cop1(Registers&);
|
||||
explicit Cop1(Registers&);
|
||||
u32 fcr0{};
|
||||
FCR31 fcr31{};
|
||||
FloatingPointReg fgr[32]{};
|
||||
|
||||
void Reset();
|
||||
template <class T> // either JIT or Interpreter
|
||||
void decode(T&, u32);
|
||||
friend struct Interpreter;
|
||||
|
||||
bool FireException();
|
||||
template <bool preserveCause = false>
|
||||
bool CheckFPUUsable();
|
||||
template <typename T>
|
||||
bool CheckResult(T&);
|
||||
template <typename T>
|
||||
bool CheckArg(T&);
|
||||
template <typename T>
|
||||
bool CheckArgs(T&, T&);
|
||||
template <typename T>
|
||||
bool isqnan(T);
|
||||
|
||||
template<typename T, bool quiet, bool cf>
|
||||
bool XORDERED(T fs, T ft);
|
||||
|
||||
template <typename T>
|
||||
void SetCauseOnResult(T& d);
|
||||
bool CheckCVTArg(float &f);
|
||||
template <typename T>
|
||||
void SetCauseByArg(T f);
|
||||
template <typename T>
|
||||
void SetCauseByArgLCVT(T f);
|
||||
template <typename T>
|
||||
void SetCauseByArgWCVT(T f);
|
||||
void SetCauseRaised(int);
|
||||
void SetCauseRaisedCVT(int);
|
||||
bool CheckCVTArg(double &f);
|
||||
|
||||
template <bool cvt = false>
|
||||
bool TestExceptions();
|
||||
void SetCauseUnimplemented();
|
||||
void SetCauseUnderflow();
|
||||
void SetCauseInexact();
|
||||
void SetCauseDivisionByZero();
|
||||
void SetCauseOverflow();
|
||||
void SetCauseInvalid();
|
||||
bool SetCauseUnderflow();
|
||||
bool SetCauseInexact();
|
||||
bool SetCauseDivisionByZero();
|
||||
bool SetCauseOverflow();
|
||||
bool SetCauseInvalid();
|
||||
private:
|
||||
template <typename T>
|
||||
auto FGR(Cop0Status&, u32) -> T&;
|
||||
auto FGR_T(Cop0Status&, u32) -> T&;
|
||||
template <typename T>
|
||||
auto FGR_S(Cop0Status&, u32) -> T&;
|
||||
template <typename T>
|
||||
auto FGR_D(Cop0Status&, u32) -> T&;
|
||||
void decodeInterp(Interpreter&, u32);
|
||||
void decodeJIT(JIT&, u32);
|
||||
void absd(u32 instr);
|
||||
@@ -133,7 +177,7 @@ private:
|
||||
void ceilws(u32 instr);
|
||||
void ceilld(u32 instr);
|
||||
void ceilwd(u32 instr);
|
||||
void cfc1(u32 instr) const;
|
||||
void cfc1(u32 instr);
|
||||
void ctc1(u32 instr);
|
||||
void unimplemented();
|
||||
void roundls(u32 instr);
|
||||
|
||||
@@ -11,6 +11,12 @@ void Registers::Reset() {
|
||||
delaySlot = false;
|
||||
prevDelaySlot = false;
|
||||
memset(gpr, 0, 32*sizeof(s64));
|
||||
|
||||
cop0.Reset();
|
||||
cop1.Reset();
|
||||
|
||||
steps = 0;
|
||||
extraCycles = 0;
|
||||
}
|
||||
|
||||
void Registers::SetPC64(s64 val) {
|
||||
@@ -24,4 +30,80 @@ void Registers::SetPC32(s32 val) {
|
||||
pc = s64(val);
|
||||
nextPC = pc + 4;
|
||||
}
|
||||
|
||||
template <> u64 Registers::Read<u64>(size_t idx) {
|
||||
return idx == 0 ? 0 : gpr[idx];
|
||||
}
|
||||
|
||||
template <> s64 Registers::Read<s64>(size_t idx) {
|
||||
return s64(Read<u64>(idx));
|
||||
}
|
||||
|
||||
template <> u32 Registers::Read<u32>(size_t idx) {
|
||||
return idx == 0 ? 0 : gpr[idx];
|
||||
}
|
||||
|
||||
template <> s32 Registers::Read<s32>(size_t idx) {
|
||||
return s32(Read<u32>(idx));
|
||||
}
|
||||
|
||||
template <> u16 Registers::Read<u16>(size_t idx) {
|
||||
return idx == 0 ? 0 : gpr[idx];
|
||||
}
|
||||
|
||||
template <> s16 Registers::Read<s16>(size_t idx) {
|
||||
return s16(Read<u16>(idx));
|
||||
}
|
||||
|
||||
template <> u8 Registers::Read<u8>(size_t idx) {
|
||||
return idx == 0 ? 0 : gpr[idx];
|
||||
}
|
||||
|
||||
template <> s8 Registers::Read<s8>(size_t idx) {
|
||||
return s8(Read<u8>(idx));
|
||||
}
|
||||
|
||||
template <> void Registers::Write<bool>(size_t idx, bool v) {
|
||||
if(idx == 0) return;
|
||||
gpr[idx] = v;
|
||||
}
|
||||
|
||||
template <> void Registers::Write<u64>(size_t idx, u64 v) {
|
||||
if(idx == 0) return;
|
||||
gpr[idx] = v;
|
||||
}
|
||||
|
||||
template <> void Registers::Write<s64>(size_t idx, s64 v) {
|
||||
Write<u64>(idx, v);
|
||||
}
|
||||
|
||||
template <> void Registers::Write<u32>(size_t idx, u32 v) {
|
||||
if(idx == 0) return;
|
||||
gpr[idx] = (u32)v;
|
||||
}
|
||||
|
||||
template <> void Registers::Write<s32>(size_t idx, s32 v) {
|
||||
if(idx == 0) return;
|
||||
gpr[idx] = v;
|
||||
}
|
||||
|
||||
template <> void Registers::Write<u16>(size_t idx, u16 v) {
|
||||
if(idx == 0) return;
|
||||
gpr[idx] = (u16)v;
|
||||
}
|
||||
|
||||
template <> void Registers::Write<s16>(size_t idx, s16 v) {
|
||||
if(idx == 0) return;
|
||||
gpr[idx] = v;
|
||||
}
|
||||
|
||||
template <> void Registers::Write<u8>(size_t idx, u8 v) {
|
||||
if(idx == 0) return;
|
||||
gpr[idx] = (u8)v;
|
||||
}
|
||||
|
||||
template <> void Registers::Write<s8>(size_t idx, s8 v) {
|
||||
if(idx == 0) return;
|
||||
gpr[idx] = v;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ struct Registers {
|
||||
return IsRegConstant(first) && IsRegConstant(second);
|
||||
}
|
||||
|
||||
s64 gpr[32]{};
|
||||
bool gprIsConstant[32]{};
|
||||
bool loIsConstant = false, hiIsConstant = false;
|
||||
Cop0 cop0;
|
||||
@@ -37,5 +36,12 @@ struct Registers {
|
||||
extraCycles = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T Read(size_t);
|
||||
template <typename T>
|
||||
void Write(size_t, T);
|
||||
private:
|
||||
s64 gpr[32]{};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@
|
||||
|
||||
namespace n64 {
|
||||
void Cop0::mtc0(u32 instr) {
|
||||
SetReg32(RD(instr), regs.gpr[RT(instr)]);
|
||||
SetReg32(RD(instr), regs.Read<u32>(RT(instr)));
|
||||
}
|
||||
|
||||
void Cop0::dmtc0(u32 instr) {
|
||||
SetReg64(RD(instr), regs.gpr[RT(instr)]);
|
||||
SetReg64(RD(instr), regs.Read<u64>(RT(instr)));
|
||||
}
|
||||
|
||||
void Cop0::mfc0(u32 instr) {
|
||||
regs.gpr[RT(instr)] = s32(GetReg32(RD(instr)));
|
||||
regs.Write(RT(instr), s32(GetReg32(RD(instr))));
|
||||
}
|
||||
|
||||
void Cop0::dmfc0(u32 instr) const {
|
||||
regs.gpr[RT(instr)] = s64(GetReg64(RD(instr)));
|
||||
regs.Write(RT(instr), s64(GetReg64(RD(instr))));
|
||||
}
|
||||
|
||||
void Cop0::eret() {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,6 @@
|
||||
#include <core/RSP.hpp>
|
||||
#include <log.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
#include <Interrupt.hpp>
|
||||
#include <Mem.hpp>
|
||||
|
||||
namespace n64 {
|
||||
|
||||
@@ -60,11 +60,11 @@ FORCE_INLINE void SetCop0Reg(Registers& regs, Mem& mem, u8 index, u32 val) {
|
||||
case 1: rsp.spDMADRAMAddr.raw = val; break;
|
||||
case 2:
|
||||
rsp.spDMALen.raw = val;
|
||||
rsp.DMAtoRSP(mem.GetRDRAM());
|
||||
rsp.DMA<false>();
|
||||
break;
|
||||
case 3:
|
||||
rsp.spDMALen.raw = val;
|
||||
rsp.DMAtoRDRAM(mem.GetRDRAM());
|
||||
rsp.DMA<true>();
|
||||
break;
|
||||
case 4: rsp.WriteStatus(val); break;
|
||||
case 7:
|
||||
|
||||
@@ -28,7 +28,6 @@ include_directories(
|
||||
../../external/parallel-rdp/parallel-rdp-standalone/vulkan
|
||||
../../external/parallel-rdp/parallel-rdp-standalone/vulkan-headers/include
|
||||
../../external/parallel-rdp/parallel-rdp-standalone/util
|
||||
../../external/nativefiledialog-extended/src/include
|
||||
../../external/imgui/imgui
|
||||
../../external/imgui/imgui/backends
|
||||
../../external/unarr
|
||||
@@ -43,7 +42,6 @@ add_subdirectory(../../external/json json)
|
||||
add_subdirectory(../../external/fmt fmt)
|
||||
add_subdirectory(../../external/mio mio)
|
||||
add_subdirectory(../backend backend)
|
||||
add_subdirectory(../../external/nativefiledialog-extended nfd)
|
||||
add_subdirectory(../../external/parallel-rdp parallel-rdp)
|
||||
add_subdirectory(../../external/unarr unarr)
|
||||
|
||||
@@ -72,7 +70,7 @@ add_executable(kaizen-qt
|
||||
InputSettings.hpp
|
||||
InputSettings.cpp)
|
||||
|
||||
target_link_libraries(kaizen-qt PUBLIC Qt6::Core Qt6::Gui Qt6::Widgets fmt mio nlohmann_json nfd parallel-rdp backend)
|
||||
target_link_libraries(kaizen-qt PUBLIC Qt6::Core Qt6::Gui Qt6::Widgets fmt mio nlohmann_json parallel-rdp backend)
|
||||
target_compile_definitions(kaizen-qt PUBLIC SDL_MAIN_HANDLED)
|
||||
|
||||
file(COPY ../../resources/ DESTINATION ${PROJECT_BINARY_DIR}/resources/)
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
#include <EmuThread.hpp>
|
||||
#include <RenderWidget.hpp>
|
||||
#include <ParallelRDPWrapper.hpp>
|
||||
#include "Audio.hpp"
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
EmuThread::EmuThread(std::unique_ptr<QtInstanceFactory>&& instance_, std::unique_ptr<Vulkan::WSIPlatform>&& wsiPlatform_, std::unique_ptr<ParallelRDP::WindowInfo>&& windowInfo_, SettingsWindow& settings) noexcept
|
||||
: instance(std::move(instance_)), wsiPlatform(std::move(wsiPlatform_)),
|
||||
windowInfo(std::move(windowInfo_)),
|
||||
controller(SDL_GameControllerClose, "GameController"),
|
||||
EmuThread::EmuThread(const std::shared_ptr<QtInstanceFactory>& instance_, const std::shared_ptr<Vulkan::WSIPlatform>& wsiPlatform_, const std::shared_ptr<ParallelRDP::WindowInfo>& windowInfo_, SettingsWindow& settings) noexcept
|
||||
: instance(instance_), wsiPlatform(wsiPlatform_),
|
||||
windowInfo(windowInfo_),
|
||||
core(parallel), settings(settings) {}
|
||||
|
||||
[[noreturn]] void EmuThread::run() noexcept {
|
||||
parallel.Init(instance.get(), std::move(wsiPlatform), std::move(windowInfo), core.cpu->GetMem().GetRDRAMPtr());
|
||||
parallel.Init(instance, wsiPlatform, windowInfo, core.cpu->GetMem().GetRDRAMPtr());
|
||||
SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER);
|
||||
bool controllerConnected = false;
|
||||
|
||||
@@ -25,11 +21,11 @@ EmuThread::EmuThread(std::unique_ptr<QtInstanceFactory>&& instance_, std::unique
|
||||
switch(e.type) {
|
||||
case SDL_CONTROLLERDEVICEADDED: {
|
||||
const int index = e.cdevice.which;
|
||||
controller.Construct(SDL_GameControllerOpen, index);
|
||||
controller = SDL_GameControllerOpen(index);
|
||||
Util::info("Found controller!");
|
||||
auto serial = SDL_GameControllerGetSerial(controller.get());
|
||||
auto name = SDL_GameControllerName(controller.get());
|
||||
auto path = SDL_GameControllerPath(controller.get());
|
||||
auto serial = SDL_GameControllerGetSerial(controller);
|
||||
auto name = SDL_GameControllerName(controller);
|
||||
auto path = SDL_GameControllerPath(controller);
|
||||
Util::info("\tName: {}", name ? name : "Not available");
|
||||
Util::info("\tSerial: {}", serial ? serial : "Not available");
|
||||
Util::info("\tPath: {}", path ? path : "Not available");
|
||||
@@ -37,7 +33,7 @@ EmuThread::EmuThread(std::unique_ptr<QtInstanceFactory>&& instance_, std::unique
|
||||
} break;
|
||||
case SDL_CONTROLLERDEVICEREMOVED: {
|
||||
controllerConnected = false;
|
||||
controller.Destroy();
|
||||
SDL_GameControllerClose(controller);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
@@ -59,22 +55,22 @@ EmuThread::EmuThread(std::unique_ptr<QtInstanceFactory>&& instance_, std::unique
|
||||
|
||||
if(controllerConnected) {
|
||||
n64::PIF& pif = core.cpu->GetMem().mmio.si.pif;
|
||||
pif.UpdateButton(0, n64::Controller::Key::A, SDL_GameControllerGetButton(controller.get(), SDL_CONTROLLER_BUTTON_A));
|
||||
pif.UpdateButton(0, n64::Controller::Key::B, SDL_GameControllerGetButton(controller.get(), SDL_CONTROLLER_BUTTON_X));
|
||||
pif.UpdateButton(0, n64::Controller::Key::Z, SDL_GameControllerGetAxis(controller.get(), SDL_CONTROLLER_AXIS_TRIGGERLEFT) == SDL_JOYSTICK_AXIS_MAX);
|
||||
pif.UpdateButton(0, n64::Controller::Key::Start, SDL_GameControllerGetButton(controller.get(), SDL_CONTROLLER_BUTTON_START));
|
||||
pif.UpdateButton(0, n64::Controller::Key::DUp, SDL_GameControllerGetButton(controller.get(), SDL_CONTROLLER_BUTTON_DPAD_UP));
|
||||
pif.UpdateButton(0, n64::Controller::Key::DDown, SDL_GameControllerGetButton(controller.get(), SDL_CONTROLLER_BUTTON_DPAD_DOWN));
|
||||
pif.UpdateButton(0, n64::Controller::Key::DLeft, SDL_GameControllerGetButton(controller.get(), SDL_CONTROLLER_BUTTON_DPAD_LEFT));
|
||||
pif.UpdateButton(0, n64::Controller::Key::DRight, SDL_GameControllerGetButton(controller.get(), SDL_CONTROLLER_BUTTON_DPAD_RIGHT));
|
||||
pif.UpdateButton(0, n64::Controller::Key::LT, SDL_GameControllerGetButton(controller.get(), SDL_CONTROLLER_BUTTON_LEFTSHOULDER));
|
||||
pif.UpdateButton(0, n64::Controller::Key::RT, SDL_GameControllerGetButton(controller.get(), SDL_CONTROLLER_BUTTON_RIGHTSHOULDER));
|
||||
pif.UpdateButton(0, n64::Controller::Key::CUp, SDL_GameControllerGetAxis(controller.get(), SDL_CONTROLLER_AXIS_RIGHTY) <= -127);
|
||||
pif.UpdateButton(0, n64::Controller::Key::CDown, SDL_GameControllerGetAxis(controller.get(), SDL_CONTROLLER_AXIS_RIGHTY) >= 127);
|
||||
pif.UpdateButton(0, n64::Controller::Key::CLeft, SDL_GameControllerGetAxis(controller.get(), SDL_CONTROLLER_AXIS_RIGHTX) <= -127);
|
||||
pif.UpdateButton(0, n64::Controller::Key::CRight, SDL_GameControllerGetAxis(controller.get(), SDL_CONTROLLER_AXIS_RIGHTX) >= 127);
|
||||
pif.UpdateButton(0, n64::Controller::Key::A, SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_A));
|
||||
pif.UpdateButton(0, n64::Controller::Key::B, SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_X));
|
||||
pif.UpdateButton(0, n64::Controller::Key::Z, SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) == SDL_JOYSTICK_AXIS_MAX);
|
||||
pif.UpdateButton(0, n64::Controller::Key::Start, SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_START));
|
||||
pif.UpdateButton(0, n64::Controller::Key::DUp, SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_UP));
|
||||
pif.UpdateButton(0, n64::Controller::Key::DDown, SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_DOWN));
|
||||
pif.UpdateButton(0, n64::Controller::Key::DLeft, SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_LEFT));
|
||||
pif.UpdateButton(0, n64::Controller::Key::DRight, SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_RIGHT));
|
||||
pif.UpdateButton(0, n64::Controller::Key::LT, SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_LEFTSHOULDER));
|
||||
pif.UpdateButton(0, n64::Controller::Key::RT, SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER));
|
||||
pif.UpdateButton(0, n64::Controller::Key::CUp, SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY) <= -127);
|
||||
pif.UpdateButton(0, n64::Controller::Key::CDown, SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY) >= 127);
|
||||
pif.UpdateButton(0, n64::Controller::Key::CLeft, SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX) <= -127);
|
||||
pif.UpdateButton(0, n64::Controller::Key::CRight, SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX) >= 127);
|
||||
|
||||
float xclamped = SDL_GameControllerGetAxis(controller.get(), SDL_CONTROLLER_AXIS_LEFTX);
|
||||
float xclamped = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
|
||||
if(xclamped < 0) {
|
||||
xclamped /= float(std::abs(SDL_JOYSTICK_AXIS_MIN));
|
||||
} else {
|
||||
@@ -83,7 +79,7 @@ EmuThread::EmuThread(std::unique_ptr<QtInstanceFactory>&& instance_, std::unique
|
||||
|
||||
xclamped *= 86;
|
||||
|
||||
float yclamped = SDL_GameControllerGetAxis(controller.get(), SDL_CONTROLLER_AXIS_LEFTY);
|
||||
float yclamped = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
|
||||
if(yclamped < 0) {
|
||||
yclamped /= float(std::abs(SDL_JOYSTICK_AXIS_MIN));
|
||||
} else {
|
||||
|
||||
@@ -9,37 +9,37 @@
|
||||
class EmuThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
std::unique_ptr<QtInstanceFactory> instance;
|
||||
std::unique_ptr<Vulkan::WSIPlatform> wsiPlatform;
|
||||
std::unique_ptr<ParallelRDP::WindowInfo> windowInfo;
|
||||
std::shared_ptr<QtInstanceFactory> instance;
|
||||
std::shared_ptr<Vulkan::WSIPlatform> wsiPlatform;
|
||||
std::shared_ptr<ParallelRDP::WindowInfo> windowInfo;
|
||||
public:
|
||||
explicit EmuThread(std::unique_ptr<QtInstanceFactory>&& instance, std::unique_ptr<Vulkan::WSIPlatform>&& wsiPlatform, std::unique_ptr<ParallelRDP::WindowInfo>&& windowInfo, SettingsWindow&) noexcept;
|
||||
explicit EmuThread(const std::shared_ptr<QtInstanceFactory>& instance, const std::shared_ptr<Vulkan::WSIPlatform>& wsiPlatform, const std::shared_ptr<ParallelRDP::WindowInfo>& windowInfo, SettingsWindow&) noexcept;
|
||||
|
||||
[[noreturn]] void run() noexcept override;
|
||||
|
||||
Util::AutoRelease<SDL_GameController, int> controller;
|
||||
SDL_GameController* controller = nullptr;
|
||||
ParallelRDP parallel;
|
||||
n64::Core core;
|
||||
SettingsWindow& settings;
|
||||
bool running = false;
|
||||
|
||||
void TogglePause()
|
||||
{
|
||||
running = !running;
|
||||
void TogglePause() {
|
||||
core.pause = !core.pause;
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
running = false;
|
||||
void SetRender(bool v) {
|
||||
core.render = v;
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
core.pause = true;
|
||||
core.Stop();
|
||||
core.LoadROM(core.rom);
|
||||
running = true;
|
||||
core.pause = false;
|
||||
}
|
||||
|
||||
void Stop()
|
||||
{
|
||||
void Stop() {
|
||||
core.rom = {};
|
||||
running = false;
|
||||
core.pause = true;
|
||||
core.Stop();
|
||||
}
|
||||
};
|
||||
@@ -28,16 +28,18 @@ KaizenQt::KaizenQt() noexcept : QWidget(nullptr) {
|
||||
grabKeyboard();
|
||||
});
|
||||
}
|
||||
|
||||
void KaizenQt::ConnectMainWindowSignalsToSlots() noexcept {
|
||||
connect(mainWindow.get(), &MainWindowController::OpenSettings, this, [this]() {
|
||||
settingsWindow->show();
|
||||
});
|
||||
connect(mainWindow.get(), &MainWindowController::OpenROM, this, &KaizenQt::LoadROM);
|
||||
connect(mainWindow.get(), &MainWindowController::Exit, this, []() {
|
||||
QApplication::quit();
|
||||
});
|
||||
connect(mainWindow.get(), &MainWindowController::Exit, this, &KaizenQt::Quit);
|
||||
connect(mainWindow.get(), &MainWindowController::Reset, emuThread.get(), &EmuThread::Reset);
|
||||
connect(mainWindow.get(), &MainWindowController::Stop, emuThread.get(), &EmuThread::Stop);
|
||||
connect(mainWindow.get(), &MainWindowController::Stop, this, [this]() {
|
||||
mainWindow->setWindowTitle("Kaizen");
|
||||
});
|
||||
connect(mainWindow.get(), &MainWindowController::Pause, emuThread.get(), &EmuThread::TogglePause);
|
||||
}
|
||||
|
||||
@@ -53,64 +55,70 @@ void KaizenQt::dropEvent(QDropEvent* event) {
|
||||
}
|
||||
|
||||
void KaizenQt::LoadROM(const QString& fileName) noexcept {
|
||||
mainWindow->view.actionPause->setEnabled(true);
|
||||
mainWindow->view.actionReset->setEnabled(true);
|
||||
mainWindow->view.actionStop->setEnabled(true);
|
||||
emuThread->start();
|
||||
emuThread->core.LoadROM(fileName.toStdString());
|
||||
mainWindow->setWindowTitle(emuThread->core.cpu->GetMem().rom.gameNameDB.c_str());
|
||||
}
|
||||
|
||||
void KaizenQt::closeEvent(QCloseEvent*) {
|
||||
void KaizenQt::Quit() noexcept {
|
||||
if(emuThread) {
|
||||
emuThread->SetRender(false);
|
||||
emuThread->Stop();
|
||||
}
|
||||
QApplication::quit();
|
||||
}
|
||||
|
||||
void KaizenQt::LoadTAS(const QString& fileName) noexcept {
|
||||
emuThread->core.LoadTAS(fileName.toStdString());
|
||||
void KaizenQt::LoadTAS(const QString& fileName) const noexcept {
|
||||
emuThread->core.LoadTAS(fs::path(fileName.toStdString()));
|
||||
}
|
||||
|
||||
void KaizenQt::keyPressEvent(QKeyEvent *e) {
|
||||
emuThread->core.pause = true;
|
||||
n64::Mem& mem = emuThread->core.cpu->GetMem();
|
||||
n64::PIF& pif = mem.mmio.si.pif;
|
||||
|
||||
auto k = static_cast<Qt::Key>(e->key());
|
||||
if(k == settingsWindow->keyMap[0]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::A, true);
|
||||
if(k == settingsWindow->keyMap[1]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::B, true);
|
||||
if(k == settingsWindow->keyMap[2]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::Z, true);
|
||||
if(k == settingsWindow->keyMap[3]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::Start, true);
|
||||
if(k == settingsWindow->keyMap[4]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::LT, true);
|
||||
if(k == settingsWindow->keyMap[5]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::RT, true);
|
||||
if(k == settingsWindow->keyMap[6]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::DUp, true);
|
||||
if(k == settingsWindow->keyMap[7]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::DDown, true);
|
||||
if(k == settingsWindow->keyMap[8]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::DLeft, true);
|
||||
if(k == settingsWindow->keyMap[9]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::DRight, true);
|
||||
if(k == settingsWindow->keyMap[10]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::CUp, true);
|
||||
if(k == settingsWindow->keyMap[11]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::CDown, true);
|
||||
if(k == settingsWindow->keyMap[12]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::CLeft, true);
|
||||
if(k == settingsWindow->keyMap[13]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::CRight, true);
|
||||
if(k == settingsWindow->keyMap[14]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateAxis(0, n64::Controller::Axis::Y, 86);
|
||||
if(k == settingsWindow->keyMap[15]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateAxis(0, n64::Controller::Axis::Y, -86);
|
||||
if(k == settingsWindow->keyMap[16]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateAxis(0, n64::Controller::Axis::X, -86);
|
||||
if(k == settingsWindow->keyMap[17]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateAxis(0, n64::Controller::Axis::X, 86);
|
||||
for(int i = 0; i < 14; i++) {
|
||||
if(k == settingsWindow->keyMap[i])
|
||||
pif.UpdateButton(0, static_cast<n64::Controller::Key>(i), true);
|
||||
}
|
||||
|
||||
if (k == settingsWindow->keyMap[14])
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::Y, 86);
|
||||
if (k == settingsWindow->keyMap[15])
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::Y, -86);
|
||||
if (k == settingsWindow->keyMap[16])
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::X, -86);
|
||||
if (k == settingsWindow->keyMap[17])
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::X, 86);
|
||||
|
||||
emuThread->core.pause = false;
|
||||
QWidget::keyPressEvent(e);
|
||||
}
|
||||
|
||||
void KaizenQt::keyReleaseEvent(QKeyEvent *e) {
|
||||
emuThread->core.pause = true;
|
||||
n64::Mem& mem = emuThread->core.cpu->GetMem();
|
||||
n64::PIF& pif = mem.mmio.si.pif;
|
||||
|
||||
auto k = static_cast<Qt::Key>(e->key());
|
||||
if (k == settingsWindow->keyMap[0]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::A, false);
|
||||
if (k == settingsWindow->keyMap[1]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::B, false);
|
||||
if (k == settingsWindow->keyMap[2]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::Z, false);
|
||||
if (k == settingsWindow->keyMap[3]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::Start, false);
|
||||
if (k == settingsWindow->keyMap[4]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::LT, false);
|
||||
if (k == settingsWindow->keyMap[5]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::RT, false);
|
||||
if (k == settingsWindow->keyMap[6]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::DUp, false);
|
||||
if (k == settingsWindow->keyMap[7]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::DDown, false);
|
||||
if (k == settingsWindow->keyMap[8]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::DLeft, false);
|
||||
if (k == settingsWindow->keyMap[9]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::DRight, false);
|
||||
if (k == settingsWindow->keyMap[10]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::CUp, false);
|
||||
if (k == settingsWindow->keyMap[11]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::CDown, false);
|
||||
if (k == settingsWindow->keyMap[12]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::CLeft, false);
|
||||
if (k == settingsWindow->keyMap[13]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateButton(0, n64::Controller::Key::CRight, false);
|
||||
if (k == settingsWindow->keyMap[14]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateAxis(0, n64::Controller::Axis::Y, 0);
|
||||
if (k == settingsWindow->keyMap[15]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateAxis(0, n64::Controller::Axis::Y, 0);
|
||||
if (k == settingsWindow->keyMap[16]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateAxis(0, n64::Controller::Axis::X, 0);
|
||||
if (k == settingsWindow->keyMap[17]) emuThread->core.cpu->GetMem().mmio.si.pif.UpdateAxis(0, n64::Controller::Axis::X, 0);
|
||||
emuThread->core.pause = false;
|
||||
QWidget::keyPressEvent(e);
|
||||
for(int i = 0; i < 14; i++) {
|
||||
if(k == settingsWindow->keyMap[i])
|
||||
pif.UpdateButton(0, static_cast<n64::Controller::Key>(i), false);
|
||||
}
|
||||
|
||||
if (k == settingsWindow->keyMap[14])
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::Y, 0);
|
||||
if (k == settingsWindow->keyMap[15])
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::Y, 0);
|
||||
if (k == settingsWindow->keyMap[16])
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::X, 0);
|
||||
if (k == settingsWindow->keyMap[17])
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::X, 0);
|
||||
|
||||
emuThread->core.pause = false;
|
||||
QWidget::keyReleaseEvent(e);
|
||||
}
|
||||
@@ -27,14 +27,14 @@ class KaizenQt : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
KaizenQt() noexcept;
|
||||
void LoadTAS(const QString& path) noexcept;
|
||||
void LoadTAS(const QString& path) const noexcept;
|
||||
void LoadROM(const QString& path) noexcept;
|
||||
void dropEvent(QDropEvent*) override;
|
||||
void dragEnterEvent(QDragEnterEvent*) override;
|
||||
void keyPressEvent(QKeyEvent*) override;
|
||||
void keyReleaseEvent(QKeyEvent*) override;
|
||||
void closeEvent(QCloseEvent*) override;
|
||||
private:
|
||||
void Quit() noexcept;
|
||||
void ConnectMainWindowSignalsToSlots() noexcept;
|
||||
std::unique_ptr<MainWindowController> mainWindow;
|
||||
std::unique_ptr<SettingsWindow> settingsWindow;
|
||||
|
||||
@@ -19,9 +19,6 @@ void MainWindowController::ConnectSignalsToSlots() noexcept {
|
||||
"All supported types (*.zip *.ZIP *.7z *.7Z *.rar *.RAR *.tar *.TAR *.n64 *.N64 *.v64 *.V64 *.z64 *.Z64)");
|
||||
|
||||
if (!file_name.isEmpty()) {
|
||||
view.actionPause->setEnabled(true);
|
||||
view.actionReset->setEnabled(true);
|
||||
view.actionStop->setEnabled(true);
|
||||
emit OpenROM(file_name);
|
||||
view.vulkanWidget->show();
|
||||
}
|
||||
@@ -31,6 +28,10 @@ void MainWindowController::ConnectSignalsToSlots() noexcept {
|
||||
emit Exit();
|
||||
});
|
||||
|
||||
connect(this, &MainWindowController::destroyed, this, [this]() {
|
||||
emit Exit();
|
||||
});
|
||||
|
||||
connect(view.actionReset, &QAction::triggered, this, [this]() {
|
||||
emit Reset();
|
||||
});
|
||||
|
||||
@@ -10,15 +10,17 @@ int main(int argc, char** argv) {
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(QCoreApplication::applicationName());
|
||||
parser.addHelpOption();
|
||||
parser.addPositionalArgument("rom", "Rom to launch from command-line");
|
||||
parser.addPositionalArgument("m64", "Mupen Movie to replay");
|
||||
parser.addOptions({
|
||||
{"rom", "Rom to launch from command-line", "path"},
|
||||
{"movie", "Mupen Movie to replay", "path"}
|
||||
});
|
||||
parser.process(app);
|
||||
|
||||
KaizenQt kaizenQt;
|
||||
if (parser.positionalArguments().size() > 0) {
|
||||
kaizenQt.LoadROM(parser.positionalArguments().first());
|
||||
if (parser.positionalArguments().size() > 1) {
|
||||
kaizenQt.LoadTAS(parser.positionalArguments()[1]);
|
||||
if (parser.isSet("rom")) {
|
||||
kaizenQt.LoadROM(parser.value("rom"));
|
||||
if (parser.isSet("movie")) {
|
||||
kaizenQt.LoadTAS(parser.value("movie"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
<height>646</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
||||
121
src/utils/FloatingPoint.hpp
Normal file
121
src/utils/FloatingPoint.hpp
Normal file
@@ -0,0 +1,121 @@
|
||||
//
|
||||
// Created by simone on 6/25/24.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
#include <cmath>
|
||||
#include <immintrin.h>
|
||||
|
||||
namespace Util {
|
||||
template <typename T>
|
||||
static inline T roundCeil(float f) {
|
||||
#ifdef SIMD_SUPPORT
|
||||
__m128 t = _mm_set_ss(f);
|
||||
t = _mm_round_ss(t, t, _MM_FROUND_TO_POS_INF);
|
||||
return _mm_cvtss_f32(t);
|
||||
#else
|
||||
return ceilf(f);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline T roundCeil(double f) {
|
||||
#ifdef SIMD_SUPPORT
|
||||
__m128d t = _mm_set_sd(f);
|
||||
t = _mm_round_sd(t, t, _MM_FROUND_TO_POS_INF);
|
||||
return _mm_cvtsd_f64(t);
|
||||
#else
|
||||
return ceil(f);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline T roundNearest(float f) {
|
||||
#ifdef SIMD_SUPPORT
|
||||
__m128 t = _mm_set_ss(f);
|
||||
t = _mm_round_ss(t, t, _MM_FROUND_TO_NEAREST_INT);
|
||||
return _mm_cvtss_f32(t);
|
||||
#else
|
||||
return roundf(f);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline T roundNearest(double f) {
|
||||
#ifdef SIMD_SUPPORT
|
||||
__m128d t = _mm_set_sd(f);
|
||||
t = _mm_round_sd(t, t, _MM_FROUND_TO_NEAREST_INT);
|
||||
return _mm_cvtsd_f64(t);
|
||||
#else
|
||||
return round(f);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline T roundCurrent(float f) {
|
||||
#ifdef SIMD_SUPPORT
|
||||
auto t = _mm_set_ss(f);
|
||||
t = _mm_round_ss(t, t, _MM_FROUND_CUR_DIRECTION);
|
||||
return _mm_cvtss_f32(t);
|
||||
#else
|
||||
return rint(f);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline T roundCurrent(double f) {
|
||||
#ifdef SIMD_SUPPORT
|
||||
auto t = _mm_set_sd(f);
|
||||
t = _mm_round_sd(t, t, _MM_FROUND_CUR_DIRECTION);
|
||||
return _mm_cvtsd_f64(t);
|
||||
#else
|
||||
return rint(f);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
static inline T roundFloor(float f) {
|
||||
#ifdef SIMD_SUPPORT
|
||||
__m128 t = _mm_set_ss(f);
|
||||
t = _mm_round_ss(t, t, _MM_FROUND_TO_NEG_INF);
|
||||
return _mm_cvtss_f32(t);
|
||||
#else
|
||||
return floor(f);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline T roundFloor(double f) {
|
||||
#ifdef SIMD_SUPPORT
|
||||
__m128d t = _mm_set_sd(f);
|
||||
t = _mm_round_sd(t, t, _MM_FROUND_TO_NEG_INF);
|
||||
return _mm_cvtsd_f64(t);
|
||||
#else
|
||||
return floor(f);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline T roundTrunc(float f) {
|
||||
#ifdef SIMD_SUPPORT
|
||||
__m128 t = _mm_set_ss(f);
|
||||
t = _mm_round_ss(t, t, _MM_FROUND_TO_ZERO);
|
||||
return _mm_cvtss_f32(t);
|
||||
#else
|
||||
return trunc(f);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline T roundTrunc(double f) {
|
||||
#ifdef SIMD_SUPPORT
|
||||
__m128d t = _mm_set_sd(f);
|
||||
t = _mm_round_sd(t, t, _MM_FROUND_TO_ZERO);
|
||||
return _mm_cvtsd_f64(t);
|
||||
#else
|
||||
return trunc(f);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -6,46 +6,6 @@
|
||||
#include <functional>
|
||||
|
||||
namespace Util {
|
||||
template <class T, typename... Args>
|
||||
struct AutoRelease {
|
||||
AutoRelease(void (*dtor)(T*), const char* name = "") : dtor(dtor), name(name) { }
|
||||
|
||||
AutoRelease(T* (*ctor)(Args...), void (*dtor)(T*), const char* name = "", Args... args) : dtor(dtor), name(name) {
|
||||
thing = ctor(args...);
|
||||
}
|
||||
|
||||
T* get() {
|
||||
if (!thing) {
|
||||
Util::panic("AutoRelease::{} is null!", name);
|
||||
}
|
||||
return thing;
|
||||
}
|
||||
|
||||
void Construct(T* (*ctor)(Args...), Args... args) {
|
||||
if(thing) {
|
||||
dtor(thing);
|
||||
}
|
||||
|
||||
thing = ctor(args...);
|
||||
}
|
||||
|
||||
void Destroy() {
|
||||
if(thing) {
|
||||
dtor(thing);
|
||||
}
|
||||
}
|
||||
|
||||
~AutoRelease() {
|
||||
if(thing) {
|
||||
dtor(thing);
|
||||
}
|
||||
}
|
||||
private:
|
||||
const char* name = "";
|
||||
T* thing = nullptr;
|
||||
void (*dtor)(T*) = nullptr;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
static FORCE_INLINE T ReadAccess(const u8* data, u32 index) {
|
||||
if constexpr (sizeof(T) == 8) {
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
|
||||
namespace Util {
|
||||
enum LogLevel : u8 {
|
||||
Trace, Debug, Info, Warn, Error, Always
|
||||
Trace, Debug, Warn, Info, Error, Always
|
||||
};
|
||||
|
||||
#ifndef NDEBUG
|
||||
static constexpr auto globalLogLevel = Debug;
|
||||
#else
|
||||
static constexpr auto globalLogLevel = Error;
|
||||
static constexpr auto globalLogLevel = Info;
|
||||
#endif
|
||||
|
||||
template <LogLevel messageType = Info, typename ...Args>
|
||||
|
||||
Reference in New Issue
Block a user