diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index 9359212c431..0a428a460d9 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -251,6 +251,19 @@ set(RUNTIME_SOURCE overlord/jak2/streamlfo.cpp overlord/jak2/streamlist.cpp overlord/jak2/vag.cpp + overlord/jak3/start.cpp + overlord/jak3/iso_api.cpp + overlord/jak3/iso_fake.cpp + overlord/jak3/iso_queue.cpp + overlord/jak3/iso.cpp + overlord/jak3/overlord.cpp + overlord/jak3/pagemanager.cpp + overlord/jak3/ramdisk.cpp + overlord/jak3/sbank.cpp + overlord/jak3/srpc.cpp + overlord/jak3/ssound.cpp + overlord/jak3/stream.cpp + overlord/jak3/vblank_handler.cpp runtime.cpp sce/deci2.cpp sce/iop.cpp diff --git a/game/common/dgo_rpc_types.h b/game/common/dgo_rpc_types.h index 14e7523e335..f4b6709f43e 100644 --- a/game/common/dgo_rpc_types.h +++ b/game/common/dgo_rpc_types.h @@ -40,8 +40,8 @@ struct RPC_Dgo_Cmd { uint32_t buffer2; uint32_t buffer_heap_top; char name[16]; - uint16_t cgo_id; - uint8_t pad[30]; + uint32_t cgo_id; + uint8_t pad[28]; }; static_assert(sizeof(RPC_Dgo_Cmd) == 0x40); } // namespace jak3 diff --git a/game/overlord/jak3/basefile.h b/game/overlord/jak3/basefile.h new file mode 100644 index 00000000000..b5ec389955b --- /dev/null +++ b/game/overlord/jak3/basefile.h @@ -0,0 +1,18 @@ +#pragma once + +#include "game/overlord/jak3/iso_structs.h" +#include "game/overlord/jak3/overlord.h" + +namespace jak3 { +class CBaseFile { + public: + CBaseFile(const ISOFileDef*); + virtual EIsoStatus BeginRead(ISOBuffer*) = 0; + virtual EIsoStatus SyncRead() = 0; + virtual void Close() = 0; + + /* unk return values */ + virtual void Unk1() = 0; + virtual void Unk2() = 0; +}; +} // namespace jak3 diff --git a/game/overlord/jak3/basefilesystem.h b/game/overlord/jak3/basefilesystem.h new file mode 100644 index 00000000000..f92162469ce --- /dev/null +++ b/game/overlord/jak3/basefilesystem.h @@ -0,0 +1,24 @@ +#pragma once + +#include "game/overlord/jak3/basefile.h" +#include "game/overlord/jak3/iso_structs.h" + +namespace jak3 { +class CBaseFileSystem { + public: + virtual int Init() = 0; + virtual void PollDrive() = 0; + virtual const ISOFileDef* Find(const char* name) = 0; + virtual const ISOFileDef* FindIN(const char* name) = 0; + virtual int GetLength(const ISOFileDef* def) = 0; + virtual CBaseFile* Open(const ISOFileDef* def, int offset, EFileComp mode) = 0; + virtual CBaseFile* OpenWad(const ISOFileDef* def, int offset) = 0; + virtual VagDirEntryJak3* FindVagFile(const char* name) = 0; + + u8* CheckForPageBoundaryCrossing(); + + private: + ISOBuffer m_Buffer; +}; + +} // namespace jak3 diff --git a/game/overlord/jak3/iso.cpp b/game/overlord/jak3/iso.cpp new file mode 100644 index 00000000000..265ef9aeb8f --- /dev/null +++ b/game/overlord/jak3/iso.cpp @@ -0,0 +1,366 @@ +#include "iso.h" + +#include + +#include "common/log/log.h" +#include "common/util/Assert.h" + +#include "game/common/dgo_rpc_types.h" +#include "game/overlord/jak3/basefilesystem.h" +#include "game/overlord/jak3/iso_api.h" +#include "game/overlord/jak3/iso_fake.h" +#include "game/overlord/jak3/iso_queue.h" +#include "game/overlord/jak3/stream.h" + +namespace jak3 { +using namespace iop; + +CBaseFileSystem* g_pFileSystem; +int g_nISOThreadID; +int g_nDGOThreadID; +int g_nSTRThreadID; +int g_nPlayThreadID; +int g_nISOMbx; +VagDirJak3 g_VagDir; +char g_szCurrentMusicName[16]; +char g_szTargetMusicName[16]; + +static int s_nISOInitFlag; +static ISO_LoadDGO s_LoadDGO; +static int s_nSyncMbx; +static MsgPacket s_MsgPacket_NotOnStackSync[2]; +static RPC_Dgo_Cmd s_aISO_RPCBuf[1]; +static int s_nDGOMbx; + +static u32 DGOThread(); +u32 ISOThread(); +int NullCallback(ISO_Hdr* msg); +int CopyDataToEE(ISO_Hdr*); +int CopyDataToIOP(ISO_Hdr*); +int CopyDataTo989snd(ISO_Hdr*); +int CopyData(ISO_LoadSingle*, int); + +/* COMPLETE */ +void InitDriver() { + if (g_pFileSystem->Init() == 0) { + s_nISOInitFlag = 0; + } + + SendMbx(s_nSyncMbx, &s_MsgPacket_NotOnStackSync[0]); +} + +/* TODO unfinished */ +static int LookMbx() { + MsgPacket* pkt; + + int ret = PollMbx(&pkt, s_nSyncMbx); + if (ret != KE_MBOX_NOMSG) { + // FIXME + } + + return ret != KE_MBOX_NOMSG; +} + +/* COMPLETE */ +static void WaitMbx(int mbx) { + MsgPacket* pkt; + ReceiveMbx(&pkt, mbx); +} + +/* TODO unfinished */ +int InitISOFS(const char* fs_mode, const char* loading_sceeen) { + const ISOFileDef* fd; + ThreadParam thp; + MbxParam mbx; + + memset(&s_LoadDGO, 0, sizeof(s_LoadDGO)); + /* TODO INIT s_LoadDgo fields */ + + s_nISOInitFlag = 1; + g_pFileSystem = &g_FakeISOCDFileSystem; + + /* Lets not bother error checking the Create* calls */ + mbx.attr = 0; + mbx.option = 0; + g_nISOMbx = CreateMbx(&mbx); + + mbx.attr = 0; + mbx.option = 0; + s_nDGOMbx = CreateMbx(&mbx); + + mbx.attr = 0; + mbx.option = 0; + s_nSyncMbx = CreateMbx(&mbx); + + thp.attr = TH_C; + thp.entry = ISOThread; + thp.initPriority = 0x37; + thp.option = 0; + thp.stackSize = 0x1100; + g_nISOThreadID = CreateThread(&thp); + + thp.attr = TH_C; + thp.entry = DGOThread; + thp.initPriority = 0x38; + thp.option = 0; + thp.stackSize = 0x900; + g_nDGOThreadID = CreateThread(&thp); + + thp.attr = TH_C; + thp.entry = STRThread; + thp.initPriority = 0x39; + thp.option = 0; + thp.stackSize = 0x900; + g_nSTRThreadID = CreateThread(&thp); + + thp.attr = TH_C; + thp.entry = PLAYThread; + thp.initPriority = 0x35; + thp.option = 0; + thp.stackSize = 0x900; + g_nPlayThreadID = CreateThread(&thp); + + StartThread(g_nISOThreadID, 0); + StartThread(g_nDGOThreadID, 0); + StartThread(g_nSTRThreadID, 0); + StartThread(g_nPlayThreadID, 0); + + WaitMbx(s_nSyncMbx); + + /* Originally VAGDIR is only loaded for the CD filesystem + * Presumably there was different mechanism for fakeiso, + * but we need it regardless */ + + fd = FindIsoFile("VAGDIR.AYB"); + LoadISOFileToIOP(fd, &g_VagDir, sizeof(g_VagDir)); + + /* Skip getting the loading screen thing? */ + + return s_nISOInitFlag; +} + +const ISOFileDef* FindIsoFile(const char* name) { + return g_pFileSystem->Find(name); +} + +u32 ISOThread() { + ISO_Msg* msg; + + g_szCurrentMusicName[0] = '\0'; + g_szTargetMusicName[0] = '\0'; + InitBuffers(); + // InitVagCmds(); + + InitDriver(); + + while (true) { + int res = PollMbx((MsgPacket**)&msg, g_nISOMbx); + if (res == KE_OK) { + msg->SetActive(false); + msg->SetUnk1(false); + msg->SetUnk2(false); + msg->file = nullptr; + msg->callback = NullCallback; + + /* LoadSingle messages */ + if (msg->msg_kind >= LOAD_TO_EE_CMD_ID && msg->msg_kind <= LOAD_TO_989SND) { + auto* ls = static_cast(msg); + int pri = 0; + if (ls->unk40 == 2) { + pri = 2; + } + if (ls->unk40 == 10) { + pri = 4; + } + if (!QueueMessage(msg, pri)) { + break; + } + + msg->file = nullptr; + if (msg->msg_kind == LOAD_TO_EE_OFFSET_CMD_ID) { + msg->file = g_pFileSystem->Open(ls->fd, ls->offset, EFileComp::MODE1); + } else if (msg->msg_kind == LOAD_TO_989SND) { + char name[16] = {0}; + if (ls->filename) { + strncpy(name, ls->filename, 12); + name[8] = 0; + strcat(name, ".sbk"); + auto fd = g_pFileSystem->Find(name); + if (fd) { + msg->file = g_pFileSystem->Open(ls->fd, -1, EFileComp::MODE1); + } + } + } else { + msg->file = g_pFileSystem->Open(ls->fd, -1, EFileComp::MODE1); + } + + if (!msg->file) { + msg->m_nStatus = 8; + UnqueueMessage(msg); + ReturnMessage(msg); + break; + } + + ls->unk44 = ls->address; + ls->unk48 = 0; + ls->length_to_copy = g_pFileSystem->GetLength(ls->fd); + if (msg->msg_kind == LOAD_TO_989SND) { + ls->length = ls->length_to_copy; + } else { + if (!ls->length_to_copy || ls->length < ls->length_to_copy) { + ls->length_to_copy = ls->length; + } + } + + switch (msg->msg_kind) { + case LOAD_TO_EE_CMD_ID: + msg->callback = CopyDataToEE; + break; + case LOAD_TO_IOP_CMD_ID: + msg->callback = CopyDataToIOP; + break; + case LOAD_TO_EE_OFFSET_CMD_ID: + msg->callback = CopyDataToEE; + break; + case LOAD_TO_989SND: + msg->callback = CopyDataTo989snd; + break; + default: + ASSERT_NOT_REACHED(); + } + + msg->m_nStatus = 2; + msg->SetActive(true); + } else if (msg->msg_kind == 0xADEADBEE) { + ReturnMessage(msg); + ExitThread(); + } + } + + DelayThread(4000); + } + + return 0; +} + +static void ISO_LoadDGO(RPC_Dgo_Cmd* msg); +static void ISO_LoadNextDGO(RPC_Dgo_Cmd* msg); +static void ISO_CancelDGO(RPC_Dgo_Cmd* msg); + +static void* RPC_DGO(u32 fno, void* data, int size) { + auto* msg = static_cast(data); + + switch (fno) { + case 0: + ISO_LoadDGO(msg); + break; + case 1: + ISO_LoadNextDGO(msg); + break; + case 2: + ISO_CancelDGO(msg); + break; + default: + msg->result = 1; + break; + } + return data; +} + +static u32 DGOThread() { + sceSifQueueData dq; + sceSifServeData serve; + + CpuDisableIntr(); + sceSifInitRpc(0); + sceSifSetRpcQueue(&dq, GetThreadId()); + sceSifRegisterRpc(&serve, 0xfab3, RPC_DGO, s_aISO_RPCBuf, sizeof(s_aISO_RPCBuf), nullptr, nullptr, + &dq); + CpuEnableIntr(); + sceSifRpcLoop(&dq); + + return 0; +} + +static void ISO_LoadDGO(RPC_Dgo_Cmd* msg) { + auto* def = g_pFileSystem->Find(msg->name); + if (def == nullptr) { + msg->result = 1; + return; + } + + ASSERT_NOT_REACHED(); + + msg->buffer1 = msg->buffer_heap_top; + msg->result = 0; +} + +static void ISO_LoadNextDGO(RPC_Dgo_Cmd* msg) { + ASSERT_NOT_REACHED(); +} + +static void ISO_CancelDGO(RPC_Dgo_Cmd* msg) { + ASSERT_NOT_REACHED(); +} + +/* COMPLETE */ +const ISOFileDef* FindISOFile(char* name) { + return g_pFileSystem->Find(name); +} + +/* COMPLETE */ +s32 GetISOFileLength(const ISOFileDef* fd) { + return g_pFileSystem->GetLength(fd); +} + +int CopyDataToEE(ISO_Hdr* msg) { + return CopyData((ISO_LoadSingle*)msg, 0); +} + +int CopyDataToIOP(ISO_Hdr* msg) { + return CopyData((ISO_LoadSingle*)msg, 1); +} + +int CopyDataTo989snd(ISO_Hdr* msg) { + return CopyData((ISO_LoadSingle*)msg, 2); +} + +int CopyData(ISO_LoadSingle*, int) { + ASSERT_NOT_REACHED(); + return 0; +} + +int NullCallback(ISO_Hdr* msg) { + return 7; +} + +void ISO_Hdr::SetActive(bool b) { + m_bActive = b; +} + +void ISO_Hdr::SetUnk1(bool b) { + unk1 = b; +} + +void ISO_Hdr::SetUnk2(bool b) { + unk2 = b; +} + +void ISOBuffer::AdjustDataLength(int size) { + int state; + + CpuSuspendIntr(&state); + decompressed_size -= size; + CpuResumeIntr(state); +} + +void ISOBuffer::AdvanceCurrentData(int size) { + int state; + + CpuSuspendIntr(&state); + decomp_buffer += size; + decompressed_size -= size; + CpuResumeIntr(state); +} + +} // namespace jak3 diff --git a/game/overlord/jak3/iso.h b/game/overlord/jak3/iso.h new file mode 100644 index 00000000000..9d7f5b69ab0 --- /dev/null +++ b/game/overlord/jak3/iso.h @@ -0,0 +1,59 @@ +#pragma once + +#include "game/overlord/jak3/basefile.h" +#include "game/sce/iop.h" + +namespace jak3 { + +constexpr int LOAD_TO_EE_CMD_ID = 0x100; // command to load file to ee +constexpr int LOAD_TO_IOP_CMD_ID = 0x101; // command to load to iop +constexpr int LOAD_TO_EE_OFFSET_CMD_ID = 0x102; // command to load file to ee with offset. +constexpr int LOAD_TO_989SND = 0x103; +constexpr int PAUSE_VAG_STREAM = 0x403; // Command to pause a vag stream +constexpr int CONTINUE_VAG_STREAM = 0x404; // Command to continue a vag stream +constexpr int SET_DIALOG_VOLUME = 0x406; // Command to set the volume of vag playback + +extern int g_nISOMbx; + +struct ISO_Hdr { + iop::MsgPacket m_Pkt; + int m_nStatus; + bool m_bActive; + bool unk1; + bool unk2; + + void SetActive(bool b); + void SetUnk1(bool b); + void SetUnk2(bool b); +}; + +struct ISO_Msg : ISO_Hdr { + u32 msg_kind; + int mbx_to_reply; + int thread_id; + int (*callback)(ISO_Hdr*); + CBaseFile* file; + u32 priority; +}; + +struct ISO_LoadDGO : ISO_Msg { + ISOFileDef* fd; +}; + +struct ISO_LoadSingle : ISO_Msg { + const ISOFileDef* fd; + void* address; + u32 length; + u32 length_to_copy; + u32 offset; + char* filename; + u32 unk40; + void* unk44; + u32 unk48; + u32 unk4c; +}; + +int InitISOFS(const char* fs_mode, const char* loading_sceeen); +const ISOFileDef* FindIsoFile(const char* name); + +} // namespace jak3 diff --git a/game/overlord/jak3/iso_api.cpp b/game/overlord/jak3/iso_api.cpp new file mode 100644 index 00000000000..1b083dd4425 --- /dev/null +++ b/game/overlord/jak3/iso_api.cpp @@ -0,0 +1,31 @@ +#include "iso_api.h" + +#include "common/common_types.h" + +#include "game/overlord/jak3/iso.h" +#include "game/overlord/jak3/iso_structs.h" + +namespace jak3 { +using namespace iop; + +u32 LoadISOFileToIOP(const ISOFileDef* file, void* addr, u32 length) { + ISO_LoadSingle msg; + + msg.msg_kind = 0x101; + msg.mbx_to_reply = 0; + msg.thread_id = GetThreadId(); + msg.fd = file; + msg.address = addr; + msg.length = length; + SendMbx(g_nISOMbx, &msg); + SleepThread(); + + u32 ret = 0; + if (msg.m_nStatus == 0) { + ret = msg.length_to_copy; + } + + return ret; +} + +} // namespace jak3 diff --git a/game/overlord/jak3/iso_api.h b/game/overlord/jak3/iso_api.h new file mode 100644 index 00000000000..6866a997edb --- /dev/null +++ b/game/overlord/jak3/iso_api.h @@ -0,0 +1,12 @@ +#ifndef ISO_API_H_ +#define ISO_API_H_ + +#include "common/common_types.h" + +#include "game/overlord/jak3/iso_structs.h" + +namespace jak3 { +u32 LoadISOFileToIOP(const ISOFileDef* file, void* addr, u32 length); +} + +#endif // ISO_API_H_ diff --git a/game/overlord/jak3/iso_fake.cpp b/game/overlord/jak3/iso_fake.cpp new file mode 100644 index 00000000000..a906a5a7114 --- /dev/null +++ b/game/overlord/jak3/iso_fake.cpp @@ -0,0 +1,36 @@ +#include "iso_fake.h" + +namespace jak3 { +CFakeISOCDFileSystem g_FakeISOCDFileSystem; + +int CFakeISOCDFileSystem::Init() { + return 0; +} + +void CFakeISOCDFileSystem::PollDrive() {} + +const ISOFileDef* CFakeISOCDFileSystem::Find(const char* name) { + return nullptr; +} + +const ISOFileDef* CFakeISOCDFileSystem::FindIN(const char* name) { + return nullptr; +} + +int CFakeISOCDFileSystem::GetLength(const ISOFileDef* def) { + return 0; +} + +CBaseFile* CFakeISOCDFileSystem::Open(const ISOFileDef* def, int offset, EFileComp mode) { + return nullptr; +} + +CBaseFile* CFakeISOCDFileSystem::OpenWad(const ISOFileDef* def, int offset) { + return nullptr; +} + +VagDirEntryJak3* CFakeISOCDFileSystem::FindVagFile(const char* name) { + return nullptr; +} + +} // namespace jak3 diff --git a/game/overlord/jak3/iso_fake.h b/game/overlord/jak3/iso_fake.h new file mode 100644 index 00000000000..16bbb7b8693 --- /dev/null +++ b/game/overlord/jak3/iso_fake.h @@ -0,0 +1,35 @@ +#ifndef ISO_FAKE_H_ +#define ISO_FAKE_H_ + +#include "basefile.h" +#include "basefilesystem.h" + +#include "game/overlord/jak3/iso.h" + +namespace jak3 { +class CFakeISOCDFileSystem : public CBaseFileSystem { + int Init() override; + void PollDrive() override; + const ISOFileDef* Find(const char* name) override; + const ISOFileDef* FindIN(const char* name) override; + int GetLength(const ISOFileDef* def) override; + CBaseFile* Open(const ISOFileDef* def, int offset, EFileComp mode) override; + CBaseFile* OpenWad(const ISOFileDef* def, int offset) override; + VagDirEntryJak3* FindVagFile(const char* name) override; +}; + +class CFakeISOCDFile : public CBaseFile { + EIsoStatus BeginRead(ISOBuffer*) override; + EIsoStatus SyncRead() override; + void Close() override; + + /* unk return values */ + void Unk1() override; + void Unk2() override; +}; + +extern CFakeISOCDFileSystem g_FakeISOCDFileSystem; + +} // namespace jak3 + +#endif // ISO_FAKE_H_ diff --git a/game/overlord/jak3/iso_queue.cpp b/game/overlord/jak3/iso_queue.cpp new file mode 100644 index 00000000000..92561d525f3 --- /dev/null +++ b/game/overlord/jak3/iso_queue.cpp @@ -0,0 +1,78 @@ +#include "iso_queue.h" + +#include "common/log/log.h" +#include "common/util/Assert.h" + +#include "game/overlord/jak3/pagemanager.h" +#include "game/overlord/jak3/util.h" +#include "game/sce/iop.h" + +namespace jak3 { +using namespace iop; + +constexpr int N_VAG_CMDS = 6; + +u32 g_auStreamSRAM[N_VAG_CMDS]; +u32 g_auTrapSRAM[N_VAG_CMDS]; +int g_nPriQueueSema; +int g_nISOSema; + +PriStackEntry gPriStack[N_PRIORITIES]; + +CPageManager g_PageManager; + +void InitBuffers() { + SemaParam semap; + + semap.init_count = 1; + semap.max_count = 1; + semap.attr = 0; + semap.option = 0; + g_nPriQueueSema = CreateSema(&semap); + + g_PageManager.Initialize(); + + semap.init_count = 1; + semap.max_count = 1; + semap.attr = SA_THPRI; + semap.option = 0; + g_nISOSema = CreateSema(&semap); +} + +bool QueueMessage(ISO_Msg* msg, int priority) { + msg->m_nStatus = 2; + msg->priority = priority; + + int level = priority == 5; + + { + ScopedLock l(g_nPriQueueSema); + + if (gPriStack[level].count != 8) { + gPriStack[level].entries[gPriStack[level].count] = msg; + gPriStack[level].count++; + + return true; + } + } + + msg->m_nStatus = 4; + ReturnMessage(msg); + + return false; +} + +void UnqueueMessage(ISO_Msg* msg) {} + +void ReturnMessage(ISO_Msg* msg) { + if (msg->mbx_to_reply) { + SendMbx(msg->mbx_to_reply, msg); + } else if (msg->thread_id) { + WakeupThread(msg->thread_id); + } else { + // FreeVAGCommand(msg); + ASSERT_NOT_REACHED_MSG("unimplemented"); + } +} + +} // namespace jak3 diff --git a/game/overlord/jak3/iso_queue.h b/game/overlord/jak3/iso_queue.h new file mode 100644 index 00000000000..156d265719e --- /dev/null +++ b/game/overlord/jak3/iso_queue.h @@ -0,0 +1,21 @@ +#ifndef ISO_QUEUE_H_ +#define ISO_QUEUE_H_ + +#include "game/overlord/jak3/iso.h" + +namespace jak3 { +constexpr int N_PRIORITIES = 2; +constexpr int PRI_STACK_LENGTH = 8; + +struct PriStackEntry { + ISO_Msg* entries[PRI_STACK_LENGTH]; + int count; +}; + +void InitBuffers(); +bool QueueMessage(ISO_Msg* msg, int priority); +void ReturnMessage(ISO_Msg* msg); +void UnqueueMessage(ISO_Msg* msg); +} // namespace jak3 + +#endif // ISO_QUEUE_H_ diff --git a/game/overlord/jak3/iso_structs.h b/game/overlord/jak3/iso_structs.h new file mode 100644 index 00000000000..b69ca409ec4 --- /dev/null +++ b/game/overlord/jak3/iso_structs.h @@ -0,0 +1,50 @@ +#pragma once + +#include "common/common_types.h" + +#include "game/overlord/jak3/pagemanager.h" + +namespace jak3 { +/* TODO check values */ +enum class EFileComp { MODE0, MODE1, KNOWN_NOT_BLZO }; + +struct ISOBuffer { + public: + void AdjustDataLength(int); + void AdvanceCurrentData(int); + void SetDataLength(int length) { m_nDataLength = length; } + int GetDataLength() { return m_nDataLength; } + + private: + CPageManager::CPageList* m_pActivePages; + u8* decomp_buffer; + int decompressed_size; + int m_nDataLength; +}; + +struct VagDirEntryJak3 { + union { + u64 data; + struct { + u64 name : 42; + bool stereo : 1; + bool international : 1; + u8 param : 4; + u64 offset : 16; + }; + }; +}; + +static constexpr int MAX_VAGDIR_ENTRIES = 4096; + +struct VagDirJak3 { + u32 id[2]; + u32 version; + u32 count; + VagDirEntryJak3 entries[MAX_VAGDIR_ENTRIES]; +}; + +struct VagDirEntry {}; + +struct ISOFileDef {}; +} // namespace jak3 diff --git a/game/overlord/jak3/overlord.cpp b/game/overlord/jak3/overlord.cpp new file mode 100644 index 00000000000..2e93b9d0a02 --- /dev/null +++ b/game/overlord/jak3/overlord.cpp @@ -0,0 +1,30 @@ +#include "overlord.h" + +#include +#include +#include + +namespace jak3 { +extern int start_overlord(int, const char* const*); + +void Panic() { + printf( + "IOP: *** Overlord panic at 0x%08lx (rel. address 0x%08lx)\n" + "IOP: *** Check mapfile to determine function name.\n" + "IOP: *** Thread halted.\n", + (intptr_t)__builtin_return_address(0), + (intptr_t)__builtin_return_address(0) - (intptr_t)start_overlord); + while (true) + ; +} + +char* strncpyz(char* dst, const char* src, size_t sz) { + if (sz) { + strncpy(dst, src, sz); + dst[sz - 1] = '\0'; + } + + return dst; +} + +} // namespace jak3 diff --git a/game/overlord/jak3/overlord.h b/game/overlord/jak3/overlord.h new file mode 100644 index 00000000000..15261e4a636 --- /dev/null +++ b/game/overlord/jak3/overlord.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include "common/common_types.h" + +namespace jak3 { + +struct Vec3 { + s32 x, y, z; +}; + +enum class EIsoStatus { Unk }; + +int start_overlord_wrapper(int argc, const char* const* argv, bool* signal); +void Panic(); +char* strncpyz(char* dst, const char* src, size_t sz); + +void InitSound(); + +int VBlank_Initialize(); +} // namespace jak3 diff --git a/game/overlord/jak3/pagemanager.cpp b/game/overlord/jak3/pagemanager.cpp new file mode 100644 index 00000000000..f4a82e9d693 --- /dev/null +++ b/game/overlord/jak3/pagemanager.cpp @@ -0,0 +1,191 @@ +#include "pagemanager.h" + +#include + +#include "common/util/Assert.h" + +#include "game/sce/iop.h" + +namespace jak3 { +using namespace iop; + +static constexpr u32 PAGE_SIZE = 0x8010; +static constexpr u32 NUM_PAGES = 29; + +CPageManager::CPage::CPage(u8* start, u8* end, int page_id) { + m_pNextPage = nullptr; + m_uPageBit = 1 << (page_id & 0x1f); + m_nPageState = 0; + m_pData = start; + m_pDataEnd = end; + m_nPageRefCount = 0; + m_nPageID = page_id; + m_nPageDmaRefCount = 0; + m_nAllocState = 0; + m_nPageState = 0; +} + +int CPageManager::CPage::AddRef() { + int state, ret = -1; + + CpuSuspendIntr(&state); + + if (m_nAllocState == 1 && m_pPageList != nullptr) { + m_pPageList->m_nListRefCount++; + m_nPageRefCount++; + ret = m_nPageRefCount; + } + + CpuResumeIntr(state); + + return ret; +} + +int CPageManager::CPage::ReleaseRef() { + int state, ret = -1; + + CpuSuspendIntr(&state); + + if (m_nAllocState == 1 && m_pPageList != nullptr) { + m_pPageList->m_nListRefCount--; + m_nPageRefCount--; + ret = m_nPageRefCount; + } + + CpuResumeIntr(state); + + return ret; +} + +int CPageManager::CPage::AddDmaRef() { + int state, ret = -1; + + CpuSuspendIntr(&state); + + if (m_nAllocState == 1 && m_pPageList != nullptr) { + m_pPageList->m_nListDmaRefCount++; + m_nPageDmaRefCount++; + ret = m_nPageDmaRefCount; + } + + CpuResumeIntr(state); + + return ret; +} + +int CPageManager::CPage::ReleaseDmaRef() { + int state, ret = -1; + + CpuSuspendIntr(&state); + + if (m_nAllocState == 1 && m_pPageList != nullptr) { + m_pPageList->m_nListDmaRefCount--; + m_nPageDmaRefCount--; + ret = m_nPageDmaRefCount; + } + + CpuResumeIntr(state); + + return ret; +} + +void CPageManager::CPage::FromPagesCopy(u8* pInPageData, u8* pDest, int nNumBytes) { + int nInputPageLengthLeft; + CPage* page = this; + + if (nNumBytes <= 0) { + return; + } + + for (;;) { + nInputPageLengthLeft = (uintptr_t)page->m_pDataEnd + (1 - (uintptr_t)pInPageData); + if (nInputPageLengthLeft <= nNumBytes) { + break; + } + + if (nNumBytes <= 0) { + nNumBytes -= nInputPageLengthLeft; + return; + } + + ASSERT(m_pNextPage != nullptr); + + page = page->m_pNextPage; + pInPageData = page->m_pData; + } + + memcpy(pDest, pInPageData, nNumBytes); +} + +CPageManager::CCache::CCache() { + m_paCache = nullptr; + m_uAllocatedPageMap = 0; + m_Unk = (1 << NUM_PAGES) - 1; +} + +int CPageManager::CCache::Initialize() { + m_paCache = AllocSysMemory(0, PAGE_SIZE * NUM_PAGES, nullptr); + if (!m_paCache) { + return 1; + } + + m_nNumFree = 29; + + for (auto& pl : m_aPageLists) { + pl = {}; + } + + int page_idx = 0; + u8* page_start = (u8*)m_paCache; + for (auto& page : m_aPages) { + page = CPage(page_start, page_start + 0x7fff, page_idx); + + page_start += PAGE_SIZE; + page_idx++; + } + + return 0; +} + +void CPageManager::Initialize() { + m_Cache.Initialize(); +} + +int CPageManager::TryFreePages(int nPages) { + return 0; +} + +CPageManager::CPageList* CPageManager::AllocPageList(int nPages, char unk) { + CPageList* pList = nullptr; + CPage* apCollectedPages[29]; + int nPageCount; + + if (nPages <= 0) { + return nullptr; + } + + if (m_Cache.m_nNumFree < nPages) { + if (nPages >= 29) { + return nullptr; + } + + int nFreed = TryFreePages(nPages); + if (nFreed < nPages) { + return nullptr; + } + } + + int nPageListID = std::countr_one(m_Cache.m_uAllocatedListMap); + if (nPages >= 29) { + return nullptr; + } + + m_Cache.m_uAllocatedListMap |= 1u << nPageListID; + + nPageCount = 0; + while (nPageCount < nPages) { + int nPageID = std::countr_one(m_Cache.m_uAllocatedPageMap); + } +} + +} // namespace jak3 diff --git a/game/overlord/jak3/pagemanager.h b/game/overlord/jak3/pagemanager.h new file mode 100644 index 00000000000..435d6118285 --- /dev/null +++ b/game/overlord/jak3/pagemanager.h @@ -0,0 +1,104 @@ +#pragma once + +#include "common/common_types.h" + +namespace jak3 { +class CPageManager { + public: + class CPageList; + + enum class AllocState { + EPLAS_FREE, + EPLAS_ALLOCATED, + }; + + class CPage { + public: + CPage() = default; + CPage(u8*, u8*, int); + int AddRef(); + int ReleaseRef(); + int AddDmaRef(); + int ReleaseDmaRef(); + void FromPagesCopy(u8* pInPageData, u8* pDest, int nNumBytes); + u8* GetStart() const; + u8* GetEnd() const; + bool IsReferenced() { return m_nPageRefCount != 0 || m_nPageDmaRefCount != 0; } + bool IsFilled() const; // Exists as string in july version, not sure on impl + bool IsAllocated() const; + void SetPageInputState(int state); // enum + int GetPageCacheIndex() const; + CPage* GetNextPage() const; + CPage* GetPrevPage() const; + + private: + CPage* m_pNextPage; + CPage* m_pPrevPage; + CPageList* m_pPageList; + int m_nPageRefCount; + int m_nPageDmaRefCount; + int m_nAllocState; + u32 m_nPageState; // 3: filled otherwise unk? + u8* m_pData; + u8* m_pDataEnd; + int m_nPageID; + u32 m_uPageBit; + }; + + class CPageList { + friend class CPage; + + public: + int AddActivePages(int); + int CancelActivePages(); + CPage* StepActivePage(); + void GarbageCollect(); + CPage* GetCurrentActivePage() const; + int GetNumRawPages() const; + int GetFirstRawPage() const; + int GetNumUnsteppedPages() const; + bool IsReferenced() { return m_nListRefCount != 0 || m_nListDmaRefCount != 0; } + int GetNumActivePages() const; + + private: + CPage* m_pFirstPage; + CPage* m_pLastPage; + CPage* m_pFirstACtivePage; + CPage* m_pLastActivePage; + CPage* m_pCurrentActivePage; + int m_nNumPages; + int m_nNumActivePages; + int m_nNumUnsteppedPages; + int m_nListRefCount; + int m_nListDmaRefCount; + int m_nAllocState; + }; + + void Initialize(); + CPageList* AllocPageListBytes(int nBytes, char unk); + CPageList* AllocPageList(int nPages, char unk); + CPageList* GrowPageList(CPageList* list, char nPages); + int FreePageList(CPageList* list); + int TryFreePages(int nUnk); + void GarbageCollect(); + + private: + class CCache { + public: + CCache(); + int Initialize(); + + void* m_paCache; + CPageList m_aPageLists[29]; + CPage m_aPages[29]; + int m_nNumFree; + u32 m_uAllocatedPageMap; + u32 m_uAllocatedListMap; + int m_nEventFlag; + u32 m_Unk; + }; + + CCache m_Cache; +}; + +} // namespace jak3 diff --git a/game/overlord/jak3/ramdisk.cpp b/game/overlord/jak3/ramdisk.cpp new file mode 100644 index 00000000000..09e285c72ca --- /dev/null +++ b/game/overlord/jak3/ramdisk.cpp @@ -0,0 +1,34 @@ +#include "ramdisk.h" + +#include "common/log/log.h" + +#include "game/sce/iop.h" + +namespace jak3 { +using namespace iop; + +static u8 gRamDisk_RPCBUF[40]; + +static void* RPC_Ramdisk(u32 fno, void* data, int size) { + lg::error("RPC_RAMDISK UNIMPLEMENTED"); + return nullptr; +} + +void InitRamdisk() {} + +u32 Thread_Server() { + sceSifQueueData dq; + sceSifServeData serve; + + CpuDisableIntr(); + sceSifInitRpc(0); + sceSifSetRpcQueue(&dq, GetThreadId()); + sceSifRegisterRpc(&serve, 0xfab2, RPC_Ramdisk, gRamDisk_RPCBUF, sizeof(gRamDisk_RPCBUF), nullptr, + nullptr, &dq); + CpuEnableIntr(); + sceSifRpcLoop(&dq); + + return 0; +} + +} // namespace jak3 diff --git a/game/overlord/jak3/ramdisk.h b/game/overlord/jak3/ramdisk.h new file mode 100644 index 00000000000..f081874264e --- /dev/null +++ b/game/overlord/jak3/ramdisk.h @@ -0,0 +1,9 @@ +#pragma once + +#include "common/common_types.h" + +namespace jak3 { + +u32 Thread_Server(); + +} diff --git a/game/overlord/jak3/sbank.cpp b/game/overlord/jak3/sbank.cpp new file mode 100644 index 00000000000..170b71820f1 --- /dev/null +++ b/game/overlord/jak3/sbank.cpp @@ -0,0 +1,49 @@ +#include "sbank.h" + +#include "overlord.h" + +namespace jak3 { + +SoundBankInfo gCommonBank, gModeBank; +SoundBankInfo gLevelBanks[6]; + +SoundBankInfo* gBanks[8] = { + &gCommonBank, &gModeBank, &gLevelBanks[0], &gLevelBanks[1], + &gLevelBanks[2], &gLevelBanks[3], &gLevelBanks[4], &gLevelBanks[5], +}; + +void InitBanks() { + for (int i = 0; i < 8; i++) { + gBanks[i]->in_use = false; + gBanks[i]->unk = 0; + gBanks[i]->unk2 = 0; + gBanks[i]->index = i; + } + + strncpyz(gBanks[0]->slot_name, "common", 16); + gBanks[0]->spu_size = 0xbbe40; + gBanks[0]->spu_loc = 0x1d1c0; + strncpyz(gBanks[1]->slot_name, "mode", 16); + gBanks[1]->spu_size = 0x25400; + gBanks[1]->spu_loc = 0xe0000; + strncpyz(gBanks[2]->slot_name, "level0", 16); + gBanks[2]->spu_size = 0x51400; + gBanks[2]->spu_loc = 0x105400; + strncpyz(gBanks[3]->slot_name, "level0h", 16); + gBanks[3]->spu_size = 0x28a00; + gBanks[3]->spu_loc = 0x12de00; + strncpyz(gBanks[4]->slot_name, "level1", 16); + gBanks[4]->spu_size = 0x51400; + gBanks[4]->spu_loc = 0x156800; + strncpyz(gBanks[5]->slot_name, "level1h", 16); + gBanks[5]->spu_size = 0x28a00; + gBanks[5]->spu_loc = 0x17f200; + strncpyz(gBanks[6]->slot_name, "level2", 16); + gBanks[6]->spu_size = 0x51400; + gBanks[6]->spu_loc = 0x1a7c00; + strncpyz(gBanks[7]->slot_name, "level2h", 16); + gBanks[7]->spu_size = 0x28a00; + gBanks[7]->spu_loc = 0x1d0600; +} + +} // namespace jak3 diff --git a/game/overlord/jak3/sbank.h b/game/overlord/jak3/sbank.h new file mode 100644 index 00000000000..69a41942380 --- /dev/null +++ b/game/overlord/jak3/sbank.h @@ -0,0 +1,19 @@ +#pragma once + +#include "common/common_types.h" + +namespace jak3 { +struct SoundBankInfo { + char bank_name[16]; + char slot_name[16]; + u32 spu_loc; + u32 spu_size; + u32 unk; + bool in_use; + u8 unk2; + u8 unk3; + u8 index; + u32 unk4; +}; +void InitBanks(); +} // namespace jak3 diff --git a/game/overlord/jak3/srpc.cpp b/game/overlord/jak3/srpc.cpp new file mode 100644 index 00000000000..f3b9a547099 --- /dev/null +++ b/game/overlord/jak3/srpc.cpp @@ -0,0 +1,56 @@ +#include "srpc.h" + +#include "common/log/log.h" + +#include "game/sce/iop.h" + +namespace jak3 { +using namespace iop; + +constexpr int SRPC_MESSAGE_SIZE = 0x50; +constexpr int SRPC_MESSAGE_COUNT = 128; + +static u8 s_anSRPC_PlayerBuf[SRPC_MESSAGE_SIZE * SRPC_MESSAGE_COUNT]; +static u8 s_anSRPC_LoaderBuf[SRPC_MESSAGE_SIZE]; + +static void* RPC_Player(u32 fno, void* data, int size) { + lg::error("RPC_PLAYER UNIMPLEMENTED"); + return nullptr; +} + +static void* RPC_Loader(u32 fno, void* data, int size) { + lg::error("RPC_LOADER UNIMPLEMENTED"); + return nullptr; +} + +u32 Thread_Player() { + sceSifQueueData dq; + sceSifServeData serve; + + CpuDisableIntr(); + sceSifInitRpc(0); + sceSifSetRpcQueue(&dq, GetThreadId()); + sceSifRegisterRpc(&serve, 0xfab0, RPC_Player, s_anSRPC_PlayerBuf, sizeof(s_anSRPC_PlayerBuf), + nullptr, nullptr, &dq); + CpuEnableIntr(); + sceSifRpcLoop(&dq); + + return 0; +} + +u32 Thread_Loader() { + sceSifQueueData dq; + sceSifServeData serve; + + CpuDisableIntr(); + sceSifInitRpc(0); + sceSifSetRpcQueue(&dq, GetThreadId()); + sceSifRegisterRpc(&serve, 0xfab1, RPC_Loader, s_anSRPC_LoaderBuf, sizeof(s_anSRPC_LoaderBuf), + nullptr, nullptr, &dq); + CpuEnableIntr(); + sceSifRpcLoop(&dq); + + return 0; +} + +} // namespace jak3 diff --git a/game/overlord/jak3/srpc.h b/game/overlord/jak3/srpc.h new file mode 100644 index 00000000000..c255741108b --- /dev/null +++ b/game/overlord/jak3/srpc.h @@ -0,0 +1,10 @@ +#pragma once + +#include "common/common_types.h" + +namespace jak3 { + +u32 Thread_Player(); +u32 Thread_Loader(); + +} // namespace jak3 diff --git a/game/overlord/jak3/ssound.cpp b/game/overlord/jak3/ssound.cpp new file mode 100644 index 00000000000..497aefc993d --- /dev/null +++ b/game/overlord/jak3/ssound.cpp @@ -0,0 +1,115 @@ +#include "overlord.h" + +#include "common/common_types.h" + +namespace jak3 { + +static s16 angle_table[2056] = { + 180, 0, 180, 0, 90, 90, 270, 270, 180, 0, 180, 0, 90, 90, 270, 270, 180, 0, 180, 0, + 90, 90, 270, 270, 180, 0, 180, 0, 90, 90, 270, 270, 180, 0, 180, 0, 90, 90, 270, 270, + 179, 1, 181, 359, 91, 89, 269, 271, 179, 1, 181, 359, 91, 89, 269, 271, 179, 1, 181, 359, + 91, 89, 269, 271, 179, 1, 181, 359, 91, 89, 269, 271, 178, 2, 182, 358, 92, 88, 268, 272, + 178, 2, 182, 358, 92, 88, 268, 272, 178, 2, 182, 358, 92, 88, 268, 272, 178, 2, 182, 358, + 92, 88, 268, 272, 178, 2, 182, 358, 92, 88, 268, 272, 177, 3, 183, 357, 93, 87, 267, 273, + 177, 3, 183, 357, 93, 87, 267, 273, 177, 3, 183, 357, 93, 87, 267, 273, 177, 3, 183, 357, + 93, 87, 267, 273, 176, 4, 184, 356, 94, 86, 266, 274, 176, 4, 184, 356, 94, 86, 266, 274, + 176, 4, 184, 356, 94, 86, 266, 274, 176, 4, 184, 356, 94, 86, 266, 274, 176, 4, 184, 356, + 94, 86, 266, 274, 175, 5, 185, 355, 95, 85, 265, 275, 175, 5, 185, 355, 95, 85, 265, 275, + 175, 5, 185, 355, 95, 85, 265, 275, 175, 5, 185, 355, 95, 85, 265, 275, 174, 6, 186, 354, + 96, 84, 264, 276, 174, 6, 186, 354, 96, 84, 264, 276, 174, 6, 186, 354, 96, 84, 264, 276, + 174, 6, 186, 354, 96, 84, 264, 276, 174, 6, 186, 354, 96, 84, 264, 276, 173, 7, 187, 353, + 97, 83, 263, 277, 173, 7, 187, 353, 97, 83, 263, 277, 173, 7, 187, 353, 97, 83, 263, 277, + 173, 7, 187, 353, 97, 83, 263, 277, 172, 8, 188, 352, 98, 82, 262, 278, 172, 8, 188, 352, + 98, 82, 262, 278, 172, 8, 188, 352, 98, 82, 262, 278, 172, 8, 188, 352, 98, 82, 262, 278, + 172, 8, 188, 352, 98, 82, 262, 278, 171, 9, 189, 351, 99, 81, 261, 279, 171, 9, 189, 351, + 99, 81, 261, 279, 171, 9, 189, 351, 99, 81, 261, 279, 171, 9, 189, 351, 99, 81, 261, 279, + 171, 9, 189, 351, 99, 81, 261, 279, 170, 10, 190, 350, 100, 80, 260, 280, 170, 10, 190, 350, + 100, 80, 260, 280, 170, 10, 190, 350, 100, 80, 260, 280, 170, 10, 190, 350, 100, 80, 260, 280, + 169, 11, 191, 349, 101, 79, 259, 281, 169, 11, 191, 349, 101, 79, 259, 281, 169, 11, 191, 349, + 101, 79, 259, 281, 169, 11, 191, 349, 101, 79, 259, 281, 169, 11, 191, 349, 101, 79, 259, 281, + 168, 12, 192, 348, 102, 78, 258, 282, 168, 12, 192, 348, 102, 78, 258, 282, 168, 12, 192, 348, + 102, 78, 258, 282, 168, 12, 192, 348, 102, 78, 258, 282, 168, 12, 192, 348, 102, 78, 258, 282, + 167, 13, 193, 347, 103, 77, 257, 283, 167, 13, 193, 347, 103, 77, 257, 283, 167, 13, 193, 347, + 103, 77, 257, 283, 167, 13, 193, 347, 103, 77, 257, 283, 166, 14, 194, 346, 104, 76, 256, 284, + 166, 14, 194, 346, 104, 76, 256, 284, 166, 14, 194, 346, 104, 76, 256, 284, 166, 14, 194, 346, + 104, 76, 256, 284, 166, 14, 194, 346, 104, 76, 256, 284, 165, 15, 195, 345, 105, 75, 255, 285, + 165, 15, 195, 345, 105, 75, 255, 285, 165, 15, 195, 345, 105, 75, 255, 285, 165, 15, 195, 345, + 105, 75, 255, 285, 165, 15, 195, 345, 105, 75, 255, 285, 164, 16, 196, 344, 106, 74, 254, 286, + 164, 16, 196, 344, 106, 74, 254, 286, 164, 16, 196, 344, 106, 74, 254, 286, 164, 16, 196, 344, + 106, 74, 254, 286, 164, 16, 196, 344, 106, 74, 254, 286, 163, 17, 197, 343, 107, 73, 253, 287, + 163, 17, 197, 343, 107, 73, 253, 287, 163, 17, 197, 343, 107, 73, 253, 287, 163, 17, 197, 343, + 107, 73, 253, 287, 163, 17, 197, 343, 107, 73, 253, 287, 162, 18, 198, 342, 108, 72, 252, 288, + 162, 18, 198, 342, 108, 72, 252, 288, 162, 18, 198, 342, 108, 72, 252, 288, 162, 18, 198, 342, + 108, 72, 252, 288, 162, 18, 198, 342, 108, 72, 252, 288, 161, 19, 199, 341, 109, 71, 251, 289, + 161, 19, 199, 341, 109, 71, 251, 289, 161, 19, 199, 341, 109, 71, 251, 289, 161, 19, 199, 341, + 109, 71, 251, 289, 161, 19, 199, 341, 109, 71, 251, 289, 160, 20, 200, 340, 110, 70, 250, 290, + 160, 20, 200, 340, 110, 70, 250, 290, 160, 20, 200, 340, 110, 70, 250, 290, 160, 20, 200, 340, + 110, 70, 250, 290, 160, 20, 200, 340, 110, 70, 250, 290, 159, 21, 201, 339, 111, 69, 249, 291, + 159, 21, 201, 339, 111, 69, 249, 291, 159, 21, 201, 339, 111, 69, 249, 291, 159, 21, 201, 339, + 111, 69, 249, 291, 159, 21, 201, 339, 111, 69, 249, 291, 158, 22, 202, 338, 112, 68, 248, 292, + 158, 22, 202, 338, 112, 68, 248, 292, 158, 22, 202, 338, 112, 68, 248, 292, 158, 22, 202, 338, + 112, 68, 248, 292, 158, 22, 202, 338, 112, 68, 248, 292, 157, 23, 203, 337, 113, 67, 247, 293, + 157, 23, 203, 337, 113, 67, 247, 293, 157, 23, 203, 337, 113, 67, 247, 293, 157, 23, 203, 337, + 113, 67, 247, 293, 157, 23, 203, 337, 113, 67, 247, 293, 157, 23, 203, 337, 113, 67, 247, 293, + 156, 24, 204, 336, 114, 66, 246, 294, 156, 24, 204, 336, 114, 66, 246, 294, 156, 24, 204, 336, + 114, 66, 246, 294, 156, 24, 204, 336, 114, 66, 246, 294, 156, 24, 204, 336, 114, 66, 246, 294, + 155, 25, 205, 335, 115, 65, 245, 295, 155, 25, 205, 335, 115, 65, 245, 295, 155, 25, 205, 335, + 115, 65, 245, 295, 155, 25, 205, 335, 115, 65, 245, 295, 155, 25, 205, 335, 115, 65, 245, 295, + 154, 26, 206, 334, 116, 64, 244, 296, 154, 26, 206, 334, 116, 64, 244, 296, 154, 26, 206, 334, + 116, 64, 244, 296, 154, 26, 206, 334, 116, 64, 244, 296, 154, 26, 206, 334, 116, 64, 244, 296, + 154, 26, 206, 334, 116, 64, 244, 296, 153, 27, 207, 333, 117, 63, 243, 297, 153, 27, 207, 333, + 117, 63, 243, 297, 153, 27, 207, 333, 117, 63, 243, 297, 153, 27, 207, 333, 117, 63, 243, 297, + 153, 27, 207, 333, 117, 63, 243, 297, 153, 27, 207, 333, 117, 63, 243, 297, 152, 28, 208, 332, + 118, 62, 242, 298, 152, 28, 208, 332, 118, 62, 242, 298, 152, 28, 208, 332, 118, 62, 242, 298, + 152, 28, 208, 332, 118, 62, 242, 298, 152, 28, 208, 332, 118, 62, 242, 298, 151, 29, 209, 331, + 119, 61, 241, 299, 151, 29, 209, 331, 119, 61, 241, 299, 151, 29, 209, 331, 119, 61, 241, 299, + 151, 29, 209, 331, 119, 61, 241, 299, 151, 29, 209, 331, 119, 61, 241, 299, 151, 29, 209, 331, + 119, 61, 241, 299, 150, 30, 210, 330, 120, 60, 240, 300, 150, 30, 210, 330, 120, 60, 240, 300, + 150, 30, 210, 330, 120, 60, 240, 300, 150, 30, 210, 330, 120, 60, 240, 300, 150, 30, 210, 330, + 120, 60, 240, 300, 150, 30, 210, 330, 120, 60, 240, 300, 149, 31, 211, 329, 121, 59, 239, 301, + 149, 31, 211, 329, 121, 59, 239, 301, 149, 31, 211, 329, 121, 59, 239, 301, 149, 31, 211, 329, + 121, 59, 239, 301, 149, 31, 211, 329, 121, 59, 239, 301, 149, 31, 211, 329, 121, 59, 239, 301, + 148, 32, 212, 328, 122, 58, 238, 302, 148, 32, 212, 328, 122, 58, 238, 302, 148, 32, 212, 328, + 122, 58, 238, 302, 148, 32, 212, 328, 122, 58, 238, 302, 148, 32, 212, 328, 122, 58, 238, 302, + 148, 32, 212, 328, 122, 58, 238, 302, 148, 32, 212, 328, 122, 58, 238, 302, 147, 33, 213, 327, + 123, 57, 237, 303, 147, 33, 213, 327, 123, 57, 237, 303, 147, 33, 213, 327, 123, 57, 237, 303, + 147, 33, 213, 327, 123, 57, 237, 303, 147, 33, 213, 327, 123, 57, 237, 303, 147, 33, 213, 327, + 123, 57, 237, 303, 146, 34, 214, 326, 124, 56, 236, 304, 146, 34, 214, 326, 124, 56, 236, 304, + 146, 34, 214, 326, 124, 56, 236, 304, 146, 34, 214, 326, 124, 56, 236, 304, 146, 34, 214, 326, + 124, 56, 236, 304, 146, 34, 214, 326, 124, 56, 236, 304, 146, 34, 214, 326, 124, 56, 236, 304, + 145, 35, 215, 325, 125, 55, 235, 305, 145, 35, 215, 325, 125, 55, 235, 305, 145, 35, 215, 325, + 125, 55, 235, 305, 145, 35, 215, 325, 125, 55, 235, 305, 145, 35, 215, 325, 125, 55, 235, 305, + 145, 35, 215, 325, 125, 55, 235, 305, 145, 35, 215, 325, 125, 55, 235, 305, 144, 36, 216, 324, + 126, 54, 234, 306, 144, 36, 216, 324, 126, 54, 234, 306, 144, 36, 216, 324, 126, 54, 234, 306, + 144, 36, 216, 324, 126, 54, 234, 306, 144, 36, 216, 324, 126, 54, 234, 306, 144, 36, 216, 324, + 126, 54, 234, 306, 143, 37, 217, 323, 127, 53, 233, 307, 143, 37, 217, 323, 127, 53, 233, 307, + 143, 37, 217, 323, 127, 53, 233, 307, 143, 37, 217, 323, 127, 53, 233, 307, 143, 37, 217, 323, + 127, 53, 233, 307, 143, 37, 217, 323, 127, 53, 233, 307, 143, 37, 217, 323, 127, 53, 233, 307, + 143, 37, 217, 323, 127, 53, 233, 307, 142, 38, 218, 322, 128, 52, 232, 308, 142, 38, 218, 322, + 128, 52, 232, 308, 142, 38, 218, 322, 128, 52, 232, 308, 142, 38, 218, 322, 128, 52, 232, 308, + 142, 38, 218, 322, 128, 52, 232, 308, 142, 38, 218, 322, 128, 52, 232, 308, 142, 38, 218, 322, + 128, 52, 232, 308, 141, 39, 219, 321, 129, 51, 231, 309, 141, 39, 219, 321, 129, 51, 231, 309, + 141, 39, 219, 321, 129, 51, 231, 309, 141, 39, 219, 321, 129, 51, 231, 309, 141, 39, 219, 321, + 129, 51, 231, 309, 141, 39, 219, 321, 129, 51, 231, 309, 141, 39, 219, 321, 129, 51, 231, 309, + 140, 40, 220, 320, 130, 50, 230, 310, 140, 40, 220, 320, 130, 50, 230, 310, 140, 40, 220, 320, + 130, 50, 230, 310, 140, 40, 220, 320, 130, 50, 230, 310, 140, 40, 220, 320, 130, 50, 230, 310, + 140, 40, 220, 320, 130, 50, 230, 310, 140, 40, 220, 320, 130, 50, 230, 310, 140, 40, 220, 320, + 130, 50, 230, 310, 139, 41, 221, 319, 131, 49, 229, 311, 139, 41, 221, 319, 131, 49, 229, 311, + 139, 41, 221, 319, 131, 49, 229, 311, 139, 41, 221, 319, 131, 49, 229, 311, 139, 41, 221, 319, + 131, 49, 229, 311, 139, 41, 221, 319, 131, 49, 229, 311, 139, 41, 221, 319, 131, 49, 229, 311, + 139, 41, 221, 319, 131, 49, 229, 311, 138, 42, 222, 318, 132, 48, 228, 312, 138, 42, 222, 318, + 132, 48, 228, 312, 138, 42, 222, 318, 132, 48, 228, 312, 138, 42, 222, 318, 132, 48, 228, 312, + 138, 42, 222, 318, 132, 48, 228, 312, 138, 42, 222, 318, 132, 48, 228, 312, 138, 42, 222, 318, + 132, 48, 228, 312, 138, 42, 222, 318, 132, 48, 228, 312, 137, 43, 223, 317, 133, 47, 227, 313, + 137, 43, 223, 317, 133, 47, 227, 313, 137, 43, 223, 317, 133, 47, 227, 313, 137, 43, 223, 317, + 133, 47, 227, 313, 137, 43, 223, 317, 133, 47, 227, 313, 137, 43, 223, 317, 133, 47, 227, 313, + 137, 43, 223, 317, 133, 47, 227, 313, 137, 43, 223, 317, 133, 47, 227, 313, 137, 43, 223, 317, + 133, 47, 227, 313, 136, 44, 224, 316, 134, 46, 226, 314, 136, 44, 224, 316, 134, 46, 226, 314, + 136, 44, 224, 316, 134, 46, 226, 314, 136, 44, 224, 316, 134, 46, 226, 314, 136, 44, 224, 316, + 134, 46, 226, 314, 136, 44, 224, 316, 134, 46, 226, 314, 136, 44, 224, 316, 134, 46, 226, 314, + 136, 44, 224, 316, 134, 46, 226, 314, 135, 45, 225, 315, 135, 45, 225, 315, +}; + +void InitSound() {} + +} // namespace jak3 diff --git a/game/overlord/jak3/ssound.h b/game/overlord/jak3/ssound.h new file mode 100644 index 00000000000..0fc21dad01b --- /dev/null +++ b/game/overlord/jak3/ssound.h @@ -0,0 +1,39 @@ +#pragma once + +#include "common/common_types.h" + +#include "game/overlord/jak3/overlord.h" + +namespace jak3 { + +struct Curve { + s32 p1; + s32 p2; + s32 p3; + s32 p4; +}; + +struct SoundPlayParams { + u16 mask; + s16 pitch_mod; + s16 bend; + s16 fo_min; + s16 fo_max; + s8 fo_curve; + s8 priority; + s32 volume; + Vec3 trans; + u8 group; + u8 reg[3]; +}; + +struct SoundInfo { + char name[16]; + s32 id; + u32 sound_handle; + s32 auto_volume; + s32 auto_time; + SoundPlayParams params; +}; + +} // namespace jak3 diff --git a/game/overlord/jak3/start.cpp b/game/overlord/jak3/start.cpp new file mode 100644 index 00000000000..4b08ce29a69 --- /dev/null +++ b/game/overlord/jak3/start.cpp @@ -0,0 +1,124 @@ +#include +#include + +#include "iso.h" +#include "overlord.h" +#include "ramdisk.h" +#include "sbank.h" + +#include "game/overlord/jak3/srpc.h" +#include "game/sce/iop.h" + +namespace jak3 { +using namespace iop; + +int g_nServerThreadID; +int g_nPlayerThreadID; +int g_nLoaderThreadID; + +int start_overlord(int argc, const char* const* argp) { + ThreadParam thp; + + if (argc < 0) { + Panic(); + } + + if (sceSifCheckInit() == 0) { + sceSifInit(); + } + sceSifInitRpc(0); + printf("======== overlrd2.irx startup ========\n"); + // printf(" mem size: %lu\n", QueryMemSize()); + // printf("total mem free: %lu\n", QueryTotalFreeMemSize()); + // printf(" max mem free: %lu\n", QueryMaxFreeMemSize()); + // printf(" used: %lu\n", QueryMemSize() - QueryTotalFreeMemSize()); + // printf(" start() addr: 0x%08x\n", start_overlord); + //__do_global_ctors(); + InitBanks(); + InitSound(); + VBlank_Initialize(); + + thp.attr = TH_C; + thp.option = 0; + thp.entry = Thread_Server; + thp.stackSize = 0x800; + thp.initPriority = 59; + g_nServerThreadID = CreateThread(&thp); + if (g_nServerThreadID < 0) { + Panic(); + return 1; + } + + thp.attr = TH_C; + thp.option = 0; + thp.entry = Thread_Player; + thp.stackSize = 0xb00; + thp.initPriority = 54; + g_nPlayerThreadID = CreateThread(&thp); + if (g_nPlayerThreadID < 0) { + Panic(); + return 1; + } + + thp.attr = TH_C; + thp.option = 0; + thp.entry = Thread_Loader; + thp.stackSize = 0x900; + thp.initPriority = 58; + g_nLoaderThreadID = CreateThread(&thp); + if (g_nPlayerThreadID < 0) { + Panic(); + return 1; + } + + // CDvdDriver::Initialize(&g_DvdDriver); + InitISOFS(argp[1], argp[2]); + + StartThread(g_nServerThreadID, 0); + StartThread(g_nPlayerThreadID, 0); + StartThread(g_nLoaderThreadID, 0); + + printf("======== overlrd2.irx post-startup ========\n"); + // printf(" mem size: %lu\n", QueryMemSize()); + // printf("total mem free: %lu\n", QueryTotalFreeMemSize()); + // printf(" max mem free: %lu\n", QueryMaxFreeMemSize()); + // printf(" used: %lu\n", QueryMemSize() - QueryTotalFreeMemSize()); + + return 0; +} + +static s32 gargc; +static const char* const* gargv; +static bool* init_complete; + +static u32 call_start() { + start_overlord(gargc, gargv); + *init_complete = true; + + while (true) { + SleepThread(); + } + return 0; +} + +int start_overlord_wrapper(int argc, const char* const* argv, bool* signal) { + ThreadParam param = {}; + + gargc = argc; + gargv = argv; + init_complete = signal; + + param.attr = TH_C; + param.initPriority = 0; + param.stackSize = 0x800; + param.option = 0; + strcpy(param.name, "start"); // added for debug + param.entry = call_start; + + auto start_thread = CreateThread(¶m); + StartThread(start_thread, 0); + + return 0; +} + +} // namespace jak3 diff --git a/game/overlord/jak3/stream.cpp b/game/overlord/jak3/stream.cpp new file mode 100644 index 00000000000..ca5e30d5d0b --- /dev/null +++ b/game/overlord/jak3/stream.cpp @@ -0,0 +1,54 @@ +#include "common/common_types.h" +#include "common/log/log.h" + +#include "game/common/str_rpc_types.h" +#include "game/sce/iop.h" + +namespace jak3 { +using namespace iop; + +static RPC_Str_Cmd_Jak2 sRPCBuf[1]; +static RPC_Str_Cmd_Jak2 sRPCBuf2[4]; + +static void* RPC_STR(unsigned int /*fno*/, void* _cmd, int /*y*/); +static void* RPC_PLAY(unsigned int /*fno*/, void* _cmd, int size); + +u32 STRThread() { + sceSifQueueData dq; + sceSifServeData serve; + + CpuDisableIntr(); + sceSifInitRpc(0); + sceSifSetRpcQueue(&dq, GetThreadId()); + sceSifRegisterRpc(&serve, 0xfab4, RPC_STR, sRPCBuf, sizeof(sRPCBuf), nullptr, nullptr, &dq); + CpuEnableIntr(); + sceSifRpcLoop(&dq); + + return 0; +} + +u32 PLAYThread() { + sceSifQueueData dq; + sceSifServeData serve; + + CpuDisableIntr(); + sceSifInitRpc(0); + sceSifSetRpcQueue(&dq, GetThreadId()); + sceSifRegisterRpc(&serve, 0xfab5, RPC_PLAY, sRPCBuf2, sizeof(sRPCBuf2), nullptr, nullptr, &dq); + CpuEnableIntr(); + sceSifRpcLoop(&dq); + + return 0; +} + +static void* RPC_STR(unsigned int /*fno*/, void* _cmd, int /*y*/) { + lg::error("RPC_STR UNIMPLEMENTED"); + return nullptr; +} + +static void* RPC_PLAY(unsigned int /*fno*/, void* _cmd, int size) { + lg::error("RPC_PLAY UNIMPLEMENTED"); + return nullptr; +} + +} // namespace jak3 diff --git a/game/overlord/jak3/stream.h b/game/overlord/jak3/stream.h new file mode 100644 index 00000000000..6938dc80048 --- /dev/null +++ b/game/overlord/jak3/stream.h @@ -0,0 +1,11 @@ +#ifndef STREAM_H_ +#define STREAM_H_ + +#include "common/common_types.h" + +namespace jak3 { +u32 STRThread(); +u32 PLAYThread(); +} // namespace jak3 + +#endif // STREAM_H_ diff --git a/game/overlord/jak3/vblank_handler.cpp b/game/overlord/jak3/vblank_handler.cpp new file mode 100644 index 00000000000..b2f6808b717 --- /dev/null +++ b/game/overlord/jak3/vblank_handler.cpp @@ -0,0 +1,9 @@ +#include "overlord.h" + +namespace jak3 { + +int VBlank_Initialize() { + return 0; +} + +} // namespace jak3 diff --git a/game/runtime.cpp b/game/runtime.cpp index b39317b604b..b1a2347cd63 100644 --- a/game/runtime.cpp +++ b/game/runtime.cpp @@ -4,6 +4,7 @@ */ #include "common/common_types.h" + #ifdef OS_POSIX #include @@ -78,6 +79,7 @@ #include "game/overlord/jak2/stream.h" #include "game/overlord/jak2/streamlist.h" #include "game/overlord/jak2/vag.h" +#include "game/overlord/jak3/overlord.h" #include "game/system/Deci2Server.h" #include "game/system/iop_thread.h" #include "sce/deci2.h" @@ -323,9 +325,11 @@ void iop_runner(SystemThreadInterface& iface, GameVersion version) { jak1::start_overlord_wrapper(iop.overlord_argc, iop.overlord_argv, &complete); break; case GameVersion::Jak2: - case GameVersion::Jak3: // TODO: jak3 using jak2's overlord. jak2::start_overlord_wrapper(iop.overlord_argc, iop.overlord_argv, &complete); break; + case GameVersion::Jak3: + jak3::start_overlord_wrapper(iop.overlord_argc, iop.overlord_argv, &complete); + break; default: ASSERT_NOT_REACHED(); } diff --git a/game/sce/iop.cpp b/game/sce/iop.cpp index 2784c9fa424..b40bdf3cf96 100644 --- a/game/sce/iop.cpp +++ b/game/sce/iop.cpp @@ -195,6 +195,10 @@ s32 SendMbx(s32 mbxid, void* sendmsg) { return iop->kernel.SendMbx(mbxid, sendmsg); } +s32 ReceiveMbx(MsgPacket** recvmsg, int mbxid) { + return iop->kernel.ReceiveMbx((void**)recvmsg, mbxid); +} + s32 PollMbx(MsgPacket** recvmsg, int mbxid) { return iop->kernel.PollMbx((void**)recvmsg, mbxid); } @@ -247,4 +251,14 @@ s32 RegisterVblankHandler(int edge, int priority, int (*handler)(void*), void* / return iop->kernel.RegisterVblankHandler(handler); } +s32 CpuSuspendIntr(int* old_state) { + (void)old_state; + return KE_OK; +} + +s32 CpuResumeIntr(int old_state) { + (void)old_state; + return KE_OK; +} + } // namespace iop diff --git a/game/sce/iop.h b/game/sce/iop.h index 50a06088c1b..306bc340893 100644 --- a/game/sce/iop.h +++ b/game/sce/iop.h @@ -30,6 +30,12 @@ #define SA_THFIFO 0 #define SA_THPRI 1 +// Message box attributes +#define MBA_THFIFO 0x000 +#define MBA_THPRI 0x001 +#define MBA_MSFIFO 0x000 +#define MBA_MSPRI 0x004 + class IOP; namespace iop { @@ -134,6 +140,7 @@ int sceCdDiskReady(int mode); u32 sceSifSetDma(sceSifDmaData* sdd, int len); s32 SendMbx(int mbxid, void* sendmsg); +s32 ReceiveMbx(MsgPacket** recvmsg, int mbxid); s32 PollMbx(MsgPacket** recvmsg, int mbxid); s32 PeekMbx(s32 mbx); s32 CreateMbx(MbxParam* param); @@ -152,6 +159,9 @@ void FlushDcache(); u32 sceSifCheckInit(); void sceSifInit(); +s32 CpuSuspendIntr(int* old_state); +s32 CpuResumeIntr(int old_state); + void LIBRARY_INIT(); void LIBRARY_register(::IOP* i); void LIBRARY_kill(); diff --git a/game/system/IOP_Kernel.cpp b/game/system/IOP_Kernel.cpp index 10ce6e88fa9..b3dcfca8036 100644 --- a/game/system/IOP_Kernel.cpp +++ b/game/system/IOP_Kernel.cpp @@ -103,6 +103,12 @@ void IOP_Kernel::iWakeupThread(s32 id) { wakeup_queue.push(id); } +s32 IOP_Kernel::CreateSema(s32 attr, s32 option, s32 init_count, s32 max_count) { + s32 id = semas.size(); + semas.emplace_back((Semaphore::attribute)attr, option, init_count, max_count); + return id; +} + s32 IOP_Kernel::WaitSema(s32 id) { auto& sema = semas.at(id); if (sema.count > 0) { @@ -159,6 +165,81 @@ s32 IOP_Kernel::PollSema(s32 id) { return KE_SEMA_ZERO; } +/*! + * Create a message box + */ +s32 IOP_Kernel::CreateMbx() { + s32 id = mbxs.size(); + mbxs.emplace_back(); + return id; +} + +s32 IOP_Kernel::ReceiveMbx(void** msg, s32 mbx) { + ASSERT(mbx < (s32)mbxs.size()); + s32 gotSomething = mbxs[mbx].messages.empty() ? 0 : 1; + if (!gotSomething) { + /* Was empty, wait until there's messages */ + mbxs[mbx].wait_list.push_back(_currentThread); + _currentThread->state = IopThread::State::Wait; + _currentThread->waitType = IopThread::Wait::MsgBox; + leaveThread(); + } + + ASSERT(mbxs[mbx].messages.empty() == false); + + void* thing = mbxs[mbx].messages.front(); + if (msg) { + *msg = thing; + } + + mbxs[mbx].messages.pop(); + + return KE_OK; +} + +/*! + * Set msg to thing if its there and pop it. + * Returns if it got something. + */ +s32 IOP_Kernel::PollMbx(void** msg, s32 mbx) { + ASSERT(mbx < (s32)mbxs.size()); + s32 gotSomething = mbxs[mbx].messages.empty() ? 0 : 1; + if (gotSomething) { + void* thing = mbxs[mbx].messages.front(); + + if (msg) { + *msg = thing; + } + + mbxs[mbx].messages.pop(); + } + + return gotSomething ? KE_OK : KE_MBOX_NOMSG; +} + +s32 IOP_Kernel::PeekMbx(s32 mbx) { + return !mbxs[mbx].messages.empty(); +} + +/*! + * Push something into a mbx + */ +s32 IOP_Kernel::SendMbx(s32 mbx, void* value) { + ASSERT(mbx < (s32)mbxs.size()); + mbxs[mbx].messages.push(value); + + IopThread* to_run = nullptr; + if (!mbxs[mbx].wait_list.empty()) { + to_run = mbxs[mbx].wait_list.front(); + mbxs[mbx].wait_list.pop_front(); + + to_run->waitType = IopThread::Wait::None; + to_run->state = IopThread::State::Ready; + } + + return KE_OK; +} + /*! * Return to kernel from a thread, not to be called from the kernel thread. */ diff --git a/game/system/IOP_Kernel.h b/game/system/IOP_Kernel.h index b8a5b513895..1ad01a66e6f 100644 --- a/game/system/IOP_Kernel.h +++ b/game/system/IOP_Kernel.h @@ -57,6 +57,7 @@ struct IopThread { None, Semaphore, Delay, + MsgBox, }; IopThread(std::string n, void (*f)(), s32 ID, u32 priority) @@ -91,6 +92,11 @@ struct Semaphore { std::list wait_list; }; +struct MsgBox { + std::queue messages; + std::list wait_list; +}; + class IOP_Kernel { public: IOP_Kernel() { @@ -122,52 +128,13 @@ class IOP_Kernel { return _currentThread->thID; } - /*! - * Create a message box - */ - s32 CreateMbx() { - s32 id = mbxs.size(); - mbxs.emplace_back(); - return id; - } - - /*! - * Set msg to thing if its there and pop it. - * Returns if it got something. - */ - s32 PollMbx(void** msg, s32 mbx) { - ASSERT(mbx < (s32)mbxs.size()); - s32 gotSomething = mbxs[mbx].empty() ? 0 : 1; - if (gotSomething) { - void* thing = mbxs[mbx].front(); - - if (msg) { - *msg = thing; - } - - mbxs[mbx].pop(); - } - - return gotSomething ? KE_OK : KE_MBOX_NOMSG; - } - - s32 PeekMbx(s32 mbx) { return !mbxs[mbx].empty(); } - - /*! - * Push something into a mbx - */ - s32 SendMbx(s32 mbx, void* value) { - ASSERT(mbx < (s32)mbxs.size()); - mbxs[mbx].push(value); - return 0; - } - - s32 CreateSema(s32 attr, s32 option, s32 init_count, s32 max_count) { - s32 id = semas.size(); - semas.emplace_back((Semaphore::attribute)attr, option, init_count, max_count); - return id; - } + s32 CreateMbx(); + s32 ReceiveMbx(void** msg, s32 mbx); + s32 PollMbx(void** msg, s32 mbx); + s32 PeekMbx(s32 mbx); + s32 SendMbx(s32 mbx, void* value); + s32 CreateSema(s32 attr, s32 option, s32 init_count, s32 max_count); s32 WaitSema(s32 id); s32 SignalSema(s32 id); s32 PollSema(s32 id); @@ -205,7 +172,7 @@ class IOP_Kernel { s32 _nextThID = 0; IopThread* _currentThread = nullptr; std::vector threads; - std::vector> mbxs; + std::vector mbxs; std::vector sif_records; std::vector semas; std::queue wakeup_queue;