basic attempt at implementing the scaling command
This commit is contained in:
parent
af768fe729
commit
e46a54ef8f
|
@ -28,9 +28,9 @@ using Platform::Log;
|
|||
using Platform::LogLevel;
|
||||
|
||||
|
||||
DSPHLE_UcodeBase::DSPHLE_UcodeBase()
|
||||
DSPHLE_UcodeBase::DSPHLE_UcodeBase(melonDS::DSi& dsi) : DSi(dsi)
|
||||
{
|
||||
//
|
||||
DSi.RegisterEventFuncs(Event_DSi_DSPHLE, this, {MakeEventThunk(DSPHLE_UcodeBase, OnUcodeCmdFinish)});
|
||||
}
|
||||
|
||||
DSPHLE_UcodeBase::~DSPHLE_UcodeBase()
|
||||
|
@ -40,11 +40,22 @@ DSPHLE_UcodeBase::~DSPHLE_UcodeBase()
|
|||
|
||||
void DSPHLE_UcodeBase::Reset()
|
||||
{
|
||||
DataMemory = nullptr;
|
||||
|
||||
memset(CmdReg, 0, sizeof(CmdReg));
|
||||
memset(CmdWritten, 0, sizeof(CmdWritten));
|
||||
memset(ReplyReg, 0, sizeof(ReplyReg));
|
||||
memset(ReplyWritten, 0, sizeof(ReplyWritten));
|
||||
memset(ReplyReadCb, 0, sizeof(ReplyReadCb));
|
||||
//memset(ReplyReadCb, 0, sizeof(ReplyReadCb));
|
||||
ReplyReadCb[0] = nullptr;
|
||||
ReplyReadCb[1] = nullptr;
|
||||
ReplyReadCb[2] = nullptr;
|
||||
|
||||
SemaphoreIn = 0;
|
||||
SemaphoreOut = 0;
|
||||
SemaphoreMask = 0;
|
||||
|
||||
UcodeCmd = 0;
|
||||
}
|
||||
|
||||
void DSPHLE_UcodeBase::DoSavestate(Savestate *file)
|
||||
|
@ -65,11 +76,12 @@ bool DSPHLE_UcodeBase::SendDataIsEmpty(u8 index)
|
|||
|
||||
u16 DSPHLE_UcodeBase::RecvData(u8 index)
|
||||
{
|
||||
if (!ReplyWritten[index]) printf("DSP: receive reply%d but empty\n", index);
|
||||
if (!ReplyWritten[index]) return 0; // CHECKME
|
||||
|
||||
u16 ret = ReplyReg[index];
|
||||
ReplyWritten[index] = false;
|
||||
|
||||
printf("DSP: receive reply%d %04X\n", index, ret);
|
||||
if (ReplyReadCb[index])
|
||||
{
|
||||
ReplyReadCb[index]();
|
||||
|
@ -81,6 +93,7 @@ u16 DSPHLE_UcodeBase::RecvData(u8 index)
|
|||
|
||||
void DSPHLE_UcodeBase::SendData(u8 index, u16 val)
|
||||
{
|
||||
// TODO less ambiguous naming for those functions
|
||||
if (CmdWritten[index])
|
||||
{
|
||||
printf("??? trying to write cmd but there's already one\n");
|
||||
|
@ -90,6 +103,32 @@ void DSPHLE_UcodeBase::SendData(u8 index, u16 val)
|
|||
CmdReg[index] = val;
|
||||
CmdWritten[index] = true;
|
||||
printf("DSP: send cmd%d %04X\n", index, val);
|
||||
|
||||
if (index == 0)
|
||||
{
|
||||
if (UcodeCmd)
|
||||
{
|
||||
printf("???? there is already a command pending\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// writing to CMD0 initiates a ucode-specific command
|
||||
// parameters are then written to pipe 7
|
||||
UcodeCmd = val;
|
||||
CmdWritten[index] = false;
|
||||
|
||||
RunUcodeCmd();
|
||||
}
|
||||
else if (index == 2)
|
||||
{
|
||||
// CMD2 serves to notify that a pipe was written to
|
||||
// value is the pipe index
|
||||
|
||||
CmdWritten[index] = false;
|
||||
|
||||
if (UcodeCmd)
|
||||
RunUcodeCmd();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -104,7 +143,12 @@ void DSPHLE_UcodeBase::SendReply(u8 index, u16 val)
|
|||
ReplyReg[index] = val;
|
||||
ReplyWritten[index] = true;
|
||||
|
||||
// TODO add callback for when it is successfully written
|
||||
switch (index)
|
||||
{
|
||||
case 0: DSi.DSP.IrqRep0(); break;
|
||||
case 1: DSi.DSP.IrqRep1(); break;
|
||||
case 2: DSi.DSP.IrqRep2(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void DSPHLE_UcodeBase::SetReplyReadCallback(u8 index, fnReplyReadCb callback)
|
||||
|
@ -115,7 +159,7 @@ void DSPHLE_UcodeBase::SetReplyReadCallback(u8 index, fnReplyReadCb callback)
|
|||
|
||||
u16 DSPHLE_UcodeBase::DMAChan0GetDstHigh()
|
||||
{
|
||||
//
|
||||
// TODO?
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -139,13 +183,36 @@ u16 DSPHLE_UcodeBase::AHBMGetUnitSize(u16 index)
|
|||
|
||||
u16 DSPHLE_UcodeBase::DataReadA32(u32 addr)
|
||||
{
|
||||
//
|
||||
return 0;
|
||||
printf("ucode: DataReadA32 %08X\n", addr);
|
||||
|
||||
addr <<= 1;
|
||||
/*if (!(addr & 0x40000))
|
||||
{
|
||||
u8* ptr = DSi.NWRAMMap_B[2][(addr >> 15) & 0x7];
|
||||
return ptr ? *(u16*)&ptr[addr & 0x7FFF] : 0;
|
||||
}
|
||||
else*/
|
||||
{
|
||||
u8* ptr = DSi.NWRAMMap_C[2][(addr >> 15) & 0x7];
|
||||
return ptr ? *(u16*)&ptr[addr & 0x7FFF] : 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DSPHLE_UcodeBase::DataWriteA32(u32 addr, u16 val)
|
||||
{
|
||||
//
|
||||
printf("ucode: DataWriteA32 %08X %04X\n", addr, val);
|
||||
|
||||
addr <<= 1;
|
||||
/*if (!(addr & 0x40000))
|
||||
{
|
||||
u8* ptr = DSi.NWRAMMap_B[2][(addr >> 15) & 0x7];
|
||||
if (ptr) *(u16*)&ptr[addr & 0x7FFF] = val;
|
||||
}
|
||||
else*/
|
||||
{
|
||||
u8* ptr = DSi.NWRAMMap_C[2][(addr >> 15) & 0x7];
|
||||
if (ptr) *(u16*)&ptr[addr & 0x7FFF] = val;
|
||||
}
|
||||
}
|
||||
|
||||
u16 DSPHLE_UcodeBase::MMIORead(u16 addr)
|
||||
|
@ -194,23 +261,29 @@ void DSPHLE_UcodeBase::AHBMWrite32(u32 addr, u32 val)
|
|||
|
||||
u16 DSPHLE_UcodeBase::GetSemaphore()
|
||||
{
|
||||
//
|
||||
return 0;
|
||||
return SemaphoreOut;
|
||||
}
|
||||
|
||||
void DSPHLE_UcodeBase::SetSemaphore(u16 val)
|
||||
{
|
||||
//
|
||||
SemaphoreIn |= val;
|
||||
}
|
||||
|
||||
void DSPHLE_UcodeBase::ClearSemaphore(u16 val)
|
||||
{
|
||||
//
|
||||
SemaphoreOut &= ~val;
|
||||
}
|
||||
|
||||
void DSPHLE_UcodeBase::MaskSemaphore(u16 val)
|
||||
{
|
||||
//
|
||||
SemaphoreMask = val;
|
||||
}
|
||||
|
||||
void DSPHLE_UcodeBase::SetSemaphoreOut(u16 val)
|
||||
{
|
||||
SemaphoreOut |= val;
|
||||
if (SemaphoreOut & (~SemaphoreMask))
|
||||
DSi.DSP.IrqSem();
|
||||
}
|
||||
|
||||
|
||||
|
@ -220,6 +293,20 @@ void DSPHLE_UcodeBase::Start()
|
|||
// TODO later: detect which ucode it is and create the right class!
|
||||
// (and fall back to Teakra if not a known ucode)
|
||||
|
||||
const u16 pipeaddr = 0x0800;
|
||||
u16* mem = (u16*)DSi.NWRAMMap_C[2][0];
|
||||
|
||||
// initialize pipe structure
|
||||
u16* pipe = &mem[pipeaddr];
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
*pipe++ = 0x1000 + (0x100 * i); // buffer address
|
||||
*pipe++ = 0x200; // length in bytes
|
||||
*pipe++ = 0; // read pointer
|
||||
*pipe++ = 0; // write pointer
|
||||
*pipe++ = i; // pipe index
|
||||
}
|
||||
|
||||
SendReply(0, 1);
|
||||
SendReply(1, 1);
|
||||
SendReply(2, 1);
|
||||
|
@ -227,7 +314,8 @@ void DSPHLE_UcodeBase::Start()
|
|||
{
|
||||
printf("reply 2 was read\n");
|
||||
|
||||
SendReply(2, 0x0800);
|
||||
SendReply(2, pipeaddr);
|
||||
SetSemaphoreOut(0x8000);
|
||||
});
|
||||
|
||||
// TODO more shit
|
||||
|
@ -240,4 +328,138 @@ void DSPHLE_UcodeBase::Run(u32 cycles)
|
|||
}
|
||||
|
||||
|
||||
u16* DSPHLE_UcodeBase::LoadPipe(u8 index)
|
||||
{
|
||||
const u16 pipeaddr = 0x0800;
|
||||
u16* mem = (u16*)DSi.NWRAMMap_C[2][0];
|
||||
|
||||
u16* pipe = &mem[pipeaddr + (index * 5)];
|
||||
return pipe;
|
||||
}
|
||||
|
||||
u32 DSPHLE_UcodeBase::GetPipeLength(u16* pipe)
|
||||
{
|
||||
u32 ret;
|
||||
u16 rdptr = pipe[2];
|
||||
u16 wrptr = pipe[3];
|
||||
if (rdptr > wrptr)
|
||||
{
|
||||
u16 len = pipe[1];
|
||||
ret = wrptr + len - rdptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = wrptr - rdptr;
|
||||
}
|
||||
|
||||
if (ret & 1) printf("HUH? pipe length is odd? (%d)\n", ret);
|
||||
return ret >> 1;
|
||||
}
|
||||
|
||||
u32 DSPHLE_UcodeBase::ReadPipe(u16* pipe, u16* data, u32 len)
|
||||
{
|
||||
u16* mem = (u16*)DSi.NWRAMMap_C[2][0];
|
||||
u16* pipebuf = &mem[pipe[0]];
|
||||
u16 pipelen = pipe[1] >> 1;
|
||||
u16 rdptr = pipe[2] >> 1;
|
||||
u16 wrptr = pipe[3] >> 1;
|
||||
printf("readpipe(%d): len=%d rd=%d wr=%d\n", len, pipelen, rdptr, wrptr);
|
||||
u32 rdlen = 0;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
data[i] = pipebuf[rdptr++];
|
||||
rdlen++;
|
||||
if (rdptr >= pipelen) rdptr = 0;
|
||||
if (rdptr == wrptr) break;
|
||||
}
|
||||
printf("-> rd=%d\n", rdptr);
|
||||
pipe[2] = rdptr << 1;
|
||||
SendReply(2, pipe[4]);
|
||||
SetSemaphoreOut(0x8000);
|
||||
|
||||
return rdlen;
|
||||
}
|
||||
|
||||
void DSPHLE_UcodeBase::RunUcodeCmd()
|
||||
{
|
||||
u16* pipe = LoadPipe(7);
|
||||
u32 len = GetPipeLength(pipe);
|
||||
printf("try to run ucode cmd: cmd=%d, len=%d\n", UcodeCmd, len);
|
||||
switch (UcodeCmd)
|
||||
{
|
||||
case 1: // scaling
|
||||
if (len < 14) return;
|
||||
UcodeCmd_Scaling(pipe);
|
||||
break;
|
||||
}
|
||||
|
||||
//UcodeCmd = 0;
|
||||
}
|
||||
|
||||
void DSPHLE_UcodeBase::OnUcodeCmdFinish(u32 param)
|
||||
{
|
||||
printf("finish cmd %d, param=%d, %d/%d\n", UcodeCmd, param, CmdWritten[2], ReplyWritten[2]);
|
||||
UcodeCmd = 0;
|
||||
SendReply(1, (u16)param);
|
||||
}
|
||||
|
||||
void DSPHLE_UcodeBase::UcodeCmd_Scaling(u16* pipe)
|
||||
{
|
||||
u16 params[14];
|
||||
ReadPipe(pipe, params, 14);
|
||||
|
||||
u32 src_addr = (params[1] << 16) | params[0];
|
||||
u32 dst_addr = (params[3] << 16) | params[2];
|
||||
u16 filter = params[4];
|
||||
u16 src_width = params[5];
|
||||
u16 src_height = params[6];
|
||||
u16 width_scale = params[7];
|
||||
u16 height_scale = params[8];
|
||||
u16 rect_xoffset = params[9];
|
||||
u16 rect_yoffset = params[10];
|
||||
u16 rect_width = params[11];
|
||||
u16 rect_height = params[12];
|
||||
|
||||
u32 dst_width = (src_width * width_scale) / 1000;
|
||||
u32 dst_height = (src_height * height_scale) / 1000;
|
||||
|
||||
// TODO those are slightly different for bicubic
|
||||
u32 x_factor = ((rect_width - 2) << 10) / (dst_width - 1);
|
||||
u32 y_factor = ((rect_height - 2) << 10) / (dst_height - 1);
|
||||
|
||||
// bound check
|
||||
// CHECKME
|
||||
//if (dst_width > rect_width) dst_width = rect_width;
|
||||
//if (dst_height > rect_height) dst_height = rect_height;
|
||||
// at 1700 it starts going out of bounds
|
||||
|
||||
src_addr += (((rect_yoffset * src_width) + rect_xoffset) << 1);
|
||||
//printf("scale %08X -> %08X, %dx%d %dx%d %dx%d\n", src_addr, dst_addr, src_width, src_height, rect_width, rect_height, dst_width, dst_height);
|
||||
for (u32 y = 0; y < dst_height; y++)
|
||||
{
|
||||
u32 sy = ((y * y_factor) + 0x3FF) >> 10;
|
||||
u32 src_line = src_addr + ((sy * src_width) << 1);
|
||||
//printf("line %d->%d %d %08X\n", y, sy, src_width, src_line);
|
||||
for (u32 x = 0; x < dst_width; x++)
|
||||
{
|
||||
u32 sx = ((x * x_factor) + 0x3FF) >> 10;
|
||||
|
||||
u16 v = DSi.ARM9Read16(src_line + (sx << 1));
|
||||
DSi.ARM9Write16(dst_addr, v);
|
||||
//printf("%d,%d %08X -> %08X\n", y, x, src_line+(sx<<1),dst_addr);
|
||||
dst_addr += 2;
|
||||
}
|
||||
|
||||
//src_addr += (src_width << 1);
|
||||
}
|
||||
|
||||
// TODO the rest of the shit!!
|
||||
|
||||
// TODO add a delay to this
|
||||
// TODO make the delay realistic
|
||||
//SendReply(1, 1);
|
||||
DSi.ScheduleEvent(Event_DSi_DSPHLE, false, 600000, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -27,10 +27,12 @@
|
|||
namespace melonDS
|
||||
{
|
||||
|
||||
class DSi;
|
||||
|
||||
class DSPHLE_UcodeBase
|
||||
{
|
||||
public:
|
||||
DSPHLE_UcodeBase();
|
||||
DSPHLE_UcodeBase(melonDS::DSi& dsi);
|
||||
~DSPHLE_UcodeBase();
|
||||
void Reset();
|
||||
void DoSavestate(Savestate* file);
|
||||
|
@ -70,16 +72,35 @@ public:
|
|||
void ClearSemaphore(u16 val);
|
||||
void MaskSemaphore(u16 val);
|
||||
|
||||
void SetSemaphoreOut(u16 val);
|
||||
|
||||
void Start();
|
||||
|
||||
void Run(u32 cycles);
|
||||
|
||||
protected:
|
||||
melonDS::DSi& DSi;
|
||||
u16* DataMemory;
|
||||
|
||||
u16 CmdReg[3];
|
||||
bool CmdWritten[3];
|
||||
u16 ReplyReg[3];
|
||||
bool ReplyWritten[3];
|
||||
fnReplyReadCb ReplyReadCb[3];
|
||||
|
||||
u16 SemaphoreIn; // ARM9 -> DSP
|
||||
u16 SemaphoreOut; // DSP -> ARM9
|
||||
u16 SemaphoreMask; // DSP -> ARM9
|
||||
|
||||
u16 UcodeCmd;
|
||||
|
||||
u16* LoadPipe(u8 index);
|
||||
u32 GetPipeLength(u16* pipe);
|
||||
u32 ReadPipe(u16* pipe, u16* data, u32 len);
|
||||
|
||||
void RunUcodeCmd();
|
||||
void OnUcodeCmdFinish(u32 param);
|
||||
void UcodeCmd_Scaling(u16* pipe);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ u16 DSi_DSP::GetPSTS() const
|
|||
if ( HleCore->RecvDataIsReady(0)) r |= 1<<10;
|
||||
if ( HleCore->RecvDataIsReady(1)) r |= 1<<11;
|
||||
if ( HleCore->RecvDataIsReady(2)) r |= 1<<12;
|
||||
|
||||
//printf("GetPSTS: %04X\n", r); 8100
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -119,7 +119,7 @@ DSi_DSP::DSi_DSP(melonDS::DSi& dsi) : DSi(dsi)
|
|||
DSi.RegisterEventFuncs(Event_DSi_DSP, this, {MakeEventThunk(DSi_DSP, DSPCatchUpU32)});
|
||||
|
||||
//TeakraCore = new Teakra::Teakra();
|
||||
HleCore = new DSPHLE_UcodeBase();
|
||||
HleCore = new DSPHLE_UcodeBase(DSi);
|
||||
SCFG_RST = false;
|
||||
|
||||
// ????
|
||||
|
@ -254,7 +254,7 @@ void DSi_DSP::PDataDMAWrite(u16 wrval)
|
|||
//addr |= (u32)TeakraCore->DMAChan0GetDstHigh() << 16;
|
||||
//TeakraCore->DataWriteA32(addr, wrval);
|
||||
addr |= (u32)HleCore->DMAChan0GetDstHigh() << 16;
|
||||
HleCore->DataWriteA32(addr, wrval);
|
||||
HleCore->DataWriteA32(addr, wrval);
|
||||
break;
|
||||
case 1<<12: // mmio
|
||||
//TeakraCore->MMIOWrite(addr & 0x7FF, wrval);
|
||||
|
@ -356,7 +356,7 @@ u16 DSi_DSP::PDataDMARead()
|
|||
}
|
||||
break;
|
||||
default: return r;
|
||||
}printf("DSP: PDATA read %08X -> %04X\n", addr, r);
|
||||
}printf("DSP: PDATA read %08X -> %04X (%04X)\n", addr, r, DSP_PCFG);
|
||||
|
||||
if (DSP_PCFG & (1<<1)) // auto-increment
|
||||
++DSP_PADR; // overflows and stays within a 64k 'page' // TODO: is this +1 or +2?
|
||||
|
|
Loading…
Reference in New Issue