diff options
| -rw-r--r-- | src/core/arm/dyncom/arm_dyncom.cpp | 4 | ||||
| -rw-r--r-- | src/core/arm/interpreter/arminit.cpp | 31 | ||||
| -rw-r--r-- | src/core/arm/skyeye_common/armdefs.h | 48 | ||||
| -rw-r--r-- | src/core/arm/skyeye_common/armemu.h | 28 | ||||
| -rw-r--r-- | src/core/hle/service/gsp_gpu.cpp | 97 |
5 files changed, 134 insertions, 74 deletions
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp index 68fddc94f..1977112dd 100644 --- a/src/core/arm/dyncom/arm_dyncom.cpp +++ b/src/core/arm/dyncom/arm_dyncom.cpp | |||
| @@ -23,7 +23,7 @@ ARM_DynCom::ARM_DynCom() { | |||
| 23 | 23 | ||
| 24 | ARMul_NewState((ARMul_State*)state.get()); | 24 | ARMul_NewState((ARMul_State*)state.get()); |
| 25 | 25 | ||
| 26 | state->abort_model = 0; | 26 | state->abort_model = ABORT_BASE_RESTORED; |
| 27 | state->cpu = (cpu_config_t*)&s_arm11_cpu_info; | 27 | state->cpu = (cpu_config_t*)&s_arm11_cpu_info; |
| 28 | state->bigendSig = LOW; | 28 | state->bigendSig = LOW; |
| 29 | 29 | ||
| @@ -34,7 +34,7 @@ ARM_DynCom::ARM_DynCom() { | |||
| 34 | ARMul_CoProInit(state.get()); | 34 | ARMul_CoProInit(state.get()); |
| 35 | ARMul_Reset(state.get()); | 35 | ARMul_Reset(state.get()); |
| 36 | state->NextInstr = RESUME; // NOTE: This will be overwritten by LoadContext | 36 | state->NextInstr = RESUME; // NOTE: This will be overwritten by LoadContext |
| 37 | state->Emulate = 3; | 37 | state->Emulate = RUN; |
| 38 | 38 | ||
| 39 | state->Reg[15] = 0x00000000; | 39 | state->Reg[15] = 0x00000000; |
| 40 | state->Reg[13] = 0x10000000; // Set stack pointer to the top of the stack | 40 | state->Reg[13] = 0x10000000; // Set stack pointer to the top of the stack |
diff --git a/src/core/arm/interpreter/arminit.cpp b/src/core/arm/interpreter/arminit.cpp index 7b502e240..e7545728e 100644 --- a/src/core/arm/interpreter/arminit.cpp +++ b/src/core/arm/interpreter/arminit.cpp | |||
| @@ -74,7 +74,7 @@ ARMul_State* ARMul_NewState(ARMul_State* state) | |||
| 74 | for (unsigned int i = 0; i < 7; i++) | 74 | for (unsigned int i = 0; i < 7; i++) |
| 75 | state->Spsr[i] = 0; | 75 | state->Spsr[i] = 0; |
| 76 | 76 | ||
| 77 | state->Mode = 0; | 77 | state->Mode = USER32MODE; |
| 78 | 78 | ||
| 79 | state->VectorCatch = 0; | 79 | state->VectorCatch = 0; |
| 80 | state->Aborted = false; | 80 | state->Aborted = false; |
| @@ -82,14 +82,6 @@ ARMul_State* ARMul_NewState(ARMul_State* state) | |||
| 82 | state->Inted = 3; | 82 | state->Inted = 3; |
| 83 | state->LastInted = 3; | 83 | state->LastInted = 3; |
| 84 | 84 | ||
| 85 | #ifdef ARM61 | ||
| 86 | state->prog32Sig = LOW; | ||
| 87 | state->data32Sig = LOW; | ||
| 88 | #else | ||
| 89 | state->prog32Sig = HIGH; | ||
| 90 | state->data32Sig = HIGH; | ||
| 91 | #endif | ||
| 92 | |||
| 93 | state->lateabtSig = HIGH; | 85 | state->lateabtSig = HIGH; |
| 94 | state->bigendSig = LOW; | 86 | state->bigendSig = LOW; |
| 95 | 87 | ||
| @@ -102,14 +94,6 @@ ARMul_State* ARMul_NewState(ARMul_State* state) | |||
| 102 | 94 | ||
| 103 | void ARMul_SelectProcessor(ARMul_State* state, unsigned properties) | 95 | void ARMul_SelectProcessor(ARMul_State* state, unsigned properties) |
| 104 | { | 96 | { |
| 105 | if (properties & ARM_Fix26_Prop) { | ||
| 106 | state->prog32Sig = LOW; | ||
| 107 | state->data32Sig = LOW; | ||
| 108 | } else { | ||
| 109 | state->prog32Sig = HIGH; | ||
| 110 | state->data32Sig = HIGH; | ||
| 111 | } | ||
| 112 | |||
| 113 | state->is_v4 = (properties & (ARM_v4_Prop | ARM_v5_Prop)) != 0; | 97 | state->is_v4 = (properties & (ARM_v4_Prop | ARM_v5_Prop)) != 0; |
| 114 | state->is_v5 = (properties & ARM_v5_Prop) != 0; | 98 | state->is_v5 = (properties & ARM_v5_Prop) != 0; |
| 115 | state->is_v5e = (properties & ARM_v5e_Prop) != 0; | 99 | state->is_v5e = (properties & ARM_v5e_Prop) != 0; |
| @@ -132,15 +116,10 @@ void ARMul_SelectProcessor(ARMul_State* state, unsigned properties) | |||
| 132 | void ARMul_Reset(ARMul_State* state) | 116 | void ARMul_Reset(ARMul_State* state) |
| 133 | { | 117 | { |
| 134 | state->NextInstr = 0; | 118 | state->NextInstr = 0; |
| 135 | if (state->prog32Sig) { | 119 | |
| 136 | state->Reg[15] = 0; | 120 | state->Reg[15] = 0; |
| 137 | state->Cpsr = INTBITS | SVC32MODE; | 121 | state->Cpsr = INTBITS | SVC32MODE; |
| 138 | state->Mode = SVC32MODE; | 122 | state->Mode = SVC32MODE; |
| 139 | } else { | ||
| 140 | state->Reg[15] = R15INTBITS | SVC26MODE; | ||
| 141 | state->Cpsr = INTBITS | SVC26MODE; | ||
| 142 | state->Mode = SVC26MODE; | ||
| 143 | } | ||
| 144 | 123 | ||
| 145 | state->Bank = SVCBANK; | 124 | state->Bank = SVCBANK; |
| 146 | FLUSHPIPE; | 125 | FLUSHPIPE; |
diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h index ff9296e0f..012c43c61 100644 --- a/src/core/arm/skyeye_common/armdefs.h +++ b/src/core/arm/skyeye_common/armdefs.h | |||
| @@ -35,15 +35,27 @@ | |||
| 35 | #define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1)) | 35 | #define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1)) |
| 36 | #define BIT(s, n) ((s >> (n)) & 1) | 36 | #define BIT(s, n) ((s >> (n)) & 1) |
| 37 | 37 | ||
| 38 | #define LOW 0 | 38 | // Signal levels |
| 39 | #define HIGH 1 | 39 | enum { |
| 40 | #define LOWHIGH 1 | 40 | LOW = 0, |
| 41 | #define HIGHLOW 2 | 41 | HIGH = 1, |
| 42 | LOWHIGH = 1, | ||
| 43 | HIGHLOW = 2 | ||
| 44 | }; | ||
| 45 | |||
| 46 | // Cache types | ||
| 47 | enum { | ||
| 48 | NONCACHE = 0, | ||
| 49 | DATACACHE = 1, | ||
| 50 | INSTCACHE = 2, | ||
| 51 | }; | ||
| 42 | 52 | ||
| 43 | //the define of cachetype | 53 | // Abort models |
| 44 | #define NONCACHE 0 | 54 | enum { |
| 45 | #define DATACACHE 1 | 55 | ABORT_BASE_RESTORED = 0, |
| 46 | #define INSTCACHE 2 | 56 | ABORT_EARLY = 1, |
| 57 | ABORT_BASE_UPDATED = 2 | ||
| 58 | }; | ||
| 47 | 59 | ||
| 48 | #define POS(i) ( (~(i)) >> 31 ) | 60 | #define POS(i) ( (~(i)) >> 31 ) |
| 49 | #define NEG(i) ( (i) >> 31 ) | 61 | #define NEG(i) ( (i) >> 31 ) |
| @@ -137,8 +149,6 @@ struct ARMul_State | |||
| 137 | unsigned abortSig; | 149 | unsigned abortSig; |
| 138 | unsigned NtransSig; | 150 | unsigned NtransSig; |
| 139 | unsigned bigendSig; | 151 | unsigned bigendSig; |
| 140 | unsigned prog32Sig; | ||
| 141 | unsigned data32Sig; | ||
| 142 | unsigned syscallSig; | 152 | unsigned syscallSig; |
| 143 | 153 | ||
| 144 | /* 2004-05-09 chy | 154 | /* 2004-05-09 chy |
| @@ -215,7 +225,6 @@ typedef ARMul_State arm_core_t; | |||
| 215 | \***************************************************************************/ | 225 | \***************************************************************************/ |
| 216 | 226 | ||
| 217 | enum { | 227 | enum { |
| 218 | ARM_Fix26_Prop = 0x01, | ||
| 219 | ARM_Nexec_Prop = 0x02, | 228 | ARM_Nexec_Prop = 0x02, |
| 220 | ARM_Debug_Prop = 0x10, | 229 | ARM_Debug_Prop = 0x10, |
| 221 | ARM_Isync_Prop = ARM_Debug_Prop, | 230 | ARM_Isync_Prop = ARM_Debug_Prop, |
| @@ -230,19 +239,6 @@ enum { | |||
| 230 | ARM_iWMMXt_Prop = 0x800, | 239 | ARM_iWMMXt_Prop = 0x800, |
| 231 | ARM_PXA27X_Prop = 0x1000, | 240 | ARM_PXA27X_Prop = 0x1000, |
| 232 | ARM_v7_Prop = 0x2000, | 241 | ARM_v7_Prop = 0x2000, |
| 233 | |||
| 234 | // ARM2 family | ||
| 235 | ARM2 = ARM_Fix26_Prop, | ||
| 236 | ARM2as = ARM2, | ||
| 237 | ARM61 = ARM2, | ||
| 238 | ARM3 = ARM2, | ||
| 239 | |||
| 240 | // ARM6 family | ||
| 241 | ARM6 = ARM_Lock_Prop, | ||
| 242 | ARM60 = ARM6, | ||
| 243 | ARM600 = ARM6, | ||
| 244 | ARM610 = ARM6, | ||
| 245 | ARM620 = ARM6 | ||
| 246 | }; | 242 | }; |
| 247 | 243 | ||
| 248 | /***************************************************************************\ | 244 | /***************************************************************************\ |
| @@ -275,10 +271,6 @@ enum { | |||
| 275 | \***************************************************************************/ | 271 | \***************************************************************************/ |
| 276 | 272 | ||
| 277 | enum { | 273 | enum { |
| 278 | USER26MODE = 0, | ||
| 279 | FIQ26MODE = 1, | ||
| 280 | IRQ26MODE = 2, | ||
| 281 | SVC26MODE = 3, | ||
| 282 | USER32MODE = 16, | 274 | USER32MODE = 16, |
| 283 | FIQ32MODE = 17, | 275 | FIQ32MODE = 17, |
| 284 | IRQ32MODE = 18, | 276 | IRQ32MODE = 18, |
diff --git a/src/core/arm/skyeye_common/armemu.h b/src/core/arm/skyeye_common/armemu.h index beee54c9a..5d4c06837 100644 --- a/src/core/arm/skyeye_common/armemu.h +++ b/src/core/arm/skyeye_common/armemu.h | |||
| @@ -76,24 +76,28 @@ | |||
| 76 | #define R15MODE (state->Reg[15] & R15MODEBITS) | 76 | #define R15MODE (state->Reg[15] & R15MODEBITS) |
| 77 | 77 | ||
| 78 | // Different ways to start the next instruction. | 78 | // Different ways to start the next instruction. |
| 79 | #define SEQ 0 | 79 | enum { |
| 80 | #define NONSEQ 1 | 80 | SEQ = 0, |
| 81 | #define PCINCEDSEQ 2 | 81 | NONSEQ = 1, |
| 82 | #define PCINCEDNONSEQ 3 | 82 | PCINCEDSEQ = 2, |
| 83 | #define PRIMEPIPE 4 | 83 | PCINCEDNONSEQ = 3, |
| 84 | #define RESUME 8 | 84 | PRIMEPIPE = 4, |
| 85 | RESUME = 8 | ||
| 86 | }; | ||
| 87 | |||
| 88 | // Values for Emulate. | ||
| 89 | enum { | ||
| 90 | STOP = 0, // Stop | ||
| 91 | CHANGEMODE = 1, // Change mode | ||
| 92 | ONCE = 2, // Execute just one interation | ||
| 93 | RUN = 3 // Continuous execution | ||
| 94 | }; | ||
| 85 | 95 | ||
| 86 | #define FLUSHPIPE state->NextInstr |= PRIMEPIPE | 96 | #define FLUSHPIPE state->NextInstr |= PRIMEPIPE |
| 87 | 97 | ||
| 88 | // Macro to rotate n right by b bits. | 98 | // Macro to rotate n right by b bits. |
| 89 | #define ROTATER(n, b) (((n) >> (b)) | ((n) << (32 - (b)))) | 99 | #define ROTATER(n, b) (((n) >> (b)) | ((n) << (32 - (b)))) |
| 90 | 100 | ||
| 91 | // Values for Emulate. | ||
| 92 | #define STOP 0 // stop | ||
| 93 | #define CHANGEMODE 1 // change mode | ||
| 94 | #define ONCE 2 // execute just one interation | ||
| 95 | #define RUN 3 // continuous execution | ||
| 96 | |||
| 97 | // Stuff that is shared across modes. | 101 | // Stuff that is shared across modes. |
| 98 | extern unsigned ARMul_MultTable[]; // Number of I cycles for a mult. | 102 | extern unsigned ARMul_MultTable[]; // Number of I cycles for a mult. |
| 99 | extern ARMword ARMul_ImmedTable[]; // Immediate DP LHS values. | 103 | extern ARMword ARMul_ImmedTable[]; // Immediate DP LHS values. |
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) { | |||
| 48 | return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr)); | 48 | return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr)); |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { | 51 | /** |
| 52 | * Checks if the parameters in a register write call are valid and logs in the case that | ||
| 53 | * they are not | ||
| 54 | * @param base_address The first address in the sequence of registers that will be written | ||
| 55 | * @param size_in_bytes The number of registers that will be written | ||
| 56 | * @return true if the parameters are valid, false otherwise | ||
| 57 | */ | ||
| 58 | static bool CheckWriteParameters(u32 base_address, u32 size_in_bytes) { | ||
| 52 | // TODO: Return proper error codes | 59 | // TODO: Return proper error codes |
| 53 | if (base_address + size_in_bytes >= 0x420000) { | 60 | if (base_address + size_in_bytes >= 0x420000) { |
| 54 | LOG_ERROR(Service_GSP, "Write address out of range! (address=0x%08x, size=0x%08x)", | 61 | LOG_ERROR(Service_GSP, "Write address out of range! (address=0x%08x, size=0x%08x)", |
| 55 | base_address, size_in_bytes); | 62 | base_address, size_in_bytes); |
| 56 | return; | 63 | return false; |
| 57 | } | 64 | } |
| 58 | 65 | ||
| 59 | // size should be word-aligned | 66 | // size should be word-aligned |
| 60 | if ((size_in_bytes % 4) != 0) { | 67 | if ((size_in_bytes % 4) != 0) { |
| 61 | LOG_ERROR(Service_GSP, "Invalid size 0x%08x", size_in_bytes); | 68 | LOG_ERROR(Service_GSP, "Invalid size 0x%08x", size_in_bytes); |
| 62 | return; | 69 | return false; |
| 63 | } | 70 | } |
| 64 | 71 | ||
| 72 | return true; | ||
| 73 | } | ||
| 74 | |||
| 75 | /** | ||
| 76 | * Writes sequential GSP GPU hardware registers using an array of source data | ||
| 77 | * | ||
| 78 | * @param base_address The address of the first register in the sequence | ||
| 79 | * @param size_in_bytes The number of registers to update (size of data) | ||
| 80 | * @param data A pointer to the source data | ||
| 81 | */ | ||
| 82 | static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { | ||
| 83 | // TODO: Return proper error codes | ||
| 84 | if (!CheckWriteParameters(base_address, size_in_bytes)) | ||
| 85 | return; | ||
| 86 | |||
| 65 | while (size_in_bytes > 0) { | 87 | while (size_in_bytes > 0) { |
| 66 | GPU::Write<u32>(base_address + 0x1EB00000, *data); | 88 | GPU::Write<u32>(base_address + 0x1EB00000, *data); |
| 67 | 89 | ||
| @@ -71,17 +93,80 @@ static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { | |||
| 71 | } | 93 | } |
| 72 | } | 94 | } |
| 73 | 95 | ||
| 74 | /// Write a GSP GPU hardware register | 96 | /** |
| 97 | * GSP_GPU::WriteHWRegs service function | ||
| 98 | * | ||
| 99 | * Writes sequential GSP GPU hardware registers | ||
| 100 | * | ||
| 101 | * Inputs: | ||
| 102 | * 1 : address of first GPU register | ||
| 103 | * 2 : number of registers to write sequentially | ||
| 104 | * 4 : pointer to source data array | ||
| 105 | */ | ||
| 75 | static void WriteHWRegs(Service::Interface* self) { | 106 | static void WriteHWRegs(Service::Interface* self) { |
| 76 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 107 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 77 | u32 reg_addr = cmd_buff[1]; | 108 | u32 reg_addr = cmd_buff[1]; |
| 78 | u32 size = cmd_buff[2]; | 109 | u32 size = cmd_buff[2]; |
| 79 | 110 | ||
| 80 | u32* src = (u32*)Memory::GetPointer(cmd_buff[0x4]); | 111 | u32* src = (u32*)Memory::GetPointer(cmd_buff[4]); |
| 81 | 112 | ||
| 82 | WriteHWRegs(reg_addr, size, src); | 113 | WriteHWRegs(reg_addr, size, src); |
| 83 | } | 114 | } |
| 84 | 115 | ||
| 116 | /** | ||
| 117 | * Updates sequential GSP GPU hardware registers using parallel arrays of source data and masks. | ||
| 118 | * For each register, the value is updated only where the mask is high | ||
| 119 | * | ||
| 120 | * @param base_address The address of the first register in the sequence | ||
| 121 | * @param size_in_bytes The number of registers to update (size of data) | ||
| 122 | * @param data A pointer to the source data to use for updates | ||
| 123 | * @param masks A pointer to the masks | ||
| 124 | */ | ||
| 125 | static void WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, const u32* data, const u32* masks) { | ||
| 126 | // TODO: Return proper error codes | ||
| 127 | if (!CheckWriteParameters(base_address, size_in_bytes)) | ||
| 128 | return; | ||
| 129 | |||
| 130 | while (size_in_bytes > 0) { | ||
| 131 | const u32 reg_address = base_address + 0x1EB00000; | ||
| 132 | |||
| 133 | u32 reg_value; | ||
| 134 | GPU::Read<u32>(reg_value, reg_address); | ||
| 135 | |||
| 136 | // Update the current value of the register only for set mask bits | ||
| 137 | reg_value = (reg_value & ~*masks) | (*data | *masks); | ||
| 138 | |||
| 139 | GPU::Write<u32>(reg_address, reg_value); | ||
| 140 | |||
| 141 | size_in_bytes -= 4; | ||
| 142 | ++data; | ||
| 143 | ++masks; | ||
| 144 | base_address += 4; | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | /** | ||
| 149 | * GSP_GPU::WriteHWRegsWithMask service function | ||
| 150 | * | ||
| 151 | * Updates sequential GSP GPU hardware registers using masks | ||
| 152 | * | ||
| 153 | * Inputs: | ||
| 154 | * 1 : address of first GPU register | ||
| 155 | * 2 : number of registers to update sequentially | ||
| 156 | * 4 : pointer to source data array | ||
| 157 | * 6 : pointer to mask array | ||
| 158 | */ | ||
| 159 | static void WriteHWRegsWithMask(Service::Interface* self) { | ||
| 160 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 161 | u32 reg_addr = cmd_buff[1]; | ||
| 162 | u32 size = cmd_buff[2]; | ||
| 163 | |||
| 164 | u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]); | ||
| 165 | u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]); | ||
| 166 | |||
| 167 | WriteHWRegsWithMask(reg_addr, size, src_data, mask_data); | ||
| 168 | } | ||
| 169 | |||
| 85 | /// Read a GSP GPU hardware register | 170 | /// Read a GSP GPU hardware register |
| 86 | static void ReadHWRegs(Service::Interface* self) { | 171 | static void ReadHWRegs(Service::Interface* self) { |
| 87 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 172 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| @@ -350,7 +435,7 @@ static void TriggerCmdReqQueue(Service::Interface* self) { | |||
| 350 | 435 | ||
| 351 | const Interface::FunctionInfo FunctionTable[] = { | 436 | const Interface::FunctionInfo FunctionTable[] = { |
| 352 | {0x00010082, WriteHWRegs, "WriteHWRegs"}, | 437 | {0x00010082, WriteHWRegs, "WriteHWRegs"}, |
| 353 | {0x00020084, nullptr, "WriteHWRegsWithMask"}, | 438 | {0x00020084, WriteHWRegsWithMask, "WriteHWRegsWithMask"}, |
| 354 | {0x00030082, nullptr, "WriteHWRegRepeat"}, | 439 | {0x00030082, nullptr, "WriteHWRegRepeat"}, |
| 355 | {0x00040080, ReadHWRegs, "ReadHWRegs"}, | 440 | {0x00040080, ReadHWRegs, "ReadHWRegs"}, |
| 356 | {0x00050200, SetBufferSwap, "SetBufferSwap"}, | 441 | {0x00050200, SetBufferSwap, "SetBufferSwap"}, |