forgot to increment v_current. Fuck me, thanks @wheremyfoodat

This commit is contained in:
CocoSimone
2022-09-09 17:03:01 +02:00
parent 314f6629f0
commit 0b5a9ba0e7
17 changed files with 106 additions and 59 deletions

2
.gitignore vendored
View File

@@ -10,3 +10,5 @@ roms/
.vscode/ .vscode/
vgcore.* vgcore.*
*.data *.data
disasm.txt
log.txt

View File

@@ -13,6 +13,15 @@ find_package(fmt REQUIRED)
add_executable(natsukashii main.cpp) add_executable(natsukashii main.cpp)
if (CMAKE_BUILD_TYPE MATCHES Debug)
set(OPTIMIZATIONS -g
#-fsanitize=address -fsanitize=undefined
)
#target_link_libraries(natsukashii PUBLIC -fsanitize=address -fsanitize=undefined)
elseif(CMAKE_BUILD_TYPE MATCHES Release)
set(OPTIMIZATIONS -O3)
endif()
target_link_libraries(natsukashii PUBLIC frontend n64 fmt) target_link_libraries(natsukashii PUBLIC frontend n64 fmt)
target_include_directories(natsukashii PUBLIC . ../external) target_include_directories(natsukashii PUBLIC . ../external)
target_compile_options(natsukashii PUBLIC -Wpedantic -Wimplicit-fallthrough -Wextra -Wall) target_compile_options(natsukashii PUBLIC ${OPTIMIZATIONS} -Wpedantic -Wimplicit-fallthrough -Wextra -Wall)

View File

@@ -43,6 +43,8 @@ void Core::Run(Window& window) {
int frameCycles = 0; int frameCycles = 0;
if(!pause && romLoaded) { if(!pause && romLoaded) {
for (int i = 0; i < mmio.vi.numHalflines; i++) { for (int i = 0; i < mmio.vi.numHalflines; i++) {
mmio.vi.current = (i << 1) + field;
if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) { if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) {
InterruptRaise(mmio.mi, cpu.regs, Interrupt::VI); InterruptRaise(mmio.mi, cpu.regs, Interrupt::VI);
} }
@@ -54,7 +56,7 @@ void Core::Run(Window& window) {
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp); mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp); mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
mmio.ai.Step(mem, cpu.regs, 1); //mmio.ai.Step(mem, cpu.regs, 1);
} }
cycles -= mmio.vi.cyclesPerHalfline; cycles -= mmio.vi.cyclesPerHalfline;
@@ -67,7 +69,7 @@ void Core::Run(Window& window) {
UpdateScreenParallelRdp(*this, window, GetVI()); UpdateScreenParallelRdp(*this, window, GetVI());
int missedCycles = N64_CYCLES_PER_FRAME - frameCycles; int missedCycles = N64_CYCLES_PER_FRAME - frameCycles;
mmio.ai.Step(mem, cpu.regs, missedCycles); //mmio.ai.Step(mem, cpu.regs, missedCycles);
} else if(pause && romLoaded) { } else if(pause && romLoaded) {
UpdateScreenParallelRdp(*this, window, GetVI()); UpdateScreenParallelRdp(*this, window, GetVI());
} else if(pause && !romLoaded) { } else if(pause && !romLoaded) {

View File

@@ -2,7 +2,7 @@
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include "util.hpp" #include "util.hpp"
namespace natsukashii::core { namespace n64 {
#define AUDIO_SAMPLE_RATE 48000 #define AUDIO_SAMPLE_RATE 48000
#define SYSTEM_SAMPLE_FORMAT AUDIO_F32SYS #define SYSTEM_SAMPLE_FORMAT AUDIO_F32SYS
#define SYSTEM_SAMPLE_SIZE 4 #define SYSTEM_SAMPLE_SIZE 4

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include "common.hpp" #include "common.hpp"
namespace natsukashii::core { namespace n64 {
void PushSample(s16, s16); void PushSample(s16, s16);
void InitAudio(); void InitAudio();
void AdjustSampleRate(int); void AdjustSampleRate(int);

View File

@@ -41,17 +41,17 @@ void FireException(Registers& regs, ExceptionCode code, int cop, s64 pc) {
bool old_exl = regs.cop0.status.exl; bool old_exl = regs.cop0.status.exl;
if(!regs.cop0.status.exl) { if(!regs.cop0.status.exl) {
if(regs.prevDelaySlot) { // TODO: cached value of delay_slot should be used, but Namco Museum breaks! if(regs.delaySlot) { // TODO: cached value of delay_slot should be used, but Namco Museum breaks!
regs.cop0.cause.branchDelay = true; regs.cop0.cause.branchDelay = true;
pc -= 4; pc -= 4;
} else { } else {
regs.cop0.cause.branchDelay = false; regs.cop0.cause.branchDelay = false;
} }
regs.cop0.status.exl = true;
regs.cop0.EPC = pc; regs.cop0.EPC = pc;
} }
regs.cop0.status.exl = true;
regs.cop0.cause.copError = cop; regs.cop0.cause.copError = cop;
regs.cop0.cause.exceptionCode = code; regs.cop0.cause.exceptionCode = code;
@@ -59,12 +59,8 @@ void FireException(Registers& regs, ExceptionCode code, int cop, s64 pc) {
util::panic("BEV bit set!\n"); util::panic("BEV bit set!\n");
} else { } else {
switch(code) { switch(code) {
case Interrupt: case TLBModification: case Interrupt ... TLBModification:
case AddressErrorLoad: case AddressErrorStore: case AddressErrorLoad ... Trap:
case InstructionBusError: case DataBusError:
case Syscall: case Breakpoint:
case ReservedInstruction: case CoprocessorUnusable:
case Overflow: case Trap:
case FloatingPointError: case Watch: case FloatingPointError: case Watch:
regs.SetPC(s64(s32(0x80000180))); regs.SetPC(s64(s32(0x80000180)));
break; break;
@@ -91,14 +87,28 @@ inline void HandleInterrupt(Registers& regs) {
void Cpu::Step(Mem& mem) { void Cpu::Step(Mem& mem) {
regs.gpr[0] = 0; regs.gpr[0] = 0;
CheckCompareInterrupt(mem.mmio.mi, regs);
HandleInterrupt(regs);
regs.prevDelaySlot = regs.delaySlot; regs.prevDelaySlot = regs.delaySlot;
regs.delaySlot = false; regs.delaySlot = false;
CheckCompareInterrupt(mem.mmio.mi, regs);
u32 instruction = mem.Read<u32>(regs, regs.pc, regs.pc); u32 instruction = mem.Read<u32>(regs, regs.pc, regs.pc);
HandleInterrupt(regs); /*cs_insn* insn;
u8 code[4]{};
memcpy(code, &instruction, 4);
u32 pc = regs.pc;
size_t count = cs_disasm(handle, code, 4, (u64)pc, 0, &insn);
if(count > 0) {
for(int i = 0; i < count; i++) {
fprintf(log, "%s", fmt::format("0x{:016X}\t{}\t{}\n", insn[i].address, insn[i].mnemonic, insn[i].op_str).c_str());
}
cs_free(insn, count);
}*/
regs.oldPC = regs.pc; regs.oldPC = regs.pc;
regs.pc = regs.nextPC; regs.pc = regs.nextPC;

View File

@@ -6,12 +6,24 @@
namespace n64 { namespace n64 {
struct Cpu { struct Cpu {
Cpu() { Reset(); } Cpu() {
~Cpu() = default; log = fopen("disasm.txt", "w");
if(cs_open(CS_ARCH_MIPS, CS_MODE_MIPS64, &handle) != CS_ERR_OK) {
util::panic("Could not initialize capstone!\n");
}
Reset();
}
~Cpu() {
fclose(log);
cs_close(&handle);
}
void Reset(); void Reset();
void Step(Mem&); void Step(Mem&);
Registers regs; Registers regs;
private: private:
csh handle;
FILE* log;
friend struct Cop1; friend struct Cop1;
void special(Mem&, u32); void special(Mem&, u32);

View File

@@ -31,13 +31,12 @@ void RSP::Reset() {
void RSP::Step(MI& mi, Registers& regs, RDP& rdp) { void RSP::Step(MI& mi, Registers& regs, RDP& rdp) {
if(!spStatus.halt) { if(!spStatus.halt) {
util::panic("RSP!\n"); gpr[0] = 0;
//gpr[0] = 0; u32 instr = util::ReadAccess<u32>(imem, pc & IMEM_DSIZE);
//u32 instr = util::ReadAccess<u32>(imem, pc & IMEM_DSIZE); oldPC = pc & 0xFFF;
//oldPC = pc & 0xFFF; pc = nextPC & 0xFFF;
//pc = nextPC & 0xFFF; nextPC += 4;
//nextPC += 4; Exec(mi, regs, rdp, instr);
//Exec(mi, regs, rdp, instr);
} }
} }

View File

@@ -137,7 +137,7 @@ void Cpu::branch_likely(bool cond, s64 address) {
if (cond) { if (cond) {
regs.nextPC = address; regs.nextPC = address;
} else { } else {
regs.SetPC(regs.pc + 4); regs.SetPC(regs.nextPC);
} }
} }
@@ -580,7 +580,7 @@ void Cpu::dsra32(u32 instr) {
void Cpu::jr(u32 instr) { void Cpu::jr(u32 instr) {
s32 address = regs.gpr[RS(instr)]; s32 address = regs.gpr[RS(instr)];
if ((address & 3) != 0) { if ((address & 3) != 0) {
HandleTLBException(regs, (s64)((s32)address)); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
} }

View File

@@ -11,7 +11,9 @@ Cop0::Cop0() {
void Cop0::Reset() { void Cop0::Reset() {
cause.raw = 0xB000007C; cause.raw = 0xB000007C;
status.raw = 0x241000E0; status.raw = 0x241000E0;
PRId = 0x00000B22; wired = 64;
index = 64;
PRId = 0x00000B00;
Config = 0x7006E463; Config = 0x7006E463;
EPC = 0xFFFFFFFFFFFFFFFF; EPC = 0xFFFFFFFFFFFFFFFF;
ErrorEPC = 0xFFFFFFFFFFFFFFFF; ErrorEPC = 0xFFFFFFFFFFFFFFFF;
@@ -54,17 +56,17 @@ u32 Cop0::GetReg32(u8 addr) {
u64 Cop0::GetReg64(u8 addr) { u64 Cop0::GetReg64(u8 addr) {
switch(addr) { switch(addr) {
case 2: return entryLo0.raw; case COP0_REG_ENTRYLO0: return entryLo0.raw;
case 3: return entryLo1.raw; case COP0_REG_ENTRYLO1: return entryLo1.raw;
case 4: return context.raw; case COP0_REG_CONTEXT: return context.raw;
case 8: return badVaddr; case COP0_REG_BADVADDR: return badVaddr;
case 10: return entryHi.raw; case COP0_REG_ENTRYHI: return entryHi.raw;
case 12: return status.raw; case COP0_REG_STATUS: return status.raw;
case 14: return EPC; case COP0_REG_EPC: return EPC;
case 15: return PRId; case COP0_REG_PRID: return PRId;
case 17: return LLAddr; case COP0_REG_LLADDR: return LLAddr;
case 20: return xcontext.raw & 0xFFFFFFFFFFFFFFF0; case COP0_REG_XCONTEXT: return xcontext.raw & 0xFFFFFFFFFFFFFFF0;
case 30: return ErrorEPC; case COP0_REG_ERROREPC: return ErrorEPC;
default: default:
util::panic("Unsupported word read from COP0 register {}\n", index); util::panic("Unsupported word read from COP0 register {}\n", index);
} }
@@ -104,7 +106,9 @@ void Cop0::SetReg32(u8 addr, u32 value) {
cause.ip0 = temp.ip0; cause.ip0 = temp.ip0;
cause.ip1 = temp.ip1; cause.ip1 = temp.ip1;
} break; } break;
case COP0_REG_EPC: EPC = s64(s32(value)); break; case COP0_REG_EPC:
EPC = s64(s32(value));
break;
case COP0_REG_PRID: break; case COP0_REG_PRID: break;
case COP0_REG_CONFIG: { case COP0_REG_CONFIG: {
Config &= ~CONFIG_MASK; Config &= ~CONFIG_MASK;
@@ -121,8 +125,8 @@ void Cop0::SetReg32(u8 addr, u32 value) {
case COP0_REG_TAGLO: TagLo = value; break; case COP0_REG_TAGLO: TagLo = value; break;
case COP0_REG_TAGHI: TagHi = value; break; case COP0_REG_TAGHI: TagHi = value; break;
case COP0_REG_ERROREPC: ErrorEPC = s64(s32(value)); break; case COP0_REG_ERROREPC: ErrorEPC = s64(s32(value)); break;
case 7: case 21: case 22: break; case 7: case 21: case 22:
case 23: case 24: case 25: break; case 23: case 24: case 25:
case 31: break; case 31: break;
default: default:
util::panic("Unsupported word read from COP0 register {}\n", index); util::panic("Unsupported word read from COP0 register {}\n", index);

View File

@@ -9,7 +9,7 @@ Cop1::Cop1() {
} }
void Cop1::Reset() { void Cop1::Reset() {
fcr0 = 0xa00; fcr0 = 0;
fcr31.raw = 0; fcr31.raw = 0;
memset(fgr, 0, 32 * sizeof(FGR)); memset(fgr, 0, 32 * sizeof(FGR));
} }

View File

@@ -10,10 +10,10 @@ void AI::Reset() {
dacRate = 0; dacRate = 0;
bitrate = 0; bitrate = 0;
dmaCount = 0; dmaCount = 0;
memset(dmaLen, 0, 2);
memset(dmaAddr, 0, 2);
dmaAddrCarry = false; dmaAddrCarry = false;
cycles = 0; cycles = 0;
memset(dmaLen, 0, 2);
memset(dmaAddr, 0, 2);
dac = {44100, N64_CPU_FREQ / dac.freq, 16}; dac = {44100, N64_CPU_FREQ / dac.freq, 16};
} }
@@ -36,8 +36,6 @@ auto AI::Read(u32 addr) const -> u32 {
#define max(x, y) ((x) > (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y))
using namespace natsukashii::core;
void AI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) { void AI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
switch(addr) { switch(addr) {
case 0x04500000: case 0x04500000:

View File

@@ -27,6 +27,7 @@ void InterruptRaise(MI &mi, Registers &regs, Interrupt intr) {
UpdateInterrupt(mi, regs); UpdateInterrupt(mi, regs);
} }
void InterruptLower(MI &mi, Registers &regs, Interrupt intr) { void InterruptLower(MI &mi, Registers &regs, Interrupt intr) {
switch(intr) { switch(intr) {
case Interrupt::VI: case Interrupt::VI:

View File

@@ -58,7 +58,7 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
dramAddr = dram_addr + len; dramAddr = dram_addr + len;
cartAddr = cart_addr + len; cartAddr = cart_addr + len;
InterruptRaise(mi, regs, Interrupt::PI); InterruptRaise(mi, regs, Interrupt::PI);
status = status & 0xFFFFFFFE; status &= 0xFFFFFFFE;
util::logdebug("PI DMA from rdram to cart (size: {:.2f} MiB)\n", (float)len / 1048576); util::logdebug("PI DMA from rdram to cart (size: {:.2f} MiB)\n", (float)len / 1048576);
} break; } break;
case 0x0460000C: { case 0x0460000C: {
@@ -75,7 +75,7 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
dramAddr = dram_addr + len; dramAddr = dram_addr + len;
cartAddr = cart_addr + len; cartAddr = cart_addr + len;
InterruptRaise(mi, regs, Interrupt::PI); InterruptRaise(mi, regs, Interrupt::PI);
status = status & 0xFFFFFFFE; status &= 0xFFFFFFFE;
util::logdebug("PI DMA from cart to rdram (size: {:.2f} MiB)\n", (float)len / 1048576); util::logdebug("PI DMA from cart to rdram (size: {:.2f} MiB)\n", (float)len / 1048576);
} break; } break;
case 0x04600010: case 0x04600010:

View File

@@ -10,7 +10,13 @@ VI::VI () {
} }
void VI::Reset() { void VI::Reset() {
status.raw = 0xF;
intr = 256; intr = 256;
origin = 0;
width = 320;
current = 0;
vsync = 0;
hsync = 0;
numHalflines = 262; numHalflines = 262;
numFields = 1; numFields = 1;
cyclesPerHalfline = 1000; cyclesPerHalfline = 1000;
@@ -35,7 +41,6 @@ u32 VI::Read(u32 paddr) const {
default: default:
util::panic("Unimplemented VI[%08X] read\n", paddr); util::panic("Unimplemented VI[%08X] read\n", paddr);
} }
return 0;
} }
void VI::Write(MI& mi, Registers& regs, u32 paddr, u32 val) { void VI::Write(MI& mi, Registers& regs, u32 paddr, u32 val) {

View File

@@ -81,15 +81,15 @@ void RSP::Exec(MI &mi, Registers &regs, RDP &rdp, u32 instr) {
u8 mask = (instr >> 26) & 0x3F; u8 mask = (instr >> 26) & 0x3F;
switch(mask) { switch(mask) {
//case 0x00: special(*this, instr); break; //case 0x00: special(*this, instr); break;
//case 0x01: regimm(*this, instr); break; case 0x01: regimm(*this, instr); break;
//case 0x02: j(instr); break; case 0x02: j(instr); break;
//case 0x03: jal(instr); break; //case 0x03: jal(instr); break;
//case 0x04: b(instr, gpr[RT(instr)] == gpr[RS(instr)]); break; //case 0x04: b(instr, gpr[RT(instr)] == gpr[RS(instr)]); break;
//case 0x05: b(instr, gpr[RT(instr)] != gpr[RS(instr)]); break; //case 0x05: b(instr, gpr[RT(instr)] != gpr[RS(instr)]); break;
//case 0x07: b(instr, gpr[RS(instr)] > 0); break; //case 0x07: b(instr, gpr[RS(instr)] > 0); break;
//case 0x08: case 0x09: addi(instr); break; case 0x08: case 0x09: addi(instr); break;
//case 0x0C: andi(instr); break; //case 0x0C: andi(instr); break;
//case 0x0D: ori(instr); break; case 0x0D: ori(instr); break;
//case 0x0F: lui(instr); break; //case 0x0F: lui(instr); break;
//case 0x10: cop0(mi, regs, *this, rdp, instr); break; //case 0x10: cop0(mi, regs, *this, rdp, instr); break;
//case 0x12: cop2(*this, instr); break; //case 0x12: cop2(*this, instr); break;
@@ -100,7 +100,7 @@ void RSP::Exec(MI &mi, Registers &regs, RDP &rdp, u32 instr) {
//case 0x2B: sw(instr); break; //case 0x2B: sw(instr); break;
//case 0x32: lwc2(*this, instr); break; //case 0x32: lwc2(*this, instr); break;
//case 0x3A: swc2(*this, instr); break; //case 0x3A: swc2(*this, instr); break;
default: util::panic("Unhandled RSP instruction {} {}\n", (mask >> 3) & 7, mask & 7); default: util::panic("Unhandled RSP instruction ({:06b})\n", mask);
} }
} }
} }

View File

@@ -91,7 +91,10 @@ void RSP::add(u32 instr) {
} }
void RSP::addi(u32 instr) { void RSP::addi(u32 instr) {
s32 op1 = gpr[RS(instr)];
s16 op2 = instr;
s32 result = op1 + op2;
gpr[RT(instr)] = result;
} }
void RSP::and_(u32 instr) { void RSP::and_(u32 instr) {
@@ -128,7 +131,8 @@ void RSP::lqv(u32 instr) {
} }
void RSP::j(u32 instr) { void RSP::j(u32 instr) {
u32 target = (instr & 0x3ffffff) << 2;
nextPC = target;
} }
void RSP::jal(u32 instr) { void RSP::jal(u32 instr) {
@@ -148,7 +152,8 @@ void RSP::or_(u32 instr) {
} }
void RSP::ori(u32 instr) { void RSP::ori(u32 instr) {
s16 imm = instr;
gpr[RT(instr)] = imm | gpr[RS(instr)];
} }
void RSP::sb(u32 instr) { void RSP::sb(u32 instr) {