mirror of
https://github.com/google0101-ryan/Emotional.git
synced 2024-06-22 22:22:37 -04:00
Booting lots of demos now
This commit is contained in:
parent
da6fdef63a
commit
3a5b21a3c2
|
@ -21,7 +21,10 @@ set(SOURCES src/main.cpp
|
|||
src/emu/gpu/gif.cpp
|
||||
src/emu/gpu/gs.cpp
|
||||
src/emu/dev/sif.cpp
|
||||
src/emu/dev/cdvd.cpp)
|
||||
src/emu/dev/cdvd.cpp
|
||||
src/emu/dev/sio2.cpp
|
||||
src/emu/cpu/ee/ee_interpret.cpp
|
||||
src/emu/cpu/ee/ee_opcode.cpp)
|
||||
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
|
||||
|
@ -30,6 +33,11 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|||
add_executable(ps2 ${SOURCES})
|
||||
set(TARGET_NAME ps2)
|
||||
|
||||
find_package(SDL2 REQUIRED)
|
||||
include_directories(ps2 ${SDL2_INCLUDE_DIRS})
|
||||
|
||||
target_link_libraries(ps2 ${SDL2_LIBRARIES})
|
||||
|
||||
if(MSVC)
|
||||
target_compile_options(${TARGET_NAME} PRIVATE /W4 /WX)
|
||||
else()
|
||||
|
|
|
@ -4,14 +4,21 @@
|
|||
#include "System.h"
|
||||
#include <emu/memory/Bus.h>
|
||||
#include <emu/cpu/ee/EmotionEngine.h>
|
||||
#include <emu/cpu/ee/ee_interpret.h>
|
||||
#include <emu/sched/scheduler.h>
|
||||
#include <emu/cpu/ee/vu.h>
|
||||
#include <emu/cpu/iop/cpu.h>
|
||||
#include <emu/gpu/gs.h>
|
||||
|
||||
#include <chrono> // NOLINT [build/c++11]
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
|
||||
Scheduler::Event vsync_event;
|
||||
std::ofstream fps_file;
|
||||
|
||||
Scheduler::Event vblank_start_event;
|
||||
Scheduler::Event vblank_end_event;
|
||||
Scheduler::Event hblank_event;
|
||||
|
||||
std::chrono::steady_clock::time_point first_tp;
|
||||
uint64_t frame_count = 0;
|
||||
|
@ -24,6 +31,9 @@ std::chrono::duration<double> uptime()
|
|||
return std::chrono::steady_clock::now() - first_tp;
|
||||
}
|
||||
|
||||
clock_t current_ticks, delta_ticks;
|
||||
clock_t fps_ = 0;
|
||||
|
||||
double fps()
|
||||
{
|
||||
const double uptime_sec = uptime().count();
|
||||
|
@ -34,11 +44,39 @@ double fps()
|
|||
return frame_count / uptime_sec;
|
||||
}
|
||||
|
||||
void HandleVsync()
|
||||
void HandleVblankStart()
|
||||
{
|
||||
Scheduler::ScheduleEvent(vblank_start_event);
|
||||
|
||||
GS::SetVblankStart(true);
|
||||
GS::UpdateOddFrame();
|
||||
|
||||
if (GS::VSIntEnabled())
|
||||
Bus::TriggerEEInterrupt(2);
|
||||
}
|
||||
|
||||
void HandleVblankEnd()
|
||||
{
|
||||
// printf("FPS: %f\n", fps());
|
||||
Scheduler::ScheduleEvent(vsync_event);
|
||||
frame_count++;
|
||||
GS::UpdateFPS(fps());
|
||||
|
||||
Scheduler::ScheduleEvent(vblank_end_event);
|
||||
|
||||
GS::SetVblankStart(false);
|
||||
|
||||
if (GS::VSIntEnabled())
|
||||
Bus::TriggerEEInterrupt(3);
|
||||
}
|
||||
|
||||
void HandleHblank()
|
||||
{
|
||||
Scheduler::ScheduleEvent(hblank_event);
|
||||
|
||||
GS::SetHblank(true);
|
||||
|
||||
if (GS::HSIntEnabled())
|
||||
Bus::TriggerEEInterrupt(0);
|
||||
}
|
||||
|
||||
void System::LoadBios(std::string biosName)
|
||||
|
@ -68,27 +106,54 @@ void System::LoadBios(std::string biosName)
|
|||
void System::Reset()
|
||||
{
|
||||
Scheduler::InitScheduler();
|
||||
#ifdef EE_JIT
|
||||
EmotionEngine::Reset();
|
||||
#else
|
||||
EEInterpreter::Reset();
|
||||
#endif
|
||||
|
||||
IOP_MANAGEMENT::Reset();
|
||||
|
||||
vsync_event.func = HandleVsync;
|
||||
vsync_event.name = "VSYNC handler";
|
||||
vsync_event.cycles_from_now = 4920115;
|
||||
Scheduler::ScheduleEvent(vsync_event);
|
||||
vblank_start_event.func = HandleVblankStart;
|
||||
vblank_start_event.name = "VBLANK start handler";
|
||||
vblank_start_event.cycles_from_now = 4489019;
|
||||
Scheduler::ScheduleEvent(vblank_start_event);
|
||||
|
||||
vblank_end_event.func = HandleVblankEnd;
|
||||
vblank_end_event.name = "VBLANK end handler";
|
||||
vblank_end_event.cycles_from_now = 4920115;
|
||||
Scheduler::ScheduleEvent(vblank_end_event);
|
||||
|
||||
fps_file.open("fps.txt");
|
||||
|
||||
first_tp = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
void System::Run()
|
||||
{
|
||||
#ifdef EE_JIT
|
||||
EmotionEngine::Clock();
|
||||
#else
|
||||
while (1)
|
||||
{
|
||||
size_t cycles = Scheduler::GetNextTimestamp();
|
||||
|
||||
EEInterpreter::Clock(cycles);
|
||||
|
||||
Scheduler::CheckScheduler(cycles);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void System::Dump()
|
||||
{
|
||||
#ifdef EE_JIT
|
||||
EmotionEngine::Dump();
|
||||
#else
|
||||
EEInterpreter::Dump();
|
||||
#endif
|
||||
Bus::Dump();
|
||||
VectorUnit::Dump();
|
||||
IOP_MANAGEMENT::Dump();
|
||||
GS::DumpVram();
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -52,6 +52,53 @@ enum IRInstrs
|
|||
ERET = 35,
|
||||
SYSCALL = 36,
|
||||
EI = 37,
|
||||
PLZCW = 38,
|
||||
PMFHI = 39,
|
||||
PMFLO = 40,
|
||||
MTHI = 41,
|
||||
MTLO = 42,
|
||||
PCPYLD = 43,
|
||||
PSUBB = 44,
|
||||
PNOR = 45,
|
||||
PAND = 46,
|
||||
PCPYUD = 47,
|
||||
BC0T = 48,
|
||||
BC0F = 49,
|
||||
PCPYH = 50,
|
||||
CFC2 = 51,
|
||||
CTC2 = 52,
|
||||
VISWR = 53,
|
||||
QMFC2 = 54,
|
||||
QMTC2 = 55,
|
||||
VSUB = 56,
|
||||
VSQI = 57,
|
||||
VIADD = 58,
|
||||
ADDAS = 59,
|
||||
PADDSB = 60,
|
||||
MADD = 61,
|
||||
MADDS = 62,
|
||||
CVTS = 63,
|
||||
MULS = 64,
|
||||
CVTW = 65,
|
||||
DIVS = 66,
|
||||
MOVS = 67,
|
||||
ADDS = 68,
|
||||
SUBS = 69,
|
||||
NEGS = 70,
|
||||
LQC2 = 71,
|
||||
VMULAX = 72,
|
||||
VMADDAZ = 73,
|
||||
VMADDAY = 74,
|
||||
VMADDW = 75,
|
||||
SQC2 = 76,
|
||||
VMADDZ = 77,
|
||||
VMADDAX = 78,
|
||||
VMULAW = 79,
|
||||
VCLIPW = 80,
|
||||
CLES = 81,
|
||||
BC1F = 82,
|
||||
CEQS = 83,
|
||||
BC1T = 84,
|
||||
};
|
||||
|
||||
struct IRValue
|
||||
|
@ -62,6 +109,7 @@ public:
|
|||
Imm,
|
||||
Reg,
|
||||
Cop0Reg,
|
||||
Cop1Reg,
|
||||
Float
|
||||
};
|
||||
private:
|
||||
|
@ -80,9 +128,10 @@ public:
|
|||
|
||||
bool IsImm() {return type == Imm;}
|
||||
bool IsCop0() {return type == Cop0Reg;}
|
||||
bool IsCop1() {return type == Cop1Reg;}
|
||||
bool IsReg() {return type == Reg;}
|
||||
bool IsFloat() {return type == Float;}
|
||||
// Can be used for guest and COP0 registers
|
||||
// Can be used for guest, COP0, and COP1 registers
|
||||
void SetReg(uint32_t reg) {value.register_num = reg;}
|
||||
void SetImm(uint16_t imm) {value.imm = (int32_t)(int16_t)imm;}
|
||||
void SetImm32(uint32_t imm) {value.imm = imm;}
|
||||
|
@ -180,6 +229,7 @@ private:
|
|||
void EmitBNE(uint32_t instr, EE_JIT::IRInstruction& i); // 0x05
|
||||
void EmitBLEZ(uint32_t instr, EE_JIT::IRInstruction& i); // 0x06
|
||||
void EmitBGTZ(uint32_t instr, EE_JIT::IRInstruction& i); // 0x06
|
||||
void EmitADDI(uint32_t instr, EE_JIT::IRInstruction& i); // 0x08
|
||||
void EmitADDIU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x09
|
||||
void EmitSLTI(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0A
|
||||
void EmitSLTIU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0B
|
||||
|
@ -206,8 +256,11 @@ private:
|
|||
void EmitSW(uint32_t instr, EE_JIT::IRInstruction& i); // 0x2B
|
||||
void EmitSDL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x2C
|
||||
void EmitSDR(uint32_t instr, EE_JIT::IRInstruction& i); // 0x2D
|
||||
void EmitLWC1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x31
|
||||
void EmitLQC2(uint32_t instr, EE_JIT::IRInstruction& i); // 0x36
|
||||
void EmitLD(uint32_t instr, EE_JIT::IRInstruction& i); // 0x37
|
||||
void EmitSWC1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x39
|
||||
void EmitSQC2(uint32_t instr, EE_JIT::IRInstruction& i); // 0x3e
|
||||
void EmitSD(uint32_t instr, EE_JIT::IRInstruction& i); // 0x3f
|
||||
|
||||
void EmitSLL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x00
|
||||
|
@ -223,20 +276,28 @@ private:
|
|||
void EmitSyscall(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0C
|
||||
void EmitBreak(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0D
|
||||
void EmitMFHI(uint32_t instr, EE_JIT::IRInstruction& i); // 0x10
|
||||
void EmitMTHI(uint32_t instr, EE_JIT::IRInstruction& i); // 0x11
|
||||
void EmitMFLO(uint32_t instr, EE_JIT::IRInstruction& i); // 0x12
|
||||
void EmitMTLO(uint32_t instr, EE_JIT::IRInstruction& i); // 0x13
|
||||
void EmitDSLLV(uint32_t instr, EE_JIT::IRInstruction& i); // 0x14
|
||||
void EmitDSRLV(uint32_t instr, EE_JIT::IRInstruction& i); // 0x16
|
||||
void EmitDSRAV(uint32_t instr, EE_JIT::IRInstruction& i); // 0x17
|
||||
void EmitMULT(uint32_t instr, EE_JIT::IRInstruction& i); // 0x18
|
||||
void EmitMULTU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x19
|
||||
void EmitDIV(uint32_t instr, EE_JIT::IRInstruction& i); // 0x1a
|
||||
void EmitDIVU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x1b
|
||||
void EmitADD(uint32_t instr, EE_JIT::IRInstruction& i); // 0x20
|
||||
void EmitADDU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x21
|
||||
void EmitSUB(uint32_t instr, EE_JIT::IRInstruction& i); // 0x22
|
||||
void EmitSUBU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x23
|
||||
void EmitAND(uint32_t instr, EE_JIT::IRInstruction& i); // 0x24
|
||||
void EmitOR(uint32_t instr, EE_JIT::IRInstruction& i); // 0x25
|
||||
void EmitXOR(uint32_t instr, EE_JIT::IRInstruction& i); // 0x25
|
||||
void EmitNOR(uint32_t instr, EE_JIT::IRInstruction& i); // 0x27
|
||||
void EmitSLT(uint32_t instr, EE_JIT::IRInstruction& i); // 0x2A
|
||||
void EmitSLTU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x2B
|
||||
void EmitDADDU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x2D
|
||||
void EmitDSUBU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x2F
|
||||
void EmitDSLL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x38
|
||||
void EmitDSRL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x3A
|
||||
void EmitDSLL32(uint32_t instr, EE_JIT::IRInstruction& i); // 0x3C
|
||||
|
@ -247,19 +308,90 @@ private:
|
|||
void EmitBGEZ(uint32_t instr, EE_JIT::IRInstruction& i); // 0x01
|
||||
void EmitBLTZL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x02
|
||||
void EmitBGEZL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x03
|
||||
void EmitBGEZAL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x11
|
||||
|
||||
// MMI
|
||||
void EmitMADD(uint32_t instr, EE_JIT::IRInstruction& i); // 0x00
|
||||
void EmitPLZCW(uint32_t instr, EE_JIT::IRInstruction& i); // 0x04
|
||||
void EmitMFHI1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x10
|
||||
void EmitMTHI1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x11
|
||||
void EmitMFLO1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x12
|
||||
void EmitMTLO1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x13
|
||||
void EmitMULT1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x18
|
||||
void EmitDIVU1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x1B
|
||||
void EmitPADDSB(uint32_t instr, EE_JIT::IRInstruction& i); // 0x30
|
||||
|
||||
void EmitPOR(uint32_t instr, EE_JIT::IRInstruction& i); // 0x05
|
||||
void EmitPSUBB(uint32_t instr, EE_JIT::IRInstruction& i); // 0x09
|
||||
|
||||
// MMI2
|
||||
void EmitPMFHI(uint32_t instr, EE_JIT::IRInstruction& i); // 0x08
|
||||
void EmitPMFLO(uint32_t instr, EE_JIT::IRInstruction& i); // 0x09
|
||||
void EmitPCPYLD(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0e
|
||||
void EmitPAND(uint32_t instr, EE_JIT::IRInstruction& i); // 0x12
|
||||
|
||||
// MMI3
|
||||
void EmitPCPYUD(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0E
|
||||
void EmitPOR(uint32_t instr, EE_JIT::IRInstruction& i); // 0x12
|
||||
void EmitPNOR(uint32_t instr, EE_JIT::IRInstruction& i); // 0x13
|
||||
void EmitPCPYH(uint32_t instr, EE_JIT::IRInstruction& i); // 0x1B
|
||||
|
||||
void EmitPADDUW(uint32_t instr, EE_JIT::IRInstruction& i); // 0x10
|
||||
|
||||
// COP0
|
||||
void EmitMFC0(uint32_t instr, EE_JIT::IRInstruction& i); // 0x00
|
||||
void EmitMTC0(uint32_t instr, EE_JIT::IRInstruction& i); // 0x04
|
||||
void EmitERET(uint32_t instr, EE_JIT::IRInstruction& i); // 0x18
|
||||
|
||||
// COP1
|
||||
void EmitMFC1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x00
|
||||
void EmitMTC1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x04
|
||||
|
||||
// COP1 BC
|
||||
void EmitBC1F(uint32_t instr, EE_JIT::IRInstruction& i); // 0x00
|
||||
void EmitBC1T(uint32_t instr, EE_JIT::IRInstruction& i); // 0x01
|
||||
|
||||
// COP1.S
|
||||
void EmitADDS(uint32_t instr, EE_JIT::IRInstruction& i); // 0x00
|
||||
void EmitSUBS(uint32_t instr, EE_JIT::IRInstruction& i); // 0x01
|
||||
void EmitMULS(uint32_t instr, EE_JIT::IRInstruction& i); // 0x02
|
||||
void EmitDIVS(uint32_t instr, EE_JIT::IRInstruction& i); // 0x03
|
||||
void EmitMOVS(uint32_t instr, EE_JIT::IRInstruction& i); // 0x06
|
||||
void EmitNEGS(uint32_t instr, EE_JIT::IRInstruction& i); // 0x07
|
||||
void EmitADDAS(uint32_t instr, EE_JIT::IRInstruction& i); // 0x18
|
||||
void EmitMADDS(uint32_t instr, EE_JIT::IRInstruction& i); // 0x1c
|
||||
void EmitCVTW(uint32_t instr, EE_JIT::IRInstruction& i); // 0x24
|
||||
void EmitCEQS(uint32_t instr, EE_JIT::IRInstruction& i); // 0x32
|
||||
void EmitCLES(uint32_t instr, EE_JIT::IRInstruction& i); // 0x36
|
||||
|
||||
// COP1.W
|
||||
void EmitCVTS(uint32_t instr, EE_JIT::IRInstruction& i); // 0x30
|
||||
|
||||
// COP2
|
||||
void EmitQMFC2(uint32_t instr, EE_JIT::IRInstruction& i); // 0x01
|
||||
void EmitCFC2(uint32_t instr, EE_JIT::IRInstruction& i); // 0x02
|
||||
void EmitQMTC2(uint32_t instr, EE_JIT::IRInstruction& i); // 0x05
|
||||
void EmitCTC2(uint32_t instr, EE_JIT::IRInstruction& i); // 0x06
|
||||
|
||||
// COP2 special1
|
||||
void EmitVMADDZ(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0a
|
||||
void EmitVMADDW(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0b
|
||||
void EmitVSUB(uint32_t instr, EE_JIT::IRInstruction& i); // 0x2c
|
||||
void EmitVIADD(uint32_t instr, EE_JIT::IRInstruction& i); // 0x30
|
||||
|
||||
// COP2 special2
|
||||
void EmitVMADDAX(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0a
|
||||
void EmitVMADDAY(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0b
|
||||
void EmitVMADDAZ(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0b
|
||||
void EmitVMULAX(uint32_t instr, EE_JIT::IRInstruction& i); // 0x18
|
||||
void EmitVMULAW(uint32_t instr, EE_JIT::IRInstruction& i); // 0x1B
|
||||
void EmitVCLIPW(uint32_t instr, EE_JIT::IRInstruction& i); // 0x1F
|
||||
void EmitVSQI(uint32_t instr, EE_JIT::IRInstruction& i); // 0x35
|
||||
void EmitVISWR(uint32_t instr, EE_JIT::IRInstruction& i); // 0x3f
|
||||
|
||||
// BC0
|
||||
void EmitBC0F(uint32_t instr, EE_JIT::IRInstruction& i); // 0x00
|
||||
void EmitBC0T(uint32_t instr, EE_JIT::IRInstruction& i); // 0x01
|
||||
|
||||
void EmitIncPC(EE_JIT::IRInstruction& i);
|
||||
public:
|
||||
using EntryFunc = void(*)();
|
||||
|
@ -285,23 +417,28 @@ struct ProcessorState
|
|||
{
|
||||
uint128_t regs[32];
|
||||
uint32_t cop0_regs[32];
|
||||
union
|
||||
{
|
||||
float f;
|
||||
uint32_t u;
|
||||
int32_t i;
|
||||
} acc;
|
||||
uint32_t pc, next_pc;
|
||||
uint32_t hi1, hi;
|
||||
uint32_t lo1, lo;
|
||||
uint64_t hi1, hi;
|
||||
uint64_t lo1, lo;
|
||||
union FPR
|
||||
{
|
||||
uint32_t i;
|
||||
int32_t s;
|
||||
float f;
|
||||
} fprs[32];
|
||||
// 0-15 are VI00-VI15, standard integer registers
|
||||
// 16-32 are control registers, including VU1's for some reason
|
||||
// In fact, you can start a VU1 microprogram through CTC2, because... yeah
|
||||
uint32_t cop2_regs[32];
|
||||
bool c = false;
|
||||
|
||||
uint32_t pc_at;
|
||||
};
|
||||
|
||||
extern bool can_disassemble;
|
||||
|
||||
void Reset();
|
||||
int Clock();
|
||||
void Dump();
|
||||
|
@ -310,11 +447,18 @@ void MarkDirty(uint32_t address, uint32_t size);
|
|||
void EmitPrequel();
|
||||
void Exception(uint8_t code);
|
||||
|
||||
void SetIp1Pending(); // Set IP1 to pending, signalling a DMA interrupt
|
||||
void ClearIp1Pending(); // Clear a DMA interrupt
|
||||
|
||||
void SetIp0Pending();
|
||||
|
||||
extern bool can_dump;
|
||||
|
||||
void CheckCacheFull();
|
||||
bool DoesBlockExit(uint32_t addr);
|
||||
void EmitIR(uint32_t instr);
|
||||
bool IsBranch(uint32_t instr);
|
||||
EE_JIT::JIT::EntryFunc EmitDone(int cycles_taken);
|
||||
EE_JIT::JIT::EntryFunc EmitDone(uint64_t cycles_taken);
|
||||
EE_JIT::JIT::EntryFunc GetExistingBlockFunc(uint32_t addr);
|
||||
uint64_t GetExistingBlockCycles(uint32_t addr);
|
||||
|
||||
|
|
|
@ -6,10 +6,13 @@
|
|||
#include <emu/memory/Bus.h>
|
||||
#include <emu/sched/scheduler.h>
|
||||
#include <emu/dev/sif.h>
|
||||
#include <emu/gpu/gif.hpp>
|
||||
#include <emu/cpu/ee/EmotionEngine.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include "dmac.hpp"
|
||||
|
||||
namespace DMAC
|
||||
{
|
||||
|
@ -122,7 +125,7 @@ void WriteVIF0Channel(uint32_t addr, uint32_t data)
|
|||
printf("[emu/DMAC]: Starting VIF0 transfer\n");
|
||||
break;
|
||||
case 0x10:
|
||||
channels[0].madr = data;
|
||||
channels[0].madr = data & 0x01fffff0;
|
||||
break;
|
||||
case 0x30:
|
||||
channels[0].tadr = data;
|
||||
|
@ -149,7 +152,7 @@ void WriteVIF1Channel(uint32_t addr, uint32_t data)
|
|||
printf("[emu/DMAC]: Starting VIF1 transfer\n");
|
||||
break;
|
||||
case 0x10:
|
||||
channels[1].madr = data;
|
||||
channels[1].madr = data & 0x01fffff0;
|
||||
break;
|
||||
case 0x30:
|
||||
channels[1].tadr = data;
|
||||
|
@ -165,6 +168,115 @@ void WriteVIF1Channel(uint32_t addr, uint32_t data)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DoGIFTransfer()
|
||||
{
|
||||
auto& c = channels[2];
|
||||
|
||||
assert(c.chcr.mode == 0);
|
||||
|
||||
while (c.qwc)
|
||||
{
|
||||
uint128_t data = Bus::Read128(c.madr);
|
||||
c.madr += 16;
|
||||
GIF::WriteFIFO(data);
|
||||
c.qwc--;
|
||||
}
|
||||
|
||||
c.chcr.start = 0;
|
||||
|
||||
stat.channel_irq |= (1 << 2);
|
||||
|
||||
#ifdef EE_JIT
|
||||
if (stat.channel_irq & stat.channel_irq_mask)
|
||||
EmotionEngine::SetIp1Pending();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool fetching_gif_tag = false;
|
||||
bool gif_ongoing_transfer = false;
|
||||
bool gif_irq_on_done = false;
|
||||
|
||||
DMATag gif_tag;
|
||||
|
||||
void DoGIFTransferChain()
|
||||
{
|
||||
auto& c = channels[2];
|
||||
|
||||
fetching_gif_tag = true;
|
||||
|
||||
if (!gif_ongoing_transfer)
|
||||
return;
|
||||
|
||||
if (c.qwc > 0)
|
||||
{
|
||||
while (c.qwc)
|
||||
{
|
||||
uint128_t data = Bus::Read128(c.madr);
|
||||
c.madr += 16;
|
||||
GIF::WriteFIFO(data);
|
||||
c.qwc--;
|
||||
|
||||
printf("Writing %s to GIF FIFO\n", print_128(data));
|
||||
}
|
||||
}
|
||||
else if (gif_irq_on_done)
|
||||
{
|
||||
printf("[emu/DMAC]: Transfer ended on GIF channel\n");
|
||||
|
||||
stat.channel_irq |= (1 << 2);
|
||||
|
||||
#ifdef EE_JIT
|
||||
if (stat.channel_irq & stat.channel_irq_mask)
|
||||
EmotionEngine::SetIp1Pending();
|
||||
#endif
|
||||
|
||||
c.chcr.start = 0;
|
||||
gif_ongoing_transfer = false;
|
||||
gif_irq_on_done = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto address = c.tadr;
|
||||
|
||||
gif_tag.value = Bus::Read128(address).u128;
|
||||
|
||||
c.qwc = gif_tag.qwc;
|
||||
c.chcr.tag = (gif_tag.value >> 16) & 0xffff;
|
||||
|
||||
uint16_t tag_id = gif_tag.tag_id;
|
||||
switch (tag_id)
|
||||
{
|
||||
case 0:
|
||||
gif_irq_on_done = true;
|
||||
c.madr = gif_tag.addr;
|
||||
c.tadr += 16;
|
||||
break;
|
||||
case 1:
|
||||
c.madr = c.tadr+16;
|
||||
c.tadr = c.madr+c.qwc*16;
|
||||
break;
|
||||
case 7:
|
||||
gif_irq_on_done = true;
|
||||
c.madr = c.tadr+16;
|
||||
break;
|
||||
default:
|
||||
printf("[emu/GIF]: Unknown tag id %d\n", tag_id);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (gif_ongoing_transfer)
|
||||
{
|
||||
Scheduler::Event gif_evt;
|
||||
gif_evt.cycles_from_now = 2;
|
||||
gif_evt.func = DoGIFTransferChain;
|
||||
gif_evt.name = "GIF DMA transfer";
|
||||
|
||||
Scheduler::ScheduleEvent(gif_evt);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteGIFChannel(uint32_t addr, uint32_t data)
|
||||
{
|
||||
switch (addr & 0xff)
|
||||
|
@ -172,10 +284,24 @@ void WriteGIFChannel(uint32_t addr, uint32_t data)
|
|||
case 0x00:
|
||||
channels[2].chcr.data = data;
|
||||
if (channels[2].chcr.start)
|
||||
printf("[emu/DMAC]: Starting GIF transfer\n");
|
||||
{
|
||||
Scheduler::Event gif_event;
|
||||
gif_event.cycles_from_now = channels[2].qwc*4;
|
||||
gif_event.func = (channels[2].chcr.mode == 0 ? DoGIFTransfer : DoGIFTransferChain);
|
||||
gif_event.name = "GIF DMAC transfer";
|
||||
Scheduler::ScheduleEvent(gif_event);
|
||||
printf("Starting GIF DMAC transfer (%d qwords)\n", channels[2].qwc);
|
||||
gif_ongoing_transfer = true;
|
||||
gif_irq_on_done = false;
|
||||
}
|
||||
break;
|
||||
case 0x10:
|
||||
channels[2].madr = data;
|
||||
channels[2].madr = data & 0x01fffff0;
|
||||
printf("Writing 0x%08x to GIF.MADR\n", data & 0x01fffff0);
|
||||
break;
|
||||
case 0x20:
|
||||
channels[2].qwc = data;
|
||||
printf("Writing 0x%08x to GIF.QWC\n", data);
|
||||
break;
|
||||
case 0x30:
|
||||
channels[2].tadr = data;
|
||||
|
@ -201,7 +327,7 @@ void WriteIPUFROMChannel(uint32_t addr, uint32_t data)
|
|||
printf("[emu/DMAC]: Starting IPU_FROM transfer\n");
|
||||
break;
|
||||
case 0x10:
|
||||
channels[3].madr = data;
|
||||
channels[3].madr = data & 0x01fffff0;
|
||||
break;
|
||||
case 0x30:
|
||||
channels[3].tadr = data;
|
||||
|
@ -227,7 +353,7 @@ void WriteIPUTOChannel(uint32_t addr, uint32_t data)
|
|||
printf("[emu/DMAC]: Starting IPU_TO transfer\n");
|
||||
break;
|
||||
case 0x10:
|
||||
channels[4].madr = data;
|
||||
channels[4].madr = data & 0x01fffff0;
|
||||
break;
|
||||
case 0x30:
|
||||
channels[4].tadr = data;
|
||||
|
@ -245,8 +371,139 @@ void WriteIPUTOChannel(uint32_t addr, uint32_t data)
|
|||
}
|
||||
|
||||
bool sif0_ongoing_transfer = false, fetching_sif0_tag = true;
|
||||
bool irq_on_done = false;
|
||||
DMATag sif0_tag;
|
||||
|
||||
size_t buf_pos = 0;
|
||||
|
||||
struct SifCmdHeader
|
||||
{
|
||||
uint32_t psize:8;
|
||||
uint32_t dsize:24;
|
||||
uint32_t dest;
|
||||
uint32_t cid;
|
||||
uint32_t opt;
|
||||
};
|
||||
|
||||
struct SifInitPkt
|
||||
{
|
||||
SifCmdHeader hdr;
|
||||
uint32_t buf;
|
||||
};
|
||||
|
||||
struct SifCmdSRegData
|
||||
{
|
||||
SifCmdHeader header;
|
||||
int index;
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
struct SifRpcBindPkt
|
||||
{
|
||||
SifCmdHeader header;
|
||||
int rec_id;
|
||||
uint32_t pkt_addr;
|
||||
int rpc_id;
|
||||
uint32_t client;
|
||||
uint32_t sid;
|
||||
};
|
||||
|
||||
struct SifRpcCallPkt
|
||||
{
|
||||
SifCmdHeader header;
|
||||
int rec_id;
|
||||
uint32_t pkt_addr;
|
||||
int rpc_id;
|
||||
uint32_t client;
|
||||
int rpc_number;
|
||||
int send_size;
|
||||
uint32_t receive;
|
||||
int recv_size;
|
||||
int rmode;
|
||||
uint32_t server;
|
||||
};
|
||||
|
||||
uint32_t currentSvrId = 0;
|
||||
|
||||
const char* GetFuncName(uint32_t func_id)
|
||||
{
|
||||
switch (currentSvrId)
|
||||
{
|
||||
case 0x80000006:
|
||||
{
|
||||
switch (func_id)
|
||||
{
|
||||
case 1:
|
||||
return "SifLoadElf";
|
||||
default:
|
||||
printf("Unknown LOADFILE func %d\n", func_id);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
default:
|
||||
printf("Unknown server 0x%08x\n", currentSvrId);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void HandleSifCommand(SifCmdHeader* hdr)
|
||||
{
|
||||
if ((hdr->cid & 0xF0000000) != 0x80000000)
|
||||
return;
|
||||
|
||||
switch (hdr->cid)
|
||||
{
|
||||
case 0x80000001:
|
||||
{
|
||||
SifCmdSRegData* sregData = (SifCmdSRegData*)hdr;
|
||||
printf("sifSetSReg(0x%08x, 0x%08x)\n", sregData->index, sregData->value);
|
||||
break;
|
||||
}
|
||||
case 0x80000002:
|
||||
{
|
||||
SifInitPkt *initPkt = (SifInitPkt*)hdr;
|
||||
if (hdr->opt)
|
||||
printf("SIFCMD Init, opt=1 (finish initialization)\n");
|
||||
else
|
||||
printf("SIFCMD Init, buf=0x%08x\n", initPkt->buf);
|
||||
break;
|
||||
}
|
||||
case 0x80000009:
|
||||
{
|
||||
SifRpcBindPkt* pkt = (SifRpcBindPkt*)hdr;
|
||||
printf("SifRpcBind(0x%08x) (", pkt->sid);
|
||||
|
||||
currentSvrId = pkt->sid;
|
||||
|
||||
switch (pkt->sid)
|
||||
{
|
||||
case 0x80000001:
|
||||
printf("FILEIO");
|
||||
break;
|
||||
case 0x80000006:
|
||||
printf("LOADFILE");
|
||||
break;
|
||||
default:
|
||||
printf("Unknown server ID 0x%08x\n", pkt->sid);
|
||||
exit(1);
|
||||
}
|
||||
printf(")\n");
|
||||
break;
|
||||
}
|
||||
case 0x80000008:
|
||||
break;
|
||||
case 0x8000000A:
|
||||
{
|
||||
SifRpcCallPkt* pkt = (SifRpcCallPkt*)hdr;
|
||||
printf("SifRpcCall(%s)\n", GetFuncName(pkt->rpc_number));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("Unknown SIF command 0x%08x\n", hdr->cid);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void HandleSIF0Transfer()
|
||||
{
|
||||
auto& c = channels[5];
|
||||
|
@ -255,20 +512,70 @@ void HandleSIF0Transfer()
|
|||
|
||||
if (!sif0_ongoing_transfer)
|
||||
return;
|
||||
|
||||
if (fetching_sif0_tag)
|
||||
|
||||
if (c.qwc > 0)
|
||||
{
|
||||
if (SIF::FIFO0_size() >= 2)
|
||||
{
|
||||
printf("Fetching DMATag\n");
|
||||
exit(1);
|
||||
}
|
||||
while (c.qwc)
|
||||
{
|
||||
if (SIF::FIFO0_size() >= 4)
|
||||
{
|
||||
uint32_t data[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
data[i] = SIF::ReadAndPopSIF0();
|
||||
|
||||
__uint128_t qword = *(__uint128_t*)data;
|
||||
|
||||
Bus::Write128(c.madr, {qword});
|
||||
|
||||
sif0_ongoing_transfer = true;
|
||||
c.qwc--;
|
||||
c.madr += 16;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (irq_on_done)
|
||||
{
|
||||
printf("[emu/DMAC]: Transfer ended on SIF0 channel\n");
|
||||
|
||||
stat.channel_irq |= (1 << 5);
|
||||
|
||||
if (stat.channel_irq & stat.channel_irq_mask)
|
||||
{
|
||||
printf("[emu/DMAC]: Trigger SIF0 interrupt\n");
|
||||
#ifdef EE_JIT
|
||||
EmotionEngine::SetIp1Pending();
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
c.chcr.start = 0;
|
||||
sif0_ongoing_transfer = false;
|
||||
irq_on_done = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SIF::FIFO0_size() >= 2)
|
||||
{
|
||||
uint32_t data[2];
|
||||
for (int i = 0; i < 2; i++)
|
||||
data[i] = SIF::ReadAndPopSIF0();
|
||||
|
||||
sif0_tag.value = *(uint64_t*)data;
|
||||
printf("[emu/DMAC]: Read SIF0 tag 0x%08lx\n", (uint64_t)sif0_tag.value);
|
||||
|
||||
c.qwc = sif0_tag.qwc;
|
||||
c.chcr.tag = (sif0_tag.value >> 16) & 0xffff;
|
||||
c.madr = sif0_tag.addr;
|
||||
c.tadr += 16;
|
||||
|
||||
printf("[emu/DMAC]: Tag contains %d qwords, to be transferred to 0x%08x (%d)\n", c.qwc, c.madr, sif0_tag.irq);
|
||||
fetching_sif0_tag = false;
|
||||
|
||||
if (c.chcr.tie && sif0_tag.irq)
|
||||
irq_on_done = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (sif0_ongoing_transfer)
|
||||
{
|
||||
|
@ -279,20 +586,6 @@ void HandleSIF0Transfer()
|
|||
|
||||
Scheduler::ScheduleEvent(sif0_evt);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[emu/DMAC]: Transfer ended on SIF0 channel\n");
|
||||
|
||||
stat.channel_irq |= (1 << 5);
|
||||
|
||||
if (stat.channel_irq & stat.channel_irq_mask)
|
||||
{
|
||||
printf("[emu/DMAC]: Fire interrupt\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
c.chcr.start = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteSIF0Channel(uint32_t addr, uint32_t data)
|
||||
|
@ -317,10 +610,14 @@ void WriteSIF0Channel(uint32_t addr, uint32_t data)
|
|||
Scheduler::ScheduleEvent(sif0_evt);
|
||||
|
||||
sif0_ongoing_transfer = true;
|
||||
fetching_sif0_tag = true;
|
||||
irq_on_done = false;
|
||||
}
|
||||
else
|
||||
sif0_ongoing_transfer = false;
|
||||
break;
|
||||
case 0x10:
|
||||
channels[5].madr = data;
|
||||
channels[5].madr = data & 0x01fffff0;
|
||||
break;
|
||||
case 0x20:
|
||||
channels[5].qwc = data & 0xffff;
|
||||
|
@ -341,106 +638,103 @@ void WriteSIF0Channel(uint32_t addr, uint32_t data)
|
|||
}
|
||||
|
||||
bool fetching_tag = true, ongoing_transfer = false;
|
||||
bool sif1_irq_on_done = false;
|
||||
|
||||
DMATag tag;
|
||||
|
||||
void HandleSIF1Transfer()
|
||||
{
|
||||
|
||||
auto& c = channels[6];
|
||||
|
||||
fetching_tag = true;
|
||||
|
||||
if (!ongoing_transfer)
|
||||
return;
|
||||
|
||||
if (fetching_tag)
|
||||
|
||||
if (c.qwc > 0)
|
||||
{
|
||||
tag.value = Bus::Read128(c.tadr).u128;
|
||||
while (c.qwc != 0)
|
||||
{
|
||||
uint128_t qword = Bus::Read128(c.madr);
|
||||
|
||||
printf("[emu/DMAC]: Found tag on SIF1 %s at 0x%08x\n", print_128({tag.value}), c.tadr);
|
||||
printf("[emu/DMAC]: Writing %s to SIF1 FIFO\n", print_128({qword.u128}));
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
SIF::WriteFIFO1(qword.u32[i]);
|
||||
|
||||
c.qwc = tag.qwc;
|
||||
|
||||
switch (tag.tag_id)
|
||||
{
|
||||
case 0:
|
||||
c.madr = tag.addr;
|
||||
c.tadr += 16;
|
||||
tag.irq = true; // End the transfer and fire an irq
|
||||
break;
|
||||
case 3:
|
||||
c.madr = tag.addr;
|
||||
c.tadr += 16;
|
||||
break;
|
||||
default:
|
||||
printf("[emu/DMAC]: unknown tag mode %d\n", tag.tag_id);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fetching_tag = false;
|
||||
|
||||
int cycles_til_transfer = tag.qwc * 2; // Each qword transfered takes two cycles, so we transfer all at once that many cycles later
|
||||
|
||||
Scheduler::Event sif1_evt;
|
||||
sif1_evt.cycles_from_now = cycles_til_transfer;
|
||||
sif1_evt.func = HandleSIF1Transfer;
|
||||
sif1_evt.name = "SIF1 DMA transfer";
|
||||
|
||||
Scheduler::ScheduleEvent(sif1_evt);
|
||||
|
||||
if (c.chcr.tte)
|
||||
{
|
||||
uint128_t qword = {tag.value};
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
SIF::WriteFIFO1(qword.u32[i]);
|
||||
}
|
||||
}
|
||||
c.qwc--;
|
||||
c.madr += 16;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < tag.qwc; i++)
|
||||
{
|
||||
uint128_t qword = Bus::Read128(c.madr);
|
||||
c.madr += 16;
|
||||
|
||||
printf("[emu/DMAC]: Transfering qword %s\n", print_128(qword));
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
SIF::WriteFIFO1(qword.u32[i]);
|
||||
}
|
||||
}
|
||||
|
||||
c.qwc = 0;
|
||||
|
||||
fetching_tag = true;
|
||||
|
||||
if (tag.irq)
|
||||
ongoing_transfer = false;
|
||||
}
|
||||
|
||||
if (ongoing_transfer)
|
||||
{
|
||||
Scheduler::Event sif1_evt;
|
||||
sif1_evt.cycles_from_now = 2;
|
||||
sif1_evt.func = HandleSIF1Transfer;
|
||||
sif1_evt.name = "SIF1 DMA transfer";
|
||||
|
||||
Scheduler::ScheduleEvent(sif1_evt);
|
||||
}
|
||||
else
|
||||
else if (sif1_irq_on_done)
|
||||
{
|
||||
printf("[emu/DMAC]: Transfer ended on SIF1 channel\n");
|
||||
|
||||
stat.channel_irq |= (1 << 6);
|
||||
|
||||
if (stat.channel_irq & stat.channel_irq_mask)
|
||||
{
|
||||
printf("[emu/DMAC]: Fire interrupt\n");
|
||||
exit(1);
|
||||
}
|
||||
{
|
||||
printf("[emu/DMAC]: Trigger SIF1 interrupt\n");
|
||||
#ifdef EE_JIT
|
||||
EmotionEngine::SetIp1Pending();
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
c.chcr.start = 0;
|
||||
ongoing_transfer = false;
|
||||
sif1_irq_on_done = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto address = c.tadr;
|
||||
|
||||
tag.value = Bus::Read128(address).u128;
|
||||
|
||||
printf("[emu/DMAC]: Read SIF1 tag %s from 0x%08x (%d qwords, from 0x%08x, tag_id %d)\n", print_128({tag.value}), address, tag.qwc, tag.addr, tag.tag_id);
|
||||
|
||||
c.qwc = tag.qwc;
|
||||
c.chcr.tag = (tag.value >> 16) & 0xffff;
|
||||
|
||||
uint16_t tag_id = tag.tag_id;
|
||||
switch (tag_id)
|
||||
{
|
||||
case 0:
|
||||
c.madr = tag.addr;
|
||||
c.tadr += 16;
|
||||
sif1_irq_on_done = true;
|
||||
break;
|
||||
case 1:
|
||||
c.madr = c.tadr+16;
|
||||
c.tadr = c.madr+(c.qwc*16);
|
||||
break;
|
||||
case 2:
|
||||
c.madr = c.tadr+16;
|
||||
c.tadr = tag.addr;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
c.madr = tag.addr;
|
||||
c.tadr += 16;
|
||||
break;
|
||||
default:
|
||||
printf("Unknown tag ID %d\n", tag.tag_id);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (c.chcr.tie && tag.irq)
|
||||
irq_on_done = true;
|
||||
}
|
||||
|
||||
if (ongoing_transfer)
|
||||
{
|
||||
Scheduler::Event sif_evt;
|
||||
sif_evt.cycles_from_now = 2;
|
||||
sif_evt.func = HandleSIF1Transfer;
|
||||
sif_evt.name = "SIF1 DMA transfer";
|
||||
|
||||
Scheduler::ScheduleEvent(sif_evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -466,10 +760,14 @@ void WriteSIF1Channel(uint32_t addr, uint32_t data)
|
|||
Scheduler::ScheduleEvent(sif1_evt);
|
||||
|
||||
ongoing_transfer = true;
|
||||
fetching_tag = true;
|
||||
sif1_irq_on_done = false;
|
||||
}
|
||||
else
|
||||
ongoing_transfer = false;
|
||||
break;
|
||||
case 0x10:
|
||||
channels[6].madr = data;
|
||||
channels[6].madr = data & 0x01fffff0;
|
||||
break;
|
||||
case 0x20:
|
||||
channels[6].qwc = data;
|
||||
|
@ -499,7 +797,7 @@ void WriteSIF2Channel(uint32_t addr, uint32_t data)
|
|||
printf("[emu/DMAC]: Starting SIF2 transfer\n");
|
||||
break;
|
||||
case 0x10:
|
||||
channels[7].madr = data;
|
||||
channels[7].madr = data & 0x01fffff0;
|
||||
break;
|
||||
case 0x30:
|
||||
channels[7].tadr = data;
|
||||
|
@ -526,7 +824,7 @@ void WriteSPRFROMChannel(uint32_t addr, uint32_t data)
|
|||
printf("[emu/DMAC]: Starting SPR_FROM transfer\n");
|
||||
break;
|
||||
case 0x10:
|
||||
channels[8].madr = data;
|
||||
channels[8].madr = data & 0x01fffff0;
|
||||
break;
|
||||
case 0x30:
|
||||
channels[8].tadr = data;
|
||||
|
@ -552,7 +850,7 @@ void WriteSPRTOChannel(uint32_t addr, uint32_t data)
|
|||
printf("[emu/DMAC]: Starting SPR_TO transfer\n");
|
||||
break;
|
||||
case 0x10:
|
||||
channels[9].madr = data;
|
||||
channels[9].madr = data & 0x01fffff0;
|
||||
break;
|
||||
case 0x30:
|
||||
channels[9].tadr = data;
|
||||
|
@ -569,6 +867,25 @@ void WriteSPRTOChannel(uint32_t addr, uint32_t data)
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t ReadGIFChannel(uint32_t addr)
|
||||
{
|
||||
switch (addr & 0xff)
|
||||
{
|
||||
case 0x00:
|
||||
return channels[2].chcr.data;
|
||||
case 0x10:
|
||||
return channels[2].madr;
|
||||
case 0x30:
|
||||
return channels[2].tadr;
|
||||
case 0x40:
|
||||
return channels[2].asr[0];
|
||||
case 0x50:
|
||||
return channels[2].asr[1];
|
||||
case 0x80:
|
||||
return channels[2].sadr.data;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ReadSIF0Channel(uint32_t addr)
|
||||
{
|
||||
switch (addr & 0xff)
|
||||
|
@ -613,11 +930,18 @@ void WriteDSTAT(uint32_t data)
|
|||
stat.clear &= ~(data & 0xffff);
|
||||
stat.reverse ^= (data >> 16);
|
||||
|
||||
printf("0x%08x\n", stat.value);
|
||||
#ifdef EE_JIT
|
||||
if (stat.channel_irq & stat.channel_irq_mask)
|
||||
|
||||
EmotionEngine::SetIp1Pending();
|
||||
else
|
||||
EmotionEngine::ClearIp1Pending();
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t ReadDSTAT()
|
||||
{
|
||||
printf("[emu/DMAC]: Reading 0x%08x from D_STAT\n", stat.value);
|
||||
return stat.value;
|
||||
}
|
||||
|
||||
|
@ -646,4 +970,9 @@ void WriteSQWC(uint32_t data)
|
|||
sqwc = data;
|
||||
}
|
||||
|
||||
bool GetCPCOND0()
|
||||
{
|
||||
return (~(dpcr & 0x3FF) | stat.channel_irq) == 0x3FF;
|
||||
}
|
||||
|
||||
} // namespace DMAC
|
||||
|
|
|
@ -19,6 +19,7 @@ void WriteSIF2Channel(uint32_t addr, uint32_t data);
|
|||
void WriteSPRFROMChannel(uint32_t addr, uint32_t data);
|
||||
void WriteSPRTOChannel(uint32_t addr, uint32_t data);
|
||||
|
||||
uint32_t ReadGIFChannel(uint32_t addr);
|
||||
uint32_t ReadSIF0Channel(uint32_t addr);
|
||||
uint32_t ReadSIF1Channel(uint32_t addr);
|
||||
|
||||
|
@ -36,4 +37,6 @@ uint32_t ReadDPCR();
|
|||
|
||||
void WriteSQWC(uint32_t data);
|
||||
|
||||
bool GetCPCOND0();
|
||||
|
||||
} // namespace DMAC
|
||||
|
|
746
src/emu/cpu/ee/ee_interpret.cpp
Normal file
746
src/emu/cpu/ee/ee_interpret.cpp
Normal file
|
@ -0,0 +1,746 @@
|
|||
#include "ee_interpret.h"
|
||||
#include <util/uint128.h>
|
||||
#include <string.h>
|
||||
#include <emu/memory/Bus.h>
|
||||
#include <emu/cpu/ee/vu.h>
|
||||
|
||||
uint128_t regs[32];
|
||||
uint32_t pc, next_pc;
|
||||
uint32_t hi, lo;
|
||||
uint32_t hi1, lo1;
|
||||
EEInterpreter::COP0 EEInterpreter::cop0;
|
||||
extern EEInterpreter::Cop1Reg cop1_regs[32];
|
||||
|
||||
void EEInterpreter::Reset()
|
||||
{
|
||||
memset(regs, 0, sizeof(regs));
|
||||
|
||||
pc = 0xbfc00000;
|
||||
next_pc = pc + 4;
|
||||
|
||||
cop0.prid = 0x2E20;
|
||||
|
||||
if (!tlb)
|
||||
tlb = new EETLB();
|
||||
}
|
||||
|
||||
void EEInterpreter::Write8(uint32_t addr, uint8_t data)
|
||||
{
|
||||
const auto page = addr >> 12;
|
||||
const auto offs = addr & 0xfff;
|
||||
const auto ptr = tlb->wrTable[page];
|
||||
|
||||
if (ptr != 0)
|
||||
*(uint8_t*)(ptr + offs) = data;
|
||||
else
|
||||
return Bus::Write8(addr, data); // Slow
|
||||
}
|
||||
|
||||
void EEInterpreter::Write16(uint32_t addr, uint16_t data)
|
||||
{
|
||||
const auto page = addr >> 12;
|
||||
const auto offs = addr & 0xfff;
|
||||
const auto ptr = tlb->wrTable[page];
|
||||
|
||||
if (ptr != 0)
|
||||
*(uint16_t*)(ptr + offs) = data;
|
||||
else
|
||||
return Bus::Write16(addr, data); // Slow
|
||||
}
|
||||
|
||||
void EEInterpreter::Write32(uint32_t addr, uint32_t data)
|
||||
{
|
||||
const auto page = addr >> 12;
|
||||
const auto offs = addr & 0xfff;
|
||||
const auto ptr = tlb->wrTable[page];
|
||||
|
||||
if (ptr != 0)
|
||||
*(uint32_t*)(ptr + offs) = data;
|
||||
else
|
||||
return Bus::Write32(addr, data); // Slow
|
||||
}
|
||||
|
||||
void EEInterpreter::Write64(uint32_t addr, uint64_t data)
|
||||
{
|
||||
const auto page = addr >> 12;
|
||||
const auto offs = addr & 0xfff;
|
||||
const auto ptr = tlb->wrTable[page];
|
||||
|
||||
if (ptr != 0)
|
||||
*(uint64_t*)(ptr + offs) = data;
|
||||
else
|
||||
return Bus::Write64(addr, data); // Slow
|
||||
}
|
||||
|
||||
void EEInterpreter::Write128(uint32_t addr, __uint128_t data)
|
||||
{
|
||||
const auto page = addr >> 12;
|
||||
const auto offs = addr & 0xfff;
|
||||
const auto ptr = tlb->wrTable[page];
|
||||
|
||||
if (ptr != 0)
|
||||
*(__uint128_t*)(ptr + offs) = data;
|
||||
else
|
||||
return Bus::Write128(addr, {data}); // Slow
|
||||
}
|
||||
|
||||
uint8_t EEInterpreter::Read8(uint32_t addr)
|
||||
{
|
||||
const auto page = addr >> 12;
|
||||
const auto offs = addr & 0xfff;
|
||||
const auto ptr = tlb->rdTable[page];
|
||||
|
||||
if (ptr != 0)
|
||||
return *(uint8_t*)(ptr + offs);
|
||||
else
|
||||
return Bus::Read8(addr); // Slow
|
||||
}
|
||||
|
||||
uint16_t EEInterpreter::Read16(uint32_t addr)
|
||||
{
|
||||
const auto page = addr >> 12;
|
||||
const auto offs = addr & 0xfff;
|
||||
const auto ptr = tlb->rdTable[page];
|
||||
|
||||
if (ptr != 0)
|
||||
return *(uint16_t*)(ptr + offs);
|
||||
else
|
||||
return Bus::Read16(addr); // Slow
|
||||
}
|
||||
|
||||
uint32_t EEInterpreter::Read32(uint32_t addr)
|
||||
{
|
||||
const auto page = addr >> 12;
|
||||
const auto offs = addr & 0xfff;
|
||||
const auto ptr = tlb->rdTable[page];
|
||||
|
||||
if (ptr != 0)
|
||||
return *(uint32_t*)(ptr + offs);
|
||||
else
|
||||
return Bus::Read32(addr); // Slow
|
||||
}
|
||||
|
||||
uint64_t EEInterpreter::Read64(uint32_t addr)
|
||||
{
|
||||
const auto page = addr >> 12;
|
||||
const auto offs = addr & 0xfff;
|
||||
const auto ptr = tlb->rdTable[page];
|
||||
|
||||
if (ptr != 0)
|
||||
return *(uint64_t*)(ptr + offs);
|
||||
else
|
||||
return Bus::Read64(addr); // Slow
|
||||
}
|
||||
|
||||
__uint128_t EEInterpreter::Read128(uint32_t addr)
|
||||
{
|
||||
const auto page = addr >> 12;
|
||||
const auto offs = addr & 0xfff;
|
||||
const auto ptr = tlb->rdTable[page];
|
||||
|
||||
if (ptr != 0)
|
||||
return *(__uint128_t*)(ptr + offs);
|
||||
else
|
||||
return Bus::Read128(addr).u128; // Slow
|
||||
}
|
||||
|
||||
void EETLB::Unmap(TlbEntry& entry)
|
||||
{
|
||||
uint32_t real_vpn = entry.entry.vpn2 * 2;
|
||||
real_vpn >>= entry.pageShift;
|
||||
|
||||
uint32_t even_page = (real_vpn * entry.pageSize) / 4096;
|
||||
uint32_t odd_page = ((real_vpn + 1) * entry.pageSize) / 4096;
|
||||
|
||||
if (entry.entry.s)
|
||||
{
|
||||
if (entry.entry.v0)
|
||||
{
|
||||
for (uint32_t i = 0; i < 1024*16; i += 4096)
|
||||
{
|
||||
int index = i / 4096;
|
||||
rdTable[even_page + index] = 0;
|
||||
wrTable[even_page + index] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (entry.entry.v0)
|
||||
{
|
||||
for (uint32_t i = 0; i < entry.pageSize; i += 4096)
|
||||
{
|
||||
int index = i / 4096;
|
||||
rdTable[even_page + index] = 0;
|
||||
wrTable[even_page + index] = 0;
|
||||
rdTable[odd_page + index] = 0;
|
||||
wrTable[odd_page + index] = 0;
|
||||
}
|
||||
}
|
||||
if (entry.entry.v1)
|
||||
{
|
||||
for (uint32_t i = 0; i < entry.pageSize; i += 4096)
|
||||
{
|
||||
int index = i / 4096;
|
||||
rdTable[odd_page + index] = 0;
|
||||
wrTable[odd_page + index] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EETLB::DoRemap(int index)
|
||||
{
|
||||
auto& tlbEntry = tlb[index];
|
||||
|
||||
uint32_t entryLo0 = EEInterpreter::cop0.regs[2];
|
||||
uint32_t entryLo1 = EEInterpreter::cop0.regs[3];
|
||||
uint32_t pageMask = EEInterpreter::cop0.regs[5];
|
||||
uint32_t entryHi = EEInterpreter::cop0.regs[10];
|
||||
|
||||
Unmap(tlbEntry);
|
||||
|
||||
switch (pageMask >> 13)
|
||||
{
|
||||
case 0:
|
||||
tlbEntry.pageSize = 4*1024;
|
||||
tlbEntry.pageShift = 0;
|
||||
break;
|
||||
case 3:
|
||||
tlbEntry.pageSize = 16*1024;
|
||||
tlbEntry.pageShift = 2;
|
||||
break;
|
||||
case 0xf:
|
||||
tlbEntry.pageSize = 64*1024;
|
||||
tlbEntry.pageShift = 4;
|
||||
break;
|
||||
case 0x3f:
|
||||
tlbEntry.pageSize = 256*1024;
|
||||
tlbEntry.pageShift = 6;
|
||||
break;
|
||||
case 0xff:
|
||||
tlbEntry.pageSize = 1024*1024;
|
||||
tlbEntry.pageShift = 8;
|
||||
break;
|
||||
case 0x3ff:
|
||||
tlbEntry.pageSize = 4*1024*1024;
|
||||
tlbEntry.pageShift = 10;
|
||||
break;
|
||||
case 0xfff:
|
||||
tlbEntry.pageSize = 16*1024*1024;
|
||||
tlbEntry.pageShift = 12;
|
||||
break;
|
||||
default:
|
||||
printf("Unknown page size 0x%08x\n", pageMask >> 13);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uint32_t pfn0 = (entryLo0 >> 6) & 0xFFFFF;
|
||||
uint32_t pfn1 = (entryLo1 >> 6) & 0xFFFFF;
|
||||
uint32_t vpn2 = (entryHi >> 13) & 0x7FFFF;
|
||||
|
||||
tlbEntry.entry.g = (entryLo0 & 1) & (entryLo1 & 1);
|
||||
tlbEntry.entry.v0 = (entryLo0 >> 1) & 1;
|
||||
tlbEntry.entry.d0 = (entryLo0 >> 2) & 1;
|
||||
tlbEntry.entry.c0 = (entryLo0 >> 3) & 0x7;
|
||||
tlbEntry.entry.pfn0 = (entryLo0 >> 6) & 0xFFFFF;
|
||||
tlbEntry.entry.v1 = (entryLo1 >> 1) & 1;
|
||||
tlbEntry.entry.d1 = (entryLo1 >> 2) & 1;
|
||||
tlbEntry.entry.c1 = (entryLo1 >> 3) & 0x7;
|
||||
tlbEntry.entry.pfn1 = (entryLo1 >> 6) & 0xFFFFF;
|
||||
|
||||
tlbEntry.entry.vpn2 = entryHi >> 13;
|
||||
tlbEntry.entry.asid = entryHi & 0xff;
|
||||
|
||||
uint32_t real_virt = vpn2 * 2;
|
||||
real_virt >>= tlbEntry.pageShift;
|
||||
real_virt *= tlbEntry.pageSize;
|
||||
|
||||
uint32_t real_phy = pfn0 >> tlbEntry.pageShift;
|
||||
real_phy *= tlbEntry.pageSize;
|
||||
uint32_t real_phy_1 = pfn1 >> tlbEntry.pageShift;
|
||||
real_phy_1 *= tlbEntry.pageSize;
|
||||
|
||||
uint32_t real_vpn = (vpn2 * 2) >> tlbEntry.pageShift;
|
||||
|
||||
uint32_t even_virt_page = (real_vpn * tlbEntry.pageSize) / 4096;
|
||||
uint32_t even_virt_addr = even_virt_page * 4096;
|
||||
uint32_t even_phy_addr = (pfn0 >> tlbEntry.pageShift) * tlbEntry.pageSize;
|
||||
uint32_t odd_virt_page = ((real_vpn+1) * tlbEntry.pageSize) / 4096;
|
||||
uint32_t odd_virt_addr = odd_virt_page * 4096;
|
||||
uint32_t odd_phy_addr = (pfn1 >> tlbEntry.pageShift) * tlbEntry.pageSize;
|
||||
|
||||
if (tlbEntry.entry.s)
|
||||
{
|
||||
if (tlbEntry.entry.v0)
|
||||
{
|
||||
for (uint32_t i = 0; i < 1024*16; i += 4096)
|
||||
{
|
||||
int index = i / 4096;
|
||||
rdTable[even_virt_page + index] = (uintptr_t)(Bus::GetSprPtr()+i);
|
||||
wrTable[even_virt_page + index] = (uintptr_t)(Bus::GetSprPtr()+i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tlbEntry.entry.v0)
|
||||
{
|
||||
for (uint32_t i = 0; i < tlbEntry.pageSize; i += 4096)
|
||||
{
|
||||
int index = i / 4096;
|
||||
uintptr_t mem = (uintptr_t)Bus::GetPtrForAddress(even_phy_addr+i);
|
||||
rdTable[even_virt_page + index] = mem;
|
||||
wrTable[even_virt_page + index] = mem;
|
||||
}
|
||||
}
|
||||
if (tlbEntry.entry.v1)
|
||||
{
|
||||
for (uint32_t i = 0; i < tlbEntry.pageSize; i += 4096)
|
||||
{
|
||||
int index = i / 4096;
|
||||
uintptr_t mem = (uintptr_t)Bus::GetPtrForAddress(odd_phy_addr+i);
|
||||
rdTable[odd_virt_page + index] = mem;
|
||||
wrTable[odd_virt_page + index] = mem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EEInterpreter::Clock(int cycles)
|
||||
{
|
||||
for (int cycle = 0; cycle < cycles; cycle++)
|
||||
{
|
||||
uint32_t instr = Read32(pc);
|
||||
|
||||
pc = next_pc;
|
||||
next_pc += 4;
|
||||
|
||||
if (instr == 0)
|
||||
{
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: nop\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t opcode = (instr >> 26) & 0x3F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x00:
|
||||
{
|
||||
opcode = instr & 0x3F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x00:
|
||||
Sll(instr);
|
||||
break;
|
||||
case 0x02:
|
||||
Srl(instr);
|
||||
break;
|
||||
case 0x03:
|
||||
Sra(instr);
|
||||
break;
|
||||
case 0x04:
|
||||
Sllv(instr);
|
||||
break;
|
||||
case 0x07:
|
||||
Srav(instr);
|
||||
break;
|
||||
case 0x08:
|
||||
Jr(instr);
|
||||
break;
|
||||
case 0x09:
|
||||
Jalr(instr);
|
||||
break;
|
||||
case 0x0a:
|
||||
Movz(instr);
|
||||
break;
|
||||
case 0x0b:
|
||||
Movn(instr);
|
||||
break;
|
||||
case 0x0f:
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sync.p\n");
|
||||
break;
|
||||
case 0x10:
|
||||
Mfhi(instr);
|
||||
break;
|
||||
case 0x12:
|
||||
Mflo(instr);
|
||||
break;
|
||||
case 0x14:
|
||||
Dsllv(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 0x21:
|
||||
Addu(instr);
|
||||
break;
|
||||
case 0x23:
|
||||
Subu(instr);
|
||||
break;
|
||||
case 0x24:
|
||||
And(instr);
|
||||
break;
|
||||
case 0x25:
|
||||
Or(instr);
|
||||
break;
|
||||
case 0x27:
|
||||
Nor(instr);
|
||||
break;
|
||||
case 0x2a:
|
||||
Slt(instr);
|
||||
break;
|
||||
case 0x2b:
|
||||
Sltu(instr);
|
||||
break;
|
||||
case 0x2d:
|
||||
Daddu(instr);
|
||||
break;
|
||||
case 0x38:
|
||||
Dsll(instr);
|
||||
break;
|
||||
case 0x3c:
|
||||
Dsll32(instr);
|
||||
break;
|
||||
case 0x3f:
|
||||
Dsra32(instr);
|
||||
break;
|
||||
default:
|
||||
printf("[emu/EE]: Unknown special instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x01:
|
||||
{
|
||||
opcode = (instr >> 16) & 0x1F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x00:
|
||||
Bltz(instr);
|
||||
break;
|
||||
case 0x01:
|
||||
Bgez(instr);
|
||||
break;
|
||||
default:
|
||||
printf("[emu/EE]: Unknown regimm instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x02:
|
||||
J(instr);
|
||||
break;
|
||||
case 0x03:
|
||||
Jal(instr);
|
||||
break;
|
||||
case 0x04:
|
||||
Beq(instr);
|
||||
break;
|
||||
case 0x05:
|
||||
Bne(instr);
|
||||
break;
|
||||
case 0x06:
|
||||
Blez(instr);
|
||||
break;
|
||||
case 0x07:
|
||||
Bgtz(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:
|
||||
{
|
||||
opcode = (instr >> 21) & 0x3F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x00:
|
||||
Mfc0(instr);
|
||||
break;
|
||||
case 0x04:
|
||||
Mtc0(instr);
|
||||
break;
|
||||
case 0x10:
|
||||
{
|
||||
opcode = instr & 0x3F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x02:
|
||||
Tlbwi(instr);
|
||||
break;
|
||||
default:
|
||||
printf("[emu/EE]: Unknown cop0 tlb instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("[emu/EE]: Unknown cop0 instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x11:
|
||||
{
|
||||
opcode = (instr >> 21) & 0x1F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x04:
|
||||
Mtc1(instr);
|
||||
break;
|
||||
case 0x06:
|
||||
break;
|
||||
case 0x10:
|
||||
{
|
||||
opcode = instr & 0x3F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x18:
|
||||
Addas(instr);
|
||||
break;
|
||||
default:
|
||||
printf("[emu/EE]: Unknown cop1.s instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("[emu/EE]: Unknown cop1 instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x12:
|
||||
{
|
||||
opcode = (instr >> 21) & 0x3F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x01:
|
||||
Qmfc2(instr);
|
||||
break;
|
||||
case 0x02:
|
||||
Cfc2(instr);
|
||||
break;
|
||||
case 0x05:
|
||||
Qmtc2(instr);
|
||||
break;
|
||||
case 0x06:
|
||||
Ctc2(instr);
|
||||
break;
|
||||
case 0x10 ... 0x1F:
|
||||
{
|
||||
opcode = instr & 0x3F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x2c:
|
||||
VectorUnit::VU0::Vsub(instr);
|
||||
break;
|
||||
case 0x30:
|
||||
VectorUnit::VU0::Viadd(instr);
|
||||
break;
|
||||
case 0x3C ... 0x3F:
|
||||
{
|
||||
opcode = (instr & 0x3) | ((instr >> 6) & 0x1F) << 2;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x35:
|
||||
VectorUnit::VU0::Vsqi(instr);
|
||||
break;
|
||||
case 0x3f:
|
||||
VectorUnit::VU0::Viswr(instr);
|
||||
break;
|
||||
default:
|
||||
printf("[emu/EE]: Unknown cop2 special2 instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("[emu/EE]: Unknown cop2 special1 instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("[emu/EE]: Unknown cop2 instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x14:
|
||||
Beql(instr);
|
||||
break;
|
||||
case 0x15:
|
||||
Bnel(instr);
|
||||
break;
|
||||
case 0x19:
|
||||
Daddiu(instr);
|
||||
break;
|
||||
case 0x1C:
|
||||
{
|
||||
opcode = instr & 0x3F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x12:
|
||||
Mflo1(instr);
|
||||
break;
|
||||
case 0x18:
|
||||
Mult1(instr);
|
||||
break;
|
||||
case 0x1b:
|
||||
Divu1(instr);
|
||||
break;
|
||||
case 0x29:
|
||||
{
|
||||
opcode = (instr >> 6) & 0x1F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x12:
|
||||
Por(instr);
|
||||
break;
|
||||
default:
|
||||
printf("[emu/EE]: Unknown mmi3 instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("[emu/EE]: Unknown mmi instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x1e:
|
||||
Lq(instr);
|
||||
break;
|
||||
case 0x1f:
|
||||
Sq(instr);
|
||||
break;
|
||||
case 0x20:
|
||||
Lb(instr);
|
||||
break;
|
||||
case 0x21:
|
||||
Lh(instr);
|
||||
break;
|
||||
case 0x23:
|
||||
Lw(instr);
|
||||
break;
|
||||
case 0x24:
|
||||
Lbu(instr);
|
||||
break;
|
||||
case 0x25:
|
||||
Lhu(instr);
|
||||
break;
|
||||
case 0x27:
|
||||
Lwu(instr);
|
||||
break;
|
||||
case 0x28:
|
||||
Sb(instr);
|
||||
break;
|
||||
case 0x29:
|
||||
Sh(instr);
|
||||
break;
|
||||
case 0x2b:
|
||||
Sw(instr);
|
||||
break;
|
||||
case 0x2f:
|
||||
if constexpr (CanDisassamble)
|
||||
printf("cache\n");
|
||||
break;
|
||||
case 0x37:
|
||||
Ld(instr);
|
||||
break;
|
||||
case 0x39:
|
||||
Swc1(instr);
|
||||
break;
|
||||
case 0x3f:
|
||||
Sd(instr);
|
||||
break;
|
||||
default:
|
||||
printf("[emu/EE]: Unknown instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cop0.count++;
|
||||
}
|
||||
}
|
||||
|
||||
extern float convert(uint32_t);
|
||||
|
||||
void EEInterpreter::Dump()
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
printf("[emu/EE]: %s\t->\t%s\n", Reg(i), print_128(regs[i]));
|
||||
for (int i = 0; i < 32; i++)
|
||||
printf("[emu/EE]: f%d\t->\t%f\n", i, convert(cop1_regs[i].u));
|
||||
printf("pc\t->\t0x%08x\n", pc);
|
||||
printf("next pc\t->\t0x%08x\n", next_pc);
|
||||
printf("hi\t->\t0x%08x\n", hi);
|
||||
printf("lo\t->\t0x%08x\n", lo);
|
||||
printf("hi1\t->\t0x%08x\n", hi1);
|
||||
printf("lo1\t->\t0x%08x\n", lo1);
|
||||
}
|
||||
|
||||
const uint32_t PAGE_SIZE = 4 * 1024;
|
||||
|
||||
EETLB::EETLB()
|
||||
{
|
||||
wrTable = new uintptr_t[0x100000];
|
||||
rdTable = new uintptr_t[0x100000];
|
||||
|
||||
memset(wrTable, 0, sizeof(uintptr_t)*0x100000);
|
||||
memset(rdTable, 0, sizeof(uintptr_t)*0x100000);
|
||||
|
||||
for (auto pageIndex = 0; pageIndex < 8192; pageIndex++)
|
||||
{
|
||||
const auto ptr = (uintptr_t)(&(Bus::GetRamPtr()[(pageIndex * PAGE_SIZE) & 0x1FFFFFF]));
|
||||
rdTable[pageIndex + 0x00000] = ptr;
|
||||
rdTable[pageIndex + 0x80000] = ptr;
|
||||
rdTable[pageIndex + 0xA0000] = ptr;
|
||||
wrTable[pageIndex + 0x00000] = ptr;
|
||||
wrTable[pageIndex + 0x80000] = ptr;
|
||||
wrTable[pageIndex + 0xA0000] = ptr;
|
||||
}
|
||||
|
||||
for (auto pageIndex = 0; pageIndex < 1024; pageIndex++)
|
||||
{
|
||||
const auto ptr = (uintptr_t)(&BiosRom[(pageIndex * PAGE_SIZE) & 0x1FFFFFF]);
|
||||
rdTable[pageIndex + 0x1FC00] = ptr;
|
||||
rdTable[pageIndex + 0x9FC00] = ptr;
|
||||
rdTable[pageIndex + 0xBFC00] = ptr;
|
||||
}
|
||||
|
||||
memset(tlb, 0, sizeof(tlb));
|
||||
}
|
333
src/emu/cpu/ee/ee_interpret.h
Normal file
333
src/emu/cpu/ee/ee_interpret.h
Normal file
|
@ -0,0 +1,333 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
class EETLB
|
||||
{
|
||||
public:
|
||||
uintptr_t* rdTable;
|
||||
uintptr_t* wrTable;
|
||||
|
||||
struct TlbEntry
|
||||
{
|
||||
union Entry
|
||||
{
|
||||
__uint128_t data;
|
||||
struct
|
||||
{
|
||||
__uint128_t v0 : 1,
|
||||
d0 : 1,
|
||||
c0 : 3,
|
||||
pfn0 : 20,
|
||||
v1 : 1,
|
||||
d1 : 1,
|
||||
c1 : 3,
|
||||
pfn1 : 20,
|
||||
s : 1,
|
||||
asid : 8,
|
||||
g : 1,
|
||||
vpn2 : 19,
|
||||
mask : 12;
|
||||
};
|
||||
} entry;
|
||||
uint32_t pageSize;
|
||||
uint32_t pageShift;
|
||||
} tlb[48];
|
||||
public:
|
||||
EETLB();
|
||||
|
||||
void Unmap(TlbEntry& entry);
|
||||
void DoRemap(int index);
|
||||
};
|
||||
|
||||
namespace EEInterpreter
|
||||
{
|
||||
|
||||
inline const char* Reg(int index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return "$zero";
|
||||
case 1:
|
||||
return "$at";
|
||||
case 2:
|
||||
return "$v0";
|
||||
case 3:
|
||||
return "$v1";
|
||||
case 4:
|
||||
return "$a0";
|
||||
case 5:
|
||||
return "$a1";
|
||||
case 6:
|
||||
return "$a2";
|
||||
case 7:
|
||||
return "$a3";
|
||||
case 8:
|
||||
return "$t0";
|
||||
case 9:
|
||||
return "$t1";
|
||||
case 10:
|
||||
return "$t2";
|
||||
case 11:
|
||||
return "$t3";
|
||||
case 12:
|
||||
return "$t4";
|
||||
case 13:
|
||||
return "$t5";
|
||||
case 14:
|
||||
return "$t6";
|
||||
case 15:
|
||||
return "$t7";
|
||||
case 16:
|
||||
return "$s0";
|
||||
case 17:
|
||||
return "$s1";
|
||||
case 18:
|
||||
return "$s2";
|
||||
case 19:
|
||||
return "$s3";
|
||||
case 20:
|
||||
return "$s4";
|
||||
case 21:
|
||||
return "$s5";
|
||||
case 22:
|
||||
return "$s6";
|
||||
case 23:
|
||||
return "$s7";
|
||||
case 24:
|
||||
return "$t8";
|
||||
case 25:
|
||||
return "$t9";
|
||||
case 26:
|
||||
return "$k0";
|
||||
case 27:
|
||||
return "$k1";
|
||||
case 28:
|
||||
return "$gp";
|
||||
case 29:
|
||||
return "$sp";
|
||||
case 30:
|
||||
return "$fp";
|
||||
case 31:
|
||||
return "$ra";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
union COP0Status
|
||||
{
|
||||
uint32_t value;
|
||||
struct
|
||||
{
|
||||
uint32_t ie : 1; /* Interrupt Enable */
|
||||
uint32_t exl : 1; /* Exception Level */
|
||||
uint32_t erl : 1; /* Error Level */
|
||||
uint32_t ksu : 2; /* Kernel/Supervisor/User Mode bits */
|
||||
uint32_t : 5;
|
||||
uint32_t im0 : 1; /* Int[1:0] signals */
|
||||
uint32_t im1 : 1;
|
||||
uint32_t bem : 1; /* Bus Error Mask */
|
||||
uint32_t : 2;
|
||||
uint32_t im7 : 1; /* Internal timer interrupt */
|
||||
uint32_t eie : 1; /* Enable IE */
|
||||
uint32_t edi : 1; /* EI/DI instruction Enable */
|
||||
uint32_t ch : 1; /* Cache Hit */
|
||||
uint32_t : 3;
|
||||
uint32_t bev : 1; /* Location of TLB refill */
|
||||
uint32_t dev : 1; /* Location of Performance counter */
|
||||
uint32_t : 2;
|
||||
uint32_t fr : 1; /* Additional floating point registers */
|
||||
uint32_t : 1;
|
||||
uint32_t cu : 4; /* Usability of each of the four coprocessors */
|
||||
};
|
||||
};
|
||||
|
||||
union COP0Cause
|
||||
{
|
||||
uint32_t value;
|
||||
struct
|
||||
{
|
||||
uint32_t : 2;
|
||||
uint32_t exccode : 5;
|
||||
uint32_t : 3;
|
||||
uint32_t ip0_pending : 1;
|
||||
uint32_t ip1_pending : 1;
|
||||
uint32_t siop : 1;
|
||||
uint32_t : 2;
|
||||
uint32_t timer_ip_pending : 1;
|
||||
uint32_t exc2 : 3;
|
||||
uint32_t : 9;
|
||||
uint32_t ce : 2;
|
||||
uint32_t bd2 : 1;
|
||||
uint32_t bd : 1;
|
||||
};
|
||||
};
|
||||
|
||||
enum OperatingMode
|
||||
{
|
||||
USER_MODE = 0b10,
|
||||
SUPERVISOR_MODE = 0b01,
|
||||
KERNEL_MODE = 0b00
|
||||
};
|
||||
|
||||
/* The COP0 registers */
|
||||
union COP0
|
||||
{
|
||||
uint32_t regs[32] = {};
|
||||
struct
|
||||
{
|
||||
uint32_t index;
|
||||
uint32_t random;
|
||||
uint32_t entry_lo0;
|
||||
uint32_t entry_lo1;
|
||||
uint32_t context;
|
||||
uint32_t page_mask;
|
||||
uint32_t wired;
|
||||
uint32_t reserved0[1];
|
||||
uint32_t bad_vaddr;
|
||||
uint32_t count;
|
||||
uint32_t entryhi;
|
||||
uint32_t compare;
|
||||
COP0Status status;
|
||||
COP0Cause cause;
|
||||
uint32_t epc;
|
||||
uint32_t prid;
|
||||
uint32_t config;
|
||||
uint32_t reserved1[6];
|
||||
uint32_t bad_paddr;
|
||||
uint32_t debug;
|
||||
uint32_t perf;
|
||||
uint32_t reserved2[2];
|
||||
uint32_t tag_lo;
|
||||
uint32_t tag_hi;
|
||||
uint32_t error_epc;
|
||||
uint32_t reserved3[1];
|
||||
};
|
||||
};
|
||||
|
||||
extern COP0 cop0;
|
||||
static constexpr bool CanDisassamble = false;
|
||||
|
||||
extern EETLB* tlb;
|
||||
|
||||
|
||||
union Cop1Reg
|
||||
{
|
||||
float f;
|
||||
uint32_t u;
|
||||
int32_t s;
|
||||
};
|
||||
|
||||
uint8_t Read8(uint32_t addr);
|
||||
uint16_t Read16(uint32_t addr);
|
||||
uint32_t Read32(uint32_t addr);
|
||||
uint64_t Read64(uint32_t addr);
|
||||
__uint128_t Read128(uint32_t addr);
|
||||
|
||||
void Write8(uint32_t addr, uint8_t data);
|
||||
void Write16(uint32_t addr, uint16_t data);
|
||||
void Write32(uint32_t addr, uint32_t data);
|
||||
void Write64(uint32_t addr, uint64_t data);
|
||||
void Write128(uint32_t addr, __uint128_t data);
|
||||
|
||||
void Reset();
|
||||
|
||||
void Clock(int cycles);
|
||||
void Dump();
|
||||
|
||||
// Normal
|
||||
void J(uint32_t instr); // 0x02
|
||||
void Jal(uint32_t instr); // 0x03
|
||||
void Beq(uint32_t instr); // 0x04
|
||||
void Bne(uint32_t instr); // 0x05
|
||||
void Blez(uint32_t instr); // 0x06
|
||||
void Bgtz(uint32_t instr); // 0x07
|
||||
void Addiu(uint32_t instr); // 0x09
|
||||
void Slti(uint32_t instr); // 0x0A
|
||||
void Sltiu(uint32_t instr); // 0x0B
|
||||
void Andi(uint32_t instr); // 0x0C
|
||||
void Ori(uint32_t instr); // 0x0D
|
||||
void Xori(uint32_t instr); // 0x0E
|
||||
void Lui(uint32_t instr); // 0x0F
|
||||
void Beql(uint32_t instr); // 0x14
|
||||
void Bnel(uint32_t instr); // 0x15
|
||||
void Daddiu(uint32_t instr); // 0x19
|
||||
void Lq(uint32_t instr); // 0x1e
|
||||
void Sq(uint32_t instr); // 0x1f
|
||||
void Lb(uint32_t instr); // 0x20
|
||||
void Lh(uint32_t instr); // 0x21
|
||||
void Lw(uint32_t instr); // 0x23
|
||||
void Lbu(uint32_t instr); // 0x24
|
||||
void Lhu(uint32_t instr); // 0x25
|
||||
void Lwu(uint32_t instr); // 0x27
|
||||
void Sb(uint32_t instr); // 0x28
|
||||
void Sh(uint32_t instr); // 0x29
|
||||
void Sw(uint32_t instr); // 0x2B
|
||||
void Swc1(uint32_t instr); // 0x31
|
||||
void Ld(uint32_t instr); // 0x37
|
||||
void Sd(uint32_t instr); // 0x3F
|
||||
|
||||
// Special
|
||||
void Sll(uint32_t instr); // 0x00
|
||||
void Srl(uint32_t instr); // 0x02
|
||||
void Sra(uint32_t instr); // 0x03
|
||||
void Sllv(uint32_t instr); // 0x04
|
||||
void Srav(uint32_t instr); // 0x07
|
||||
void Jr(uint32_t instr); // 0x08
|
||||
void Jalr(uint32_t instr); // 0x09
|
||||
void Movz(uint32_t instr); // 0x0a
|
||||
void Movn(uint32_t instr); // 0x0b
|
||||
void Mfhi(uint32_t instr); // 0x10
|
||||
void Mflo(uint32_t instr); // 0x12
|
||||
void Dsllv(uint32_t instr); // 0x14
|
||||
void Dsrav(uint32_t instr); // 0x17
|
||||
void Mult(uint32_t instr); // 0x18
|
||||
void Multu(uint32_t instr); // 0x19
|
||||
void Div(uint32_t instr); // 0x1A
|
||||
void Divu(uint32_t instr); // 0x1B
|
||||
void Addu(uint32_t instr); // 0x21
|
||||
void Subu(uint32_t instr); // 0x23
|
||||
void And(uint32_t instr); // 0x24
|
||||
void Or(uint32_t instr); // 0x25
|
||||
void Nor(uint32_t instr); // 0x27
|
||||
void Slt(uint32_t instr); // 0x2a
|
||||
void Sltu(uint32_t instr); // 0x2b
|
||||
void Daddu(uint32_t instr); // 0x2d
|
||||
void Dsll(uint32_t instr); // 0x38
|
||||
void Dsll32(uint32_t instr); // 0x3c
|
||||
void Dsra32(uint32_t instr); // 0x3f
|
||||
|
||||
// Regimm
|
||||
void Bltz(uint32_t instr); // 0x00
|
||||
void Bgez(uint32_t instr); // 0x01
|
||||
|
||||
// Cop0
|
||||
void Mfc0(uint32_t instr); // 0x00
|
||||
void Mtc0(uint32_t instr); // 0x04
|
||||
|
||||
// Cop0 TLB
|
||||
void Tlbwi(uint32_t instr); // 0x02
|
||||
|
||||
// MMI
|
||||
void Mflo1(uint32_t instr); // 0x12
|
||||
void Mult1(uint32_t instr); // 0x18
|
||||
void Divu1(uint32_t instr); // 0x1B
|
||||
|
||||
// MMI3
|
||||
void Por(uint32_t instr);
|
||||
|
||||
// COP2
|
||||
void Qmfc2(uint32_t instr); // 0x01
|
||||
void Cfc2(uint32_t instr); // 0x02
|
||||
void Qmtc2(uint32_t instr); // 0x05
|
||||
void Ctc2(uint32_t instr); // 0x06
|
||||
|
||||
// COP1
|
||||
void Mtc1(uint32_t instr); // 0x04
|
||||
|
||||
// COP1.S
|
||||
void Addas(uint32_t instr); // 0x18
|
||||
|
||||
}
|
675
src/emu/cpu/ee/ee_opcode.cpp
Normal file
675
src/emu/cpu/ee/ee_opcode.cpp
Normal file
|
@ -0,0 +1,675 @@
|
|||
#include "ee_interpret.h"
|
||||
|
||||
#include <util/uint128.h>
|
||||
#include <emu/memory/Bus.h>
|
||||
#include <emu/cpu/ee/vu.h>
|
||||
|
||||
#define _rs_ ((instr >> 21) & 0x1F)
|
||||
#define _rt_ ((instr >> 16) & 0x1F)
|
||||
#define _rd_ ((instr >> 11) & 0x1F)
|
||||
#define _sa_ ((instr >> 6) & 0x1F)
|
||||
|
||||
#define _ft_ ((instr >> 16) & 0x1F)
|
||||
#define _fs_ ((instr >> 11) & 0x1F)
|
||||
|
||||
#define _imm16_ (instr & 0xffff)
|
||||
#define _simm64_ ((int64_t)(int16_t)(instr & 0xffff))
|
||||
#define _simm32_ ((int32_t)(int16_t)(instr & 0xffff))
|
||||
#define _imm26_ (instr & 0x3ffffff)
|
||||
|
||||
extern float convert(uint32_t);
|
||||
|
||||
extern uint128_t regs[32];
|
||||
extern uint32_t pc, next_pc;
|
||||
extern uint32_t hi, lo;
|
||||
extern uint32_t hi1, lo1;
|
||||
EEInterpreter::Cop1Reg cop1_regs[32], accumulator;
|
||||
|
||||
EETLB *EEInterpreter::tlb;
|
||||
|
||||
void EEInterpreter::Mfc0(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u32[0] = cop0.regs[_rd_];
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: mfc0 %s, r%d\n", Reg(_rt_), _rd_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Mtc0(uint32_t instr)
|
||||
{
|
||||
cop0.regs[_rd_] = regs[_rt_].u32[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: mtc0 %s, r%d\n", Reg(_rt_), _rd_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Tlbwi(uint32_t)
|
||||
{
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: tlbwi\n");
|
||||
|
||||
tlb->DoRemap(cop0.regs[0]);
|
||||
}
|
||||
|
||||
void EEInterpreter::Slti(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u64[0] = ((int64_t)regs[_rs_].u64[0] < _simm64_);
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: slti %s, %s, 0x%04lx\n", Reg(_rt_), Reg(_rs_), _simm64_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Andi(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u64[0] = regs[_rs_].u64[0] & _imm16_;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: andi %s, %s, 0x%04x\n", Reg(_rt_), Reg(_rs_), _imm16_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Ori(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u64[0] = regs[_rs_].u64[0] | _imm16_;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: ori %s, %s, 0x%04x\n", Reg(_rt_), Reg(_rs_), _imm16_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Xori(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u64[0] = regs[_rs_].u64[0] ^ _imm16_;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: xori %s, %s, 0x%04x\n", Reg(_rt_), Reg(_rs_), _imm16_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Lui(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u64[0] = (_simm64_ << 16);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: lui %s, 0x%08lx\n", Reg(_rt_), (_simm64_ << 16));
|
||||
}
|
||||
|
||||
void EEInterpreter::Beql(uint32_t instr)
|
||||
{
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: beql %s, %s, 0x%08lx\n", Reg(_rs_), Reg(_rt_), next_pc + (_simm64_ << 2));
|
||||
|
||||
if (regs[_rs_].u64[0] == regs[_rt_].u64[0])
|
||||
next_pc = pc + (_simm64_ << 2);
|
||||
else
|
||||
{
|
||||
pc = next_pc;
|
||||
next_pc += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void EEInterpreter::Bnel(uint32_t instr)
|
||||
{
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: bnel %s, %s, 0x%08lx\n", Reg(_rs_), Reg(_rt_), next_pc + (_simm64_ << 2));
|
||||
|
||||
if (regs[_rs_].u64[0] != regs[_rt_].u64[0])
|
||||
next_pc = pc + (_simm64_ << 2);
|
||||
else
|
||||
{
|
||||
pc = next_pc;
|
||||
next_pc += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void EEInterpreter::Daddiu(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u64[0] = regs[_rs_].u64[0] + _simm64_;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: daddiu %s, %s, 0x%08lx\n", Reg(_rt_), Reg(_rs_), _simm64_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Lq(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
regs[_rt_].u128 = Read128(addr);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: lq %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Sq(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
Write128(addr, regs[_rt_].u128);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sq %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Lb(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
regs[_rt_].u64[0] = (int8_t)Read8(addr);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: lb %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Lh(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
regs[_rt_].u64[0] = (int16_t)Read16(addr);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: lh %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Lw(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
regs[_rt_].u64[0] = (int32_t)Read32(addr);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: lw %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
|
||||
void EEInterpreter::Lbu(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
regs[_rt_].u64[0] = Read8(addr);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: lbu %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Lhu(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
regs[_rt_].u64[0] = Read16(addr);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: lhu %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Lwu(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
regs[_rt_].u64[0] = Read32(addr);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: lwu %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Sb(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
Write8(addr, regs[_rt_].u8[0]);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sb %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Sh(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
Write16(addr, regs[_rt_].u8[0]);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sh %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Sw(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
Write32(addr, regs[_rt_].u32[0]);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sw %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Swc1(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
Write32(addr, cop1_regs[_rt_].u);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: swc1 f%d, 0x%08x(%s)\n", _rt_, _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Ld(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
regs[_rt_].u64[0] = Read64(addr);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: ld %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Sd(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
Write64(addr, regs[_rt_].u64[0]);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sd %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Sll(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (int64_t)(int32_t)(regs[_rt_].u32[0] << _sa_);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sll %s, %s, %d\n", Reg(_rd_), Reg(_rt_), _sa_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Srl(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (int64_t)(regs[_rt_].u32[0] >> _sa_);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: srl %s, %s, %d\n", Reg(_rd_), Reg(_rt_), _sa_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Sra(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (int64_t)((int32_t)regs[_rt_].u32[0] >> _sa_);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sra %s, %s, %d\n", Reg(_rd_), Reg(_rt_), _sa_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Sllv(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (regs[_rt_].u32[0] << (regs[_rs_].u32[0] & 0x3F));
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sllv %s, %s, %s\n", Reg(_rd_), Reg(_rt_), Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Srav(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (int64_t)((int32_t)regs[_rt_].u32[0] >> (regs[_rs_].u32[0] & 0x3F));
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: srav %s, %s, %s\n", Reg(_rd_), Reg(_rt_), Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Jr(uint32_t instr)
|
||||
{
|
||||
next_pc = regs[_rs_].u32[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: jr %s\n", Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Jalr(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u32[0] = next_pc;
|
||||
next_pc = regs[_rs_].u32[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: jalr %s, %s\n", Reg(_rd_), Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Movz(uint32_t instr)
|
||||
{
|
||||
if (regs[_rt_].u64[0] == 0) regs[_rd_].u64[0] = regs[_rs_].u64[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: movz %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Movn(uint32_t instr)
|
||||
{
|
||||
if (regs[_rt_].u64[0] != 0) regs[_rd_].u64[0] = regs[_rs_].u64[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: movn %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Sltiu(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u64[0] = (regs[_rs_].u64[0] < _imm16_);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sltiu %s, %s, 0x%08lx\n", Reg(_rt_), Reg(_rs_), (uint64_t)_simm64_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Mfhi(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = hi;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: mfhi %s\n", Reg(_rd_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Mflo(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = lo;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: mflo %s\n", Reg(_rd_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Dsllv(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (regs[_rt_].u64[0] << (regs[_rs_].u32[0] & 0x3F));
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: dsllv %s, %s, %s\n", Reg(_rd_), Reg(_rt_), Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Dsrav(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = ((int64_t)regs[_rt_].u64[0] >> (regs[_rs_].u32[0] & 0x3F));
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: dsrav %s, %s, %s\n", Reg(_rd_), Reg(_rt_), Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Mult(uint32_t instr)
|
||||
{
|
||||
uint64_t result = (int32_t)regs[_rs_].u32[0] * (int32_t)regs[_rt_].u32[0];
|
||||
|
||||
lo = regs[_rd_].u64[0] = (int64_t)(int32_t)result;
|
||||
hi = (int32_t)(result >> 32);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: mult %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Multu(uint32_t instr)
|
||||
{
|
||||
uint64_t result = regs[_rs_].u32[0] * regs[_rt_].u32[0];
|
||||
|
||||
lo = regs[_rd_].u64[0] = (int64_t)(int32_t)result;
|
||||
hi = (int32_t)(result >> 32);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: multu %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Div(uint32_t instr)
|
||||
{
|
||||
int64_t numerator = regs[_rs_].u64[0];
|
||||
int64_t denominator = regs[_rt_].u64[0];
|
||||
|
||||
if (numerator == (int64_t)0x80000000 && denominator == -1)
|
||||
{
|
||||
lo = 0x80000000;
|
||||
hi = 0xFFFFFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
lo = numerator / denominator;
|
||||
hi = numerator % denominator;
|
||||
}
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: div %s, %s\n", Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Divu(uint32_t instr)
|
||||
{
|
||||
if (regs[_rt_].u32[0] == 0)
|
||||
{
|
||||
lo = 0xffffffff;
|
||||
hi = regs[_rs_].u32[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
lo = regs[_rs_].u32[0] / regs[_rt_].u32[0];
|
||||
hi = regs[_rs_].u32[0] % regs[_rt_].u32[0];
|
||||
}
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: divu %s, %s\n", Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Addu(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (int32_t)regs[_rs_].u32[0] + (int32_t)regs[_rt_].u32[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: addu %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Subu(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (int64_t)regs[_rs_].u64[0] - (int64_t)regs[_rt_].u64[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: subu %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::And(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = regs[_rs_].u64[0] & regs[_rt_].u64[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: and %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Or(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = regs[_rs_].u64[0] | regs[_rt_].u64[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: or %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Nor(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = ~(regs[_rs_].u64[0] | regs[_rt_].u64[0]);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: nor %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Daddu(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = regs[_rs_].u64[0] + regs[_rt_].u64[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: daddu %s, %s, %s (0x%08lx)\n", Reg(_rd_), Reg(_rs_), Reg(_rt_), regs[_rd_].u64[0]);
|
||||
}
|
||||
|
||||
void EEInterpreter::Dsll(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (int64_t)(regs[_rt_].u64[0] << _sa_);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: dsll %s, %s, %d\n", Reg(_rd_), Reg(_rt_), _sa_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Dsll32(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (int64_t)(regs[_rt_].u64[0] << (_sa_ + 32));
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: dsll32 %s, %s, %d\n", Reg(_rd_), Reg(_rt_), _sa_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Dsra32(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = ((int64_t)regs[_rt_].u64[0] >> (_sa_ + 32));
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: dsra32 %s, %s, %d\n", Reg(_rd_), Reg(_rt_), _sa_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Slt(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = ((int64_t)regs[_rs_].u64[0] < (int64_t)regs[_rt_].u64[0]);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: slt %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Sltu(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (regs[_rs_].u64[0] < regs[_rt_].u64[0]);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sltu %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Bltz(uint32_t instr)
|
||||
{
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: bltz %s, 0x%08lx\n", Reg(_rs_), pc + (_simm64_ << 2));
|
||||
|
||||
if ((int64_t)regs[_rs_].u64[0] < 0)
|
||||
next_pc = pc + (_simm64_ << 2);
|
||||
}
|
||||
|
||||
void EEInterpreter::Bgez(uint32_t instr)
|
||||
{
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: bgez %s, 0x%08lx\n", Reg(_rs_), pc + (_simm64_ << 2));
|
||||
|
||||
if ((int64_t)regs[_rs_].u64[0] >= 0)
|
||||
next_pc = pc + (_simm64_ << 2);
|
||||
}
|
||||
|
||||
|
||||
void EEInterpreter::J(uint32_t instr)
|
||||
{
|
||||
next_pc = (next_pc & 0xf0000000) | _imm26_ << 2;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: j 0x%08x\n", next_pc);
|
||||
}
|
||||
|
||||
void EEInterpreter::Jal(uint32_t instr)
|
||||
{
|
||||
regs[31].u32[0] = next_pc;
|
||||
next_pc = (next_pc & 0xf0000000) | _imm26_ << 2;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: jal 0x%08x\n", next_pc);
|
||||
}
|
||||
|
||||
void EEInterpreter::Beq(uint32_t instr)
|
||||
{
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: beq %s, %s, 0x%08lx\n", Reg(_rs_), Reg(_rt_), next_pc + (_simm64_ << 2));
|
||||
|
||||
if (regs[_rs_].u64[0] == regs[_rt_].u64[0])
|
||||
next_pc = pc + (_simm64_ << 2);
|
||||
}
|
||||
|
||||
void EEInterpreter::Bne(uint32_t instr)
|
||||
{
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: bne %s, %s, 0x%08lx\n", Reg(_rs_), Reg(_rt_), pc + (_simm64_ << 2));
|
||||
|
||||
if (regs[_rs_].u64[0] != regs[_rt_].u64[0])
|
||||
next_pc = pc + (_simm64_ << 2);
|
||||
}
|
||||
|
||||
void EEInterpreter::Blez(uint32_t instr)
|
||||
{
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: blez %s, 0x%08lx\n", Reg(_rs_), pc + (_simm64_ << 2));
|
||||
|
||||
if ((int64_t)regs[_rs_].u64[0] <= 0)
|
||||
next_pc = pc + (_simm64_ << 2);
|
||||
}
|
||||
|
||||
void EEInterpreter::Bgtz(uint32_t instr)
|
||||
{
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: bgtz %s, 0x%08lx\n", Reg(_rs_), pc + (_simm64_ << 2));
|
||||
|
||||
if ((int64_t)regs[_rs_].u64[0] > 0)
|
||||
next_pc = pc + (_simm64_ << 2);
|
||||
}
|
||||
|
||||
void EEInterpreter::Addiu(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u64[0] = (int32_t)regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: addiu %s, %s, 0x%08x\n", Reg(_rt_), Reg(_rs_), _simm32_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Mflo1(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = lo1;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: mflo1 %s\n", Reg(_rd_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Divu1(uint32_t instr)
|
||||
{
|
||||
lo1 = regs[_rs_].u32[0] / regs[_rt_].u32[0];
|
||||
hi1 = regs[_rs_].u32[0] % regs[_rt_].u32[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: divu1 %s, %s\n", Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Mult1(uint32_t instr)
|
||||
{
|
||||
uint64_t result = (int32_t)regs[_rs_].u32[0] * (int32_t)regs[_rt_].u32[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: mult1 %s, %s, %s (0x%08x, 0x%08x)\n", Reg(_rd_), Reg(_rs_), Reg(_rt_), (int32_t)regs[_rs_].u32[0], (int32_t)regs[_rt_].u32[0]);
|
||||
|
||||
lo1 = regs[_rd_].u64[0] = (int64_t)(int32_t)result;
|
||||
hi1 = (int32_t)(result >> 32);
|
||||
}
|
||||
|
||||
void EEInterpreter::Por(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u128 = regs[_rs_].u128 | regs[_rt_].u128;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: por %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Qmfc2(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u128 = VectorUnit::VU0::ReadReg(_rd_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Cfc2(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u64[0] = (int64_t)(int32_t)VectorUnit::VU0::ReadControl(_rd_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Qmtc2(uint32_t instr)
|
||||
{
|
||||
VectorUnit::VU0::WriteReg(_rd_, regs[_rt_].u128);
|
||||
}
|
||||
|
||||
void EEInterpreter::Ctc2(uint32_t instr)
|
||||
{
|
||||
VectorUnit::VU0::WriteControl(_rd_, regs[_rt_].u32[0]);
|
||||
}
|
||||
|
||||
void EEInterpreter::Mtc1(uint32_t instr)
|
||||
{
|
||||
cop1_regs[_rs_].u = regs[_rt_].u32[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: mtc1 %s, f%d\n", Reg(_rt_), _rs_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Addas(uint32_t instr)
|
||||
{
|
||||
float op1 = convert(cop1_regs[_fs_].u);
|
||||
float op2 = convert(cop1_regs[_ft_].u);
|
||||
accumulator.f = op1 + op2;
|
||||
}
|
|
@ -1,5 +1,10 @@
|
|||
#include "vu.h"
|
||||
#include <fstream>
|
||||
#include <emu/memory/Bus.h>
|
||||
#include <emu/cpu/ee/EmotionEngine.h>
|
||||
#include <cassert>
|
||||
|
||||
extern float convert(uint32_t value);
|
||||
|
||||
namespace VectorUnit
|
||||
{
|
||||
|
@ -19,9 +24,33 @@ void WriteDataMem128(int vector, uint32_t addr, uint128_t _data)
|
|||
|
||||
addr &= data_address_mask[vector];
|
||||
|
||||
if (vector == 0 && (addr >= 0x4000 && addr <= 0x43ff))
|
||||
{
|
||||
printf("Unhandled write to VU1 register 0x%04x\n", addr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
*(uint128_t*)&data[vector][addr] = _data;
|
||||
}
|
||||
|
||||
void WriteDataMem32(int vector, uint32_t addr, uint32_t _data)
|
||||
{
|
||||
if (vector == 1)
|
||||
addr = (addr - 0x1100C000);
|
||||
else
|
||||
addr = (addr - 0x11004000);
|
||||
|
||||
addr &= data_address_mask[vector];
|
||||
|
||||
if (vector == 0 && (addr >= 0x4000 && addr <= 0x43ff))
|
||||
{
|
||||
printf("Unhandled write to VU1 register 0x%04x\n", addr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
*(uint32_t*)&data[vector][addr] = _data;
|
||||
}
|
||||
|
||||
void WriteCodeMem128(int vector, uint32_t addr, uint128_t data)
|
||||
{
|
||||
if (vector == 1)
|
||||
|
@ -55,11 +84,557 @@ void Dump()
|
|||
out_file << code[0][i];
|
||||
}
|
||||
|
||||
out_file.close();
|
||||
out_file.open("vu0_data.bin");
|
||||
|
||||
for (int i = 0; i < 0x4000; i++)
|
||||
{
|
||||
out_file << data[0][i];
|
||||
}
|
||||
|
||||
out_file.close();
|
||||
out_file.open("vu1_code.bin");
|
||||
for (int i = 0; i < 0x4000; i++)
|
||||
{
|
||||
out_file << code[1][i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
printf("[emu/VU0]: VI%02d:\t->\t0x%04x\n", i, VU0::vu0_state.vi[i]);
|
||||
for (int i = 0; i < 32; i++)
|
||||
printf("[emu/VU0]: VF%02d:\t->\t{x = %f, y = %f, z = %f, w = %f}\n", i, convert(VU0::vu0_state.vf[i].xi), convert(VU0::vu0_state.vf[i].yi), convert(VU0::vu0_state.vf[i].zi), convert(VU0::vu0_state.vf[i].wi));
|
||||
printf("[emu/VU0]: I:\t->\t%f\n", VU0::vu0_state.i);
|
||||
}
|
||||
|
||||
namespace VU0
|
||||
{
|
||||
|
||||
VectorState vu0_state;
|
||||
|
||||
uint32_t ReadControl(int index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 1 ... 15:
|
||||
return vu0_state.vi[index];
|
||||
case 28:
|
||||
return vu0_state.fbrst;
|
||||
default:
|
||||
printf("[emu/VU0]: Read from unknown control register %d\n", index);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteControl(int index, uint32_t data)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 1 ... 15:
|
||||
vu0_state.vi[index] = data;
|
||||
break;
|
||||
case 16:
|
||||
vu0_state.status = data & 0xFFF;
|
||||
break;
|
||||
case 18:
|
||||
vu0_state.clipping.val = data & 0xFFFFFF;
|
||||
break;
|
||||
case 20:
|
||||
vu0_state.r = data & 0x7FFFFF;
|
||||
break;
|
||||
case 21:
|
||||
vu0_state.i = data;
|
||||
break;
|
||||
case 22:
|
||||
vu0_state.q = data;
|
||||
break;
|
||||
case 27:
|
||||
vu0_state.cmsar0 = data;
|
||||
break;
|
||||
case 28:
|
||||
vu0_state.fbrst = data & 0xC0C;
|
||||
break;
|
||||
default:
|
||||
printf("[emu/VU0]: Write to unknown control register %d\n", index);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
__uint128_t ReadReg(int index)
|
||||
{
|
||||
return vu0_state.vf[index].u128.u128;
|
||||
}
|
||||
|
||||
void WriteReg(int index, __uint128_t val)
|
||||
{
|
||||
vu0_state.vf[index].u128.u128 = val;
|
||||
}
|
||||
|
||||
void LQC2(uint32_t instr)
|
||||
{
|
||||
int32_t offs = (int32_t)(int16_t)(instr & 0xffff);
|
||||
|
||||
uint8_t base = (instr >> 21) & 0x1F;
|
||||
uint8_t ft = (instr >> 16) & 0x1F;
|
||||
|
||||
vu0_state.vf[ft].u128 = Bus::Read128(EmotionEngine::GetState()->regs[base].u32[0]+offs);
|
||||
}
|
||||
|
||||
void SQC2(uint32_t instr)
|
||||
{
|
||||
int32_t offs = (int32_t)(int16_t)(instr & 0xffff);
|
||||
|
||||
uint8_t base = (instr >> 21) & 0x1F;
|
||||
uint8_t ft = (instr >> 16) & 0x1F;
|
||||
|
||||
Bus::Write128(EmotionEngine::GetState()->regs[base].u32[0]+offs, vu0_state.vf[ft].u128);
|
||||
}
|
||||
|
||||
void Vmaddz(uint32_t instr)
|
||||
{
|
||||
uint8_t dest = (instr >> 21) & 0xf;
|
||||
bool x = (dest >> 3) & 1;
|
||||
bool y = (dest >> 2) & 1;
|
||||
bool z = (dest >> 1) & 1;
|
||||
bool w = (dest >> 0) & 1;
|
||||
|
||||
std::string dest_;
|
||||
if (x)
|
||||
dest_ += "x";
|
||||
if (y)
|
||||
dest_ += "y";
|
||||
if (z)
|
||||
dest_ += "z";
|
||||
if (w)
|
||||
dest_ += "w";
|
||||
|
||||
int fd = (instr >> 6) & 0x1F;
|
||||
int ft = (instr >> 16) & 0x1F;
|
||||
int fs = (instr >> 11) & 0x1F;
|
||||
|
||||
float op = convert(vu0_state.vf[ft].zi);
|
||||
|
||||
if (x)
|
||||
{
|
||||
vu0_state.vf[fd].x = convert(vu0_state.acc.xi) + (convert(vu0_state.vf[fs].xi) * op);
|
||||
}
|
||||
if (y)
|
||||
{
|
||||
vu0_state.vf[fd].y = convert(vu0_state.acc.yi) + (convert(vu0_state.vf[fs].yi) * op);
|
||||
}
|
||||
if (z)
|
||||
{
|
||||
vu0_state.vf[fd].z = convert(vu0_state.acc.zi) + (convert(vu0_state.vf[fs].zi) * op);
|
||||
}
|
||||
if (w)
|
||||
{
|
||||
vu0_state.vf[fd].w = convert(vu0_state.acc.wi) + (convert(vu0_state.vf[fs].wi) * op);
|
||||
}
|
||||
|
||||
printf("vmaddz.%s vf%02d.%s, vf%02d.%s, vf%02dz\n", dest_.c_str(), fd, dest_.c_str(), fs, dest_.c_str(), ft);
|
||||
}
|
||||
|
||||
void Vmaddw(uint32_t instr)
|
||||
{
|
||||
uint8_t dest = (instr >> 21) & 0xf;
|
||||
bool x = (dest >> 3) & 1;
|
||||
bool y = (dest >> 2) & 1;
|
||||
bool z = (dest >> 1) & 1;
|
||||
bool w = (dest >> 0) & 1;
|
||||
|
||||
std::string dest_;
|
||||
if (x)
|
||||
dest_ += "x";
|
||||
if (y)
|
||||
dest_ += "y";
|
||||
if (z)
|
||||
dest_ += "z";
|
||||
if (w)
|
||||
dest_ += "w";
|
||||
|
||||
int fd = (instr >> 6) & 0x1F;
|
||||
int ft = (instr >> 16) & 0x1F;
|
||||
int fs = (instr >> 11) & 0x1F;
|
||||
|
||||
float op = convert(vu0_state.vf[ft].wi);
|
||||
|
||||
if (x)
|
||||
{
|
||||
vu0_state.vf[fd].x = convert(vu0_state.acc.xi) + (convert(vu0_state.vf[fs].xi) * op);
|
||||
}
|
||||
if (y)
|
||||
{
|
||||
vu0_state.vf[fd].y = convert(vu0_state.acc.yi) + (convert(vu0_state.vf[fs].yi) * op);
|
||||
}
|
||||
if (z)
|
||||
{
|
||||
vu0_state.vf[fd].z = convert(vu0_state.acc.zi) + (convert(vu0_state.vf[fs].zi) * op);
|
||||
}
|
||||
if (w)
|
||||
{
|
||||
vu0_state.vf[fd].w = convert(vu0_state.acc.wi) + (convert(vu0_state.vf[fs].wi) * op);
|
||||
}
|
||||
|
||||
printf("vmaddw.%s vf%02d.%s, vf%02d.%s, vf%02dw\n", dest_.c_str(), fd, dest_.c_str(), fs, dest_.c_str(), ft);
|
||||
}
|
||||
|
||||
void Vsub(uint32_t instr)
|
||||
{
|
||||
uint8_t dest = (instr >> 21) & 0xf;
|
||||
bool x = (dest >> 3) & 1;
|
||||
bool y = (dest >> 2) & 1;
|
||||
bool z = (dest >> 1) & 1;
|
||||
bool w = (dest >> 0) & 1;
|
||||
|
||||
std::string dest_;
|
||||
if (x)
|
||||
dest_ += "x";
|
||||
if (y)
|
||||
dest_ += "y";
|
||||
if (z)
|
||||
dest_ += "z";
|
||||
if (w)
|
||||
dest_ += "w";
|
||||
|
||||
int ft = (instr >> 16) & 0x1F;
|
||||
int fs = (instr >> 11) & 0x1F;
|
||||
int fd = (instr >> 6) & 0x1F;
|
||||
|
||||
if (x)
|
||||
vu0_state.vf[fd].x = convert(vu0_state.vf[fs].xi) - convert(vu0_state.vf[ft].xi);
|
||||
if (y)
|
||||
vu0_state.vf[fd].y = convert(vu0_state.vf[fs].yi) - convert(vu0_state.vf[ft].yi);
|
||||
if (z)
|
||||
vu0_state.vf[fd].z = convert(vu0_state.vf[fs].zi) - convert(vu0_state.vf[ft].zi);
|
||||
if (w)
|
||||
vu0_state.vf[fd].w = convert(vu0_state.vf[fs].wi) - convert(vu0_state.vf[ft].wi);
|
||||
|
||||
printf("vsub.%s vf%02d.%s, vf%02d.%s, vf%02d.%s\n", dest_.c_str(), fd, dest_.c_str(), fs, dest_.c_str(), ft, dest_.c_str());
|
||||
|
||||
// TODO: Handle VU0 flags
|
||||
}
|
||||
|
||||
void Viadd(uint32_t instr)
|
||||
{
|
||||
int it = (instr >> 16) & 0x1F;
|
||||
int is = (instr >> 11) & 0x1F;
|
||||
int id = (instr >> 6) & 0x1F;
|
||||
|
||||
vu0_state.vi[id] = vu0_state.vi[is] + vu0_state.vi[it];
|
||||
|
||||
printf("viadd vi%02d, vi%02d, vi%02d\n", id, is, it);
|
||||
}
|
||||
|
||||
void Vmaddax(uint32_t instr)
|
||||
{
|
||||
uint8_t dest = (instr >> 21) & 0xf;
|
||||
bool x = (dest >> 3) & 1;
|
||||
bool y = (dest >> 2) & 1;
|
||||
bool z = (dest >> 1) & 1;
|
||||
bool w = (dest >> 0) & 1;
|
||||
|
||||
std::string dest_;
|
||||
if (x)
|
||||
dest_ += "x";
|
||||
if (y)
|
||||
dest_ += "y";
|
||||
if (z)
|
||||
dest_ += "z";
|
||||
if (w)
|
||||
dest_ += "w";
|
||||
|
||||
int ft = (instr >> 16) & 0x1F;
|
||||
int fs = (instr >> 11) & 0x1F;
|
||||
|
||||
float op = convert(vu0_state.vf[ft].xi);
|
||||
|
||||
if (x)
|
||||
{
|
||||
vu0_state.acc.x = convert(vu0_state.acc.xi) + (convert(vu0_state.vf[fs].xi) * op);
|
||||
}
|
||||
if (y)
|
||||
{
|
||||
vu0_state.acc.y = convert(vu0_state.acc.yi) + (convert(vu0_state.vf[fs].yi) * op);
|
||||
}
|
||||
if (z)
|
||||
{
|
||||
vu0_state.acc.z = convert(vu0_state.acc.zi) + (convert(vu0_state.vf[fs].zi) * op);
|
||||
}
|
||||
if (w)
|
||||
{
|
||||
vu0_state.acc.w = convert(vu0_state.acc.wi) + (convert(vu0_state.vf[fs].wi) * op);
|
||||
}
|
||||
|
||||
printf("vmaddax.%s acc, vf%02d.%s, vf%02dx\n", dest_.c_str(), fs, dest_.c_str(), ft);
|
||||
}
|
||||
|
||||
void Vmadday(uint32_t instr)
|
||||
{
|
||||
uint8_t dest = (instr >> 21) & 0xf;
|
||||
bool x = (dest >> 3) & 1;
|
||||
bool y = (dest >> 2) & 1;
|
||||
bool z = (dest >> 1) & 1;
|
||||
bool w = (dest >> 0) & 1;
|
||||
|
||||
std::string dest_;
|
||||
if (x)
|
||||
dest_ += "x";
|
||||
if (y)
|
||||
dest_ += "y";
|
||||
if (z)
|
||||
dest_ += "z";
|
||||
if (w)
|
||||
dest_ += "w";
|
||||
|
||||
int ft = (instr >> 16) & 0x1F;
|
||||
int fs = (instr >> 11) & 0x1F;
|
||||
|
||||
float op = convert(vu0_state.vf[ft].yi);
|
||||
|
||||
if (x)
|
||||
{
|
||||
vu0_state.acc.x = convert(vu0_state.acc.xi) + (convert(vu0_state.vf[fs].xi) * op);
|
||||
}
|
||||
if (y)
|
||||
{
|
||||
vu0_state.acc.y = convert(vu0_state.acc.yi) + (convert(vu0_state.vf[fs].yi) * op);
|
||||
}
|
||||
if (z)
|
||||
{
|
||||
vu0_state.acc.z = convert(vu0_state.acc.zi) + (convert(vu0_state.vf[fs].zi) * op);
|
||||
}
|
||||
if (w)
|
||||
{
|
||||
vu0_state.acc.w = convert(vu0_state.acc.wi) + (convert(vu0_state.vf[fs].wi) * op);
|
||||
}
|
||||
|
||||
printf("vmadday.%s acc, vf%02d.%s, vf%02dy\n", dest_.c_str(), fs, dest_.c_str(), ft);
|
||||
}
|
||||
|
||||
void Vmaddaz(uint32_t instr)
|
||||
{
|
||||
uint8_t dest = (instr >> 21) & 0xf;
|
||||
bool x = (dest >> 3) & 1;
|
||||
bool y = (dest >> 2) & 1;
|
||||
bool z = (dest >> 1) & 1;
|
||||
bool w = (dest >> 0) & 1;
|
||||
|
||||
std::string dest_;
|
||||
if (x)
|
||||
dest_ += "x";
|
||||
if (y)
|
||||
dest_ += "y";
|
||||
if (z)
|
||||
dest_ += "z";
|
||||
if (w)
|
||||
dest_ += "w";
|
||||
|
||||
int ft = (instr >> 16) & 0x1F;
|
||||
int fs = (instr >> 11) & 0x1F;
|
||||
|
||||
float op = convert(vu0_state.vf[ft].zi);
|
||||
|
||||
if (x)
|
||||
{
|
||||
vu0_state.acc.x = convert(vu0_state.acc.xi) + (convert(vu0_state.vf[fs].xi) * op);
|
||||
}
|
||||
if (y)
|
||||
{
|
||||
vu0_state.acc.y = convert(vu0_state.acc.yi) + (convert(vu0_state.vf[fs].yi) * op);
|
||||
}
|
||||
if (z)
|
||||
{
|
||||
vu0_state.acc.z = convert(vu0_state.acc.zi) + (convert(vu0_state.vf[fs].zi) * op);
|
||||
}
|
||||
if (w)
|
||||
{
|
||||
vu0_state.acc.w = convert(vu0_state.acc.wi) + (convert(vu0_state.vf[fs].wi) * op);
|
||||
}
|
||||
|
||||
printf("vmaddaz.%s acc, vf%02d.%s, vf%02dz\n", dest_.c_str(), fs, dest_.c_str(), ft);
|
||||
}
|
||||
|
||||
void Vmulax(uint32_t instr)
|
||||
{
|
||||
uint8_t dest = (instr >> 21) & 0xf;
|
||||
bool x = (dest >> 3) & 1;
|
||||
bool y = (dest >> 2) & 1;
|
||||
bool z = (dest >> 1) & 1;
|
||||
bool w = (dest >> 0) & 1;
|
||||
|
||||
std::string dest_;
|
||||
if (x)
|
||||
dest_ += "x";
|
||||
if (y)
|
||||
dest_ += "y";
|
||||
if (z)
|
||||
dest_ += "z";
|
||||
if (w)
|
||||
dest_ += "w";
|
||||
|
||||
int ft = (instr >> 16) & 0x1F;
|
||||
int fs = (instr >> 11) & 0x1F;
|
||||
|
||||
float op = convert(vu0_state.vf[ft].xi);
|
||||
|
||||
if (x)
|
||||
{
|
||||
vu0_state.acc.x = convert(vu0_state.vf[fs].xi) * op;
|
||||
}
|
||||
if (y)
|
||||
{
|
||||
vu0_state.acc.y = convert(vu0_state.vf[fs].yi) * op;
|
||||
}
|
||||
if (z)
|
||||
{
|
||||
vu0_state.acc.z = convert(vu0_state.vf[fs].zi) * op;
|
||||
}
|
||||
if (w)
|
||||
{
|
||||
vu0_state.acc.w = convert(vu0_state.vf[fs].wi) * op;
|
||||
}
|
||||
|
||||
printf("vmulax.%s acc, vf%02d.%s, vf%02dx\n", dest_.c_str(), fs, dest_.c_str(), ft);
|
||||
}
|
||||
|
||||
void Vmulaw(uint32_t instr)
|
||||
{
|
||||
uint8_t dest = (instr >> 21) & 0xf;
|
||||
bool x = (dest >> 3) & 1;
|
||||
bool y = (dest >> 2) & 1;
|
||||
bool z = (dest >> 1) & 1;
|
||||
bool w = (dest >> 0) & 1;
|
||||
|
||||
std::string dest_;
|
||||
if (x)
|
||||
dest_ += "x";
|
||||
if (y)
|
||||
dest_ += "y";
|
||||
if (z)
|
||||
dest_ += "z";
|
||||
if (w)
|
||||
dest_ += "w";
|
||||
|
||||
int ft = (instr >> 16) & 0x1F;
|
||||
int fs = (instr >> 11) & 0x1F;
|
||||
|
||||
float op = convert(vu0_state.vf[ft].wi);
|
||||
|
||||
if (x)
|
||||
{
|
||||
vu0_state.acc.x = convert(vu0_state.vf[fs].xi) * op;
|
||||
}
|
||||
if (y)
|
||||
{
|
||||
vu0_state.acc.y = convert(vu0_state.vf[fs].yi) * op;
|
||||
}
|
||||
if (z)
|
||||
{
|
||||
vu0_state.acc.z = convert(vu0_state.vf[fs].zi) * op;
|
||||
}
|
||||
if (w)
|
||||
{
|
||||
vu0_state.acc.w = convert(vu0_state.vf[fs].wi) * op;
|
||||
}
|
||||
|
||||
printf("vmulaw.%s acc, vf%02d.%s, vf%02dw\n", dest_.c_str(), fs, dest_.c_str(), ft);
|
||||
}
|
||||
|
||||
void Vclipw(uint32_t instr)
|
||||
{
|
||||
vu0_state.clipping.val <<= 6;
|
||||
|
||||
int ft = (instr >> 16) & 0x1F;
|
||||
int fs = (instr >> 11) & 0x1F;
|
||||
|
||||
float value = fabs(convert(vu0_state.vf[ft].wi));
|
||||
|
||||
float x = convert(vu0_state.vf[fs].xi);
|
||||
float y = convert(vu0_state.vf[fs].yi);
|
||||
float z = convert(vu0_state.vf[fs].zi);
|
||||
|
||||
vu0_state.clipping.val |= (x > +value);
|
||||
vu0_state.clipping.val |= (x < -value) << 1;
|
||||
vu0_state.clipping.val |= (y > +value) << 2;
|
||||
vu0_state.clipping.val |= (y > -value) << 3;
|
||||
vu0_state.clipping.val |= (z > +value) << 4;
|
||||
vu0_state.clipping.val |= (z > -value) << 5;
|
||||
|
||||
printf("vclipw.xyz vf%02d.xyz, vf%02d.w\n", fs, ft);
|
||||
}
|
||||
|
||||
void Vsqi(uint32_t instr)
|
||||
{
|
||||
uint8_t dest = (instr >> 21) & 0xf;
|
||||
bool x = (dest >> 3) & 1;
|
||||
bool y = (dest >> 2) & 1;
|
||||
bool z = (dest >> 1) & 1;
|
||||
bool w = (dest >> 0) & 1;
|
||||
|
||||
std::string dest_;
|
||||
if (x)
|
||||
dest_ += "x";
|
||||
if (y)
|
||||
dest_ += "y";
|
||||
if (z)
|
||||
dest_ += "z";
|
||||
if (w)
|
||||
dest_ += "w";
|
||||
|
||||
int it = (instr >> 16) & 0x1F;
|
||||
int fs = (instr >> 11) & 0x1F;
|
||||
|
||||
auto& f = vu0_state.vf[fs];
|
||||
|
||||
if (x)
|
||||
WriteDataMem32(0, vu0_state.vi[it]+0x0, f.x);
|
||||
if (y)
|
||||
WriteDataMem32(0, vu0_state.vi[it]+0x4, f.y);
|
||||
if (z)
|
||||
WriteDataMem32(0, vu0_state.vi[it]+0x8, f.z);
|
||||
if (w)
|
||||
WriteDataMem32(0, vu0_state.vi[it]+0xc, f.w);
|
||||
|
||||
vu0_state.vi[it] += 0x10;
|
||||
|
||||
printf("sqi.%s vf%02d, (vi%02d++).%s\n", dest_.c_str(), fs, it, dest_.c_str());
|
||||
}
|
||||
|
||||
void Viswr(uint32_t instr)
|
||||
{
|
||||
uint8_t dest = (instr >> 21) & 0xf;
|
||||
bool x = (dest >> 3) & 1;
|
||||
bool y = (dest >> 2) & 1;
|
||||
bool z = (dest >> 1) & 1;
|
||||
bool w = (dest >> 0) & 1;
|
||||
|
||||
std::string dest_;
|
||||
if (x)
|
||||
dest_ += "x";
|
||||
if (y)
|
||||
dest_ += "y";
|
||||
if (z)
|
||||
dest_ += "z";
|
||||
if (w)
|
||||
dest_ += "w";
|
||||
|
||||
// Make sure only one dest bit is set
|
||||
assert((x && !y && !z && !w) || (!x && y && !z && !w) || (!x && !y && z && !w) || (!x && !y && !z && w));
|
||||
|
||||
int it = (instr >> 16) & 0x1F;
|
||||
int is = (instr >> 11) & 0x1F;
|
||||
|
||||
printf("viswr.%s vi%02d, (vi%02d).%s\n", dest_.c_str(), it, is, dest_.c_str());
|
||||
|
||||
uint16_t addr = vu0_state.vi[is];
|
||||
|
||||
if (y)
|
||||
addr += 4;
|
||||
if (z)
|
||||
addr += 8;
|
||||
if (w)
|
||||
addr += 12;
|
||||
|
||||
WriteDataMem32(0, addr, vu0_state.vi[it]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ namespace VectorUnit
|
|||
{
|
||||
|
||||
void WriteDataMem128(int vector, uint32_t addr, uint128_t data);
|
||||
void WriteDataMem32(int vector, uint32_t addr, uint32_t data);
|
||||
|
||||
void WriteCodeMem128(int vector, uint32_t addr, uint128_t data);
|
||||
void WriteCodeMem64(int vector, uint32_t addr, uint64_t data);
|
||||
|
@ -16,7 +17,81 @@ void Dump();
|
|||
namespace VU0
|
||||
{
|
||||
|
||||
struct VectorState
|
||||
{
|
||||
uint32_t fbrst = 0;
|
||||
uint16_t vi[16] = {0};
|
||||
|
||||
uint32_t status;
|
||||
|
||||
union
|
||||
{
|
||||
uint32_t val;
|
||||
struct
|
||||
{
|
||||
uint32_t pos_x_0 : 1;
|
||||
uint32_t neg_x_0 : 1;
|
||||
uint32_t pos_y_0 : 1;
|
||||
uint32_t neg_y_0 : 1;
|
||||
uint32_t pos_z_0 : 1;
|
||||
uint32_t neg_z_0 : 1;
|
||||
uint32_t : 26;
|
||||
};
|
||||
} clipping;
|
||||
|
||||
uint32_t r;
|
||||
float i, q;
|
||||
|
||||
uint16_t cmsar0;
|
||||
|
||||
union
|
||||
{
|
||||
uint128_t u128;
|
||||
float components[4];
|
||||
struct
|
||||
{
|
||||
float w;
|
||||
float z;
|
||||
float y;
|
||||
float x;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint32_t wi;
|
||||
uint32_t zi;
|
||||
uint32_t yi;
|
||||
uint32_t xi;
|
||||
};
|
||||
} vf[32], acc;
|
||||
};
|
||||
|
||||
extern VectorState vu0_state;
|
||||
|
||||
// VU0 specific stuff, like COP2 opcodes
|
||||
uint32_t ReadControl(int index);
|
||||
void WriteControl(int index, uint32_t data);
|
||||
|
||||
__uint128_t ReadReg(int index);
|
||||
void WriteReg(int index, __uint128_t val);
|
||||
|
||||
void LQC2(uint32_t instr);
|
||||
void SQC2(uint32_t instr);
|
||||
|
||||
// Special 1
|
||||
void Vmaddz(uint32_t instr); // 0x0a
|
||||
void Vmaddw(uint32_t instr); // 0x0b
|
||||
void Vsub(uint32_t instr); // 0x2c
|
||||
void Viadd(uint32_t instr); // 0x30
|
||||
|
||||
// Special2
|
||||
void Vmaddax(uint32_t instr); // 0x08
|
||||
void Vmadday(uint32_t instr); // 0x09
|
||||
void Vmaddaz(uint32_t instr); // 0x0A
|
||||
void Vmulax(uint32_t instr); // 0x18
|
||||
void Vmulaw(uint32_t instr); // 0x1B
|
||||
void Vclipw(uint32_t instr); // 0x1F
|
||||
void Vsqi(uint32_t instr); // 0x35
|
||||
void Viswr(uint32_t instr); // 0x3f
|
||||
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -27,6 +27,8 @@ private:
|
|||
void EmitSaveHostRegs();
|
||||
void EmitRestoreHostRegs();
|
||||
void EmitMov(IRInstruction i);
|
||||
void EmitPMFLO(IRInstruction i);
|
||||
void EmitPMFHI(IRInstruction i);
|
||||
void EmitMovCond(IRInstruction i);
|
||||
void EmitSLTI(IRInstruction i);
|
||||
void EmitBC(IRInstruction i);
|
||||
|
@ -61,6 +63,51 @@ private:
|
|||
void EmitERET(IRInstruction i);
|
||||
void EmitSyscall(IRInstruction i);
|
||||
void EmitEI(IRInstruction i);
|
||||
void EmitPLZCW(IRInstruction i);
|
||||
void EmitMTLO(IRInstruction i);
|
||||
void EmitMTHI(IRInstruction i);
|
||||
void EmitPCPYLD(IRInstruction i);
|
||||
void EmitPSUBB(IRInstruction i);
|
||||
void EmitPADDSB(IRInstruction i);
|
||||
void EmitPNOR(IRInstruction i);
|
||||
void EmitPAND(IRInstruction i);
|
||||
void EmitPCPYUD(IRInstruction i);
|
||||
void EmitBC0T(IRInstruction i);
|
||||
void EmitBC0F(IRInstruction i);
|
||||
void EmitPCPYH(IRInstruction i);
|
||||
void EmitCFC2(IRInstruction i);
|
||||
void EmitCTC2(IRInstruction i);
|
||||
void EmitVISWR(IRInstruction i);
|
||||
void EmitQMFC2(IRInstruction i);
|
||||
void EmitQMTC2(IRInstruction i);
|
||||
void EmitVSUB(IRInstruction i);
|
||||
void EmitVSQI(IRInstruction i);
|
||||
void EmitVIADD(IRInstruction i);
|
||||
void EmitADDA(IRInstruction i);
|
||||
void EmitMADD(IRInstruction i);
|
||||
void EmitMADDS(IRInstruction i);
|
||||
void EmitCVTS(IRInstruction i);
|
||||
void EmitMULS(IRInstruction i);
|
||||
void EmitCVTW(IRInstruction i);
|
||||
void EmitDIVS(IRInstruction i);
|
||||
void EmitMOVS(IRInstruction i);
|
||||
void EmitADDS(IRInstruction i);
|
||||
void EmitSUBS(IRInstruction i);
|
||||
void EmitNEGS(IRInstruction i);
|
||||
void EmitLQC2(IRInstruction i);
|
||||
void EmitSQC2(IRInstruction i);
|
||||
void EmitVMULAX(IRInstruction i);
|
||||
void EmitVMADDAX(IRInstruction i);
|
||||
void EmitVMADDAY(IRInstruction i);
|
||||
void EmitVMADDAZ(IRInstruction i);
|
||||
void EmitVMADDW(IRInstruction i);
|
||||
void EmitVMADDZ(IRInstruction i);
|
||||
void EmitVMULAW(IRInstruction i);
|
||||
void EmitVCLIPW(IRInstruction i);
|
||||
void EmitCLES(IRInstruction i);
|
||||
void EmitCEQS(IRInstruction i);
|
||||
void EmitBC1F(IRInstruction i);
|
||||
void EmitBC1T(IRInstruction i);
|
||||
|
||||
EE_JIT::JIT::EntryFunc dispatcher_entry;
|
||||
public:
|
||||
|
|
|
@ -6,13 +6,12 @@
|
|||
#include <emu/cpu/iop/cpu.h>
|
||||
|
||||
#include <cstring>
|
||||
#include "cpu.h"
|
||||
|
||||
uint32_t exception_addr[2] = { 0x80000080, 0xBFC00180 };
|
||||
|
||||
void CPU::exception(Exception cause, uint32_t cop)
|
||||
{
|
||||
// printf("[IOP] Exception of type %d\n", (int)cause);
|
||||
|
||||
uint32_t mode = Cop0.status.value;
|
||||
Cop0.status.value &= ~(uint32_t)0x3F;
|
||||
Cop0.status.value |= (mode << 2) & 0x3F;
|
||||
|
@ -119,17 +118,12 @@ void CPU::load(uint32_t regN, uint32_t value)
|
|||
delayed_memory_load.data = value;
|
||||
}
|
||||
|
||||
void CPU::Clock(int cycles)
|
||||
void CPU::Clock(uint64_t cycles)
|
||||
{
|
||||
for (int cycle = cycles; cycle > 0; cycle--)
|
||||
{
|
||||
if (singleStep)
|
||||
{
|
||||
getc(stdin);
|
||||
}
|
||||
|
||||
for (uint64_t cycle = 0; cycle < cycles; cycle++)
|
||||
{
|
||||
i = next_instr;
|
||||
|
||||
|
||||
if (i.pc == 0x12C48 || i.pc == 0x1420C || i.pc == 0x1230C)
|
||||
{
|
||||
uint32_t ptr = regs[5];
|
||||
|
@ -206,10 +200,8 @@ void CPU::Clock(int cycles)
|
|||
last_instruction_was_lwr = false;
|
||||
}
|
||||
|
||||
if (IntPending())
|
||||
{
|
||||
if (IntPending())
|
||||
exception(Exception::Interrupt);
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Dump()
|
||||
|
@ -217,6 +209,8 @@ void CPU::Dump()
|
|||
for (int i = 0; i < 32; i++)
|
||||
printf("[emu/IOP]: %s: %s\t->\t0x%08x\n", __FUNCTION__, Reg(i), regs[i]);
|
||||
printf("[emu/IOP]: %s: pc\t->\t0x%08x\n", __FUNCTION__, pc - 4);
|
||||
printf("[emu/IOP]: COP0_Cause: 0x%08x\n", Cop0.cause.value);
|
||||
printf("[emu/IOP]: COP0_Status: 0x%08x\n", Cop0.status.value);
|
||||
}
|
||||
|
||||
bool CPU::IntPending()
|
||||
|
@ -225,12 +219,18 @@ bool CPU::IntPending()
|
|||
Cop0.cause.IP = (Cop0.cause.IP & ~0x4) | (pending << 2);
|
||||
|
||||
bool enabled = Cop0.status.IEc && (Cop0.status.Im & Cop0.cause.IP);
|
||||
|
||||
return pending && enabled;
|
||||
}
|
||||
|
||||
bool CPU::CanDisassemble()
|
||||
{
|
||||
return can_disassemble;
|
||||
}
|
||||
|
||||
static CPU iop;
|
||||
|
||||
void IOP_MANAGEMENT::Clock(int cycles)
|
||||
void IOP_MANAGEMENT::Clock(uint64_t cycles)
|
||||
{
|
||||
iop.Clock(cycles);
|
||||
}
|
||||
|
@ -242,5 +242,10 @@ void IOP_MANAGEMENT::Reset()
|
|||
|
||||
void IOP_MANAGEMENT::Dump()
|
||||
{
|
||||
iop.Dump();
|
||||
iop.Dump();
|
||||
}
|
||||
|
||||
bool IOP_MANAGEMENT::CanDisassemble()
|
||||
{
|
||||
return iop.CanDisassemble();
|
||||
}
|
||||
|
|
|
@ -269,17 +269,20 @@ public:
|
|||
void Reset();
|
||||
~CPU();
|
||||
|
||||
void Clock(int cycles);
|
||||
void Clock(uint64_t cycles);
|
||||
void Dump();
|
||||
|
||||
bool IntPending();
|
||||
bool CanDisassemble();
|
||||
};
|
||||
|
||||
namespace IOP_MANAGEMENT
|
||||
{
|
||||
|
||||
void Clock(int cycles);
|
||||
void Clock(uint64_t cycles);
|
||||
void Reset();
|
||||
void Dump();
|
||||
|
||||
bool CanDisassemble();
|
||||
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include <emu/memory/Bus.h>
|
||||
#include <cassert>
|
||||
|
||||
union DICR2
|
||||
union DICR
|
||||
{
|
||||
uint32_t value;
|
||||
struct
|
||||
|
@ -18,12 +18,11 @@ union DICR2
|
|||
uint32_t flags : 6;
|
||||
uint32_t : 2;
|
||||
};
|
||||
} dicr2 = {0};
|
||||
} dicr, dicr2 = {0};
|
||||
|
||||
uint32_t dpcr;
|
||||
uint32_t dpcr2;
|
||||
bool dmacen = true;
|
||||
uint32_t dicr = 0;
|
||||
|
||||
union DN_CHCR
|
||||
{
|
||||
|
@ -75,6 +74,7 @@ union DMATag
|
|||
uint64_t irq : 1;
|
||||
uint64_t end : 1;
|
||||
uint64_t size : 24;
|
||||
uint64_t : 8;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -102,8 +102,6 @@ void HandleSIF1Transfer()
|
|||
if (!sif1_transfer_running)
|
||||
return;
|
||||
|
||||
printf("[emu/IopDma]: Transfer of mode %d, %d blocks\n", c.chcr.transfer_mode, c.bcr.count);
|
||||
|
||||
if (c.bcr.count)
|
||||
{
|
||||
while (c.bcr.count)
|
||||
|
@ -121,28 +119,19 @@ void HandleSIF1Transfer()
|
|||
}
|
||||
|
||||
|
||||
if (sif1_tag.irq && !c.bcr.count)
|
||||
if (sif1_tag.irq || sif1_tag.end)
|
||||
{
|
||||
dicr2.flags |= (1 << 3);
|
||||
|
||||
if (dicr2.flags & dicr2.mask)
|
||||
Bus::TriggerIOPInterrupt(3);
|
||||
}
|
||||
|
||||
if (sif1_tag.end)
|
||||
{
|
||||
|
||||
sif1_transfer_running = false;
|
||||
c.chcr.running = 0;
|
||||
|
||||
dicr2.flags |= (1 << 3);
|
||||
|
||||
if (dicr2.flags & dicr2.mask)
|
||||
Bus::TriggerIOPInterrupt(3);
|
||||
c.chcr.trigger = c.chcr.running = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[emu/IopDma]: Sif1 FIFO size is %ld\n", SIF::FIFO1_size());
|
||||
if (SIF::FIFO1_size() >= 4)
|
||||
{
|
||||
uint32_t data[2];
|
||||
|
@ -154,7 +143,7 @@ void HandleSIF1Transfer()
|
|||
|
||||
sif1_tag.value = *(uint64_t*)data;
|
||||
|
||||
printf("[emu/IopDma]: Found SIF1 DMATag 0x%08lx: Start address 0x%08x, size %d bytes\n", sif1_tag.value, sif1_tag.start_addr, sif1_tag.size);
|
||||
printf("[emu/IopDma]: Found SIF1 DMATag 0x%08lx: Start address 0x%08x, size %d words (%d, %d)\n", sif1_tag.value, sif1_tag.start_addr, sif1_tag.size, sif1_tag.end, sif1_tag.irq);
|
||||
|
||||
c.madr = sif1_tag.start_addr;
|
||||
c.bcr.count = (sif1_tag.size + 3) & 0xfffffffc;
|
||||
|
@ -167,6 +156,7 @@ void HandleSIF1Transfer()
|
|||
evt.name = "SIF1Transfer";
|
||||
evt.func = HandleSIF1Transfer;
|
||||
evt.cycles_from_now = 8*c.bcr.count;
|
||||
if (evt.cycles_from_now == 0) evt.cycles_from_now = 8;
|
||||
|
||||
Scheduler::ScheduleEvent(evt);
|
||||
}
|
||||
|
@ -186,32 +176,30 @@ void HandleSIF0Transfer()
|
|||
if (!sif0_transfer_running)
|
||||
return;
|
||||
|
||||
printf("[emu/IopDma]: Transfer of mode %d, %d blocks\n", c.chcr.transfer_mode, c.bcr.count);
|
||||
printf("[emu/IopDma]: Transfer of mode %d, %d blocks from 0x%08x\n", c.chcr.transfer_mode, c.bcr.count, c.madr);
|
||||
|
||||
if (c.bcr.count)
|
||||
{
|
||||
while (c.bcr.count)
|
||||
{
|
||||
uint32_t data = Bus::iop_read<uint32_t>(c.madr);
|
||||
printf("[emu/IopDma]: Adding 0x%08x to SIF0 fifo\n", data);
|
||||
SIF::WriteFIFO0(data);
|
||||
c.madr += 4;
|
||||
c.bcr.count--;
|
||||
printf("\r%08d blocks remaining", c.bcr.count);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
|
||||
if (sif0_tag.irq && !c.bcr.count)
|
||||
if (sif0_tag.irq || sif0_tag.end)
|
||||
{
|
||||
dicr2.flags |= (1 << 2);
|
||||
|
||||
if (dicr2.flags & dicr2.mask)
|
||||
Bus::TriggerIOPInterrupt(3);
|
||||
}
|
||||
|
||||
if (sif1_tag.end)
|
||||
{
|
||||
|
||||
sif0_transfer_running = false;
|
||||
c.chcr.running = 0;
|
||||
c.chcr.trigger = c.chcr.running = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -219,6 +207,8 @@ void HandleSIF0Transfer()
|
|||
sif0_tag.value = Bus::iop_read<uint64_t>(c.tadr);
|
||||
c.madr = sif0_tag.start_addr;
|
||||
|
||||
printf("[emu/IopDma]: Tag read from 0x%08x\n", c.tadr);
|
||||
|
||||
c.bcr.count = (sif0_tag.size + 3) & 0xfffffffc;
|
||||
c.tadr += 8;
|
||||
|
||||
|
@ -230,7 +220,9 @@ void HandleSIF0Transfer()
|
|||
c.tadr += 8;
|
||||
}
|
||||
|
||||
printf("[emu/IopDma]: Found SIF0 DMATag 0x%08lx: Start address 0x%08x, size %d bytes\n", sif0_tag.value, sif0_tag.start_addr, sif0_tag.size);
|
||||
sif0_transfer_running = true;
|
||||
|
||||
printf("[emu/IopDma]: Found SIF0 DMATag 0x%08lx: Start address 0x%08x, size %d words (%d, %d)\n", sif0_tag.value, sif0_tag.start_addr, sif0_tag.size, sif0_tag.irq, sif0_tag.end);
|
||||
}
|
||||
|
||||
if (sif0_transfer_running)
|
||||
|
@ -239,6 +231,48 @@ void HandleSIF0Transfer()
|
|||
evt.name = "SIF0Transfer";
|
||||
evt.func = HandleSIF0Transfer;
|
||||
evt.cycles_from_now = 8*c.bcr.count;
|
||||
if (evt.cycles_from_now == 0) evt.cycles_from_now = 8;
|
||||
|
||||
Scheduler::ScheduleEvent(evt);
|
||||
}
|
||||
}
|
||||
|
||||
bool spu2_done = false;
|
||||
|
||||
void HandleSPU2Transfer()
|
||||
{
|
||||
auto& c = channels[7];
|
||||
|
||||
bool schedule_new = true;
|
||||
|
||||
if (c.bcr.count)
|
||||
c.bcr.count--;
|
||||
else if (spu2_done)
|
||||
{
|
||||
Bus::spu2_stat |= 0x80;
|
||||
c.chcr.running = c.chcr.trigger = 0;
|
||||
spu2_done = false;
|
||||
|
||||
dicr2.flags |= (1 << 0);
|
||||
|
||||
if (dicr2.flags & dicr2.mask)
|
||||
Bus::TriggerIOPInterrupt(3);
|
||||
|
||||
schedule_new = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(channels[7].chcr.transfer_mode == 1);
|
||||
spu2_done = true;
|
||||
}
|
||||
|
||||
if (schedule_new)
|
||||
{
|
||||
Scheduler::Event evt;
|
||||
evt.name = "SPU2 DMA Transfer";
|
||||
evt.func = HandleSPU2Transfer;
|
||||
evt.cycles_from_now = 8*c.bcr.count;
|
||||
if (evt.cycles_from_now == 0) evt.cycles_from_now = 8;
|
||||
|
||||
Scheduler::ScheduleEvent(evt);
|
||||
}
|
||||
|
@ -269,6 +303,19 @@ void HandleRunningChannel(int chan, DMAChannels& c)
|
|||
|
||||
Scheduler::ScheduleEvent(evt);
|
||||
}
|
||||
else if (chan == 4)
|
||||
channels[4].chcr.running = channels[4].chcr.trigger = 0;
|
||||
else if (chan == 7)
|
||||
{
|
||||
sif0_transfer_running = true;
|
||||
|
||||
Scheduler::Event evt;
|
||||
evt.name = "SPU2 DMA Transfer";
|
||||
evt.func = HandleSPU2Transfer;
|
||||
evt.cycles_from_now = 8;
|
||||
|
||||
Scheduler::ScheduleEvent(evt);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
|
@ -295,11 +342,16 @@ void IopDma::WriteDMACEN(uint32_t data)
|
|||
|
||||
void IopDma::WriteDICR(uint32_t data)
|
||||
{
|
||||
dicr = data;
|
||||
auto& irq = dicr;
|
||||
auto flags = irq.flags;
|
||||
|
||||
irq.value = data;
|
||||
irq.flags = flags & ~((data >> 24) & 0x7f);
|
||||
}
|
||||
|
||||
void IopDma::WriteDICR2(uint32_t data)
|
||||
{
|
||||
printf("[emu/IopDma]: Writing 0x%08x to DICR2\n", data);
|
||||
auto& irq = dicr2;
|
||||
auto flags = irq.flags;
|
||||
|
||||
|
@ -341,7 +393,7 @@ void IopDma::WriteChannel(uint32_t addr, uint32_t data)
|
|||
break;
|
||||
}
|
||||
|
||||
if (channels[channel].chcr.running && dmacen)
|
||||
if ((channels[channel].chcr.running || channels[channel].chcr.trigger) && dmacen)
|
||||
{
|
||||
printf("[emu/IopDma]: Starting transfer on channel %d\n", channel);
|
||||
HandleRunningChannel(channel, channels[channel]);
|
||||
|
@ -374,13 +426,34 @@ void IopDma::WriteNewChannel(uint32_t addr, uint32_t data)
|
|||
break;
|
||||
}
|
||||
|
||||
if (channels[channel].chcr.running && dmacen)
|
||||
if ((channels[channel].chcr.running || channels[channel].chcr.trigger) && dmacen)
|
||||
{
|
||||
printf("[emu/IopDma]: Starting transfer on channel %d\n", channel);
|
||||
HandleRunningChannel(channel, channels[channel]);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t IopDma::ReadChannel(uint32_t addr)
|
||||
{
|
||||
int channel = (addr >> 4) & 0xf;
|
||||
int reg = addr & 0xf;
|
||||
reg /= 4;
|
||||
|
||||
channel -= 8;
|
||||
|
||||
switch (reg)
|
||||
{
|
||||
case 0x0:
|
||||
return channels[channel].madr;
|
||||
case 0x1:
|
||||
return channels[channel].bcr.value;
|
||||
case 0x2:
|
||||
return channels[channel].chcr.value;
|
||||
case 0x3:
|
||||
return channels[channel].tadr;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t IopDma::ReadNewChannel(uint32_t addr)
|
||||
{
|
||||
int channel = (addr >> 4) & 0xf;
|
||||
|
@ -414,7 +487,7 @@ uint32_t IopDma::ReadDICR2()
|
|||
|
||||
uint32_t IopDma::ReadDICR()
|
||||
{
|
||||
return dicr;
|
||||
return dicr.value;
|
||||
}
|
||||
|
||||
uint32_t IopDma::ReadDPCR2()
|
||||
|
|
|
@ -14,6 +14,7 @@ void WriteDICR2(uint32_t data);
|
|||
void WriteChannel(uint32_t addr, uint32_t data);
|
||||
void WriteNewChannel(uint32_t addr, uint32_t data);
|
||||
|
||||
uint32_t ReadChannel(uint32_t addr);
|
||||
uint32_t ReadNewChannel(uint32_t addr);
|
||||
|
||||
uint32_t ReadDMACEN();
|
||||
|
|
|
@ -83,6 +83,9 @@ void CPU::op_jal()
|
|||
set_reg(31, pc);
|
||||
op_j();
|
||||
if (can_disassemble) printf("jal 0x%08x\n", pc);
|
||||
|
||||
if (pc == 0x800)
|
||||
printf("[emu/IOP]: Entered LOADCORE(0x%08x, 0x%08x)\n", regs[4], regs[5]);
|
||||
}
|
||||
|
||||
void CPU::op_beq()
|
||||
|
@ -597,6 +600,11 @@ void CPU::op_jr()
|
|||
next_instr.is_delay_slot = true;
|
||||
next_instr.branch_taken = true;
|
||||
if (can_disassemble && i.r_type.func == 0b001000) printf("jr %s\n", Reg(i.r_type.rs));
|
||||
|
||||
if (pc == 0xBFC4A000)
|
||||
{
|
||||
printf("Called IOPBOOT:_start(%d, %d, 0x%08x, %d)\n", regs[4], regs[5], regs[6], regs[7]);
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::op_jalr()
|
||||
|
@ -853,7 +861,7 @@ void CPU::op_mtc0()
|
|||
|
||||
Cop0.regs[rd] = regs[rt];
|
||||
|
||||
if (can_disassemble) printf("mtc0 %d, %s\n", rd, Reg(rt));
|
||||
if (can_disassemble) printf("mtc0 %d, %s (0x%08x)\n", rd, Reg(rt), regs[rt]);
|
||||
}
|
||||
|
||||
void CPU::op_rfe()
|
||||
|
|
|
@ -2,10 +2,66 @@
|
|||
// This code is licensed under MIT license (see LICENSE for details)
|
||||
|
||||
#include <emu/dev/cdvd.h>
|
||||
#include "cdvd.h"
|
||||
#include <queue>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
|
||||
uint8_t N_status = (1 << 6);
|
||||
|
||||
std::queue<uint8_t> results;
|
||||
|
||||
uint8_t CDVD::ReadNStatus()
|
||||
{
|
||||
return N_status;
|
||||
return N_status;
|
||||
}
|
||||
|
||||
uint8_t CDVD::ReadSStatus()
|
||||
{
|
||||
return results.empty() << 6;
|
||||
}
|
||||
|
||||
static const uint8_t monthmap[13] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */
|
||||
#define itob(i) ((i)/10*16 + (i)%10)
|
||||
|
||||
uint8_t currentcmd = 0;
|
||||
|
||||
void CDVD::AddSCommand(uint8_t cmd)
|
||||
{
|
||||
currentcmd = cmd;
|
||||
switch (cmd)
|
||||
{
|
||||
case 0x08:
|
||||
{
|
||||
time_t t = time(NULL);
|
||||
tm* tim = localtime(&t);
|
||||
|
||||
results.push(0);
|
||||
results.push(itob(tim->tm_sec));
|
||||
results.push(itob(tim->tm_min));
|
||||
results.push(itob(tim->tm_hour));
|
||||
results.push(0);
|
||||
results.push(itob(tim->tm_mday));
|
||||
results.push(itob(tim->tm_mon));
|
||||
results.push(itob(tim->tm_year));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("[emu/CDVD]: Unknown S-command 0x%02x\n", cmd);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t CDVD::ReadSCommand()
|
||||
{
|
||||
return currentcmd;
|
||||
}
|
||||
|
||||
uint8_t CDVD::ReadSResult()
|
||||
{
|
||||
uint8_t data = results.front();
|
||||
results.pop();
|
||||
return data;
|
||||
}
|
||||
|
|
|
@ -8,4 +8,10 @@
|
|||
namespace CDVD
|
||||
{
|
||||
uint8_t ReadNStatus();
|
||||
uint8_t ReadSStatus();
|
||||
|
||||
void AddSCommand(uint8_t cmd);
|
||||
uint8_t ReadSCommand();
|
||||
|
||||
uint8_t ReadSResult();
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <emu/dev/sif.h>
|
||||
|
||||
#include <queue>
|
||||
#include "sif.h"
|
||||
|
||||
uint32_t sif_ctrl;
|
||||
uint32_t bd6;
|
||||
|
@ -16,16 +17,19 @@ std::queue<uint32_t> fifo0, fifo1;
|
|||
|
||||
void SIF::WriteMSCOM_EE(uint32_t data)
|
||||
{
|
||||
printf("[emu/SIF]: Writing 0x%08x to MSCOM_EE\n", data);
|
||||
mscom = data;
|
||||
}
|
||||
|
||||
void SIF::WriteMSFLG_EE(uint32_t data)
|
||||
{
|
||||
printf("[emu/SIF]: Writing 0x%08x to MSFLG_EE\n", data);
|
||||
msflg |= data;
|
||||
}
|
||||
|
||||
void SIF::WriteSMFLG_EE(uint32_t data)
|
||||
{
|
||||
printf("[emu/SIF]: Writing 0x%08x to SMFLG_EE\n", data);
|
||||
smflg &= ~data;
|
||||
}
|
||||
|
||||
|
@ -60,16 +64,19 @@ void SIF::WriteCTRL_IOP(uint32_t data)
|
|||
|
||||
void SIF::WriteSMCOM_IOP(uint32_t data)
|
||||
{
|
||||
printf("[emu/SIF]: Writing 0x%08x to SMCOM_IOP\n", data);
|
||||
smcom = data;
|
||||
}
|
||||
|
||||
void SIF::WriteSMFLG_IOP(uint32_t data)
|
||||
{
|
||||
printf("[emu/SIF]: Writing 0x%08x to SMFLG_IOP\n", data);
|
||||
smflg = data;
|
||||
}
|
||||
|
||||
void SIF::WriteMSFLG_IOP(uint32_t data)
|
||||
{
|
||||
printf("[emu/SIF]: Writing 0x%08x to MSFLG_IOP\n", data);
|
||||
msflg &= ~data;
|
||||
}
|
||||
|
||||
|
@ -118,6 +125,14 @@ void SIF::WriteFIFO1(uint32_t data)
|
|||
fifo1.push(data);
|
||||
}
|
||||
|
||||
uint32_t SIF::ReadAndPopSIF0()
|
||||
{
|
||||
uint32_t data = fifo0.front();
|
||||
fifo0.pop();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
uint32_t SIF::ReadAndPopSIF1()
|
||||
{
|
||||
uint32_t data = fifo1.front();
|
||||
|
|
|
@ -31,6 +31,7 @@ size_t FIFO1_size();
|
|||
void WriteFIFO0(uint32_t data);
|
||||
void WriteFIFO1(uint32_t data);
|
||||
|
||||
uint32_t ReadAndPopSIF0();
|
||||
uint32_t ReadAndPopSIF1();
|
||||
|
||||
} // namespace SIF
|
||||
|
|
22
src/emu/dev/sio2.cpp
Normal file
22
src/emu/dev/sio2.cpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include "sio2.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <emu/memory/Bus.h>
|
||||
|
||||
uint32_t sio2_ctrl = 0;
|
||||
|
||||
void SIO2::WriteCtrl(uint32_t data)
|
||||
{
|
||||
sio2_ctrl = data;
|
||||
|
||||
if (sio2_ctrl & 1)
|
||||
{
|
||||
Bus::TriggerIOPInterrupt(17);
|
||||
sio2_ctrl &= ~1;
|
||||
}
|
||||
|
||||
if (data & 0xc)
|
||||
{
|
||||
printf("[emu/SIO2]: Reset\n");
|
||||
}
|
||||
}
|
10
src/emu/dev/sio2.h
Normal file
10
src/emu/dev/sio2.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace SIO2
|
||||
{
|
||||
|
||||
void WriteCtrl(uint32_t data);
|
||||
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
// This code is licensed under MIT license (see LICENSE for details)
|
||||
|
||||
#include <emu/gpu/gif.hpp>
|
||||
#include <emu/gpu/gs.h>
|
||||
|
||||
#include <emu/sched/scheduler.h>
|
||||
|
||||
|
@ -70,32 +71,134 @@ union GIFTag
|
|||
} tag;
|
||||
|
||||
int data_count = 0;
|
||||
int regs_left = 0;
|
||||
|
||||
void ProcessPacked(uint128_t qword)
|
||||
{
|
||||
int curr_reg = tag.nregs - regs_left;
|
||||
uint64_t regs = tag.reg;
|
||||
uint32_t desc = (regs >> 4 * curr_reg) & 0xf;
|
||||
uint64_t data1 = qword.u64[0];
|
||||
uint64_t data2 = qword.u64[1];
|
||||
|
||||
|
||||
switch (desc)
|
||||
{
|
||||
case 0x01:
|
||||
{
|
||||
uint8_t r = qword.u128 & 0xff;
|
||||
uint8_t g = (qword.u128 >> 32) & 0xff;
|
||||
uint8_t b = (qword.u128 >> 64) & 0xff;
|
||||
uint8_t a = (qword.u128 >> 96) & 0xff;
|
||||
GS::WriteRGBAQ(r, g, b, a);
|
||||
break;
|
||||
}
|
||||
case 0x04:
|
||||
{
|
||||
uint32_t x = data1 & 0xffff;
|
||||
uint32_t y = (data1 >> 32) & 0xffff;
|
||||
uint32_t z = (data2 >> 4) & 0xFFFFFF;
|
||||
bool disable_drawing = (data2 >> (111 - 64)) & 1;
|
||||
uint8_t f = (data2 >> (100 - 64)) & 0xff;
|
||||
printf("Write vertex (%d, %d, %d) to %s (%s) (%d)\n", x >> 4, y >> 4, z, desc == 0x04 ? "xyzf2" : "xyzf3", print_128(qword), disable_drawing);
|
||||
GS::WriteXYZF(x, y, z, f, false);
|
||||
break;
|
||||
}
|
||||
case 0x05:
|
||||
{
|
||||
uint32_t x = data1 & 0xffff;
|
||||
uint32_t y = (data1 >> 32) & 0xffff;
|
||||
uint32_t z = data2 & 0xFFFFFFFF;
|
||||
printf("Write vertex (%d, %d, %d) to %s (%s)\n", x >> 4, y >> 4, z, desc == 0x04 ? "xyz2" : "xyz3", print_128(qword));
|
||||
GS::WriteXYZF(x, y, z, 0.0f, false);
|
||||
break;
|
||||
}
|
||||
case 0x0e:
|
||||
desc = qword.u64[1];
|
||||
GS::WriteRegister(desc, qword.u64[0]);
|
||||
break;
|
||||
default:
|
||||
printf("Write %s to unknown register GIF packed mode 0x%02x\n", print_128(qword), desc);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessREGLIST(uint128_t qword)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
uint64_t reg_offset = (tag.nregs - regs_left) << 2;
|
||||
uint8_t reg = (tag.reg >> reg_offset) & 0xf;
|
||||
|
||||
if (reg != 0xE)
|
||||
GS::WriteRegister(reg, qword.u64[i]);
|
||||
|
||||
regs_left--;
|
||||
if (!regs_left)
|
||||
{
|
||||
regs_left = tag.nregs;
|
||||
data_count--;
|
||||
|
||||
if (!data_count && !i)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessGIFData()
|
||||
{
|
||||
if (!data_count)
|
||||
while (!fifo.empty())
|
||||
{
|
||||
tag.value = fifo.front().u128;
|
||||
data_count = tag.nloop;
|
||||
printf("[emu/GIF]: Received GIFTag: nloop: 0%04x, eop: %d, prim_en: %d, prim_data: 0x%04x, fmt: %d, nregs: %d, regs: 0x%08lx\n",
|
||||
tag.nloop, tag.eop,
|
||||
tag.prim_en, tag.prim_data,
|
||||
tag.fmt, tag.nregs, tag.reg);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (tag.fmt)
|
||||
if (!data_count)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
printf("Unknown GIFTAG format %d\n", tag.fmt);
|
||||
exit(1);
|
||||
tag.value = fifo.front().u128;
|
||||
fifo.pop();
|
||||
data_count = tag.nloop;
|
||||
regs_left = tag.nregs;
|
||||
|
||||
printf("[emu/GIF]: Found tag %s\n", print_128({tag.value}));
|
||||
|
||||
if (tag.prim_en)
|
||||
GS::WritePRIM(tag.prim_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint128_t qword = fifo.front();
|
||||
|
||||
|
||||
switch (tag.fmt)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
ProcessPacked(qword);
|
||||
regs_left--;
|
||||
if (!regs_left)
|
||||
{
|
||||
regs_left = tag.nregs;
|
||||
data_count--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
ProcessREGLIST(qword);
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
GS::WriteHWReg(qword.u128);
|
||||
GS::WriteHWReg(qword.u128 >> 64);
|
||||
data_count--;
|
||||
break;
|
||||
default:
|
||||
printf("Unknown GIFTAG format %d\n", tag.fmt);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("%ld qwords left in packet\n", data_count);
|
||||
|
||||
fifo.pop();
|
||||
}
|
||||
data_count--;
|
||||
}
|
||||
|
||||
fifo.pop();
|
||||
if (!fifo.empty())
|
||||
{
|
||||
Scheduler::Event event;
|
||||
|
@ -127,17 +230,12 @@ uint32_t ReadStat()
|
|||
|
||||
void WriteFIFO(uint128_t data)
|
||||
{
|
||||
printf("[emu/GIF]: Adding 0x%lx%016lx to GIF FIFO\n",
|
||||
data.u64[1], data.u64[0]);
|
||||
if (fifo.size() < 16)
|
||||
{
|
||||
fifo.push(data);
|
||||
}
|
||||
fifo.push(data);
|
||||
|
||||
if (!event_scheduled)
|
||||
{
|
||||
Scheduler::Event event;
|
||||
event.cycles_from_now = curTransferSize;
|
||||
event.cycles_from_now = curTransferSize*4;
|
||||
event.name = "GIF Data Processing";
|
||||
event.func = ProcessGIFData;
|
||||
|
||||
|
|
|
@ -2,34 +2,841 @@
|
|||
// This code is licensed under MIT license (see LICENSE for details)
|
||||
|
||||
#include <emu/gpu/gs.h>
|
||||
#include <emu/gpu/gs_types.h>
|
||||
#include <emu/memory/Bus.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <queue>
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <algorithm>
|
||||
#include "gs.h"
|
||||
|
||||
namespace GS
|
||||
{
|
||||
|
||||
union GS_CSR
|
||||
GS_CSR csr;
|
||||
GS_IMR imr;
|
||||
|
||||
PRIM prim;
|
||||
RGBAQ rgbaq;
|
||||
ST st;
|
||||
UV uv;
|
||||
|
||||
uint8_t fog;
|
||||
uint8_t scanmsk;
|
||||
|
||||
PRMODE prmode;
|
||||
TEXCLUT texclut;
|
||||
FOGCOL fogcol;
|
||||
TEXA texa;
|
||||
|
||||
Bitbltbuf bitbltbuf;
|
||||
TRXPOS trxpos;
|
||||
TRXREG trxreg;
|
||||
uint8_t trxdir;
|
||||
|
||||
SMODE2 smode2;
|
||||
|
||||
bool use_prim = false;
|
||||
bool pabe = false;
|
||||
bool dthe = false;
|
||||
bool clamp = false;
|
||||
|
||||
XYZF xyzf2, xyzf3;
|
||||
|
||||
Context contexts[2], *cur_contex = &contexts[0];
|
||||
|
||||
uint8_t* vram, *drawBuf;
|
||||
|
||||
std::queue<Vertex> vertices;
|
||||
|
||||
int requiredVerts[] =
|
||||
{
|
||||
uint32_t data;
|
||||
struct
|
||||
1, // Point
|
||||
2, // Line
|
||||
2, // Line strip
|
||||
3, // Triangle
|
||||
3, // Triangle Strip
|
||||
3, // Triangle Fan
|
||||
2, // Sprite
|
||||
0, // Reserved
|
||||
};
|
||||
|
||||
uint32_t ReadVram32(uint32_t base, uint32_t width, int32_t x, int32_t y, bool is_bitbltbuf = false)
|
||||
{
|
||||
uint32_t addr = (is_bitbltbuf ? base*64 : base*2048) + x + (y * (width*64));
|
||||
return *(uint32_t*)&vram[addr*4];
|
||||
}
|
||||
|
||||
void WriteVRAM32(uint32_t base, uint32_t width, int32_t x, int32_t y, uint32_t val, bool is_bitbltbuf = false)
|
||||
{
|
||||
uint32_t addr = (is_bitbltbuf ? base*64 : base*2048) + x + (y * (width*64));
|
||||
*(uint32_t*)&vram[addr*4] = val;
|
||||
}
|
||||
|
||||
void DrawPixel(int32_t x, int32_t y, uint32_t z, uint32_t color)
|
||||
{
|
||||
auto& ctxt = contexts[use_prim ? prim.ctxt : prmode.ctxt];
|
||||
|
||||
if (scanmsk == 2 && (y & 1) == 0)
|
||||
return;
|
||||
else if (scanmsk == 3 & (y & 1) == 1)
|
||||
return;
|
||||
|
||||
if (x < ctxt.scissor.scax0 || x > ctxt.scissor.scax1 || y < ctxt.scissor.scay0 || y > ctxt.scissor.scay1)
|
||||
return;
|
||||
|
||||
bool update_frame = true;
|
||||
bool update_alpha = true;
|
||||
bool update_z = !ctxt.zbuf.zmsk;
|
||||
|
||||
uint8_t a = (color >> 24);
|
||||
|
||||
if (ctxt.test.ate)
|
||||
{
|
||||
uint32_t signal : 1;
|
||||
uint32_t finish : 1;
|
||||
uint32_t hsint : 1;
|
||||
uint32_t vsint : 1;
|
||||
uint32_t edwint : 1;
|
||||
uint32_t : 3;
|
||||
uint32_t flush : 1;
|
||||
uint32_t reset : 1;
|
||||
uint32_t : 2;
|
||||
uint32_t nfield : 1;
|
||||
uint32_t field : 1;
|
||||
uint32_t fifo : 2;
|
||||
uint32_t rev : 8;
|
||||
uint32_t id : 8;
|
||||
bool fail = false;
|
||||
switch (ctxt.test.atst)
|
||||
{
|
||||
case 0:
|
||||
fail = true;
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
if (a >= ctxt.test.aref)
|
||||
fail = true;
|
||||
break;
|
||||
case 3:
|
||||
if (a > ctxt.test.aref)
|
||||
fail = true;
|
||||
break;
|
||||
case 4:
|
||||
if (a != ctxt.test.aref)
|
||||
fail = true;
|
||||
break;
|
||||
case 5:
|
||||
if (a < ctxt.test.aref)
|
||||
fail = true;
|
||||
break;
|
||||
case 6:
|
||||
if (a <= ctxt.test.aref)
|
||||
fail = true;
|
||||
break;
|
||||
case 7:
|
||||
if (a == ctxt.test.aref)
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (fail)
|
||||
{
|
||||
switch (ctxt.test.afail)
|
||||
{
|
||||
case 0:
|
||||
return;
|
||||
case 1:
|
||||
update_z = false;
|
||||
break;
|
||||
case 2:
|
||||
update_frame = false;
|
||||
break;
|
||||
case 3:
|
||||
printf("Unhandled RGB_ONLY\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool pass_depth_test = true;
|
||||
|
||||
if (ctxt.test.zte)
|
||||
{
|
||||
switch (ctxt.test.ztst)
|
||||
{
|
||||
case 0:
|
||||
pass_depth_test = false;
|
||||
break;
|
||||
case 1:
|
||||
pass_depth_test = true;
|
||||
break;
|
||||
case 2:
|
||||
pass_depth_test = (z >= ReadVram32(ctxt.zbuf.zbp, ctxt.frame.fbw, x, y));
|
||||
break;
|
||||
case 3:
|
||||
pass_depth_test = (z > ReadVram32(ctxt.zbuf.zbp, ctxt.frame.fbw, x, y));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
update_z = false;
|
||||
|
||||
if (!pass_depth_test)
|
||||
return;
|
||||
|
||||
if (ctxt.test.date)
|
||||
{
|
||||
bool alpha = ReadVram32(ctxt.frame.fbp, ctxt.frame.fbw, x, y) & (1 << 31);
|
||||
if (ctxt.test.datm ^ alpha)
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t mask = ctxt.frame.fbmsk;
|
||||
color = (color & ~mask) | (ReadVram32(ctxt.frame.fbp, ctxt.frame.fbw, x, y) & mask);
|
||||
|
||||
if (update_frame)
|
||||
{
|
||||
WriteVRAM32(ctxt.frame.fbp, ctxt.frame.fbw, x, y, color);
|
||||
}
|
||||
|
||||
if (update_z)
|
||||
{
|
||||
WriteVRAM32(ctxt.zbuf.zbp, ctxt.frame.fbw, x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawSprite()
|
||||
{
|
||||
cur_contex = &contexts[use_prim ? prim.ctxt : prmode.ctxt];
|
||||
auto ve0 = vertices.front();
|
||||
vertices.pop();
|
||||
auto ve1 = vertices.front();
|
||||
vertices.pop();
|
||||
|
||||
int32_t x1, x2, y1, y2;
|
||||
int32_t u1, u2, v1, v2;
|
||||
uint8_t r1, r2, r3, g1, g2, g3, b1, b2, b3, a1, a2, a3;
|
||||
float s1, s2, t1, t2, q1, q2;
|
||||
x1 = ve1.vert.x - contexts[prim.ctxt].xyoffset.ofx;
|
||||
x2 = ve0.vert.x - contexts[prim.ctxt].xyoffset.ofx;
|
||||
y1 = ve1.vert.y - contexts[prim.ctxt].xyoffset.ofy;
|
||||
y2 = ve0.vert.y - contexts[prim.ctxt].xyoffset.ofy;
|
||||
u1 = ve1.uv.u;
|
||||
u2 = ve0.uv.v;
|
||||
v1 = ve1.uv.u;
|
||||
v2 = ve0.uv.v;
|
||||
uint32_t z = ve0.vert.z;
|
||||
|
||||
auto vtx_color = ve0.rgba;
|
||||
|
||||
if (x1 > x2)
|
||||
{
|
||||
std::swap(x1, x2);
|
||||
std::swap(y1, y2);
|
||||
}
|
||||
|
||||
if (u1 > u2)
|
||||
{
|
||||
std::swap(u1, u2);
|
||||
std::swap(v1, v2);
|
||||
}
|
||||
|
||||
printf("Sprite (%d, %d), (%d, %d), (%d, %d, %d, %d)\n", x1, y1, x2, y2, vtx_color.r, vtx_color.g, vtx_color.b, vtx_color.a);
|
||||
|
||||
for (int32_t y = y1, v = v1; y < y2; y++, v++)
|
||||
{
|
||||
for (int32_t x = x1, u = u1; x < x2; x++, u++)
|
||||
{
|
||||
uint32_t final_color;
|
||||
if (!prim.tme)
|
||||
final_color = (vtx_color.a << 24) | (vtx_color.b << 16) | (vtx_color.g << 8) | vtx_color.r;
|
||||
else
|
||||
{
|
||||
uint32_t color = ReadVram32(cur_contex->tex0.tbp0, cur_contex->tex0.tbw, u, v, true);
|
||||
uint8_t r = color & 0xff;
|
||||
uint8_t g = (color >> 8) & 0xff;
|
||||
uint8_t b = (color >> 16) & 0xff;
|
||||
uint8_t a = (color >> 24) & 0xff;
|
||||
final_color = (a << 24) | (b << 16) | (g << 8) | r;
|
||||
}
|
||||
|
||||
DrawPixel(x, y, z, final_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t orient2d(Vector3& v1, Vector3& v2, Vector3& v3)
|
||||
{
|
||||
return (v2.x - v1.x) * (v3.y - v1.y) - (v3.x - v1.x) * (v2.y - v1.y);
|
||||
}
|
||||
|
||||
void DrawTriangle(Vertex p0, Vertex p1, Vertex p2)
|
||||
{
|
||||
assert(!prim.tme);
|
||||
|
||||
auto& ctxt = contexts[prim.ctxt];
|
||||
|
||||
auto& v0 = p0.vert;
|
||||
auto& v1 = p1.vert;
|
||||
auto& v2 = p2.vert;
|
||||
|
||||
v0.x -= ctxt.xyoffset.ofx;
|
||||
v1.x -= ctxt.xyoffset.ofx;
|
||||
v2.x -= ctxt.xyoffset.ofx;
|
||||
v0.y -= ctxt.xyoffset.ofy;
|
||||
v1.y -= ctxt.xyoffset.ofy;
|
||||
v2.y -= ctxt.xyoffset.ofy;
|
||||
|
||||
if (orient2d(v0, v1, v2) < 0)
|
||||
std::swap(v1, v2);
|
||||
|
||||
int32_t min_x = std::min({v0.x, v1.x, v2.x});
|
||||
int32_t max_x = std::max({v0.x, v1.x, v2.x});
|
||||
int32_t min_y = std::min({v0.y, v1.y, v2.y});
|
||||
int32_t max_y = std::max({v0.y, v1.y, v2.y});
|
||||
|
||||
int32_t A12 = v0.y - v1.y;
|
||||
int32_t B12 = v1.x - v0.x;
|
||||
int32_t A23 = v1.y - v2.y;
|
||||
int32_t B23 = v2.x - v1.x;
|
||||
int32_t A31 = v2.y - v0.y;
|
||||
int32_t B31 = v0.x - v2.x;
|
||||
|
||||
int r1 = p0.rgba.r;
|
||||
int r2 = p1.rgba.r;
|
||||
int r3 = p2.rgba.r;
|
||||
|
||||
int g1 = p0.rgba.g;
|
||||
int g2 = p1.rgba.g;
|
||||
int g3 = p2.rgba.g;
|
||||
|
||||
int b1 = p0.rgba.b;
|
||||
int b2 = p1.rgba.b;
|
||||
int b3 = p2.rgba.b;
|
||||
|
||||
Vector3 min_corner;
|
||||
min_corner.x = min_x;
|
||||
min_corner.y = min_y;
|
||||
int32_t w1_row = orient2d(v1, v2, min_corner);
|
||||
int32_t w2_row = orient2d(v2, v0, min_corner);
|
||||
int32_t w3_row = orient2d(v0, v1, min_corner);
|
||||
|
||||
int32_t divider = orient2d(v0, v1, v2);
|
||||
|
||||
printf("Triangle (%d, %d), (%d, %d), (%d, %d)\n", v0.x, v0.y, v1.x, v1.y, v2.x, v2.y);
|
||||
|
||||
for (int32_t y = min_y; y <= max_y; y++)
|
||||
{
|
||||
int32_t w1 = w1_row;
|
||||
int32_t w2 = w2_row;
|
||||
int32_t w3 = w3_row;
|
||||
|
||||
for (int32_t x = min_x; x <= max_x; x++)
|
||||
{
|
||||
if ((w1 | w2 | w3) >= 0)
|
||||
{
|
||||
double z = (double) v0.z * w1 + (double) v1.z * w2 + (double) v2.z * w3;
|
||||
z /= divider;
|
||||
|
||||
int r = ((float) r1 * w1 + (float) r2 * w2 + (float) r3 * w3) / divider;
|
||||
int g = ((float) g1 * w1 + (float) g2 * w2 + (float) g3 * w3) / divider;
|
||||
int b = ((float) b1 * w1 + (float) b2 * w2 + (float) b3 * w3) / divider;
|
||||
|
||||
uint32_t color = (0xFF << 24) | (b << 16) | (g << 8) | r;
|
||||
DrawPixel(x, y, (uint32_t)z, color);
|
||||
}
|
||||
w1 += A23;
|
||||
w2 += A31;
|
||||
w3 += A12;
|
||||
}
|
||||
w1_row += B23;
|
||||
w2_row += B31;
|
||||
w3_row += B12;
|
||||
}
|
||||
}
|
||||
|
||||
void AddVertex(uint64_t data, bool draw_kick = true)
|
||||
{
|
||||
Vertex v;
|
||||
|
||||
v.vert.x = data & 0xffff;
|
||||
v.vert.y = (data >> 16) & 0xffff;
|
||||
v.vert.z = (data >> 32) & 0xffffff;
|
||||
|
||||
v.vert.x >>= 4;
|
||||
v.vert.y >>= 4;
|
||||
|
||||
v.rgba.r = rgbaq.r;
|
||||
v.rgba.g = rgbaq.g;
|
||||
v.rgba.b = rgbaq.b;
|
||||
v.rgba.a = rgbaq.a;
|
||||
v.rgba.q = rgbaq.q;
|
||||
|
||||
v.uv.u = uv.u;
|
||||
v.uv.v = uv.v;
|
||||
|
||||
vertices.push(v);
|
||||
|
||||
printf("%ld vertices out of %d (draw_kick: %d)\n", vertices.size(), requiredVerts[prim.prim], draw_kick);
|
||||
|
||||
if ((vertices.size() == requiredVerts[prim.prim]) && draw_kick)
|
||||
{
|
||||
printf("%d\n", prim.prim);
|
||||
switch (prim.prim)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
v = vertices.front();
|
||||
uint32_t color = (0xFF << 24) | (v.rgba.b << 16) | (v.rgba.g << 8) | v.rgba.r;
|
||||
DrawPixel(v.vert.x, v.vert.y, v.vert.z, color);
|
||||
printf("Point at (%d, %d)\n", v.vert.x, v.vert.y);
|
||||
vertices.pop();
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
auto& v1 = vertices.front();
|
||||
vertices.pop();
|
||||
auto& v2 = vertices.front();
|
||||
vertices.pop();
|
||||
auto& v3 = vertices.front();
|
||||
vertices.pop();
|
||||
DrawTriangle(v1, v2, v3);
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
DrawSprite();
|
||||
break;
|
||||
default:
|
||||
printf("Unknown shape type %d\n", prim.prim);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t trxpos_dsax, trxpos_dsay;
|
||||
uint64_t trxpos_ssax, trxpos_ssay;
|
||||
uint64_t pixels_transferred = 0;
|
||||
|
||||
void DoVramToVram()
|
||||
{
|
||||
printf("[emu/GS]: Local to local transfer, (%d, %d) -> (%d, %d) (%dx%d)\n", trxpos.ssax, trxpos.ssay, trxpos.dsax, trxpos.dsay, trxreg.rrw, trxreg.rrh);
|
||||
|
||||
int max_pixels = trxreg.rrw * trxreg.rrh;
|
||||
int int_dest_x, int_source_x;
|
||||
int int_dest_y, int_source_y;
|
||||
|
||||
uint16_t dest_start_x = 0, src_start_x = 0;
|
||||
int x_step = 0, y_step = 0;
|
||||
|
||||
printf("[emu/GS]: Transmission direction %d\n", trxpos.dir);
|
||||
assert(!trxpos.dir);
|
||||
|
||||
dest_start_x = int_dest_x = trxpos.dsax;
|
||||
src_start_x = int_source_x = trxpos.ssax;
|
||||
int_dest_y = trxpos.dsay;
|
||||
int_source_y = trxpos.ssay;
|
||||
x_step = 1;
|
||||
y_step = 1;
|
||||
|
||||
while (pixels_transferred < max_pixels)
|
||||
{
|
||||
uint32_t data = ReadVram32(bitbltbuf.sbp, bitbltbuf.sbw, int_source_x, int_source_y, true);
|
||||
WriteVRAM32(bitbltbuf.dbp, bitbltbuf.dbw, int_dest_x, int_dest_y, data, true);
|
||||
|
||||
pixels_transferred++;
|
||||
int_source_x += x_step;
|
||||
int_dest_x += x_step;
|
||||
|
||||
if (pixels_transferred % trxreg.rrw == 0)
|
||||
{
|
||||
int_source_x = src_start_x;
|
||||
int_source_y += y_step;
|
||||
|
||||
int_dest_x = dest_start_x;
|
||||
int_dest_y += y_step;
|
||||
}
|
||||
|
||||
int_source_x %= 2048;
|
||||
int_source_y %= 2048;
|
||||
int_dest_x %= 2048;
|
||||
int_dest_y %= 2048;
|
||||
}
|
||||
|
||||
pixels_transferred = 0;
|
||||
trxdir = 3;
|
||||
}
|
||||
|
||||
void WriteRegister(uint64_t reg, uint64_t data)
|
||||
{
|
||||
switch (reg)
|
||||
{
|
||||
case 0x00:
|
||||
printf("[emu/GS]: Write 0x%08lx to PRIM\n", prim.data);
|
||||
prim.data = data;
|
||||
printf("%ld, %d\n", prim.data, prim.prim);
|
||||
break;
|
||||
case 0x01:
|
||||
rgbaq.data = data;
|
||||
break;
|
||||
case 0x02:
|
||||
st.data = data;
|
||||
break;
|
||||
case 0x03:
|
||||
uv.data = data;
|
||||
printf("Wrote (%d, %d) to UV\n", uv.u, uv.v);
|
||||
break;
|
||||
case 0x05:
|
||||
AddVertex(data);
|
||||
break;
|
||||
case 0x06:
|
||||
{
|
||||
auto& tex0 = contexts[0].tex0;
|
||||
tex0.data = data;
|
||||
printf("TEX0_1 buffer is now at 0x%08x, %d bytes wide, format %d (%dx%d)\n", tex0.tbp0*64, tex0.tbw*64, tex0.psm, 1 << tex0.tw, 1 << tex0.th);
|
||||
break;
|
||||
}
|
||||
case 0x07:
|
||||
{
|
||||
auto& tex0 = contexts[1].tex0;
|
||||
contexts[1].tex0.data = data;
|
||||
printf("TEX0_1 buffer is now at 0x%08x, %d bytes wide, format %d (%dx%d)\n", tex0.tbp0*64, tex0.tbw*64, tex0.psm, 1 << tex0.tw, 1 << tex0.th);
|
||||
break;
|
||||
}
|
||||
case 0x08:
|
||||
case 0x09:
|
||||
break;
|
||||
case 0x0A:
|
||||
fog = (data >> 56) & 0xFF;
|
||||
break;
|
||||
case 0x14:
|
||||
contexts[0].tex1.data = data;
|
||||
break;
|
||||
case 0x15:
|
||||
contexts[1].tex1.data = data;
|
||||
break;
|
||||
case 0x16:
|
||||
contexts[0].tex2.data = data;
|
||||
break;
|
||||
case 0x17:
|
||||
contexts[1].tex2.data = data;
|
||||
break;
|
||||
case 0x18:
|
||||
contexts[0].xyoffset.data = data;
|
||||
break;
|
||||
case 0x19:
|
||||
contexts[1].xyoffset.data = data;
|
||||
break;
|
||||
case 0x1A:
|
||||
printf("[emu/GS]: Using %s\n", (data & 1) ? "prim" : "prmode");
|
||||
use_prim = data & 1;
|
||||
break;
|
||||
case 0x1B:
|
||||
prmode.data = data;
|
||||
printf("Writing 0x%08lx to PRMODE\n", data);
|
||||
break;
|
||||
case 0x1C:
|
||||
texclut.data = data;
|
||||
break;
|
||||
case 0x22:
|
||||
scanmsk = data & 0x3;
|
||||
break;
|
||||
case 0x34:
|
||||
case 0x35:
|
||||
case 0x36:
|
||||
case 0x37:
|
||||
break;
|
||||
case 0x3B:
|
||||
texa.data = data;
|
||||
break;
|
||||
case 0x3D:
|
||||
fogcol.data = data;
|
||||
break;
|
||||
case 0x3f:
|
||||
break;
|
||||
case 0x40:
|
||||
contexts[0].scissor.data = data;
|
||||
printf("Scissor_1 area is now (%d, %d), (%d, %d)\n", contexts[0].scissor.scax0, contexts[0].scissor.scay0, contexts[0].scissor.scax1, contexts[0].scissor.scay1);
|
||||
break;
|
||||
case 0x41:
|
||||
contexts[1].scissor.data = data;
|
||||
printf("Scissor_2 area is now (%d, %d), (%d, %d)\n", contexts[1].scissor.scax0, contexts[1].scissor.scay0, contexts[1].scissor.scax1, contexts[1].scissor.scay1);
|
||||
break;
|
||||
case 0x42:
|
||||
case 0x43:
|
||||
case 0x44:
|
||||
break;
|
||||
case 0x45:
|
||||
dthe = data & 1;
|
||||
break;
|
||||
case 0x46:
|
||||
clamp = data & 1;
|
||||
break;
|
||||
case 0x47:
|
||||
contexts[0].test.data = data;
|
||||
break;
|
||||
case 0x48:
|
||||
contexts[1].test.data = data;
|
||||
break;
|
||||
case 0x49:
|
||||
pabe = data & 1;
|
||||
break;
|
||||
case 0x4A:
|
||||
case 0x4B:
|
||||
break;
|
||||
case 0x4C:
|
||||
contexts[0].frame.data = data;
|
||||
printf("Framebuffer_1 is now at 0x%08x, %d pixels wide, format %d\n", contexts[0].frame.fbp*2048, contexts[0].frame.fbw*64, contexts[0].frame.psm);
|
||||
break;
|
||||
case 0x4D:
|
||||
contexts[1].frame.data = data;
|
||||
printf("Framebuffer_2 is now at 0x%08x, %d pixels wide, format %d\n", contexts[1].frame.fbp*2048, contexts[1].frame.fbw*64, contexts[1].frame.psm);
|
||||
break;
|
||||
case 0x4E:
|
||||
contexts[0].zbuf.data = data;
|
||||
printf("Zbuf_1 is now at 0x%08x, format %d (0x%08lx)\n", contexts[0].zbuf.zbp*2048, contexts[0].zbuf.psm, data);
|
||||
break;
|
||||
case 0x4F:
|
||||
contexts[1].zbuf.data = data;
|
||||
printf("Zbuf_2 is now at 0x%08x, format %d (0x%08lx)\n", contexts[1].zbuf.zbp*2048, contexts[1].zbuf.psm, data);
|
||||
break;
|
||||
case 0x50:
|
||||
printf("Writing 0x%08lx to bitbltbuf\n", data);
|
||||
bitbltbuf.value = data;
|
||||
break;
|
||||
case 0x51:
|
||||
trxpos.data = data;
|
||||
break;
|
||||
case 0x52:
|
||||
trxreg.data = data;
|
||||
break;
|
||||
case 0x53:
|
||||
trxdir = data & 0x3;
|
||||
trxpos_dsax = 0;
|
||||
trxpos_dsay = 0;
|
||||
trxpos_ssax = 0;
|
||||
trxpos_ssay = 0;
|
||||
|
||||
printf("Doing transmission, direction %d, (%d, %d) -> (%d, %d) (%dx%d)\n", trxdir, trxpos.ssax, trxpos.ssay, trxpos.dsax, trxpos.dsay, trxreg.rrw, trxreg.rrh);
|
||||
|
||||
if (trxdir == 2)
|
||||
{
|
||||
DoVramToVram();
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x61:
|
||||
csr.finish = 1;
|
||||
Bus::TriggerEEInterrupt(0);
|
||||
break;
|
||||
default:
|
||||
printf("Write to unknown GS register 0x%02lx\n", reg);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteHWReg(uint64_t data)
|
||||
{
|
||||
auto write_pixel = [=](uint32_t data) {
|
||||
uint32_t x = (trxpos_dsax + trxpos.dsax) & 0x7FF;
|
||||
uint32_t y = (trxpos_dsay + trxpos.dsay) & 0x7FF;
|
||||
WriteVRAM32(bitbltbuf.dbp, bitbltbuf.dbw, x, y, data, true);
|
||||
trxpos_dsax++;
|
||||
if (trxpos_dsax >= trxreg.rrw)
|
||||
{
|
||||
trxpos_dsax = 0;
|
||||
trxpos_dsay++;
|
||||
}
|
||||
};
|
||||
} csr;
|
||||
|
||||
write_pixel(data & 0xffffffff);
|
||||
write_pixel(data >> 32);
|
||||
|
||||
if (trxpos_dsay >= trxreg.rrh)
|
||||
trxdir = 3;
|
||||
}
|
||||
|
||||
void WriteRGBAQ(uint8_t r, uint8_t g, uint8_t b, uint8_t a, float q)
|
||||
{
|
||||
printf("Writing (%d, %d, %d, %d, %f)\n", r, g, b, a, q);
|
||||
rgbaq.r = r;
|
||||
rgbaq.g = g;
|
||||
rgbaq.b = b;
|
||||
rgbaq.a = a;
|
||||
rgbaq.q = q;
|
||||
}
|
||||
|
||||
void WriteXYZF(int32_t x, int32_t y, int32_t z, uint8_t f, bool adc)
|
||||
{
|
||||
auto& xyzf = adc ? xyzf3 : xyzf2;
|
||||
|
||||
x >>= 4;
|
||||
y >>= 4;
|
||||
|
||||
xyzf.x = x;
|
||||
xyzf.y = y;
|
||||
xyzf.z = z;
|
||||
xyzf.f = f;
|
||||
|
||||
AddVertex(xyzf.data, !adc);
|
||||
}
|
||||
|
||||
void WriteGSSMODE2(uint64_t data)
|
||||
{
|
||||
smode2.data = data;
|
||||
}
|
||||
|
||||
SDL_Window *window;
|
||||
SDL_Renderer* renderer;
|
||||
SDL_Texture* texture;
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
vram = new uint8_t[4*1024*1024];
|
||||
drawBuf = new uint8_t[4*1024*1024];
|
||||
|
||||
SDL_Init(SDL_INIT_EVERYTHING);
|
||||
|
||||
window = SDL_CreateWindow("Emotional - PS2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1280, 960, 0);
|
||||
renderer = SDL_CreateRenderer(window, -1, -1);
|
||||
// SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR32, SDL_TEXTUREACCESS_STATIC, 640, 224);
|
||||
}
|
||||
|
||||
void DumpVram()
|
||||
{
|
||||
std::ofstream out("vram.bin");
|
||||
|
||||
out.write((char*)vram, 4*1024*1024);
|
||||
out.close();
|
||||
|
||||
out.open("disp.bin");
|
||||
|
||||
out.write((char*)drawBuf, 4*1024*1024);
|
||||
out.close();
|
||||
|
||||
out.open("tex0.bin");
|
||||
|
||||
for (int y = 0; y < (1 << contexts[0].tex0.th); y++)
|
||||
{
|
||||
for (int x = 0; x < (1 << contexts[0].tex0.tw); x++)
|
||||
{
|
||||
uint32_t color = ReadVram32(contexts[0].tex0.tbp0, contexts[0].tex0.tbw, x, y, true);
|
||||
out.write((char*)&color, 4);
|
||||
}
|
||||
}
|
||||
|
||||
out.close();
|
||||
}
|
||||
|
||||
bool is_in_frame(DISPLAY& display, int32_t x_start, int32_t y_start, int32_t x, int32_t y)
|
||||
{
|
||||
int width = contexts[1].display.dw+1;
|
||||
width /= contexts[1].display.magh+1;
|
||||
if (x >= x_start && x < (x_start + width))
|
||||
{
|
||||
if (y >= y_start && y < (y_start + contexts[1].display.dh+1))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void render_frame()
|
||||
{
|
||||
uint32_t* target = (uint32_t*)drawBuf;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
int32_t y_increment = 1;
|
||||
int32_t start_scanline = 0;
|
||||
int32_t frame_line_increment = 1;
|
||||
int32_t fb_offset = 0;
|
||||
int32_t display1_yoffset = 0;
|
||||
int32_t display1_xoffset = 0;
|
||||
int32_t display2_yoffset = 0;
|
||||
int32_t display2_xoffset = 0;
|
||||
bool enable_circuit1 = false;
|
||||
bool enable_circuit2 = true;
|
||||
bool field_offset = !csr.field;
|
||||
|
||||
width = contexts[1].display.dw+1;
|
||||
width /= contexts[1].display.magh+1;
|
||||
height = contexts[1].display.dh+1;
|
||||
|
||||
if (height >= (width * 1.3))
|
||||
height = height / 2;
|
||||
|
||||
memset((uint8_t*)drawBuf, 0, 4*1024*1024);
|
||||
|
||||
for (int y = start_scanline; y < height; y += y_increment)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
int32_t pixel_x = x;
|
||||
int32_t pixel_y = y;
|
||||
|
||||
if (!is_in_frame(contexts[1].display, display2_xoffset, display2_yoffset, pixel_x, pixel_y))
|
||||
continue;
|
||||
|
||||
uint32_t output2 = ReadVram32(contexts[1].dispfb.fbp, contexts[1].dispfb.fbw, x, y);
|
||||
|
||||
uint8_t r = output2 & 0xff;
|
||||
uint8_t g = (output2 >> 8) & 0xff;
|
||||
uint8_t b = (output2 >> 16) & 0xff;
|
||||
uint8_t a = (output2 >> 24) & 0xff;
|
||||
|
||||
uint32_t final_color = r | (g << 8) | (b << 16) | (a << 24);
|
||||
|
||||
if (smode2.interlace)
|
||||
{
|
||||
if (smode2.ffmd)
|
||||
{
|
||||
pixel_y *= 2;
|
||||
target[pixel_x + (pixel_y*width)] = final_color;
|
||||
target[pixel_x + ((csr.field ? pixel_y+1 : pixel_y-1)*width)] = final_color;
|
||||
}
|
||||
else
|
||||
target[pixel_x + (pixel_y*width)] = final_color;
|
||||
}
|
||||
else
|
||||
target[pixel_x + (pixel_y*width)] = final_color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetVblankStart(bool start)
|
||||
{
|
||||
csr.vsint = start;
|
||||
|
||||
if (start)
|
||||
{
|
||||
int width = contexts[1].display.dw+1;
|
||||
width /= contexts[1].display.magh+1;
|
||||
int height = contexts[1].display.dh+1;
|
||||
|
||||
render_frame();
|
||||
|
||||
SDL_Surface* sur = SDL_CreateRGBSurfaceFrom(drawBuf, width, height, 32, width*4, 0xFF, 0xFF00, 0xFF0000, 0xFF000000);
|
||||
|
||||
SDL_Surface* winSur = SDL_GetWindowSurface(window);
|
||||
|
||||
SDL_BlitScaled(sur, NULL, winSur, NULL);
|
||||
SDL_UpdateWindowSurface(window);
|
||||
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
case SDL_QUIT:
|
||||
SDL_Quit();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetHblank(bool hb)
|
||||
{
|
||||
csr.hsint = hb;
|
||||
}
|
||||
|
||||
void UpdateOddFrame()
|
||||
{
|
||||
csr.field = !csr.field;
|
||||
}
|
||||
|
||||
void WriteGSCSR(uint64_t data)
|
||||
{
|
||||
|
@ -54,4 +861,97 @@ void WriteGSCSR(uint64_t data)
|
|||
}
|
||||
}
|
||||
|
||||
} // namespace GS
|
||||
uint64_t ReadGSCSR()
|
||||
{
|
||||
uint64_t reg = csr.data;
|
||||
|
||||
reg |= 0x1B << 16;
|
||||
reg |= 0x55 << 24;
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
void WriteIMR(uint64_t data)
|
||||
{
|
||||
imr.value = data;
|
||||
}
|
||||
|
||||
bool VSIntEnabled()
|
||||
{
|
||||
return !imr.vsmsk;
|
||||
}
|
||||
|
||||
bool HSIntEnabled()
|
||||
{
|
||||
return !imr.hsmsk;
|
||||
}
|
||||
|
||||
void WritePRIM(uint64_t data)
|
||||
{
|
||||
printf("Write 0x%08lx to prim\n", data);
|
||||
prim.data = data;
|
||||
}
|
||||
|
||||
void UpdateFPS(double fps)
|
||||
{
|
||||
static char buf[256];
|
||||
|
||||
int width = contexts[1].display.dw+1;
|
||||
width /= contexts[1].display.magh+1;
|
||||
int height = contexts[1].display.dh+1;
|
||||
|
||||
sprintf(buf, "Emotional - PS2 Emulator: %dx%d, %f fps\n", width, height, fps);
|
||||
SDL_SetWindowTitle(window, buf);
|
||||
}
|
||||
|
||||
void WriteBGCOLOR(uint64_t data)
|
||||
{
|
||||
}
|
||||
|
||||
void WriteDISPFB1(uint64_t data)
|
||||
{
|
||||
auto& dispfb = contexts[0].dispfb;
|
||||
dispfb.value = data;
|
||||
printf("Area 1 read buffer is now at 0x%08x, %d pixels wide, format %d\n", dispfb.fbp*2048, dispfb.fbw*64, dispfb.psm);
|
||||
}
|
||||
|
||||
void WriteDISPLAY1(uint64_t data)
|
||||
{
|
||||
auto& display = contexts[0].display;
|
||||
contexts[0].display.value = data;
|
||||
|
||||
int width = contexts[1].display.dw+1;
|
||||
width /= contexts[1].display.magh+1;
|
||||
int height = contexts[0].display.dh+1;
|
||||
|
||||
printf("DISPLAY1 area is now %dx%d\n", width, height);
|
||||
}
|
||||
|
||||
void WriteDISPFB2(uint64_t data)
|
||||
{
|
||||
auto& dispfb = contexts[1].dispfb;
|
||||
dispfb.value = data;
|
||||
printf("Area 2 read buffer is now at 0x%08x, %d pixels wide, format %d\n", dispfb.fbp*2048, dispfb.fbw*64, dispfb.psm);
|
||||
}
|
||||
|
||||
void WriteDISPLAY2(uint64_t data)
|
||||
{
|
||||
auto& display = contexts[1].display;
|
||||
contexts[1].display.value = data;
|
||||
|
||||
int width = contexts[1].display.dw+1;
|
||||
width /= contexts[1].display.magh+1;
|
||||
int height = contexts[1].display.dh+1;
|
||||
|
||||
printf("DISPLAY2 area is now %dx%d (0x%08lx)\n", width, height, data);
|
||||
|
||||
// if (contexts[1].display.dh != 0 && contexts[1].display.dw != 0)
|
||||
// {
|
||||
// SDL_DestroyRenderer(renderer);
|
||||
// SDL_DestroyWindow(window);
|
||||
|
||||
// window = SDL_CreateWindow("Emotional - PS2 Emulator", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, 0);
|
||||
// renderer = SDL_CreateRenderer(window, -1, -1);
|
||||
// }
|
||||
}
|
||||
} // namespace GS
|
||||
|
|
|
@ -8,12 +8,43 @@
|
|||
namespace GS
|
||||
{
|
||||
|
||||
void Initialize();
|
||||
void DumpVram();
|
||||
|
||||
void SetVblankStart(bool start);
|
||||
void SetHblank(bool hb);
|
||||
void UpdateOddFrame();
|
||||
|
||||
void WriteGSCSR(uint64_t data);
|
||||
uint64_t ReadGSCSR();
|
||||
|
||||
void WriteIMR(uint64_t data);
|
||||
|
||||
bool VSIntEnabled();
|
||||
bool HSIntEnabled();
|
||||
|
||||
void WritePRIM(uint64_t data);
|
||||
|
||||
void UpdateFPS(double fps);
|
||||
|
||||
void WriteBGCOLOR(uint64_t data);
|
||||
void WriteDISPFB1(uint64_t data);
|
||||
void WriteDISPLAY1(uint64_t data);
|
||||
void WriteDISPFB2(uint64_t data);
|
||||
void WriteDISPLAY2(uint64_t data);
|
||||
|
||||
// Used by the GIF to send data
|
||||
void WriteRegister(uint64_t reg, uint64_t data);
|
||||
void WriteHWReg(uint64_t data);
|
||||
void WriteRGBAQ(uint8_t r, uint8_t g, uint8_t b, uint8_t a, float q = 1.0f);
|
||||
void WriteXYZF(int32_t x, int32_t y, int32_t z, uint8_t f, bool adc);
|
||||
|
||||
inline void WriteGSSMODE1(uint64_t data) {}
|
||||
inline void WriteGSSMODE2(uint64_t data) {}
|
||||
void WriteGSSMODE2(uint64_t data);
|
||||
inline void WriteGSSRFSH(uint64_t data) {}
|
||||
inline void WriteGSSYNCH1(uint64_t data) {}
|
||||
inline void WriteGSSYNCH2(uint64_t data) {}
|
||||
inline void WriteGSSYNCV(uint64_t data) {}
|
||||
inline void WriteGSPMODE(uint64_t data) {}
|
||||
|
||||
} // namespace GS
|
||||
|
|
430
src/emu/gpu/gs_types.h
Normal file
430
src/emu/gpu/gs_types.h
Normal file
|
@ -0,0 +1,430 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace GS
|
||||
{
|
||||
|
||||
union GS_CSR
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
uint32_t signal : 1;
|
||||
uint32_t finish : 1;
|
||||
uint32_t hsint : 1;
|
||||
uint32_t vsint : 1;
|
||||
uint32_t edwint : 1;
|
||||
uint32_t : 3;
|
||||
uint32_t flush : 1;
|
||||
uint32_t reset : 1;
|
||||
uint32_t : 2;
|
||||
uint32_t nfield : 1;
|
||||
uint32_t field : 1;
|
||||
uint32_t fifo : 2;
|
||||
uint32_t rev : 8;
|
||||
uint32_t id : 8;
|
||||
};
|
||||
};
|
||||
|
||||
union GS_IMR
|
||||
{
|
||||
uint32_t value;
|
||||
struct
|
||||
{
|
||||
uint32_t : 8;
|
||||
uint32_t sigmsk : 1;
|
||||
uint32_t finishmsk : 1;
|
||||
uint32_t hsmsk : 1;
|
||||
uint32_t vsmsk : 1;
|
||||
uint32_t edwmsk : 1;
|
||||
uint32_t : 19;
|
||||
};
|
||||
};
|
||||
|
||||
union DISPFB
|
||||
{
|
||||
uint64_t value;
|
||||
struct
|
||||
{
|
||||
uint64_t fbp : 9;
|
||||
uint64_t fbw : 6;
|
||||
uint64_t psm : 5;
|
||||
uint64_t : 12;
|
||||
uint64_t dbx : 11;
|
||||
uint64_t dby : 11;
|
||||
uint64_t : 10;
|
||||
};
|
||||
};
|
||||
|
||||
union DISPLAY
|
||||
{
|
||||
uint64_t value;
|
||||
struct
|
||||
{
|
||||
uint64_t dx : 12;
|
||||
uint64_t dy : 11;
|
||||
uint64_t magh : 4;
|
||||
uint64_t magv : 2;
|
||||
uint64_t : 3;
|
||||
uint64_t dw : 12;
|
||||
uint64_t dh : 11;
|
||||
uint64_t : 9;
|
||||
};
|
||||
};
|
||||
|
||||
union XYOFFSET
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
uint64_t : 4;
|
||||
uint64_t ofx : 12;
|
||||
uint64_t : 20;
|
||||
uint64_t ofy : 12;
|
||||
uint64_t : 16;
|
||||
};
|
||||
};
|
||||
|
||||
union TEX0
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
uint64_t tbp0 : 14;
|
||||
uint64_t tbw : 6;
|
||||
uint64_t psm : 6;
|
||||
uint64_t tw : 4;
|
||||
uint64_t th : 4;
|
||||
uint64_t tcc : 1;
|
||||
uint64_t tfx : 2;
|
||||
uint64_t cbp : 14;
|
||||
uint64_t cpsm : 4;
|
||||
uint64_t csm : 1;
|
||||
uint64_t csa : 5;
|
||||
uint64_t cld : 3;
|
||||
};
|
||||
};
|
||||
|
||||
union TEX1
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
uint64_t lcm : 1;
|
||||
uint64_t : 1;
|
||||
uint64_t mxl : 3;
|
||||
uint64_t mmag : 1;
|
||||
uint64_t mmin : 3;
|
||||
uint64_t mtba : 1;
|
||||
uint64_t : 9;
|
||||
uint64_t l : 2;
|
||||
uint64_t : 4;
|
||||
uint64_t k : 7;
|
||||
uint64_t : 1;
|
||||
uint64_t : 20;
|
||||
};
|
||||
};
|
||||
|
||||
union TEX2
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
uint64_t : 20;
|
||||
uint64_t psm : 6;
|
||||
uint64_t : 11;
|
||||
uint64_t cbp : 14;
|
||||
uint64_t cpsm : 4;
|
||||
uint64_t csm : 1;
|
||||
uint64_t csa : 5;
|
||||
uint64_t cld : 3;
|
||||
};
|
||||
};
|
||||
|
||||
union TEXCLUT
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
uint64_t cbw : 6;
|
||||
uint64_t cou : 6;
|
||||
uint64_t cov : 10;
|
||||
uint64_t : 42;
|
||||
};
|
||||
};
|
||||
|
||||
union SCISSOR
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
uint64_t scax0 : 11;
|
||||
uint64_t : 5;
|
||||
uint64_t scax1 : 11;
|
||||
uint64_t : 5;
|
||||
uint64_t scay0 : 11;
|
||||
uint64_t : 5;
|
||||
uint64_t scay1 : 11;
|
||||
uint64_t : 5;
|
||||
};
|
||||
};
|
||||
|
||||
union FRAME
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
uint64_t fbp : 9;
|
||||
uint64_t : 7;
|
||||
uint64_t fbw : 6;
|
||||
uint64_t : 2;
|
||||
uint64_t psm : 6;
|
||||
uint64_t : 2;
|
||||
uint64_t fbmsk : 32;
|
||||
};
|
||||
};
|
||||
|
||||
union ZBUF
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
uint64_t zbp : 9;
|
||||
uint64_t : 15;
|
||||
uint64_t psm : 4;
|
||||
uint64_t : 4;
|
||||
uint64_t zmsk : 1;
|
||||
uint64_t : 31;
|
||||
};
|
||||
};
|
||||
|
||||
union TEST
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
uint64_t ate : 1;
|
||||
uint64_t atst : 3;
|
||||
uint64_t aref : 8;
|
||||
uint64_t afail : 2;
|
||||
uint64_t date : 1;
|
||||
uint64_t datm : 1;
|
||||
uint64_t zte : 1;
|
||||
uint64_t ztst : 2;
|
||||
uint64_t : 45;
|
||||
};
|
||||
};
|
||||
|
||||
struct Context
|
||||
{
|
||||
DISPFB dispfb;
|
||||
DISPLAY display;
|
||||
XYOFFSET xyoffset;
|
||||
TEX0 tex0;
|
||||
TEX1 tex1;
|
||||
TEX2 tex2;
|
||||
SCISSOR scissor;
|
||||
FRAME frame;
|
||||
ZBUF zbuf;
|
||||
TEST test;
|
||||
};
|
||||
|
||||
union PRMODE
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
uint64_t : 3;
|
||||
uint64_t iip : 1;
|
||||
uint64_t tme : 1;
|
||||
uint64_t fge : 1;
|
||||
uint64_t abe : 1;
|
||||
uint64_t aa1 : 1;
|
||||
uint64_t fst : 1;
|
||||
uint64_t ctxt : 1;
|
||||
uint64_t fix : 1;
|
||||
uint64_t : 53;
|
||||
};
|
||||
};
|
||||
|
||||
union RGBAQ
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
uint64_t r : 8;
|
||||
uint64_t g : 8;
|
||||
uint64_t b : 8;
|
||||
uint64_t a : 8;
|
||||
uint64_t q : 32;
|
||||
};
|
||||
};
|
||||
|
||||
union ST
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
float s;
|
||||
float t;
|
||||
};
|
||||
};
|
||||
|
||||
union UV
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
uint64_t : 4;
|
||||
uint64_t u : 10;
|
||||
uint64_t : 6;
|
||||
uint64_t v : 10;
|
||||
uint64_t : 34;
|
||||
};
|
||||
};
|
||||
|
||||
union TEXA
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
uint64_t ta0 : 8;
|
||||
uint64_t : 7;
|
||||
uint64_t aem : 1;
|
||||
uint64_t : 16;
|
||||
uint64_t ta1 : 8;
|
||||
uint64_t : 24;
|
||||
};
|
||||
};
|
||||
|
||||
union FOGCOL
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
uint64_t fcr : 8;
|
||||
uint64_t fcg : 8;
|
||||
uint64_t fcb : 8;
|
||||
uint64_t : 40;
|
||||
};
|
||||
};
|
||||
|
||||
union Bitbltbuf
|
||||
{
|
||||
uint64_t value;
|
||||
struct
|
||||
{
|
||||
uint64_t sbp : 14;
|
||||
uint64_t : 2;
|
||||
uint64_t sbw : 6;
|
||||
uint64_t : 2;
|
||||
uint64_t spsm : 6;
|
||||
uint64_t : 2;
|
||||
uint64_t dbp : 14;
|
||||
uint64_t : 2;
|
||||
uint64_t dbw : 6;
|
||||
uint64_t : 2;
|
||||
uint64_t dpsm : 6;
|
||||
uint64_t : 2;
|
||||
};
|
||||
};
|
||||
|
||||
union TRXPOS
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
uint64_t ssax : 11;
|
||||
uint64_t : 5;
|
||||
uint64_t ssay : 11;
|
||||
uint64_t : 5;
|
||||
uint64_t dsax : 11;
|
||||
uint64_t : 5;
|
||||
uint64_t dsay : 11;
|
||||
uint64_t dir : 2;
|
||||
uint64_t : 3;
|
||||
};
|
||||
};
|
||||
|
||||
union TRXREG
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
uint64_t rrw : 12;
|
||||
uint64_t : 20;
|
||||
uint64_t rrh : 12;
|
||||
uint64_t : 20;
|
||||
};
|
||||
};
|
||||
|
||||
union PRIM
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
uint64_t prim : 3;
|
||||
uint64_t iip : 1;
|
||||
uint64_t tme : 1;
|
||||
uint64_t fge : 1;
|
||||
uint64_t abe : 1;
|
||||
uint64_t aa1 : 1;
|
||||
uint64_t fst : 1;
|
||||
uint64_t ctxt : 1;
|
||||
uint64_t fix : 1;
|
||||
uint64_t : 53;
|
||||
};
|
||||
};
|
||||
|
||||
union XYZF
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
uint64_t : 4;
|
||||
uint64_t x : 12;
|
||||
uint64_t : 4;
|
||||
uint64_t y : 12;
|
||||
uint64_t z : 24;
|
||||
uint64_t f : 8;
|
||||
};
|
||||
};
|
||||
|
||||
struct Vector3
|
||||
{
|
||||
int32_t x, y;
|
||||
uint32_t z;
|
||||
};
|
||||
|
||||
struct RGBAQ_Data
|
||||
{
|
||||
uint32_t r, g, b, a;
|
||||
float q;
|
||||
};
|
||||
|
||||
struct UV_Data
|
||||
{
|
||||
uint32_t u, v;
|
||||
};
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
Vector3 vert;
|
||||
RGBAQ_Data rgba;
|
||||
UV_Data uv;
|
||||
};
|
||||
|
||||
union SMODE2
|
||||
{
|
||||
uint64_t data;
|
||||
struct
|
||||
{
|
||||
uint64_t interlace : 1;
|
||||
uint64_t ffmd : 1;
|
||||
uint64_t dpms : 1;
|
||||
uint64_t : 61;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <emu/gpu/gif.hpp>
|
||||
#include <emu/cpu/ee/dmac.hpp>
|
||||
#include "Bus.h"
|
||||
|
||||
uint8_t* BiosRom;
|
||||
uint8_t spr[0x4000];
|
||||
|
@ -27,6 +28,7 @@ uint32_t rdram_sdevid;
|
|||
|
||||
uint32_t INTC_MASK = 0, INTC_STAT = 0;
|
||||
uint32_t Bus::I_MASK = 0, Bus::I_STAT = 0, Bus::I_CTRL = 0;
|
||||
uint32_t Bus::spu2_stat = 0;
|
||||
|
||||
uint32_t Translate(uint32_t addr)
|
||||
{
|
||||
|
@ -61,6 +63,8 @@ void Bus::LoadBios(uint8_t *data)
|
|||
|
||||
memcpy(BiosRom, data, 0x400000);
|
||||
console.open("console.txt");
|
||||
|
||||
GS::Initialize();
|
||||
}
|
||||
|
||||
void Bus::Dump()
|
||||
|
@ -91,6 +95,36 @@ void Bus::Dump()
|
|||
}
|
||||
|
||||
dump.close();
|
||||
|
||||
printf("[emu/Bus]: IOP_ISTAT: 0x%08x, IOP_IMASK: 0x%08x\n", I_STAT, I_MASK);
|
||||
}
|
||||
|
||||
uint8_t *Bus::GetRamPtr()
|
||||
{
|
||||
return ram;
|
||||
}
|
||||
|
||||
uint8_t *Bus::GetSprPtr()
|
||||
{
|
||||
return spr;
|
||||
}
|
||||
|
||||
uint8_t *Bus::GetPtrForAddress(uint32_t addr)
|
||||
{
|
||||
addr = Translate(addr);
|
||||
|
||||
if (addr < 0x10000000)
|
||||
{
|
||||
addr &= (1024*1024*32)-1;
|
||||
return ram+addr;
|
||||
}
|
||||
if (addr >= 0x1FC00000 && addr < 0x20000000)
|
||||
{
|
||||
addr &= (1024*1024*4)-1;
|
||||
return BiosRom+addr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint128_t Bus::Read128(uint32_t addr)
|
||||
|
@ -99,6 +133,8 @@ uint128_t Bus::Read128(uint32_t addr)
|
|||
|
||||
if (addr < 0x2000000)
|
||||
return {*reinterpret_cast<__uint128_t*>(&ram[addr])};
|
||||
if (addr >= 0x1C000000 && addr < 0x1C200000)
|
||||
return {*reinterpret_cast<__uint128_t*>(&iop_ram[addr-0x1C000000])};
|
||||
|
||||
printf("Read128 from unknown address 0x%08x\n", addr);
|
||||
exit(1);
|
||||
|
@ -114,6 +150,14 @@ uint64_t Bus::Read64(uint32_t addr)
|
|||
return *reinterpret_cast<uint64_t*>(&spr[addr - 0x70000000]);
|
||||
if (addr < 0x2000000)
|
||||
return *reinterpret_cast<uint64_t*>(&ram[addr]);
|
||||
if (addr >= 0x1C000000 && addr < 0x1C200000)
|
||||
return *reinterpret_cast<uint64_t*>(&iop_ram[addr-0x1C000000]);
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x12001000:
|
||||
return GS::ReadGSCSR();
|
||||
}
|
||||
|
||||
printf("Read64 from unknown address 0x%08x\n", addr);
|
||||
exit(1);
|
||||
|
@ -194,6 +238,18 @@ uint32_t Bus::Read32(uint32_t addr)
|
|||
return SIF::ReadSMFLG();
|
||||
case 0x1000F520:
|
||||
return DMAC::ReadDENABLE();
|
||||
case 0x1000A000:
|
||||
case 0x1000A010:
|
||||
case 0x1000A030:
|
||||
case 0x1000A040:
|
||||
case 0x1000A050:
|
||||
case 0x1000A080:
|
||||
return DMAC::ReadGIFChannel(addr);
|
||||
case 0x12001000:
|
||||
return GS::ReadGSCSR() & 0xffffffff;
|
||||
case 0x10001000:
|
||||
case 0x10001010:
|
||||
case 0x10001810:
|
||||
case 0x10002010:
|
||||
return 0;
|
||||
}
|
||||
|
@ -239,6 +295,8 @@ uint8_t Bus::Read8(uint32_t addr)
|
|||
return spr[addr - 0x70000000];
|
||||
if (addr < 0x2000000)
|
||||
return ram[addr];
|
||||
if (addr >= 0x1C000000 && addr < 0x1C200000)
|
||||
return iop_ram[addr-0x1C000000];
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
|
@ -330,6 +388,9 @@ void Bus::Write64(uint32_t addr, uint64_t data)
|
|||
case 0x12001000:
|
||||
GS::WriteGSCSR(data);
|
||||
return;
|
||||
case 0x12000000:
|
||||
GS::WriteGSPMODE(data);
|
||||
return;
|
||||
case 0x12000010:
|
||||
GS::WriteGSSMODE1(data);
|
||||
return;
|
||||
|
@ -348,6 +409,27 @@ void Bus::Write64(uint32_t addr, uint64_t data)
|
|||
case 0x12000060:
|
||||
GS::WriteGSSYNCV(data);
|
||||
return;
|
||||
case 0x12000070:
|
||||
GS::WriteDISPFB1(data);
|
||||
return;
|
||||
case 0x12000080:
|
||||
GS::WriteDISPLAY1(data);
|
||||
return;
|
||||
case 0x12000090:
|
||||
GS::WriteDISPFB2(data);
|
||||
return;
|
||||
case 0x120000A0:
|
||||
GS::WriteDISPLAY2(data);
|
||||
return;
|
||||
case 0x120000E0:
|
||||
GS::WriteBGCOLOR(data);
|
||||
return;
|
||||
case 0x12001010:
|
||||
GS::WriteIMR(data);
|
||||
return;
|
||||
case 0x10000800: // Timer 1
|
||||
case 0x10000810:
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Write64 0x%08lx to unknown address 0x%08x\n", data, addr);
|
||||
|
@ -397,9 +479,11 @@ void Bus::Write32(uint32_t addr, uint32_t data)
|
|||
case 0x1f80141c:
|
||||
return;
|
||||
case 0x1000f000:
|
||||
printf("Writing 0x%08x to INTC_STAT\n", data);
|
||||
INTC_STAT &= ~(data);
|
||||
return;
|
||||
case 0x1000f010:
|
||||
printf("Writing 0x%08x to INTC_MASK\n", data);
|
||||
INTC_MASK = data;
|
||||
return;
|
||||
case 0x1000f500: // EE TLB enable?
|
||||
|
@ -459,6 +543,7 @@ void Bus::Write32(uint32_t addr, uint32_t data)
|
|||
return;
|
||||
case 0x1000A000:
|
||||
case 0x1000A010:
|
||||
case 0x1000A020:
|
||||
case 0x1000A030:
|
||||
case 0x1000A040:
|
||||
case 0x1000A050:
|
||||
|
@ -570,6 +655,9 @@ void Bus::Write32(uint32_t addr, uint32_t data)
|
|||
case 0x1000F590:
|
||||
DMAC::WriteDENABLE(data);
|
||||
return;
|
||||
case 0x12001000:
|
||||
GS::WriteGSCSR((GS::ReadGSCSR() & 0xffffffff00000000) | data);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Write32 0x%08x to unknown address 0x%08x\n", data, addr);
|
||||
|
@ -633,3 +721,78 @@ void Bus::Write8(uint32_t addr, uint8_t data)
|
|||
printf("Write8 to unknown address 0x%08x\n", addr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uint32_t Bus::LoadElf(std::string name)
|
||||
{
|
||||
struct Elf32_Hdr
|
||||
{
|
||||
uint8_t e_ident[16];
|
||||
uint16_t e_type;
|
||||
uint16_t e_machine;
|
||||
uint32_t e_version;
|
||||
uint32_t e_entry;
|
||||
uint32_t e_phoff;
|
||||
uint32_t e_shoff;
|
||||
uint32_t e_flags;
|
||||
uint16_t e_ehsize;
|
||||
uint16_t e_phentsize;
|
||||
uint16_t e_phnum;
|
||||
uint16_t e_shentsize;
|
||||
uint16_t e_shnum;
|
||||
uint16_t e_shstrndx;
|
||||
};
|
||||
|
||||
struct Elf32_Phdr
|
||||
{
|
||||
uint32_t p_type;
|
||||
uint32_t p_offset;
|
||||
uint32_t p_vaddr;
|
||||
uint32_t p_paddr;
|
||||
uint32_t p_filesz;
|
||||
uint32_t p_memsz;
|
||||
uint32_t p_flags;
|
||||
uint32_t p_align;
|
||||
};
|
||||
|
||||
std::ifstream reader;
|
||||
reader.open(name, std::ios::in | std::ios::binary);
|
||||
|
||||
reader.seekg(0, std::ios::end);
|
||||
int size = reader.tellg();
|
||||
uint8_t* buffer = new uint8_t[size];
|
||||
|
||||
reader.seekg(0, std::ios::beg);
|
||||
reader.read((char*)buffer, size);
|
||||
reader.close();
|
||||
|
||||
auto header = *(Elf32_Hdr*)&buffer[0];
|
||||
printf("[CORE][ELF] Loading %s\n", name.c_str());
|
||||
printf("Entry: 0x%x\n", header.e_entry);
|
||||
printf("Program header start: 0x%x\n", header.e_phoff);
|
||||
printf("Section header start: 0x%x\n", header.e_shoff);
|
||||
printf("Program header entries: %d\n", header.e_phnum);
|
||||
printf("Section header entries: %d\n", header.e_shnum);
|
||||
printf("Section header names index: %d\n", header.e_shstrndx);
|
||||
|
||||
for (auto i = header.e_phoff; i < header.e_phoff + (header.e_phnum*0x20); i += 0x20)
|
||||
{
|
||||
auto pheader = *(Elf32_Phdr*)&buffer[i];
|
||||
|
||||
int mem_w = pheader.p_paddr;
|
||||
for (auto file_w = pheader.p_offset; file_w < pheader.p_offset+pheader.p_filesz; file_w += 4)
|
||||
{
|
||||
uint32_t word = *(uint32_t*)&buffer[file_w];
|
||||
Write32(mem_w, word);
|
||||
mem_w += 4;
|
||||
}
|
||||
}
|
||||
|
||||
return header.e_entry;
|
||||
}
|
||||
|
||||
void Bus::TriggerEEInterrupt(int i_num)
|
||||
{
|
||||
INTC_STAT |= (1 << i_num);
|
||||
if (INTC_STAT & INTC_MASK)
|
||||
EmotionEngine::SetIp0Pending();
|
||||
}
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
#include <emu/cpu/iop/dma.h>
|
||||
#include <emu/dev/cdvd.h>
|
||||
#include <emu/dev/sif.h>
|
||||
#include <emu/dev/sio2.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
uint32_t Translate(uint32_t addr);
|
||||
extern uint8_t* BiosRom;
|
||||
|
@ -21,6 +23,11 @@ void LoadBios(uint8_t* data);
|
|||
|
||||
void Dump();
|
||||
|
||||
uint8_t* GetRamPtr();
|
||||
uint8_t* GetSprPtr();
|
||||
uint8_t* GetPtrForAddress(uint32_t addr);
|
||||
|
||||
|
||||
uint128_t Read128(uint32_t addr);
|
||||
uint64_t Read64(uint32_t addr);
|
||||
uint32_t Read32(uint32_t addr);
|
||||
|
@ -34,6 +41,9 @@ void Write16(uint32_t addr, uint16_t data);
|
|||
void Write8(uint32_t addr, uint8_t data);
|
||||
|
||||
extern uint32_t I_MASK, I_STAT, I_CTRL;
|
||||
extern uint32_t spu2_stat;
|
||||
|
||||
uint32_t LoadElf(std::string name);
|
||||
|
||||
template<typename T>
|
||||
T iop_read(uint32_t addr)
|
||||
|
@ -98,6 +108,30 @@ T iop_read(uint32_t addr)
|
|||
case 0x1f801540 ... 0x1f80154C:
|
||||
case 0x1f801550 ... 0x1f80155C:
|
||||
return IopDma::ReadNewChannel(addr);
|
||||
case 0x1f402018:
|
||||
return CDVD::ReadSResult();
|
||||
case 0x1f402017:
|
||||
return CDVD::ReadSStatus();
|
||||
case 0x1f402016:
|
||||
return CDVD::ReadSCommand();
|
||||
case 0x1f900744:
|
||||
{
|
||||
uint16_t copy = spu2_stat;
|
||||
spu2_stat &= ~0x80;
|
||||
return copy;
|
||||
}
|
||||
case 0x1f900000 ... 0x1f900743:
|
||||
case 0x1f900745 ... 0x1f900780:
|
||||
case 0x1f900b60 ... 0x1f900B70:
|
||||
return 0;
|
||||
case 0x1f801080 ... 0x1f80108C:
|
||||
case 0x1f801090 ... 0x1f80109C:
|
||||
case 0x1f8010A0 ... 0x1f8010AC:
|
||||
case 0x1f8010B0 ... 0x1f8010BC:
|
||||
case 0x1f8010C0 ... 0x1f8010CC:
|
||||
case 0x1f8010D0 ... 0x1f8010DC:
|
||||
case 0x1f8010E0 ... 0x1f8010EC:
|
||||
return IopDma::ReadChannel(addr);
|
||||
}
|
||||
|
||||
printf("[emu/IopBus]: Read from unknown addr 0x%08x\n", addr);
|
||||
|
@ -157,6 +191,9 @@ void iop_write(uint32_t addr, T data)
|
|||
case 0x1ffe0130:
|
||||
case 0x1ffe0140:
|
||||
return;
|
||||
case 0x1f900000 ... 0x1f900800:
|
||||
case 0x1f900b60 ... 0x1f900B70:
|
||||
return;
|
||||
case 0x1ffe0144:
|
||||
printf("[emu/IOP]: Scratchpad start 0x%08x\n", data);
|
||||
return;
|
||||
|
@ -167,7 +204,7 @@ void iop_write(uint32_t addr, T data)
|
|||
I_MASK = data;
|
||||
return;
|
||||
case 0x1f801078:
|
||||
I_CTRL = data;
|
||||
I_CTRL = data & 1;
|
||||
return;
|
||||
case 0x1f8010f0:
|
||||
IopDma::WriteDPCR(data);
|
||||
|
@ -209,15 +246,24 @@ void iop_write(uint32_t addr, T data)
|
|||
case 0x1F801490 ... 0x1F801498:
|
||||
case 0x1F8014A0 ... 0x1F8014A8:
|
||||
return;
|
||||
case 0x1f402016:
|
||||
CDVD::AddSCommand(data & 0xff);
|
||||
return;
|
||||
case 0x1f808268:
|
||||
SIO2::WriteCtrl(data);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("[emu/IopBus]: Write to unknown addr 0x%08x\n", addr);
|
||||
printf("[emu/IopBus]: Write 0x%08x to unknown addr 0x%08x\n", data, addr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
inline void TriggerIOPInterrupt(int i_num)
|
||||
{
|
||||
printf("[emu/IOP]: Trigerring interrupt %d\n", i_num);
|
||||
I_STAT |= (1 << i_num);
|
||||
}
|
||||
|
||||
void TriggerEEInterrupt(int i_num);
|
||||
|
||||
} // namespace Bus
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <cinttypes>
|
||||
#include "scheduler.h"
|
||||
|
||||
namespace Scheduler
|
||||
{
|
||||
|
@ -17,50 +18,63 @@ uintmax_t global_cycles = 0;
|
|||
|
||||
std::vector<Event> event_queue;
|
||||
|
||||
void InitScheduler()
|
||||
{
|
||||
std::make_heap(event_queue.begin(), event_queue.end());
|
||||
}
|
||||
|
||||
bool CompareEvents(const Event& a, const Event& b)
|
||||
{
|
||||
return a.cycles_from_now > b.cycles_from_now;
|
||||
}
|
||||
|
||||
void InitScheduler()
|
||||
{
|
||||
std::make_heap(event_queue.begin(), event_queue.end(), CompareEvents);
|
||||
}
|
||||
|
||||
void ScheduleEvent(Event event)
|
||||
{
|
||||
event.cycles_from_now += global_cycles;
|
||||
if (event.cycles_from_now < global_cycles) // Overflow detected
|
||||
{
|
||||
printf("[emu/Sched]: Overflow found\n");
|
||||
for (auto& e : event_queue)
|
||||
{
|
||||
e.cycles_from_now = e.cycles_from_now - global_cycles;
|
||||
}
|
||||
global_cycles = 0;
|
||||
}
|
||||
event_queue.emplace_back(event);
|
||||
std::push_heap(event_queue.begin(), event_queue.end(), CompareEvents);
|
||||
}
|
||||
|
||||
int iop_cycles = 0;
|
||||
uint64_t next_tp = 0;
|
||||
|
||||
void CheckScheduler(int cycles)
|
||||
void CheckScheduler(uint64_t cycles)
|
||||
{
|
||||
global_cycles += cycles;
|
||||
|
||||
IOP_MANAGEMENT::Clock(cycles / 4);
|
||||
|
||||
if (event_queue.empty())
|
||||
if (!next_tp && !event_queue.empty())
|
||||
{
|
||||
next_tp = event_queue.front().cycles_from_now;
|
||||
}
|
||||
|
||||
if (global_cycles < next_tp)
|
||||
return;
|
||||
|
||||
if (event_queue.empty())
|
||||
return;
|
||||
|
||||
while (event_queue.front().cycles_from_now <= global_cycles)
|
||||
{
|
||||
auto e = event_queue.front();
|
||||
std::pop_heap(event_queue.begin(), event_queue.end());
|
||||
std::pop_heap(event_queue.begin(), event_queue.end(), CompareEvents);
|
||||
event_queue.pop_back();
|
||||
e.func();
|
||||
next_tp = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the cycles until the next event
|
||||
// Used for ticking the EE
|
||||
size_t GetNextTimestamp()
|
||||
{
|
||||
if (event_queue.size() == 0)
|
||||
return 30;
|
||||
int64_t ts = event_queue.front().cycles_from_now - global_cycles;
|
||||
if (ts < 0)
|
||||
return 30;
|
||||
return event_queue.front().cycles_from_now - global_cycles;
|
||||
}
|
||||
} // namespace Scheduler
|
||||
|
|
|
@ -26,6 +26,8 @@ struct Event
|
|||
|
||||
void InitScheduler();
|
||||
void ScheduleEvent(Event event);
|
||||
void CheckScheduler(int cycles);
|
||||
void CheckScheduler(uint64_t cycles);
|
||||
|
||||
size_t GetNextTimestamp();
|
||||
|
||||
} // namespace Scheduler
|
||||
|
|
|
@ -25,7 +25,7 @@ inline char* print_128(uint128_t s)
|
|||
|
||||
memset(ret, 0, 512);
|
||||
|
||||
sprintf(ret, "%016lx %016lx", s.u64[1], s.u64[0]);
|
||||
sprintf(ret, "0x%016lx%016lx", s.u64[1], s.u64[0]);
|
||||
|
||||
return ret;
|
||||
}
|
BIN
util/DMACMAN
Normal file
BIN
util/DMACMAN
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
util/EESYNC
Normal file
BIN
util/EESYNC
Normal file
Binary file not shown.
BIN
util/LOADCORE
Normal file
BIN
util/LOADCORE
Normal file
Binary file not shown.
BIN
util/SIFMAN
Normal file
BIN
util/SIFMAN
Normal file
Binary file not shown.
BIN
util/romdumper
Executable file
BIN
util/romdumper
Executable file
Binary file not shown.
86
util/romdumper.cpp
Normal file
86
util/romdumper.cpp
Normal file
|
@ -0,0 +1,86 @@
|
|||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
|
||||
struct RomdirEntry
|
||||
{
|
||||
char name[10];
|
||||
uint16_t ext_info_size;
|
||||
uint32_t file_size;
|
||||
} __attribute__((packed));
|
||||
|
||||
static_assert(sizeof(RomdirEntry) == 16);
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc < 3)
|
||||
{
|
||||
printf("Usage: %s <bios file> <rom file>\n", argv[0]);
|
||||
printf("\tExtracts a file from a PS2 BIOS image\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::ifstream file(argv[1], std::ios::ate | std::ios::binary);
|
||||
size_t size = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
uint8_t* buf = new uint8_t[size];
|
||||
|
||||
file.read((char*)buf, size);
|
||||
|
||||
uint32_t romdir_start = 0;
|
||||
|
||||
// Search for the first instance of "RESET"
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
if (!std::strncmp("RESET", (const char*)&buf[i], 5))
|
||||
{
|
||||
printf("Found \"RESET\" signature at 0x%08x\n", (uint32_t)i);
|
||||
romdir_start = (uint32_t)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (romdir_start == 0)
|
||||
{
|
||||
printf("ERROR: Invalid PS2 BIOS, no romdir found\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
RomdirEntry* entries = (RomdirEntry*)(buf+romdir_start);
|
||||
|
||||
int entryCount = 0;
|
||||
while (entries[entryCount++].name[0] != 0);
|
||||
|
||||
printf("%d entries in ROMDIR\n", entryCount);
|
||||
|
||||
uint32_t pos = 0;
|
||||
for (int i = 0; i < entryCount; i++)
|
||||
{
|
||||
printf("Found entry %s, at 0x%08x\n", entries[i].name, pos);
|
||||
pos += entries[i].file_size;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
|
||||
for (int i = 0; i < entryCount; i++)
|
||||
{
|
||||
printf("0x%08x\n", pos);
|
||||
if (!strncmp(entries[i].name, argv[2], 10))
|
||||
{
|
||||
printf("Found \"%s\" at 0x%08x\n", entries[i].name, pos);
|
||||
|
||||
std::ofstream out(argv[2]);
|
||||
|
||||
out.write((char*)(buf+pos), entries[i].file_size);
|
||||
out.close();
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
pos += entries[i].file_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue