1 #include <algorithm>
2 //#include <mutex>
3 #include <assert.h>
4 #include <setjmp.h>
5 
6 // Uncomment the following line to measure the time until the OS is loaded
7 // #define BENCHMARK
8 #ifdef BENCHMARK
9     #include <time.h>
10 #endif
11 
12 #include "armv5te/armsnippets.h"
13 #include "armv5te/asmcode.h"
14 #include "armv5te/cpu.h"
15 #include "armv5te/cpudefs.h"
16 #include "armv5te/debug.h"
17 #include "armv5te/emu.h"
18 #include "armv5te/mem.h"
19 #include "armv5te/mmu.h"
20 #include "armv5te/translate.h"
21 
22 // Global CPU state
23 struct arm_state arm;
24 
cpu_arm_loop()25 void cpu_arm_loop()
26 {
27     while (!exiting && cycle_count_delta < 0 && current_instr_size == 4)
28     {
29         arm.reg[15] &= ~0x3; // Align PC
30         Instruction *p = static_cast<Instruction*>(read_instruction(arm.reg[15]));
31 
32         #ifdef BENCHMARK
33             static clock_t start = 0;
34             if(arm.reg[15] == 0)
35             {
36                 start = clock();
37                 turbo_mode = true;
38             }
39             else if(arm.reg[15] == 0x10000000 || arm.reg[15] == 0x11800000)
40             {
41                 clock_t diff = clock() - start;
42                 printf("%ld ms\n", diff / 1000);
43             }
44         #endif
45 
46         uint32_t *flags_ptr = &RAM_FLAGS(p);
47 
48         // Check for pending events
49         if(cpu_events)
50         {
51             // Events other than DEBUG_STEP are handled outside
52             if(cpu_events & ~EVENT_DEBUG_STEP)
53                 break;
54             goto enter_debugger;
55         }
56 
57         // TODO: Other flags
58         if(*flags_ptr & (RF_EXEC_BREAKPOINT | RF_EXEC_DEBUG_NEXT | RF_ARMLOADER_CB))
59         {
60             if(*flags_ptr & RF_ARMLOADER_CB)
61             {
62                 *flags_ptr &= ~RF_ARMLOADER_CB;
63                 armloader_cb();
64             }
65             else
66             {
67                 if(*flags_ptr & RF_EXEC_BREAKPOINT)
68                     gui_debug_printf("Breakpoint at 0x%08X\n", arm.reg[15]);
69                 enter_debugger:
70                 uint32_t pc = arm.reg[15];
71                 debugger(DBG_EXEC_BREAKPOINT, 0);
72                 if(arm.reg[15] != pc)
73                     continue; // Debugger changed PC
74             }
75         }
76 #ifndef NO_TRANSLATION
77         else if(do_translate && !(*flags_ptr & DONT_TRANSLATE) && (*flags_ptr & RF_CODE_EXECUTED))
78             translate(arm.reg[15], &p->raw);
79 
80         // If the instruction is translated, use the translation
81         if((~cpu_events & EVENT_DEBUG_STEP) && *flags_ptr & RF_CODE_TRANSLATED)
82         {
83             #if TRANSLATION_ENTER_HAS_PTR
84                 translation_enter(p);
85             #else
86                 translation_enter();
87             #endif
88             continue;
89         }
90 
91 	*flags_ptr |= RF_CODE_EXECUTED;
92 #endif
93 
94         /*
95         //TODO: remove this, causes slowdown
96         if(arm.reg[15] == 0x200AC088)
97            emuprintf("HAL state set:%d\n", arm.reg[0]);
98         */
99 
100         arm.reg[15] += 4; // Increment now to account for the pipeline
101         ++cycle_count_delta;
102         do_arm_instruction(*p);
103     }
104 }
105 
106 // Makes arm.reg[15] point to the current instruction
fix_pc_for_fault()107 void fix_pc_for_fault()
108 {
109 #ifndef NO_TRANSLATION
110     translate_fix_pc();
111 #endif
112 
113     arm.reg[15] -= current_instr_size;
114 }
115 
prefetch_abort(uint32_t mva,uint8_t status)116 void prefetch_abort(uint32_t mva, uint8_t status)
117 {
118     warn("Prefetch abort: address=%08X status=%02X\n", mva, status);
119     arm.reg[15] += 4;
120     // Fault address register not changed
121     arm.instruction_fault_status = status;
122     cpu_exception(EX_PREFETCH_ABORT);
123     if (mva == arm.reg[15])
124         error("Abort occurred with exception vectors unmapped");
125     longjmp(restart_after_exception, 1);
126 }
127 
data_abort(uint32_t mva,uint8_t status)128 void data_abort(uint32_t mva, uint8_t status)
129 {
130     fix_pc_for_fault();
131     warn("Data abort: address=%08X status=%02X instruction at %08X\n", mva, status, arm.reg[15]);
132     arm.reg[15] += 8;
133     arm.fault_address = mva;
134     arm.data_fault_status = status;
135     cpu_exception(EX_DATA_ABORT);
136     longjmp(restart_after_exception, 1);
137 }
138 
undefined_instruction()139 void undefined_instruction()
140 {
141     fix_pc_for_fault();
142     if(current_instr_size == 4)
143        warn("Undefined instruction 0x%08X at 0x%08X\n", read_word(arm.reg[15]), arm.reg[15]);
144     else
145        warn("Undefined instruction 0x%04X at 0x%08X\n", read_half(arm.reg[15]), arm.reg[15]);
146     arm.reg[15] += current_instr_size;
147     cpu_exception(EX_UNDEFINED);
148     longjmp(restart_after_exception, 1);
149 }
150 
try_ptr(uint32_t addr)151 void *try_ptr(uint32_t addr)
152 {
153     //There are two different addr_cache formats...
154 #ifdef AC_FLAGS
155     uintptr_t entry = *(uintptr_t*)(addr_cache + ((addr >> 10) << 1));
156 
157     if(unlikely(entry & AC_FLAGS))
158     {
159         if(entry & AC_INVALID)
160             return addr_cache_miss(addr, false, nullptr);
161         else // MMIO stuff
162             return nullptr;
163     }
164 
165     entry += addr;
166     return (void*)entry;
167 #else
168     void *ptr = &addr_cache[(addr >> 10) << 1][addr];
169     if(unlikely((uintptr_t)ptr & AC_NOT_PTR))
170         ptr = addr_cache_miss(addr, false, nullptr);
171 
172     return ptr;
173 #endif
174 }
175 
read_instruction(uint32_t addr)176 void * FASTCALL read_instruction(uint32_t addr)
177 {
178     //There are two different addr_cache formats...
179 #ifdef AC_FLAGS
180     uintptr_t entry = *(uintptr_t*)(addr_cache + ((addr >> 10) << 1));
181 
182     if(unlikely(entry & AC_FLAGS))
183     {
184         if(entry & AC_INVALID)
185             return addr_cache_miss(addr, false, prefetch_abort);
186         else // Executing MMIO stuff
187             error("PC in MMIO range: 0x%x\n", addr);
188     }
189 
190     entry += addr;
191     return (void*)entry;
192 #else
193     void *ptr = &addr_cache[(addr >> 10) << 1][addr];
194     if(unlikely((uintptr_t)ptr & AC_NOT_PTR))
195     {
196         ptr = addr_cache_miss(addr, false, prefetch_abort);
197         if (!ptr)
198             error("Bad PC: %08X\n", addr);
199     }
200     return ptr;
201 #endif
202 }
203 
204 // Update cpu_events
cpu_int_check()205 void cpu_int_check()
206 {
207     //events arnt threaded like this in Mu, plus this breaks the RetroArch build, some undefined reference thing
208     //static std::mutex mut;
209     //std::lock_guard<std::mutex> lg(mut);
210 
211     if (arm.interrupts & ~arm.cpsr_low28 & 0x80)
212         cpu_events |= EVENT_IRQ;
213     else
214         cpu_events &= ~EVENT_IRQ;
215 
216     if (arm.interrupts & ~arm.cpsr_low28 & 0x40)
217         cpu_events |= EVENT_FIQ;
218     else
219         cpu_events &= ~EVENT_FIQ;
220 }
221 
222 static const constexpr uint8_t exc_flags[] = {
223     MODE_SVC | 0xC0, /* Reset */
224     MODE_UND | 0x80, /* Undefined instruction */
225     MODE_SVC | 0x80, /* Software interrupt */
226     MODE_ABT | 0x80, /* Prefetch abort */
227     MODE_ABT | 0x80, /* Data abort */
228     0,               /* Reserved */
229     MODE_IRQ | 0x80, /* IRQ */
230     MODE_FIQ | 0xC0, /* FIQ */
231 };
232 
cpu_exception(int type)233 void cpu_exception(int type)
234 {
235     /* Switch mode, disable interrupts */
236     uint32_t old_cpsr = get_cpsr();
237     set_cpsr_full((old_cpsr & ~0x3F) | exc_flags[type]);
238     *ptr_spsr() = old_cpsr;
239 
240     /* Branch-and-link to exception handler */
241     arm.reg[14] = arm.reg[15];
242     arm.reg[15] = type << 2;
243     if (arm.control & 0x2000) /* High vectors */
244         arm.reg[15] += 0xFFFF0000;
245 }
246 
get_cpsr_flags()247 uint32_t get_cpsr_flags()
248 {
249     return arm.cpsr_n << 31
250          | arm.cpsr_z << 30
251          | arm.cpsr_c << 29
252          | arm.cpsr_v << 28;
253 }
254 
set_cpsr_flags(uint32_t flags)255 void set_cpsr_flags(uint32_t flags)
256 {
257     arm.cpsr_n = (flags >> 31) & 1;
258     arm.cpsr_z = (flags >> 30) & 1;
259     arm.cpsr_c = (flags >> 29) & 1;
260     arm.cpsr_v = (flags >> 28) & 1;
261 }
262 
263 // Get full CPSR register
get_cpsr()264 uint32_t get_cpsr()
265 {
266     return arm.cpsr_n << 31
267          | arm.cpsr_z << 30
268          | arm.cpsr_c << 29
269          | arm.cpsr_v << 28
270          | arm.cpsr_low28;
271 }
272 
set_cpsr_full(uint32_t cpsr)273 void set_cpsr_full(uint32_t cpsr)
274 {
275     uint8_t old_mode = arm.cpsr_low28 & 0x1F,
276             new_mode = cpsr & 0x1F;
277 
278     if(old_mode == new_mode)
279         goto same_mode;
280 
281     // Only FIQ mode has more than 2 regs banked
282     if(old_mode == MODE_FIQ)
283         std::copy(arm.reg + 8, arm.reg + 13, arm.r8_fiq);
284     else
285         std::copy(arm.reg + 8, arm.reg + 13, arm.r8_usr);
286 
287     switch(old_mode)
288     {
289     case MODE_USR: case MODE_SYS:
290         std::copy(arm.reg + 13, arm.reg + 15, arm.r13_usr);
291         break;
292     case MODE_FIQ:
293         std::copy(arm.reg + 13, arm.reg + 15, arm.r13_fiq);
294         break;
295     case MODE_IRQ:
296         std::copy(arm.reg + 13, arm.reg + 15, arm.r13_irq);
297         break;
298     case MODE_SVC:
299         std::copy(arm.reg + 13, arm.reg + 15, arm.r13_svc);
300         break;
301     case MODE_ABT:
302         std::copy(arm.reg + 13, arm.reg + 15, arm.r13_abt);
303         break;
304     case MODE_UND:
305         std::copy(arm.reg + 13, arm.reg + 15, arm.r13_und);
306         break;
307     default: assert(false);
308     }
309 
310     if(new_mode == MODE_FIQ)
311         std::copy(arm.r8_fiq, arm.r8_fiq + 5, arm.reg + 8);
312     else
313         std::copy(arm.r8_usr, arm.r8_usr + 5, arm.reg + 8);
314 
315     switch(new_mode)
316     {
317     case MODE_USR: case MODE_SYS:
318         std::copy(arm.r13_usr, arm.r13_usr + 2, arm.reg + 13);
319         break;
320     case MODE_FIQ:
321         std::copy(arm.r13_fiq, arm.r13_fiq + 2, arm.reg + 13);
322         break;
323     case MODE_IRQ:
324         std::copy(arm.r13_irq, arm.r13_irq + 2, arm.reg + 13);
325         break;
326     case MODE_SVC:
327         std::copy(arm.r13_svc, arm.r13_svc + 2, arm.reg + 13);
328         break;
329     case MODE_ABT:
330         std::copy(arm.r13_abt, arm.r13_abt + 2, arm.reg + 13);
331         break;
332     case MODE_UND:
333         std::copy(arm.r13_und, arm.r13_und + 2, arm.reg + 13);
334         break;
335     default: error("Invalid mode 0x%x\n", new_mode);
336     }
337 
338     // Access permissions are different
339     if((old_mode == MODE_USR) ^ (new_mode == MODE_USR))
340         addr_cache_flush();
341 
342     same_mode:
343     if(cpsr & 0x01000000)
344         error("Jazelle not implemented!");
345 
346     arm.cpsr_n = (cpsr >> 31) & 1;
347     arm.cpsr_z = (cpsr >> 30) & 1;
348     arm.cpsr_c = (cpsr >> 29) & 1;
349     arm.cpsr_v = (cpsr >> 28) & 1;
350     arm.cpsr_low28 = cpsr & 0x090000FF; // Mask off reserved bits
351     cpu_int_check();
352 }
353 
set_cpsr(uint32_t cpsr,uint32_t mask)354 void FASTCALL set_cpsr(uint32_t cpsr, uint32_t mask) {
355     if (!(arm.cpsr_low28 & 0x0F)) {
356         /* User mode. Don't change privileged or execution state bits */
357         mask &= ~0x010000FF;
358     }
359     cpsr = (cpsr & mask) | (get_cpsr() & ~mask);
360     if (cpsr & 0x20)
361         error("Cannot set T bit with MSR instruction");
362     set_cpsr_full(cpsr);
363 }
364 
ptr_spsr()365 uint32_t *ptr_spsr()
366 {
367     switch (arm.cpsr_low28 & 0x1F)
368     {
369         case MODE_FIQ: return &arm.spsr_fiq;
370         case MODE_IRQ: return &arm.spsr_irq;
371         case MODE_SVC: return &arm.spsr_svc;
372         case MODE_ABT: return &arm.spsr_abt;
373         case MODE_UND: return &arm.spsr_und;
374     }
375     error("Attempted to access SPSR from user or system mode");
376 }
377 
get_spsr()378 uint32_t get_spsr() {
379     return *ptr_spsr();
380 }
381 
set_spsr(uint32_t spsr,uint32_t mask)382 void FASTCALL set_spsr(uint32_t spsr, uint32_t mask) {
383     *ptr_spsr() ^= (*ptr_spsr() ^ spsr) & mask;
384 }
385 
reg(uint8_t i)386 uint32_t reg(uint8_t i)
387 {
388     if(unlikely(i == 15))
389         error("PC invalid in this context!\n");
390     return arm.reg[i];
391 }
392 
reg_pc(uint8_t i)393 uint32_t reg_pc(uint8_t i)
394 {
395     if(unlikely(i == 15))
396         return arm.reg[15] + 4;
397     return arm.reg[i];
398 }
399 
reg_pc_mem(uint8_t i)400 uint32_t reg_pc_mem(uint8_t i)
401 {
402     if(unlikely(i == 15))
403         return arm.reg[15] + 8;
404     return arm.reg[i];
405 }
406 
set_reg(uint8_t i,uint32_t value)407 void set_reg(uint8_t i, uint32_t value)
408 {
409     if(unlikely(i == 15))
410         error("PC invalid in this context!\n");
411     arm.reg[i] = value;
412 }
413 
set_reg_pc(uint8_t i,uint32_t value)414 void set_reg_pc(uint8_t i, uint32_t value)
415 {
416     arm.reg[i] = value;
417 }
418 
set_reg_bx(uint8_t i,uint32_t value)419 void set_reg_bx(uint8_t i, uint32_t value)
420 {
421     arm.reg[i] = value;
422 
423     if(i == 15 && (value & 1))
424     {
425         arm.cpsr_low28 |= 0x20; // Enter Thumb mode
426         arm.reg[15] -= 1;
427     }
428 }
429