mirror of
https://github.com/DaedalusX64/daedalus.git
synced 2025-04-02 10:21:48 -04:00
305 lines
7.5 KiB
C++
305 lines
7.5 KiB
C++
/*
|
|
Copyright (C) 2001 StrmnNrmn
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
#include "Base/Types.h"
|
|
#include <cstring>
|
|
#include <fstream>
|
|
|
|
#include "Core/RSP_HLE.h"
|
|
|
|
#include "Core/Interrupt.h"
|
|
#include "Core/Memory.h"
|
|
#include "Debug/DBGConsole.h"
|
|
#include "Debug/DebugLog.h"
|
|
#include "Debug/Dump.h" // For Dump_GetDumpDirectory()
|
|
#include "Utility/MathUtil.h"
|
|
#include "Ultra/ultra_mbi.h"
|
|
#include "Ultra/ultra_rcp.h"
|
|
#include "Ultra/ultra_sptask.h"
|
|
#include "HLEAudio/AudioPlugin.h"
|
|
#include "HLEGraphics/GraphicsPlugin.h"
|
|
#include "Utility/BatchTest.h"
|
|
|
|
#include "Debug/PrintOpCode.h"
|
|
#include "Utility/Profiler.h"
|
|
|
|
static const bool gGraphicsEnabled = true;
|
|
static const bool gAudioEnabled = true;
|
|
|
|
extern void jpeg_decode_PS(OSTask *task);
|
|
extern void jpeg_decode_PS0(OSTask *task);
|
|
extern void jpeg_decode_OB(OSTask *task);
|
|
|
|
|
|
/* RE2Task.cpp + HqvmTask.cpp */
|
|
extern "C" {
|
|
//extern void resize_bilinear_task(OSTask *task);
|
|
//extern void decode_video_frame_task(OSTask *task);
|
|
//extern void fill_video_double_buffer_task(OSTask *task);
|
|
extern void hvqm2_decode_sp1_task(OSTask *task);
|
|
};
|
|
|
|
#ifdef DAEDALUS_DEBUG_CONSOLE
|
|
#if 0
|
|
static void RDP_DumpRSPCode(char * name, u32 crc, u32 * mem_base, u32 pc_base, u32 len)
|
|
{
|
|
std::string filename = FORMAT_NAMESPACE::format("task_dump_{}_crc_0x{}.txt", name, crc);
|
|
|
|
// snprintf(filename, sizeof(filename), "task_dump_%s_crc_0x%08x.txt", name, crc);
|
|
|
|
std::filesystem::path filepath = setBasePath("rsp_dumps");
|
|
std::filesystem::create_directory(filepath);
|
|
filepath /= filename;
|
|
|
|
std::fstream fp(filepath, std::ios::in);
|
|
|
|
if (fp.is_open())
|
|
{
|
|
for (u32 i = 0; i < len; i+=4)
|
|
{
|
|
OpCode op;
|
|
u32 pc = i & 0x0FFF;
|
|
op._u32 = mem_base[i/4];
|
|
|
|
char opinfo[400];
|
|
SprintRSPOpCodeInfo( opinfo, pc + pc_base, op );
|
|
|
|
fp << FORMAT_NAMESPACE::format("0x{:08x}: <0x{:08x}> {}\n", pc + pc_base, op._u32, opinfo);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
#if 0
|
|
static void RSP_HLE_DumpTaskInfo( const OSTask * pTask )
|
|
{
|
|
DBGConsole_Msg(0, "DP: Task:%08x Flags:%08x BootCode:%08x BootCodeSize:%08x",
|
|
pTask->t.type, pTask->t.flags, pTask->t.ucode_boot, pTask->t.ucode_boot_size);
|
|
|
|
DBGConsole_Msg(0, "DP: uCode:%08x uCodeSize:%08x uCodeData:%08x uCodeDataSize:%08x",
|
|
pTask->t.ucode, pTask->t.ucode_size, pTask->t.ucode_data, pTask->t.ucode_data_size);
|
|
|
|
DBGConsole_Msg(0, "DP: Stack:%08x StackS:%08x Output:%08x OutputS:%08x",
|
|
pTask->t.dram_stack, pTask->t.dram_stack_size, pTask->t.output_buff, pTask->t.output_buff_size);
|
|
|
|
DBGConsole_Msg(0, "DP: Data(PC):%08x DataSize:%08x YieldData:%08x YieldDataSize:%08x",
|
|
pTask->t.data_ptr, pTask->t.data_size, pTask->t.yield_data_ptr, pTask->t.yield_data_size);
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
//
|
|
|
|
void RSP_HLE_Finished(u32 setbits)
|
|
{
|
|
// Need to point to last instr?
|
|
//Memory_DPC_SetRegister(DPC_CURRENT_REG, (u32)pTask->t.data_ptr);
|
|
|
|
//
|
|
// Set the SP flags appropriately. The RSP is not running anyway, no need to stop it
|
|
//
|
|
u32 status = Memory_SP_SetRegisterBits(SP_STATUS_REG, setbits);
|
|
|
|
//
|
|
// We've set the SP_STATUS_BROKE flag - better check if it causes an interrupt
|
|
//
|
|
if( status & SP_STATUS_INTR_BREAK )
|
|
{
|
|
Memory_MI_SetRegisterBits(MI_INTR_REG, MI_INTR_SP);
|
|
R4300_Interrupt_UpdateCause3();
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
|
|
static EProcessResult RSP_HLE_Graphics()
|
|
{
|
|
DAEDALUS_PROFILE( "HLE: Graphics" );
|
|
|
|
if (gGraphicsEnabled && gGraphicsPlugin != nullptr)
|
|
{
|
|
gGraphicsPlugin->ProcessDList();
|
|
}
|
|
else
|
|
{
|
|
// Skip the entire dlist if graphics are disabled
|
|
Memory_MI_SetRegisterBits(MI_INTR_REG, MI_INTR_DP);
|
|
R4300_Interrupt_UpdateCause3();
|
|
}
|
|
|
|
|
|
#ifdef DAEDALUS_BATCH_TEST_ENABLED
|
|
if (CBatchTestEventHandler * handler = BatchTest_GetHandler())
|
|
{
|
|
handler->OnDisplayListComplete();
|
|
}
|
|
#endif
|
|
|
|
return PR_COMPLETED;
|
|
}
|
|
|
|
|
|
//
|
|
|
|
static EProcessResult RSP_HLE_Audio()
|
|
{
|
|
DAEDALUS_PROFILE( "HLE: Audio" );
|
|
|
|
if (gAudioEnabled && gAudioPlugin != nullptr)
|
|
{
|
|
return gAudioPlugin->ProcessAList();
|
|
}
|
|
return PR_COMPLETED;
|
|
}
|
|
|
|
// RSP_HLE_Jpeg and RSP_HLE_CICX105 were borrowed from Mupen64plus
|
|
static u32 sum_bytes(const u8 *bytes, u32 size)
|
|
{
|
|
u32 sum = 0;
|
|
const u8 * const bytes_end = bytes + size;
|
|
|
|
while (bytes != bytes_end)
|
|
sum += *bytes++;
|
|
|
|
return sum;
|
|
}
|
|
|
|
EProcessResult RSP_HLE_Jpeg(OSTask * task)
|
|
{
|
|
// most ucode_boot procedure copy 0xf80 bytes of ucode whatever the ucode_size is.
|
|
// For practical purpose we use a ucode_size = min(0xf80, task->ucode_size)
|
|
u32 sum = sum_bytes(g_pu8RamBase + (u32)task->t.ucode , std::min<u32>(task->t.ucode_size, 0xf80) >> 1);
|
|
|
|
//DBGConsole_Msg(0, "JPEG Task: Sum=0x%08x", sum);
|
|
switch(sum)
|
|
{
|
|
case 0x2c85a: // Pokemon Stadium Jap Exclusive jpg decompression
|
|
jpeg_decode_PS0(task);
|
|
break;
|
|
case 0x2caa6: // Zelda OOT, Pokemon Stadium {1,2} jpg decompression
|
|
jpeg_decode_PS(task);
|
|
break;
|
|
case 0x130de: // Ogre Battle & Buttom of the 9th background decompression
|
|
case 0x278b0:
|
|
jpeg_decode_OB(task);
|
|
break;
|
|
}
|
|
|
|
return PR_COMPLETED;
|
|
}
|
|
|
|
EProcessResult RSP_HLE_CICX105(OSTask * task [[maybe_unused]])
|
|
{
|
|
const u32 sum {sum_bytes(g_pu8SpImemBase, 0x1000 >> 1)};
|
|
|
|
switch(sum)
|
|
{
|
|
/* CIC x105 ucode (used during boot of CIC x105 games) */
|
|
case 0x9e2: /* CIC 6105 */
|
|
case 0x9f2: /* CIC 7105 */
|
|
{
|
|
u32 i;
|
|
u8 * dst {g_pu8RamBase + 0x2fb1f0};
|
|
u8 * src {g_pu8SpImemBase + 0x120};
|
|
|
|
/* dma_read(0x1120, 0x1e8, 0x1e8) */
|
|
memcpy(g_pu8SpImemBase + 0x120, g_pu8RamBase + 0x1e8, 0x1f0);
|
|
|
|
/* dma_write(0x1120, 0x2fb1f0, 0xfe817000) */
|
|
for (i = 0; i < 24; ++i)
|
|
{
|
|
memcpy(dst, src, 8);
|
|
dst += 0xff0;
|
|
src += 0x8;
|
|
|
|
}
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
return PR_COMPLETED;
|
|
}
|
|
|
|
// Pokemon Puzzle League uses this
|
|
EProcessResult RSP_HLE_Hvqm(OSTask * task)
|
|
{
|
|
hvqm2_decode_sp1_task(task);
|
|
return PR_COMPLETED;
|
|
}
|
|
|
|
void RSP_HLE_Reset()
|
|
{}
|
|
|
|
void RSP_HLE_ProcessTask()
|
|
{
|
|
OSTask * pTask = (OSTask *)(g_pu8SpMemBase + 0x0FC0);
|
|
EProcessResult result( PR_NOT_STARTED );
|
|
|
|
// non task
|
|
if(pTask->t.ucode_boot_size > 0x1000)
|
|
{
|
|
RSP_HLE_CICX105(pTask);
|
|
RSP_HLE_Finished(SP_STATUS_BROKE|SP_STATUS_HALT);
|
|
return;
|
|
}
|
|
|
|
switch ( pTask->t.type )
|
|
{
|
|
case M_GFXTASK:
|
|
// frozen task
|
|
if(Memory_DPC_GetRegister(DPC_STATUS_REG) & DPC_STATUS_FREEZE)
|
|
{
|
|
return;
|
|
}
|
|
result = RSP_HLE_Graphics();
|
|
break;
|
|
|
|
case M_AUDTASK:
|
|
result = RSP_HLE_Audio();
|
|
break;
|
|
|
|
case M_VIDTASK:
|
|
// Can't handle
|
|
break;
|
|
|
|
case M_FBTASK:
|
|
result = RSP_HLE_Hvqm(pTask);
|
|
break;
|
|
|
|
case M_JPGTASK:
|
|
result = RSP_HLE_Jpeg(pTask);
|
|
break;
|
|
default:
|
|
// Can't handle
|
|
DBGConsole_Msg(0, "Unknown task: %08x", pTask->t.type );
|
|
// RSP_HLE_DumpTaskInfo( pTask );
|
|
// RDP_DumpRSPCode("boot", 0xDEAFF00D, (u32*)(g_pu8RamBase + (((u32)pTask->t.ucode_boot)&0x00FFFFFF)), 0x04001000, pTask->t.ucode_boot_size);
|
|
// RDP_DumpRSPCode("unkcode", 0xDEAFF00D, (u32*)(g_pu8RamBase + (((u32)pTask->t.ucode)&0x00FFFFFF)), 0x04001080, 0x1000 - 0x80);//pTask->t.ucode_size);
|
|
|
|
break;
|
|
}
|
|
|
|
// Started and completed. No need to change cores. [synchronously]
|
|
if( result == PR_COMPLETED )
|
|
RSP_HLE_Finished(SP_STATUS_TASKDONE|SP_STATUS_BROKE|SP_STATUS_HALT);
|
|
}
|