N64 Coprocessors integration

This commit is contained in:
CocoSimone
2022-07-04 01:13:49 +02:00
parent e1600c9151
commit cdc4289020
17 changed files with 961 additions and 8 deletions

View File

@@ -10,8 +10,6 @@ add_library(cores
Scheduler.cpp
Scheduler.hpp
common.hpp
util.hpp
Audio.hpp
Audio.cpp)
util.hpp)
target_include_directories(cores PUBLIC . ../../external)
target_link_libraries(cores PUBLIC n64)

View File

@@ -1,6 +1,6 @@
#include <Audio.hpp>
#include "Audio.hpp"
#include <SDL2/SDL.h>
#include <util.hpp>
#include "util.hpp"
namespace natsukashii::core {
#define AUDIO_SAMPLE_RATE 48000

View File

@@ -1,5 +1,5 @@
#pragma once
#include <common.hpp>
#include "common.hpp"
namespace natsukashii::core {
void PushSample(s16, s16);

View File

@@ -12,6 +12,8 @@ add_library(n64-core
Mem.hpp
RDP.cpp
RDP.hpp
Audio.cpp
Audio.hpp
mmio/AI.cpp
mmio/AI.hpp
mmio/Interrupt.cpp

View File

@@ -98,5 +98,7 @@ void Cpu::Step(Mem& mem) {
regs.oldPC = regs.pc;
regs.pc = regs.nextPC;
regs.nextPC += 4;
Exec(mem, instruction);
}
}

View File

@@ -7,6 +7,96 @@ struct Cpu {
Cpu() = default;
void Step(Mem&);
Registers regs;
private:
friend struct Cop1;
void special(Mem&, u32);
void regimm(u32);
void Exec(Mem&, u32);
void add(u32);
void addu(u32);
void addi(u32);
void addiu(u32);
void andi(u32);
void and_(u32);
void branch(bool, s64);
void branch_likely(bool, s64);
void b(u32, bool);
void blink(u32, bool);
void bl(u32, bool);
void bllink(u32, bool);
void dadd(u32);
void daddu(u32);
void daddi(u32);
void daddiu(u32);
void ddiv(u32);
void ddivu(u32);
void div_(u32);
void divu(u32);
void dmult(u32);
void dmultu(u32);
void dsll(u32);
void dsllv(u32);
void dsll32(u32);
void dsra(u32);
void dsrav(u32);
void dsra32(u32);
void dsrl(u32);
void dsrlv(u32);
void dsrl32(u32);
void dsub(u32);
void dsubu(u32);
void j(u32);
void jr(u32);
void jal(u32);
void jalr(u32);
void lui(u32);
void lbu(Mem&, u32);
void lb(Mem&, u32);
void ld(Mem&, u32);
void ldl(Mem&, u32);
void ldr(Mem&, u32);
void lh(Mem&, u32);
void lhu(Mem&, u32);
void ll(Mem&, u32);
void lld(Mem&, u32);
void lw(Mem&, u32);
void lwl(Mem&, u32);
void lwu(Mem&, u32);
void lwr(Mem&, u32);
void mfhi(u32);
void mflo(u32);
void mult(u32);
void multu(u32);
void mthi(u32);
void mtlo(u32);
void nor(u32);
void sb(Mem&, u32);
void sc(Mem&, u32);
void scd(Mem&, u32);
void sd(Mem&, u32);
void sdl(Mem&, u32);
void sdr(Mem&, u32);
void sh(Mem&, u32);
void sw(Mem&, u32);
void swl(Mem&, u32);
void swr(Mem&, u32);
void slti(u32);
void sltiu(u32);
void slt(u32);
void sltu(u32);
void sll(u32);
void sllv(u32);
void sub(u32);
void subu(u32);
void sra(u32);
void srav(u32);
void srl(u32);
void srlv(u32);
void trap(bool);
void or_(u32);
void ori(u32);
void xor_(u32);
void xori(u32);
};
enum class ExceptionCode : u8 {

View File

@@ -81,6 +81,10 @@ template u8 Mem::Read<u8>(Registers& regs, u32 vaddr, s64 pc);
template u16 Mem::Read<u16>(Registers& regs, u32 vaddr, s64 pc);
template u32 Mem::Read<u32>(Registers& regs, u32 vaddr, s64 pc);
template u64 Mem::Read<u64>(Registers& regs, u32 vaddr, s64 pc);
template u8 Mem::Read<u8, false>(Registers& regs, u32 vaddr, s64 pc);
template u16 Mem::Read<u16, false>(Registers& regs, u32 vaddr, s64 pc);
template u32 Mem::Read<u32, false>(Registers& regs, u32 vaddr, s64 pc);
template u64 Mem::Read<u64, false>(Registers& regs, u32 vaddr, s64 pc);
template <class T, bool tlb>
void Mem::Write(Registers& regs, u32 vaddr, T val, s64 pc) {
@@ -111,4 +115,8 @@ template void Mem::Write<u8>(Registers& regs, u32 vaddr, u8 val, s64 pc);
template void Mem::Write<u16>(Registers& regs, u32 vaddr, u16 val, s64 pc);
template void Mem::Write<u32>(Registers& regs, u32 vaddr, u32 val, s64 pc);
template void Mem::Write<u64>(Registers& regs, u32 vaddr, u64 val, s64 pc);
template void Mem::Write<u8, false>(Registers& regs, u32 vaddr, u8 val, s64 pc);
template void Mem::Write<u16, false>(Registers& regs, u32 vaddr, u16 val, s64 pc);
template void Mem::Write<u32, false>(Registers& regs, u32 vaddr, u32 val, s64 pc);
template void Mem::Write<u64, false>(Registers& regs, u32 vaddr, u64 val, s64 pc);
}

View File

@@ -5,7 +5,7 @@ add_library(n64-cpu
Registers.cpp
Registers.hpp
registers/Cop0.cpp
registers/Cop0.hpp)
registers/Cop0.hpp decode.cpp registers/cop0instructions.cpp registers/Cop1.cpp registers/Cop1.hpp registers/cop1instructions.cpp)
target_include_directories(n64-cpu PRIVATE . .. ../../ ../../../)
target_include_directories(n64-cpu PUBLIC registers ../../../../../external)

View File

@@ -1,5 +1,6 @@
#pragma once
#include <n64/core/cpu/registers/Cop0.hpp>
#include <n64/core/cpu/registers/Cop1.hpp>
namespace natsukashii::n64::core {
struct Registers {
@@ -7,6 +8,7 @@ struct Registers {
void SetPC(s64);
s64 gpr[32];
Cop0 cop0;
Cop1 cop1;
s64 oldPC, pc, nextPC;
s64 hi, lo;
bool LLBit;

View File

@@ -0,0 +1,143 @@
#include <n64/core/Cpu.hpp>
#include <util.hpp>
namespace natsukashii::n64::core {
void Cpu::special(Mem& mem, u32 instr) {
u8 mask = (instr & 0x3F);
// 00rr_rccc
switch (mask) { // TODO: named constants for clearer code
case 0:
if (instr != 0) {
sll(instr);
}
break;
case 0x02: srl(instr); break;
case 0x03: sra(instr); break;
case 0x04: sllv(instr); break;
case 0x06: srlv(instr); break;
case 0x07: srav(instr); break;
case 0x08: jr(instr); break;
case 0x09: jalr(instr); break;
case 0x0C: FireException(regs, ExceptionCode::Syscall, 0, regs.oldPC); break;
case 0x0D: FireException(regs, ExceptionCode::Breakpoint, 0, regs.oldPC); break;
case 0x0F: break;
case 0x10: mfhi(instr); break;
case 0x11: mthi(instr); break;
case 0x12: mflo(instr); break;
case 0x13: mtlo(instr); break;
case 0x14: dsllv(instr); break;
case 0x16: dsrlv(instr); break;
case 0x17: dsrav(instr); break;
case 0x18: mult(instr); break;
case 0x19: multu(instr); break;
case 0x1A: div_(instr); break;
case 0x1B: divu(instr); break;
case 0x1C: dmult(instr); break;
case 0x1D: dmultu(instr); break;
case 0x1E: ddiv(instr); break;
case 0x1F: ddivu(instr); break;
case 0x20: add(instr); break;
case 0x21: addu(instr); break;
case 0x22: sub(instr); break;
case 0x23: subu(instr); break;
case 0x24: and_(instr); break;
case 0x25: or_(instr); break;
case 0x26: xor_(instr); break;
case 0x27: nor(instr); break;
case 0x2A: slt(instr); break;
case 0x2B: sltu(instr); break;
case 0x2C: dadd(instr); break;
case 0x2D: daddu(instr); break;
case 0x2E: dsub(instr); break;
case 0x2F: dsubu(instr); break;
case 0x34: trap(regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); break;
case 0x38: dsll(instr); break;
case 0x3A: dsrl(instr); break;
case 0x3B: dsra(instr); break;
case 0x3C: dsll32(instr); break;
case 0x3E: dsrl32(instr); break;
case 0x3F: dsra32(instr); break;
default:
util::panic("Unimplemented special {} {}", (mask >> 3) & 7, mask & 7);
}
}
void Cpu::regimm(u32 instr) {
u8 mask = ((instr >> 16) & 0x1F);
// 000r_rccc
switch (mask) { // TODO: named constants for clearer code
case 0x00: b(instr, regs.gpr[RS(instr)] < 0); break;
case 0x01: b(instr, regs.gpr[RS(instr)] >= 0); break;
case 0x02: bl(instr, regs.gpr[RS(instr)] < 0); break;
case 0x03: bl(instr, regs.gpr[RS(instr)] >= 0); break;
case 0x10: blink(instr, regs.gpr[RS(instr)] < 0); break;
case 0x11: blink(instr, regs.gpr[RS(instr)] >= 0); break;
case 0x12: bllink(instr, regs.gpr[RS(instr)] < 0); break;
case 0x13: bllink(instr, regs.gpr[RS(instr)] >= 0); break;
default:
util::panic("Unimplemented regimm {} {}", (mask >> 3) & 3, mask & 7);
}
}
void Cpu::Exec(Mem& mem, u32 instr) {
u8 mask = (instr >> 26) & 0x3f;
// 00rr_rccc
switch(mask) { // TODO: named constants for clearer code
case 0x00: special(mem, instr); break;
case 0x01: regimm(instr); break;
case 0x02: j(instr); break;
case 0x03: jal(instr); break;
case 0x04: b(instr, regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); break;
case 0x05: b(instr, regs.gpr[RS(instr)] != regs.gpr[RT(instr)]); break;
case 0x06: b(instr, regs.gpr[RS(instr)] <= 0); break;
case 0x07: b(instr, regs.gpr[RS(instr)] > 0); break;
case 0x08: addi(instr); break;
case 0x09: addiu(instr); break;
case 0x0A: slti(instr); break;
case 0x0B: sltiu(instr); break;
case 0x0C: andi(instr); break;
case 0x0D: ori(instr); break;
case 0x0E: xori(instr); break;
case 0x0F: lui(instr); break;
case 0x10: regs.cop0.decode(regs, mem, instr); break;
case 0x11: regs.cop1.decode(regs, instr); break;
case 0x14: bl(instr, regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); break;
case 0x15: bl(instr, regs.gpr[RS(instr)] != regs.gpr[RT(instr)]); break;
case 0x16: bl(instr, regs.gpr[RS(instr)] <= 0); break;
case 0x17: bl(instr, regs.gpr[RS(instr)] > 0); break;
case 0x18: daddi(instr); break;
case 0x19: daddiu(instr); break;
case 0x1A: ldl(mem, instr); break;
case 0x1B: ldr(mem, instr); break;
case 0x1F: FireException(regs, ExceptionCode::ReservedInstruction, 0, regs.oldPC); break;
case 0x20: lb(mem, instr); break;
case 0x21: lh(mem, instr); break;
case 0x22: lwl(mem, instr); break;
case 0x23: lw(mem, instr); break;
case 0x24: lbu(mem, instr); break;
case 0x25: lhu(mem, instr); break;
case 0x26: lwr(mem, instr); break;
case 0x27: lwu(mem, instr); break;
case 0x28: sb(mem, instr); break;
case 0x29: sh(mem, instr); break;
case 0x2A: swl(mem, instr); break;
case 0x2B: sw(mem, instr); break;
case 0x2C: sdl(mem, instr); break;
case 0x2D: sdr(mem, instr); break;
case 0x2E: swr(mem, instr); break;
case 0x2F: break; // CACHE
case 0x30: ll(mem, instr); break;
case 0x31: lwc1(mem, instr); break;
case 0x34: lld(mem, instr); break;
case 0x35: ldc1(mem, instr); break;
case 0x37: ld(mem, instr); break;
case 0x38: sc(mem, instr); break;
case 0x39: swc1(mem, instr); break;
case 0x3C: scd(mem, instr); break;
case 0x3D: sdc1(mem, instr); break;
case 0x3F: sd(mem, instr); break;
default:
util::panic("Unimplemented instruction {} {}", (mask >> 3) & 7, mask & 7);
}
}
}

View File

@@ -192,4 +192,25 @@ ExceptionCode GetTLBExceptionCode(TLBError error, TLBAccessType accessType) {
util::panic("Getting TLB exception for unknown error code! ({})\n", error);
}
}
void Cop0::decode(Registers& regs, Mem& mem, u32 instr) {
u8 mask_cop = (instr >> 21) & 0x1F;
u8 mask_cop2 = instr & 0x3F;
switch(mask_cop) {
case 0x00: mfc0(regs, instr); break;
case 0x01: dmfc0(regs, instr); break;
case 0x04: mtc0(regs, instr); break;
case 0x05: dmtc0(regs, instr); break;
case 0x10 ... 0x1F:
switch(mask_cop2) {
case 0x01: tlbr(regs); break;
case 0x02: tlbwi(regs); break;
case 0x08: tlbp(regs); break;
case 0x18: eret(regs); break;
default: util::panic("Unimplemented COP0 function {} {} ({:08X}) ({:016lX})", mask_cop2 >> 3, mask_cop2 & 7, instr, regs->old_pc);
}
break;
default: util::panic("Unimplemented COP0 instruction {} {}", mask_cop >> 4, mask_cop & 7);
}
}
}

View File

@@ -5,6 +5,7 @@ namespace natsukashii::n64::core {
#define STATUS_MASK 0xFF77FFFF
struct Cpu;
struct Registers;
struct Mem;
union Cop0Cause {
@@ -176,6 +177,17 @@ struct Cop0 {
u32 r31{};
TLBEntry tlb[32]{};
TLBError tlbError = NONE;
void decode(Registers&, Mem&, u32);
private:
void mtc0(Registers&, u32);
void dmtc0(Registers&, u32);
void mfc0(Registers&, u32);
void dmfc0(Registers&, u32);
void eret(Registers&);
void tlbr(Registers&);
void tlbwi(Registers&);
void tlbp(Registers&);
};
struct Registers;

View File

@@ -0,0 +1,139 @@
#include <n64/core/cpu/registers/Cop1.hpp>
#include <n64/core/cpu/Registers.hpp>
#include <n64/core/Cpu.hpp>
#include <util.hpp>
namespace natsukashii::n64::core {
void Cop1::decode(Cpu& cpu, u32 instr) {
Registers& regs = cpu.regs;
if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC);
return;
}
u8 mask_sub = (instr >> 21) & 0x1F;
u8 mask_fun = instr & 0x3F;
u8 mask_branch = (instr >> 16) & 0x1F;
switch(mask_sub) {
// 000r_rccc
case 0x00: mfc1(regs, instr); break;
case 0x01: dmfc1(regs, instr); break;
case 0x02: cfc1(regs, instr); break;
case 0x04: mtc1(regs, instr); break;
case 0x05: dmtc1(regs, instr); break;
case 0x06: ctc1(regs, instr); break;
case 0x08:
switch(mask_branch) {
case 0: cpu.b(instr, !regs.cop1.fcr31.compare); break;
case 1: cpu.b(instr, regs.cop1.fcr31.compare); break;
case 2: cpu.bl(instr, !regs.cop1.fcr31.compare); break;
case 3: cpu.bl(instr, regs.cop1.fcr31.compare); break;
default: util::panic("Undefined BC COP1 {:02X}\n", mask_branch);
}
break;
case 0x10: // s
switch(mask_fun) {
case 0x00: adds(regs, instr); break;
case 0x01: subs(regs, instr); break;
case 0x02: muls(regs, instr); break;
case 0x03: divs(regs, instr); break;
case 0x04: sqrts(regs, instr); break;
case 0x05: abss(regs, instr); break;
case 0x06: movs(regs, instr); break;
case 0x07: negs(regs, instr); break;
case 0x08: roundls(regs, instr); break;
case 0x09: truncls(regs, instr); break;
case 0x0A: ceills(regs, instr); break;
case 0x0B: floorls(regs, instr); break;
case 0x0C: roundws(regs, instr); break;
case 0x0D: truncws(regs, instr); break;
case 0x0E: ceilws(regs, instr); break;
case 0x0F: floorws(regs, instr); break;
case 0x21: cvtds(regs, instr); break;
case 0x24: cvtws(regs, instr); break;
case 0x25: cvtls(regs, instr); break;
case 0x30: cconds(regs, instr, F); break;
case 0x31: cconds(regs, instr, UN); break;
case 0x32: cconds(regs, instr, EQ); break;
case 0x33: cconds(regs, instr, UEQ); break;
case 0x34: cconds(regs, instr, OLT); break;
case 0x35: cconds(regs, instr, ULT); break;
case 0x36: cconds(regs, instr, OLE); break;
case 0x37: cconds(regs, instr, ULE); break;
case 0x38: cconds(regs, instr, SF); break;
case 0x39: cconds(regs, instr, NGLE); break;
case 0x3A: cconds(regs, instr, SEQ); break;
case 0x3B: cconds(regs, instr, NGL); break;
case 0x3C: cconds(regs, instr, LT); break;
case 0x3D: cconds(regs, instr, NGE); break;
case 0x3E: cconds(regs, instr, LE); break;
case 0x3F: cconds(regs, instr, NGT); break;
default: util::panic("Unimplemented COP1 function S[{} {}] ({:08X}) ({:016lX})", mask_fun >> 3, mask_fun & 7, instr, regs.oldPC);
}
break;
case 0x11: // d
switch(mask_fun) {
case 0x00: addd(regs, instr); break;
case 0x01: subd(regs, instr); break;
case 0x02: muld(regs, instr); break;
case 0x03: divd(regs, instr); break;
case 0x04: sqrtd(regs, instr); break;
case 0x05: absd(regs, instr); break;
case 0x06: movd(regs, instr); break;
case 0x07: negd(regs, instr); break;
case 0x08: roundld(regs, instr); break;
case 0x09: truncld(regs, instr); break;
case 0x0A: ceilld(regs, instr); break;
case 0x0B: floorld(regs, instr); break;
case 0x0C: roundwd(regs, instr); break;
case 0x0D: truncwd(regs, instr); break;
case 0x0E: ceilwd(regs, instr); break;
case 0x0F: floorwd(regs, instr); break;
case 0x20: cvtsd(regs, instr); break;
case 0x24: cvtwd(regs, instr); break;
case 0x25: cvtld(regs, instr); break;
case 0x30: ccondd(regs, instr, F); break;
case 0x31: ccondd(regs, instr, UN); break;
case 0x32: ccondd(regs, instr, EQ); break;
case 0x33: ccondd(regs, instr, UEQ); break;
case 0x34: ccondd(regs, instr, OLT); break;
case 0x35: ccondd(regs, instr, ULT); break;
case 0x36: ccondd(regs, instr, OLE); break;
case 0x37: ccondd(regs, instr, ULE); break;
case 0x38: ccondd(regs, instr, SF); break;
case 0x39: ccondd(regs, instr, NGLE); break;
case 0x3A: ccondd(regs, instr, SEQ); break;
case 0x3B: ccondd(regs, instr, NGL); break;
case 0x3C: ccondd(regs, instr, LT); break;
case 0x3D: ccondd(regs, instr, NGE); break;
case 0x3E: ccondd(regs, instr, LE); break;
case 0x3F: ccondd(regs, instr, NGT); break;
default: util::panic("Unimplemented COP1 function D[{} {}] ({:08X}) ({:016lX})", mask_fun >> 3, mask_fun & 7, instr, regs.oldPC);
}
break;
case 0x14: // w
switch(mask_fun) {
case 0x01: subw(regs, instr); break;
case 0x05: absw(regs, instr); break;
case 0x02: mulw(regs, instr); break;
case 0x06: movw(regs, instr); break;
case 0x20: cvtsw(regs, instr); break;
case 0x21: cvtdw(regs, instr); break;
default: util::panic("Unimplemented COP1 function W[{} {}] ({:08X}) ({:016lX})", mask_fun >> 3, mask_fun & 7, instr, regs.oldPC);
}
break;
case 0x15: // l
switch(mask_fun) {
case 0x01: subl(regs, instr); break;
case 0x05: absl(regs, instr); break;
case 0x02: mull(regs, instr); break;
case 0x06: movl(regs, instr); break;
case 0x20: cvtsl(regs, instr); break;
case 0x21: cvtdl(regs, instr); break;
default: util::panic("Unimplemented COP1 function L[{} {}] ({:08X}) ({:016lX})", mask_fun >> 3, mask_fun & 7, instr, regs.oldPC);
}
break;
default: util::panic("Unimplemented COP1 instruction {} {}", mask_sub >> 3, mask_sub & 7);
}
}
}

View File

@@ -0,0 +1,200 @@
#pragma once
#include <n64/core/cpu/registers/Cop0.hpp>
namespace natsukashii::n64::core {
union FCR31 {
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;
unsigned:5;
unsigned compare:1;
unsigned fs:1;
unsigned:7;
} __attribute__((__packed__));
struct {
unsigned:7;
unsigned enable:5;
unsigned cause:6;
unsigned:14;
} __attribute__((__packed__));
u32 raw;
};
union FGR {
struct {
s32 lo:32;
s32 hi:32;
} __attribute__((__packed__));
s64 raw;
};
struct Cpu;
struct Registers;
struct Cop1 {
u32 fcr0;
FCR31 fcr31;
FGR fgr[32];
void decode(Cpu&, u32);
private:
template <typename T>
inline void SetReg(Cop0& cop0, u8 index, T value) {
if constexpr(sizeof(T) == 4) {
if (cop0.status.fr) {
fgr[index].lo = value;
} else {
if (index & 1) {
fgr[index & ~1].hi = value;
} else {
fgr[index].lo = value;
}
}
} else if constexpr(sizeof(T) == 8) {
if(!cop0.status.fr) {
index &= ~1;
}
fgr[index].raw = value;
}
}
template <typename T>
inline T GetReg(Cop0& cop0, u8 index) {
if constexpr(sizeof(T) == 4) {
if(cop0.status.fr) {
return fgr[index].lo;
} else {
if (index & 1) {
return fgr[index & ~1].hi;
} else {
return fgr[index].lo;
}
}
} else if constexpr(sizeof(T) == 8) {
if(!cop0.status.fr) {
index &= ~1;
}
return fgr[index].raw;
}
}
inline void SetCop1RegDouble(Cop0& cop0, u8 index, double value) {
u64 raw;
memcpy(&raw, &value, sizeof(double));
SetReg<u64>(cop0, index, raw);
}
inline double GetCop1RegDouble(Cop0& cop0, u8 index) {
double doublevalue;
u64 raw = GetReg<u64>(cop0, index);
memcpy(&doublevalue, &raw, sizeof(double));
return doublevalue;
}
inline void SetCop1RegFloat(Cop0& cop0, u8 index, float value) {
u32 raw;
memcpy(&raw, &value, sizeof(float));
SetReg<u32>(cop0, index, raw);
}
inline float GetCop1RegFloat(Cop0& cop0, u8 index) {
u32 raw = GetReg<u32>(cop0, index);
float floatvalue;
memcpy(&floatvalue, &raw, sizeof(float));
return floatvalue;
}
enum CompConds {
T, UN, EQ, UEQ,
OLT, ULT, OLE, ULE,
SF, NGLE, SEQ, NGL,
LT, NGE, LE, NGT,
F, OR, NEQ, OLG,
UGE, OGE, UGT, OGT,
ST, GLE, SNE, GL,
NLT, GE, NLE, GT
};
void absd(Registers&, u32 instr);
void abss(Registers&, u32 instr);
void absw(Registers&, u32 instr);
void absl(Registers&, u32 instr);
void adds(Registers&, u32 instr);
void addd(Registers&, u32 instr);
void subs(Registers&, u32 instr);
void subd(Registers&, u32 instr);
void subw(Registers&, u32 instr);
void subl(Registers&, u32 instr);
void ceills(Registers&, u32 instr);
void ceilws(Registers&, u32 instr);
void ceilld(Registers&, u32 instr);
void ceilwd(Registers&, u32 instr);
void cfc1(Registers&, u32 instr);
void ctc1(Registers&, u32 instr);
void roundls(Registers&, u32 instr);
void roundld(Registers&, u32 instr);
void roundws(Registers&, u32 instr);
void roundwd(Registers&, u32 instr);
void floorls(Registers&, u32 instr);
void floorld(Registers&, u32 instr);
void floorws(Registers&, u32 instr);
void floorwd(Registers&, u32 instr);
void cvtls(Registers&, u32 instr);
void cvtws(Registers&, u32 instr);
void cvtds(Registers&, u32 instr);
void cvtsw(Registers&, u32 instr);
void cvtdw(Registers&, u32 instr);
void cvtsd(Registers&, u32 instr);
void cvtwd(Registers&, u32 instr);
void cvtld(Registers&, u32 instr);
void cvtdl(Registers&, u32 instr);
void cvtsl(Registers&, u32 instr);
void ccondd(Registers&, u32 instr, CompConds);
void cconds(Registers&, u32 instr, CompConds);
void divs(Registers&, u32 instr);
void divd(Registers&, u32 instr);
void muls(Registers&, u32 instr);
void muld(Registers&, u32 instr);
void mulw(Registers&, u32 instr);
void mull(Registers&, u32 instr);
void movs(Registers&, u32 instr);
void movd(Registers&, u32 instr);
void movw(Registers&, u32 instr);
void movl(Registers&, u32 instr);
void negs(Registers&, u32 instr);
void negd(Registers&, u32 instr);
void sqrts(Registers&, u32 instr);
void sqrtd(Registers&, u32 instr);
void lwc1(Registers&, Mem&, u32 instr);
void swc1(Registers&, Mem&, u32 instr);
void ldc1(Registers&, Mem&, u32 instr);
void mfc1(Registers&, u32 instr);
void dmfc1(Registers&, u32 instr);
void mtc1(Registers&, u32 instr);
void dmtc1(Registers&, u32 instr);
void sdc1(Registers&, Mem&, u32 instr);
void truncws(Registers&, u32 instr);
void truncwd(Registers&, u32 instr);
void truncls(Registers&, u32 instr);
void truncld(Registers&, u32 instr);
};
}

View File

@@ -0,0 +1,81 @@
#include <n64/core/cpu/registers/Cop0.hpp>
#include <n64/core/cpu/Registers.hpp>
#include <util.hpp>
namespace natsukashii::n64::core {
void Cop0::mtc0(Registers& regs, u32 instr) {
SetReg<u32>(RD(instr), regs.gpr[RT(instr)]);
}
void Cop0::dmtc0(Registers& regs, u32 instr) {
SetReg(RD(instr), regs.gpr[RT(instr)]);
}
void Cop0::mfc0(Registers& regs, u32 instr) {
regs.gpr[RT(instr)] = GetReg<s32>(RD(instr));
}
void Cop0::dmfc0(Registers& regs, u32 instr) {
regs.gpr[RT(instr)] = GetReg<s64>(RD(instr));
}
void Cop0::eret(Registers& regs) {
if(status.erl) {
regs.SetPC((s64)ErrorEPC);
status.erl = false;
} else {
regs.SetPC((s64)EPC);
status.exl = false;
}
}
void Cop0::tlbr(Registers& regs) {
int Index = index & 0b111111;
if (Index >= 32) {
util::panic("TLBR with TLB index {}", index);
}
TLBEntry entry = tlb[Index];
entryHi.raw = entry.entryHi.raw;
entryLo0.raw = entry.entryLo0.raw & 0x3FFFFFFF;
entryLo1.raw = entry.entryLo1.raw & 0x3FFFFFFF;
entryLo0.g = entry.global;
entryLo1.g = entry.global;
pageMask.raw = entry.pageMask.raw;
}
void Cop0::tlbwi(Registers& regs) {
PageMask page_mask;
page_mask = pageMask;
u32 top = page_mask.mask & 0xAAA;
page_mask.mask = top | (top >> 1);
int Index = index & 0x3F;
if(Index >= 32) {
util::panic("TLBWI with TLB index {}", Index);
}
tlb[Index].entryHi.raw = entryHi.raw;
tlb[Index].entryHi.vpn2 &= ~page_mask.mask;
tlb[Index].entryLo0.raw = entryLo0.raw & 0x03FFFFFE;
tlb[Index].entryLo1.raw = entryLo1.raw & 0x03FFFFFE;
tlb[Index].pageMask.raw = page_mask.raw;
tlb[Index].global = entryLo0.g && entryLo1.g;
}
void Cop0::tlbp(Registers& regs) {
int match = -1;
TLBEntry* entry = TLBTryMatch(regs, entryHi.raw, &match);
if(entry && match >= 0) {
index = match;
} else {
index = 0x80000000;
}
}
}

View File

@@ -0,0 +1,255 @@
#include <n64/core/cpu/registers/Cop1.hpp>
#include <n64/core/cpu/Registers.hpp>
namespace natsukashii::n64::core {
void Cop1::absd(Registers& regs, u32 instr) {
double fs = GetCop1RegDouble(regs.cop0, FS(instr));
SetCop1RegDouble(regs.cop0, FD(instr), fabs(fs));
}
void Cop1::abss(Registers& regs, u32 instr) {
float fs = GetCop1RegFloat(regs.cop0, FS(instr));
SetCop1RegFloat(regs.cop0, FD(instr), fabsf(fs));
}
void Cop1::absw(Registers& regs, u32 instr) {
}
void Cop1::absl(Registers& regs, u32 instr) {
}
void Cop1::adds(Registers& regs, u32 instr) {
}
void Cop1::addd(Registers& regs, u32 instr) {
}
void Cop1::subs(Registers& regs, u32 instr) {
}
void Cop1::subd(Registers& regs, u32 instr) {
}
void Cop1::subw(Registers& regs, u32 instr) {
}
void Cop1::subl(Registers& regs, u32 instr) {
}
void Cop1::ceills(Registers& regs, u32 instr) {
}
void Cop1::ceilws(Registers& regs, u32 instr) {
}
void Cop1::ceilld(Registers& regs, u32 instr) {
}
void Cop1::ceilwd(Registers& regs, u32 instr) {
}
void Cop1::cfc1(Registers& regs, u32 instr) {
}
void Cop1::ctc1(Registers& regs, u32 instr) {
}
void Cop1::roundls(Registers& regs, u32 instr) {
}
void Cop1::roundld(Registers& regs, u32 instr) {
}
void Cop1::roundws(Registers& regs, u32 instr) {
}
void Cop1::roundwd(Registers& regs, u32 instr) {
}
void Cop1::floorls(Registers& regs, u32 instr) {
}
void Cop1::floorld(Registers& regs, u32 instr) {
}
void Cop1::floorws(Registers& regs, u32 instr) {
}
void Cop1::floorwd(Registers& regs, u32 instr) {
}
void Cop1::cvtls(Registers& regs, u32 instr) {
}
void Cop1::cvtws(Registers& regs, u32 instr) {
}
void Cop1::cvtds(Registers& regs, u32 instr) {
}
void Cop1::cvtsw(Registers& regs, u32 instr) {
}
void Cop1::cvtdw(Registers& regs, u32 instr) {
}
void Cop1::cvtsd(Registers& regs, u32 instr) {
}
void Cop1::cvtwd(Registers& regs, u32 instr) {
}
void Cop1::cvtld(Registers& regs, u32 instr) {
}
void Cop1::cvtdl(Registers& regs, u32 instr) {
}
void Cop1::cvtsl(Registers& regs, u32 instr) {
}
void Cop1::ccondd(Registers& regs, u32 instr, CompConds cond) {
}
void Cop1::cconds(Registers& regs, u32 instr, CompConds cond) {
}
void Cop1::divs(Registers& regs, u32 instr) {
}
void Cop1::divd(Registers& regs, u32 instr) {
}
void Cop1::muls(Registers& regs, u32 instr) {
}
void Cop1::muld(Registers& regs, u32 instr) {
}
void Cop1::mulw(Registers& regs, u32 instr) {
}
void Cop1::mull(Registers& regs, u32 instr) {
}
void Cop1::movs(Registers& regs, u32 instr) {
}
void Cop1::movd(Registers& regs, u32 instr) {
}
void Cop1::movw(Registers& regs, u32 instr) {
}
void Cop1::movl(Registers& regs, u32 instr) {
}
void Cop1::negs(Registers& regs, u32 instr) {
}
void Cop1::negd(Registers& regs, u32 instr) {
}
void Cop1::sqrts(Registers& regs, u32 instr) {
}
void Cop1::sqrtd(Registers& regs, u32 instr) {
}
void Cop1::lwc1(Registers& regs, Mem& mem, u32 instr) {
}
void Cop1::swc1(Registers& regs, Mem& mem, u32 instr) {
}
void Cop1::ldc1(Registers& regs, Mem& mem, u32 instr) {
}
void Cop1::mfc1(Registers& regs, u32 instr) {
}
void Cop1::dmfc1(Registers& regs, u32 instr) {
}
void Cop1::mtc1(Registers& regs, u32 instr) {
}
void Cop1::dmtc1(Registers& regs, u32 instr) {
}
void Cop1::sdc1(Registers& regs, Mem&, u32 instr) {
}
void Cop1::truncws(Registers& regs, u32 instr) {
}
void Cop1::truncwd(Registers& regs, u32 instr) {
}
void Cop1::truncls(Registers& regs, u32 instr) {
}
void Cop1::truncld(Registers& regs, u32 instr) {
}
}

View File

@@ -2,7 +2,7 @@
#include <util.hpp>
#include <n64/core/Mem.hpp>
#include <n64/core/cpu/Registers.hpp>
#include <Audio.hpp>
#include <n64/core/Audio.hpp>
namespace natsukashii::n64::core {
auto AI::Read(u32 addr) const -> u32 {