Booting lots of demos now

This commit is contained in:
Your Name 2023-06-10 19:12:46 -04:00
parent da6fdef63a
commit 3a5b21a3c2
39 changed files with 7681 additions and 404 deletions

View file

@ -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()

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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

View 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));
}

View 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
}

View 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;
}

View file

@ -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]);
}
}
}

View file

@ -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

View file

@ -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:

View file

@ -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();
}

View file

@ -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();
}

View file

@ -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()

View file

@ -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();

View file

@ -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()

View file

@ -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;
}

View file

@ -8,4 +8,10 @@
namespace CDVD
{
uint8_t ReadNStatus();
uint8_t ReadSStatus();
void AddSCommand(uint8_t cmd);
uint8_t ReadSCommand();
uint8_t ReadSResult();
}

View file

@ -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();

View file

@ -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
View 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
View file

@ -0,0 +1,10 @@
#pragma once
#include <cstdint>
namespace SIO2
{
void WriteCtrl(uint32_t data);
}

View file

@ -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;

View file

@ -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

View file

@ -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
View 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;
};
};
}

View file

@ -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();
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
util/EESYNC Normal file

Binary file not shown.

BIN
util/LOADCORE Normal file

Binary file not shown.

BIN
util/SIFMAN Normal file

Binary file not shown.

BIN
util/romdumper Executable file

Binary file not shown.

86
util/romdumper.cpp Normal file
View 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;
}