summaryrefslogtreecommitdiff
path: root/src/core/arm/skyeye_common
diff options
context:
space:
mode:
authorGravatar bunnei2018-01-02 22:24:12 -0500
committerGravatar bunnei2018-01-02 22:24:12 -0500
commitb172f0d770486d4367fbea22906a5e908ef621e8 (patch)
tree6a564c23ed8f52c16c50942803f4a69fd0047f6c /src/core/arm/skyeye_common
parentvm_manager: Use a more reasonable MAX_ADDRESS size. (diff)
downloadyuzu-b172f0d770486d4367fbea22906a5e908ef621e8.tar.gz
yuzu-b172f0d770486d4367fbea22906a5e908ef621e8.tar.xz
yuzu-b172f0d770486d4367fbea22906a5e908ef621e8.zip
arm: Remove SkyEye/Dyncom code that is ARMv6-only.
Diffstat (limited to 'src/core/arm/skyeye_common')
-rw-r--r--src/core/arm/skyeye_common/arm_regformat.h187
-rw-r--r--src/core/arm/skyeye_common/armstate.cpp597
-rw-r--r--src/core/arm/skyeye_common/armstate.h245
-rw-r--r--src/core/arm/skyeye_common/armsupp.cpp189
-rw-r--r--src/core/arm/skyeye_common/armsupp.h32
-rw-r--r--src/core/arm/skyeye_common/vfp/asm_vfp.h83
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.cpp137
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.h43
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp_helper.h433
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpdouble.cpp1247
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpinstr.cpp1703
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpsingle.cpp1272
12 files changed, 0 insertions, 6168 deletions
diff --git a/src/core/arm/skyeye_common/arm_regformat.h b/src/core/arm/skyeye_common/arm_regformat.h
deleted file mode 100644
index 706195a05..000000000
--- a/src/core/arm/skyeye_common/arm_regformat.h
+++ /dev/null
@@ -1,187 +0,0 @@
1#pragma once
2
3enum {
4 R0 = 0,
5 R1,
6 R2,
7 R3,
8 R4,
9 R5,
10 R6,
11 R7,
12 R8,
13 R9,
14 R10,
15 R11,
16 R12,
17 R13,
18 LR,
19 R15, // PC,
20 CPSR_REG,
21 SPSR_REG,
22
23 PHYS_PC,
24 R13_USR,
25 R14_USR,
26 R13_SVC,
27 R14_SVC,
28 R13_ABORT,
29 R14_ABORT,
30 R13_UNDEF,
31 R14_UNDEF,
32 R13_IRQ,
33 R14_IRQ,
34 R8_FIRQ,
35 R9_FIRQ,
36 R10_FIRQ,
37 R11_FIRQ,
38 R12_FIRQ,
39 R13_FIRQ,
40 R14_FIRQ,
41 SPSR_INVALID1,
42 SPSR_INVALID2,
43 SPSR_SVC,
44 SPSR_ABORT,
45 SPSR_UNDEF,
46 SPSR_IRQ,
47 SPSR_FIRQ,
48 MODE_REG, /* That is the cpsr[4 : 0], just for calculation easily */
49 BANK_REG,
50 EXCLUSIVE_TAG,
51 EXCLUSIVE_STATE,
52 EXCLUSIVE_RESULT,
53
54 MAX_REG_NUM,
55};
56
57// VFP system registers
58enum VFPSystemRegister {
59 VFP_FPSID,
60 VFP_FPSCR,
61 VFP_FPEXC,
62 VFP_FPINST,
63 VFP_FPINST2,
64 VFP_MVFR0,
65 VFP_MVFR1,
66
67 // Not an actual register.
68 // All VFP system registers should be defined above this.
69 VFP_SYSTEM_REGISTER_COUNT
70};
71
72enum CP15Register {
73 // c0 - Information registers
74 CP15_MAIN_ID,
75 CP15_CACHE_TYPE,
76 CP15_TCM_STATUS,
77 CP15_TLB_TYPE,
78 CP15_CPU_ID,
79 CP15_PROCESSOR_FEATURE_0,
80 CP15_PROCESSOR_FEATURE_1,
81 CP15_DEBUG_FEATURE_0,
82 CP15_AUXILIARY_FEATURE_0,
83 CP15_MEMORY_MODEL_FEATURE_0,
84 CP15_MEMORY_MODEL_FEATURE_1,
85 CP15_MEMORY_MODEL_FEATURE_2,
86 CP15_MEMORY_MODEL_FEATURE_3,
87 CP15_ISA_FEATURE_0,
88 CP15_ISA_FEATURE_1,
89 CP15_ISA_FEATURE_2,
90 CP15_ISA_FEATURE_3,
91 CP15_ISA_FEATURE_4,
92
93 // c1 - Control registers
94 CP15_CONTROL,
95 CP15_AUXILIARY_CONTROL,
96 CP15_COPROCESSOR_ACCESS_CONTROL,
97
98 // c2 - Translation table registers
99 CP15_TRANSLATION_BASE_TABLE_0,
100 CP15_TRANSLATION_BASE_TABLE_1,
101 CP15_TRANSLATION_BASE_CONTROL,
102 CP15_DOMAIN_ACCESS_CONTROL,
103 CP15_RESERVED,
104
105 // c5 - Fault status registers
106 CP15_FAULT_STATUS,
107 CP15_INSTR_FAULT_STATUS,
108 CP15_COMBINED_DATA_FSR = CP15_FAULT_STATUS,
109 CP15_INST_FSR,
110
111 // c6 - Fault Address registers
112 CP15_FAULT_ADDRESS,
113 CP15_COMBINED_DATA_FAR = CP15_FAULT_ADDRESS,
114 CP15_WFAR,
115 CP15_IFAR,
116
117 // c7 - Cache operation registers
118 CP15_WAIT_FOR_INTERRUPT,
119 CP15_PHYS_ADDRESS,
120 CP15_INVALIDATE_INSTR_CACHE,
121 CP15_INVALIDATE_INSTR_CACHE_USING_MVA,
122 CP15_INVALIDATE_INSTR_CACHE_USING_INDEX,
123 CP15_FLUSH_PREFETCH_BUFFER,
124 CP15_FLUSH_BRANCH_TARGET_CACHE,
125 CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY,
126 CP15_INVALIDATE_DATA_CACHE,
127 CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA,
128 CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX,
129 CP15_INVALIDATE_DATA_AND_INSTR_CACHE,
130 CP15_CLEAN_DATA_CACHE,
131 CP15_CLEAN_DATA_CACHE_LINE_USING_MVA,
132 CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX,
133 CP15_DATA_SYNC_BARRIER,
134 CP15_DATA_MEMORY_BARRIER,
135 CP15_CLEAN_AND_INVALIDATE_DATA_CACHE,
136 CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA,
137 CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX,
138
139 // c8 - TLB operations
140 CP15_INVALIDATE_ITLB,
141 CP15_INVALIDATE_ITLB_SINGLE_ENTRY,
142 CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH,
143 CP15_INVALIDATE_ITLB_ENTRY_ON_MVA,
144 CP15_INVALIDATE_DTLB,
145 CP15_INVALIDATE_DTLB_SINGLE_ENTRY,
146 CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH,
147 CP15_INVALIDATE_DTLB_ENTRY_ON_MVA,
148 CP15_INVALIDATE_UTLB,
149 CP15_INVALIDATE_UTLB_SINGLE_ENTRY,
150 CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH,
151 CP15_INVALIDATE_UTLB_ENTRY_ON_MVA,
152
153 // c9 - Data cache lockdown register
154 CP15_DATA_CACHE_LOCKDOWN,
155
156 // c10 - TLB/Memory map registers
157 CP15_TLB_LOCKDOWN,
158 CP15_PRIMARY_REGION_REMAP,
159 CP15_NORMAL_REGION_REMAP,
160
161 // c13 - Thread related registers
162 CP15_PID,
163 CP15_CONTEXT_ID,
164 CP15_THREAD_UPRW, // Thread ID register - User/Privileged Read/Write
165 CP15_THREAD_URO, // Thread ID register - User Read Only (Privileged R/W)
166 CP15_THREAD_PRW, // Thread ID register - Privileged R/W only.
167
168 // c15 - Performance and TLB lockdown registers
169 CP15_PERFORMANCE_MONITOR_CONTROL,
170 CP15_CYCLE_COUNTER,
171 CP15_COUNT_0,
172 CP15_COUNT_1,
173 CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY,
174 CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY,
175 CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS,
176 CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS,
177 CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE,
178 CP15_TLB_DEBUG_CONTROL,
179
180 // Skyeye defined
181 CP15_TLB_FAULT_ADDR,
182 CP15_TLB_FAULT_STATUS,
183
184 // Not an actual register.
185 // All registers should be defined above this.
186 CP15_REGISTER_COUNT,
187};
diff --git a/src/core/arm/skyeye_common/armstate.cpp b/src/core/arm/skyeye_common/armstate.cpp
deleted file mode 100644
index 92b644825..000000000
--- a/src/core/arm/skyeye_common/armstate.cpp
+++ /dev/null
@@ -1,597 +0,0 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include "common/logging/log.h"
7#include "common/swap.h"
8#include "core/arm/skyeye_common/armstate.h"
9#include "core/arm/skyeye_common/vfp/vfp.h"
10#include "core/gdbstub/gdbstub.h"
11#include "core/memory.h"
12
13ARMul_State::ARMul_State(PrivilegeMode initial_mode) {
14 Reset();
15 ChangePrivilegeMode(initial_mode);
16}
17
18void ARMul_State::ChangePrivilegeMode(u32 new_mode) {
19 if (Mode == new_mode)
20 return;
21
22 if (new_mode != USERBANK) {
23 switch (Mode) {
24 case SYSTEM32MODE: // Shares registers with user mode
25 case USER32MODE:
26 Reg_usr[0] = Reg[13];
27 Reg_usr[1] = Reg[14];
28 break;
29 case IRQ32MODE:
30 Reg_irq[0] = Reg[13];
31 Reg_irq[1] = Reg[14];
32 Spsr[IRQBANK] = Spsr_copy;
33 break;
34 case SVC32MODE:
35 Reg_svc[0] = Reg[13];
36 Reg_svc[1] = Reg[14];
37 Spsr[SVCBANK] = Spsr_copy;
38 break;
39 case ABORT32MODE:
40 Reg_abort[0] = Reg[13];
41 Reg_abort[1] = Reg[14];
42 Spsr[ABORTBANK] = Spsr_copy;
43 break;
44 case UNDEF32MODE:
45 Reg_undef[0] = Reg[13];
46 Reg_undef[1] = Reg[14];
47 Spsr[UNDEFBANK] = Spsr_copy;
48 break;
49 case FIQ32MODE:
50 std::copy(Reg.begin() + 8, Reg.end() - 1, Reg_firq.begin());
51 Spsr[FIQBANK] = Spsr_copy;
52 break;
53 }
54
55 switch (new_mode) {
56 case USER32MODE:
57 Reg[13] = Reg_usr[0];
58 Reg[14] = Reg_usr[1];
59 Bank = USERBANK;
60 break;
61 case IRQ32MODE:
62 Reg[13] = Reg_irq[0];
63 Reg[14] = Reg_irq[1];
64 Spsr_copy = Spsr[IRQBANK];
65 Bank = IRQBANK;
66 break;
67 case SVC32MODE:
68 Reg[13] = Reg_svc[0];
69 Reg[14] = Reg_svc[1];
70 Spsr_copy = Spsr[SVCBANK];
71 Bank = SVCBANK;
72 break;
73 case ABORT32MODE:
74 Reg[13] = Reg_abort[0];
75 Reg[14] = Reg_abort[1];
76 Spsr_copy = Spsr[ABORTBANK];
77 Bank = ABORTBANK;
78 break;
79 case UNDEF32MODE:
80 Reg[13] = Reg_undef[0];
81 Reg[14] = Reg_undef[1];
82 Spsr_copy = Spsr[UNDEFBANK];
83 Bank = UNDEFBANK;
84 break;
85 case FIQ32MODE:
86 std::copy(Reg_firq.begin(), Reg_firq.end(), Reg.begin() + 8);
87 Spsr_copy = Spsr[FIQBANK];
88 Bank = FIQBANK;
89 break;
90 case SYSTEM32MODE: // Shares registers with user mode.
91 Reg[13] = Reg_usr[0];
92 Reg[14] = Reg_usr[1];
93 Bank = SYSTEMBANK;
94 break;
95 }
96
97 // Set the mode bits in the APSR
98 Cpsr = (Cpsr & ~Mode) | new_mode;
99 Mode = new_mode;
100 }
101}
102
103// Performs a reset
104void ARMul_State::Reset() {
105 VFPInit(this);
106
107 // Set stack pointer to the top of the stack
108 Reg[13] = 0x10000000;
109 Reg[15] = 0;
110
111 Cpsr = INTBITS | SVC32MODE;
112 Mode = SVC32MODE;
113 Bank = SVCBANK;
114
115 ResetMPCoreCP15Registers();
116
117 NresetSig = HIGH;
118 NfiqSig = HIGH;
119 NirqSig = HIGH;
120 NtransSig = (Mode & 3) ? HIGH : LOW;
121 abortSig = LOW;
122
123 NumInstrs = 0;
124 Emulate = RUN;
125}
126
127// Resets certain MPCore CP15 values to their ARM-defined reset values.
128void ARMul_State::ResetMPCoreCP15Registers() {
129 // c0
130 CP15[CP15_MAIN_ID] = 0x410FB024;
131 CP15[CP15_TLB_TYPE] = 0x00000800;
132 CP15[CP15_PROCESSOR_FEATURE_0] = 0x00000111;
133 CP15[CP15_PROCESSOR_FEATURE_1] = 0x00000001;
134 CP15[CP15_DEBUG_FEATURE_0] = 0x00000002;
135 CP15[CP15_MEMORY_MODEL_FEATURE_0] = 0x01100103;
136 CP15[CP15_MEMORY_MODEL_FEATURE_1] = 0x10020302;
137 CP15[CP15_MEMORY_MODEL_FEATURE_2] = 0x01222000;
138 CP15[CP15_MEMORY_MODEL_FEATURE_3] = 0x00000000;
139 CP15[CP15_ISA_FEATURE_0] = 0x00100011;
140 CP15[CP15_ISA_FEATURE_1] = 0x12002111;
141 CP15[CP15_ISA_FEATURE_2] = 0x11221011;
142 CP15[CP15_ISA_FEATURE_3] = 0x01102131;
143 CP15[CP15_ISA_FEATURE_4] = 0x00000141;
144
145 // c1
146 CP15[CP15_CONTROL] = 0x00054078;
147 CP15[CP15_AUXILIARY_CONTROL] = 0x0000000F;
148 CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = 0x00000000;
149
150 // c2
151 CP15[CP15_TRANSLATION_BASE_TABLE_0] = 0x00000000;
152 CP15[CP15_TRANSLATION_BASE_TABLE_1] = 0x00000000;
153 CP15[CP15_TRANSLATION_BASE_CONTROL] = 0x00000000;
154
155 // c3
156 CP15[CP15_DOMAIN_ACCESS_CONTROL] = 0x00000000;
157
158 // c7
159 CP15[CP15_PHYS_ADDRESS] = 0x00000000;
160
161 // c9
162 CP15[CP15_DATA_CACHE_LOCKDOWN] = 0xFFFFFFF0;
163
164 // c10
165 CP15[CP15_TLB_LOCKDOWN] = 0x00000000;
166 CP15[CP15_PRIMARY_REGION_REMAP] = 0x00098AA4;
167 CP15[CP15_NORMAL_REGION_REMAP] = 0x44E048E0;
168
169 // c13
170 CP15[CP15_PID] = 0x00000000;
171 CP15[CP15_CONTEXT_ID] = 0x00000000;
172 CP15[CP15_THREAD_UPRW] = 0x00000000;
173 CP15[CP15_THREAD_URO] = 0x00000000;
174 CP15[CP15_THREAD_PRW] = 0x00000000;
175
176 // c15
177 CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = 0x00000000;
178 CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = 0x00000000;
179 CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = 0x00000000;
180 CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = 0x00000000;
181 CP15[CP15_TLB_DEBUG_CONTROL] = 0x00000000;
182}
183
184static void CheckMemoryBreakpoint(u32 address, GDBStub::BreakpointType type) {
185 if (GDBStub::IsServerEnabled() && GDBStub::CheckBreakpoint(address, type)) {
186 LOG_DEBUG(Debug, "Found memory breakpoint @ %08x", address);
187 GDBStub::Break(true);
188 }
189}
190
191u8 ARMul_State::ReadMemory8(u32 address) const {
192 CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
193
194 return Memory::Read8(address);
195}
196
197u16 ARMul_State::ReadMemory16(u32 address) const {
198 CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
199
200 u16 data = Memory::Read16(address);
201
202 if (InBigEndianMode())
203 data = Common::swap16(data);
204
205 return data;
206}
207
208u32 ARMul_State::ReadMemory32(u32 address) const {
209 CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
210
211 u32 data = Memory::Read32(address);
212
213 if (InBigEndianMode())
214 data = Common::swap32(data);
215
216 return data;
217}
218
219u64 ARMul_State::ReadMemory64(u32 address) const {
220 CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
221
222 u64 data = Memory::Read64(address);
223
224 if (InBigEndianMode())
225 data = Common::swap64(data);
226
227 return data;
228}
229
230void ARMul_State::WriteMemory8(u32 address, u8 data) {
231 CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write);
232
233 Memory::Write8(address, data);
234}
235
236void ARMul_State::WriteMemory16(u32 address, u16 data) {
237 CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write);
238
239 if (InBigEndianMode())
240 data = Common::swap16(data);
241
242 Memory::Write16(address, data);
243}
244
245void ARMul_State::WriteMemory32(u32 address, u32 data) {
246 CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write);
247
248 if (InBigEndianMode())
249 data = Common::swap32(data);
250
251 Memory::Write32(address, data);
252}
253
254void ARMul_State::WriteMemory64(u32 address, u64 data) {
255 CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write);
256
257 if (InBigEndianMode())
258 data = Common::swap64(data);
259
260 Memory::Write64(address, data);
261}
262
263// Reads from the CP15 registers. Used with implementation of the MRC instruction.
264// Note that since the 3DS does not have the hypervisor extensions, these registers
265// are not implemented.
266u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const {
267 // Unprivileged registers
268 if (crn == 13 && opcode_1 == 0 && crm == 0) {
269 if (opcode_2 == 2)
270 return CP15[CP15_THREAD_UPRW];
271
272 if (opcode_2 == 3)
273 return CP15[CP15_THREAD_URO];
274 }
275
276 if (InAPrivilegedMode()) {
277 if (crn == 0 && opcode_1 == 0) {
278 if (crm == 0) {
279 if (opcode_2 == 0)
280 return CP15[CP15_MAIN_ID];
281
282 if (opcode_2 == 1)
283 return CP15[CP15_CACHE_TYPE];
284
285 if (opcode_2 == 3)
286 return CP15[CP15_TLB_TYPE];
287
288 if (opcode_2 == 5)
289 return CP15[CP15_CPU_ID];
290 } else if (crm == 1) {
291 if (opcode_2 == 0)
292 return CP15[CP15_PROCESSOR_FEATURE_0];
293
294 if (opcode_2 == 1)
295 return CP15[CP15_PROCESSOR_FEATURE_1];
296
297 if (opcode_2 == 2)
298 return CP15[CP15_DEBUG_FEATURE_0];
299
300 if (opcode_2 == 4)
301 return CP15[CP15_MEMORY_MODEL_FEATURE_0];
302
303 if (opcode_2 == 5)
304 return CP15[CP15_MEMORY_MODEL_FEATURE_1];
305
306 if (opcode_2 == 6)
307 return CP15[CP15_MEMORY_MODEL_FEATURE_2];
308
309 if (opcode_2 == 7)
310 return CP15[CP15_MEMORY_MODEL_FEATURE_3];
311 } else if (crm == 2) {
312 if (opcode_2 == 0)
313 return CP15[CP15_ISA_FEATURE_0];
314
315 if (opcode_2 == 1)
316 return CP15[CP15_ISA_FEATURE_1];
317
318 if (opcode_2 == 2)
319 return CP15[CP15_ISA_FEATURE_2];
320
321 if (opcode_2 == 3)
322 return CP15[CP15_ISA_FEATURE_3];
323
324 if (opcode_2 == 4)
325 return CP15[CP15_ISA_FEATURE_4];
326 }
327 }
328
329 if (crn == 1 && opcode_1 == 0 && crm == 0) {
330 if (opcode_2 == 0)
331 return CP15[CP15_CONTROL];
332
333 if (opcode_2 == 1)
334 return CP15[CP15_AUXILIARY_CONTROL];
335
336 if (opcode_2 == 2)
337 return CP15[CP15_COPROCESSOR_ACCESS_CONTROL];
338 }
339
340 if (crn == 2 && opcode_1 == 0 && crm == 0) {
341 if (opcode_2 == 0)
342 return CP15[CP15_TRANSLATION_BASE_TABLE_0];
343
344 if (opcode_2 == 1)
345 return CP15[CP15_TRANSLATION_BASE_TABLE_1];
346
347 if (opcode_2 == 2)
348 return CP15[CP15_TRANSLATION_BASE_CONTROL];
349 }
350
351 if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
352 return CP15[CP15_DOMAIN_ACCESS_CONTROL];
353
354 if (crn == 5 && opcode_1 == 0 && crm == 0) {
355 if (opcode_2 == 0)
356 return CP15[CP15_FAULT_STATUS];
357
358 if (opcode_2 == 1)
359 return CP15[CP15_INSTR_FAULT_STATUS];
360 }
361
362 if (crn == 6 && opcode_1 == 0 && crm == 0) {
363 if (opcode_2 == 0)
364 return CP15[CP15_FAULT_ADDRESS];
365
366 if (opcode_2 == 1)
367 return CP15[CP15_WFAR];
368 }
369
370 if (crn == 7 && opcode_1 == 0 && crm == 4 && opcode_2 == 0)
371 return CP15[CP15_PHYS_ADDRESS];
372
373 if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
374 return CP15[CP15_DATA_CACHE_LOCKDOWN];
375
376 if (crn == 10 && opcode_1 == 0) {
377 if (crm == 0 && opcode_2 == 0)
378 return CP15[CP15_TLB_LOCKDOWN];
379
380 if (crm == 2) {
381 if (opcode_2 == 0)
382 return CP15[CP15_PRIMARY_REGION_REMAP];
383
384 if (opcode_2 == 1)
385 return CP15[CP15_NORMAL_REGION_REMAP];
386 }
387 }
388
389 if (crn == 13 && crm == 0) {
390 if (opcode_2 == 0)
391 return CP15[CP15_PID];
392
393 if (opcode_2 == 1)
394 return CP15[CP15_CONTEXT_ID];
395
396 if (opcode_2 == 4)
397 return CP15[CP15_THREAD_PRW];
398 }
399
400 if (crn == 15) {
401 if (opcode_1 == 0 && crm == 12) {
402 if (opcode_2 == 0)
403 return CP15[CP15_PERFORMANCE_MONITOR_CONTROL];
404
405 if (opcode_2 == 1)
406 return CP15[CP15_CYCLE_COUNTER];
407
408 if (opcode_2 == 2)
409 return CP15[CP15_COUNT_0];
410
411 if (opcode_2 == 3)
412 return CP15[CP15_COUNT_1];
413 }
414
415 if (opcode_1 == 5 && opcode_2 == 2) {
416 if (crm == 5)
417 return CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS];
418
419 if (crm == 6)
420 return CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS];
421
422 if (crm == 7)
423 return CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE];
424 }
425
426 if (opcode_1 == 7 && crm == 1 && opcode_2 == 0)
427 return CP15[CP15_TLB_DEBUG_CONTROL];
428 }
429 }
430
431 LOG_ERROR(Core_ARM, "MRC CRn=%u, CRm=%u, OP1=%u OP2=%u is not implemented. Returning zero.",
432 crn, crm, opcode_1, opcode_2);
433 return 0;
434}
435
436// Write to the CP15 registers. Used with implementation of the MCR instruction.
437// Note that since the 3DS does not have the hypervisor extensions, these registers
438// are not implemented.
439void ARMul_State::WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) {
440 if (InAPrivilegedMode()) {
441 if (crn == 1 && opcode_1 == 0 && crm == 0) {
442 if (opcode_2 == 0)
443 CP15[CP15_CONTROL] = value;
444 else if (opcode_2 == 1)
445 CP15[CP15_AUXILIARY_CONTROL] = value;
446 else if (opcode_2 == 2)
447 CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = value;
448 } else if (crn == 2 && opcode_1 == 0 && crm == 0) {
449 if (opcode_2 == 0)
450 CP15[CP15_TRANSLATION_BASE_TABLE_0] = value;
451 else if (opcode_2 == 1)
452 CP15[CP15_TRANSLATION_BASE_TABLE_1] = value;
453 else if (opcode_2 == 2)
454 CP15[CP15_TRANSLATION_BASE_CONTROL] = value;
455 } else if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) {
456 CP15[CP15_DOMAIN_ACCESS_CONTROL] = value;
457 } else if (crn == 5 && opcode_1 == 0 && crm == 0) {
458 if (opcode_2 == 0)
459 CP15[CP15_FAULT_STATUS] = value;
460 else if (opcode_2 == 1)
461 CP15[CP15_INSTR_FAULT_STATUS] = value;
462 } else if (crn == 6 && opcode_1 == 0 && crm == 0) {
463 if (opcode_2 == 0)
464 CP15[CP15_FAULT_ADDRESS] = value;
465 else if (opcode_2 == 1)
466 CP15[CP15_WFAR] = value;
467 } else if (crn == 7 && opcode_1 == 0) {
468 if (crm == 0 && opcode_2 == 4) {
469 CP15[CP15_WAIT_FOR_INTERRUPT] = value;
470 } else if (crm == 4 && opcode_2 == 0) {
471 // NOTE: Not entirely accurate. This should do permission checks.
472 CP15[CP15_PHYS_ADDRESS] = Memory::VirtualToPhysicalAddress(value);
473 } else if (crm == 5) {
474 if (opcode_2 == 0)
475 CP15[CP15_INVALIDATE_INSTR_CACHE] = value;
476 else if (opcode_2 == 1)
477 CP15[CP15_INVALIDATE_INSTR_CACHE_USING_MVA] = value;
478 else if (opcode_2 == 2)
479 CP15[CP15_INVALIDATE_INSTR_CACHE_USING_INDEX] = value;
480 else if (opcode_2 == 6)
481 CP15[CP15_FLUSH_BRANCH_TARGET_CACHE] = value;
482 else if (opcode_2 == 7)
483 CP15[CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY] = value;
484 } else if (crm == 6) {
485 if (opcode_2 == 0)
486 CP15[CP15_INVALIDATE_DATA_CACHE] = value;
487 else if (opcode_2 == 1)
488 CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value;
489 else if (opcode_2 == 2)
490 CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value;
491 } else if (crm == 7 && opcode_2 == 0) {
492 CP15[CP15_INVALIDATE_DATA_AND_INSTR_CACHE] = value;
493 } else if (crm == 10) {
494 if (opcode_2 == 0)
495 CP15[CP15_CLEAN_DATA_CACHE] = value;
496 else if (opcode_2 == 1)
497 CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_MVA] = value;
498 else if (opcode_2 == 2)
499 CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX] = value;
500 } else if (crm == 14) {
501 if (opcode_2 == 0)
502 CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE] = value;
503 else if (opcode_2 == 1)
504 CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value;
505 else if (opcode_2 == 2)
506 CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value;
507 }
508 } else if (crn == 8 && opcode_1 == 0) {
509 if (crm == 5) {
510 if (opcode_2 == 0)
511 CP15[CP15_INVALIDATE_ITLB] = value;
512 else if (opcode_2 == 1)
513 CP15[CP15_INVALIDATE_ITLB_SINGLE_ENTRY] = value;
514 else if (opcode_2 == 2)
515 CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH] = value;
516 else if (opcode_2 == 3)
517 CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_MVA] = value;
518 } else if (crm == 6) {
519 if (opcode_2 == 0)
520 CP15[CP15_INVALIDATE_DTLB] = value;
521 else if (opcode_2 == 1)
522 CP15[CP15_INVALIDATE_DTLB_SINGLE_ENTRY] = value;
523 else if (opcode_2 == 2)
524 CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH] = value;
525 else if (opcode_2 == 3)
526 CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_MVA] = value;
527 } else if (crm == 7) {
528 if (opcode_2 == 0)
529 CP15[CP15_INVALIDATE_UTLB] = value;
530 else if (opcode_2 == 1)
531 CP15[CP15_INVALIDATE_UTLB_SINGLE_ENTRY] = value;
532 else if (opcode_2 == 2)
533 CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH] = value;
534 else if (opcode_2 == 3)
535 CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_MVA] = value;
536 }
537 } else if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) {
538 CP15[CP15_DATA_CACHE_LOCKDOWN] = value;
539 } else if (crn == 10 && opcode_1 == 0) {
540 if (crm == 0 && opcode_2 == 0) {
541 CP15[CP15_TLB_LOCKDOWN] = value;
542 } else if (crm == 2) {
543 if (opcode_2 == 0)
544 CP15[CP15_PRIMARY_REGION_REMAP] = value;
545 else if (opcode_2 == 1)
546 CP15[CP15_NORMAL_REGION_REMAP] = value;
547 }
548 } else if (crn == 13 && opcode_1 == 0 && crm == 0) {
549 if (opcode_2 == 0)
550 CP15[CP15_PID] = value;
551 else if (opcode_2 == 1)
552 CP15[CP15_CONTEXT_ID] = value;
553 else if (opcode_2 == 3)
554 CP15[CP15_THREAD_URO] = value;
555 else if (opcode_2 == 4)
556 CP15[CP15_THREAD_PRW] = value;
557 } else if (crn == 15) {
558 if (opcode_1 == 0 && crm == 12) {
559 if (opcode_2 == 0)
560 CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = value;
561 else if (opcode_2 == 1)
562 CP15[CP15_CYCLE_COUNTER] = value;
563 else if (opcode_2 == 2)
564 CP15[CP15_COUNT_0] = value;
565 else if (opcode_2 == 3)
566 CP15[CP15_COUNT_1] = value;
567 } else if (opcode_1 == 5) {
568 if (crm == 4) {
569 if (opcode_2 == 2)
570 CP15[CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY] = value;
571 else if (opcode_2 == 4)
572 CP15[CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY] = value;
573 } else if (crm == 5 && opcode_2 == 2) {
574 CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = value;
575 } else if (crm == 6 && opcode_2 == 2) {
576 CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = value;
577 } else if (crm == 7 && opcode_2 == 2) {
578 CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = value;
579 }
580 } else if (opcode_1 == 7 && crm == 1 && opcode_2 == 0) {
581 CP15[CP15_TLB_DEBUG_CONTROL] = value;
582 }
583 }
584 }
585
586 // Unprivileged registers
587 if (crn == 7 && opcode_1 == 0 && crm == 5 && opcode_2 == 4) {
588 CP15[CP15_FLUSH_PREFETCH_BUFFER] = value;
589 } else if (crn == 7 && opcode_1 == 0 && crm == 10) {
590 if (opcode_2 == 4)
591 CP15[CP15_DATA_SYNC_BARRIER] = value;
592 else if (opcode_2 == 5)
593 CP15[CP15_DATA_MEMORY_BARRIER] = value;
594 } else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2) {
595 CP15[CP15_THREAD_UPRW] = value;
596 }
597}
diff --git a/src/core/arm/skyeye_common/armstate.h b/src/core/arm/skyeye_common/armstate.h
deleted file mode 100644
index 893877797..000000000
--- a/src/core/arm/skyeye_common/armstate.h
+++ /dev/null
@@ -1,245 +0,0 @@
1/* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator.
2 Copyright (C) 1994 Advanced RISC Machines Ltd.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18#pragma once
19
20#include <array>
21#include <unordered_map>
22#include "common/common_types.h"
23#include "core/arm/skyeye_common/arm_regformat.h"
24
25// Signal levels
26enum { LOW = 0, HIGH = 1, LOWHIGH = 1, HIGHLOW = 2 };
27
28// Cache types
29enum {
30 NONCACHE = 0,
31 DATACACHE = 1,
32 INSTCACHE = 2,
33};
34
35// ARM privilege modes
36enum PrivilegeMode {
37 USER32MODE = 16,
38 FIQ32MODE = 17,
39 IRQ32MODE = 18,
40 SVC32MODE = 19,
41 ABORT32MODE = 23,
42 UNDEF32MODE = 27,
43 SYSTEM32MODE = 31
44};
45
46// ARM privilege mode register banks
47enum {
48 USERBANK = 0,
49 FIQBANK = 1,
50 IRQBANK = 2,
51 SVCBANK = 3,
52 ABORTBANK = 4,
53 UNDEFBANK = 5,
54 DUMMYBANK = 6,
55 SYSTEMBANK = 7
56};
57
58// Hardware vector addresses
59enum {
60 ARMResetV = 0,
61 ARMUndefinedInstrV = 4,
62 ARMSWIV = 8,
63 ARMPrefetchAbortV = 12,
64 ARMDataAbortV = 16,
65 ARMAddrExceptnV = 20,
66 ARMIRQV = 24,
67 ARMFIQV = 28,
68 ARMErrorV = 32, // This is an offset, not an address!
69
70 ARMul_ResetV = ARMResetV,
71 ARMul_UndefinedInstrV = ARMUndefinedInstrV,
72 ARMul_SWIV = ARMSWIV,
73 ARMul_PrefetchAbortV = ARMPrefetchAbortV,
74 ARMul_DataAbortV = ARMDataAbortV,
75 ARMul_AddrExceptnV = ARMAddrExceptnV,
76 ARMul_IRQV = ARMIRQV,
77 ARMul_FIQV = ARMFIQV
78};
79
80// Coprocessor status values
81enum {
82 ARMul_FIRST = 0,
83 ARMul_TRANSFER = 1,
84 ARMul_BUSY = 2,
85 ARMul_DATA = 3,
86 ARMul_INTERRUPT = 4,
87 ARMul_DONE = 0,
88 ARMul_CANT = 1,
89 ARMul_INC = 3
90};
91
92// Instruction condition codes
93enum ConditionCode {
94 EQ = 0,
95 NE = 1,
96 CS = 2,
97 CC = 3,
98 MI = 4,
99 PL = 5,
100 VS = 6,
101 VC = 7,
102 HI = 8,
103 LS = 9,
104 GE = 10,
105 LT = 11,
106 GT = 12,
107 LE = 13,
108 AL = 14,
109 NV = 15,
110};
111
112// Flags for use with the APSR.
113enum : u32 {
114 NBIT = (1U << 31U),
115 ZBIT = (1 << 30),
116 CBIT = (1 << 29),
117 VBIT = (1 << 28),
118 QBIT = (1 << 27),
119 JBIT = (1 << 24),
120 EBIT = (1 << 9),
121 ABIT = (1 << 8),
122 IBIT = (1 << 7),
123 FBIT = (1 << 6),
124 TBIT = (1 << 5),
125
126 // Masks for groups of bits in the APSR.
127 MODEBITS = 0x1F,
128 INTBITS = 0x1C0,
129};
130
131// Values for Emulate.
132enum {
133 STOP = 0, // Stop
134 CHANGEMODE = 1, // Change mode
135 ONCE = 2, // Execute just one iteration
136 RUN = 3 // Continuous execution
137};
138
139struct ARMul_State final {
140public:
141 explicit ARMul_State(PrivilegeMode initial_mode);
142
143 void ChangePrivilegeMode(u32 new_mode);
144 void Reset();
145
146 // Reads/writes data in big/little endian format based on the
147 // state of the E (endian) bit in the APSR.
148 u8 ReadMemory8(u32 address) const;
149 u16 ReadMemory16(u32 address) const;
150 u32 ReadMemory32(u32 address) const;
151 u64 ReadMemory64(u32 address) const;
152 void WriteMemory8(u32 address, u8 data);
153 void WriteMemory16(u32 address, u16 data);
154 void WriteMemory32(u32 address, u32 data);
155 void WriteMemory64(u32 address, u64 data);
156
157 u32 ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const;
158 void WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2);
159
160 // Exclusive memory access functions
161 bool IsExclusiveMemoryAccess(u32 address) const {
162 return exclusive_state && exclusive_tag == (address & RESERVATION_GRANULE_MASK);
163 }
164 void SetExclusiveMemoryAddress(u32 address) {
165 exclusive_tag = address & RESERVATION_GRANULE_MASK;
166 exclusive_state = true;
167 }
168 void UnsetExclusiveMemoryAddress() {
169 exclusive_tag = 0xFFFFFFFF;
170 exclusive_state = false;
171 }
172
173 // Whether or not the given CPU is in big endian mode (E bit is set)
174 bool InBigEndianMode() const {
175 return (Cpsr & (1 << 9)) != 0;
176 }
177 // Whether or not the given CPU is in a mode other than user mode.
178 bool InAPrivilegedMode() const {
179 return (Mode != USER32MODE);
180 }
181 // Note that for the 3DS, a Thumb instruction will only ever be
182 // two bytes in size. Thus we don't need to worry about ThumbEE
183 // or Thumb-2 where instructions can be 4 bytes in length.
184 u32 GetInstructionSize() const {
185 return TFlag ? 2 : 4;
186 }
187
188 std::array<u32, 16> Reg{}; // The current register file
189 std::array<u32, 2> Reg_usr{};
190 std::array<u32, 2> Reg_svc{}; // R13_SVC R14_SVC
191 std::array<u32, 2> Reg_abort{}; // R13_ABORT R14_ABORT
192 std::array<u32, 2> Reg_undef{}; // R13 UNDEF R14 UNDEF
193 std::array<u32, 2> Reg_irq{}; // R13_IRQ R14_IRQ
194 std::array<u32, 7> Reg_firq{}; // R8---R14 FIRQ
195 std::array<u32, 7> Spsr{}; // The exception psr's
196 std::array<u32, CP15_REGISTER_COUNT> CP15{};
197
198 // FPSID, FPSCR, and FPEXC
199 std::array<u32, VFP_SYSTEM_REGISTER_COUNT> VFP{};
200
201 // VFPv2 and VFPv3-D16 has 16 doubleword registers (D0-D16 or S0-S31).
202 // VFPv3-D32/ASIMD may have up to 32 doubleword registers (D0-D31),
203 // and only 32 singleword registers are accessible (S0-S31).
204 std::array<u32, 64> ExtReg{};
205
206 u32 Emulate; // To start and stop emulation
207 u32 Cpsr; // The current PSR
208 u32 Spsr_copy;
209 u32 phys_pc;
210
211 u32 Mode; // The current mode
212 u32 Bank; // The current register bank
213
214 u32 NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed
215 unsigned int shifter_carry_out;
216
217 u32 TFlag; // Thumb state
218
219 unsigned long long NumInstrs; // The number of instructions executed
220 unsigned NumInstrsToExecute;
221
222 unsigned NresetSig; // Reset the processor
223 unsigned NfiqSig;
224 unsigned NirqSig;
225
226 unsigned abortSig;
227 unsigned NtransSig;
228 unsigned bigendSig;
229 unsigned syscallSig;
230
231 // TODO(bunnei): Move this cache to a better place - it should be per codeset (likely per
232 // process for our purposes), not per ARMul_State (which tracks CPU core state).
233 std::unordered_map<u32, std::size_t> instruction_cache;
234
235private:
236 void ResetMPCoreCP15Registers();
237
238 // Defines a reservation granule of 2 words, which protects the first 2 words starting at the
239 // tag. This is the smallest granule allowed by the v7 spec, and is coincidentally just large
240 // enough to support LDR/STREXD.
241 static const u32 RESERVATION_GRANULE_MASK = 0xFFFFFFF8;
242
243 u32 exclusive_tag; // The address for which the local monitor is in exclusive access mode
244 bool exclusive_state;
245};
diff --git a/src/core/arm/skyeye_common/armsupp.cpp b/src/core/arm/skyeye_common/armsupp.cpp
deleted file mode 100644
index 06aa1b075..000000000
--- a/src/core/arm/skyeye_common/armsupp.cpp
+++ /dev/null
@@ -1,189 +0,0 @@
1/* armsupp.c -- ARMulator support code: ARM6 Instruction Emulator.
2 Copyright (C) 1994 Advanced RISC Machines Ltd.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18#include "common/logging/log.h"
19#include "core/arm/skyeye_common/arm_regformat.h"
20#include "core/arm/skyeye_common/armstate.h"
21#include "core/arm/skyeye_common/armsupp.h"
22
23// Unsigned sum of absolute difference
24u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right) {
25 if (left > right)
26 return left - right;
27
28 return right - left;
29}
30
31// Add with carry, indicates if a carry-out or signed overflow occurred.
32u32 AddWithCarry(u32 left, u32 right, u32 carry_in, bool* carry_out_occurred,
33 bool* overflow_occurred) {
34 u64 unsigned_sum = (u64)left + (u64)right + (u64)carry_in;
35 s64 signed_sum = (s64)(s32)left + (s64)(s32)right + (s64)carry_in;
36 u64 result = (unsigned_sum & 0xFFFFFFFF);
37
38 if (carry_out_occurred)
39 *carry_out_occurred = (result != unsigned_sum);
40
41 if (overflow_occurred)
42 *overflow_occurred = ((s64)(s32)result != signed_sum);
43
44 return (u32)result;
45}
46
47// Compute whether an addition of A and B, giving RESULT, overflowed.
48bool AddOverflow(u32 a, u32 b, u32 result) {
49 return ((NEG(a) && NEG(b) && POS(result)) || (POS(a) && POS(b) && NEG(result)));
50}
51
52// Compute whether a subtraction of A and B, giving RESULT, overflowed.
53bool SubOverflow(u32 a, u32 b, u32 result) {
54 return ((NEG(a) && POS(b) && POS(result)) || (POS(a) && NEG(b) && NEG(result)));
55}
56
57// Returns true if the Q flag should be set as a result of overflow.
58bool ARMul_AddOverflowQ(u32 a, u32 b) {
59 u32 result = a + b;
60 if (((result ^ a) & (u32)0x80000000) && ((a ^ b) & (u32)0x80000000) == 0)
61 return true;
62
63 return false;
64}
65
66// 8-bit signed saturated addition
67u8 ARMul_SignedSaturatedAdd8(u8 left, u8 right) {
68 u8 result = left + right;
69
70 if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) == 0) {
71 if (left & 0x80)
72 result = 0x80;
73 else
74 result = 0x7F;
75 }
76
77 return result;
78}
79
80// 8-bit signed saturated subtraction
81u8 ARMul_SignedSaturatedSub8(u8 left, u8 right) {
82 u8 result = left - right;
83
84 if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) != 0) {
85 if (left & 0x80)
86 result = 0x80;
87 else
88 result = 0x7F;
89 }
90
91 return result;
92}
93
94// 16-bit signed saturated addition
95u16 ARMul_SignedSaturatedAdd16(u16 left, u16 right) {
96 u16 result = left + right;
97
98 if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) == 0) {
99 if (left & 0x8000)
100 result = 0x8000;
101 else
102 result = 0x7FFF;
103 }
104
105 return result;
106}
107
108// 16-bit signed saturated subtraction
109u16 ARMul_SignedSaturatedSub16(u16 left, u16 right) {
110 u16 result = left - right;
111
112 if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) != 0) {
113 if (left & 0x8000)
114 result = 0x8000;
115 else
116 result = 0x7FFF;
117 }
118
119 return result;
120}
121
122// 8-bit unsigned saturated addition
123u8 ARMul_UnsignedSaturatedAdd8(u8 left, u8 right) {
124 u8 result = left + right;
125
126 if (result < left)
127 result = 0xFF;
128
129 return result;
130}
131
132// 16-bit unsigned saturated addition
133u16 ARMul_UnsignedSaturatedAdd16(u16 left, u16 right) {
134 u16 result = left + right;
135
136 if (result < left)
137 result = 0xFFFF;
138
139 return result;
140}
141
142// 8-bit unsigned saturated subtraction
143u8 ARMul_UnsignedSaturatedSub8(u8 left, u8 right) {
144 if (left <= right)
145 return 0;
146
147 return left - right;
148}
149
150// 16-bit unsigned saturated subtraction
151u16 ARMul_UnsignedSaturatedSub16(u16 left, u16 right) {
152 if (left <= right)
153 return 0;
154
155 return left - right;
156}
157
158// Signed saturation.
159u32 ARMul_SignedSatQ(s32 value, u8 shift, bool* saturation_occurred) {
160 const u32 max = (1 << shift) - 1;
161 const s32 top = (value >> shift);
162
163 if (top > 0) {
164 *saturation_occurred = true;
165 return max;
166 } else if (top < -1) {
167 *saturation_occurred = true;
168 return ~max;
169 }
170
171 *saturation_occurred = false;
172 return (u32)value;
173}
174
175// Unsigned saturation
176u32 ARMul_UnsignedSatQ(s32 value, u8 shift, bool* saturation_occurred) {
177 const u32 max = (1 << shift) - 1;
178
179 if (value < 0) {
180 *saturation_occurred = true;
181 return 0;
182 } else if ((u32)value > max) {
183 *saturation_occurred = true;
184 return max;
185 }
186
187 *saturation_occurred = false;
188 return (u32)value;
189}
diff --git a/src/core/arm/skyeye_common/armsupp.h b/src/core/arm/skyeye_common/armsupp.h
deleted file mode 100644
index bf9299c07..000000000
--- a/src/core/arm/skyeye_common/armsupp.h
+++ /dev/null
@@ -1,32 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9#define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1))
10#define BIT(s, n) ((s >> (n)) & 1)
11
12#define POS(i) ((~(i)) >> 31)
13#define NEG(i) ((i) >> 31)
14
15bool AddOverflow(u32, u32, u32);
16bool SubOverflow(u32, u32, u32);
17
18u32 AddWithCarry(u32, u32, u32, bool*, bool*);
19bool ARMul_AddOverflowQ(u32, u32);
20
21u8 ARMul_SignedSaturatedAdd8(u8, u8);
22u8 ARMul_SignedSaturatedSub8(u8, u8);
23u16 ARMul_SignedSaturatedAdd16(u16, u16);
24u16 ARMul_SignedSaturatedSub16(u16, u16);
25
26u8 ARMul_UnsignedSaturatedAdd8(u8, u8);
27u16 ARMul_UnsignedSaturatedAdd16(u16, u16);
28u8 ARMul_UnsignedSaturatedSub8(u8, u8);
29u16 ARMul_UnsignedSaturatedSub16(u16, u16);
30u8 ARMul_UnsignedAbsoluteDifference(u8, u8);
31u32 ARMul_SignedSatQ(s32, u8, bool*);
32u32 ARMul_UnsignedSatQ(s32, u8, bool*);
diff --git a/src/core/arm/skyeye_common/vfp/asm_vfp.h b/src/core/arm/skyeye_common/vfp/asm_vfp.h
deleted file mode 100644
index 15b2394eb..000000000
--- a/src/core/arm/skyeye_common/vfp/asm_vfp.h
+++ /dev/null
@@ -1,83 +0,0 @@
1/*
2 * arch/arm/include/asm/vfp.h
3 *
4 * VFP register definitions.
5 * First, the standard VFP set.
6 */
7
8#pragma once
9
10// ARM11 MPCore FPSID Information
11// Note that these are used as values and not as flags.
12enum : u32 {
13 VFP_FPSID_IMPLMEN = 0x41, // Implementation code. Should be the same as cp15 0 c0 0
14 VFP_FPSID_SW = 0, // Software emulation bit value
15 VFP_FPSID_SUBARCH = 0x1, // Subarchitecture version number
16 VFP_FPSID_PARTNUM = 0x20, // Part number
17 VFP_FPSID_VARIANT = 0xB, // Variant number
18 VFP_FPSID_REVISION = 0x4 // Revision number
19};
20
21// FPEXC bits
22enum : u32 {
23 FPEXC_EX = (1U << 31U),
24 FPEXC_EN = (1 << 30),
25 FPEXC_DEX = (1 << 29),
26 FPEXC_FP2V = (1 << 28),
27 FPEXC_VV = (1 << 27),
28 FPEXC_TFV = (1 << 26),
29 FPEXC_LENGTH_BIT = (8),
30 FPEXC_LENGTH_MASK = (7 << FPEXC_LENGTH_BIT),
31 FPEXC_IDF = (1 << 7),
32 FPEXC_IXF = (1 << 4),
33 FPEXC_UFF = (1 << 3),
34 FPEXC_OFF = (1 << 2),
35 FPEXC_DZF = (1 << 1),
36 FPEXC_IOF = (1 << 0),
37 FPEXC_TRAP_MASK = (FPEXC_IDF | FPEXC_IXF | FPEXC_UFF | FPEXC_OFF | FPEXC_DZF | FPEXC_IOF)
38};
39
40// FPSCR Flags
41enum : u32 {
42 FPSCR_NFLAG = (1U << 31U), // Negative condition flag
43 FPSCR_ZFLAG = (1 << 30), // Zero condition flag
44 FPSCR_CFLAG = (1 << 29), // Carry condition flag
45 FPSCR_VFLAG = (1 << 28), // Overflow condition flag
46
47 FPSCR_QC = (1 << 27), // Cumulative saturation bit
48 FPSCR_AHP = (1 << 26), // Alternative half-precision control bit
49 FPSCR_DEFAULT_NAN = (1 << 25), // Default NaN mode control bit
50 FPSCR_FLUSH_TO_ZERO = (1 << 24), // Flush-to-zero mode control bit
51 FPSCR_RMODE_MASK = (3 << 22), // Rounding Mode bit mask
52 FPSCR_STRIDE_MASK = (3 << 20), // Vector stride bit mask
53 FPSCR_LENGTH_MASK = (7 << 16), // Vector length bit mask
54
55 FPSCR_IDE = (1 << 15), // Input Denormal exception trap enable.
56 FPSCR_IXE = (1 << 12), // Inexact exception trap enable
57 FPSCR_UFE = (1 << 11), // Undeflow exception trap enable
58 FPSCR_OFE = (1 << 10), // Overflow exception trap enable
59 FPSCR_DZE = (1 << 9), // Division by Zero exception trap enable
60 FPSCR_IOE = (1 << 8), // Invalid Operation exception trap enable
61
62 FPSCR_IDC = (1 << 7), // Input Denormal cumulative exception bit
63 FPSCR_IXC = (1 << 4), // Inexact cumulative exception bit
64 FPSCR_UFC = (1 << 3), // Undeflow cumulative exception bit
65 FPSCR_OFC = (1 << 2), // Overflow cumulative exception bit
66 FPSCR_DZC = (1 << 1), // Division by Zero cumulative exception bit
67 FPSCR_IOC = (1 << 0), // Invalid Operation cumulative exception bit
68};
69
70// FPSCR bit offsets
71enum : u32 {
72 FPSCR_RMODE_BIT = 22,
73 FPSCR_STRIDE_BIT = 20,
74 FPSCR_LENGTH_BIT = 16,
75};
76
77// FPSCR rounding modes
78enum : u32 {
79 FPSCR_ROUND_NEAREST = (0 << 22),
80 FPSCR_ROUND_PLUSINF = (1 << 22),
81 FPSCR_ROUND_MINUSINF = (2 << 22),
82 FPSCR_ROUND_TOZERO = (3 << 22)
83};
diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp
deleted file mode 100644
index 0466b999a..000000000
--- a/src/core/arm/skyeye_common/vfp/vfp.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
1/*
2 armvfp.c - ARM VFPv3 emulation unit
3 Copyright (C) 2003 Skyeye Develop Group
4 for help please send mail to <skyeye-developer@lists.gro.clinux.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21/* Note: this file handles interface with arm core and vfp registers */
22
23#include "common/common_funcs.h"
24#include "common/common_types.h"
25#include "common/logging/log.h"
26#include "core/arm/skyeye_common/armstate.h"
27#include "core/arm/skyeye_common/vfp/asm_vfp.h"
28#include "core/arm/skyeye_common/vfp/vfp.h"
29
30void VFPInit(ARMul_State* state) {
31 state->VFP[VFP_FPSID] = VFP_FPSID_IMPLMEN << 24 | VFP_FPSID_SW << 23 | VFP_FPSID_SUBARCH << 16 |
32 VFP_FPSID_PARTNUM << 8 | VFP_FPSID_VARIANT << 4 | VFP_FPSID_REVISION;
33 state->VFP[VFP_FPEXC] = 0;
34 state->VFP[VFP_FPSCR] = 0;
35
36 // ARM11 MPCore instruction register reset values.
37 state->VFP[VFP_FPINST] = 0xEE000A00;
38 state->VFP[VFP_FPINST2] = 0;
39
40 // ARM11 MPCore feature register values.
41 state->VFP[VFP_MVFR0] = 0x11111111;
42 state->VFP[VFP_MVFR1] = 0;
43}
44
45void VMOVBRS(ARMul_State* state, u32 to_arm, u32 t, u32 n, u32* value) {
46 if (to_arm) {
47 *value = state->ExtReg[n];
48 } else {
49 state->ExtReg[n] = *value;
50 }
51}
52
53void VMOVBRRD(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2) {
54 if (to_arm) {
55 *value2 = state->ExtReg[n * 2 + 1];
56 *value1 = state->ExtReg[n * 2];
57 } else {
58 state->ExtReg[n * 2 + 1] = *value2;
59 state->ExtReg[n * 2] = *value1;
60 }
61}
62void VMOVBRRSS(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2) {
63 if (to_arm) {
64 *value1 = state->ExtReg[n + 0];
65 *value2 = state->ExtReg[n + 1];
66 } else {
67 state->ExtReg[n + 0] = *value1;
68 state->ExtReg[n + 1] = *value2;
69 }
70}
71
72void VMOVI(ARMul_State* state, u32 single, u32 d, u32 imm) {
73 if (single) {
74 state->ExtReg[d] = imm;
75 } else {
76 /* Check endian please */
77 state->ExtReg[d * 2 + 1] = imm;
78 state->ExtReg[d * 2] = 0;
79 }
80}
81void VMOVR(ARMul_State* state, u32 single, u32 d, u32 m) {
82 if (single) {
83 state->ExtReg[d] = state->ExtReg[m];
84 } else {
85 /* Check endian please */
86 state->ExtReg[d * 2 + 1] = state->ExtReg[m * 2 + 1];
87 state->ExtReg[d * 2] = state->ExtReg[m * 2];
88 }
89}
90
91/* Miscellaneous functions */
92s32 vfp_get_float(ARMul_State* state, unsigned int reg) {
93 LOG_TRACE(Core_ARM, "VFP get float: s%d=[%08x]", reg, state->ExtReg[reg]);
94 return state->ExtReg[reg];
95}
96
97void vfp_put_float(ARMul_State* state, s32 val, unsigned int reg) {
98 LOG_TRACE(Core_ARM, "VFP put float: s%d <= [%08x]", reg, val);
99 state->ExtReg[reg] = val;
100}
101
102u64 vfp_get_double(ARMul_State* state, unsigned int reg) {
103 u64 result = ((u64)state->ExtReg[reg * 2 + 1]) << 32 | state->ExtReg[reg * 2];
104 LOG_TRACE(Core_ARM, "VFP get double: s[%d-%d]=[%016llx]", reg * 2 + 1, reg * 2, result);
105 return result;
106}
107
108void vfp_put_double(ARMul_State* state, u64 val, unsigned int reg) {
109 LOG_TRACE(Core_ARM, "VFP put double: s[%d-%d] <= [%08x-%08x]", reg * 2 + 1, reg * 2,
110 (u32)(val >> 32), (u32)(val & 0xffffffff));
111 state->ExtReg[reg * 2] = (u32)(val & 0xffffffff);
112 state->ExtReg[reg * 2 + 1] = (u32)(val >> 32);
113}
114
115/*
116 * Process bitmask of exception conditions. (from vfpmodule.c)
117 */
118void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr) {
119 LOG_TRACE(Core_ARM, "VFP: raising exceptions %08x", exceptions);
120
121 if (exceptions == VFP_EXCEPTION_ERROR) {
122 LOG_CRITICAL(Core_ARM, "unhandled bounce %x", inst);
123 Crash();
124 }
125
126 /*
127 * If any of the status flags are set, update the FPSCR.
128 * Comparison instructions always return at least one of
129 * these flags set.
130 */
131 if (exceptions & (FPSCR_NFLAG | FPSCR_ZFLAG | FPSCR_CFLAG | FPSCR_VFLAG))
132 fpscr &= ~(FPSCR_NFLAG | FPSCR_ZFLAG | FPSCR_CFLAG | FPSCR_VFLAG);
133
134 fpscr |= exceptions;
135
136 state->VFP[VFP_FPSCR] = fpscr;
137}
diff --git a/src/core/arm/skyeye_common/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h
deleted file mode 100644
index fe9c4dac8..000000000
--- a/src/core/arm/skyeye_common/vfp/vfp.h
+++ /dev/null
@@ -1,43 +0,0 @@
1/*
2 vfp/vfp.h - ARM VFPv3 emulation unit - vfp interface
3 Copyright (C) 2003 Skyeye Develop Group
4 for help please send mail to <skyeye-developer@lists.gro.clinux.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21#pragma once
22
23#include "core/arm/skyeye_common/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */
24
25#define VFP_DEBUG_UNTESTED(x) LOG_TRACE(Core_ARM, "in func %s, " #x " untested", __FUNCTION__);
26#define CHECK_VFP_ENABLED
27#define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
28
29void VFPInit(ARMul_State* state);
30
31s32 vfp_get_float(ARMul_State* state, u32 reg);
32void vfp_put_float(ARMul_State* state, s32 val, u32 reg);
33u64 vfp_get_double(ARMul_State* state, u32 reg);
34void vfp_put_double(ARMul_State* state, u64 val, u32 reg);
35void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr);
36u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
37u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
38
39void VMOVBRS(ARMul_State* state, u32 to_arm, u32 t, u32 n, u32* value);
40void VMOVBRRD(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2);
41void VMOVBRRSS(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2);
42void VMOVI(ARMul_State* state, u32 single, u32 d, u32 imm);
43void VMOVR(ARMul_State* state, u32 single, u32 d, u32 imm);
diff --git a/src/core/arm/skyeye_common/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h
deleted file mode 100644
index 1eba71b48..000000000
--- a/src/core/arm/skyeye_common/vfp/vfp_helper.h
+++ /dev/null
@@ -1,433 +0,0 @@
1/*
2 vfp/vfp.h - ARM VFPv3 emulation unit - SoftFloat lib helper
3 Copyright (C) 2003 Skyeye Develop Group
4 for help please send mail to <skyeye-developer@lists.gro.clinux.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21/*
22 * The following code is derivative from Linux Android kernel vfp
23 * floating point support.
24 *
25 * Copyright (C) 2004 ARM Limited.
26 * Written by Deep Blue Solutions Limited.
27 *
28 * This program is free software; you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License version 2 as
30 * published by the Free Software Foundation.
31 */
32
33#pragma once
34
35#include <cstdio>
36#include "common/common_types.h"
37#include "core/arm/skyeye_common/armstate.h"
38#include "core/arm/skyeye_common/vfp/asm_vfp.h"
39
40#define do_div(n, base) \
41 { n /= base; }
42
43enum : u32 {
44 FOP_MASK = 0x00b00040,
45 FOP_FMAC = 0x00000000,
46 FOP_FNMAC = 0x00000040,
47 FOP_FMSC = 0x00100000,
48 FOP_FNMSC = 0x00100040,
49 FOP_FMUL = 0x00200000,
50 FOP_FNMUL = 0x00200040,
51 FOP_FADD = 0x00300000,
52 FOP_FSUB = 0x00300040,
53 FOP_FDIV = 0x00800000,
54 FOP_EXT = 0x00b00040
55};
56
57#define FOP_TO_IDX(inst) ((inst & 0x00b00000) >> 20 | (inst & (1 << 6)) >> 4)
58
59enum : u32 {
60 FEXT_MASK = 0x000f0080,
61 FEXT_FCPY = 0x00000000,
62 FEXT_FABS = 0x00000080,
63 FEXT_FNEG = 0x00010000,
64 FEXT_FSQRT = 0x00010080,
65 FEXT_FCMP = 0x00040000,
66 FEXT_FCMPE = 0x00040080,
67 FEXT_FCMPZ = 0x00050000,
68 FEXT_FCMPEZ = 0x00050080,
69 FEXT_FCVT = 0x00070080,
70 FEXT_FUITO = 0x00080000,
71 FEXT_FSITO = 0x00080080,
72 FEXT_FTOUI = 0x000c0000,
73 FEXT_FTOUIZ = 0x000c0080,
74 FEXT_FTOSI = 0x000d0000,
75 FEXT_FTOSIZ = 0x000d0080
76};
77
78#define FEXT_TO_IDX(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7)
79
80#define vfp_get_sd(inst) ((inst & 0x0000f000) >> 11 | (inst & (1 << 22)) >> 22)
81#define vfp_get_dd(inst) ((inst & 0x0000f000) >> 12 | (inst & (1 << 22)) >> 18)
82#define vfp_get_sm(inst) ((inst & 0x0000000f) << 1 | (inst & (1 << 5)) >> 5)
83#define vfp_get_dm(inst) ((inst & 0x0000000f) | (inst & (1 << 5)) >> 1)
84#define vfp_get_sn(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7)
85#define vfp_get_dn(inst) ((inst & 0x000f0000) >> 16 | (inst & (1 << 7)) >> 3)
86
87#define vfp_single(inst) (((inst)&0x0000f00) == 0xa00)
88
89inline u32 vfp_shiftright32jamming(u32 val, unsigned int shift) {
90 if (shift) {
91 if (shift < 32)
92 val = val >> shift | ((val << (32 - shift)) != 0);
93 else
94 val = val != 0;
95 }
96 return val;
97}
98
99inline u64 vfp_shiftright64jamming(u64 val, unsigned int shift) {
100 if (shift) {
101 if (shift < 64)
102 val = val >> shift | ((val << (64 - shift)) != 0);
103 else
104 val = val != 0;
105 }
106 return val;
107}
108
109inline u32 vfp_hi64to32jamming(u64 val) {
110 u32 v;
111 u32 highval = val >> 32;
112 u32 lowval = val & 0xffffffff;
113
114 if (lowval >= 1)
115 v = highval | 1;
116 else
117 v = highval;
118
119 return v;
120}
121
122inline void add128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml) {
123 *resl = nl + ml;
124 *resh = nh + mh;
125 if (*resl < nl)
126 *resh += 1;
127}
128
129inline void sub128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml) {
130 *resl = nl - ml;
131 *resh = nh - mh;
132 if (*resl > nl)
133 *resh -= 1;
134}
135
136inline void mul64to128(u64* resh, u64* resl, u64 n, u64 m) {
137 u32 nh, nl, mh, ml;
138 u64 rh, rma, rmb, rl;
139
140 nl = static_cast<u32>(n);
141 ml = static_cast<u32>(m);
142 rl = (u64)nl * ml;
143
144 nh = n >> 32;
145 rma = (u64)nh * ml;
146
147 mh = m >> 32;
148 rmb = (u64)nl * mh;
149 rma += rmb;
150
151 rh = (u64)nh * mh;
152 rh += ((u64)(rma < rmb) << 32) + (rma >> 32);
153
154 rma <<= 32;
155 rl += rma;
156 rh += (rl < rma);
157
158 *resl = rl;
159 *resh = rh;
160}
161
162inline void shift64left(u64* resh, u64* resl, u64 n) {
163 *resh = n >> 63;
164 *resl = n << 1;
165}
166
167inline u64 vfp_hi64multiply64(u64 n, u64 m) {
168 u64 rh, rl;
169 mul64to128(&rh, &rl, n, m);
170 return rh | (rl != 0);
171}
172
173inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m) {
174 u64 mh, ml, remh, reml, termh, terml, z;
175
176 if (nh >= m)
177 return ~0ULL;
178 mh = m >> 32;
179 if (mh << 32 <= nh) {
180 z = 0xffffffff00000000ULL;
181 } else {
182 z = nh;
183 do_div(z, mh);
184 z <<= 32;
185 }
186 mul64to128(&termh, &terml, m, z);
187 sub128(&remh, &reml, nh, nl, termh, terml);
188 ml = m << 32;
189 while ((s64)remh < 0) {
190 z -= 0x100000000ULL;
191 add128(&remh, &reml, remh, reml, mh, ml);
192 }
193 remh = (remh << 32) | (reml >> 32);
194 if (mh << 32 <= remh) {
195 z |= 0xffffffff;
196 } else {
197 do_div(remh, mh);
198 z |= remh;
199 }
200 return z;
201}
202
203// Operations on unpacked elements
204#define vfp_sign_negate(sign) (sign ^ 0x8000)
205
206// Single-precision
207struct vfp_single {
208 s16 exponent;
209 u16 sign;
210 u32 significand;
211};
212
213// VFP_SINGLE_MANTISSA_BITS - number of bits in the mantissa
214// VFP_SINGLE_EXPONENT_BITS - number of bits in the exponent
215// VFP_SINGLE_LOW_BITS - number of low bits in the unpacked significand
216// which are not propagated to the float upon packing.
217#define VFP_SINGLE_MANTISSA_BITS (23)
218#define VFP_SINGLE_EXPONENT_BITS (8)
219#define VFP_SINGLE_LOW_BITS (32 - VFP_SINGLE_MANTISSA_BITS - 2)
220#define VFP_SINGLE_LOW_BITS_MASK ((1 << VFP_SINGLE_LOW_BITS) - 1)
221
222// The bit in an unpacked float which indicates that it is a quiet NaN
223#define VFP_SINGLE_SIGNIFICAND_QNAN (1 << (VFP_SINGLE_MANTISSA_BITS - 1 + VFP_SINGLE_LOW_BITS))
224
225// Operations on packed single-precision numbers
226#define vfp_single_packed_sign(v) ((v)&0x80000000)
227#define vfp_single_packed_negate(v) ((v) ^ 0x80000000)
228#define vfp_single_packed_abs(v) ((v) & ~0x80000000)
229#define vfp_single_packed_exponent(v) \
230 (((v) >> VFP_SINGLE_MANTISSA_BITS) & ((1 << VFP_SINGLE_EXPONENT_BITS) - 1))
231#define vfp_single_packed_mantissa(v) ((v) & ((1 << VFP_SINGLE_MANTISSA_BITS) - 1))
232
233enum : u32 {
234 VFP_NUMBER = (1 << 0),
235 VFP_ZERO = (1 << 1),
236 VFP_DENORMAL = (1 << 2),
237 VFP_INFINITY = (1 << 3),
238 VFP_NAN = (1 << 4),
239 VFP_NAN_SIGNAL = (1 << 5),
240
241 VFP_QNAN = (VFP_NAN),
242 VFP_SNAN = (VFP_NAN | VFP_NAN_SIGNAL)
243};
244
245inline int vfp_single_type(const vfp_single* s) {
246 int type = VFP_NUMBER;
247 if (s->exponent == 255) {
248 if (s->significand == 0)
249 type = VFP_INFINITY;
250 else if (s->significand & VFP_SINGLE_SIGNIFICAND_QNAN)
251 type = VFP_QNAN;
252 else
253 type = VFP_SNAN;
254 } else if (s->exponent == 0) {
255 if (s->significand == 0)
256 type |= VFP_ZERO;
257 else
258 type |= VFP_DENORMAL;
259 }
260 return type;
261}
262
263// Unpack a single-precision float. Note that this returns the magnitude
264// of the single-precision float mantissa with the 1. if necessary,
265// aligned to bit 30.
266inline u32 vfp_single_unpack(vfp_single* s, s32 val, u32 fpscr) {
267 u32 exceptions = 0;
268 s->sign = vfp_single_packed_sign(val) >> 16, s->exponent = vfp_single_packed_exponent(val);
269
270 u32 significand = ((u32)val << (32 - VFP_SINGLE_MANTISSA_BITS)) >> 2;
271 if (s->exponent && s->exponent != 255)
272 significand |= 0x40000000;
273 s->significand = significand;
274
275 // If flush-to-zero mode is enabled, turn the denormal into zero.
276 // On a VFPv2 architecture, the sign of the zero is always positive.
277 if ((fpscr & FPSCR_FLUSH_TO_ZERO) != 0 && (vfp_single_type(s) & VFP_DENORMAL) != 0) {
278 s->sign = 0;
279 s->exponent = 0;
280 s->significand = 0;
281 exceptions |= FPSCR_IDC;
282 }
283 return exceptions;
284}
285
286// Re-pack a single-precision float. This assumes that the float is
287// already normalised such that the MSB is bit 30, _not_ bit 31.
288inline s32 vfp_single_pack(const vfp_single* s) {
289 u32 val = (s->sign << 16) + (s->exponent << VFP_SINGLE_MANTISSA_BITS) +
290 (s->significand >> VFP_SINGLE_LOW_BITS);
291 return (s32)val;
292}
293
294u32 vfp_single_normaliseround(ARMul_State* state, int sd, vfp_single* vs, u32 fpscr, u32 exceptions,
295 const char* func);
296
297// Double-precision
298struct vfp_double {
299 s16 exponent;
300 u16 sign;
301 u64 significand;
302};
303
304// VFP_REG_ZERO is a special register number for vfp_get_double
305// which returns (double)0.0. This is useful for the compare with
306// zero instructions.
307#ifdef CONFIG_VFPv3
308#define VFP_REG_ZERO 32
309#else
310#define VFP_REG_ZERO 16
311#endif
312
313#define VFP_DOUBLE_MANTISSA_BITS (52)
314#define VFP_DOUBLE_EXPONENT_BITS (11)
315#define VFP_DOUBLE_LOW_BITS (64 - VFP_DOUBLE_MANTISSA_BITS - 2)
316#define VFP_DOUBLE_LOW_BITS_MASK ((1 << VFP_DOUBLE_LOW_BITS) - 1)
317
318// The bit in an unpacked double which indicates that it is a quiet NaN
319#define VFP_DOUBLE_SIGNIFICAND_QNAN (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1 + VFP_DOUBLE_LOW_BITS))
320
321// Operations on packed single-precision numbers
322#define vfp_double_packed_sign(v) ((v) & (1ULL << 63))
323#define vfp_double_packed_negate(v) ((v) ^ (1ULL << 63))
324#define vfp_double_packed_abs(v) ((v) & ~(1ULL << 63))
325#define vfp_double_packed_exponent(v) \
326 (((v) >> VFP_DOUBLE_MANTISSA_BITS) & ((1 << VFP_DOUBLE_EXPONENT_BITS) - 1))
327#define vfp_double_packed_mantissa(v) ((v) & ((1ULL << VFP_DOUBLE_MANTISSA_BITS) - 1))
328
329inline int vfp_double_type(const vfp_double* s) {
330 int type = VFP_NUMBER;
331 if (s->exponent == 2047) {
332 if (s->significand == 0)
333 type = VFP_INFINITY;
334 else if (s->significand & VFP_DOUBLE_SIGNIFICAND_QNAN)
335 type = VFP_QNAN;
336 else
337 type = VFP_SNAN;
338 } else if (s->exponent == 0) {
339 if (s->significand == 0)
340 type |= VFP_ZERO;
341 else
342 type |= VFP_DENORMAL;
343 }
344 return type;
345}
346
347// Unpack a double-precision float. Note that this returns the magnitude
348// of the double-precision float mantissa with the 1. if necessary,
349// aligned to bit 62.
350inline u32 vfp_double_unpack(vfp_double* s, s64 val, u32 fpscr) {
351 u32 exceptions = 0;
352 s->sign = vfp_double_packed_sign(val) >> 48;
353 s->exponent = vfp_double_packed_exponent(val);
354
355 u64 significand = ((u64)val << (64 - VFP_DOUBLE_MANTISSA_BITS)) >> 2;
356 if (s->exponent && s->exponent != 2047)
357 significand |= (1ULL << 62);
358 s->significand = significand;
359
360 // If flush-to-zero mode is enabled, turn the denormal into zero.
361 // On a VFPv2 architecture, the sign of the zero is always positive.
362 if ((fpscr & FPSCR_FLUSH_TO_ZERO) != 0 && (vfp_double_type(s) & VFP_DENORMAL) != 0) {
363 s->sign = 0;
364 s->exponent = 0;
365 s->significand = 0;
366 exceptions |= FPSCR_IDC;
367 }
368 return exceptions;
369}
370
371// Re-pack a double-precision float. This assumes that the float is
372// already normalised such that the MSB is bit 30, _not_ bit 31.
373inline s64 vfp_double_pack(const vfp_double* s) {
374 u64 val = ((u64)s->sign << 48) + ((u64)s->exponent << VFP_DOUBLE_MANTISSA_BITS) +
375 (s->significand >> VFP_DOUBLE_LOW_BITS);
376 return (s64)val;
377}
378
379u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand);
380
381// A special flag to tell the normalisation code not to normalise.
382#define VFP_NAN_FLAG 0x100
383
384// A bit pattern used to indicate the initial (unset) value of the
385// exception mask, in case nothing handles an instruction. This
386// doesn't include the NAN flag, which get masked out before
387// we check for an error.
388#define VFP_EXCEPTION_ERROR ((u32)-1 & ~VFP_NAN_FLAG)
389
390// A flag to tell vfp instruction type.
391// OP_SCALAR - This operation always operates in scalar mode
392// OP_SD - The instruction exceptionally writes to a single precision result.
393// OP_DD - The instruction exceptionally writes to a double precision result.
394// OP_SM - The instruction exceptionally reads from a single precision operand.
395enum : u32 { OP_SCALAR = (1 << 0), OP_SD = (1 << 1), OP_DD = (1 << 1), OP_SM = (1 << 2) };
396
397struct op {
398 u32 (*const fn)(ARMul_State* state, int dd, int dn, int dm, u32 fpscr);
399 u32 flags;
400};
401
402inline u32 fls(u32 x) {
403 int r = 32;
404
405 if (!x)
406 return 0;
407 if (!(x & 0xffff0000u)) {
408 x <<= 16;
409 r -= 16;
410 }
411 if (!(x & 0xff000000u)) {
412 x <<= 8;
413 r -= 8;
414 }
415 if (!(x & 0xf0000000u)) {
416 x <<= 4;
417 r -= 4;
418 }
419 if (!(x & 0xc0000000u)) {
420 x <<= 2;
421 r -= 2;
422 }
423 if (!(x & 0x80000000u)) {
424 x <<= 1;
425 r -= 1;
426 }
427 return r;
428}
429
430u32 vfp_double_multiply(vfp_double* vdd, vfp_double* vdn, vfp_double* vdm, u32 fpscr);
431u32 vfp_double_add(vfp_double* vdd, vfp_double* vdn, vfp_double* vdm, u32 fpscr);
432u32 vfp_double_normaliseround(ARMul_State* state, int dd, vfp_double* vd, u32 fpscr, u32 exceptions,
433 const char* func);
diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
deleted file mode 100644
index e5cb54aab..000000000
--- a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
+++ /dev/null
@@ -1,1247 +0,0 @@
1/*
2 vfp/vfpdouble.c - ARM VFPv3 emulation unit - SoftFloat double instruction
3 Copyright (C) 2003 Skyeye Develop Group
4 for help please send mail to <skyeye-developer@lists.gro.clinux.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21/*
22 * This code is derived in part from :
23 * - Android kernel
24 * - John R. Housers softfloat library, which
25 * carries the following notice:
26 *
27 * ===========================================================================
28 * This C source file is part of the SoftFloat IEC/IEEE Floating-point
29 * Arithmetic Package, Release 2.
30 *
31 * Written by John R. Hauser. This work was made possible in part by the
32 * International Computer Science Institute, located at Suite 600, 1947 Center
33 * Street, Berkeley, California 94704. Funding was partially provided by the
34 * National Science Foundation under grant MIP-9311980. The original version
35 * of this code was written as part of a project to build a fixed-point vector
36 * processor in collaboration with the University of California at Berkeley,
37 * overseen by Profs. Nelson Morgan and John Wawrzynek. More information
38 * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
39 * arithmetic/softfloat.html'.
40 *
41 * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
42 * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
43 * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
44 * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
45 * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
46 *
47 * Derivative works are acceptable, even for commercial purposes, so long as
48 * (1) they include prominent notice that the work is derivative, and (2) they
49 * include prominent notice akin to these three paragraphs for those parts of
50 * this code that are retained.
51 * ===========================================================================
52 */
53
54#include <algorithm>
55#include "common/logging/log.h"
56#include "core/arm/skyeye_common/vfp/asm_vfp.h"
57#include "core/arm/skyeye_common/vfp/vfp.h"
58#include "core/arm/skyeye_common/vfp/vfp_helper.h"
59
60static struct vfp_double vfp_double_default_qnan = {
61 2047, 0, VFP_DOUBLE_SIGNIFICAND_QNAN,
62};
63
64static void vfp_double_dump(const char* str, struct vfp_double* d) {
65 LOG_TRACE(Core_ARM, "VFP: %s: sign=%d exponent=%d significand=%016llx", str, d->sign != 0,
66 d->exponent, d->significand);
67}
68
69static void vfp_double_normalise_denormal(struct vfp_double* vd) {
70 int bits = 31 - fls((u32)(vd->significand >> 32));
71 if (bits == 31)
72 bits = 63 - fls((u32)vd->significand);
73
74 vfp_double_dump("normalise_denormal: in", vd);
75
76 if (bits) {
77 vd->exponent -= bits - 1;
78 vd->significand <<= bits;
79 }
80
81 vfp_double_dump("normalise_denormal: out", vd);
82}
83
84u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double* vd, u32 fpscr,
85 u32 exceptions, const char* func) {
86 u64 significand, incr;
87 int exponent, shift, underflow;
88 u32 rmode;
89
90 vfp_double_dump("pack: in", vd);
91
92 /*
93 * Infinities and NaNs are a special case.
94 */
95 if (vd->exponent == 2047 && (vd->significand == 0 || exceptions))
96 goto pack;
97
98 /*
99 * Special-case zero.
100 */
101 if (vd->significand == 0) {
102 vd->exponent = 0;
103 goto pack;
104 }
105
106 exponent = vd->exponent;
107 significand = vd->significand;
108
109 shift = 32 - fls((u32)(significand >> 32));
110 if (shift == 32)
111 shift = 64 - fls((u32)significand);
112 if (shift) {
113 exponent -= shift;
114 significand <<= shift;
115 }
116
117#if 1
118 vd->exponent = exponent;
119 vd->significand = significand;
120 vfp_double_dump("pack: normalised", vd);
121#endif
122
123 /*
124 * Tiny number?
125 */
126 underflow = exponent < 0;
127 if (underflow) {
128 significand = vfp_shiftright64jamming(significand, -exponent);
129 exponent = 0;
130#if 1
131 vd->exponent = exponent;
132 vd->significand = significand;
133 vfp_double_dump("pack: tiny number", vd);
134#endif
135 if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1)))
136 underflow = 0;
137
138 int type = vfp_double_type(vd);
139
140 if ((type & VFP_DENORMAL) && (fpscr & FPSCR_FLUSH_TO_ZERO)) {
141 // Flush denormal to positive 0
142 significand = 0;
143
144 vd->sign = 0;
145 vd->significand = significand;
146
147 underflow = 0;
148 exceptions |= FPSCR_UFC;
149 }
150 }
151
152 /*
153 * Select rounding increment.
154 */
155 incr = 0;
156 rmode = fpscr & FPSCR_RMODE_MASK;
157
158 if (rmode == FPSCR_ROUND_NEAREST) {
159 incr = 1ULL << VFP_DOUBLE_LOW_BITS;
160 if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0)
161 incr -= 1;
162 } else if (rmode == FPSCR_ROUND_TOZERO) {
163 incr = 0;
164 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0))
165 incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1;
166
167 LOG_TRACE(Core_ARM, "VFP: rounding increment = 0x%08llx", incr);
168
169 /*
170 * Is our rounding going to overflow?
171 */
172 if ((significand + incr) < significand) {
173 exponent += 1;
174 significand = (significand >> 1) | (significand & 1);
175 incr >>= 1;
176#if 1
177 vd->exponent = exponent;
178 vd->significand = significand;
179 vfp_double_dump("pack: overflow", vd);
180#endif
181 }
182
183 /*
184 * If any of the low bits (which will be shifted out of the
185 * number) are non-zero, the result is inexact.
186 */
187 if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1))
188 exceptions |= FPSCR_IXC;
189
190 /*
191 * Do our rounding.
192 */
193 significand += incr;
194
195 /*
196 * Infinity?
197 */
198 if (exponent >= 2046) {
199 exceptions |= FPSCR_OFC | FPSCR_IXC;
200 if (incr == 0) {
201 vd->exponent = 2045;
202 vd->significand = 0x7fffffffffffffffULL;
203 } else {
204 vd->exponent = 2047; /* infinity */
205 vd->significand = 0;
206 }
207 } else {
208 if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0)
209 exponent = 0;
210 if (exponent || significand > 0x8000000000000000ULL)
211 underflow = 0;
212 if (underflow)
213 exceptions |= FPSCR_UFC;
214 vd->exponent = exponent;
215 vd->significand = significand >> 1;
216 }
217
218pack:
219 vfp_double_dump("pack: final", vd);
220 {
221 s64 d = vfp_double_pack(vd);
222 LOG_TRACE(Core_ARM, "VFP: %s: d(d%d)=%016llx exceptions=%08x", func, dd, d, exceptions);
223 vfp_put_double(state, d, dd);
224 }
225 return exceptions;
226}
227
228/*
229 * Propagate the NaN, setting exceptions if it is signalling.
230 * 'n' is always a NaN. 'm' may be a number, NaN or infinity.
231 */
232static u32 vfp_propagate_nan(struct vfp_double* vdd, struct vfp_double* vdn, struct vfp_double* vdm,
233 u32 fpscr) {
234 struct vfp_double* nan;
235 int tn, tm = 0;
236
237 tn = vfp_double_type(vdn);
238
239 if (vdm)
240 tm = vfp_double_type(vdm);
241
242 if (fpscr & FPSCR_DEFAULT_NAN)
243 /*
244 * Default NaN mode - always returns a quiet NaN
245 */
246 nan = &vfp_double_default_qnan;
247 else {
248 /*
249 * Contemporary mode - select the first signalling
250 * NAN, or if neither are signalling, the first
251 * quiet NAN.
252 */
253 if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN))
254 nan = vdn;
255 else
256 nan = vdm;
257 /*
258 * Make the NaN quiet.
259 */
260 nan->significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
261 }
262
263 *vdd = *nan;
264
265 /*
266 * If one was a signalling NAN, raise invalid operation.
267 */
268 return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
269}
270
271/*
272 * Extended operations
273 */
274static u32 vfp_double_fabs(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
275 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
276 vfp_put_double(state, vfp_double_packed_abs(vfp_get_double(state, dm)), dd);
277 return 0;
278}
279
280static u32 vfp_double_fcpy(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
281 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
282 vfp_put_double(state, vfp_get_double(state, dm), dd);
283 return 0;
284}
285
286static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
287 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
288 vfp_put_double(state, vfp_double_packed_negate(vfp_get_double(state, dm)), dd);
289 return 0;
290}
291
292static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
293 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
294 vfp_double vdm, vdd, *vdp;
295 int ret, tm;
296 u32 exceptions = 0;
297
298 exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr);
299
300 tm = vfp_double_type(&vdm);
301 if (tm & (VFP_NAN | VFP_INFINITY)) {
302 vdp = &vdd;
303
304 if (tm & VFP_NAN)
305 ret = vfp_propagate_nan(vdp, &vdm, nullptr, fpscr);
306 else if (vdm.sign == 0) {
307 sqrt_copy:
308 vdp = &vdm;
309 ret = 0;
310 } else {
311 sqrt_invalid:
312 vdp = &vfp_double_default_qnan;
313 ret = FPSCR_IOC;
314 }
315 vfp_put_double(state, vfp_double_pack(vdp), dd);
316 return ret;
317 }
318
319 /*
320 * sqrt(+/- 0) == +/- 0
321 */
322 if (tm & VFP_ZERO)
323 goto sqrt_copy;
324
325 /*
326 * Normalise a denormalised number
327 */
328 if (tm & VFP_DENORMAL)
329 vfp_double_normalise_denormal(&vdm);
330
331 /*
332 * sqrt(<0) = invalid
333 */
334 if (vdm.sign)
335 goto sqrt_invalid;
336
337 vfp_double_dump("sqrt", &vdm);
338
339 /*
340 * Estimate the square root.
341 */
342 vdd.sign = 0;
343 vdd.exponent = ((vdm.exponent - 1023) >> 1) + 1023;
344 vdd.significand = (u64)vfp_estimate_sqrt_significand(vdm.exponent, vdm.significand >> 32) << 31;
345
346 vfp_double_dump("sqrt estimate1", &vdd);
347
348 vdm.significand >>= 1 + (vdm.exponent & 1);
349 vdd.significand += 2 + vfp_estimate_div128to64(vdm.significand, 0, vdd.significand);
350
351 vfp_double_dump("sqrt estimate2", &vdd);
352
353 /*
354 * And now adjust.
355 */
356 if ((vdd.significand & VFP_DOUBLE_LOW_BITS_MASK) <= 5) {
357 if (vdd.significand < 2) {
358 vdd.significand = ~0ULL;
359 } else {
360 u64 termh, terml, remh, reml;
361 vdm.significand <<= 2;
362 mul64to128(&termh, &terml, vdd.significand, vdd.significand);
363 sub128(&remh, &reml, vdm.significand, 0, termh, terml);
364 while ((s64)remh < 0) {
365 vdd.significand -= 1;
366 shift64left(&termh, &terml, vdd.significand);
367 terml |= 1;
368 add128(&remh, &reml, remh, reml, termh, terml);
369 }
370 vdd.significand |= (remh | reml) != 0;
371 }
372 }
373 vdd.significand = vfp_shiftright64jamming(vdd.significand, 1);
374
375 exceptions |= vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fsqrt");
376
377 return exceptions;
378}
379
380/*
381 * Equal := ZC
382 * Less than := N
383 * Greater than := C
384 * Unordered := CV
385 */
386static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u32 fpscr) {
387 s64 d, m;
388 u32 ret = 0;
389
390 LOG_TRACE(Core_ARM, "In %s, state=0x%p, fpscr=0x%x", __FUNCTION__, state, fpscr);
391 m = vfp_get_double(state, dm);
392 if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) {
393 ret |= FPSCR_CFLAG | FPSCR_VFLAG;
394 if (signal_on_qnan ||
395 !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
396 /*
397 * Signalling NaN, or signalling on quiet NaN
398 */
399 ret |= FPSCR_IOC;
400 }
401
402 d = vfp_get_double(state, dd);
403 if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) {
404 ret |= FPSCR_CFLAG | FPSCR_VFLAG;
405 if (signal_on_qnan ||
406 !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
407 /*
408 * Signalling NaN, or signalling on quiet NaN
409 */
410 ret |= FPSCR_IOC;
411 }
412
413 if (ret == 0) {
414 // printf("In %s, d=%lld, m =%lld\n ", __FUNCTION__, d, m);
415 if (d == m || vfp_double_packed_abs(d | m) == 0) {
416 /*
417 * equal
418 */
419 ret |= FPSCR_ZFLAG | FPSCR_CFLAG;
420 // printf("In %s,1 ret=0x%x\n", __FUNCTION__, ret);
421 } else if (vfp_double_packed_sign(d ^ m)) {
422 /*
423 * different signs
424 */
425 if (vfp_double_packed_sign(d))
426 /*
427 * d is negative, so d < m
428 */
429 ret |= FPSCR_NFLAG;
430 else
431 /*
432 * d is positive, so d > m
433 */
434 ret |= FPSCR_CFLAG;
435 } else if ((vfp_double_packed_sign(d) != 0) ^ (d < m)) {
436 /*
437 * d < m
438 */
439 ret |= FPSCR_NFLAG;
440 } else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) {
441 /*
442 * d > m
443 */
444 ret |= FPSCR_CFLAG;
445 }
446 }
447 LOG_TRACE(Core_ARM, "In %s, state=0x%p, ret=0x%x", __FUNCTION__, state, ret);
448
449 return ret;
450}
451
452static u32 vfp_double_fcmp(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
453 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
454 return vfp_compare(state, dd, 0, dm, fpscr);
455}
456
457static u32 vfp_double_fcmpe(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
458 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
459 return vfp_compare(state, dd, 1, dm, fpscr);
460}
461
462static u32 vfp_double_fcmpz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
463 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
464 return vfp_compare(state, dd, 0, VFP_REG_ZERO, fpscr);
465}
466
467static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
468 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
469 return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr);
470}
471
472static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) {
473 struct vfp_double vdm;
474 struct vfp_single vsd;
475 int tm;
476 u32 exceptions = 0;
477
478 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
479 exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr);
480
481 tm = vfp_double_type(&vdm);
482
483 /*
484 * If we have a signalling NaN, signal invalid operation.
485 */
486 if (tm == VFP_SNAN)
487 exceptions = FPSCR_IOC;
488
489 if (tm & VFP_DENORMAL)
490 vfp_double_normalise_denormal(&vdm);
491
492 vsd.sign = vdm.sign;
493 vsd.significand = vfp_hi64to32jamming(vdm.significand);
494
495 /*
496 * If we have an infinity or a NaN, the exponent must be 255
497 */
498 if (tm & (VFP_INFINITY | VFP_NAN)) {
499 vsd.exponent = 255;
500 if (tm == VFP_QNAN)
501 vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
502 goto pack_nan;
503 } else if (tm & VFP_ZERO)
504 vsd.exponent = 0;
505 else
506 vsd.exponent = vdm.exponent - (1023 - 127);
507
508 return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts");
509
510pack_nan:
511 vfp_put_float(state, vfp_single_pack(&vsd), sd);
512 return exceptions;
513}
514
515static u32 vfp_double_fuito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
516 struct vfp_double vdm;
517 u32 m = vfp_get_float(state, dm);
518
519 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
520 vdm.sign = 0;
521 vdm.exponent = 1023 + 63 - 1;
522 vdm.significand = (u64)m;
523
524 return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fuito");
525}
526
527static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
528 struct vfp_double vdm;
529 u32 m = vfp_get_float(state, dm);
530
531 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
532 vdm.sign = (m & 0x80000000) >> 16;
533 vdm.exponent = 1023 + 63 - 1;
534 vdm.significand = vdm.sign ? (~m + 1) : m;
535
536 return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fsito");
537}
538
539static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) {
540 struct vfp_double vdm;
541 u32 d, exceptions = 0;
542 int rmode = fpscr & FPSCR_RMODE_MASK;
543 int tm;
544
545 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
546 exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr);
547
548 /*
549 * Do we have a denormalised number?
550 */
551 tm = vfp_double_type(&vdm);
552 if (tm & VFP_DENORMAL)
553 exceptions |= FPSCR_IDC;
554
555 if (tm & VFP_NAN)
556 vdm.sign = 1;
557
558 if (vdm.exponent >= 1023 + 32) {
559 d = vdm.sign ? 0 : 0xffffffff;
560 exceptions = FPSCR_IOC;
561 } else if (vdm.exponent >= 1023) {
562 int shift = 1023 + 63 - vdm.exponent;
563 u64 rem, incr = 0;
564
565 /*
566 * 2^0 <= m < 2^32-2^8
567 */
568 d = (u32)((vdm.significand << 1) >> shift);
569 rem = vdm.significand << (65 - shift);
570
571 if (rmode == FPSCR_ROUND_NEAREST) {
572 incr = 0x8000000000000000ULL;
573 if ((d & 1) == 0)
574 incr -= 1;
575 } else if (rmode == FPSCR_ROUND_TOZERO) {
576 incr = 0;
577 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) {
578 incr = ~0ULL;
579 }
580
581 if ((rem + incr) < rem) {
582 if (d < 0xffffffff)
583 d += 1;
584 else
585 exceptions |= FPSCR_IOC;
586 }
587
588 if (d && vdm.sign) {
589 d = 0;
590 exceptions |= FPSCR_IOC;
591 } else if (rem)
592 exceptions |= FPSCR_IXC;
593 } else {
594 d = 0;
595 if (vdm.exponent | vdm.significand) {
596 if (rmode == FPSCR_ROUND_NEAREST) {
597 if (vdm.exponent >= 1022) {
598 d = vdm.sign ? 0 : 1;
599 exceptions |= vdm.sign ? FPSCR_IOC : FPSCR_IXC;
600 } else {
601 exceptions |= FPSCR_IXC;
602 }
603 } else if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) {
604 d = 1;
605 exceptions |= FPSCR_IXC;
606 } else if (rmode == FPSCR_ROUND_MINUSINF) {
607 exceptions |= vdm.sign ? FPSCR_IOC : FPSCR_IXC;
608 } else {
609 exceptions |= FPSCR_IXC;
610 }
611 }
612 }
613
614 LOG_TRACE(Core_ARM, "VFP: ftoui: d(s%d)=%08x exceptions=%08x", sd, d, exceptions);
615
616 vfp_put_float(state, d, sd);
617
618 return exceptions;
619}
620
621static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) {
622 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
623 return vfp_double_ftoui(state, sd, unused, dm,
624 (fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO);
625}
626
627static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) {
628 struct vfp_double vdm;
629 u32 d, exceptions = 0;
630 int rmode = fpscr & FPSCR_RMODE_MASK;
631 int tm;
632
633 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
634 exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr);
635 vfp_double_dump("VDM", &vdm);
636
637 /*
638 * Do we have denormalised number?
639 */
640 tm = vfp_double_type(&vdm);
641 if (tm & VFP_DENORMAL)
642 exceptions |= FPSCR_IDC;
643
644 if (tm & VFP_NAN) {
645 d = 0;
646 exceptions |= FPSCR_IOC;
647 } else if (vdm.exponent >= 1023 + 31) {
648 d = 0x7fffffff;
649 if (vdm.sign)
650 d = ~d;
651 exceptions |= FPSCR_IOC;
652 } else if (vdm.exponent >= 1023) {
653 int shift = 1023 + 63 - vdm.exponent; /* 58 */
654 u64 rem, incr = 0;
655
656 d = (u32)((vdm.significand << 1) >> shift);
657 rem = vdm.significand << (65 - shift);
658
659 if (rmode == FPSCR_ROUND_NEAREST) {
660 incr = 0x8000000000000000ULL;
661 if ((d & 1) == 0)
662 incr -= 1;
663 } else if (rmode == FPSCR_ROUND_TOZERO) {
664 incr = 0;
665 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) {
666 incr = ~0ULL;
667 }
668
669 if ((rem + incr) < rem && d < 0xffffffff)
670 d += 1;
671 if (d > (0x7fffffffU + (vdm.sign != 0))) {
672 d = (0x7fffffffU + (vdm.sign != 0));
673 exceptions |= FPSCR_IOC;
674 } else if (rem)
675 exceptions |= FPSCR_IXC;
676
677 if (vdm.sign)
678 d = (~d + 1);
679 } else {
680 d = 0;
681 if (vdm.exponent | vdm.significand) {
682 exceptions |= FPSCR_IXC;
683 if (rmode == FPSCR_ROUND_NEAREST) {
684 if (vdm.exponent >= 1022) {
685 d = vdm.sign ? 0xffffffff : 1;
686 } else {
687 d = 0;
688 }
689 } else if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) {
690 d = 1;
691 } else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) {
692 d = 0xffffffff;
693 }
694 }
695 }
696
697 LOG_TRACE(Core_ARM, "VFP: ftosi: d(s%d)=%08x exceptions=%08x", sd, d, exceptions);
698
699 vfp_put_float(state, (s32)d, sd);
700
701 return exceptions;
702}
703
704static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
705 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
706 return vfp_double_ftosi(state, dd, unused, dm,
707 (fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO);
708}
709
710static struct op fops_ext[] = {
711 {vfp_double_fcpy, 0}, // 0x00000000 - FEXT_FCPY
712 {vfp_double_fabs, 0}, // 0x00000001 - FEXT_FABS
713 {vfp_double_fneg, 0}, // 0x00000002 - FEXT_FNEG
714 {vfp_double_fsqrt, 0}, // 0x00000003 - FEXT_FSQRT
715 {nullptr, 0},
716 {nullptr, 0},
717 {nullptr, 0},
718 {nullptr, 0},
719 {vfp_double_fcmp, OP_SCALAR}, // 0x00000008 - FEXT_FCMP
720 {vfp_double_fcmpe, OP_SCALAR}, // 0x00000009 - FEXT_FCMPE
721 {vfp_double_fcmpz, OP_SCALAR}, // 0x0000000A - FEXT_FCMPZ
722 {vfp_double_fcmpez, OP_SCALAR}, // 0x0000000B - FEXT_FCMPEZ
723 {nullptr, 0},
724 {nullptr, 0},
725 {nullptr, 0},
726 {vfp_double_fcvts, OP_SCALAR | OP_DD}, // 0x0000000F - FEXT_FCVT
727 {vfp_double_fuito, OP_SCALAR | OP_SM}, // 0x00000010 - FEXT_FUITO
728 {vfp_double_fsito, OP_SCALAR | OP_SM}, // 0x00000011 - FEXT_FSITO
729 {nullptr, 0},
730 {nullptr, 0},
731 {nullptr, 0},
732 {nullptr, 0},
733 {nullptr, 0},
734 {nullptr, 0},
735 {vfp_double_ftoui, OP_SCALAR | OP_SD}, // 0x00000018 - FEXT_FTOUI
736 {vfp_double_ftouiz, OP_SCALAR | OP_SD}, // 0x00000019 - FEXT_FTOUIZ
737 {vfp_double_ftosi, OP_SCALAR | OP_SD}, // 0x0000001A - FEXT_FTOSI
738 {vfp_double_ftosiz, OP_SCALAR | OP_SD}, // 0x0000001B - FEXT_FTOSIZ
739};
740
741static u32 vfp_double_fadd_nonnumber(struct vfp_double* vdd, struct vfp_double* vdn,
742 struct vfp_double* vdm, u32 fpscr) {
743 struct vfp_double* vdp;
744 u32 exceptions = 0;
745 int tn, tm;
746
747 tn = vfp_double_type(vdn);
748 tm = vfp_double_type(vdm);
749
750 if (tn & tm & VFP_INFINITY) {
751 /*
752 * Two infinities. Are they different signs?
753 */
754 if (vdn->sign ^ vdm->sign) {
755 /*
756 * different signs -> invalid
757 */
758 exceptions = FPSCR_IOC;
759 vdp = &vfp_double_default_qnan;
760 } else {
761 /*
762 * same signs -> valid
763 */
764 vdp = vdn;
765 }
766 } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) {
767 /*
768 * One infinity and one number -> infinity
769 */
770 vdp = vdn;
771 } else {
772 /*
773 * 'n' is a NaN of some type
774 */
775 return vfp_propagate_nan(vdd, vdn, vdm, fpscr);
776 }
777 *vdd = *vdp;
778 return exceptions;
779}
780
781u32 vfp_double_add(struct vfp_double* vdd, struct vfp_double* vdn, struct vfp_double* vdm,
782 u32 fpscr) {
783 u32 exp_diff;
784 u64 m_sig;
785
786 if (vdn->significand & (1ULL << 63) || vdm->significand & (1ULL << 63)) {
787 LOG_INFO(Core_ARM, "VFP: bad FP values in %s", __func__);
788 vfp_double_dump("VDN", vdn);
789 vfp_double_dump("VDM", vdm);
790 }
791
792 /*
793 * Ensure that 'n' is the largest magnitude number. Note that
794 * if 'n' and 'm' have equal exponents, we do not swap them.
795 * This ensures that NaN propagation works correctly.
796 */
797 if (vdn->exponent < vdm->exponent) {
798 std::swap(vdm, vdn);
799 }
800
801 /*
802 * Is 'n' an infinity or a NaN? Note that 'm' may be a number,
803 * infinity or a NaN here.
804 */
805 if (vdn->exponent == 2047)
806 return vfp_double_fadd_nonnumber(vdd, vdn, vdm, fpscr);
807
808 /*
809 * We have two proper numbers, where 'vdn' is the larger magnitude.
810 *
811 * Copy 'n' to 'd' before doing the arithmetic.
812 */
813 *vdd = *vdn;
814
815 /*
816 * Align 'm' with the result.
817 */
818 exp_diff = vdn->exponent - vdm->exponent;
819 m_sig = vfp_shiftright64jamming(vdm->significand, exp_diff);
820
821 /*
822 * If the signs are different, we are really subtracting.
823 */
824 if (vdn->sign ^ vdm->sign) {
825 m_sig = vdn->significand - m_sig;
826 if ((s64)m_sig < 0) {
827 vdd->sign = vfp_sign_negate(vdd->sign);
828 m_sig = (~m_sig + 1);
829 } else if (m_sig == 0) {
830 vdd->sign = (fpscr & FPSCR_RMODE_MASK) == FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
831 }
832 } else {
833 m_sig += vdn->significand;
834 }
835 vdd->significand = m_sig;
836
837 return 0;
838}
839
840u32 vfp_double_multiply(struct vfp_double* vdd, struct vfp_double* vdn, struct vfp_double* vdm,
841 u32 fpscr) {
842 vfp_double_dump("VDN", vdn);
843 vfp_double_dump("VDM", vdm);
844
845 /*
846 * Ensure that 'n' is the largest magnitude number. Note that
847 * if 'n' and 'm' have equal exponents, we do not swap them.
848 * This ensures that NaN propagation works correctly.
849 */
850 if (vdn->exponent < vdm->exponent) {
851 std::swap(vdm, vdn);
852 LOG_TRACE(Core_ARM, "VFP: swapping M <-> N");
853 }
854
855 vdd->sign = vdn->sign ^ vdm->sign;
856
857 /*
858 * If 'n' is an infinity or NaN, handle it. 'm' may be anything.
859 */
860 if (vdn->exponent == 2047) {
861 if (vdn->significand || (vdm->exponent == 2047 && vdm->significand))
862 return vfp_propagate_nan(vdd, vdn, vdm, fpscr);
863 if ((vdm->exponent | vdm->significand) == 0) {
864 *vdd = vfp_double_default_qnan;
865 return FPSCR_IOC;
866 }
867 vdd->exponent = vdn->exponent;
868 vdd->significand = 0;
869 return 0;
870 }
871
872 /*
873 * If 'm' is zero, the result is always zero. In this case,
874 * 'n' may be zero or a number, but it doesn't matter which.
875 */
876 if ((vdm->exponent | vdm->significand) == 0) {
877 vdd->exponent = 0;
878 vdd->significand = 0;
879 return 0;
880 }
881
882 /*
883 * We add 2 to the destination exponent for the same reason
884 * as the addition case - though this time we have +1 from
885 * each input operand.
886 */
887 vdd->exponent = vdn->exponent + vdm->exponent - 1023 + 2;
888 vdd->significand = vfp_hi64multiply64(vdn->significand, vdm->significand);
889
890 vfp_double_dump("VDD", vdd);
891 return 0;
892}
893
894#define NEG_MULTIPLY (1 << 0)
895#define NEG_SUBTRACT (1 << 1)
896
897static u32 vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr,
898 u32 negate, const char* func) {
899 struct vfp_double vdd, vdp, vdn, vdm;
900 u32 exceptions = 0;
901
902 exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr);
903 if (vdn.exponent == 0 && vdn.significand)
904 vfp_double_normalise_denormal(&vdn);
905
906 exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr);
907 if (vdm.exponent == 0 && vdm.significand)
908 vfp_double_normalise_denormal(&vdm);
909
910 exceptions |= vfp_double_multiply(&vdp, &vdn, &vdm, fpscr);
911 if (negate & NEG_MULTIPLY)
912 vdp.sign = vfp_sign_negate(vdp.sign);
913
914 exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dd), fpscr);
915 if (vdn.exponent == 0 && vdn.significand != 0)
916 vfp_double_normalise_denormal(&vdn);
917
918 if (negate & NEG_SUBTRACT)
919 vdn.sign = vfp_sign_negate(vdn.sign);
920
921 exceptions |= vfp_double_add(&vdd, &vdn, &vdp, fpscr);
922
923 return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, func);
924}
925
926/*
927 * Standard operations
928 */
929
930/*
931 * sd = sd + (sn * sm)
932 */
933static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) {
934 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
935 return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, 0, "fmac");
936}
937
938/*
939 * sd = sd - (sn * sm)
940 */
941static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) {
942 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
943 return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac");
944}
945
946/*
947 * sd = -sd + (sn * sm)
948 */
949static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) {
950 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
951 return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc");
952}
953
954/*
955 * sd = -sd - (sn * sm)
956 */
957static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) {
958 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
959 return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY,
960 "fnmsc");
961}
962
963/*
964 * sd = sn * sm
965 */
966static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) {
967 struct vfp_double vdd, vdn, vdm;
968 u32 exceptions = 0;
969
970 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
971 exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr);
972 if (vdn.exponent == 0 && vdn.significand)
973 vfp_double_normalise_denormal(&vdn);
974
975 exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr);
976 if (vdm.exponent == 0 && vdm.significand)
977 vfp_double_normalise_denormal(&vdm);
978
979 exceptions |= vfp_double_multiply(&vdd, &vdn, &vdm, fpscr);
980 return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fmul");
981}
982
983/*
984 * sd = -(sn * sm)
985 */
986static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) {
987 struct vfp_double vdd, vdn, vdm;
988 u32 exceptions = 0;
989
990 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
991 exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr);
992 if (vdn.exponent == 0 && vdn.significand)
993 vfp_double_normalise_denormal(&vdn);
994
995 exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr);
996 if (vdm.exponent == 0 && vdm.significand)
997 vfp_double_normalise_denormal(&vdm);
998
999 exceptions |= vfp_double_multiply(&vdd, &vdn, &vdm, fpscr);
1000 vdd.sign = vfp_sign_negate(vdd.sign);
1001
1002 return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fnmul");
1003}
1004
1005/*
1006 * sd = sn + sm
1007 */
1008static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) {
1009 struct vfp_double vdd, vdn, vdm;
1010 u32 exceptions = 0;
1011
1012 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
1013 exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr);
1014 if (vdn.exponent == 0 && vdn.significand)
1015 vfp_double_normalise_denormal(&vdn);
1016
1017 exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr);
1018 if (vdm.exponent == 0 && vdm.significand)
1019 vfp_double_normalise_denormal(&vdm);
1020
1021 exceptions |= vfp_double_add(&vdd, &vdn, &vdm, fpscr);
1022
1023 return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fadd");
1024}
1025
1026/*
1027 * sd = sn - sm
1028 */
1029static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) {
1030 struct vfp_double vdd, vdn, vdm;
1031 u32 exceptions = 0;
1032
1033 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
1034 exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr);
1035 if (vdn.exponent == 0 && vdn.significand)
1036 vfp_double_normalise_denormal(&vdn);
1037
1038 exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr);
1039 if (vdm.exponent == 0 && vdm.significand)
1040 vfp_double_normalise_denormal(&vdm);
1041
1042 /*
1043 * Subtraction is like addition, but with a negated operand.
1044 */
1045 vdm.sign = vfp_sign_negate(vdm.sign);
1046
1047 exceptions |= vfp_double_add(&vdd, &vdn, &vdm, fpscr);
1048
1049 return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fsub");
1050}
1051
1052/*
1053 * sd = sn / sm
1054 */
1055static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) {
1056 struct vfp_double vdd, vdn, vdm;
1057 u32 exceptions = 0;
1058 int tm, tn;
1059
1060 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
1061 exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr);
1062 exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr);
1063
1064 vdd.sign = vdn.sign ^ vdm.sign;
1065
1066 tn = vfp_double_type(&vdn);
1067 tm = vfp_double_type(&vdm);
1068
1069 /*
1070 * Is n a NAN?
1071 */
1072 if (tn & VFP_NAN)
1073 goto vdn_nan;
1074
1075 /*
1076 * Is m a NAN?
1077 */
1078 if (tm & VFP_NAN)
1079 goto vdm_nan;
1080
1081 /*
1082 * If n and m are infinity, the result is invalid
1083 * If n and m are zero, the result is invalid
1084 */
1085 if (tm & tn & (VFP_INFINITY | VFP_ZERO))
1086 goto invalid;
1087
1088 /*
1089 * If n is infinity, the result is infinity
1090 */
1091 if (tn & VFP_INFINITY)
1092 goto infinity;
1093
1094 /*
1095 * If m is zero, raise div0 exceptions
1096 */
1097 if (tm & VFP_ZERO)
1098 goto divzero;
1099
1100 /*
1101 * If m is infinity, or n is zero, the result is zero
1102 */
1103 if (tm & VFP_INFINITY || tn & VFP_ZERO)
1104 goto zero;
1105
1106 if (tn & VFP_DENORMAL)
1107 vfp_double_normalise_denormal(&vdn);
1108 if (tm & VFP_DENORMAL)
1109 vfp_double_normalise_denormal(&vdm);
1110
1111 /*
1112 * Ok, we have two numbers, we can perform division.
1113 */
1114 vdd.exponent = vdn.exponent - vdm.exponent + 1023 - 1;
1115 vdm.significand <<= 1;
1116 if (vdm.significand <= (2 * vdn.significand)) {
1117 vdn.significand >>= 1;
1118 vdd.exponent++;
1119 }
1120 vdd.significand = vfp_estimate_div128to64(vdn.significand, 0, vdm.significand);
1121 if ((vdd.significand & 0x1ff) <= 2) {
1122 u64 termh, terml, remh, reml;
1123 mul64to128(&termh, &terml, vdm.significand, vdd.significand);
1124 sub128(&remh, &reml, vdn.significand, 0, termh, terml);
1125 while ((s64)remh < 0) {
1126 vdd.significand -= 1;
1127 add128(&remh, &reml, remh, reml, 0, vdm.significand);
1128 }
1129 vdd.significand |= (reml != 0);
1130 }
1131 return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fdiv");
1132
1133vdn_nan:
1134 exceptions |= vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr);
1135pack:
1136 vfp_put_double(state, vfp_double_pack(&vdd), dd);
1137 return exceptions;
1138
1139vdm_nan:
1140 exceptions |= vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr);
1141 goto pack;
1142
1143zero:
1144 vdd.exponent = 0;
1145 vdd.significand = 0;
1146 goto pack;
1147
1148divzero:
1149 exceptions |= FPSCR_DZC;
1150infinity:
1151 vdd.exponent = 2047;
1152 vdd.significand = 0;
1153 goto pack;
1154
1155invalid:
1156 vfp_put_double(state, vfp_double_pack(&vfp_double_default_qnan), dd);
1157 return FPSCR_IOC;
1158}
1159
1160static struct op fops[] = {
1161 {vfp_double_fmac, 0}, {vfp_double_fmsc, 0}, {vfp_double_fmul, 0},
1162 {vfp_double_fadd, 0}, {vfp_double_fnmac, 0}, {vfp_double_fnmsc, 0},
1163 {vfp_double_fnmul, 0}, {vfp_double_fsub, 0}, {vfp_double_fdiv, 0},
1164};
1165
1166#define FREG_BANK(x) ((x)&0x0c)
1167#define FREG_IDX(x) ((x)&3)
1168
1169u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr) {
1170 u32 op = inst & FOP_MASK;
1171 u32 exceptions = 0;
1172 unsigned int dest;
1173 unsigned int dn = vfp_get_dn(inst);
1174 unsigned int dm;
1175 unsigned int vecitr, veclen, vecstride;
1176 struct op* fop;
1177
1178 LOG_TRACE(Core_ARM, "In %s", __FUNCTION__);
1179 vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK));
1180
1181 fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
1182
1183 /*
1184 * fcvtds takes an sN register number as destination, not dN.
1185 * It also always operates on scalars.
1186 */
1187 if (fop->flags & OP_SD)
1188 dest = vfp_get_sd(inst);
1189 else
1190 dest = vfp_get_dd(inst);
1191
1192 /*
1193 * f[us]ito takes a sN operand, not a dN operand.
1194 */
1195 if (fop->flags & OP_SM)
1196 dm = vfp_get_sm(inst);
1197 else
1198 dm = vfp_get_dm(inst);
1199
1200 /*
1201 * If destination bank is zero, vector length is always '1'.
1202 * ARM DDI0100F C5.1.3, C5.3.2.
1203 */
1204 if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0))
1205 veclen = 0;
1206 else
1207 veclen = fpscr & FPSCR_LENGTH_MASK;
1208
1209 LOG_TRACE(Core_ARM, "VFP: vecstride=%u veclen=%u", vecstride,
1210 (veclen >> FPSCR_LENGTH_BIT) + 1);
1211
1212 if (!fop->fn) {
1213 printf("VFP: could not find double op %d\n", FEXT_TO_IDX(inst));
1214 goto invalid;
1215 }
1216
1217 for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
1218 u32 except;
1219 char type;
1220
1221 type = (fop->flags & OP_SD) ? 's' : 'd';
1222 if (op == FOP_EXT)
1223 LOG_TRACE(Core_ARM, "VFP: itr%d (%c%u) = op[%u] (d%u)", vecitr >> FPSCR_LENGTH_BIT,
1224 type, dest, dn, dm);
1225 else
1226 LOG_TRACE(Core_ARM, "VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)",
1227 vecitr >> FPSCR_LENGTH_BIT, type, dest, dn, FOP_TO_IDX(op), dm);
1228
1229 except = fop->fn(state, dest, dn, dm, fpscr);
1230 LOG_TRACE(Core_ARM, "VFP: itr%d: exceptions=%08x", vecitr >> FPSCR_LENGTH_BIT, except);
1231
1232 exceptions |= except & ~VFP_NAN_FLAG;
1233
1234 /*
1235 * CHECK: It appears to be undefined whether we stop when
1236 * we encounter an exception. We continue.
1237 */
1238 dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 3);
1239 dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 3);
1240 if (FREG_BANK(dm) != 0)
1241 dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 3);
1242 }
1243 return exceptions;
1244
1245invalid:
1246 return ~0;
1247}
diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
deleted file mode 100644
index a66dc1016..000000000
--- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
+++ /dev/null
@@ -1,1703 +0,0 @@
1// Copyright 2012 Michael Kang, 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5/* Notice: this file should not be compiled as is, and is meant to be
6 included in other files only. */
7
8/* ----------------------------------------------------------------------- */
9/* CDP instructions */
10/* cond 1110 opc1 CRn- CRd- copr op20 CRm- CDP */
11
12/* ----------------------------------------------------------------------- */
13/* VMLA */
14/* cond 1110 0D00 Vn-- Vd-- 101X N0M0 Vm-- */
15#ifdef VFP_INTERPRETER_STRUCT
16struct vmla_inst {
17 unsigned int instr;
18 unsigned int dp_operation;
19};
20#endif
21#ifdef VFP_INTERPRETER_TRANS
22static ARM_INST_PTR INTERPRETER_TRANSLATE(vmla)(unsigned int inst, int index) {
23 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmla_inst));
24 vmla_inst* inst_cream = (vmla_inst*)inst_base->component;
25
26 inst_base->cond = BITS(inst, 28, 31);
27 inst_base->idx = index;
28 inst_base->br = TransExtData::NON_BRANCH;
29
30 inst_cream->dp_operation = BIT(inst, 8);
31 inst_cream->instr = inst;
32
33 return inst_base;
34}
35#endif
36#ifdef VFP_INTERPRETER_IMPL
37VMLA_INST : {
38 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
39 CHECK_VFP_ENABLED;
40
41 vmla_inst* inst_cream = (vmla_inst*)inst_base->component;
42
43 int ret;
44
45 if (inst_cream->dp_operation)
46 ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
47 else
48 ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
49
50 CHECK_VFP_CDP_RET;
51 }
52 cpu->Reg[15] += cpu->GetInstructionSize();
53 INC_PC(sizeof(vmla_inst));
54 FETCH_INST;
55 GOTO_NEXT_INST;
56}
57#endif
58
59/* ----------------------------------------------------------------------- */
60/* VNMLS */
61/* cond 1110 0D00 Vn-- Vd-- 101X N1M0 Vm-- */
62#ifdef VFP_INTERPRETER_STRUCT
63struct vmls_inst {
64 unsigned int instr;
65 unsigned int dp_operation;
66};
67#endif
68#ifdef VFP_INTERPRETER_TRANS
69static ARM_INST_PTR INTERPRETER_TRANSLATE(vmls)(unsigned int inst, int index) {
70 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmls_inst));
71 vmls_inst* inst_cream = (vmls_inst*)inst_base->component;
72
73 inst_base->cond = BITS(inst, 28, 31);
74 inst_base->idx = index;
75 inst_base->br = TransExtData::NON_BRANCH;
76
77 inst_cream->dp_operation = BIT(inst, 8);
78 inst_cream->instr = inst;
79
80 return inst_base;
81}
82#endif
83#ifdef VFP_INTERPRETER_IMPL
84VMLS_INST : {
85 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
86 CHECK_VFP_ENABLED;
87
88 vmls_inst* inst_cream = (vmls_inst*)inst_base->component;
89
90 int ret;
91
92 if (inst_cream->dp_operation)
93 ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
94 else
95 ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
96
97 CHECK_VFP_CDP_RET;
98 }
99 cpu->Reg[15] += cpu->GetInstructionSize();
100 INC_PC(sizeof(vmls_inst));
101 FETCH_INST;
102 GOTO_NEXT_INST;
103}
104#endif
105
106/* ----------------------------------------------------------------------- */
107/* VNMLA */
108/* cond 1110 0D01 Vn-- Vd-- 101X N1M0 Vm-- */
109#ifdef VFP_INTERPRETER_STRUCT
110struct vnmla_inst {
111 unsigned int instr;
112 unsigned int dp_operation;
113};
114#endif
115#ifdef VFP_INTERPRETER_TRANS
116static ARM_INST_PTR INTERPRETER_TRANSLATE(vnmla)(unsigned int inst, int index) {
117 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vnmla_inst));
118 vnmla_inst* inst_cream = (vnmla_inst*)inst_base->component;
119
120 inst_base->cond = BITS(inst, 28, 31);
121 inst_base->idx = index;
122 inst_base->br = TransExtData::NON_BRANCH;
123
124 inst_cream->dp_operation = BIT(inst, 8);
125 inst_cream->instr = inst;
126
127 return inst_base;
128}
129#endif
130#ifdef VFP_INTERPRETER_IMPL
131VNMLA_INST : {
132 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
133 CHECK_VFP_ENABLED;
134
135 vnmla_inst* inst_cream = (vnmla_inst*)inst_base->component;
136
137 int ret;
138
139 if (inst_cream->dp_operation)
140 ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
141 else
142 ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
143
144 CHECK_VFP_CDP_RET;
145 }
146 cpu->Reg[15] += cpu->GetInstructionSize();
147 INC_PC(sizeof(vnmla_inst));
148 FETCH_INST;
149 GOTO_NEXT_INST;
150}
151#endif
152
153/* ----------------------------------------------------------------------- */
154/* VNMLS */
155/* cond 1110 0D01 Vn-- Vd-- 101X N0M0 Vm-- */
156
157#ifdef VFP_INTERPRETER_STRUCT
158struct vnmls_inst {
159 unsigned int instr;
160 unsigned int dp_operation;
161};
162#endif
163#ifdef VFP_INTERPRETER_TRANS
164static ARM_INST_PTR INTERPRETER_TRANSLATE(vnmls)(unsigned int inst, int index) {
165 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vnmls_inst));
166 vnmls_inst* inst_cream = (vnmls_inst*)inst_base->component;
167
168 inst_base->cond = BITS(inst, 28, 31);
169 inst_base->idx = index;
170 inst_base->br = TransExtData::NON_BRANCH;
171
172 inst_cream->dp_operation = BIT(inst, 8);
173 inst_cream->instr = inst;
174
175 return inst_base;
176}
177#endif
178#ifdef VFP_INTERPRETER_IMPL
179VNMLS_INST : {
180 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
181 CHECK_VFP_ENABLED;
182
183 vnmls_inst* inst_cream = (vnmls_inst*)inst_base->component;
184
185 int ret;
186
187 if (inst_cream->dp_operation)
188 ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
189 else
190 ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
191
192 CHECK_VFP_CDP_RET;
193 }
194 cpu->Reg[15] += cpu->GetInstructionSize();
195 INC_PC(sizeof(vnmls_inst));
196 FETCH_INST;
197 GOTO_NEXT_INST;
198}
199#endif
200
201/* ----------------------------------------------------------------------- */
202/* VNMUL */
203/* cond 1110 0D10 Vn-- Vd-- 101X N0M0 Vm-- */
204#ifdef VFP_INTERPRETER_STRUCT
205struct vnmul_inst {
206 unsigned int instr;
207 unsigned int dp_operation;
208};
209#endif
210#ifdef VFP_INTERPRETER_TRANS
211static ARM_INST_PTR INTERPRETER_TRANSLATE(vnmul)(unsigned int inst, int index) {
212 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vnmul_inst));
213 vnmul_inst* inst_cream = (vnmul_inst*)inst_base->component;
214
215 inst_base->cond = BITS(inst, 28, 31);
216 inst_base->idx = index;
217 inst_base->br = TransExtData::NON_BRANCH;
218
219 inst_cream->dp_operation = BIT(inst, 8);
220 inst_cream->instr = inst;
221
222 return inst_base;
223}
224#endif
225#ifdef VFP_INTERPRETER_IMPL
226VNMUL_INST : {
227 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
228 CHECK_VFP_ENABLED;
229
230 vnmul_inst* inst_cream = (vnmul_inst*)inst_base->component;
231
232 int ret;
233
234 if (inst_cream->dp_operation)
235 ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
236 else
237 ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
238
239 CHECK_VFP_CDP_RET;
240 }
241 cpu->Reg[15] += cpu->GetInstructionSize();
242 INC_PC(sizeof(vnmul_inst));
243 FETCH_INST;
244 GOTO_NEXT_INST;
245}
246#endif
247
248/* ----------------------------------------------------------------------- */
249/* VMUL */
250/* cond 1110 0D10 Vn-- Vd-- 101X N0M0 Vm-- */
251#ifdef VFP_INTERPRETER_STRUCT
252struct vmul_inst {
253 unsigned int instr;
254 unsigned int dp_operation;
255};
256#endif
257#ifdef VFP_INTERPRETER_TRANS
258static ARM_INST_PTR INTERPRETER_TRANSLATE(vmul)(unsigned int inst, int index) {
259 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmul_inst));
260 vmul_inst* inst_cream = (vmul_inst*)inst_base->component;
261
262 inst_base->cond = BITS(inst, 28, 31);
263 inst_base->idx = index;
264 inst_base->br = TransExtData::NON_BRANCH;
265
266 inst_cream->dp_operation = BIT(inst, 8);
267 inst_cream->instr = inst;
268
269 return inst_base;
270}
271#endif
272#ifdef VFP_INTERPRETER_IMPL
273VMUL_INST : {
274 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
275 CHECK_VFP_ENABLED;
276
277 vmul_inst* inst_cream = (vmul_inst*)inst_base->component;
278
279 int ret;
280
281 if (inst_cream->dp_operation)
282 ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
283 else
284 ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
285
286 CHECK_VFP_CDP_RET;
287 }
288 cpu->Reg[15] += cpu->GetInstructionSize();
289 INC_PC(sizeof(vmul_inst));
290 FETCH_INST;
291 GOTO_NEXT_INST;
292}
293#endif
294
295/* ----------------------------------------------------------------------- */
296/* VADD */
297/* cond 1110 0D11 Vn-- Vd-- 101X N0M0 Vm-- */
298#ifdef VFP_INTERPRETER_STRUCT
299struct vadd_inst {
300 unsigned int instr;
301 unsigned int dp_operation;
302};
303#endif
304#ifdef VFP_INTERPRETER_TRANS
305static ARM_INST_PTR INTERPRETER_TRANSLATE(vadd)(unsigned int inst, int index) {
306 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vadd_inst));
307 vadd_inst* inst_cream = (vadd_inst*)inst_base->component;
308
309 inst_base->cond = BITS(inst, 28, 31);
310 inst_base->idx = index;
311 inst_base->br = TransExtData::NON_BRANCH;
312
313 inst_cream->dp_operation = BIT(inst, 8);
314 inst_cream->instr = inst;
315
316 return inst_base;
317}
318#endif
319#ifdef VFP_INTERPRETER_IMPL
320VADD_INST : {
321 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
322 CHECK_VFP_ENABLED;
323
324 vadd_inst* inst_cream = (vadd_inst*)inst_base->component;
325
326 int ret;
327
328 if (inst_cream->dp_operation)
329 ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
330 else
331 ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
332
333 CHECK_VFP_CDP_RET;
334 }
335 cpu->Reg[15] += cpu->GetInstructionSize();
336 INC_PC(sizeof(vadd_inst));
337 FETCH_INST;
338 GOTO_NEXT_INST;
339}
340#endif
341
342/* ----------------------------------------------------------------------- */
343/* VSUB */
344/* cond 1110 0D11 Vn-- Vd-- 101X N1M0 Vm-- */
345#ifdef VFP_INTERPRETER_STRUCT
346struct vsub_inst {
347 unsigned int instr;
348 unsigned int dp_operation;
349};
350#endif
351#ifdef VFP_INTERPRETER_TRANS
352static ARM_INST_PTR INTERPRETER_TRANSLATE(vsub)(unsigned int inst, int index) {
353 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vsub_inst));
354 vsub_inst* inst_cream = (vsub_inst*)inst_base->component;
355
356 inst_base->cond = BITS(inst, 28, 31);
357 inst_base->idx = index;
358 inst_base->br = TransExtData::NON_BRANCH;
359
360 inst_cream->dp_operation = BIT(inst, 8);
361 inst_cream->instr = inst;
362
363 return inst_base;
364}
365#endif
366#ifdef VFP_INTERPRETER_IMPL
367VSUB_INST : {
368 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
369 CHECK_VFP_ENABLED;
370
371 vsub_inst* inst_cream = (vsub_inst*)inst_base->component;
372
373 int ret;
374
375 if (inst_cream->dp_operation)
376 ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
377 else
378 ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
379
380 CHECK_VFP_CDP_RET;
381 }
382 cpu->Reg[15] += cpu->GetInstructionSize();
383 INC_PC(sizeof(vsub_inst));
384 FETCH_INST;
385 GOTO_NEXT_INST;
386}
387#endif
388
389/* ----------------------------------------------------------------------- */
390/* VDIV */
391/* cond 1110 1D00 Vn-- Vd-- 101X N0M0 Vm-- */
392#ifdef VFP_INTERPRETER_STRUCT
393struct vdiv_inst {
394 unsigned int instr;
395 unsigned int dp_operation;
396};
397#endif
398#ifdef VFP_INTERPRETER_TRANS
399static ARM_INST_PTR INTERPRETER_TRANSLATE(vdiv)(unsigned int inst, int index) {
400 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vdiv_inst));
401 vdiv_inst* inst_cream = (vdiv_inst*)inst_base->component;
402
403 inst_base->cond = BITS(inst, 28, 31);
404 inst_base->idx = index;
405 inst_base->br = TransExtData::NON_BRANCH;
406
407 inst_cream->dp_operation = BIT(inst, 8);
408 inst_cream->instr = inst;
409
410 return inst_base;
411}
412#endif
413#ifdef VFP_INTERPRETER_IMPL
414VDIV_INST : {
415 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
416 CHECK_VFP_ENABLED;
417
418 vdiv_inst* inst_cream = (vdiv_inst*)inst_base->component;
419
420 int ret;
421
422 if (inst_cream->dp_operation)
423 ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
424 else
425 ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
426
427 CHECK_VFP_CDP_RET;
428 }
429 cpu->Reg[15] += cpu->GetInstructionSize();
430 INC_PC(sizeof(vdiv_inst));
431 FETCH_INST;
432 GOTO_NEXT_INST;
433}
434#endif
435
436/* ----------------------------------------------------------------------- */
437/* VMOVI move immediate */
438/* cond 1110 1D11 im4H Vd-- 101X 0000 im4L */
439/* cond 1110 opc1 CRn- CRd- copr op20 CRm- CDP */
440#ifdef VFP_INTERPRETER_STRUCT
441struct vmovi_inst {
442 unsigned int single;
443 unsigned int d;
444 unsigned int imm;
445};
446#endif
447#ifdef VFP_INTERPRETER_TRANS
448static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovi)(unsigned int inst, int index) {
449 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovi_inst));
450 vmovi_inst* inst_cream = (vmovi_inst*)inst_base->component;
451
452 inst_base->cond = BITS(inst, 28, 31);
453 inst_base->idx = index;
454 inst_base->br = TransExtData::NON_BRANCH;
455
456 inst_cream->single = BIT(inst, 8) == 0;
457 inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22)
458 : BITS(inst, 12, 15) | BIT(inst, 22) << 4);
459 unsigned int imm8 = BITS(inst, 16, 19) << 4 | BITS(inst, 0, 3);
460 if (inst_cream->single)
461 inst_cream->imm = BIT(imm8, 7) << 31 | (BIT(imm8, 6) == 0) << 30 |
462 (BIT(imm8, 6) ? 0x1f : 0) << 25 | BITS(imm8, 0, 5) << 19;
463 else
464 inst_cream->imm = BIT(imm8, 7) << 31 | (BIT(imm8, 6) == 0) << 30 |
465 (BIT(imm8, 6) ? 0xff : 0) << 22 | BITS(imm8, 0, 5) << 16;
466 return inst_base;
467}
468#endif
469#ifdef VFP_INTERPRETER_IMPL
470VMOVI_INST : {
471 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
472 CHECK_VFP_ENABLED;
473
474 vmovi_inst* inst_cream = (vmovi_inst*)inst_base->component;
475
476 VMOVI(cpu, inst_cream->single, inst_cream->d, inst_cream->imm);
477 }
478 cpu->Reg[15] += cpu->GetInstructionSize();
479 INC_PC(sizeof(vmovi_inst));
480 FETCH_INST;
481 GOTO_NEXT_INST;
482}
483#endif
484
485/* ----------------------------------------------------------------------- */
486/* VMOVR move register */
487/* cond 1110 1D11 0000 Vd-- 101X 01M0 Vm-- */
488/* cond 1110 opc1 CRn- CRd- copr op20 CRm- CDP */
489#ifdef VFP_INTERPRETER_STRUCT
490struct vmovr_inst {
491 unsigned int single;
492 unsigned int d;
493 unsigned int m;
494};
495#endif
496#ifdef VFP_INTERPRETER_TRANS
497static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovr)(unsigned int inst, int index) {
498 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovr_inst));
499 vmovr_inst* inst_cream = (vmovr_inst*)inst_base->component;
500
501 inst_base->cond = BITS(inst, 28, 31);
502 inst_base->idx = index;
503 inst_base->br = TransExtData::NON_BRANCH;
504
505 inst_cream->single = BIT(inst, 8) == 0;
506 inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22)
507 : BITS(inst, 12, 15) | BIT(inst, 22) << 4);
508 inst_cream->m = (inst_cream->single ? BITS(inst, 0, 3) << 1 | BIT(inst, 5)
509 : BITS(inst, 0, 3) | BIT(inst, 5) << 4);
510 return inst_base;
511}
512#endif
513#ifdef VFP_INTERPRETER_IMPL
514VMOVR_INST : {
515 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
516 CHECK_VFP_ENABLED;
517
518 vmovr_inst* inst_cream = (vmovr_inst*)inst_base->component;
519
520 VMOVR(cpu, inst_cream->single, inst_cream->d, inst_cream->m);
521 }
522 cpu->Reg[15] += cpu->GetInstructionSize();
523 INC_PC(sizeof(vmovr_inst));
524 FETCH_INST;
525 GOTO_NEXT_INST;
526}
527#endif
528
529/* ----------------------------------------------------------------------- */
530/* VABS */
531/* cond 1110 1D11 0000 Vd-- 101X 11M0 Vm-- */
532#ifdef VFP_INTERPRETER_STRUCT
533typedef struct _vabs_inst {
534 unsigned int instr;
535 unsigned int dp_operation;
536} vabs_inst;
537#endif
538#ifdef VFP_INTERPRETER_TRANS
539static ARM_INST_PTR INTERPRETER_TRANSLATE(vabs)(unsigned int inst, int index) {
540 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vabs_inst));
541 vabs_inst* inst_cream = (vabs_inst*)inst_base->component;
542
543 inst_base->cond = BITS(inst, 28, 31);
544 inst_base->idx = index;
545 inst_base->br = TransExtData::NON_BRANCH;
546
547 inst_cream->dp_operation = BIT(inst, 8);
548 inst_cream->instr = inst;
549
550 return inst_base;
551}
552#endif
553#ifdef VFP_INTERPRETER_IMPL
554VABS_INST : {
555 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
556 CHECK_VFP_ENABLED;
557
558 vabs_inst* inst_cream = (vabs_inst*)inst_base->component;
559
560 int ret;
561
562 if (inst_cream->dp_operation)
563 ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
564 else
565 ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
566
567 CHECK_VFP_CDP_RET;
568 }
569 cpu->Reg[15] += cpu->GetInstructionSize();
570 INC_PC(sizeof(vabs_inst));
571 FETCH_INST;
572 GOTO_NEXT_INST;
573}
574#endif
575
576/* ----------------------------------------------------------------------- */
577/* VNEG */
578/* cond 1110 1D11 0001 Vd-- 101X 11M0 Vm-- */
579
580#ifdef VFP_INTERPRETER_STRUCT
581struct vneg_inst {
582 unsigned int instr;
583 unsigned int dp_operation;
584};
585#endif
586#ifdef VFP_INTERPRETER_TRANS
587static ARM_INST_PTR INTERPRETER_TRANSLATE(vneg)(unsigned int inst, int index) {
588 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vneg_inst));
589 vneg_inst* inst_cream = (vneg_inst*)inst_base->component;
590
591 inst_base->cond = BITS(inst, 28, 31);
592 inst_base->idx = index;
593 inst_base->br = TransExtData::NON_BRANCH;
594
595 inst_cream->dp_operation = BIT(inst, 8);
596 inst_cream->instr = inst;
597
598 return inst_base;
599}
600#endif
601#ifdef VFP_INTERPRETER_IMPL
602VNEG_INST : {
603 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
604 CHECK_VFP_ENABLED;
605
606 vneg_inst* inst_cream = (vneg_inst*)inst_base->component;
607
608 int ret;
609
610 if (inst_cream->dp_operation)
611 ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
612 else
613 ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
614
615 CHECK_VFP_CDP_RET;
616 }
617 cpu->Reg[15] += cpu->GetInstructionSize();
618 INC_PC(sizeof(vneg_inst));
619 FETCH_INST;
620 GOTO_NEXT_INST;
621}
622#endif
623
624/* ----------------------------------------------------------------------- */
625/* VSQRT */
626/* cond 1110 1D11 0001 Vd-- 101X 11M0 Vm-- */
627#ifdef VFP_INTERPRETER_STRUCT
628struct vsqrt_inst {
629 unsigned int instr;
630 unsigned int dp_operation;
631};
632#endif
633#ifdef VFP_INTERPRETER_TRANS
634static ARM_INST_PTR INTERPRETER_TRANSLATE(vsqrt)(unsigned int inst, int index) {
635 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vsqrt_inst));
636 vsqrt_inst* inst_cream = (vsqrt_inst*)inst_base->component;
637
638 inst_base->cond = BITS(inst, 28, 31);
639 inst_base->idx = index;
640 inst_base->br = TransExtData::NON_BRANCH;
641
642 inst_cream->dp_operation = BIT(inst, 8);
643 inst_cream->instr = inst;
644
645 return inst_base;
646}
647#endif
648#ifdef VFP_INTERPRETER_IMPL
649VSQRT_INST : {
650 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
651 CHECK_VFP_ENABLED;
652
653 vsqrt_inst* inst_cream = (vsqrt_inst*)inst_base->component;
654
655 int ret;
656
657 if (inst_cream->dp_operation)
658 ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
659 else
660 ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
661
662 CHECK_VFP_CDP_RET;
663 }
664 cpu->Reg[15] += cpu->GetInstructionSize();
665 INC_PC(sizeof(vsqrt_inst));
666 FETCH_INST;
667 GOTO_NEXT_INST;
668}
669#endif
670
671/* ----------------------------------------------------------------------- */
672/* VCMP VCMPE */
673/* cond 1110 1D11 0100 Vd-- 101X E1M0 Vm-- Encoding 1 */
674#ifdef VFP_INTERPRETER_STRUCT
675struct vcmp_inst {
676 unsigned int instr;
677 unsigned int dp_operation;
678};
679#endif
680#ifdef VFP_INTERPRETER_TRANS
681static ARM_INST_PTR INTERPRETER_TRANSLATE(vcmp)(unsigned int inst, int index) {
682 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vcmp_inst));
683 vcmp_inst* inst_cream = (vcmp_inst*)inst_base->component;
684
685 inst_base->cond = BITS(inst, 28, 31);
686 inst_base->idx = index;
687 inst_base->br = TransExtData::NON_BRANCH;
688
689 inst_cream->dp_operation = BIT(inst, 8);
690 inst_cream->instr = inst;
691
692 return inst_base;
693}
694#endif
695#ifdef VFP_INTERPRETER_IMPL
696VCMP_INST : {
697 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
698 CHECK_VFP_ENABLED;
699
700 vcmp_inst* inst_cream = (vcmp_inst*)inst_base->component;
701
702 int ret;
703
704 if (inst_cream->dp_operation)
705 ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
706 else
707 ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
708
709 CHECK_VFP_CDP_RET;
710 }
711 cpu->Reg[15] += cpu->GetInstructionSize();
712 INC_PC(sizeof(vcmp_inst));
713 FETCH_INST;
714 GOTO_NEXT_INST;
715}
716#endif
717
718/* ----------------------------------------------------------------------- */
719/* VCMP VCMPE */
720/* cond 1110 1D11 0100 Vd-- 101X E1M0 Vm-- Encoding 2 */
721#ifdef VFP_INTERPRETER_STRUCT
722struct vcmp2_inst {
723 unsigned int instr;
724 unsigned int dp_operation;
725};
726#endif
727#ifdef VFP_INTERPRETER_TRANS
728static ARM_INST_PTR INTERPRETER_TRANSLATE(vcmp2)(unsigned int inst, int index) {
729 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vcmp2_inst));
730 vcmp2_inst* inst_cream = (vcmp2_inst*)inst_base->component;
731
732 inst_base->cond = BITS(inst, 28, 31);
733 inst_base->idx = index;
734 inst_base->br = TransExtData::NON_BRANCH;
735
736 inst_cream->dp_operation = BIT(inst, 8);
737 inst_cream->instr = inst;
738
739 return inst_base;
740}
741#endif
742#ifdef VFP_INTERPRETER_IMPL
743VCMP2_INST : {
744 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
745 CHECK_VFP_ENABLED;
746
747 vcmp2_inst* inst_cream = (vcmp2_inst*)inst_base->component;
748
749 int ret;
750
751 if (inst_cream->dp_operation)
752 ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
753 else
754 ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
755
756 CHECK_VFP_CDP_RET;
757 }
758 cpu->Reg[15] += cpu->GetInstructionSize();
759 INC_PC(sizeof(vcmp2_inst));
760 FETCH_INST;
761 GOTO_NEXT_INST;
762}
763#endif
764
765/* ----------------------------------------------------------------------- */
766/* VCVTBDS between double and single */
767/* cond 1110 1D11 0111 Vd-- 101X 11M0 Vm-- */
768#ifdef VFP_INTERPRETER_STRUCT
769struct vcvtbds_inst {
770 unsigned int instr;
771 unsigned int dp_operation;
772};
773#endif
774#ifdef VFP_INTERPRETER_TRANS
775static ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbds)(unsigned int inst, int index) {
776 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vcvtbds_inst));
777 vcvtbds_inst* inst_cream = (vcvtbds_inst*)inst_base->component;
778
779 inst_base->cond = BITS(inst, 28, 31);
780 inst_base->idx = index;
781 inst_base->br = TransExtData::NON_BRANCH;
782
783 inst_cream->dp_operation = BIT(inst, 8);
784 inst_cream->instr = inst;
785
786 return inst_base;
787}
788#endif
789#ifdef VFP_INTERPRETER_IMPL
790VCVTBDS_INST : {
791 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
792 CHECK_VFP_ENABLED;
793
794 vcvtbds_inst* inst_cream = (vcvtbds_inst*)inst_base->component;
795
796 int ret;
797
798 if (inst_cream->dp_operation)
799 ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
800 else
801 ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
802
803 CHECK_VFP_CDP_RET;
804 }
805 cpu->Reg[15] += cpu->GetInstructionSize();
806 INC_PC(sizeof(vcvtbds_inst));
807 FETCH_INST;
808 GOTO_NEXT_INST;
809}
810#endif
811
812/* ----------------------------------------------------------------------- */
813/* VCVTBFF between floating point and fixed point */
814/* cond 1110 1D11 1op2 Vd-- 101X X1M0 Vm-- */
815#ifdef VFP_INTERPRETER_STRUCT
816struct vcvtbff_inst {
817 unsigned int instr;
818 unsigned int dp_operation;
819};
820#endif
821#ifdef VFP_INTERPRETER_TRANS
822static ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbff)(unsigned int inst, int index) {
823 VFP_DEBUG_UNTESTED(VCVTBFF);
824
825 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vcvtbff_inst));
826 vcvtbff_inst* inst_cream = (vcvtbff_inst*)inst_base->component;
827
828 inst_base->cond = BITS(inst, 28, 31);
829 inst_base->idx = index;
830 inst_base->br = TransExtData::NON_BRANCH;
831
832 inst_cream->dp_operation = BIT(inst, 8);
833 inst_cream->instr = inst;
834
835 return inst_base;
836}
837#endif
838#ifdef VFP_INTERPRETER_IMPL
839VCVTBFF_INST : {
840 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
841 CHECK_VFP_ENABLED;
842
843 vcvtbff_inst* inst_cream = (vcvtbff_inst*)inst_base->component;
844
845 int ret;
846
847 if (inst_cream->dp_operation)
848 ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
849 else
850 ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
851
852 CHECK_VFP_CDP_RET;
853 }
854 cpu->Reg[15] += cpu->GetInstructionSize();
855 INC_PC(sizeof(vcvtbff_inst));
856 FETCH_INST;
857 GOTO_NEXT_INST;
858}
859#endif
860
861/* ----------------------------------------------------------------------- */
862/* VCVTBFI between floating point and integer */
863/* cond 1110 1D11 1op2 Vd-- 101X X1M0 Vm-- */
864#ifdef VFP_INTERPRETER_STRUCT
865struct vcvtbfi_inst {
866 unsigned int instr;
867 unsigned int dp_operation;
868};
869#endif
870#ifdef VFP_INTERPRETER_TRANS
871static ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbfi)(unsigned int inst, int index) {
872 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vcvtbfi_inst));
873 vcvtbfi_inst* inst_cream = (vcvtbfi_inst*)inst_base->component;
874
875 inst_base->cond = BITS(inst, 28, 31);
876 inst_base->idx = index;
877 inst_base->br = TransExtData::NON_BRANCH;
878
879 inst_cream->dp_operation = BIT(inst, 8);
880 inst_cream->instr = inst;
881
882 return inst_base;
883}
884#endif
885#ifdef VFP_INTERPRETER_IMPL
886VCVTBFI_INST : {
887 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
888 CHECK_VFP_ENABLED;
889
890 vcvtbfi_inst* inst_cream = (vcvtbfi_inst*)inst_base->component;
891
892 int ret;
893
894 if (inst_cream->dp_operation)
895 ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
896 else
897 ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
898
899 CHECK_VFP_CDP_RET;
900 }
901 cpu->Reg[15] += cpu->GetInstructionSize();
902 INC_PC(sizeof(vcvtbfi_inst));
903 FETCH_INST;
904 GOTO_NEXT_INST;
905}
906#endif
907
908/* ----------------------------------------------------------------------- */
909/* MRC / MCR instructions */
910/* cond 1110 AAAL XXXX XXXX 101C XBB1 XXXX */
911/* cond 1110 op11 CRn- Rt-- copr op21 CRm- */
912
913/* ----------------------------------------------------------------------- */
914/* VMOVBRS between register and single precision */
915/* cond 1110 000o Vn-- Rt-- 1010 N001 0000 */
916/* cond 1110 op11 CRn- Rt-- copr op21 CRm- MRC */
917#ifdef VFP_INTERPRETER_STRUCT
918struct vmovbrs_inst {
919 unsigned int to_arm;
920 unsigned int t;
921 unsigned int n;
922};
923#endif
924#ifdef VFP_INTERPRETER_TRANS
925static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrs)(unsigned int inst, int index) {
926 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovbrs_inst));
927 vmovbrs_inst* inst_cream = (vmovbrs_inst*)inst_base->component;
928
929 inst_base->cond = BITS(inst, 28, 31);
930 inst_base->idx = index;
931 inst_base->br = TransExtData::NON_BRANCH;
932
933 inst_cream->to_arm = BIT(inst, 20) == 1;
934 inst_cream->t = BITS(inst, 12, 15);
935 inst_cream->n = BIT(inst, 7) | BITS(inst, 16, 19) << 1;
936
937 return inst_base;
938}
939#endif
940#ifdef VFP_INTERPRETER_IMPL
941VMOVBRS_INST : {
942 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
943 CHECK_VFP_ENABLED;
944
945 vmovbrs_inst* inst_cream = (vmovbrs_inst*)inst_base->component;
946
947 VMOVBRS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->n, &(cpu->Reg[inst_cream->t]));
948 }
949 cpu->Reg[15] += cpu->GetInstructionSize();
950 INC_PC(sizeof(vmovbrs_inst));
951 FETCH_INST;
952 GOTO_NEXT_INST;
953}
954#endif
955
956/* ----------------------------------------------------------------------- */
957/* VMSR */
958/* cond 1110 1110 reg- Rt-- 1010 0001 0000 */
959/* cond 1110 op10 CRn- Rt-- copr op21 CRm- MCR */
960#ifdef VFP_INTERPRETER_STRUCT
961struct vmsr_inst {
962 unsigned int reg;
963 unsigned int Rt;
964};
965#endif
966#ifdef VFP_INTERPRETER_TRANS
967static ARM_INST_PTR INTERPRETER_TRANSLATE(vmsr)(unsigned int inst, int index) {
968 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmsr_inst));
969 vmsr_inst* inst_cream = (vmsr_inst*)inst_base->component;
970
971 inst_base->cond = BITS(inst, 28, 31);
972 inst_base->idx = index;
973 inst_base->br = TransExtData::NON_BRANCH;
974
975 inst_cream->reg = BITS(inst, 16, 19);
976 inst_cream->Rt = BITS(inst, 12, 15);
977
978 return inst_base;
979}
980#endif
981#ifdef VFP_INTERPRETER_IMPL
982VMSR_INST : {
983 if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
984 /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled ,
985 and in privileged mode */
986 /* Exceptions must be checked, according to v7 ref manual */
987 CHECK_VFP_ENABLED;
988
989 vmsr_inst* const inst_cream = (vmsr_inst*)inst_base->component;
990
991 unsigned int reg = inst_cream->reg;
992 unsigned int rt = inst_cream->Rt;
993
994 if (reg == 1) {
995 cpu->VFP[VFP_FPSCR] = cpu->Reg[rt];
996 } else if (cpu->InAPrivilegedMode()) {
997 if (reg == 8)
998 cpu->VFP[VFP_FPEXC] = cpu->Reg[rt];
999 else if (reg == 9)
1000 cpu->VFP[VFP_FPINST] = cpu->Reg[rt];
1001 else if (reg == 10)
1002 cpu->VFP[VFP_FPINST2] = cpu->Reg[rt];
1003 }
1004 }
1005 cpu->Reg[15] += cpu->GetInstructionSize();
1006 INC_PC(sizeof(vmsr_inst));
1007 FETCH_INST;
1008 GOTO_NEXT_INST;
1009}
1010#endif
1011
1012/* ----------------------------------------------------------------------- */
1013/* VMOVBRC register to scalar */
1014/* cond 1110 0XX0 Vd-- Rt-- 1011 DXX1 0000 */
1015/* cond 1110 op10 CRn- Rt-- copr op21 CRm- MCR */
1016#ifdef VFP_INTERPRETER_STRUCT
1017struct vmovbrc_inst {
1018 unsigned int esize;
1019 unsigned int index;
1020 unsigned int d;
1021 unsigned int t;
1022};
1023#endif
1024#ifdef VFP_INTERPRETER_TRANS
1025static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrc)(unsigned int inst, int index) {
1026 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovbrc_inst));
1027 vmovbrc_inst* inst_cream = (vmovbrc_inst*)inst_base->component;
1028
1029 inst_base->cond = BITS(inst, 28, 31);
1030 inst_base->idx = index;
1031 inst_base->br = TransExtData::NON_BRANCH;
1032
1033 inst_cream->d = BITS(inst, 16, 19) | BIT(inst, 7) << 4;
1034 inst_cream->t = BITS(inst, 12, 15);
1035 /* VFP variant of instruction */
1036 inst_cream->esize = 32;
1037 inst_cream->index = BIT(inst, 21);
1038
1039 return inst_base;
1040}
1041#endif
1042#ifdef VFP_INTERPRETER_IMPL
1043VMOVBRC_INST : {
1044 if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
1045 CHECK_VFP_ENABLED;
1046
1047 vmovbrc_inst* const inst_cream = (vmovbrc_inst*)inst_base->component;
1048
1049 cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index] = cpu->Reg[inst_cream->t];
1050 }
1051 cpu->Reg[15] += cpu->GetInstructionSize();
1052 INC_PC(sizeof(vmovbrc_inst));
1053 FETCH_INST;
1054 GOTO_NEXT_INST;
1055}
1056#endif
1057
1058/* ----------------------------------------------------------------------- */
1059/* VMRS */
1060/* cond 1110 1111 CRn- Rt-- 1010 0001 0000 */
1061/* cond 1110 op11 CRn- Rt-- copr op21 CRm- MRC */
1062#ifdef VFP_INTERPRETER_STRUCT
1063struct vmrs_inst {
1064 unsigned int reg;
1065 unsigned int Rt;
1066};
1067#endif
1068#ifdef VFP_INTERPRETER_TRANS
1069static ARM_INST_PTR INTERPRETER_TRANSLATE(vmrs)(unsigned int inst, int index) {
1070 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmrs_inst));
1071 vmrs_inst* inst_cream = (vmrs_inst*)inst_base->component;
1072
1073 inst_base->cond = BITS(inst, 28, 31);
1074 inst_base->idx = index;
1075 inst_base->br = TransExtData::NON_BRANCH;
1076
1077 inst_cream->reg = BITS(inst, 16, 19);
1078 inst_cream->Rt = BITS(inst, 12, 15);
1079
1080 return inst_base;
1081}
1082#endif
1083#ifdef VFP_INTERPRETER_IMPL
1084VMRS_INST : {
1085 if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
1086 /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled,
1087 and in privileged mode */
1088 /* Exceptions must be checked, according to v7 ref manual */
1089 CHECK_VFP_ENABLED;
1090
1091 vmrs_inst* const inst_cream = (vmrs_inst*)inst_base->component;
1092
1093 unsigned int reg = inst_cream->reg;
1094 unsigned int rt = inst_cream->Rt;
1095
1096 if (reg == 1) // FPSCR
1097 {
1098 if (rt != 15) {
1099 cpu->Reg[rt] = cpu->VFP[VFP_FPSCR];
1100 } else {
1101 cpu->NFlag = (cpu->VFP[VFP_FPSCR] >> 31) & 1;
1102 cpu->ZFlag = (cpu->VFP[VFP_FPSCR] >> 30) & 1;
1103 cpu->CFlag = (cpu->VFP[VFP_FPSCR] >> 29) & 1;
1104 cpu->VFlag = (cpu->VFP[VFP_FPSCR] >> 28) & 1;
1105 }
1106 } else if (reg == 0) {
1107 cpu->Reg[rt] = cpu->VFP[VFP_FPSID];
1108 } else if (reg == 6) {
1109 cpu->Reg[rt] = cpu->VFP[VFP_MVFR1];
1110 } else if (reg == 7) {
1111 cpu->Reg[rt] = cpu->VFP[VFP_MVFR0];
1112 } else if (cpu->InAPrivilegedMode()) {
1113 if (reg == 8)
1114 cpu->Reg[rt] = cpu->VFP[VFP_FPEXC];
1115 else if (reg == 9)
1116 cpu->Reg[rt] = cpu->VFP[VFP_FPINST];
1117 else if (reg == 10)
1118 cpu->Reg[rt] = cpu->VFP[VFP_FPINST2];
1119 }
1120 }
1121 cpu->Reg[15] += cpu->GetInstructionSize();
1122 INC_PC(sizeof(vmrs_inst));
1123 FETCH_INST;
1124 GOTO_NEXT_INST;
1125}
1126#endif
1127
1128/* ----------------------------------------------------------------------- */
1129/* VMOVBCR scalar to register */
1130/* cond 1110 XXX1 Vd-- Rt-- 1011 NXX1 0000 */
1131/* cond 1110 op11 CRn- Rt-- copr op21 CRm- MCR */
1132#ifdef VFP_INTERPRETER_STRUCT
1133struct vmovbcr_inst {
1134 unsigned int esize;
1135 unsigned int index;
1136 unsigned int d;
1137 unsigned int t;
1138};
1139#endif
1140#ifdef VFP_INTERPRETER_TRANS
1141static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbcr)(unsigned int inst, int index) {
1142 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovbcr_inst));
1143 vmovbcr_inst* inst_cream = (vmovbcr_inst*)inst_base->component;
1144
1145 inst_base->cond = BITS(inst, 28, 31);
1146 inst_base->idx = index;
1147 inst_base->br = TransExtData::NON_BRANCH;
1148
1149 inst_cream->d = BITS(inst, 16, 19) | BIT(inst, 7) << 4;
1150 inst_cream->t = BITS(inst, 12, 15);
1151 /* VFP variant of instruction */
1152 inst_cream->esize = 32;
1153 inst_cream->index = BIT(inst, 21);
1154
1155 return inst_base;
1156}
1157#endif
1158#ifdef VFP_INTERPRETER_IMPL
1159VMOVBCR_INST : {
1160 if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
1161 CHECK_VFP_ENABLED;
1162
1163 vmovbcr_inst* const inst_cream = (vmovbcr_inst*)inst_base->component;
1164
1165 cpu->Reg[inst_cream->t] = cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index];
1166 }
1167 cpu->Reg[15] += cpu->GetInstructionSize();
1168 INC_PC(sizeof(vmovbcr_inst));
1169 FETCH_INST;
1170 GOTO_NEXT_INST;
1171}
1172#endif
1173
1174/* ----------------------------------------------------------------------- */
1175/* MRRC / MCRR instructions */
1176/* cond 1100 0101 Rt2- Rt-- copr opc1 CRm- MRRC */
1177/* cond 1100 0100 Rt2- Rt-- copr opc1 CRm- MCRR */
1178
1179/* ----------------------------------------------------------------------- */
1180/* VMOVBRRSS between 2 registers to 2 singles */
1181/* cond 1100 010X Rt2- Rt-- 1010 00X1 Vm-- */
1182/* cond 1100 0101 Rt2- Rt-- copr opc1 CRm- MRRC */
1183#ifdef VFP_INTERPRETER_STRUCT
1184struct vmovbrrss_inst {
1185 unsigned int to_arm;
1186 unsigned int t;
1187 unsigned int t2;
1188 unsigned int m;
1189};
1190#endif
1191#ifdef VFP_INTERPRETER_TRANS
1192static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrrss)(unsigned int inst, int index) {
1193 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovbrrss_inst));
1194 vmovbrrss_inst* inst_cream = (vmovbrrss_inst*)inst_base->component;
1195
1196 inst_base->cond = BITS(inst, 28, 31);
1197 inst_base->idx = index;
1198 inst_base->br = TransExtData::NON_BRANCH;
1199
1200 inst_cream->to_arm = BIT(inst, 20) == 1;
1201 inst_cream->t = BITS(inst, 12, 15);
1202 inst_cream->t2 = BITS(inst, 16, 19);
1203 inst_cream->m = BITS(inst, 0, 3) << 1 | BIT(inst, 5);
1204
1205 return inst_base;
1206}
1207#endif
1208#ifdef VFP_INTERPRETER_IMPL
1209VMOVBRRSS_INST : {
1210 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
1211 CHECK_VFP_ENABLED;
1212
1213 vmovbrrss_inst* const inst_cream = (vmovbrrss_inst*)inst_base->component;
1214
1215 VMOVBRRSS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m,
1216 &cpu->Reg[inst_cream->t], &cpu->Reg[inst_cream->t2]);
1217 }
1218 cpu->Reg[15] += cpu->GetInstructionSize();
1219 INC_PC(sizeof(vmovbrrss_inst));
1220 FETCH_INST;
1221 GOTO_NEXT_INST;
1222}
1223#endif
1224
1225/* ----------------------------------------------------------------------- */
1226/* VMOVBRRD between 2 registers and 1 double */
1227/* cond 1100 010X Rt2- Rt-- 1011 00X1 Vm-- */
1228/* cond 1100 0101 Rt2- Rt-- copr opc1 CRm- MRRC */
1229#ifdef VFP_INTERPRETER_STRUCT
1230struct vmovbrrd_inst {
1231 unsigned int to_arm;
1232 unsigned int t;
1233 unsigned int t2;
1234 unsigned int m;
1235};
1236#endif
1237#ifdef VFP_INTERPRETER_TRANS
1238static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrrd)(unsigned int inst, int index) {
1239 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovbrrd_inst));
1240 vmovbrrd_inst* inst_cream = (vmovbrrd_inst*)inst_base->component;
1241
1242 inst_base->cond = BITS(inst, 28, 31);
1243 inst_base->idx = index;
1244 inst_base->br = TransExtData::NON_BRANCH;
1245
1246 inst_cream->to_arm = BIT(inst, 20) == 1;
1247 inst_cream->t = BITS(inst, 12, 15);
1248 inst_cream->t2 = BITS(inst, 16, 19);
1249 inst_cream->m = BIT(inst, 5) << 4 | BITS(inst, 0, 3);
1250
1251 return inst_base;
1252}
1253#endif
1254#ifdef VFP_INTERPRETER_IMPL
1255VMOVBRRD_INST : {
1256 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
1257 CHECK_VFP_ENABLED;
1258
1259 vmovbrrd_inst* inst_cream = (vmovbrrd_inst*)inst_base->component;
1260
1261 VMOVBRRD(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m,
1262 &(cpu->Reg[inst_cream->t]), &(cpu->Reg[inst_cream->t2]));
1263 }
1264 cpu->Reg[15] += cpu->GetInstructionSize();
1265 INC_PC(sizeof(vmovbrrd_inst));
1266 FETCH_INST;
1267 GOTO_NEXT_INST;
1268}
1269#endif
1270
1271/* ----------------------------------------------------------------------- */
1272/* LDC/STC between 2 registers and 1 double */
1273/* cond 110X XXX1 Rn-- CRd- copr imm- imm- LDC */
1274/* cond 110X XXX0 Rn-- CRd- copr imm8 imm8 STC */
1275
1276/* ----------------------------------------------------------------------- */
1277/* VSTR */
1278/* cond 1101 UD00 Rn-- Vd-- 101X imm8 imm8 */
1279#ifdef VFP_INTERPRETER_STRUCT
1280struct vstr_inst {
1281 unsigned int single;
1282 unsigned int n;
1283 unsigned int d;
1284 unsigned int imm32;
1285 unsigned int add;
1286};
1287#endif
1288#ifdef VFP_INTERPRETER_TRANS
1289static ARM_INST_PTR INTERPRETER_TRANSLATE(vstr)(unsigned int inst, int index) {
1290 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vstr_inst));
1291 vstr_inst* inst_cream = (vstr_inst*)inst_base->component;
1292
1293 inst_base->cond = BITS(inst, 28, 31);
1294 inst_base->idx = index;
1295 inst_base->br = TransExtData::NON_BRANCH;
1296
1297 inst_cream->single = BIT(inst, 8) == 0;
1298 inst_cream->add = BIT(inst, 23);
1299 inst_cream->imm32 = BITS(inst, 0, 7) << 2;
1300 inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22)
1301 : BITS(inst, 12, 15) | BIT(inst, 22) << 4);
1302 inst_cream->n = BITS(inst, 16, 19);
1303
1304 return inst_base;
1305}
1306#endif
1307#ifdef VFP_INTERPRETER_IMPL
1308VSTR_INST : {
1309 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
1310 CHECK_VFP_ENABLED;
1311
1312 vstr_inst* inst_cream = (vstr_inst*)inst_base->component;
1313
1314 unsigned int base = (inst_cream->n == 15 ? (cpu->Reg[inst_cream->n] & 0xFFFFFFFC) + 8
1315 : cpu->Reg[inst_cream->n]);
1316 addr = (inst_cream->add ? base + inst_cream->imm32 : base - inst_cream->imm32);
1317
1318 if (inst_cream->single) {
1319 cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d]);
1320 } else {
1321 const u32 word1 = cpu->ExtReg[inst_cream->d * 2 + 0];
1322 const u32 word2 = cpu->ExtReg[inst_cream->d * 2 + 1];
1323
1324 if (cpu->InBigEndianMode()) {
1325 cpu->WriteMemory32(addr + 0, word2);
1326 cpu->WriteMemory32(addr + 4, word1);
1327 } else {
1328 cpu->WriteMemory32(addr + 0, word1);
1329 cpu->WriteMemory32(addr + 4, word2);
1330 }
1331 }
1332 }
1333 cpu->Reg[15] += cpu->GetInstructionSize();
1334 INC_PC(sizeof(vstr_inst));
1335 FETCH_INST;
1336 GOTO_NEXT_INST;
1337}
1338#endif
1339
1340/* ----------------------------------------------------------------------- */
1341/* VPUSH */
1342/* cond 1101 0D10 1101 Vd-- 101X imm8 imm8 */
1343#ifdef VFP_INTERPRETER_STRUCT
1344struct vpush_inst {
1345 unsigned int single;
1346 unsigned int d;
1347 unsigned int imm32;
1348 unsigned int regs;
1349};
1350#endif
1351#ifdef VFP_INTERPRETER_TRANS
1352static ARM_INST_PTR INTERPRETER_TRANSLATE(vpush)(unsigned int inst, int index) {
1353 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vpush_inst));
1354 vpush_inst* inst_cream = (vpush_inst*)inst_base->component;
1355
1356 inst_base->cond = BITS(inst, 28, 31);
1357 inst_base->idx = index;
1358 inst_base->br = TransExtData::NON_BRANCH;
1359
1360 inst_cream->single = BIT(inst, 8) == 0;
1361 inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22)
1362 : BITS(inst, 12, 15) | BIT(inst, 22) << 4);
1363 inst_cream->imm32 = BITS(inst, 0, 7) << 2;
1364 inst_cream->regs = (inst_cream->single ? BITS(inst, 0, 7) : BITS(inst, 1, 7));
1365
1366 return inst_base;
1367}
1368#endif
1369#ifdef VFP_INTERPRETER_IMPL
1370VPUSH_INST : {
1371 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
1372 CHECK_VFP_ENABLED;
1373
1374 vpush_inst* inst_cream = (vpush_inst*)inst_base->component;
1375
1376 addr = cpu->Reg[R13] - inst_cream->imm32;
1377
1378 for (unsigned int i = 0; i < inst_cream->regs; i++) {
1379 if (inst_cream->single) {
1380 cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d + i]);
1381 addr += 4;
1382 } else {
1383 const u32 word1 = cpu->ExtReg[(inst_cream->d + i) * 2 + 0];
1384 const u32 word2 = cpu->ExtReg[(inst_cream->d + i) * 2 + 1];
1385
1386 if (cpu->InBigEndianMode()) {
1387 cpu->WriteMemory32(addr + 0, word2);
1388 cpu->WriteMemory32(addr + 4, word1);
1389 } else {
1390 cpu->WriteMemory32(addr + 0, word1);
1391 cpu->WriteMemory32(addr + 4, word2);
1392 }
1393
1394 addr += 8;
1395 }
1396 }
1397
1398 cpu->Reg[R13] -= inst_cream->imm32;
1399 }
1400 cpu->Reg[15] += cpu->GetInstructionSize();
1401 INC_PC(sizeof(vpush_inst));
1402 FETCH_INST;
1403 GOTO_NEXT_INST;
1404}
1405#endif
1406
1407/* ----------------------------------------------------------------------- */
1408/* VSTM */
1409/* cond 110P UDW0 Rn-- Vd-- 101X imm8 imm8 */
1410#ifdef VFP_INTERPRETER_STRUCT
1411struct vstm_inst {
1412 unsigned int single;
1413 unsigned int add;
1414 unsigned int wback;
1415 unsigned int d;
1416 unsigned int n;
1417 unsigned int imm32;
1418 unsigned int regs;
1419};
1420#endif
1421#ifdef VFP_INTERPRETER_TRANS
1422static ARM_INST_PTR INTERPRETER_TRANSLATE(vstm)(unsigned int inst, int index) {
1423 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vstm_inst));
1424 vstm_inst* inst_cream = (vstm_inst*)inst_base->component;
1425
1426 inst_base->cond = BITS(inst, 28, 31);
1427 inst_base->idx = index;
1428 inst_base->br = TransExtData::NON_BRANCH;
1429
1430 inst_cream->single = BIT(inst, 8) == 0;
1431 inst_cream->add = BIT(inst, 23);
1432 inst_cream->wback = BIT(inst, 21);
1433 inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22)
1434 : BITS(inst, 12, 15) | BIT(inst, 22) << 4);
1435 inst_cream->n = BITS(inst, 16, 19);
1436 inst_cream->imm32 = BITS(inst, 0, 7) << 2;
1437 inst_cream->regs = (inst_cream->single ? BITS(inst, 0, 7) : BITS(inst, 1, 7));
1438
1439 return inst_base;
1440}
1441#endif
1442#ifdef VFP_INTERPRETER_IMPL
1443VSTM_INST : /* encoding 1 */
1444{
1445 if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
1446 CHECK_VFP_ENABLED;
1447
1448 vstm_inst* inst_cream = (vstm_inst*)inst_base->component;
1449
1450 u32 address = cpu->Reg[inst_cream->n];
1451
1452 // Only possible in ARM mode, where PC accesses have an 8 byte offset.
1453 if (inst_cream->n == 15)
1454 address += 8;
1455
1456 if (inst_cream->add == 0)
1457 address -= inst_cream->imm32;
1458
1459 for (unsigned int i = 0; i < inst_cream->regs; i++) {
1460 if (inst_cream->single) {
1461 cpu->WriteMemory32(address, cpu->ExtReg[inst_cream->d + i]);
1462 address += 4;
1463 } else {
1464 const u32 word1 = cpu->ExtReg[(inst_cream->d + i) * 2 + 0];
1465 const u32 word2 = cpu->ExtReg[(inst_cream->d + i) * 2 + 1];
1466
1467 if (cpu->InBigEndianMode()) {
1468 cpu->WriteMemory32(address + 0, word2);
1469 cpu->WriteMemory32(address + 4, word1);
1470 } else {
1471 cpu->WriteMemory32(address + 0, word1);
1472 cpu->WriteMemory32(address + 4, word2);
1473 }
1474
1475 address += 8;
1476 }
1477 }
1478 if (inst_cream->wback) {
1479 cpu->Reg[inst_cream->n] =
1480 (inst_cream->add ? cpu->Reg[inst_cream->n] + inst_cream->imm32
1481 : cpu->Reg[inst_cream->n] - inst_cream->imm32);
1482 }
1483 }
1484 cpu->Reg[15] += 4;
1485 INC_PC(sizeof(vstm_inst));
1486
1487 FETCH_INST;
1488 GOTO_NEXT_INST;
1489}
1490#endif
1491
1492/* ----------------------------------------------------------------------- */
1493/* VPOP */
1494/* cond 1100 1D11 1101 Vd-- 101X imm8 imm8 */
1495#ifdef VFP_INTERPRETER_STRUCT
1496struct vpop_inst {
1497 unsigned int single;
1498 unsigned int d;
1499 unsigned int imm32;
1500 unsigned int regs;
1501};
1502#endif
1503#ifdef VFP_INTERPRETER_TRANS
1504static ARM_INST_PTR INTERPRETER_TRANSLATE(vpop)(unsigned int inst, int index) {
1505 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vpop_inst));
1506 vpop_inst* inst_cream = (vpop_inst*)inst_base->component;
1507
1508 inst_base->cond = BITS(inst, 28, 31);
1509 inst_base->idx = index;
1510 inst_base->br = TransExtData::NON_BRANCH;
1511
1512 inst_cream->single = BIT(inst, 8) == 0;
1513 inst_cream->d = (inst_cream->single ? (BITS(inst, 12, 15) << 1) | BIT(inst, 22)
1514 : BITS(inst, 12, 15) | (BIT(inst, 22) << 4));
1515 inst_cream->imm32 = BITS(inst, 0, 7) << 2;
1516 inst_cream->regs = (inst_cream->single ? BITS(inst, 0, 7) : BITS(inst, 1, 7));
1517
1518 return inst_base;
1519}
1520#endif
1521#ifdef VFP_INTERPRETER_IMPL
1522VPOP_INST : {
1523 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
1524 CHECK_VFP_ENABLED;
1525
1526 vpop_inst* inst_cream = (vpop_inst*)inst_base->component;
1527
1528 addr = cpu->Reg[R13];
1529
1530 for (unsigned int i = 0; i < inst_cream->regs; i++) {
1531 if (inst_cream->single) {
1532 cpu->ExtReg[inst_cream->d + i] = cpu->ReadMemory32(addr);
1533 addr += 4;
1534 } else {
1535 const u32 word1 = cpu->ReadMemory32(addr + 0);
1536 const u32 word2 = cpu->ReadMemory32(addr + 4);
1537
1538 if (cpu->InBigEndianMode()) {
1539 cpu->ExtReg[(inst_cream->d + i) * 2 + 0] = word2;
1540 cpu->ExtReg[(inst_cream->d + i) * 2 + 1] = word1;
1541 } else {
1542 cpu->ExtReg[(inst_cream->d + i) * 2 + 0] = word1;
1543 cpu->ExtReg[(inst_cream->d + i) * 2 + 1] = word2;
1544 }
1545
1546 addr += 8;
1547 }
1548 }
1549 cpu->Reg[R13] += inst_cream->imm32;
1550 }
1551 cpu->Reg[15] += cpu->GetInstructionSize();
1552 INC_PC(sizeof(vpop_inst));
1553 FETCH_INST;
1554 GOTO_NEXT_INST;
1555}
1556#endif
1557
1558/* ----------------------------------------------------------------------- */
1559/* VLDR */
1560/* cond 1101 UD01 Rn-- Vd-- 101X imm8 imm8 */
1561#ifdef VFP_INTERPRETER_STRUCT
1562struct vldr_inst {
1563 unsigned int single;
1564 unsigned int n;
1565 unsigned int d;
1566 unsigned int imm32;
1567 unsigned int add;
1568};
1569#endif
1570#ifdef VFP_INTERPRETER_TRANS
1571static ARM_INST_PTR INTERPRETER_TRANSLATE(vldr)(unsigned int inst, int index) {
1572 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vldr_inst));
1573 vldr_inst* inst_cream = (vldr_inst*)inst_base->component;
1574
1575 inst_base->cond = BITS(inst, 28, 31);
1576 inst_base->idx = index;
1577 inst_base->br = TransExtData::NON_BRANCH;
1578
1579 inst_cream->single = BIT(inst, 8) == 0;
1580 inst_cream->add = BIT(inst, 23);
1581 inst_cream->imm32 = BITS(inst, 0, 7) << 2;
1582 inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22)
1583 : BITS(inst, 12, 15) | BIT(inst, 22) << 4);
1584 inst_cream->n = BITS(inst, 16, 19);
1585
1586 return inst_base;
1587}
1588#endif
1589#ifdef VFP_INTERPRETER_IMPL
1590VLDR_INST : {
1591 if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
1592 CHECK_VFP_ENABLED;
1593
1594 vldr_inst* inst_cream = (vldr_inst*)inst_base->component;
1595
1596 unsigned int base = (inst_cream->n == 15 ? (cpu->Reg[inst_cream->n] & 0xFFFFFFFC) + 8
1597 : cpu->Reg[inst_cream->n]);
1598 addr = (inst_cream->add ? base + inst_cream->imm32 : base - inst_cream->imm32);
1599
1600 if (inst_cream->single) {
1601 cpu->ExtReg[inst_cream->d] = cpu->ReadMemory32(addr);
1602 } else {
1603 const u32 word1 = cpu->ReadMemory32(addr + 0);
1604 const u32 word2 = cpu->ReadMemory32(addr + 4);
1605
1606 if (cpu->InBigEndianMode()) {
1607 cpu->ExtReg[inst_cream->d * 2 + 0] = word2;
1608 cpu->ExtReg[inst_cream->d * 2 + 1] = word1;
1609 } else {
1610 cpu->ExtReg[inst_cream->d * 2 + 0] = word1;
1611 cpu->ExtReg[inst_cream->d * 2 + 1] = word2;
1612 }
1613 }
1614 }
1615 cpu->Reg[15] += cpu->GetInstructionSize();
1616 INC_PC(sizeof(vldr_inst));
1617 FETCH_INST;
1618 GOTO_NEXT_INST;
1619}
1620#endif
1621
1622/* ----------------------------------------------------------------------- */
1623/* VLDM */
1624/* cond 110P UDW1 Rn-- Vd-- 101X imm8 imm8 */
1625#ifdef VFP_INTERPRETER_STRUCT
1626struct vldm_inst {
1627 unsigned int single;
1628 unsigned int add;
1629 unsigned int wback;
1630 unsigned int d;
1631 unsigned int n;
1632 unsigned int imm32;
1633 unsigned int regs;
1634};
1635#endif
1636#ifdef VFP_INTERPRETER_TRANS
1637static ARM_INST_PTR INTERPRETER_TRANSLATE(vldm)(unsigned int inst, int index) {
1638 arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vldm_inst));
1639 vldm_inst* inst_cream = (vldm_inst*)inst_base->component;
1640
1641 inst_base->cond = BITS(inst, 28, 31);
1642 inst_base->idx = index;
1643 inst_base->br = TransExtData::NON_BRANCH;
1644
1645 inst_cream->single = BIT(inst, 8) == 0;
1646 inst_cream->add = BIT(inst, 23);
1647 inst_cream->wback = BIT(inst, 21);
1648 inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22)
1649 : BITS(inst, 12, 15) | BIT(inst, 22) << 4);
1650 inst_cream->n = BITS(inst, 16, 19);
1651 inst_cream->imm32 = BITS(inst, 0, 7) << 2;
1652 inst_cream->regs = (inst_cream->single ? BITS(inst, 0, 7) : BITS(inst, 1, 7));
1653
1654 return inst_base;
1655}
1656#endif
1657#ifdef VFP_INTERPRETER_IMPL
1658VLDM_INST : {
1659 if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
1660 CHECK_VFP_ENABLED;
1661
1662 vldm_inst* inst_cream = (vldm_inst*)inst_base->component;
1663
1664 u32 address = cpu->Reg[inst_cream->n];
1665
1666 // Only possible in ARM mode, where PC accesses have an 8 byte offset.
1667 if (inst_cream->n == 15)
1668 address += 8;
1669
1670 if (inst_cream->add == 0)
1671 address -= inst_cream->imm32;
1672
1673 for (unsigned int i = 0; i < inst_cream->regs; i++) {
1674 if (inst_cream->single) {
1675 cpu->ExtReg[inst_cream->d + i] = cpu->ReadMemory32(address);
1676 address += 4;
1677 } else {
1678 const u32 word1 = cpu->ReadMemory32(address + 0);
1679 const u32 word2 = cpu->ReadMemory32(address + 4);
1680
1681 if (cpu->InBigEndianMode()) {
1682 cpu->ExtReg[(inst_cream->d + i) * 2 + 0] = word2;
1683 cpu->ExtReg[(inst_cream->d + i) * 2 + 1] = word1;
1684 } else {
1685 cpu->ExtReg[(inst_cream->d + i) * 2 + 0] = word1;
1686 cpu->ExtReg[(inst_cream->d + i) * 2 + 1] = word2;
1687 }
1688
1689 address += 8;
1690 }
1691 }
1692 if (inst_cream->wback) {
1693 cpu->Reg[inst_cream->n] =
1694 (inst_cream->add ? cpu->Reg[inst_cream->n] + inst_cream->imm32
1695 : cpu->Reg[inst_cream->n] - inst_cream->imm32);
1696 }
1697 }
1698 cpu->Reg[15] += cpu->GetInstructionSize();
1699 INC_PC(sizeof(vldm_inst));
1700 FETCH_INST;
1701 GOTO_NEXT_INST;
1702}
1703#endif
diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
deleted file mode 100644
index 108f03aa9..000000000
--- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
+++ /dev/null
@@ -1,1272 +0,0 @@
1/*
2 vfp/vfpsingle.c - ARM VFPv3 emulation unit - SoftFloat single instruction
3 Copyright (C) 2003 Skyeye Develop Group
4 for help please send mail to <skyeye-developer@lists.gro.clinux.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21/*
22 * This code is derived in part from :
23 * - Android kernel
24 * - John R. Housers softfloat library, which
25 * carries the following notice:
26 *
27 * ===========================================================================
28 * This C source file is part of the SoftFloat IEC/IEEE Floating-point
29 * Arithmetic Package, Release 2.
30 *
31 * Written by John R. Hauser. This work was made possible in part by the
32 * International Computer Science Institute, located at Suite 600, 1947 Center
33 * Street, Berkeley, California 94704. Funding was partially provided by the
34 * National Science Foundation under grant MIP-9311980. The original version
35 * of this code was written as part of a project to build a fixed-point vector
36 * processor in collaboration with the University of California at Berkeley,
37 * overseen by Profs. Nelson Morgan and John Wawrzynek. More information
38 * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
39 * arithmetic/softfloat.html'.
40 *
41 * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
42 * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
43 * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
44 * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
45 * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
46 *
47 * Derivative works are acceptable, even for commercial purposes, so long as
48 * (1) they include prominent notice that the work is derivative, and (2) they
49 * include prominent notice akin to these three paragraphs for those parts of
50 * this code that are retained.
51 * ===========================================================================
52 */
53
54#include <algorithm>
55#include <cinttypes>
56#include "common/common_funcs.h"
57#include "common/common_types.h"
58#include "common/logging/log.h"
59#include "core/arm/skyeye_common/vfp/asm_vfp.h"
60#include "core/arm/skyeye_common/vfp/vfp.h"
61#include "core/arm/skyeye_common/vfp/vfp_helper.h"
62
63static struct vfp_single vfp_single_default_qnan = {
64 255, 0, VFP_SINGLE_SIGNIFICAND_QNAN,
65};
66
67static void vfp_single_dump(const char* str, struct vfp_single* s) {
68 LOG_TRACE(Core_ARM, "%s: sign=%d exponent=%d significand=%08x", str, s->sign != 0,
69 s->exponent, s->significand);
70}
71
72static void vfp_single_normalise_denormal(struct vfp_single* vs) {
73 int bits = 31 - fls(vs->significand);
74
75 vfp_single_dump("normalise_denormal: in", vs);
76
77 if (bits) {
78 vs->exponent -= bits - 1;
79 vs->significand <<= bits;
80 }
81
82 vfp_single_dump("normalise_denormal: out", vs);
83}
84
85u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single* vs, u32 fpscr,
86 u32 exceptions, const char* func) {
87 u32 significand, incr, rmode;
88 int exponent, shift, underflow;
89
90 vfp_single_dump("pack: in", vs);
91
92 /*
93 * Infinities and NaNs are a special case.
94 */
95 if (vs->exponent == 255 && (vs->significand == 0 || exceptions))
96 goto pack;
97
98 /*
99 * Special-case zero.
100 */
101 if (vs->significand == 0) {
102 vs->exponent = 0;
103 goto pack;
104 }
105
106 exponent = vs->exponent;
107 significand = vs->significand;
108
109 /*
110 * Normalise first. Note that we shift the significand up to
111 * bit 31, so we have VFP_SINGLE_LOW_BITS + 1 below the least
112 * significant bit.
113 */
114 shift = 32 - fls(significand);
115 if (shift < 32 && shift) {
116 exponent -= shift;
117 significand <<= shift;
118 }
119
120#if 1
121 vs->exponent = exponent;
122 vs->significand = significand;
123 vfp_single_dump("pack: normalised", vs);
124#endif
125
126 /*
127 * Tiny number?
128 */
129 underflow = exponent < 0;
130 if (underflow) {
131 significand = vfp_shiftright32jamming(significand, -exponent);
132 exponent = 0;
133#if 1
134 vs->exponent = exponent;
135 vs->significand = significand;
136 vfp_single_dump("pack: tiny number", vs);
137#endif
138 if (!(significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1)))
139 underflow = 0;
140
141 int type = vfp_single_type(vs);
142
143 if ((type & VFP_DENORMAL) && (fpscr & FPSCR_FLUSH_TO_ZERO)) {
144 // Flush denormal to positive 0
145 significand = 0;
146
147 vs->sign = 0;
148 vs->significand = significand;
149
150 underflow = 0;
151 exceptions |= FPSCR_UFC;
152 }
153 }
154
155 /*
156 * Select rounding increment.
157 */
158 incr = 0;
159 rmode = fpscr & FPSCR_RMODE_MASK;
160
161 if (rmode == FPSCR_ROUND_NEAREST) {
162 incr = 1 << VFP_SINGLE_LOW_BITS;
163 if ((significand & (1 << (VFP_SINGLE_LOW_BITS + 1))) == 0)
164 incr -= 1;
165 } else if (rmode == FPSCR_ROUND_TOZERO) {
166 incr = 0;
167 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vs->sign != 0))
168 incr = (1 << (VFP_SINGLE_LOW_BITS + 1)) - 1;
169
170 LOG_TRACE(Core_ARM, "rounding increment = 0x%08x", incr);
171
172 /*
173 * Is our rounding going to overflow?
174 */
175 if ((significand + incr) < significand) {
176 exponent += 1;
177 significand = (significand >> 1) | (significand & 1);
178 incr >>= 1;
179#if 1
180 vs->exponent = exponent;
181 vs->significand = significand;
182 vfp_single_dump("pack: overflow", vs);
183#endif
184 }
185
186 /*
187 * If any of the low bits (which will be shifted out of the
188 * number) are non-zero, the result is inexact.
189 */
190 if (significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1))
191 exceptions |= FPSCR_IXC;
192
193 /*
194 * Do our rounding.
195 */
196 significand += incr;
197
198 /*
199 * Infinity?
200 */
201 if (exponent >= 254) {
202 exceptions |= FPSCR_OFC | FPSCR_IXC;
203 if (incr == 0) {
204 vs->exponent = 253;
205 vs->significand = 0x7fffffff;
206 } else {
207 vs->exponent = 255; /* infinity */
208 vs->significand = 0;
209 }
210 } else {
211 if (significand >> (VFP_SINGLE_LOW_BITS + 1) == 0)
212 exponent = 0;
213 if (exponent || significand > 0x80000000)
214 underflow = 0;
215 if (underflow)
216 exceptions |= FPSCR_UFC;
217 vs->exponent = exponent;
218 vs->significand = significand >> 1;
219 }
220
221pack:
222 vfp_single_dump("pack: final", vs);
223 {
224 s32 d = vfp_single_pack(vs);
225 LOG_TRACE(Core_ARM, "%s: d(s%d)=%08x exceptions=%08x", func, sd, d, exceptions);
226 vfp_put_float(state, d, sd);
227 }
228
229 return exceptions;
230}
231
232/*
233 * Propagate the NaN, setting exceptions if it is signalling.
234 * 'n' is always a NaN. 'm' may be a number, NaN or infinity.
235 */
236static u32 vfp_propagate_nan(struct vfp_single* vsd, struct vfp_single* vsn, struct vfp_single* vsm,
237 u32 fpscr) {
238 struct vfp_single* nan;
239 int tn, tm = 0;
240
241 tn = vfp_single_type(vsn);
242
243 if (vsm)
244 tm = vfp_single_type(vsm);
245
246 if (fpscr & FPSCR_DEFAULT_NAN)
247 /*
248 * Default NaN mode - always returns a quiet NaN
249 */
250 nan = &vfp_single_default_qnan;
251 else {
252 /*
253 * Contemporary mode - select the first signalling
254 * NAN, or if neither are signalling, the first
255 * quiet NAN.
256 */
257 if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN))
258 nan = vsn;
259 else
260 nan = vsm;
261 /*
262 * Make the NaN quiet.
263 */
264 nan->significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
265 }
266
267 *vsd = *nan;
268
269 /*
270 * If one was a signalling NAN, raise invalid operation.
271 */
272 return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
273}
274
275/*
276 * Extended operations
277 */
278static u32 vfp_single_fabs(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
279 vfp_put_float(state, vfp_single_packed_abs(m), sd);
280 return 0;
281}
282
283static u32 vfp_single_fcpy(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
284 vfp_put_float(state, m, sd);
285 return 0;
286}
287
288static u32 vfp_single_fneg(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
289 vfp_put_float(state, vfp_single_packed_negate(m), sd);
290 return 0;
291}
292
293static const u16 sqrt_oddadjust[] = {
294 0x0004, 0x0022, 0x005d, 0x00b1, 0x011d, 0x019f, 0x0236, 0x02e0,
295 0x039c, 0x0468, 0x0545, 0x0631, 0x072b, 0x0832, 0x0946, 0x0a67,
296};
297
298static const u16 sqrt_evenadjust[] = {
299 0x0a2d, 0x08af, 0x075a, 0x0629, 0x051a, 0x0429, 0x0356, 0x029e,
300 0x0200, 0x0179, 0x0109, 0x00af, 0x0068, 0x0034, 0x0012, 0x0002,
301};
302
303u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand) {
304 int index;
305 u32 z, a;
306
307 if ((significand & 0xc0000000) != 0x40000000) {
308 LOG_TRACE(Core_ARM, "invalid significand");
309 }
310
311 a = significand << 1;
312 index = (a >> 27) & 15;
313 if (exponent & 1) {
314 z = 0x4000 + (a >> 17) - sqrt_oddadjust[index];
315 z = ((a / z) << 14) + (z << 15);
316 a >>= 1;
317 } else {
318 z = 0x8000 + (a >> 17) - sqrt_evenadjust[index];
319 z = a / z + z;
320 z = (z >= 0x20000) ? 0xffff8000 : (z << 15);
321 if (z <= a)
322 return (s32)a >> 1;
323 }
324 {
325 u64 v = (u64)a << 31;
326 do_div(v, z);
327 return (u32)(v + (z >> 1));
328 }
329}
330
331static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
332 struct vfp_single vsm, vsd, *vsp;
333 int ret, tm;
334 u32 exceptions = 0;
335
336 exceptions |= vfp_single_unpack(&vsm, m, fpscr);
337 tm = vfp_single_type(&vsm);
338 if (tm & (VFP_NAN | VFP_INFINITY)) {
339 vsp = &vsd;
340
341 if (tm & VFP_NAN)
342 ret = vfp_propagate_nan(vsp, &vsm, nullptr, fpscr);
343 else if (vsm.sign == 0) {
344 sqrt_copy:
345 vsp = &vsm;
346 ret = 0;
347 } else {
348 sqrt_invalid:
349 vsp = &vfp_single_default_qnan;
350 ret = FPSCR_IOC;
351 }
352 vfp_put_float(state, vfp_single_pack(vsp), sd);
353 return ret;
354 }
355
356 /*
357 * sqrt(+/- 0) == +/- 0
358 */
359 if (tm & VFP_ZERO)
360 goto sqrt_copy;
361
362 /*
363 * Normalise a denormalised number
364 */
365 if (tm & VFP_DENORMAL)
366 vfp_single_normalise_denormal(&vsm);
367
368 /*
369 * sqrt(<0) = invalid
370 */
371 if (vsm.sign)
372 goto sqrt_invalid;
373
374 vfp_single_dump("sqrt", &vsm);
375
376 /*
377 * Estimate the square root.
378 */
379 vsd.sign = 0;
380 vsd.exponent = ((vsm.exponent - 127) >> 1) + 127;
381 vsd.significand = vfp_estimate_sqrt_significand(vsm.exponent, vsm.significand) + 2;
382
383 vfp_single_dump("sqrt estimate", &vsd);
384
385 /*
386 * And now adjust.
387 */
388 if ((vsd.significand & VFP_SINGLE_LOW_BITS_MASK) <= 5) {
389 if (vsd.significand < 2) {
390 vsd.significand = 0xffffffff;
391 } else {
392 u64 term;
393 s64 rem;
394 vsm.significand <<= static_cast<u32>((vsm.exponent & 1) == 0);
395 term = (u64)vsd.significand * vsd.significand;
396 rem = ((u64)vsm.significand << 32) - term;
397
398 LOG_TRACE(Core_ARM, "term=%016" PRIx64 "rem=%016" PRIx64, term, rem);
399
400 while (rem < 0) {
401 vsd.significand -= 1;
402 rem += ((u64)vsd.significand << 1) | 1;
403 }
404 vsd.significand |= rem != 0;
405 }
406 }
407 vsd.significand = vfp_shiftright32jamming(vsd.significand, 1);
408
409 exceptions |= vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fsqrt");
410
411 return exceptions;
412}
413
414/*
415 * Equal := ZC
416 * Less than := N
417 * Greater than := C
418 * Unordered := CV
419 */
420static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u32 fpscr) {
421 s32 d;
422 u32 ret = 0;
423
424 d = vfp_get_float(state, sd);
425 if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) {
426 ret |= FPSCR_CFLAG | FPSCR_VFLAG;
427 if (signal_on_qnan ||
428 !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
429 /*
430 * Signalling NaN, or signalling on quiet NaN
431 */
432 ret |= FPSCR_IOC;
433 }
434
435 if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) {
436 ret |= FPSCR_CFLAG | FPSCR_VFLAG;
437 if (signal_on_qnan ||
438 !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
439 /*
440 * Signalling NaN, or signalling on quiet NaN
441 */
442 ret |= FPSCR_IOC;
443 }
444
445 if (ret == 0) {
446 if (d == m || vfp_single_packed_abs(d | m) == 0) {
447 /*
448 * equal
449 */
450 ret |= FPSCR_ZFLAG | FPSCR_CFLAG;
451 } else if (vfp_single_packed_sign(d ^ m)) {
452 /*
453 * different signs
454 */
455 if (vfp_single_packed_sign(d))
456 /*
457 * d is negative, so d < m
458 */
459 ret |= FPSCR_NFLAG;
460 else
461 /*
462 * d is positive, so d > m
463 */
464 ret |= FPSCR_CFLAG;
465 } else if ((vfp_single_packed_sign(d) != 0) ^ (d < m)) {
466 /*
467 * d < m
468 */
469 ret |= FPSCR_NFLAG;
470 } else if ((vfp_single_packed_sign(d) != 0) ^ (d > m)) {
471 /*
472 * d > m
473 */
474 ret |= FPSCR_CFLAG;
475 }
476 }
477 return ret;
478}
479
480static u32 vfp_single_fcmp(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
481 return vfp_compare(state, sd, 0, m, fpscr);
482}
483
484static u32 vfp_single_fcmpe(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
485 return vfp_compare(state, sd, 1, m, fpscr);
486}
487
488static u32 vfp_single_fcmpz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
489 return vfp_compare(state, sd, 0, 0, fpscr);
490}
491
492static u32 vfp_single_fcmpez(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
493 return vfp_compare(state, sd, 1, 0, fpscr);
494}
495
496static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 fpscr) {
497 struct vfp_single vsm;
498 struct vfp_double vdd;
499 int tm;
500 u32 exceptions = 0;
501
502 exceptions |= vfp_single_unpack(&vsm, m, fpscr);
503
504 tm = vfp_single_type(&vsm);
505
506 /*
507 * If we have a signalling NaN, signal invalid operation.
508 */
509 if (tm == VFP_SNAN)
510 exceptions |= FPSCR_IOC;
511
512 if (tm & VFP_DENORMAL)
513 vfp_single_normalise_denormal(&vsm);
514
515 vdd.sign = vsm.sign;
516 vdd.significand = (u64)vsm.significand << 32;
517
518 /*
519 * If we have an infinity or NaN, the exponent must be 2047.
520 */
521 if (tm & (VFP_INFINITY | VFP_NAN)) {
522 vdd.exponent = 2047;
523 if (tm == VFP_QNAN)
524 vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
525 goto pack_nan;
526 } else if (tm & VFP_ZERO)
527 vdd.exponent = 0;
528 else
529 vdd.exponent = vsm.exponent + (1023 - 127);
530
531 return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fcvtd");
532
533pack_nan:
534 vfp_put_double(state, vfp_double_pack(&vdd), dd);
535 return exceptions;
536}
537
538static u32 vfp_single_fuito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
539 struct vfp_single vs;
540
541 vs.sign = 0;
542 vs.exponent = 127 + 31 - 1;
543 vs.significand = (u32)m;
544
545 return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fuito");
546}
547
548static u32 vfp_single_fsito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
549 struct vfp_single vs;
550
551 vs.sign = (m & 0x80000000) >> 16;
552 vs.exponent = 127 + 31 - 1;
553 vs.significand = vs.sign ? -m : m;
554
555 return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fsito");
556}
557
558static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
559 struct vfp_single vsm;
560 u32 d, exceptions = 0;
561 int rmode = fpscr & FPSCR_RMODE_MASK;
562 int tm;
563
564 exceptions |= vfp_single_unpack(&vsm, m, fpscr);
565 vfp_single_dump("VSM", &vsm);
566
567 /*
568 * Do we have a denormalised number?
569 */
570 tm = vfp_single_type(&vsm);
571 if (tm & VFP_DENORMAL)
572 exceptions |= FPSCR_IDC;
573
574 if (tm & VFP_NAN)
575 vsm.sign = 1;
576
577 if (vsm.exponent >= 127 + 32) {
578 d = vsm.sign ? 0 : 0xffffffff;
579 exceptions |= FPSCR_IOC;
580 } else if (vsm.exponent >= 127) {
581 int shift = 127 + 31 - vsm.exponent;
582 u32 rem, incr = 0;
583
584 /*
585 * 2^0 <= m < 2^32-2^8
586 */
587 d = (vsm.significand << 1) >> shift;
588 if (shift > 0) {
589 rem = (vsm.significand << 1) << (32 - shift);
590 } else {
591 rem = 0;
592 }
593
594 if (rmode == FPSCR_ROUND_NEAREST) {
595 incr = 0x80000000;
596 if ((d & 1) == 0)
597 incr -= 1;
598 } else if (rmode == FPSCR_ROUND_TOZERO) {
599 incr = 0;
600 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) {
601 incr = ~0;
602 }
603
604 if ((rem + incr) < rem) {
605 if (d < 0xffffffff)
606 d += 1;
607 else
608 exceptions |= FPSCR_IOC;
609 }
610
611 if (d && vsm.sign) {
612 d = 0;
613 exceptions |= FPSCR_IOC;
614 } else if (rem)
615 exceptions |= FPSCR_IXC;
616 } else {
617 d = 0;
618 if (vsm.exponent | vsm.significand) {
619 if (rmode == FPSCR_ROUND_NEAREST) {
620 if (vsm.exponent >= 126) {
621 d = vsm.sign ? 0 : 1;
622 exceptions |= vsm.sign ? FPSCR_IOC : FPSCR_IXC;
623 } else {
624 exceptions |= FPSCR_IXC;
625 }
626 } else if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) {
627 d = 1;
628 exceptions |= FPSCR_IXC;
629 } else if (rmode == FPSCR_ROUND_MINUSINF) {
630 exceptions |= vsm.sign ? FPSCR_IOC : FPSCR_IXC;
631 } else {
632 exceptions |= FPSCR_IXC;
633 }
634 }
635 }
636
637 LOG_TRACE(Core_ARM, "ftoui: d(s%d)=%08x exceptions=%08x", sd, d, exceptions);
638
639 vfp_put_float(state, d, sd);
640
641 return exceptions;
642}
643
644static u32 vfp_single_ftouiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
645 return vfp_single_ftoui(state, sd, unused, m, (fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO);
646}
647
648static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
649 struct vfp_single vsm;
650 u32 d, exceptions = 0;
651 int rmode = fpscr & FPSCR_RMODE_MASK;
652 int tm;
653
654 exceptions |= vfp_single_unpack(&vsm, m, fpscr);
655 vfp_single_dump("VSM", &vsm);
656
657 /*
658 * Do we have a denormalised number?
659 */
660 tm = vfp_single_type(&vsm);
661 if (vfp_single_type(&vsm) & VFP_DENORMAL)
662 exceptions |= FPSCR_IDC;
663
664 if (tm & VFP_NAN) {
665 d = 0;
666 exceptions |= FPSCR_IOC;
667 } else if (vsm.exponent >= 127 + 31) {
668 /*
669 * m >= 2^31-2^7: invalid
670 */
671 d = 0x7fffffff;
672 if (vsm.sign)
673 d = ~d;
674 exceptions |= FPSCR_IOC;
675 } else if (vsm.exponent >= 127) {
676 int shift = 127 + 31 - vsm.exponent;
677 u32 rem, incr = 0;
678
679 /* 2^0 <= m <= 2^31-2^7 */
680 d = (vsm.significand << 1) >> shift;
681 rem = (vsm.significand << 1) << (32 - shift);
682
683 if (rmode == FPSCR_ROUND_NEAREST) {
684 incr = 0x80000000;
685 if ((d & 1) == 0)
686 incr -= 1;
687 } else if (rmode == FPSCR_ROUND_TOZERO) {
688 incr = 0;
689 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) {
690 incr = ~0;
691 }
692
693 if ((rem + incr) < rem && d < 0xffffffff)
694 d += 1;
695 if (d > (0x7fffffffu + (vsm.sign != 0))) {
696 d = (0x7fffffffu + (vsm.sign != 0));
697 exceptions |= FPSCR_IOC;
698 } else if (rem)
699 exceptions |= FPSCR_IXC;
700
701 if (vsm.sign)
702 d = (~d + 1);
703 } else {
704 d = 0;
705 if (vsm.exponent | vsm.significand) {
706 exceptions |= FPSCR_IXC;
707 if (rmode == FPSCR_ROUND_NEAREST) {
708 if (vsm.exponent >= 126)
709 d = vsm.sign ? 0xffffffff : 1;
710 } else if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) {
711 d = 1;
712 } else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) {
713 d = 0xffffffff;
714 }
715 }
716 }
717
718 LOG_TRACE(Core_ARM, "ftosi: d(s%d)=%08x exceptions=%08x", sd, d, exceptions);
719
720 vfp_put_float(state, (s32)d, sd);
721
722 return exceptions;
723}
724
725static u32 vfp_single_ftosiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
726 return vfp_single_ftosi(state, sd, unused, m, (fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO);
727}
728
729static struct op fops_ext[] = {
730 {vfp_single_fcpy, 0}, // 0x00000000 - FEXT_FCPY
731 {vfp_single_fabs, 0}, // 0x00000001 - FEXT_FABS
732 {vfp_single_fneg, 0}, // 0x00000002 - FEXT_FNEG
733 {vfp_single_fsqrt, 0}, // 0x00000003 - FEXT_FSQRT
734 {nullptr, 0},
735 {nullptr, 0},
736 {nullptr, 0},
737 {nullptr, 0},
738 {vfp_single_fcmp, OP_SCALAR}, // 0x00000008 - FEXT_FCMP
739 {vfp_single_fcmpe, OP_SCALAR}, // 0x00000009 - FEXT_FCMPE
740 {vfp_single_fcmpz, OP_SCALAR}, // 0x0000000A - FEXT_FCMPZ
741 {vfp_single_fcmpez, OP_SCALAR}, // 0x0000000B - FEXT_FCMPEZ
742 {nullptr, 0},
743 {nullptr, 0},
744 {nullptr, 0},
745 {vfp_single_fcvtd, OP_SCALAR | OP_DD}, // 0x0000000F - FEXT_FCVT
746 {vfp_single_fuito, OP_SCALAR}, // 0x00000010 - FEXT_FUITO
747 {vfp_single_fsito, OP_SCALAR}, // 0x00000011 - FEXT_FSITO
748 {nullptr, 0},
749 {nullptr, 0},
750 {nullptr, 0},
751 {nullptr, 0},
752 {nullptr, 0},
753 {nullptr, 0},
754 {vfp_single_ftoui, OP_SCALAR}, // 0x00000018 - FEXT_FTOUI
755 {vfp_single_ftouiz, OP_SCALAR}, // 0x00000019 - FEXT_FTOUIZ
756 {vfp_single_ftosi, OP_SCALAR}, // 0x0000001A - FEXT_FTOSI
757 {vfp_single_ftosiz, OP_SCALAR}, // 0x0000001B - FEXT_FTOSIZ
758};
759
760static u32 vfp_single_fadd_nonnumber(struct vfp_single* vsd, struct vfp_single* vsn,
761 struct vfp_single* vsm, u32 fpscr) {
762 struct vfp_single* vsp;
763 u32 exceptions = 0;
764 int tn, tm;
765
766 tn = vfp_single_type(vsn);
767 tm = vfp_single_type(vsm);
768
769 if (tn & tm & VFP_INFINITY) {
770 /*
771 * Two infinities. Are they different signs?
772 */
773 if (vsn->sign ^ vsm->sign) {
774 /*
775 * different signs -> invalid
776 */
777 exceptions |= FPSCR_IOC;
778 vsp = &vfp_single_default_qnan;
779 } else {
780 /*
781 * same signs -> valid
782 */
783 vsp = vsn;
784 }
785 } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) {
786 /*
787 * One infinity and one number -> infinity
788 */
789 vsp = vsn;
790 } else {
791 /*
792 * 'n' is a NaN of some type
793 */
794 return vfp_propagate_nan(vsd, vsn, vsm, fpscr);
795 }
796 *vsd = *vsp;
797 return exceptions;
798}
799
800static u32 vfp_single_add(struct vfp_single* vsd, struct vfp_single* vsn, struct vfp_single* vsm,
801 u32 fpscr) {
802 u32 exp_diff, m_sig;
803
804 if (vsn->significand & 0x80000000 || vsm->significand & 0x80000000) {
805 LOG_WARNING(Core_ARM, "bad FP values");
806 vfp_single_dump("VSN", vsn);
807 vfp_single_dump("VSM", vsm);
808 }
809
810 /*
811 * Ensure that 'n' is the largest magnitude number. Note that
812 * if 'n' and 'm' have equal exponents, we do not swap them.
813 * This ensures that NaN propagation works correctly.
814 */
815 if (vsn->exponent < vsm->exponent) {
816 std::swap(vsm, vsn);
817 }
818
819 /*
820 * Is 'n' an infinity or a NaN? Note that 'm' may be a number,
821 * infinity or a NaN here.
822 */
823 if (vsn->exponent == 255)
824 return vfp_single_fadd_nonnumber(vsd, vsn, vsm, fpscr);
825
826 /*
827 * We have two proper numbers, where 'vsn' is the larger magnitude.
828 *
829 * Copy 'n' to 'd' before doing the arithmetic.
830 */
831 *vsd = *vsn;
832
833 /*
834 * Align both numbers.
835 */
836 exp_diff = vsn->exponent - vsm->exponent;
837 m_sig = vfp_shiftright32jamming(vsm->significand, exp_diff);
838
839 /*
840 * If the signs are different, we are really subtracting.
841 */
842 if (vsn->sign ^ vsm->sign) {
843 m_sig = vsn->significand - m_sig;
844 if ((s32)m_sig < 0) {
845 vsd->sign = vfp_sign_negate(vsd->sign);
846 m_sig = (~m_sig + 1);
847 } else if (m_sig == 0) {
848 vsd->sign = (fpscr & FPSCR_RMODE_MASK) == FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
849 }
850 } else {
851 m_sig = vsn->significand + m_sig;
852 }
853 vsd->significand = m_sig;
854
855 return 0;
856}
857
858static u32 vfp_single_multiply(struct vfp_single* vsd, struct vfp_single* vsn,
859 struct vfp_single* vsm, u32 fpscr) {
860 vfp_single_dump("VSN", vsn);
861 vfp_single_dump("VSM", vsm);
862
863 /*
864 * Ensure that 'n' is the largest magnitude number. Note that
865 * if 'n' and 'm' have equal exponents, we do not swap them.
866 * This ensures that NaN propagation works correctly.
867 */
868 if (vsn->exponent < vsm->exponent) {
869 std::swap(vsm, vsn);
870 LOG_TRACE(Core_ARM, "swapping M <-> N");
871 }
872
873 vsd->sign = vsn->sign ^ vsm->sign;
874
875 /*
876 * If 'n' is an infinity or NaN, handle it. 'm' may be anything.
877 */
878 if (vsn->exponent == 255) {
879 if (vsn->significand || (vsm->exponent == 255 && vsm->significand))
880 return vfp_propagate_nan(vsd, vsn, vsm, fpscr);
881 if ((vsm->exponent | vsm->significand) == 0) {
882 *vsd = vfp_single_default_qnan;
883 return FPSCR_IOC;
884 }
885 vsd->exponent = vsn->exponent;
886 vsd->significand = 0;
887 return 0;
888 }
889
890 /*
891 * If 'm' is zero, the result is always zero. In this case,
892 * 'n' may be zero or a number, but it doesn't matter which.
893 */
894 if ((vsm->exponent | vsm->significand) == 0) {
895 vsd->exponent = 0;
896 vsd->significand = 0;
897 return 0;
898 }
899
900 /*
901 * We add 2 to the destination exponent for the same reason as
902 * the addition case - though this time we have +1 from each
903 * input operand.
904 */
905 vsd->exponent = vsn->exponent + vsm->exponent - 127 + 2;
906 vsd->significand = vfp_hi64to32jamming((u64)vsn->significand * vsm->significand);
907
908 vfp_single_dump("VSD", vsd);
909 return 0;
910}
911
912#define NEG_MULTIPLY (1 << 0)
913#define NEG_SUBTRACT (1 << 1)
914
915static u32 vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr,
916 u32 negate, const char* func) {
917 vfp_single vsd, vsp, vsn, vsm;
918 u32 exceptions = 0;
919 s32 v;
920
921 v = vfp_get_float(state, sn);
922 LOG_TRACE(Core_ARM, "s%u = %08x", sn, v);
923 exceptions |= vfp_single_unpack(&vsn, v, fpscr);
924 if (vsn.exponent == 0 && vsn.significand)
925 vfp_single_normalise_denormal(&vsn);
926
927 exceptions |= vfp_single_unpack(&vsm, m, fpscr);
928 if (vsm.exponent == 0 && vsm.significand)
929 vfp_single_normalise_denormal(&vsm);
930
931 exceptions |= vfp_single_multiply(&vsp, &vsn, &vsm, fpscr);
932
933 if (negate & NEG_MULTIPLY)
934 vsp.sign = vfp_sign_negate(vsp.sign);
935
936 v = vfp_get_float(state, sd);
937 LOG_TRACE(Core_ARM, "s%u = %08x", sd, v);
938 exceptions |= vfp_single_unpack(&vsn, v, fpscr);
939 if (vsn.exponent == 0 && vsn.significand != 0)
940 vfp_single_normalise_denormal(&vsn);
941
942 if (negate & NEG_SUBTRACT)
943 vsn.sign = vfp_sign_negate(vsn.sign);
944
945 exceptions |= vfp_single_add(&vsd, &vsn, &vsp, fpscr);
946
947 return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, func);
948}
949
950/*
951 * Standard operations
952 */
953
954/*
955 * sd = sd + (sn * sm)
956 */
957static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) {
958 LOG_TRACE(Core_ARM, "s%u = %08x", sn, sd);
959 return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, 0, "fmac");
960}
961
962/*
963 * sd = sd - (sn * sm)
964 */
965static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) {
966 // TODO: this one has its arguments inverted, investigate.
967 LOG_TRACE(Core_ARM, "s%u = %08x", sd, sn);
968 return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_MULTIPLY, "fnmac");
969}
970
971/*
972 * sd = -sd + (sn * sm)
973 */
974static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) {
975 LOG_TRACE(Core_ARM, "s%u = %08x", sn, sd);
976 return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT, "fmsc");
977}
978
979/*
980 * sd = -sd - (sn * sm)
981 */
982static u32 vfp_single_fnmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) {
983 LOG_TRACE(Core_ARM, "s%u = %08x", sn, sd);
984 return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY,
985 "fnmsc");
986}
987
988/*
989 * sd = sn * sm
990 */
991static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) {
992 struct vfp_single vsd, vsn, vsm;
993 u32 exceptions = 0;
994 s32 n = vfp_get_float(state, sn);
995
996 LOG_TRACE(Core_ARM, "s%u = %08x", sn, n);
997
998 exceptions |= vfp_single_unpack(&vsn, n, fpscr);
999 if (vsn.exponent == 0 && vsn.significand)
1000 vfp_single_normalise_denormal(&vsn);
1001
1002 exceptions |= vfp_single_unpack(&vsm, m, fpscr);
1003 if (vsm.exponent == 0 && vsm.significand)
1004 vfp_single_normalise_denormal(&vsm);
1005
1006 exceptions |= vfp_single_multiply(&vsd, &vsn, &vsm, fpscr);
1007 return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fmul");
1008}
1009
1010/*
1011 * sd = -(sn * sm)
1012 */
1013static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) {
1014 struct vfp_single vsd, vsn, vsm;
1015 u32 exceptions = 0;
1016 s32 n = vfp_get_float(state, sn);
1017
1018 LOG_TRACE(Core_ARM, "s%u = %08x", sn, n);
1019
1020 exceptions |= vfp_single_unpack(&vsn, n, fpscr);
1021 if (vsn.exponent == 0 && vsn.significand)
1022 vfp_single_normalise_denormal(&vsn);
1023
1024 exceptions |= vfp_single_unpack(&vsm, m, fpscr);
1025 if (vsm.exponent == 0 && vsm.significand)
1026 vfp_single_normalise_denormal(&vsm);
1027
1028 exceptions |= vfp_single_multiply(&vsd, &vsn, &vsm, fpscr);
1029 vsd.sign = vfp_sign_negate(vsd.sign);
1030 return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fnmul");
1031}
1032
1033/*
1034 * sd = sn + sm
1035 */
1036static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) {
1037 struct vfp_single vsd, vsn, vsm;
1038 u32 exceptions = 0;
1039 s32 n = vfp_get_float(state, sn);
1040
1041 LOG_TRACE(Core_ARM, "s%u = %08x", sn, n);
1042
1043 /*
1044 * Unpack and normalise denormals.
1045 */
1046 exceptions |= vfp_single_unpack(&vsn, n, fpscr);
1047 if (vsn.exponent == 0 && vsn.significand)
1048 vfp_single_normalise_denormal(&vsn);
1049
1050 exceptions |= vfp_single_unpack(&vsm, m, fpscr);
1051 if (vsm.exponent == 0 && vsm.significand)
1052 vfp_single_normalise_denormal(&vsm);
1053
1054 exceptions |= vfp_single_add(&vsd, &vsn, &vsm, fpscr);
1055
1056 return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fadd");
1057}
1058
1059/*
1060 * sd = sn - sm
1061 */
1062static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) {
1063 LOG_TRACE(Core_ARM, "s%u = %08x", sn, sd);
1064 /*
1065 * Subtraction is addition with one sign inverted. Unpack the second operand to perform FTZ if
1066 * necessary, we can't let fadd do this because a denormal in m might get flushed to +0 in FTZ
1067 * mode, and the resulting sign of 0 OP +0 differs between fadd and fsub. We do not need to do
1068 * this for n because +0 OP 0 is always +0 for both fadd and fsub.
1069 */
1070 struct vfp_single vsm;
1071 u32 exceptions = vfp_single_unpack(&vsm, m, fpscr);
1072 if (exceptions & FPSCR_IDC) {
1073 // The value was flushed to zero, re-pack it.
1074 m = vfp_single_pack(&vsm);
1075 }
1076
1077 if (m != 0x7FC00000) // Only negate if m isn't NaN.
1078 m = vfp_single_packed_negate(m);
1079
1080 return vfp_single_fadd(state, sd, sn, m, fpscr) | exceptions;
1081}
1082
1083/*
1084 * sd = sn / sm
1085 */
1086static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) {
1087 struct vfp_single vsd, vsn, vsm;
1088 u32 exceptions = 0;
1089 s32 n = vfp_get_float(state, sn);
1090 int tm, tn;
1091
1092 LOG_TRACE(Core_ARM, "s%u = %08x", sn, n);
1093
1094 exceptions |= vfp_single_unpack(&vsn, n, fpscr);
1095 exceptions |= vfp_single_unpack(&vsm, m, fpscr);
1096
1097 vsd.sign = vsn.sign ^ vsm.sign;
1098
1099 tn = vfp_single_type(&vsn);
1100 tm = vfp_single_type(&vsm);
1101
1102 /*
1103 * Is n a NAN?
1104 */
1105 if (tn & VFP_NAN)
1106 goto vsn_nan;
1107
1108 /*
1109 * Is m a NAN?
1110 */
1111 if (tm & VFP_NAN)
1112 goto vsm_nan;
1113
1114 /*
1115 * If n and m are infinity, the result is invalid
1116 * If n and m are zero, the result is invalid
1117 */
1118 if (tm & tn & (VFP_INFINITY | VFP_ZERO))
1119 goto invalid;
1120
1121 /*
1122 * If n is infinity, the result is infinity
1123 */
1124 if (tn & VFP_INFINITY)
1125 goto infinity;
1126
1127 /*
1128 * If m is zero, raise div0 exception
1129 */
1130 if (tm & VFP_ZERO)
1131 goto divzero;
1132
1133 /*
1134 * If m is infinity, or n is zero, the result is zero
1135 */
1136 if (tm & VFP_INFINITY || tn & VFP_ZERO)
1137 goto zero;
1138
1139 if (tn & VFP_DENORMAL)
1140 vfp_single_normalise_denormal(&vsn);
1141 if (tm & VFP_DENORMAL)
1142 vfp_single_normalise_denormal(&vsm);
1143
1144 /*
1145 * Ok, we have two numbers, we can perform division.
1146 */
1147 vsd.exponent = vsn.exponent - vsm.exponent + 127 - 1;
1148 vsm.significand <<= 1;
1149 if (vsm.significand <= (2 * vsn.significand)) {
1150 vsn.significand >>= 1;
1151 vsd.exponent++;
1152 }
1153 {
1154 u64 significand = (u64)vsn.significand << 32;
1155 do_div(significand, vsm.significand);
1156 vsd.significand = (u32)significand;
1157 }
1158 if ((vsd.significand & 0x3f) == 0)
1159 vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32);
1160
1161 return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fdiv");
1162
1163vsn_nan:
1164 exceptions |= vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr);
1165pack:
1166 vfp_put_float(state, vfp_single_pack(&vsd), sd);
1167 return exceptions;
1168
1169vsm_nan:
1170 exceptions |= vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr);
1171 goto pack;
1172
1173zero:
1174 vsd.exponent = 0;
1175 vsd.significand = 0;
1176 goto pack;
1177
1178divzero:
1179 exceptions |= FPSCR_DZC;
1180infinity:
1181 vsd.exponent = 255;
1182 vsd.significand = 0;
1183 goto pack;
1184
1185invalid:
1186 vfp_put_float(state, vfp_single_pack(&vfp_single_default_qnan), sd);
1187 return FPSCR_IOC;
1188}
1189
1190static struct op fops[] = {
1191 {vfp_single_fmac, 0}, {vfp_single_fmsc, 0}, {vfp_single_fmul, 0},
1192 {vfp_single_fadd, 0}, {vfp_single_fnmac, 0}, {vfp_single_fnmsc, 0},
1193 {vfp_single_fnmul, 0}, {vfp_single_fsub, 0}, {vfp_single_fdiv, 0},
1194};
1195
1196#define FREG_BANK(x) ((x)&0x18)
1197#define FREG_IDX(x) ((x)&7)
1198
1199u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr) {
1200 u32 op = inst & FOP_MASK;
1201 u32 exceptions = 0;
1202 unsigned int dest;
1203 unsigned int sn = vfp_get_sn(inst);
1204 unsigned int sm = vfp_get_sm(inst);
1205 unsigned int vecitr, veclen, vecstride;
1206 struct op* fop;
1207
1208 vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK);
1209
1210 fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
1211
1212 /*
1213 * fcvtsd takes a dN register number as destination, not sN.
1214 * Technically, if bit 0 of dd is set, this is an invalid
1215 * instruction. However, we ignore this for efficiency.
1216 * It also only operates on scalars.
1217 */
1218 if (fop->flags & OP_DD)
1219 dest = vfp_get_dd(inst);
1220 else
1221 dest = vfp_get_sd(inst);
1222
1223 /*
1224 * If destination bank is zero, vector length is always '1'.
1225 * ARM DDI0100F C5.1.3, C5.3.2.
1226 */
1227 if ((fop->flags & OP_SCALAR) || FREG_BANK(dest) == 0)
1228 veclen = 0;
1229 else
1230 veclen = fpscr & FPSCR_LENGTH_MASK;
1231
1232 LOG_TRACE(Core_ARM, "vecstride=%u veclen=%u", vecstride, (veclen >> FPSCR_LENGTH_BIT) + 1);
1233
1234 if (!fop->fn) {
1235 LOG_CRITICAL(Core_ARM, "could not find single op %d, inst=0x%x@0x%x", FEXT_TO_IDX(inst),
1236 inst, state->Reg[15]);
1237 Crash();
1238 goto invalid;
1239 }
1240
1241 for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
1242 s32 m = vfp_get_float(state, sm);
1243 u32 except;
1244 char type;
1245
1246 type = (fop->flags & OP_DD) ? 'd' : 's';
1247 if (op == FOP_EXT)
1248 LOG_TRACE(Core_ARM, "itr%d (%c%u) = op[%u] (s%u=%08x)", vecitr >> FPSCR_LENGTH_BIT,
1249 type, dest, sn, sm, m);
1250 else
1251 LOG_TRACE(Core_ARM, "itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)",
1252 vecitr >> FPSCR_LENGTH_BIT, type, dest, sn, FOP_TO_IDX(op), sm, m);
1253
1254 except = fop->fn(state, dest, sn, m, fpscr);
1255 LOG_TRACE(Core_ARM, "itr%d: exceptions=%08x", vecitr >> FPSCR_LENGTH_BIT, except);
1256
1257 exceptions |= except & ~VFP_NAN_FLAG;
1258
1259 /*
1260 * CHECK: It appears to be undefined whether we stop when
1261 * we encounter an exception. We continue.
1262 */
1263 dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7);
1264 sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7);
1265 if (FREG_BANK(sm) != 0)
1266 sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7);
1267 }
1268 return exceptions;
1269
1270invalid:
1271 return (u32)-1;
1272}