summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/arm/dyncom/arm_dyncom.cpp7
-rw-r--r--src/core/arm/interpreter/arminit.cpp40
-rw-r--r--src/core/arm/skyeye_common/armdefs.h7
-rw-r--r--src/core/arm/skyeye_common/armemu.h8
-rw-r--r--src/core/hle/service/gsp_gpu.cpp97
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"},