diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/arm/dyncom/arm_dyncom.cpp | 7 | ||||
-rw-r--r-- | src/core/arm/interpreter/arminit.cpp | 40 | ||||
-rw-r--r-- | src/core/arm/skyeye_common/armdefs.h | 7 | ||||
-rw-r--r-- | src/core/arm/skyeye_common/armemu.h | 8 | ||||
-rw-r--r-- | src/core/hle/service/gsp_gpu.cpp | 97 |
5 files changed, 92 insertions, 67 deletions
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp index 1977112dd..c4af85242 100644 --- a/src/core/arm/dyncom/arm_dyncom.cpp +++ b/src/core/arm/dyncom/arm_dyncom.cpp @@ -18,10 +18,7 @@ const static cpu_config_t s_arm11_cpu_info = { ARM_DynCom::ARM_DynCom() { state = std::unique_ptr<ARMul_State>(new ARMul_State); - ARMul_EmulateInit(); - memset(state.get(), 0, sizeof(ARMul_State)); - - ARMul_NewState((ARMul_State*)state.get()); + ARMul_NewState(state.get()); state->abort_model = ABORT_BASE_RESTORED; state->cpu = (cpu_config_t*)&s_arm11_cpu_info; @@ -41,8 +38,6 @@ ARM_DynCom::ARM_DynCom() { state->NirqSig = HIGH; VFPInit(state.get()); // Initialize the VFP - - ARMul_EmulateInit(); } ARM_DynCom::~ARM_DynCom() { diff --git a/src/core/arm/interpreter/arminit.cpp b/src/core/arm/interpreter/arminit.cpp index e7545728e..0c0ce6c91 100644 --- a/src/core/arm/interpreter/arminit.cpp +++ b/src/core/arm/interpreter/arminit.cpp @@ -19,46 +19,6 @@ #include "core/arm/skyeye_common/armemu.h" /***************************************************************************\ -* Definitions for the emulator architecture * -\***************************************************************************/ - -void ARMul_EmulateInit(); -ARMul_State* ARMul_NewState(ARMul_State* state); -void ARMul_Reset (ARMul_State* state); - -unsigned ARMul_MultTable[32] = { - 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, - 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16 -}; -ARMword ARMul_ImmedTable[4096]; // immediate DP LHS values -char ARMul_BitList[256]; // number of bits in a byte table - -/***************************************************************************\ -* Call this routine once to set up the emulator's tables. * -\***************************************************************************/ -void ARMul_EmulateInit() -{ - unsigned int i, j; - - // the values of 12 bit dp rhs's - for (i = 0; i < 4096; i++) { - ARMul_ImmedTable[i] = ROTATER (i & 0xffL, (i >> 7L) & 0x1eL); - } - - // how many bits in LSM - for (i = 0; i < 256; ARMul_BitList[i++] = 0); - for (j = 1; j < 256; j <<= 1) - for (i = 0; i < 256; i++) - if ((i & j) > 0) - ARMul_BitList[i]++; - - // you always need 4 times these values - for (i = 0; i < 256; i++) - ARMul_BitList[i] *= 4; - -} - -/***************************************************************************\ * Returns a new instantiation of the ARMulator's state * \***************************************************************************/ ARMul_State* ARMul_NewState(ARMul_State* state) diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h index 012c43c61..02f54f385 100644 --- a/src/core/arm/skyeye_common/armdefs.h +++ b/src/core/arm/skyeye_common/armdefs.h @@ -294,14 +294,7 @@ enum { /***************************************************************************\ * Definitons of things in the emulator * \***************************************************************************/ -#ifdef __cplusplus -extern "C" { -#endif -extern void ARMul_EmulateInit(); extern void ARMul_Reset(ARMul_State* state); -#ifdef __cplusplus - } -#endif extern ARMul_State* ARMul_NewState(ARMul_State* state); /***************************************************************************\ diff --git a/src/core/arm/skyeye_common/armemu.h b/src/core/arm/skyeye_common/armemu.h index 5d4c06837..2467f4319 100644 --- a/src/core/arm/skyeye_common/armemu.h +++ b/src/core/arm/skyeye_common/armemu.h @@ -95,14 +95,6 @@ enum { #define FLUSHPIPE state->NextInstr |= PRIMEPIPE -// Macro to rotate n right by b bits. -#define ROTATER(n, b) (((n) >> (b)) | ((n) << (32 - (b)))) - -// Stuff that is shared across modes. -extern unsigned ARMul_MultTable[]; // Number of I cycles for a mult. -extern ARMword ARMul_ImmedTable[]; // Immediate DP LHS values. -extern char ARMul_BitList[]; // Number of bits in a byte table. - // Coprocessor support functions. extern void ARMul_CoProInit(ARMul_State*); extern void ARMul_CoProExit(ARMul_State*); diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 4c3ac845b..dcc1b6942 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -48,20 +48,42 @@ static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) { return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr)); } -static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { +/** + * Checks if the parameters in a register write call are valid and logs in the case that + * they are not + * @param base_address The first address in the sequence of registers that will be written + * @param size_in_bytes The number of registers that will be written + * @return true if the parameters are valid, false otherwise + */ +static bool CheckWriteParameters(u32 base_address, u32 size_in_bytes) { // TODO: Return proper error codes if (base_address + size_in_bytes >= 0x420000) { LOG_ERROR(Service_GSP, "Write address out of range! (address=0x%08x, size=0x%08x)", base_address, size_in_bytes); - return; + return false; } // size should be word-aligned if ((size_in_bytes % 4) != 0) { LOG_ERROR(Service_GSP, "Invalid size 0x%08x", size_in_bytes); - return; + return false; } + return true; +} + +/** + * Writes sequential GSP GPU hardware registers using an array of source data + * + * @param base_address The address of the first register in the sequence + * @param size_in_bytes The number of registers to update (size of data) + * @param data A pointer to the source data + */ +static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { + // TODO: Return proper error codes + if (!CheckWriteParameters(base_address, size_in_bytes)) + return; + while (size_in_bytes > 0) { GPU::Write<u32>(base_address + 0x1EB00000, *data); @@ -71,17 +93,80 @@ static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { } } -/// Write a GSP GPU hardware register +/** + * GSP_GPU::WriteHWRegs service function + * + * Writes sequential GSP GPU hardware registers + * + * Inputs: + * 1 : address of first GPU register + * 2 : number of registers to write sequentially + * 4 : pointer to source data array + */ static void WriteHWRegs(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 reg_addr = cmd_buff[1]; u32 size = cmd_buff[2]; - u32* src = (u32*)Memory::GetPointer(cmd_buff[0x4]); + u32* src = (u32*)Memory::GetPointer(cmd_buff[4]); WriteHWRegs(reg_addr, size, src); } +/** + * Updates sequential GSP GPU hardware registers using parallel arrays of source data and masks. + * For each register, the value is updated only where the mask is high + * + * @param base_address The address of the first register in the sequence + * @param size_in_bytes The number of registers to update (size of data) + * @param data A pointer to the source data to use for updates + * @param masks A pointer to the masks + */ +static void WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, const u32* data, const u32* masks) { + // TODO: Return proper error codes + if (!CheckWriteParameters(base_address, size_in_bytes)) + return; + + while (size_in_bytes > 0) { + const u32 reg_address = base_address + 0x1EB00000; + + u32 reg_value; + GPU::Read<u32>(reg_value, reg_address); + + // Update the current value of the register only for set mask bits + reg_value = (reg_value & ~*masks) | (*data | *masks); + + GPU::Write<u32>(reg_address, reg_value); + + size_in_bytes -= 4; + ++data; + ++masks; + base_address += 4; + } +} + +/** + * GSP_GPU::WriteHWRegsWithMask service function + * + * Updates sequential GSP GPU hardware registers using masks + * + * Inputs: + * 1 : address of first GPU register + * 2 : number of registers to update sequentially + * 4 : pointer to source data array + * 6 : pointer to mask array + */ +static void WriteHWRegsWithMask(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 reg_addr = cmd_buff[1]; + u32 size = cmd_buff[2]; + + u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]); + u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]); + + WriteHWRegsWithMask(reg_addr, size, src_data, mask_data); +} + /// Read a GSP GPU hardware register static void ReadHWRegs(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); @@ -350,7 +435,7 @@ static void TriggerCmdReqQueue(Service::Interface* self) { const Interface::FunctionInfo FunctionTable[] = { {0x00010082, WriteHWRegs, "WriteHWRegs"}, - {0x00020084, nullptr, "WriteHWRegsWithMask"}, + {0x00020084, WriteHWRegsWithMask, "WriteHWRegsWithMask"}, {0x00030082, nullptr, "WriteHWRegRepeat"}, {0x00040080, ReadHWRegs, "ReadHWRegs"}, {0x00050200, SetBufferSwap, "SetBufferSwap"}, |