pureikyubu/src/cp.cpp
2024-04-19 10:03:36 +03:00

2469 lines
60 KiB
C++

// CP - command processor
#include "pch.h"
// TODO: It's a bit crooked right now after refactoring, but will settle with time
using namespace Debug;
//
// Stubs
//
static void CPRegRead(uint32_t addr, uint32_t* reg)
{
*reg = Flipper::Gx->CpReadReg((GX::CPMappedRegister)((addr & 0xFF) >> 1));
}
static void CPRegWrite(uint32_t addr, uint32_t data)
{
Flipper::Gx->CpWriteReg((GX::CPMappedRegister)((addr & 0xFF) >> 1), data);
}
// init
void CPOpen()
{
Report(Channel::CP, "Command processor (for GX)\n");
// Command Processor
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_STATUS_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_ENABLE_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_CLR_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_MEMPERF_SEL_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_STM_LOW_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_FIFO_BASEL_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_FIFO_BASEH_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_FIFO_TOPL_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_FIFO_TOPH_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_FIFO_HICNTL_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_FIFO_HICNTH_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_FIFO_LOCNTL_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_FIFO_LOCNTH_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_FIFO_COUNTL_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_FIFO_COUNTH_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_FIFO_WPTRL_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_FIFO_WPTRH_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_FIFO_RPTRL_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_FIFO_RPTRH_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_FIFO_BRKL_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_FIFO_BRKH_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_COUNTER0L_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_COUNTER0H_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_COUNTER1L_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_COUNTER1H_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_COUNTER2L_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_COUNTER2H_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_COUNTER3L_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_COUNTER3H_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_VC_CHKCNTL_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_VC_CHKCNTH_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_VC_MISSL_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_VC_MISSH_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_VC_STALLL_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_VC_STALLH_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_FRCLK_CNTL_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_FRCLK_CNTH_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_XF_ADDR_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_XF_DATAL_ID), CPRegRead, CPRegWrite);
PISetTrap(16, PI_REG16_TO_SPACE(PI_REGSPACE_CP, GX::CPMappedRegister::CP_XF_DATAH_ID), CPRegRead, CPRegWrite);
}
void CPClose()
{
}
namespace GX
{
#pragma region "Dealing with registers"
void GXCore::CP_BREAK()
{
if (cpregs.cr & CP_CR_BPINTEN && (cpregs.sr & CP_SR_BPINT) == 0)
{
cpregs.sr |= CP_SR_BPINT;
PIAssertInt(PI_INTERRUPT_CP);
Report(Channel::CP, "BREAK\n");
}
}
void GXCore::CP_OVF()
{
if (cpregs.cr & CP_CR_OVFEN && (cpregs.sr & CP_SR_OVF) == 0)
{
cpregs.sr |= CP_SR_OVF;
PIAssertInt(PI_INTERRUPT_CP);
Report(Channel::CP, "OVF\n");
}
}
void GXCore::CP_UVF()
{
if (cpregs.cr & CP_CR_UVFEN && (cpregs.sr & CP_SR_UVF) == 0)
{
cpregs.sr |= CP_SR_UVF;
PIAssertInt(PI_INTERRUPT_CP);
Report(Channel::CP, "UVF\n");
}
}
void GXCore::GXWriteFifo(uint8_t dataPtr[32])
{
fifo->WriteBytes(dataPtr);
while (fifo->EnoughToExecute())
{
GxCommand(fifo);
}
}
void GXCore::CPThread(void* Param)
{
GXCore* gx = (GXCore*)Param;
int64_t ticks = Core->GetTicks();
if (ticks < gx->updateTbrValue)
{
return;
}
gx->updateTbrValue = ticks + gx->tickPerFifo;
// Calculate count
if (gx->cpregs.wrptr >= gx->cpregs.rdptr)
{
gx->cpregs.cnt = gx->cpregs.wrptr - gx->cpregs.rdptr;
}
else
{
gx->cpregs.cnt = (gx->cpregs.top - gx->cpregs.rdptr) + (gx->cpregs.wrptr - gx->cpregs.base);
}
// Watermarks logic. Active only in linked-mode.
if (gx->cpregs.cnt > gx->cpregs.himark && (gx->cpregs.cr & CP_CR_WPINC))
{
gx->CP_OVF();
}
if (gx->cpregs.cnt < gx->cpregs.lomark && (gx->cpregs.cr & CP_CR_WPINC))
{
gx->CP_UVF();
}
// Breakpoint
if ((gx->cpregs.rdptr & ~0x1f) == (gx->cpregs.bpptr & ~0x1f) && (gx->cpregs.cr & CP_CR_BPEN))
{
gx->CP_BREAK();
}
// Advance read pointer.
if (gx->cpregs.cnt != 0 && gx->cpregs.cr & CP_CR_RDEN && (gx->cpregs.sr & (CP_SR_OVF | CP_SR_UVF | CP_SR_BPINT)) == 0)
{
gx->cpregs.sr &= ~CP_SR_RD_IDLE;
gx->cpregs.sr &= ~CP_SR_CMD_IDLE;
gx->GXWriteFifo(&mi.ram[gx->cpregs.rdptr & RAMMASK]);
gx->cpregs.sr |= CP_SR_CMD_IDLE;
gx->cpregs.rdptr += 32;
if (gx->cpregs.rdptr == gx->cpregs.top)
{
gx->cpregs.rdptr = gx->cpregs.base;
}
}
else
{
gx->cpregs.sr |= (CP_SR_RD_IDLE | CP_SR_CMD_IDLE);
}
}
void GXCore::DONE_INT()
{
if (peregs.sr & PE_SR_DONEMSK)
{
peregs.sr |= PE_SR_DONE;
PIAssertInt(PI_INTERRUPT_PE_FINISH);
}
}
void GXCore::TOKEN_INT()
{
if (peregs.sr & PE_SR_TOKENMSK)
{
peregs.sr |= PE_SR_TOKEN;
PIAssertInt(PI_INTERRUPT_PE_TOKEN);
}
}
void GXCore::CPAbortFifo()
{
Report(Channel::GP, "CP Abort FIFO\n");
fifo->Reset();
}
uint16_t GXCore::CpReadReg(CPMappedRegister id)
{
switch (id)
{
case CPMappedRegister::CP_STATUS_ID:
return cpregs.sr;
case CPMappedRegister::CP_ENABLE_ID:
return cpregs.cr;
case CPMappedRegister::CP_CLR_ID:
return 0;
case CPMappedRegister::CP_MEMPERF_SEL_ID:
return 0;
case CPMappedRegister::CP_STM_LOW_ID:
return 0;
case CPMappedRegister::CP_FIFO_BASEL_ID:
return cpregs.basel & 0xffe0;
case CPMappedRegister::CP_FIFO_BASEH_ID:
return cpregs.baseh;
case CPMappedRegister::CP_FIFO_TOPL_ID:
return cpregs.topl & 0xffe0;
case CPMappedRegister::CP_FIFO_TOPH_ID:
return cpregs.toph;
case CPMappedRegister::CP_FIFO_HICNTL_ID:
return cpregs.himarkl & 0xffe0;
case CPMappedRegister::CP_FIFO_HICNTH_ID:
return cpregs.himarkh;
case CPMappedRegister::CP_FIFO_LOCNTL_ID:
return cpregs.lomarkl & 0xffe0;
case CPMappedRegister::CP_FIFO_LOCNTH_ID:
return cpregs.lomarkh;
case CPMappedRegister::CP_FIFO_COUNTL_ID:
return cpregs.cntl & 0xffe0;
case CPMappedRegister::CP_FIFO_COUNTH_ID:
return cpregs.cnth;
case CPMappedRegister::CP_FIFO_WPTRL_ID:
return cpregs.wrptrl & 0xffe0;
case CPMappedRegister::CP_FIFO_WPTRH_ID:
return cpregs.wrptrh;
case CPMappedRegister::CP_FIFO_RPTRL_ID:
return cpregs.rdptrl & 0xffe0;
case CPMappedRegister::CP_FIFO_RPTRH_ID:
return cpregs.rdptrh;
case CPMappedRegister::CP_FIFO_BRKL_ID:
return cpregs.bpptrl & 0xffe0;
case CPMappedRegister::CP_FIFO_BRKH_ID:
return cpregs.bpptrh;
case CPMappedRegister::CP_COUNTER0L_ID:
return 0;
case CPMappedRegister::CP_COUNTER0H_ID:
return 0;
case CPMappedRegister::CP_COUNTER1L_ID:
return 0;
case CPMappedRegister::CP_COUNTER1H_ID:
return 0;
case CPMappedRegister::CP_COUNTER2L_ID:
return 0;
case CPMappedRegister::CP_COUNTER2H_ID:
return 0;
case CPMappedRegister::CP_COUNTER3L_ID:
return 0;
case CPMappedRegister::CP_COUNTER3H_ID:
return 0;
case CPMappedRegister::CP_VC_CHKCNTL_ID:
return 0;
case CPMappedRegister::CP_VC_CHKCNTH_ID:
return 0;
case CPMappedRegister::CP_VC_MISSL_ID:
return 0;
case CPMappedRegister::CP_VC_MISSH_ID:
return 0;
case CPMappedRegister::CP_VC_STALLL_ID:
return 0;
case CPMappedRegister::CP_VC_STALLH_ID:
return 0;
case CPMappedRegister::CP_FRCLK_CNTL_ID:
return 0;
case CPMappedRegister::CP_FRCLK_CNTH_ID:
return 0;
case CPMappedRegister::CP_XF_ADDR_ID:
return 0;
case CPMappedRegister::CP_XF_DATAL_ID:
return 0;
case CPMappedRegister::CP_XF_DATAH_ID:
return 0;
}
return 0;
}
void GXCore::CpWriteReg(CPMappedRegister id, uint16_t value)
{
switch (id)
{
case CPMappedRegister::CP_STATUS_ID:
break;
case CPMappedRegister::CP_ENABLE_ID:
cpregs.cr = (uint16_t)value;
// clear breakpoint
if ((value & CP_CR_BPINTEN) == 0)
{
cpregs.sr &= ~CP_SR_BPINT;
}
if ((cpregs.sr & CP_SR_BPINT) == 0 && (cpregs.sr & CP_SR_OVF) == 0 && (cpregs.sr & CP_SR_UVF) == 0)
{
PIClearInt(PI_INTERRUPT_CP);
}
break;
case CPMappedRegister::CP_CLR_ID:
// clear watermark conditions
if (value & CP_CLR_OVFCLR)
{
cpregs.sr &= ~CP_SR_OVF;
}
if (value & CP_CLR_UVFCLR)
{
cpregs.sr &= ~CP_SR_UVF;
}
if ((cpregs.sr & CP_SR_BPINT) == 0 && (cpregs.sr & CP_SR_OVF) == 0 && (cpregs.sr & CP_SR_UVF) == 0)
{
PIClearInt(PI_INTERRUPT_CP);
}
break;
case CPMappedRegister::CP_MEMPERF_SEL_ID:
break;
case CPMappedRegister::CP_STM_LOW_ID:
break;
case CPMappedRegister::CP_FIFO_BASEL_ID:
cpregs.basel = value & 0xffe0;
break;
case CPMappedRegister::CP_FIFO_BASEH_ID:
cpregs.baseh = value;
break;
case CPMappedRegister::CP_FIFO_TOPL_ID:
cpregs.topl = value & 0xffe0;
break;
case CPMappedRegister::CP_FIFO_TOPH_ID:
cpregs.toph = value;
break;
case CPMappedRegister::CP_FIFO_HICNTL_ID:
cpregs.himarkl = value & 0xffe0;
break;
case CPMappedRegister::CP_FIFO_HICNTH_ID:
cpregs.himarkh = value;
break;
case CPMappedRegister::CP_FIFO_LOCNTL_ID:
cpregs.lomarkl = value & 0xffe0;
break;
case CPMappedRegister::CP_FIFO_LOCNTH_ID:
cpregs.lomarkh = value;
break;
case CPMappedRegister::CP_FIFO_COUNTL_ID:
cpregs.cntl = value & 0xffe0;
break;
case CPMappedRegister::CP_FIFO_COUNTH_ID:
cpregs.cnth = value;
break;
case CPMappedRegister::CP_FIFO_WPTRL_ID:
cpregs.wrptrl = value & 0xffe0;
break;
case CPMappedRegister::CP_FIFO_WPTRH_ID:
cpregs.wrptrh = value;
break;
case CPMappedRegister::CP_FIFO_RPTRL_ID:
cpregs.rdptrl = value & 0xffe0;
break;
case CPMappedRegister::CP_FIFO_RPTRH_ID:
cpregs.rdptrh = value;
break;
case CPMappedRegister::CP_FIFO_BRKL_ID:
cpregs.bpptrl = value & 0xffe0;
break;
case CPMappedRegister::CP_FIFO_BRKH_ID:
cpregs.bpptrh = value;
break;
case CPMappedRegister::CP_COUNTER0L_ID:
break;
case CPMappedRegister::CP_COUNTER0H_ID:
break;
case CPMappedRegister::CP_COUNTER1L_ID:
break;
case CPMappedRegister::CP_COUNTER1H_ID:
break;
case CPMappedRegister::CP_COUNTER2L_ID:
break;
case CPMappedRegister::CP_COUNTER2H_ID:
break;
case CPMappedRegister::CP_COUNTER3L_ID:
break;
case CPMappedRegister::CP_COUNTER3H_ID:
break;
case CPMappedRegister::CP_VC_CHKCNTL_ID:
break;
case CPMappedRegister::CP_VC_CHKCNTH_ID:
break;
case CPMappedRegister::CP_VC_MISSL_ID:
break;
case CPMappedRegister::CP_VC_MISSH_ID:
break;
case CPMappedRegister::CP_VC_STALLL_ID:
break;
case CPMappedRegister::CP_VC_STALLH_ID:
break;
case CPMappedRegister::CP_FRCLK_CNTL_ID:
break;
case CPMappedRegister::CP_FRCLK_CNTH_ID:
break;
case CPMappedRegister::CP_XF_ADDR_ID:
break;
case CPMappedRegister::CP_XF_DATAL_ID:
break;
case CPMappedRegister::CP_XF_DATAH_ID:
break;
}
}
uint32_t GXCore::PiCpReadReg(PI_CPMappedRegister id)
{
switch (id)
{
case PI_CPMappedRegister::PI_CPBAS_ID:
return pi_cp_base & ~0x1f;
case PI_CPMappedRegister::PI_CPTOP_ID:
return pi_cp_top & ~0x1f;
case PI_CPMappedRegister::PI_CPWRT_ID:
return (pi_cp_wrptr & ~0x1f) | (wrap_bit ? PI_CPWRT_WRAP : 0);
case PI_CPMappedRegister::PI_CPABT_ID:
Report(Channel::GP, "PI CP Abort read not implemented!\n");
return 0;
}
return 0;
}
void GXCore::PiCpWriteReg(PI_CPMappedRegister id, uint32_t value)
{
switch (id)
{
case PI_CPMappedRegister::PI_CPBAS_ID:
pi_cp_base = value & ~0x1f;
break;
case PI_CPMappedRegister::PI_CPTOP_ID:
pi_cp_top = value & ~0x1f;
break;
case PI_CPMappedRegister::PI_CPWRT_ID:
pi_cp_wrptr = value & ~0x1f;
wrap_bit = 0;
break;
case PI_CPMappedRegister::PI_CPABT_ID:
if ((value & 1) != 0) {
CPAbortFifo();
}
break;
}
}
// This method handles all the magic that occurs when writing to GX FIFO Streaming Pointer.
void GXCore::FifoWriteBurst(uint8_t data[32])
{
// PI FIFO
PIWriteBurst(pi_cp_wrptr & RAMMASK, data);
pi_cp_wrptr += 32;
if (pi_cp_wrptr == pi_cp_top)
{
pi_cp_wrptr = pi_cp_base;
wrap_bit = 1;
}
// CP FIFO
if (cpregs.cr & CP_CR_WPINC)
{
cpregs.wrptr += 32;
if (cpregs.wrptr == cpregs.top)
{
cpregs.wrptr = cpregs.base;
}
// All other work is done by CommandProcessor thread.
}
}
// show PI fifo configuration
void GXCore::DumpPIFIFO()
{
Report(Channel::Norm, "PI fifo configuration\n");
Report(Channel::Norm, " base :0x%08X\n", pi_cp_base);
Report(Channel::Norm, " top :0x%08X\n", pi_cp_top);
Report(Channel::Norm, " wrptr:0x%08X\n", pi_cp_wrptr);
Report(Channel::Norm, " wrap :%i\n", (pi_cp_wrptr & PI_CPWRT_WRAP) ? (1) : (0));
}
// show CP fifo configuration
void GXCore::DumpCPFIFO()
{
// fifo modes
char* md = (cpregs.cr & CP_CR_WPINC) ? ((char*)"immediate ") : ((char*)"multi-");
char bp = (cpregs.cr & CP_CR_BPEN) ? ('B') : ('b'); // breakpoint
char lw = (cpregs.cr & CP_CR_UVFEN) ? ('U') : ('u'); // low-wmark
char hw = (cpregs.cr & CP_CR_OVFEN) ? ('O') : ('o'); // high-wmark
Report(Channel::Norm, "CP %sfifo configuration:%c%c%c\n", md, bp, lw, hw);
Report(Channel::Norm, " status :0x%08X\n", cpregs.sr);
Report(Channel::Norm, " enable :0x%08X\n", cpregs.cr);
Report(Channel::Norm, " base :0x%08X\n", cpregs.base);
Report(Channel::Norm, " top :0x%08X\n", cpregs.top);
Report(Channel::Norm, " low :0x%08X\n", cpregs.lomark);
Report(Channel::Norm, " high :0x%08X\n", cpregs.himark);
Report(Channel::Norm, " cnt :0x%08X\n", cpregs.cnt);
Report(Channel::Norm, " wrptr:0x%08X\n", cpregs.wrptr);
Report(Channel::Norm, " rdptr:0x%08X\n", cpregs.rdptr);
Report(Channel::Norm, " break:0x%08X\n", cpregs.bpptr);
}
// index range = 00..FF
// reg size = 32 bit
void GXCore::loadCPReg(size_t index, uint32_t value, FifoProcessor* gxfifo)
{
cpLoads++;
if (GpRegsLog)
{
Report(Channel::GP, "Load CP: index: 0x%02X, data: 0x%08X\n", index, value);
}
switch(index)
{
case CP_MATINDEX_A_ID:
{
cp.matIndexA.bits = value;
}
return;
case CP_MATINDEX_B_ID:
{
cp.matIndexB.bits = value;
}
return;
case CP_VCD_LO_ID:
{
cp.vcdLo.bits = value;
FifoReconfigure(gxfifo);
}
return;
case CP_VCD_HI_ID:
{
cp.vcdHi.bits = value;
FifoReconfigure(gxfifo);
}
return;
case CP_VAT_A_ID | 0:
case CP_VAT_A_ID | 1:
case CP_VAT_A_ID | 2:
case CP_VAT_A_ID | 3:
case CP_VAT_A_ID | 4:
case CP_VAT_A_ID | 5:
case CP_VAT_A_ID | 6:
case CP_VAT_A_ID | 7:
{
cp.vatA[index & 7].bits = value;
FifoReconfigure(gxfifo);
}
return;
case CP_VAT_B_ID | 0:
case CP_VAT_B_ID | 1:
case CP_VAT_B_ID | 2:
case CP_VAT_B_ID | 3:
case CP_VAT_B_ID | 4:
case CP_VAT_B_ID | 5:
case CP_VAT_B_ID | 6:
case CP_VAT_B_ID | 7:
{
cp.vatB[index & 7].bits = value;
FifoReconfigure(gxfifo);
}
return;
case CP_VAT_C_ID | 0:
case CP_VAT_C_ID | 1:
case CP_VAT_C_ID | 2:
case CP_VAT_C_ID | 3:
case CP_VAT_C_ID | 4:
case CP_VAT_C_ID | 5:
case CP_VAT_C_ID | 6:
case CP_VAT_C_ID | 7:
{
cp.vatC[index & 7].bits = value;
FifoReconfigure(gxfifo);
}
return;
case CP_ARRAY_BASE_ID | 0:
case CP_ARRAY_BASE_ID | 1:
case CP_ARRAY_BASE_ID | 2:
case CP_ARRAY_BASE_ID | 3:
case CP_ARRAY_BASE_ID | 4:
case CP_ARRAY_BASE_ID | 5:
case CP_ARRAY_BASE_ID | 6:
case CP_ARRAY_BASE_ID | 7:
case CP_ARRAY_BASE_ID | 8:
case CP_ARRAY_BASE_ID | 9:
case CP_ARRAY_BASE_ID | 0xa:
case CP_ARRAY_BASE_ID | 0xb:
case CP_ARRAY_BASE_ID | 0xc:
case CP_ARRAY_BASE_ID | 0xd:
case CP_ARRAY_BASE_ID | 0xe:
case CP_ARRAY_BASE_ID | 0xf:
{
cp.arrayBase[index & 0xf].bits = value;
}
return;
case CP_ARRAY_STRIDE_ID | 0:
case CP_ARRAY_STRIDE_ID | 1:
case CP_ARRAY_STRIDE_ID | 2:
case CP_ARRAY_STRIDE_ID | 3:
case CP_ARRAY_STRIDE_ID | 4:
case CP_ARRAY_STRIDE_ID | 5:
case CP_ARRAY_STRIDE_ID | 6:
case CP_ARRAY_STRIDE_ID | 7:
case CP_ARRAY_STRIDE_ID | 8:
case CP_ARRAY_STRIDE_ID | 9:
case CP_ARRAY_STRIDE_ID | 0xa:
case CP_ARRAY_STRIDE_ID | 0xb:
case CP_ARRAY_STRIDE_ID | 0xc:
case CP_ARRAY_STRIDE_ID | 0xd:
case CP_ARRAY_STRIDE_ID | 0xe:
case CP_ARRAY_STRIDE_ID | 0xf:
{
cp.arrayStride[index & 0xf].bits = value & 0xFF;
}
return;
default:
{
Report(Channel::GP, "Unknown CP load, index: 0x%02X\n", index);
}
}
}
#pragma endregion "Dealing with registers"
#pragma region "FIFO Processing"
FifoProcessor::FifoProcessor(GXCore* gx)
{
gxcore = gx;
fifo = new uint8_t[fifoSize];
memset(fifo, 0, fifoSize);
allocated = true;
}
FifoProcessor::FifoProcessor(GXCore* gx, uint8_t* fifoPtr, size_t size)
{
gxcore = gx;
fifo = fifoPtr;
fifoSize = size + 1;
writePtr = fifoSize - 1;
allocated = false;
}
FifoProcessor::~FifoProcessor()
{
if (allocated)
{
delete[] fifo;
}
}
void FifoProcessor::Reset()
{
readPtr = writePtr = 0;
}
void FifoProcessor::WriteBytes(uint8_t dataPtr[32])
{
lock.Lock();
if ((writePtr + 32) < fifoSize)
{
memcpy(&fifo[writePtr], dataPtr, 32);
writePtr += 32;
}
else
{
size_t part1Size = fifoSize - writePtr;
memcpy(&fifo[writePtr], dataPtr, part1Size);
writePtr = 32 - part1Size;
memcpy(fifo, dataPtr + part1Size, writePtr);
Report(Channel::GP, "FifoProcessor: fifo wrapped\n");
}
lock.Unlock();
//while (EnoughToExecute())
//{
// ExecuteCommand();
//}
}
size_t FifoProcessor::GetSize()
{
if (writePtr >= readPtr)
{
return writePtr - readPtr;
}
else
{
return (fifoSize - readPtr) + writePtr;
}
}
bool FifoProcessor::EnoughToExecute()
{
if (GetSize() < 1)
return false;
CPCommand cmd = (CPCommand)Peek8(0);
switch(cmd)
{
case CPCommand::CP_CMD_NOP | 0:
case CPCommand::CP_CMD_NOP | 1:
case CPCommand::CP_CMD_NOP | 2:
case CPCommand::CP_CMD_NOP | 3:
case CPCommand::CP_CMD_NOP | 4:
case CPCommand::CP_CMD_NOP | 5:
case CPCommand::CP_CMD_NOP | 6:
case CPCommand::CP_CMD_NOP | 7:
return true;
case CPCommand::CP_CMD_VCACHE_INVD | 0:
case CPCommand::CP_CMD_VCACHE_INVD | 1:
case CPCommand::CP_CMD_VCACHE_INVD | 2:
case CPCommand::CP_CMD_VCACHE_INVD | 3:
case CPCommand::CP_CMD_VCACHE_INVD | 4:
case CPCommand::CP_CMD_VCACHE_INVD | 5:
case CPCommand::CP_CMD_VCACHE_INVD | 6:
case CPCommand::CP_CMD_VCACHE_INVD | 7:
return true;
case CPCommand::CP_CMD_CALL_DL | 0:
case CPCommand::CP_CMD_CALL_DL | 1:
case CPCommand::CP_CMD_CALL_DL | 2:
case CPCommand::CP_CMD_CALL_DL | 3:
case CPCommand::CP_CMD_CALL_DL | 4:
case CPCommand::CP_CMD_CALL_DL | 5:
case CPCommand::CP_CMD_CALL_DL | 6:
case CPCommand::CP_CMD_CALL_DL | 7:
return GetSize() >= 9;
case CPCommand::CP_CMD_LOAD_BPREG | 0:
case CPCommand::CP_CMD_LOAD_BPREG | 1:
case CPCommand::CP_CMD_LOAD_BPREG | 2:
case CPCommand::CP_CMD_LOAD_BPREG | 3:
case CPCommand::CP_CMD_LOAD_BPREG | 4:
case CPCommand::CP_CMD_LOAD_BPREG | 5:
case CPCommand::CP_CMD_LOAD_BPREG | 6:
case CPCommand::CP_CMD_LOAD_BPREG | 7:
case CPCommand::CP_CMD_LOAD_BPREG | 8:
case CPCommand::CP_CMD_LOAD_BPREG | 0xa:
case CPCommand::CP_CMD_LOAD_BPREG | 0xb:
case CPCommand::CP_CMD_LOAD_BPREG | 0xc:
case CPCommand::CP_CMD_LOAD_BPREG | 0xd:
case CPCommand::CP_CMD_LOAD_BPREG | 0xe:
case CPCommand::CP_CMD_LOAD_BPREG | 0xf:
return GetSize() >= 5;
case CPCommand::CP_CMD_LOAD_CPREG | 0:
case CPCommand::CP_CMD_LOAD_CPREG | 1:
case CPCommand::CP_CMD_LOAD_CPREG | 2:
case CPCommand::CP_CMD_LOAD_CPREG | 3:
case CPCommand::CP_CMD_LOAD_CPREG | 4:
case CPCommand::CP_CMD_LOAD_CPREG | 5:
case CPCommand::CP_CMD_LOAD_CPREG | 6:
case CPCommand::CP_CMD_LOAD_CPREG | 7:
return GetSize() >= 6;
case CPCommand::CP_CMD_LOAD_XFREG | 0:
case CPCommand::CP_CMD_LOAD_XFREG | 1:
case CPCommand::CP_CMD_LOAD_XFREG | 2:
case CPCommand::CP_CMD_LOAD_XFREG | 3:
case CPCommand::CP_CMD_LOAD_XFREG | 4:
case CPCommand::CP_CMD_LOAD_XFREG | 5:
case CPCommand::CP_CMD_LOAD_XFREG | 6:
case CPCommand::CP_CMD_LOAD_XFREG | 7:
{
if (GetSize() < 5)
return false;
uint16_t len = Peek16(1) + 1;
return GetSize() >= (len * 4 + 5);
}
case CPCommand::CP_CMD_LOAD_INDXA | 0:
case CPCommand::CP_CMD_LOAD_INDXA | 1:
case CPCommand::CP_CMD_LOAD_INDXA | 2:
case CPCommand::CP_CMD_LOAD_INDXA | 3:
case CPCommand::CP_CMD_LOAD_INDXA | 4:
case CPCommand::CP_CMD_LOAD_INDXA | 5:
case CPCommand::CP_CMD_LOAD_INDXA | 6:
case CPCommand::CP_CMD_LOAD_INDXA | 7:
return GetSize() >= 5;
case CPCommand::CP_CMD_LOAD_INDXB | 0:
case CPCommand::CP_CMD_LOAD_INDXB | 1:
case CPCommand::CP_CMD_LOAD_INDXB | 2:
case CPCommand::CP_CMD_LOAD_INDXB | 3:
case CPCommand::CP_CMD_LOAD_INDXB | 4:
case CPCommand::CP_CMD_LOAD_INDXB | 5:
case CPCommand::CP_CMD_LOAD_INDXB | 6:
case CPCommand::CP_CMD_LOAD_INDXB | 7:
return GetSize() >= 5;
case CPCommand::CP_CMD_LOAD_INDXC | 0:
case CPCommand::CP_CMD_LOAD_INDXC | 1:
case CPCommand::CP_CMD_LOAD_INDXC | 2:
case CPCommand::CP_CMD_LOAD_INDXC | 3:
case CPCommand::CP_CMD_LOAD_INDXC | 4:
case CPCommand::CP_CMD_LOAD_INDXC | 5:
case CPCommand::CP_CMD_LOAD_INDXC | 6:
case CPCommand::CP_CMD_LOAD_INDXC | 7:
return GetSize() >= 5;
case CPCommand::CP_CMD_LOAD_INDXD | 0:
case CPCommand::CP_CMD_LOAD_INDXD | 1:
case CPCommand::CP_CMD_LOAD_INDXD | 2:
case CPCommand::CP_CMD_LOAD_INDXD | 3:
case CPCommand::CP_CMD_LOAD_INDXD | 4:
case CPCommand::CP_CMD_LOAD_INDXD | 5:
case CPCommand::CP_CMD_LOAD_INDXD | 6:
case CPCommand::CP_CMD_LOAD_INDXD | 7:
return GetSize() >= 5;
case CPCommand::CP_CMD_DRAW_QUAD | 0:
case CPCommand::CP_CMD_DRAW_QUAD | 1:
case CPCommand::CP_CMD_DRAW_QUAD | 2:
case CPCommand::CP_CMD_DRAW_QUAD | 3:
case CPCommand::CP_CMD_DRAW_QUAD | 4:
case CPCommand::CP_CMD_DRAW_QUAD | 5:
case CPCommand::CP_CMD_DRAW_QUAD | 6:
case CPCommand::CP_CMD_DRAW_QUAD | 7:
case CPCommand::CP_CMD_DRAW_QUAD_STRIP | 0:
case CPCommand::CP_CMD_DRAW_QUAD_STRIP | 1:
case CPCommand::CP_CMD_DRAW_QUAD_STRIP | 2:
case CPCommand::CP_CMD_DRAW_QUAD_STRIP | 3:
case CPCommand::CP_CMD_DRAW_QUAD_STRIP | 4:
case CPCommand::CP_CMD_DRAW_QUAD_STRIP | 5:
case CPCommand::CP_CMD_DRAW_QUAD_STRIP | 6:
case CPCommand::CP_CMD_DRAW_QUAD_STRIP | 7:
case CPCommand::CP_CMD_DRAW_TRIANGLE | 0:
case CPCommand::CP_CMD_DRAW_TRIANGLE | 1:
case CPCommand::CP_CMD_DRAW_TRIANGLE | 2:
case CPCommand::CP_CMD_DRAW_TRIANGLE | 3:
case CPCommand::CP_CMD_DRAW_TRIANGLE | 4:
case CPCommand::CP_CMD_DRAW_TRIANGLE | 5:
case CPCommand::CP_CMD_DRAW_TRIANGLE | 6:
case CPCommand::CP_CMD_DRAW_TRIANGLE | 7:
case CPCommand::CP_CMD_DRAW_STRIP | 0:
case CPCommand::CP_CMD_DRAW_STRIP | 1:
case CPCommand::CP_CMD_DRAW_STRIP | 2:
case CPCommand::CP_CMD_DRAW_STRIP | 3:
case CPCommand::CP_CMD_DRAW_STRIP | 4:
case CPCommand::CP_CMD_DRAW_STRIP | 5:
case CPCommand::CP_CMD_DRAW_STRIP | 6:
case CPCommand::CP_CMD_DRAW_STRIP | 7:
case CPCommand::CP_CMD_DRAW_FAN | 0:
case CPCommand::CP_CMD_DRAW_FAN | 1:
case CPCommand::CP_CMD_DRAW_FAN | 2:
case CPCommand::CP_CMD_DRAW_FAN | 3:
case CPCommand::CP_CMD_DRAW_FAN | 4:
case CPCommand::CP_CMD_DRAW_FAN | 5:
case CPCommand::CP_CMD_DRAW_FAN | 6:
case CPCommand::CP_CMD_DRAW_FAN | 7:
case CPCommand::CP_CMD_DRAW_LINE | 0:
case CPCommand::CP_CMD_DRAW_LINE | 1:
case CPCommand::CP_CMD_DRAW_LINE | 2:
case CPCommand::CP_CMD_DRAW_LINE | 3:
case CPCommand::CP_CMD_DRAW_LINE | 4:
case CPCommand::CP_CMD_DRAW_LINE | 5:
case CPCommand::CP_CMD_DRAW_LINE | 6:
case CPCommand::CP_CMD_DRAW_LINE | 7:
case CPCommand::CP_CMD_DRAW_LINESTRIP | 0:
case CPCommand::CP_CMD_DRAW_LINESTRIP | 1:
case CPCommand::CP_CMD_DRAW_LINESTRIP | 2:
case CPCommand::CP_CMD_DRAW_LINESTRIP | 3:
case CPCommand::CP_CMD_DRAW_LINESTRIP | 4:
case CPCommand::CP_CMD_DRAW_LINESTRIP | 5:
case CPCommand::CP_CMD_DRAW_LINESTRIP | 6:
case CPCommand::CP_CMD_DRAW_LINESTRIP | 7:
case CPCommand::CP_CMD_DRAW_POINT | 0:
case CPCommand::CP_CMD_DRAW_POINT | 1:
case CPCommand::CP_CMD_DRAW_POINT | 2:
case CPCommand::CP_CMD_DRAW_POINT | 3:
case CPCommand::CP_CMD_DRAW_POINT | 4:
case CPCommand::CP_CMD_DRAW_POINT | 5:
case CPCommand::CP_CMD_DRAW_POINT | 6:
case CPCommand::CP_CMD_DRAW_POINT | 7:
{
if (GetSize() < 3)
return false;
int vtxnum = Peek16(1);
return GetSize() >= (vtxnum * vertexSize[cmd & 7] + 3);
}
default:
{
Halt("GFX: Unsupported opcode: 0x%02X (%s, readPtr: 0x%x)\n", cmd, allocated ? "Call DL" : "Stream", readPtr);
break;
}
}
return false;
}
uint8_t FifoProcessor::Read8()
{
assert(GetSize() >= 1);
lock.Lock();
uint8_t value = fifo[readPtr++];
if (readPtr >= fifoSize)
{
readPtr = 0;
}
lock.Unlock();
return value;
}
uint16_t FifoProcessor::Read16()
{
assert(GetSize() >= 2);
return ((uint16_t)Read8() << 8) | Read8();
}
uint32_t FifoProcessor::Read32()
{
assert(GetSize() >= 4);
return ((uint32_t)Read8() << 24) | ((uint32_t)Read8() << 16) | ((uint32_t)Read8() << 8) | Read8();
}
float FifoProcessor::ReadFloat()
{
assert(GetSize() >= 4);
uint32_t value = Read32();
return *(float*)&value;
}
uint8_t FifoProcessor::Peek8(size_t offset)
{
lock.Lock();
size_t ptr = readPtr + offset;
if (ptr >= fifoSize)
{
ptr -= fifoSize;
}
lock.Unlock();
return fifo[ptr];
}
uint8_t FifoProcessor::Peek16(size_t offset)
{
return ((uint16_t)Peek8(offset) << 8) | Peek8(offset + 1);
}
void FifoProcessor::RecalcVertexSize()
{
}
void FifoProcessor::ExecuteCommand()
{
}
#pragma endregion "FIFO Processing"
// Helper function
std::string GXCore::AttrToString(VertexAttr attr)
{
switch (attr)
{
case VertexAttr::VTX_POS: return "Position";
case VertexAttr::VTX_NRM: return "Normal";
case VertexAttr::VTX_BINRM: return "Binormal";
case VertexAttr::VTX_TANGENT: return "Tangent";
case VertexAttr::VTX_COLOR0: return "Color 0";
case VertexAttr::VTX_COLOR1: return "Color 1";
case VertexAttr::VTX_TEXCOORD0: return "Texture Coordinate 0";
case VertexAttr::VTX_TEXCOORD1: return "Texture Coordinate 1";
case VertexAttr::VTX_TEXCOORD2: return "Texture Coordinate 2";
case VertexAttr::VTX_TEXCOORD3: return "Texture Coordinate 3";
case VertexAttr::VTX_TEXCOORD4: return "Texture Coordinate 4";
case VertexAttr::VTX_TEXCOORD5: return "Texture Coordinate 5";
case VertexAttr::VTX_TEXCOORD6: return "Texture Coordinate 6";
case VertexAttr::VTX_TEXCOORD7: return "Texture Coordinate 7";
case VertexAttr::VTX_MATIDX0: return "Matrix Index 0";
case VertexAttr::VTX_MATIDX1: return "Matrix Index 1";
case VertexAttr::VTX_MAX_ATTR: return "MAX attr";
}
return "Unknown attribute";
}
// calculate size of current vertex
int GXCore::gx_vtxsize(unsigned v)
{
int vtxsize = 0;
static int cntp[] = { 2, 3 };
static int cntn[] = { 3, 9 };
static int cntt[] = { 1, 2 };
static int fmtsz[] = { 1, 1, 2, 2, 4 };
static int cfmtsz[] = { 2, 3, 4, 2, 4, 4 };
if (cp.vcdLo.PosNrmMatIdx) vtxsize++;
if (cp.vcdLo.Tex0MatIdx) vtxsize++;
if (cp.vcdLo.Tex1MatIdx) vtxsize++;
if (cp.vcdLo.Tex2MatIdx) vtxsize++;
if (cp.vcdLo.Tex3MatIdx) vtxsize++;
if (cp.vcdLo.Tex4MatIdx) vtxsize++;
if (cp.vcdLo.Tex5MatIdx) vtxsize++;
if (cp.vcdLo.Tex6MatIdx) vtxsize++;
if (cp.vcdLo.Tex7MatIdx) vtxsize++;
// Position
switch (cp.vcdLo.Position)
{
case VCD_DIRECT:
vtxsize += fmtsz[cp.vatA[v].posfmt] * cntp[cp.vatA[v].poscnt];
break;
case VCD_INDEX8:
vtxsize += 1;
break;
case VCD_INDEX16:
vtxsize += 2;
break;
}
// Normal
switch (cp.vcdLo.Normal)
{
case VCD_DIRECT:
vtxsize += fmtsz[cp.vatA[v].nrmfmt] * cntn[cp.vatA[v].nrmcnt];
break;
case VCD_INDEX8:
if (cp.vatA[v].nrmidx3) vtxsize += 3;
else vtxsize += 1;
break;
case VCD_INDEX16:
if (cp.vatA[v].nrmidx3) vtxsize += 2 * 3;
else vtxsize += 2;
break;
}
// Colors
switch (cp.vcdLo.Color0)
{
case VCD_DIRECT:
vtxsize += cfmtsz[cp.vatA[v].col0fmt];
break;
case VCD_INDEX8:
vtxsize += 1;
break;
case VCD_INDEX16:
vtxsize += 2;
break;
}
switch (cp.vcdLo.Color1)
{
case VCD_DIRECT:
vtxsize += cfmtsz[cp.vatA[v].col1fmt];
break;
case VCD_INDEX8:
vtxsize += 1;
break;
case VCD_INDEX16:
vtxsize += 2;
break;
}
// TexCoords
switch (cp.vcdHi.Tex0Coord)
{
case VCD_DIRECT:
vtxsize += fmtsz[cp.vatA[v].tex0fmt] * cntt[cp.vatA[v].tex0cnt];
break;
case VCD_INDEX8:
vtxsize += 1;
break;
case VCD_INDEX16:
vtxsize += 2;
break;
}
switch (cp.vcdHi.Tex1Coord)
{
case VCD_DIRECT:
vtxsize += fmtsz[cp.vatB[v].tex1fmt] * cntt[cp.vatB[v].tex1cnt];
break;
case VCD_INDEX8:
vtxsize += 1;
break;
case VCD_INDEX16:
vtxsize += 2;
break;
}
switch (cp.vcdHi.Tex2Coord)
{
case VCD_DIRECT:
vtxsize += fmtsz[cp.vatB[v].tex2fmt] * cntt[cp.vatB[v].tex2cnt];
break;
case VCD_INDEX8:
vtxsize += 1;
break;
case VCD_INDEX16:
vtxsize += 2;
break;
}
switch (cp.vcdHi.Tex3Coord)
{
case VCD_DIRECT:
vtxsize += fmtsz[cp.vatB[v].tex3fmt] * cntt[cp.vatB[v].tex3cnt];
break;
case VCD_INDEX8:
vtxsize += 1;
break;
case VCD_INDEX16:
vtxsize += 2;
break;
}
switch (cp.vcdHi.Tex4Coord)
{
case VCD_DIRECT:
vtxsize += fmtsz[cp.vatB[v].tex4fmt] * cntt[cp.vatB[v].tex4cnt];
break;
case VCD_INDEX8:
vtxsize += 1;
break;
case VCD_INDEX16:
vtxsize += 2;
break;
}
switch (cp.vcdHi.Tex5Coord)
{
case VCD_DIRECT:
vtxsize += fmtsz[cp.vatC[v].tex5fmt] * cntt[cp.vatC[v].tex5cnt];
break;
case VCD_INDEX8:
vtxsize += 1;
break;
case VCD_INDEX16:
vtxsize += 2;
break;
}
switch (cp.vcdHi.Tex6Coord)
{
case VCD_DIRECT:
vtxsize += fmtsz[cp.vatC[v].tex6fmt] * cntt[cp.vatC[v].tex6cnt];
break;
case VCD_INDEX8:
vtxsize += 1;
break;
case VCD_INDEX16:
vtxsize += 2;
break;
}
switch (cp.vcdHi.Tex7Coord)
{
case VCD_DIRECT:
vtxsize += fmtsz[cp.vatC[v].tex7fmt] * cntt[cp.vatC[v].tex7cnt];
break;
case VCD_INDEX8:
vtxsize += 1;
break;
case VCD_INDEX16:
vtxsize += 2;
break;
}
return vtxsize;
}
void GXCore::FifoReconfigure(FifoProcessor *gxfifo)
{
for (unsigned v = 0; v < 8; v++)
{
gxfifo->vertexSize[v] = gx_vtxsize(v);
}
}
void * GXCore::GetArrayPtr(ArrayId arrayId, int idx, int compSize)
{
uint32_t address = cp.arrayBase[(size_t)arrayId].Base +
(uint32_t)idx * cp.arrayStride[(size_t)arrayId].Stride;
return MIGetMemoryPointerForCP(address);
}
void GXCore::FetchComp(float* comp, int count, int type, int fmt, int shft, FifoProcessor* gxfifo, ArrayId arrayId)
{
void* ptr;
static int fmtsz[] = { 1, 1, 2, 2, 4 };
union
{
uint8_t u8[3];
uint16_t u16[3];
int8_t s8[3];
int16_t s16[3];
uint32_t u32[3];
} Comp;
switch (type)
{
case VCD_NONE: // Skip attribute
return;
case VCD_INDEX8:
ptr = GetArrayPtr(arrayId, gxfifo->Read8(), fmtsz[fmt]);
break;
case VCD_INDEX16:
ptr = GetArrayPtr(arrayId, gxfifo->Read16(), fmtsz[fmt]);
break;
default:
ptr = nullptr;
break;
}
switch (fmt)
{
case VFMT_U8:
if (type == VCD_DIRECT)
{
for (int i = 0; i < count; i++)
{
Comp.u8[i] = gxfifo->Read8();
}
}
else
{
for (int i = 0; i < count; i++)
{
Comp.u8[i] = ((uint8_t*)ptr)[i];
}
}
for (int i = 0; i < count; i++)
{
comp[i] = (float)(Comp.u8[i]) / (float)pow(2.0, shft);
}
break;
case VFMT_S8:
if (type == VCD_DIRECT)
{
for (int i = 0; i < count; i++)
{
Comp.s8[i] = gxfifo->Read8();
}
}
else
{
for (int i = 0; i < count; i++)
{
Comp.s8[i] = ((uint8_t*)ptr)[i];
}
}
for (int i = 0; i < count; i++)
{
comp[i] = (float)(Comp.s8[i]) / (float)pow(2.0, shft);
}
break;
case VFMT_U16:
if (type == VCD_DIRECT)
{
for (int i = 0; i < count; i++)
{
Comp.u16[i] = gxfifo->Read16();
}
}
else
{
for (int i = 0; i < count; i++)
{
Comp.u16[i] = _BYTESWAP_UINT16(((uint16_t*)ptr)[i]);
}
}
for (int i = 0; i < count; i++)
{
comp[i] = (float)(Comp.u16[i]) / (float)pow(2.0, shft);
}
break;
case VFMT_S16:
if (type == VCD_DIRECT)
{
for (int i = 0; i < count; i++)
{
Comp.s16[i] = gxfifo->Read16();
}
}
else
{
for (int i = 0; i < count; i++)
{
Comp.s16[i] = _BYTESWAP_UINT16(((uint16_t*)ptr)[i]);
}
}
for (int i = 0; i < count; i++)
{
comp[i] = (float)(Comp.s16[i]) / (float)pow(2.0, shft);
}
break;
case VFMT_F32:
if (type == VCD_DIRECT)
{
for (int i = 0; i < count; i++)
{
Comp.u32[i] = gxfifo->Read32();
}
}
else
{
for (int i = 0; i < count; i++)
{
Comp.u32[i] = _BYTESWAP_UINT32(((uint32_t*)ptr)[i]);
}
}
for (int i = 0; i < count; i++)
{
comp[i] = *(float*)&Comp.u32[i];
}
break;
default:
Halt("FetchComp: Invalid combination of VAT settings\n");
break;
}
}
void GXCore::FetchNorm(float* comp, int count, int type, int fmt, int shft, FifoProcessor* gxfifo, ArrayId arrayId, bool nrmidx3)
{
void* ptr1;
void* ptr2;
void* ptr3;
void** ptrptr[3] = { &ptr1, &ptr2, &ptr3 };
static int fmtsz[] = { 1, 1, 2, 2, 4 };
union
{
uint8_t u8[9];
uint16_t u16[9];
int8_t s8[9];
int16_t s16[9];
uint32_t u32[9];
} Comp;
switch (type)
{
case VCD_NONE: // Skip attribute
return;
case VCD_INDEX8:
ptr1 = GetArrayPtr(arrayId, gxfifo->Read8(), fmtsz[fmt]);
if (count == 9 && nrmidx3)
{
ptr2 = GetArrayPtr(arrayId, gxfifo->Read8(), fmtsz[fmt]);
ptr3 = GetArrayPtr(arrayId, gxfifo->Read8(), fmtsz[fmt]);
}
break;
case VCD_INDEX16:
ptr1 = GetArrayPtr(arrayId, gxfifo->Read16(), fmtsz[fmt]);
if (count == 9 && nrmidx3)
{
ptr2 = GetArrayPtr(arrayId, gxfifo->Read16(), fmtsz[fmt]);
ptr3 = GetArrayPtr(arrayId, gxfifo->Read16(), fmtsz[fmt]);
}
break;
}
switch (fmt)
{
case VFMT_S8:
if (type == VCD_DIRECT)
{
for (int i = 0; i < count; i++)
{
Comp.s8[i] = gxfifo->Read8();
}
}
else
{
for (int i = 0; i < count; i++)
{
void* ptr;
if (count == 9 && nrmidx3)
{
ptr = *ptrptr[i / 3];
}
else
{
ptr = ptr1;
}
Comp.s8[i] = ((uint8_t*)ptr)[i];
}
}
for (int i = 0; i < count; i++)
{
comp[i] = (float)(Comp.s8[i]) / (float)pow(2.0, shft);
}
break;
case VFMT_S16:
if (type == VCD_DIRECT)
{
for (int i = 0; i < count; i++)
{
Comp.s16[i] = gxfifo->Read16();
}
}
else
{
for (int i = 0; i < count; i++)
{
void* ptr;
if (count == 9 && nrmidx3)
{
ptr = *ptrptr[i / 3];
}
else
{
ptr = ptr1;
}
Comp.s16[i] = _BYTESWAP_UINT16(((uint16_t*)ptr)[i]);
}
}
for (int i = 0; i < count; i++)
{
comp[i] = (float)(Comp.s16[i]) / (float)pow(2.0, shft);
}
break;
case VFMT_F32:
if (type == VCD_DIRECT)
{
for (int i = 0; i < count; i++)
{
Comp.u32[i] = gxfifo->Read32();
}
}
else
{
for (int i = 0; i < count; i++)
{
void* ptr;
if (count == 9 && nrmidx3)
{
ptr = *ptrptr[i / 3];
}
else
{
ptr = ptr1;
}
Comp.u32[i] = _BYTESWAP_UINT32(((uint32_t*)ptr)[i]);
}
}
for (int i = 0; i < count; i++)
{
comp[i] = *(float*)&Comp.u32[i];
}
break;
default:
Halt("FetchComp: Invalid combination of VAT settings (normals)\n");
break;
}
}
Color GXCore::FetchColor(int type, int fmt, FifoProcessor* gxfifo, ArrayId arrayId)
{
void* ptr;
Color col;
static int cfmtsz[] = { 2, 3, 4, 2, 4, 4 };
col.R = 0;
col.G = 0;
col.B = 0;
col.A = 255;
uint16_t p16;
uint32_t p32;
uint8_t r, g, b, a;
switch (type)
{
case VCD_NONE: // Skip attribute
return col;
case VCD_INDEX8:
ptr = GetArrayPtr(arrayId, gxfifo->Read8(), cfmtsz[fmt]);
break;
case VCD_INDEX16:
ptr = GetArrayPtr(arrayId, gxfifo->Read16(), cfmtsz[fmt]);
break;
default:
ptr = nullptr;
break;
}
switch (fmt)
{
case VFMT_RGB565:
if (type == VCD_DIRECT)
{
p16 = gxfifo->Read16();
}
else
{
p16 = _BYTESWAP_UINT16(((uint16_t*)ptr)[0]);
}
r = p16 >> 11;
g = (p16 >> 5) & 0x3f;
b = p16 & 0x1f;
col.R = (r << 3) | (r >> 2);
col.G = (g << 2) | (g >> 4);
col.B = (b << 3) | (b >> 2);
col.A = 255;
break;
case VFMT_RGB8:
if (type == VCD_DIRECT)
{
col.R = gxfifo->Read8();
col.G = gxfifo->Read8();
col.B = gxfifo->Read8();
}
else
{
col.R = ((uint8_t*)ptr)[0];
col.G = ((uint8_t*)ptr)[1];
col.B = ((uint8_t*)ptr)[2];
}
col.A = 255;
break;
case VFMT_RGBX8:
if (type == VCD_DIRECT)
{
col.R = gxfifo->Read8();
col.G = gxfifo->Read8();
col.B = gxfifo->Read8();
gxfifo->Read8();
}
else
{
col.R = ((uint8_t*)ptr)[0];
col.G = ((uint8_t*)ptr)[1];
col.B = ((uint8_t*)ptr)[2];
}
col.A = 255;
break;
case VFMT_RGBA4:
if (type == VCD_DIRECT)
{
p16 = gxfifo->Read16();
}
else
{
p16 = _BYTESWAP_UINT16(((uint16_t*)ptr)[0]);
}
r = (p16 >> 12) & 0xf;
g = (p16 >> 8) & 0xf;
b = (p16 >> 4) & 0xf;
a = (p16 >> 0) & 0xf;
col.R = (r << 4) | r;
col.G = (g << 4) | g;
col.B = (b << 4) | b;
col.A = (a << 4) | a;
break;
case VFMT_RGBA6:
if (type == VCD_DIRECT)
{
p32 = ((uint32_t)gxfifo->Read8() << 16) | ((uint32_t)gxfifo->Read8() << 8) | gxfifo->Read8();
}
else
{
p32 = ((uint32_t)((uint8_t*)ptr)[0] << 16) | ((uint32_t)((uint8_t*)ptr)[1] << 8) | ((uint8_t*)ptr)[2];
}
r = (p32 >> 18) & 0x3f;
g = (p32 >> 12) & 0x3f;
b = (p32 >> 6) & 0x3f;
a = (p32 >> 0) & 0x3f;
col.R = (r << 6) | r;
col.G = (g << 6) | g;
col.B = (b << 6) | b;
col.A = (a << 6) | a;
break;
case VFMT_RGBA8:
if (type == VCD_DIRECT)
{
col.R = gxfifo->Read8();
col.G = gxfifo->Read8();
col.B = gxfifo->Read8();
col.A = gxfifo->Read8();
}
else
{
col.R = ((uint8_t*)ptr)[0];
col.G = ((uint8_t*)ptr)[1];
col.B = ((uint8_t*)ptr)[2];
col.A = ((uint8_t*)ptr)[3];
}
break;
default:
Halt("FetchComp: Invalid combination of VAT settings (color)\n");
break;
}
return col;
}
// collect vertex data
void GXCore::FifoWalk(unsigned vatnum, Vertex* vtx, FifoProcessor* gxfifo)
{
// overrided by 'mtxidx' attributes
vtx->matIdx0.PosNrmMatIdx = xf.matIdxA.PosNrmMatIdx;
vtx->matIdx0.Tex0MatIdx = xf.matIdxA.Tex0MatIdx;
vtx->matIdx0.Tex1MatIdx = xf.matIdxA.Tex1MatIdx;
vtx->matIdx0.Tex2MatIdx = xf.matIdxA.Tex2MatIdx;
vtx->matIdx0.Tex3MatIdx = xf.matIdxA.Tex3MatIdx;
vtx->matIdx1.Tex4MatIdx = xf.matIdxB.Tex4MatIdx;
vtx->matIdx1.Tex5MatIdx = xf.matIdxB.Tex5MatIdx;
vtx->matIdx1.Tex6MatIdx = xf.matIdxB.Tex6MatIdx;
vtx->matIdx1.Tex7MatIdx = xf.matIdxB.Tex7MatIdx;
// Matrix Index
if (cp.vcdLo.PosNrmMatIdx)
{
vtx->matIdx0.PosNrmMatIdx = gxfifo->Read8();
}
if (cp.vcdLo.Tex0MatIdx)
{
vtx->matIdx0.Tex0MatIdx = gxfifo->Read8();
}
if (cp.vcdLo.Tex1MatIdx)
{
vtx->matIdx0.Tex1MatIdx = gxfifo->Read8();
}
if (cp.vcdLo.Tex2MatIdx)
{
vtx->matIdx0.Tex2MatIdx = gxfifo->Read8();
}
if (cp.vcdLo.Tex3MatIdx)
{
vtx->matIdx0.Tex3MatIdx = gxfifo->Read8();
}
if (cp.vcdLo.Tex4MatIdx)
{
vtx->matIdx1.Tex4MatIdx = gxfifo->Read8();
}
if (cp.vcdLo.Tex5MatIdx)
{
vtx->matIdx1.Tex5MatIdx = gxfifo->Read8();
}
if (cp.vcdLo.Tex6MatIdx)
{
vtx->matIdx1.Tex6MatIdx = gxfifo->Read8();
}
if (cp.vcdLo.Tex7MatIdx)
{
vtx->matIdx1.Tex7MatIdx = gxfifo->Read8();
}
// Position
vtx->Position[0] = vtx->Position[1] = vtx->Position[2] = 1.0f;
FetchComp(vtx->Position,
cp.vatA[vatnum].poscnt == VCNT_POS_XYZ ? 3 : 2,
cp.vcdLo.Position,
cp.vatA[vatnum].posfmt,
cp.vatA[vatnum].bytedeq ? cp.vatA[vatnum].posshft : 0,
gxfifo,
ArrayId::Pos);
// Normal
vtx->Normal[0] = vtx->Normal[1] = vtx->Normal[2] = 1.0f;
vtx->Binormal[0] = vtx->Binormal[1] = vtx->Binormal[2] = 1.0f;
vtx->Tangent[0] = vtx->Tangent[1] = vtx->Tangent[2] = 1.0f;
int nrmshft = 0;
switch (cp.vatA[vatnum].nrmfmt)
{
case VFMT_U8:
case VFMT_S8:
nrmshft = 6;
break;
case VFMT_U16:
case VFMT_S16:
nrmshft = 14;
break;
}
FetchNorm(vtx->Normal,
cp.vatA[vatnum].nrmcnt == VCNT_NRM_NBT ? 9 : 3,
cp.vcdLo.Normal,
cp.vatA[vatnum].nrmfmt,
nrmshft,
gxfifo,
ArrayId::Nrm,
cp.vatA[vatnum].nrmidx3 ? true : false);
// Color0
vtx->Col[0] = FetchColor(cp.vcdLo.Color0, cp.vatA[vatnum].col0fmt, gxfifo, ArrayId::Color0);
// Color1
vtx->Col[1] = FetchColor(cp.vcdLo.Color1, cp.vatA[vatnum].col1fmt, gxfifo, ArrayId::Color1);
// TexNCoord
vtx->TexCoord[0][0] = vtx->TexCoord[0][1] = 1.0f;
FetchComp(vtx->TexCoord[0],
cp.vatA[vatnum].tex0cnt == VCNT_TEX_ST ? 2 : 1,
cp.vcdHi.Tex0Coord,
cp.vatA[vatnum].tex0fmt,
cp.vatA[vatnum].bytedeq ? cp.vatA[vatnum].tex0shft : 0,
gxfifo,
ArrayId::Tex0Coord);
vtx->TexCoord[1][0] = vtx->TexCoord[1][1] = 1.0f;
FetchComp(vtx->TexCoord[1],
cp.vatB[vatnum].tex1cnt == VCNT_TEX_ST ? 2 : 1,
cp.vcdHi.Tex1Coord,
cp.vatB[vatnum].tex1fmt,
cp.vatA[vatnum].bytedeq ? cp.vatB[vatnum].tex1shft : 0,
gxfifo,
ArrayId::Tex1Coord);
vtx->TexCoord[2][0] = vtx->TexCoord[2][1] = 1.0f;
FetchComp(vtx->TexCoord[2],
cp.vatB[vatnum].tex2cnt == VCNT_TEX_ST ? 2 : 1,
cp.vcdHi.Tex2Coord,
cp.vatB[vatnum].tex2fmt,
cp.vatA[vatnum].bytedeq ? cp.vatB[vatnum].tex2shft : 0,
gxfifo,
ArrayId::Tex2Coord);
vtx->TexCoord[3][0] = vtx->TexCoord[3][1] = 1.0f;
FetchComp(vtx->TexCoord[3],
cp.vatB[vatnum].tex3cnt == VCNT_TEX_ST ? 2 : 1,
cp.vcdHi.Tex3Coord,
cp.vatB[vatnum].tex3fmt,
cp.vatA[vatnum].bytedeq ? cp.vatB[vatnum].tex3shft : 0,
gxfifo,
ArrayId::Tex3Coord);
vtx->TexCoord[4][0] = vtx->TexCoord[4][1] = 1.0f;
FetchComp(vtx->TexCoord[4],
cp.vatB[vatnum].tex4cnt == VCNT_TEX_ST ? 2 : 1,
cp.vcdHi.Tex4Coord,
cp.vatB[vatnum].tex4fmt,
cp.vatA[vatnum].bytedeq ? cp.vatC[vatnum].tex4shft : 0,
gxfifo,
ArrayId::Tex4Coord);
vtx->TexCoord[5][0] = vtx->TexCoord[5][1] = 1.0f;
FetchComp(vtx->TexCoord[5],
cp.vatC[vatnum].tex5cnt == VCNT_TEX_ST ? 2 : 1,
cp.vcdHi.Tex5Coord,
cp.vatC[vatnum].tex5fmt,
cp.vatA[vatnum].bytedeq ? cp.vatC[vatnum].tex5shft : 0,
gxfifo,
ArrayId::Tex5Coord);
vtx->TexCoord[6][0] = vtx->TexCoord[6][1] = 1.0f;
FetchComp(vtx->TexCoord[6],
cp.vatC[vatnum].tex6cnt == VCNT_TEX_ST ? 2 : 1,
cp.vcdHi.Tex6Coord,
cp.vatC[vatnum].tex6fmt,
cp.vatA[vatnum].bytedeq ? cp.vatC[vatnum].tex6shft : 0,
gxfifo,
ArrayId::Tex6Coord);
vtx->TexCoord[7][0] = vtx->TexCoord[7][1] = 1.0f;
FetchComp(vtx->TexCoord[7],
cp.vatC[vatnum].tex7cnt == VCNT_TEX_ST ? 2 : 1,
cp.vcdHi.Tex7Coord,
cp.vatC[vatnum].tex7fmt,
cp.vatA[vatnum].bytedeq ? cp.vatC[vatnum].tex7shft : 0,
gxfifo,
ArrayId::Tex7Coord);
}
void GXCore::GxBadFifo(uint8_t command)
{
Halt(
"Unimplemented command : 0x%02X\n"
"VCD configuration :\n"
"pmidx:%i\n"
"t0idx:%i\t tex0:%i\n"
"t1idx:%i\t tex1:%i\n"
"t2idx:%i\t tex2:%i\n"
"t3idx:%i\t tex3:%i\n"
"t4idx:%i\t tex4:%i\n"
"t5idx:%i\t tex5:%i\n"
"t6idx:%i\t tex6:%i\n"
"t7idx:%i\t tex7:%i\n"
"pos:%i\n"
"nrm:%i\n"
"col0:%i\n"
"col1:%i\n",
command,
cp.vcdLo.PosNrmMatIdx,
cp.vcdLo.Tex0MatIdx, cp.vcdHi.Tex0Coord,
cp.vcdLo.Tex1MatIdx, cp.vcdHi.Tex1Coord,
cp.vcdLo.Tex2MatIdx, cp.vcdHi.Tex2Coord,
cp.vcdLo.Tex3MatIdx, cp.vcdHi.Tex3Coord,
cp.vcdLo.Tex4MatIdx, cp.vcdHi.Tex4Coord,
cp.vcdLo.Tex5MatIdx, cp.vcdHi.Tex5Coord,
cp.vcdLo.Tex6MatIdx, cp.vcdHi.Tex6Coord,
cp.vcdLo.Tex7MatIdx, cp.vcdHi.Tex7Coord,
cp.vcdLo.Position,
cp.vcdLo.Normal,
cp.vcdLo.Color0,
cp.vcdLo.Color1
);
}
void GXCore::GxCommand(FifoProcessor* gxfifo)
{
if(frame_done)
{
GL_OpenSubsystem();
GL_BeginFrame();
frame_done = 0;
}
uint8_t cmd = gxfifo->Read8();
if (logOpcode) {
Report(Channel::GP, "GxCommand: 0x%02X\n", cmd);
}
switch(cmd)
{
// do nothing
case CP_CMD_NOP | 0:
case CP_CMD_NOP | 1:
case CP_CMD_NOP | 2:
case CP_CMD_NOP | 3:
case CP_CMD_NOP | 4:
case CP_CMD_NOP | 5:
case CP_CMD_NOP | 6:
case CP_CMD_NOP | 7:
break;
case CP_CMD_VCACHE_INVD | 0:
case CP_CMD_VCACHE_INVD | 1:
case CP_CMD_VCACHE_INVD | 2:
case CP_CMD_VCACHE_INVD | 3:
case CP_CMD_VCACHE_INVD | 4:
case CP_CMD_VCACHE_INVD | 5:
case CP_CMD_VCACHE_INVD | 6:
case CP_CMD_VCACHE_INVD | 7:
//Report(Channel::GP, "Invalidate V$\n");
break;
case CP_CMD_CALL_DL | 0:
case CP_CMD_CALL_DL | 1:
case CP_CMD_CALL_DL | 2:
case CP_CMD_CALL_DL | 3:
case CP_CMD_CALL_DL | 4:
case CP_CMD_CALL_DL | 5:
case CP_CMD_CALL_DL | 6:
case CP_CMD_CALL_DL | 7:
{
uint32_t physAddress = gxfifo->Read32() & ~0x1f;
uint8_t* fifoPtr = (uint8_t *)MIGetMemoryPointerForCP(physAddress);
size_t size = gxfifo->Read32() & ~0x1f;
if (logDrawCommands)
{
Report(Channel::GP, "CP_CMD_CALL_DL: addr: 0x%08X, size: %i\n", physAddress, size);
}
FifoProcessor* callDlFifo = new FifoProcessor(this, fifoPtr, size);
while (callDlFifo->EnoughToExecute())
{
GxCommand(callDlFifo);
}
delete callDlFifo;
break;
}
// ---------------------------------------------------------------
// loading of internal regs
case CP_CMD_LOAD_BPREG | 0:
case CP_CMD_LOAD_BPREG | 1:
case CP_CMD_LOAD_BPREG | 2:
case CP_CMD_LOAD_BPREG | 3:
case CP_CMD_LOAD_BPREG | 4:
case CP_CMD_LOAD_BPREG | 5:
case CP_CMD_LOAD_BPREG | 6:
case CP_CMD_LOAD_BPREG | 7:
case CP_CMD_LOAD_BPREG | 8:
case CP_CMD_LOAD_BPREG | 0xa:
case CP_CMD_LOAD_BPREG | 0xb:
case CP_CMD_LOAD_BPREG | 0xc:
case CP_CMD_LOAD_BPREG | 0xd:
case CP_CMD_LOAD_BPREG | 0xe:
case CP_CMD_LOAD_BPREG | 0xf:
{
uint32_t word = gxfifo->Read32();
loadBPReg(word >> 24, word & 0xffffff);
break;
}
case CP_CMD_LOAD_CPREG | 0:
case CP_CMD_LOAD_CPREG | 1:
case CP_CMD_LOAD_CPREG | 2:
case CP_CMD_LOAD_CPREG | 3:
case CP_CMD_LOAD_CPREG | 4:
case CP_CMD_LOAD_CPREG | 5:
case CP_CMD_LOAD_CPREG | 6:
case CP_CMD_LOAD_CPREG | 7:
{
uint8_t index = gxfifo->Read8();
uint32_t word = gxfifo->Read32();
loadCPReg(index, word, gxfifo);
break;
}
case CP_CMD_LOAD_XFREG | 0:
case CP_CMD_LOAD_XFREG | 1:
case CP_CMD_LOAD_XFREG | 2:
case CP_CMD_LOAD_XFREG | 3:
case CP_CMD_LOAD_XFREG | 4:
case CP_CMD_LOAD_XFREG | 5:
case CP_CMD_LOAD_XFREG | 6:
case CP_CMD_LOAD_XFREG | 7:
{
uint16_t len, index;
len = gxfifo->Read16() + 1;
index = gxfifo->Read16();
loadXFRegs(index, len, gxfifo);
break;
}
case CP_CMD_LOAD_INDXA | 0:
case CP_CMD_LOAD_INDXA | 1:
case CP_CMD_LOAD_INDXA | 2:
case CP_CMD_LOAD_INDXA | 3:
case CP_CMD_LOAD_INDXA | 4:
case CP_CMD_LOAD_INDXA | 5:
case CP_CMD_LOAD_INDXA | 6:
case CP_CMD_LOAD_INDXA | 7:
{
uint16_t idx, start, len;
idx = gxfifo->Read16();
start = gxfifo->Read16();
len = (start >> 12) + 1;
start &= 0xfff;
Report(Channel::GP, "CP_CMD_LOAD_INDXA: idx: %i, start: %i, len: %i\n", idx, start, len);
break;
}
case CP_CMD_LOAD_INDXB | 0:
case CP_CMD_LOAD_INDXB | 1:
case CP_CMD_LOAD_INDXB | 2:
case CP_CMD_LOAD_INDXB | 3:
case CP_CMD_LOAD_INDXB | 4:
case CP_CMD_LOAD_INDXB | 5:
case CP_CMD_LOAD_INDXB | 6:
case CP_CMD_LOAD_INDXB | 7:
{
uint16_t idx, start, len;
idx = gxfifo->Read16();
start = gxfifo->Read16();
len = (start >> 12) + 1;
start &= 0xfff;
Report(Channel::GP, "CP_CMD_LOAD_INDXB: idx: %i, start: %i, len: %i\n", idx, start, len);
break;
}
case CP_CMD_LOAD_INDXC | 0:
case CP_CMD_LOAD_INDXC | 1:
case CP_CMD_LOAD_INDXC | 2:
case CP_CMD_LOAD_INDXC | 3:
case CP_CMD_LOAD_INDXC | 4:
case CP_CMD_LOAD_INDXC | 5:
case CP_CMD_LOAD_INDXC | 6:
case CP_CMD_LOAD_INDXC | 7:
{
uint16_t idx, start, len;
idx = gxfifo->Read16();
start = gxfifo->Read16();
len = (start >> 12) + 1;
start &= 0xfff;
Report(Channel::GP, "CP_CMD_LOAD_INDXC: idx: %i, start: %i, len: %i\n", idx, start, len);
break;
}
case CP_CMD_LOAD_INDXD | 0:
case CP_CMD_LOAD_INDXD | 1:
case CP_CMD_LOAD_INDXD | 2:
case CP_CMD_LOAD_INDXD | 3:
case CP_CMD_LOAD_INDXD | 4:
case CP_CMD_LOAD_INDXD | 5:
case CP_CMD_LOAD_INDXD | 6:
case CP_CMD_LOAD_INDXD | 7:
{
uint16_t idx, start, len;
idx = gxfifo->Read16();
start = gxfifo->Read16();
len = (start >> 12) + 1;
start &= 0xfff;
Report(Channel::GP, "CP_CMD_LOAD_INDXD: idx: %i, start: %i, len: %i\n", idx, start, len);
break;
}
// ---------------------------------------------------------------
// draw commands
// 0x80
case CP_CMD_DRAW_QUAD | 0:
case CP_CMD_DRAW_QUAD | 1:
case CP_CMD_DRAW_QUAD | 2:
case CP_CMD_DRAW_QUAD | 3:
case CP_CMD_DRAW_QUAD | 4:
case CP_CMD_DRAW_QUAD | 5:
case CP_CMD_DRAW_QUAD | 6:
case CP_CMD_DRAW_QUAD | 7:
{
unsigned vatnum = cmd & 7;
unsigned vtxnum = gxfifo->Read16();
if (logDrawCommands)
{
Report(Channel::GP, "CP_CMD_DRAW_QUAD: vtxnum: %i, vat: %i\n", vtxnum, vatnum);
}
if (vtxnum != 0) {
tris += (vtxnum / 4) / 2;
#if GFX_BLACKJACK_AND_SHADERS
for (unsigned i = 0; i < vtxnum; i++) {
FifoWalk(vatnum, &vertex_data[i], gxfifo);
}
glBufferData(GL_ARRAY_BUFFER, vtxnum * sizeof(Vertex), vertex_data, GL_STATIC_DRAW);
glDrawArrays(GL_QUADS, 0, vtxnum);
gl_error = glGetError();
if (gl_error != GL_NO_ERROR) {
Halt("GL Error CP_CMD_DRAW_QUAD: %x\n", gl_error);
}
#else
RAS_Begin(RAS_QUAD, vtxnum);
Vertex vtx;
while (vtxnum--) {
FifoWalk(vatnum, &vtx, gxfifo);
RAS_SendVertex(&vtx);
}
RAS_End();
#endif
}
break;
}
// 0x88
case CP_CMD_DRAW_QUAD_STRIP | 0:
case CP_CMD_DRAW_QUAD_STRIP | 1:
case CP_CMD_DRAW_QUAD_STRIP | 2:
case CP_CMD_DRAW_QUAD_STRIP | 3:
case CP_CMD_DRAW_QUAD_STRIP | 4:
case CP_CMD_DRAW_QUAD_STRIP | 5:
case CP_CMD_DRAW_QUAD_STRIP | 6:
case CP_CMD_DRAW_QUAD_STRIP | 7:
{
unsigned vatnum = cmd & 7;
unsigned vtxnum = gxfifo->Read16();
if (logDrawCommands)
{
Report(Channel::GP, "CP_CMD_DRAW_QUAD_STRIP: vtxnum: %i, vat: %i\n", vtxnum, vatnum);
}
if (vtxnum != 0) {
tris += (vtxnum / 2 - 1) / 2;
#if GFX_BLACKJACK_AND_SHADERS
for (unsigned i = 0; i < vtxnum; i++) {
FifoWalk(vatnum, &vertex_data[i], gxfifo);
}
glBufferData(GL_ARRAY_BUFFER, vtxnum * sizeof(Vertex), vertex_data, GL_STATIC_DRAW);
glDrawArrays(GL_QUAD_STRIP, 0, vtxnum);
gl_error = glGetError();
if (gl_error != GL_NO_ERROR) {
Halt("GL Error CP_CMD_DRAW_QUAD: %x\n", gl_error);
}
#else
RAS_Begin(RAS_QUAD_STRIP, vtxnum);
Vertex vtx;
while (vtxnum--) {
FifoWalk(vatnum, &vtx, gxfifo);
RAS_SendVertex(&vtx);
}
RAS_End();
#endif
}
break;
}
// 0x90
case CP_CMD_DRAW_TRIANGLE | 0:
case CP_CMD_DRAW_TRIANGLE | 1:
case CP_CMD_DRAW_TRIANGLE | 2:
case CP_CMD_DRAW_TRIANGLE | 3:
case CP_CMD_DRAW_TRIANGLE | 4:
case CP_CMD_DRAW_TRIANGLE | 5:
case CP_CMD_DRAW_TRIANGLE | 6:
case CP_CMD_DRAW_TRIANGLE | 7:
{
unsigned vatnum = cmd & 7;
unsigned vtxnum = gxfifo->Read16();
if (logDrawCommands)
{
Report(Channel::GP, "CP_CMD_DRAW_TRIANGLE: vtxnum: %i, vat: %i\n", vtxnum, vatnum);
}
if (vtxnum != 0) {
tris += vtxnum / 3;
#if GFX_BLACKJACK_AND_SHADERS
for (unsigned i = 0; i < vtxnum; i++) {
FifoWalk(vatnum, &vertex_data[i], gxfifo);
}
glBufferData(GL_ARRAY_BUFFER, vtxnum * sizeof(Vertex), vertex_data, GL_STATIC_DRAW);
glDrawArrays(GL_TRIANGLES, 0, vtxnum);
gl_error = glGetError();
if (gl_error != GL_NO_ERROR) {
Halt("GL Error CP_CMD_DRAW_TRIANGLE: %x\n", gl_error);
}
#else
RAS_Begin(RAS_TRIANGLE, vtxnum);
Vertex vtx;
while (vtxnum--) {
FifoWalk(vatnum, &vtx, gxfifo);
RAS_SendVertex(&vtx);
}
RAS_End();
#endif
}
break;
}
// 0x98
case CP_CMD_DRAW_STRIP | 0:
case CP_CMD_DRAW_STRIP | 1:
case CP_CMD_DRAW_STRIP | 2:
case CP_CMD_DRAW_STRIP | 3:
case CP_CMD_DRAW_STRIP | 4:
case CP_CMD_DRAW_STRIP | 5:
case CP_CMD_DRAW_STRIP | 6:
case CP_CMD_DRAW_STRIP | 7:
{
unsigned vatnum = cmd & 7;
unsigned vtxnum = gxfifo->Read16();
if (logDrawCommands)
{
Report(Channel::GP, "CP_CMD_DRAW_STRIP: vtxnum: %i, vat: %i\n", vtxnum, vatnum);
}
if (vtxnum != 0) {
tris += vtxnum - 2;
#if GFX_BLACKJACK_AND_SHADERS
for (unsigned i = 0; i < vtxnum; i++) {
FifoWalk(vatnum, &vertex_data[i], gxfifo);
}
glBufferData(GL_ARRAY_BUFFER, vtxnum * sizeof(Vertex), vertex_data, GL_STATIC_DRAW);
glDrawArrays(GL_TRIANGLE_STRIP, 0, vtxnum);
gl_error = glGetError();
if (gl_error != GL_NO_ERROR) {
Halt("GL Error CP_CMD_DRAW_STRIP: %x\n", gl_error);
}
#else
RAS_Begin(RAS_TRIANGLE_STRIP, vtxnum);
Vertex vtx;
while (vtxnum--) {
FifoWalk(vatnum, &vtx, gxfifo);
RAS_SendVertex(&vtx);
}
RAS_End();
#endif
}
break;
}
// 0xA0
case CP_CMD_DRAW_FAN | 0:
case CP_CMD_DRAW_FAN | 1:
case CP_CMD_DRAW_FAN | 2:
case CP_CMD_DRAW_FAN | 3:
case CP_CMD_DRAW_FAN | 4:
case CP_CMD_DRAW_FAN | 5:
case CP_CMD_DRAW_FAN | 6:
case CP_CMD_DRAW_FAN | 7:
{
unsigned vatnum = cmd & 7;
unsigned vtxnum = gxfifo->Read16();
if (logDrawCommands)
{
Report(Channel::GP, "CP_CMD_DRAW_FAN: vtxnum: %i, vat: %i\n", vtxnum, vatnum);
}
if (vtxnum != 0) {
tris += vtxnum - 2;
#if GFX_BLACKJACK_AND_SHADERS
for (unsigned i = 0; i < vtxnum; i++) {
FifoWalk(vatnum, &vertex_data[i], gxfifo);
}
glBufferData(GL_ARRAY_BUFFER, vtxnum * sizeof(Vertex), vertex_data, GL_STATIC_DRAW);
glDrawArrays(GL_TRIANGLE_FAN, 0, vtxnum);
gl_error = glGetError();
if (gl_error != GL_NO_ERROR) {
Halt("GL Error CP_CMD_DRAW_FAN: %x\n", gl_error);
}
#else
RAS_Begin(RAS_TRIANGLE_FAN, vtxnum);
Vertex vtx;
while (vtxnum--) {
FifoWalk(vatnum, &vtx, gxfifo);
RAS_SendVertex(&vtx);
}
RAS_End();
#endif
}
break;
}
// 0xA8
case CP_CMD_DRAW_LINE | 0:
case CP_CMD_DRAW_LINE | 1:
case CP_CMD_DRAW_LINE | 2:
case CP_CMD_DRAW_LINE | 3:
case CP_CMD_DRAW_LINE | 4:
case CP_CMD_DRAW_LINE | 5:
case CP_CMD_DRAW_LINE | 6:
case CP_CMD_DRAW_LINE | 7:
{
unsigned vatnum = cmd & 7;
unsigned vtxnum = gxfifo->Read16();
if (logDrawCommands)
{
Report(Channel::GP, "CP_CMD_DRAW_LINE: vtxnum: %i, vat: %i\n", vtxnum, vatnum);
}
if (vtxnum != 0) {
lines += vtxnum / 2;
#if GFX_BLACKJACK_AND_SHADERS
for (unsigned i = 0; i < vtxnum; i++) {
FifoWalk(vatnum, &vertex_data[i], gxfifo);
}
glBufferData(GL_ARRAY_BUFFER, vtxnum * sizeof(Vertex), vertex_data, GL_STATIC_DRAW);
glDrawArrays(GL_LINES, 0, vtxnum);
gl_error = glGetError();
if (gl_error != GL_NO_ERROR) {
Halt("GL Error CP_CMD_DRAW_LINE: %x\n", gl_error);
}
#else
RAS_Begin(RAS_LINE, vtxnum);
Vertex vtx;
while (vtxnum--) {
FifoWalk(vatnum, &vtx, gxfifo);
RAS_SendVertex(&vtx);
}
RAS_End();
#endif
}
break;
}
// 0xB0
case CP_CMD_DRAW_LINESTRIP | 0:
case CP_CMD_DRAW_LINESTRIP | 1:
case CP_CMD_DRAW_LINESTRIP | 2:
case CP_CMD_DRAW_LINESTRIP | 3:
case CP_CMD_DRAW_LINESTRIP | 4:
case CP_CMD_DRAW_LINESTRIP | 5:
case CP_CMD_DRAW_LINESTRIP | 6:
case CP_CMD_DRAW_LINESTRIP | 7:
{
unsigned vatnum = cmd & 7;
unsigned vtxnum = gxfifo->Read16();
if (logDrawCommands)
{
Report(Channel::GP, "CP_CMD_DRAW_LINESTRIP: vtxnum: %i, vat: %i\n", vtxnum, vatnum);
}
if (vtxnum != 0) {
lines += vtxnum - 1;
#if GFX_BLACKJACK_AND_SHADERS
for (unsigned i = 0; i < vtxnum; i++) {
FifoWalk(vatnum, &vertex_data[i], gxfifo);
}
glBufferData(GL_ARRAY_BUFFER, vtxnum * sizeof(Vertex), vertex_data, GL_STATIC_DRAW);
glDrawArrays(GL_LINE_STRIP, 0, vtxnum);
gl_error = glGetError();
if (gl_error != GL_NO_ERROR) {
Halt("GL Error CP_CMD_DRAW_LINESTRIP: %x\n", gl_error);
}
#else
RAS_Begin(RAS_LINE_STRIP, vtxnum);
Vertex vtx;
while (vtxnum--) {
FifoWalk(vatnum, &vtx, gxfifo);
RAS_SendVertex(&vtx);
}
RAS_End();
#endif
}
break;
}
// 0xB8
case CP_CMD_DRAW_POINT | 0:
case CP_CMD_DRAW_POINT | 1:
case CP_CMD_DRAW_POINT | 2:
case CP_CMD_DRAW_POINT | 3:
case CP_CMD_DRAW_POINT | 4:
case CP_CMD_DRAW_POINT | 5:
case CP_CMD_DRAW_POINT | 6:
case CP_CMD_DRAW_POINT | 7:
{
unsigned vatnum = cmd & 7;
unsigned vtxnum = gxfifo->Read16();
if (logDrawCommands)
{
Report(Channel::GP, "CP_CMD_DRAW_POINT: vtxnum: %i, vat: %i\n", vtxnum, vatnum);
}
if (vtxnum != 0) {
pts += vtxnum;
#if GFX_BLACKJACK_AND_SHADERS
for (unsigned i = 0; i < vtxnum; i++) {
FifoWalk(vatnum, &vertex_data[i], gxfifo);
}
glBufferData(GL_ARRAY_BUFFER, vtxnum * sizeof(Vertex), vertex_data, GL_STATIC_DRAW);
glDrawArrays(GL_POINTS, 0, vtxnum);
gl_error = glGetError();
if (gl_error != GL_NO_ERROR) {
Halt("GL Error CP_CMD_DRAW_POINT: %x\n", gl_error);
}
#else
RAS_Begin(RAS_POINT, vtxnum);
Vertex vtx;
while (vtxnum--) {
FifoWalk(vatnum, &vtx, gxfifo);
RAS_SendVertex(&vtx);
}
RAS_End();
#endif
}
break;
}
// ---------------------------------------------------------------
// Unknown/unsupported fifo command
default:
{
GxBadFifo(cmd);
break;
}
}
}
}