From 15746b8fb826b48431c68b1a86dbc7fb19985f13 Mon Sep 17 00:00:00 2001 From: CocoSimone Date: Sat, 2 Jul 2022 22:24:12 +0200 Subject: [PATCH] N64 integration --- src/core/n64/core/CMakeLists.txt | 2 +- src/core/n64/core/Mem.hpp | 1 + src/core/n64/core/mmio/AI.cpp | 94 ++++++++++++++++++++++++++++ src/core/n64/core/mmio/AI.hpp | 30 +++++++++ src/core/n64/core/mmio/Interrupt.cpp | 32 +++++----- src/core/n64/core/mmio/Interrupt.hpp | 8 +-- 6 files changed, 146 insertions(+), 21 deletions(-) create mode 100644 src/core/n64/core/mmio/AI.cpp create mode 100644 src/core/n64/core/mmio/AI.hpp diff --git a/src/core/n64/core/CMakeLists.txt b/src/core/n64/core/CMakeLists.txt index 65d0f74b..d1444a9c 100644 --- a/src/core/n64/core/CMakeLists.txt +++ b/src/core/n64/core/CMakeLists.txt @@ -23,7 +23,7 @@ add_library(n64-core RSP.cpp RSP.hpp rsp/decode.cpp - rsp/instructions.cpp) + rsp/instructions.cpp mmio/AI.cpp mmio/AI.hpp) target_include_directories(n64-core PRIVATE . .. ../../ mmio) target_link_libraries(n64-core PUBLIC n64-cpu parallel-rdp) diff --git a/src/core/n64/core/Mem.hpp b/src/core/n64/core/Mem.hpp index 7d928eaf..988037f2 100644 --- a/src/core/n64/core/Mem.hpp +++ b/src/core/n64/core/Mem.hpp @@ -18,6 +18,7 @@ struct Mem { template void Write(Registers&, u32, T, s64); private: + friend struct AI; friend struct Cpu; friend struct RSP; MMIO mmio; diff --git a/src/core/n64/core/mmio/AI.cpp b/src/core/n64/core/mmio/AI.cpp new file mode 100644 index 00000000..1f312ac2 --- /dev/null +++ b/src/core/n64/core/mmio/AI.cpp @@ -0,0 +1,94 @@ +#include +#include +#include +#include + +namespace natsukashii::n64::core { +auto AI::Read(u32 addr) const -> u32 { + switch(addr) { + case 0x04500004: return dmaLen[0]; + case 0x0450000C: { + u32 val = 0; + val |= (dmaCount > 1); + val |= 1 << 20; + val |= 1 << 24; + val |= (dmaCount > 0) << 30; + val |= (dmaCount > 1) << 31; + return val; + } + default: util::panic("Unhandled AI read at addr {:08X}\n", addr); + } + return 0; +} + +#define max(x, y) ((x) > (y) ? (x) : (y)) + +void AI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) { + switch(addr) { + case 0x04500000: + if(dmaCount < 2) { + dmaAddr[dmaCount] = val & 0xFFFFFF & ~7; + } + break; + case 0x04500004: { + u32 len = (val & 0x3FFFF) & ~7; + if((dmaCount < 2) && len) { + dmaLen[dmaCount] = len; + dmaCount++; + } + } break; + case 0x04500008: + dmaEnable = val & 1; + break; + case 0x0450000C: + InterruptLower(mem.mmio.mi, regs, Interrupt::AI); + break; + case 0x04500010: { + u32 old_dac_freq = dac.freq; + dacRate = val & 0x3FFF; + dac.freq = max(1, N64_CPU_FREQ / 2 / (dacRate + 1)) * 1.037; + dac.period = N64_CPU_FREQ / dac.freq; + if(old_dac_freq != dac.freq) { + AdjustSampleRate(dac.freq); + } + } break; + case 0x04500014: + bitrate = val & 0xF; + break; + default: util::panic("Unhandled AI write at addr {:08X} with val {:08X}\n", addr, val); + } +} + +void AI::Step(Mem& mem, Registers& regs, int) { + cycles += cycles; + while(cycles > dac.period) { + if (dmaCount == 0) { + return; + } + + u32 address_hi = ((dmaAddr[0] >> 13) + dmaAddrCarry) & 0x7ff; + dmaAddr[0] = (address_hi << 13) | dmaAddr[0] & 0x1fff; + u32 data = mem.Read(regs, dmaAddr[0], regs.pc); + + s16 left = (s16)(data >> 16); + s16 right = (s16)data; + PushSample(left, right); + + u32 address_lo = (dmaAddr[0] + 4) & 0x1fff; + dmaAddr[0] = (dmaAddr[0] & ~0x1fff) | address_lo; + dmaAddrCarry = (address_lo == 0); + dmaLen[0] -= 4; + + if(!dmaLen[0]) { + InterruptRaise(mem.mmio.mi, regs, Interrupt::AI); + if(--dmaCount > 0) { // If we have another DMA pending, start on that one. + dmaAddr[0] = dmaAddr[1]; + dmaLen[0] = dmaLen[1]; + } + } + + cycles -= dac.period; + } +} + +} diff --git a/src/core/n64/core/mmio/AI.hpp b/src/core/n64/core/mmio/AI.hpp new file mode 100644 index 00000000..ca80e97b --- /dev/null +++ b/src/core/n64/core/mmio/AI.hpp @@ -0,0 +1,30 @@ +#pragma once +#include +#include + +namespace natsukashii::n64::core { +struct Mem; +struct Registers; + +struct AI { + AI() = default; + auto Read(u32) const -> u32; + void Write(Mem&, Registers&, u32, u32); + void Step(Mem&, Registers&, int); + bool dmaEnable{}; + u16 dacRate{}; + u8 bitrate{}; + int dmaCount{}; + u32 dmaLen[2]{}; + u32 dmaAddr[2]{}; + bool dmaAddrCarry{}; + int cycles{}; + + struct { + u32 freq{44100}; + u32 period{N64_CPU_FREQ / freq}; + u32 precision{16}; + } dac; +}; + +} \ No newline at end of file diff --git a/src/core/n64/core/mmio/Interrupt.cpp b/src/core/n64/core/mmio/Interrupt.cpp index e49c1f27..89b48caf 100644 --- a/src/core/n64/core/mmio/Interrupt.cpp +++ b/src/core/n64/core/mmio/Interrupt.cpp @@ -1,50 +1,50 @@ -#include -#include +#include +#include #include namespace natsukashii::n64::core { -void InterruptRaise(MI &mi, Registers ®s, InterruptType intr) { +void InterruptRaise(MI &mi, Registers ®s, Interrupt intr) { switch(intr) { - case InterruptType::VI: + case Interrupt::VI: mi.miIntr.vi = true; break; - case InterruptType::SI: + case Interrupt::SI: mi.miIntr.si = true; break; - case InterruptType::PI: + case Interrupt::PI: mi.miIntr.pi = true; break; - case InterruptType::AI: + case Interrupt::AI: mi.miIntr.ai = true; break; - case InterruptType::DP: + case Interrupt::DP: mi.miIntr.dp = true; break; - case InterruptType::SP: + case Interrupt::SP: mi.miIntr.sp = true; break; } UpdateInterrupt(mi, regs); } -void InterruptLower(MI &mi, Registers ®s, InterruptType intr) { +void InterruptLower(MI &mi, Registers ®s, Interrupt intr) { switch(intr) { - case InterruptType::VI: + case Interrupt::VI: mi.miIntr.vi = false; break; - case InterruptType::SI: + case Interrupt::SI: mi.miIntr.si = false; break; - case InterruptType::PI: + case Interrupt::PI: mi.miIntr.pi = false; break; - case InterruptType::AI: + case Interrupt::AI: mi.miIntr.ai = false; break; - case InterruptType::DP: + case Interrupt::DP: mi.miIntr.dp = false; break; - case InterruptType::SP: + case Interrupt::SP: mi.miIntr.sp = false; break; } diff --git a/src/core/n64/core/mmio/Interrupt.hpp b/src/core/n64/core/mmio/Interrupt.hpp index cffdd078..ad9aa1ce 100644 --- a/src/core/n64/core/mmio/Interrupt.hpp +++ b/src/core/n64/core/mmio/Interrupt.hpp @@ -1,16 +1,16 @@ #pragma once #include -#include +#include namespace natsukashii::n64::core { struct Registers; -enum class InterruptType : u8 { +enum class Interrupt : u8 { VI, SI, PI, AI, DP, SP }; -void InterruptRaise(MI &mi, Registers ®s, InterruptType intr); -void InterruptLower(MI &mi, Registers ®s, InterruptType intr); +void InterruptRaise(MI &mi, Registers ®s, Interrupt intr); +void InterruptLower(MI &mi, Registers ®s, Interrupt intr); void UpdateInterrupt(MI &mi, Registers ®s); } \ No newline at end of file