N64 integration
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -18,6 +18,7 @@ struct Mem {
|
||||
template <class T, bool tlb = true>
|
||||
void Write(Registers&, u32, T, s64);
|
||||
private:
|
||||
friend struct AI;
|
||||
friend struct Cpu;
|
||||
friend struct RSP;
|
||||
MMIO mmio;
|
||||
|
||||
94
src/core/n64/core/mmio/AI.cpp
Normal file
94
src/core/n64/core/mmio/AI.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
#include <n64/core/mmio/AI.hpp>
|
||||
#include <util.hpp>
|
||||
#include <n64/core/Mem.hpp>
|
||||
#include <n64/core/cpu/Registers.hpp>
|
||||
|
||||
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<u32, false>(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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
30
src/core/n64/core/mmio/AI.hpp
Normal file
30
src/core/n64/core/mmio/AI.hpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
#include <n64/core/mmio/Interrupt.hpp>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,50 +1,50 @@
|
||||
#include <Interrupt.hpp>
|
||||
#include <MI.hpp>
|
||||
#include <n64/core/mmio/Interrupt.hpp>
|
||||
#include <n64/core/mmio/MI.hpp>
|
||||
#include <n64/core/cpu/Registers.hpp>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
#include <MI.hpp>
|
||||
#include <n64/core/mmio/MI.hpp>
|
||||
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user