mirror of
https://github.com/emu-russia/pureikyubu.git
synced 2024-06-01 19:17:33 -04:00
2469 lines
60 KiB
C++
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|