1 /* arm.c
2
3 ARM 2/3/6 Emulation (26 bit address bus)
4
5 Todo:
6 Timing - Currently very approximated, nothing relies on proper timing so far.
7 IRQ timing not yet correct (again, nothing is affected by this so far).
8
9 Recent changes (2005):
10 Fixed software interrupts
11 Fixed various mode change bugs
12 Added preliminary co-processor support.
13
14 By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino
15
16 */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 //#include "state.h"
22 //#include "driver.h"
23 #include "burnint.h"
24 #include "arm_intf.h"
25
26 #define READ8(addr) cpu_read8(addr)
27 #define WRITE8(addr,data) cpu_write8(addr,data)
28 #define READ32(addr) cpu_read32(addr)
29 #define WRITE32(addr,data) cpu_write32(addr,data)
30
31 //#define change_pc(x)
32
33 #define ARM_DEBUG_CORE 0
34 #define ARM_DEBUG_COPRO 0
35
36 enum
37 {
38 ARM32_PC=0,
39 ARM32_R0, ARM32_R1, ARM32_R2, ARM32_R3, ARM32_R4, ARM32_R5, ARM32_R6, ARM32_R7,
40 ARM32_R8, ARM32_R9, ARM32_R10, ARM32_R11, ARM32_R12, ARM32_R13, ARM32_R14, ARM32_R15,
41 ARM32_FR8, ARM32_FR9, ARM32_FR10, ARM32_FR11, ARM32_FR12, ARM32_FR13, ARM32_FR14,
42 ARM32_IR13, ARM32_IR14, ARM32_SR13, ARM32_SR14
43 };
44
45 enum
46 {
47 eARM_MODE_USER = 0x0,
48 eARM_MODE_FIQ = 0x1,
49 eARM_MODE_IRQ = 0x2,
50 eARM_MODE_SVC = 0x3,
51
52 kNumModes
53 };
54
55 /* There are 27 32 bit processor registers */
56 enum
57 {
58 eR0=0,eR1,eR2,eR3,eR4,eR5,eR6,eR7,
59 eR8,eR9,eR10,eR11,eR12,
60 eR13, /* Stack Pointer */
61 eR14, /* Link Register (holds return address) */
62 eR15, /* Program Counter */
63
64 /* Fast Interrupt */
65 eR8_FIQ,eR9_FIQ,eR10_FIQ,eR11_FIQ,eR12_FIQ,eR13_FIQ,eR14_FIQ,
66
67 /* IRQ */
68 eR13_IRQ,eR14_IRQ,
69
70 /* Software Interrupt */
71 eR13_SVC,eR14_SVC,
72
73 kNumRegisters
74 };
75
76 /* 16 processor registers are visible at any given time,
77 * banked depending on processor mode.
78 */
79 static const int sRegisterTable[kNumModes][16] =
80 {
81 { /* USR */
82 eR0,eR1,eR2,eR3,eR4,eR5,eR6,eR7,
83 eR8,eR9,eR10,eR11,eR12,
84 eR13,eR14,
85 eR15
86 },
87 { /* FIQ */
88 eR0,eR1,eR2,eR3,eR4,eR5,eR6,eR7,
89 eR8_FIQ,eR9_FIQ,eR10_FIQ,eR11_FIQ,eR12_FIQ,
90 eR13_FIQ,eR14_FIQ,
91 eR15
92 },
93 { /* IRQ */
94 eR0,eR1,eR2,eR3,eR4,eR5,eR6,eR7,
95 eR8,eR9,eR10,eR11,eR12,
96 eR13_IRQ,eR14_IRQ,
97 eR15
98 },
99 { /* SVC */
100 eR0,eR1,eR2,eR3,eR4,eR5,eR6,eR7,
101 eR8,eR9,eR10,eR11,eR12,
102 eR13_SVC,eR14_SVC,
103 eR15
104 }
105 };
106
107 #define N_BIT 31
108 #define Z_BIT 30
109 #define C_BIT 29
110 #define V_BIT 28
111 #define I_BIT 27
112 #define F_BIT 26
113
114 #define N_MASK ((UINT32)(1<<N_BIT)) /* Negative flag */
115 #define Z_MASK ((UINT32)(1<<Z_BIT)) /* Zero flag */
116 #define C_MASK ((UINT32)(1<<C_BIT)) /* Carry flag */
117 #define V_MASK ((UINT32)(1<<V_BIT)) /* oVerflow flag */
118 #define I_MASK ((UINT32)(1<<I_BIT)) /* Interrupt request disable */
119 #define F_MASK ((UINT32)(1<<F_BIT)) /* Fast interrupt request disable */
120
121 #define N_IS_SET(pc) ((pc) & N_MASK)
122 #define Z_IS_SET(pc) ((pc) & Z_MASK)
123 #define C_IS_SET(pc) ((pc) & C_MASK)
124 #define V_IS_SET(pc) ((pc) & V_MASK)
125 #define I_IS_SET(pc) ((pc) & I_MASK)
126 #define F_IS_SET(pc) ((pc) & F_MASK)
127
128 #define N_IS_CLEAR(pc) (!N_IS_SET(pc))
129 #define Z_IS_CLEAR(pc) (!Z_IS_SET(pc))
130 #define C_IS_CLEAR(pc) (!C_IS_SET(pc))
131 #define V_IS_CLEAR(pc) (!V_IS_SET(pc))
132 #define I_IS_CLEAR(pc) (!I_IS_SET(pc))
133 #define F_IS_CLEAR(pc) (!F_IS_SET(pc))
134
135 #define PSR_MASK ((UINT32) 0xf0000000u)
136 #define IRQ_MASK ((UINT32) 0x0c000000u)
137 #define ADDRESS_MASK ((UINT32) 0x03fffffcu)
138 #define MODE_MASK ((UINT32) 0x00000003u)
139
140 #define R15 arm.sArmRegister[eR15]
141 #define MODE (R15&0x03)
142 #define SIGN_BIT ((UINT32)(1<<31))
143 #define SIGN_BITS_DIFFER(a,b) (((a)^(b)) >> 31)
144
145 /* Deconstructing an instruction */
146
147 #define INSN_COND ((UINT32) 0xf0000000u)
148 #define INSN_SDT_L ((UINT32) 0x00100000u)
149 #define INSN_SDT_W ((UINT32) 0x00200000u)
150 #define INSN_SDT_B ((UINT32) 0x00400000u)
151 #define INSN_SDT_U ((UINT32) 0x00800000u)
152 #define INSN_SDT_P ((UINT32) 0x01000000u)
153 #define INSN_BDT_L ((UINT32) 0x00100000u)
154 #define INSN_BDT_W ((UINT32) 0x00200000u)
155 #define INSN_BDT_S ((UINT32) 0x00400000u)
156 #define INSN_BDT_U ((UINT32) 0x00800000u)
157 #define INSN_BDT_P ((UINT32) 0x01000000u)
158 #define INSN_BDT_REGS ((UINT32) 0x0000ffffu)
159 #define INSN_SDT_IMM ((UINT32) 0x00000fffu)
160 #define INSN_MUL_A ((UINT32) 0x00200000u)
161 #define INSN_MUL_RM ((UINT32) 0x0000000fu)
162 #define INSN_MUL_RS ((UINT32) 0x00000f00u)
163 #define INSN_MUL_RN ((UINT32) 0x0000f000u)
164 #define INSN_MUL_RD ((UINT32) 0x000f0000u)
165 #define INSN_I ((UINT32) 0x02000000u)
166 #define INSN_OPCODE ((UINT32) 0x01e00000u)
167 #define INSN_S ((UINT32) 0x00100000u)
168 #define INSN_BL ((UINT32) 0x01000000u)
169 #define INSN_BRANCH ((UINT32) 0x00ffffffu)
170 #define INSN_SWI ((UINT32) 0x00ffffffu)
171 #define INSN_RN ((UINT32) 0x000f0000u)
172 #define INSN_RD ((UINT32) 0x0000f000u)
173 #define INSN_OP2 ((UINT32) 0x00000fffu)
174 #define INSN_OP2_SHIFT ((UINT32) 0x00000f80u)
175 #define INSN_OP2_SHIFT_TYPE ((UINT32) 0x00000070u)
176 #define INSN_OP2_RM ((UINT32) 0x0000000fu)
177 #define INSN_OP2_ROTATE ((UINT32) 0x00000f00u)
178 #define INSN_OP2_IMM ((UINT32) 0x000000ffu)
179 #define INSN_OP2_SHIFT_TYPE_SHIFT 4
180 #define INSN_OP2_SHIFT_SHIFT 7
181 #define INSN_OP2_ROTATE_SHIFT 8
182 #define INSN_MUL_RS_SHIFT 8
183 #define INSN_MUL_RN_SHIFT 12
184 #define INSN_MUL_RD_SHIFT 16
185 #define INSN_OPCODE_SHIFT 21
186 #define INSN_RN_SHIFT 16
187 #define INSN_RD_SHIFT 12
188 #define INSN_COND_SHIFT 28
189
190 #define S_CYCLE 1
191 #define N_CYCLE 1
192 #define I_CYCLE 1
193
194 enum
195 {
196 OPCODE_AND, /* 0000 */
197 OPCODE_EOR, /* 0001 */
198 OPCODE_SUB, /* 0010 */
199 OPCODE_RSB, /* 0011 */
200 OPCODE_ADD, /* 0100 */
201 OPCODE_ADC, /* 0101 */
202 OPCODE_SBC, /* 0110 */
203 OPCODE_RSC, /* 0111 */
204 OPCODE_TST, /* 1000 */
205 OPCODE_TEQ, /* 1001 */
206 OPCODE_CMP, /* 1010 */
207 OPCODE_CMN, /* 1011 */
208 OPCODE_ORR, /* 1100 */
209 OPCODE_MOV, /* 1101 */
210 OPCODE_BIC, /* 1110 */
211 OPCODE_MVN /* 1111 */
212 };
213
214 enum
215 {
216 COND_EQ = 0, /* Z: equal */
217 COND_NE, /* ~Z: not equal */
218 COND_CS, COND_HS = 2, /* C: unsigned higher or same */
219 COND_CC, COND_LO = 3, /* ~C: unsigned lower */
220 COND_MI, /* N: negative */
221 COND_PL, /* ~N: positive or zero */
222 COND_VS, /* V: overflow */
223 COND_VC, /* ~V: no overflow */
224 COND_HI, /* C && ~Z: unsigned higher */
225 COND_LS, /* ~C || Z: unsigned lower or same */
226 COND_GE, /* N == V: greater or equal */
227 COND_LT, /* N != V: less than */
228 COND_GT, /* ~Z && (N == V): greater than */
229 COND_LE, /* Z || (N != V): less than or equal */
230 COND_AL, /* always */
231 COND_NV /* never */
232 };
233
234 #define LSL(v,s) ((v) << (s))
235 #define LSR(v,s) ((v) >> (s))
236 #define ROL(v,s) (LSL((v),(s)) | (LSR((v),32u - (s))))
237 #define ROR(v,s) (LSR((v),(s)) | (LSL((v),32u - (s))))
238
239 /* Private Data */
240
241 /* sArmRegister defines the CPU state */
242 typedef struct
243 {
244 UINT32 sArmRegister[kNumRegisters];
245 UINT32 coproRegister[16];
246 UINT8 pendingIrq;
247 UINT8 pendingFiq;
248
249 UINT32 ArmTotalCycles;
250 UINT32 ArmLeftCycles;
251 } ARM_REGS;
252
253 static ARM_REGS arm;
254
255 static int arm_icount;
256
257 /* Prototypes */
258 static void HandleALU( UINT32 insn);
259 static void HandleMul( UINT32 insn);
260 static void HandleBranch( UINT32 insn);
261 static void HandleMemSingle( UINT32 insn);
262 static void HandleMemBlock( UINT32 insn);
263 static void HandleCoPro( UINT32 insn);
264 static UINT32 decodeShift( UINT32 insn, UINT32 *pCarry);
265 static void arm_check_irq_state(void);
266
267 /***************************************************************************/
268
cpu_write32(int addr,UINT32 data)269 inline void cpu_write32( int addr, UINT32 data )
270 {
271 /* Unaligned writes are treated as normal writes */
272 ArmWriteLong(addr&ADDRESS_MASK,data);
273 }
274
cpu_write8(int addr,UINT8 data)275 inline void cpu_write8( int addr, UINT8 data )
276 {
277 ArmWriteByte(addr,data);
278 }
279
cpu_read32(int addr)280 inline UINT32 cpu_read32( int addr )
281 {
282 UINT32 result = ArmReadLong(addr&ADDRESS_MASK);
283
284 /* Unaligned reads rotate the word, they never combine words */
285 if (addr&3) {
286 if ((addr&3)==1)
287 return ((result&0x000000ff)<<24)|((result&0xffffff00)>> 8);
288 if ((addr&3)==2)
289 return ((result&0x0000ffff)<<16)|((result&0xffff0000)>>16);
290 if ((addr&3)==3)
291 return ((result&0x00ffffff)<< 8)|((result&0xff000000)>>24);
292 }
293
294 return result;
295 }
296
cpu_read8(int addr)297 inline UINT8 cpu_read8( int addr )
298 {
299 return ArmReadByte(addr);
300 }
301
GetRegister(int rIndex)302 inline UINT32 GetRegister( int rIndex )
303 {
304 return arm.sArmRegister[sRegisterTable[MODE][rIndex]];
305 }
306
SetRegister(int rIndex,UINT32 value)307 inline void SetRegister( int rIndex, UINT32 value )
308 {
309 arm.sArmRegister[sRegisterTable[MODE][rIndex]] = value;
310 }
311
GetModeRegister(int mode,int rIndex)312 inline UINT32 GetModeRegister( int mode, int rIndex )
313 {
314 return arm.sArmRegister[sRegisterTable[mode][rIndex]];
315 }
316
SetModeRegister(int mode,int rIndex,UINT32 value)317 inline void SetModeRegister( int mode, int rIndex, UINT32 value )
318 {
319 arm.sArmRegister[sRegisterTable[mode][rIndex]] = value;
320 }
321
322 /***************************************************************************/
323
ArmReset(void)324 void ArmReset(void)
325 {
326 memset(&arm, 0, sizeof(arm));
327
328 /* start up in SVC mode with interrupts disabled. */
329 R15 = eARM_MODE_SVC|I_MASK|F_MASK;
330 }
331
ArmRun(int cycles)332 int ArmRun( int cycles )
333 {
334 UINT32 pc;
335 UINT32 insn;
336
337 arm_icount = cycles;
338 arm.ArmLeftCycles = cycles;
339
340 do
341 {
342 /* load instruction */
343 pc = R15;
344 insn = ArmFetchLong( pc & ADDRESS_MASK );
345
346 switch (insn >> INSN_COND_SHIFT)
347 {
348 case COND_EQ:
349 if (Z_IS_CLEAR(pc)) goto L_Next;
350 break;
351 case COND_NE:
352 if (Z_IS_SET(pc)) goto L_Next;
353 break;
354 case COND_CS:
355 if (C_IS_CLEAR(pc)) goto L_Next;
356 break;
357 case COND_CC:
358 if (C_IS_SET(pc)) goto L_Next;
359 break;
360 case COND_MI:
361 if (N_IS_CLEAR(pc)) goto L_Next;
362 break;
363 case COND_PL:
364 if (N_IS_SET(pc)) goto L_Next;
365 break;
366 case COND_VS:
367 if (V_IS_CLEAR(pc)) goto L_Next;
368 break;
369 case COND_VC:
370 if (V_IS_SET(pc)) goto L_Next;
371 break;
372 case COND_HI:
373 if (C_IS_CLEAR(pc) || Z_IS_SET(pc)) goto L_Next;
374 break;
375 case COND_LS:
376 if (C_IS_SET(pc) && Z_IS_CLEAR(pc)) goto L_Next;
377 break;
378 case COND_GE:
379 if (!(pc & N_MASK) != !(pc & V_MASK)) goto L_Next; /* Use x ^ (x >> ...) method */
380 break;
381 case COND_LT:
382 if (!(pc & N_MASK) == !(pc & V_MASK)) goto L_Next;
383 break;
384 case COND_GT:
385 if (Z_IS_SET(pc) || (!(pc & N_MASK) != !(pc & V_MASK))) goto L_Next;
386 break;
387 case COND_LE:
388 if (Z_IS_CLEAR(pc) && (!(pc & N_MASK) == !(pc & V_MASK))) goto L_Next;
389 break;
390 case COND_NV:
391 goto L_Next;
392 }
393 /* Condition satisfied, so decode the instruction */
394 if ((insn & 0x0fc000f0u) == 0x00000090u) /* Multiplication */
395 {
396 HandleMul(insn);
397 R15 += 4;
398 }
399 else if (!(insn & 0x0c000000u)) /* Data processing */
400 {
401 HandleALU(insn);
402 }
403 else if ((insn & 0x0c000000u) == 0x04000000u) /* Single data access */
404 {
405 HandleMemSingle(insn);
406 R15 += 4;
407 }
408 else if ((insn & 0x0e000000u) == 0x08000000u ) /* Block data access */
409 {
410 HandleMemBlock(insn);
411 R15 += 4;
412 }
413 else if ((insn & 0x0e000000u) == 0x0a000000u) /* Branch */
414 {
415 HandleBranch(insn);
416 }
417 else if ((insn & 0x0f000000u) == 0x0e000000u) /* Coprocessor */
418 {
419 HandleCoPro(insn);
420 R15 += 4;
421 }
422 else if ((insn & 0x0f000000u) == 0x0f000000u) /* Software interrupt */
423 {
424 pc=R15+4;
425 R15 = eARM_MODE_SVC; /* Set SVC mode so PC is saved to correct R14 bank */
426 SetRegister( 14, pc ); /* save PC */
427 R15 = (pc&PSR_MASK)|(pc&IRQ_MASK)|0x8|eARM_MODE_SVC|I_MASK|(pc&MODE_MASK);
428 arm_icount -= 2 * S_CYCLE + N_CYCLE;
429 }
430 else /* Undefined */
431 {
432 L_Next:
433 arm_icount -= S_CYCLE;
434 R15 += 4;
435 }
436
437 arm_check_irq_state();
438
439 } while( arm_icount > 0 );
440
441 arm.ArmTotalCycles += (cycles - arm_icount);
442
443 return cycles - arm_icount;
444 } /* arm_execute */
445
arm_check_irq_state(void)446 static void arm_check_irq_state(void)
447 {
448 UINT32 pc = R15+4; /* save old pc (already incremented in pipeline) */;
449
450 /* Exception priorities (from ARM6, not specifically ARM2/3):
451
452 Reset
453 Data abort
454 FIRQ
455 IRQ
456 Prefetch abort
457 Undefined instruction
458 */
459
460 if (arm.pendingFiq && (pc&F_MASK)==0) {
461 R15 = eARM_MODE_FIQ; /* Set FIQ mode so PC is saved to correct R14 bank */
462 SetRegister( 14, pc ); /* save PC */
463 R15 = (pc&PSR_MASK)|(pc&IRQ_MASK)|0x1c|eARM_MODE_FIQ|I_MASK|F_MASK; /* Mask both IRQ & FIRQ, set PC=0x1c */
464 arm.pendingFiq=0;
465 return;
466 }
467
468 if (arm.pendingIrq && (pc&I_MASK)==0) {
469 R15 = eARM_MODE_IRQ; /* Set IRQ mode so PC is saved to correct R14 bank */
470 SetRegister( 14, pc ); /* save PC */
471 R15 = (pc&PSR_MASK)|(pc&IRQ_MASK)|0x18|eARM_MODE_IRQ|I_MASK|(pc&F_MASK); /* Mask only IRQ, set PC=0x18 */
472 arm.pendingIrq=0;
473 return;
474 }
475 }
476
arm_set_irq_line(int irqline,int state)477 void arm_set_irq_line(int irqline, int state)
478 {
479 #if defined FBA_DEBUG
480 if (!DebugCPU_ARMInitted) bprintf(PRINT_ERROR, _T("arm_set_irq_line called without init\n"));
481 #endif
482
483 switch (irqline) {
484
485 case ARM_IRQ_LINE: /* IRQ */
486 if (state && (R15&0x3)!=eARM_MODE_IRQ) /* Don't allow nested IRQs */
487 arm.pendingIrq=1;
488 else
489 arm.pendingIrq=0;
490 break;
491
492 case ARM_FIRQ_LINE: /* FIRQ */
493 if (state && (R15&0x3)!=eARM_MODE_FIQ) /* Don't allow nested FIRQs */
494 arm.pendingFiq=1;
495 else
496 arm.pendingFiq=0;
497 break;
498 }
499
500 arm_check_irq_state();
501 }
502
503 /***************************************************************************/
504
HandleBranch(UINT32 insn)505 static void HandleBranch( UINT32 insn )
506 {
507 UINT32 off = (insn & INSN_BRANCH) << 2;
508
509 /* Save PC into LR if this is a branch with link */
510 if (insn & INSN_BL)
511 {
512 SetRegister(14,R15 + 4);
513 }
514
515 /* Sign-extend the 24-bit offset in our calculations */
516 if (off & 0x2000000u)
517 {
518 R15 = ((R15 - (((~(off | 0xfc000000u)) + 1) - 8)) & ADDRESS_MASK) | (R15 & ~ADDRESS_MASK);
519 }
520 else
521 {
522 R15 = ((R15 + (off + 8)) & ADDRESS_MASK) | (R15 & ~ADDRESS_MASK);
523 }
524 arm_icount -= 2 * S_CYCLE + N_CYCLE;
525 }
526
HandleMemSingle(UINT32 insn)527 static void HandleMemSingle( UINT32 insn )
528 {
529 UINT32 rn, rnv, off, rd;
530
531 /* Fetch the offset */
532 if (insn & INSN_I)
533 {
534 off = decodeShift(insn, NULL);
535 }
536 else
537 {
538 off = insn & INSN_SDT_IMM;
539 }
540
541 /* Calculate Rn, accounting for PC */
542 rn = (insn & INSN_RN) >> INSN_RN_SHIFT;
543
544 if (insn & INSN_SDT_P)
545 {
546 /* Pre-indexed addressing */
547 if (insn & INSN_SDT_U)
548 {
549 if (rn != eR15)
550 rnv = (GetRegister(rn) + off);
551 else
552 rnv = (R15 & ADDRESS_MASK) + off;
553 }
554 else
555 {
556 if (rn != eR15)
557 rnv = (GetRegister(rn) - off);
558 else
559 rnv = (R15 & ADDRESS_MASK) - off;
560 }
561
562 /*if (insn & INSN_SDT_W)
563 {
564 SetRegister(rn,rnv);
565 }
566 else*/ if (rn == eR15)
567 {
568 rnv = rnv + 8;
569 }
570 }
571 else
572 {
573 /* Post-indexed addressing */
574 if (rn == eR15)
575 {
576 rnv = (R15 & ADDRESS_MASK) + 8;
577 }
578 else
579 {
580 rnv = GetRegister(rn);
581 }
582 }
583
584 /* Do the transfer */
585 rd = (insn & INSN_RD) >> INSN_RD_SHIFT;
586 if (insn & INSN_SDT_L)
587 {
588 /* Load */
589 arm_icount -= S_CYCLE + I_CYCLE + N_CYCLE;
590 if (insn & INSN_SDT_B)
591 {
592 SetRegister(rd,(UINT32) READ8(rnv));
593 }
594 else
595 {
596 if (rd == eR15)
597 {
598 R15 = (READ32(rnv) & ADDRESS_MASK) | (R15 & PSR_MASK) | (R15 & IRQ_MASK) | (R15 & MODE_MASK);
599
600 /*
601 The docs are explicit in that the bottom bits should be masked off
602 when writing to R15 in this way, however World Cup Volleyball 95 has
603 an example of an unaligned jump (bottom bits = 2) where execution
604 should definitely continue from the rounded up address.
605
606 In other cases, 4 is subracted from R15 here to account for pipelining.
607 */
608 if ((READ32(rnv)&3)==0)
609 R15 -= 4;
610
611 arm_icount -= S_CYCLE + N_CYCLE;
612 }
613 else
614 {
615 SetRegister(rd,READ32(rnv));
616 }
617 }
618 }
619 else
620 {
621 /* Store */
622 arm_icount -= 2 * N_CYCLE;
623 if (insn & INSN_SDT_B)
624 {
625 WRITE8(rnv, (UINT8) GetRegister(rd) & 0xffu);
626 }
627 else
628 {
629 WRITE32(rnv, rd == eR15 ? R15 + 8 : GetRegister(rd));
630 }
631 }
632
633 /* Do pre-indexing writeback */
634 if ((insn & INSN_SDT_P) && (insn & INSN_SDT_W))
635 {
636 if ((insn & INSN_SDT_L) && rd == rn)
637 SetRegister(rn, GetRegister(rd));
638 else
639 SetRegister(rn, rnv);
640 }
641
642 /* Do post-indexing writeback */
643 if (!(insn & INSN_SDT_P)/* && (insn&INSN_SDT_W)*/)
644 {
645 if (insn & INSN_SDT_U)
646 {
647 /* Writeback is applied in pipeline, before value is read from mem,
648 so writeback is effectively ignored */
649 if (rd==rn) {
650 SetRegister(rn,GetRegister(rd));
651 }
652 else {
653 SetRegister(rn,(rnv + off));
654 }
655 }
656 else
657 {
658 /* Writeback is applied in pipeline, before value is read from mem,
659 so writeback is effectively ignored */
660 if (rd==rn) {
661 SetRegister(rn,GetRegister(rd));
662 }
663 else {
664 SetRegister(rn,(rnv - off));
665 }
666 }
667 }
668 } /* HandleMemSingle */
669
670 #define IsNeg(i) ((i) >> 31)
671 #define IsPos(i) ((~(i)) >> 31)
672
673 /* Set NZCV flags for ADDS / SUBS */
674
675 #define HandleALUAddFlags(rd, rn, op2) \
676 if (insn & INSN_S) \
677 R15 = \
678 ((R15 &~ (N_MASK | Z_MASK | V_MASK | C_MASK)) \
679 | (((!SIGN_BITS_DIFFER(rn, op2)) && SIGN_BITS_DIFFER(rn, rd)) \
680 << V_BIT) \
681 | (((~(rn)) < (op2)) << C_BIT) \
682 | HandleALUNZFlags(rd)) \
683 + 4; \
684 else R15 += 4;
685
686 #define HandleALUSubFlags(rd, rn, op2) \
687 if (insn & INSN_S) \
688 R15 = \
689 ((R15 &~ (N_MASK | Z_MASK | V_MASK | C_MASK)) \
690 | ((SIGN_BITS_DIFFER(rn, op2) && SIGN_BITS_DIFFER(rn, rd)) \
691 << V_BIT) \
692 | (((IsNeg(rn) & IsPos(op2)) | (IsNeg(rn) & IsPos(rd)) | (IsPos(op2) & IsPos(rd))) ? C_MASK : 0) \
693 | HandleALUNZFlags(rd)) \
694 + 4; \
695 else R15 += 4;
696
697 /* Set NZC flags for logical operations. */
698
699 #define HandleALUNZFlags(rd) \
700 (((rd) & SIGN_BIT) | ((!(rd)) << Z_BIT))
701
702 #define HandleALULogicalFlags(rd, sc) \
703 if (insn & INSN_S) \
704 R15 = ((R15 &~ (N_MASK | Z_MASK | C_MASK)) \
705 | HandleALUNZFlags(rd) \
706 | (((sc) != 0) << C_BIT)) + 4; \
707 else R15 += 4;
708
HandleALU(UINT32 insn)709 static void HandleALU( UINT32 insn )
710 {
711 UINT32 op2, sc=0, rd, rn, opcode;
712 UINT32 by, rdn;
713
714 opcode = (insn & INSN_OPCODE) >> INSN_OPCODE_SHIFT;
715 arm_icount -= S_CYCLE;
716
717 rd = 0;
718 rn = 0;
719
720 /* Construct Op2 */
721 if (insn & INSN_I)
722 {
723 /* Immediate constant */
724 by = (insn & INSN_OP2_ROTATE) >> INSN_OP2_ROTATE_SHIFT;
725 if (by)
726 {
727 op2 = ROR(insn & INSN_OP2_IMM, by << 1);
728 sc = op2 & SIGN_BIT;
729 }
730 else
731 {
732 op2 = insn & INSN_OP2;
733 sc = R15 & C_MASK;
734 }
735 }
736 else
737 {
738 op2 = decodeShift(insn, (insn & INSN_S) ? &sc : NULL);
739
740 if (!(insn & INSN_S))
741 sc=0;
742 }
743
744 /* Calculate Rn to account for pipelining */
745 if ((opcode & 0xd) != 0xd) /* No Rn in MOV */
746 {
747 if ((rn = (insn & INSN_RN) >> INSN_RN_SHIFT) == eR15)
748 {
749 /* Docs strongly suggest the mode bits should be included here, but it breaks Captain
750 America, as it starts doing unaligned reads */
751 rn=(R15+8)&ADDRESS_MASK;
752 }
753 else
754 {
755 rn = GetRegister(rn);
756 }
757 }
758
759 /* Perform the operation */
760 switch ((insn & INSN_OPCODE) >> INSN_OPCODE_SHIFT)
761 {
762 /* Arithmetic operations */
763 case OPCODE_SBC:
764 rd = (rn - op2 - (R15 & C_MASK ? 0 : 1));
765 HandleALUSubFlags(rd, rn, op2);
766 break;
767 case OPCODE_CMP:
768 case OPCODE_SUB:
769 rd = (rn - op2);
770 HandleALUSubFlags(rd, rn, op2);
771 break;
772 case OPCODE_RSC:
773 rd = (op2 - rn - (R15 & C_MASK ? 0 : 1));
774 HandleALUSubFlags(rd, op2, rn);
775 break;
776 case OPCODE_RSB:
777 rd = (op2 - rn);
778 HandleALUSubFlags(rd, op2, rn);
779 break;
780 case OPCODE_ADC:
781 rd = (rn + op2 + ((R15 & C_MASK) >> C_BIT));
782 HandleALUAddFlags(rd, rn, op2);
783 break;
784 case OPCODE_CMN:
785 case OPCODE_ADD:
786 rd = (rn + op2);
787 HandleALUAddFlags(rd, rn, op2);
788 break;
789 /* Logical operations */
790 case OPCODE_AND:
791 case OPCODE_TST:
792 rd = rn & op2;
793 HandleALULogicalFlags(rd, sc);
794 break;
795 case OPCODE_BIC:
796 rd = rn &~ op2;
797 HandleALULogicalFlags(rd, sc);
798 break;
799 case OPCODE_TEQ:
800 case OPCODE_EOR:
801 rd = rn ^ op2;
802 HandleALULogicalFlags(rd, sc);
803 break;
804 case OPCODE_ORR:
805 rd = rn | op2;
806 HandleALULogicalFlags(rd, sc);
807 break;
808 case OPCODE_MOV:
809 rd = op2;
810 HandleALULogicalFlags(rd, sc);
811 break;
812 case OPCODE_MVN:
813 rd = (~op2);
814 HandleALULogicalFlags(rd, sc);
815 break;
816 }
817
818 /* Put the result in its register if not a test */
819 rdn = (insn & INSN_RD) >> INSN_RD_SHIFT;
820 if ((opcode & 0xc) != 0x8)
821 {
822 if (rdn == eR15 && !(insn & INSN_S))
823 {
824 /* Merge the old NZCV flags into the new PC value */
825 R15 = (rd & ADDRESS_MASK) | (R15 & PSR_MASK) | (R15 & IRQ_MASK) | (R15&MODE_MASK);
826 arm_icount -= S_CYCLE + N_CYCLE;
827 }
828 else
829 {
830 if (rdn==eR15)
831 {
832 /* S Flag is set - update PSR & mode if in non-user mode only */
833 if ((R15&MODE_MASK)!=0)
834 {
835 SetRegister(rdn,rd);
836 }
837 else
838 {
839 SetRegister(rdn,(rd&ADDRESS_MASK) | (rd&PSR_MASK) | (R15&IRQ_MASK) | (R15&MODE_MASK));
840 }
841 arm_icount -= S_CYCLE + N_CYCLE;
842 }
843 else
844 {
845 SetRegister(rdn,rd);
846 }
847 }
848 /* TST & TEQ can affect R15 (the condition code register) with the S bit set */
849 }
850 else if ((rdn==eR15) && (insn & INSN_S))
851 {
852 // update only the flags
853 if ((R15&MODE_MASK)!=0)
854 {
855 // combine the flags from rd with the address from R15
856 rd &= ~ADDRESS_MASK;
857 rd |= (R15 & ADDRESS_MASK);
858 SetRegister(rdn,rd);
859 }
860 else
861 {
862 // combine the flags from rd with the address from R15
863 rd &= ~ADDRESS_MASK; // clear address part of RD
864 rd |= (R15 & ADDRESS_MASK); // RD = address part of R15
865 SetRegister(rdn,(rd&ADDRESS_MASK) | (rd&PSR_MASK) | (R15&IRQ_MASK) | (R15&MODE_MASK));
866 }
867 arm_icount -= S_CYCLE + N_CYCLE;
868 }
869 }
870
HandleMul(UINT32 insn)871 static void HandleMul( UINT32 insn)
872 {
873 UINT32 r;
874
875 arm_icount -= S_CYCLE + I_CYCLE;
876 /* should be:
877 Range of Rs Number of cycles
878
879 &0 -- &1 1S + 1I
880 &2 -- &7 1S + 2I
881 &8 -- &1F 1S + 3I
882 &20 -- &7F 1S + 4I
883 &80 -- &1FF 1S + 5I
884 &200 -- &7FF 1S + 6I
885 &800 -- &1FFF 1S + 7I
886 &2000 -- &7FFF 1S + 8I
887 &8000 -- &1FFFF 1S + 9I
888 &20000 -- &7FFFF 1S + 10I
889 &80000 -- &1FFFFF 1S + 11I
890 &200000 -- &7FFFFF 1S + 12I
891 &800000 -- &1FFFFFF 1S + 13I
892 &2000000 -- &7FFFFFF 1S + 14I
893 &8000000 -- &1FFFFFFF 1S + 15I
894 &20000000 -- &FFFFFFFF 1S + 16I
895 */
896
897 /* Do the basic multiply of Rm and Rs */
898 r = GetRegister( insn&INSN_MUL_RM ) *
899 GetRegister( (insn&INSN_MUL_RS)>>INSN_MUL_RS_SHIFT );
900
901 /* Add on Rn if this is a MLA */
902 if (insn & INSN_MUL_A)
903 {
904 r += GetRegister((insn&INSN_MUL_RN)>>INSN_MUL_RN_SHIFT);
905 }
906
907 /* Write the result */
908 SetRegister((insn&INSN_MUL_RD)>>INSN_MUL_RD_SHIFT,r);
909
910 /* Set N and Z if asked */
911 if( insn & INSN_S )
912 {
913 R15 = (R15 &~ (N_MASK | Z_MASK)) | HandleALUNZFlags(r);
914 }
915 }
916
loadInc(UINT32 pat,UINT32 rbv,UINT32 s)917 static int loadInc ( UINT32 pat, UINT32 rbv, UINT32 s)
918 {
919 int i,result;
920
921 result = 0;
922 for( i=0; i<16; i++ )
923 {
924 if( (pat>>i)&1 )
925 {
926 if (i==15) {
927 if (s) /* Pull full contents from stack */
928 SetRegister( 15, READ32(rbv+=4) );
929 else /* Pull only address, preserve mode & status flags */
930 SetRegister( 15, (R15&PSR_MASK) | (R15&IRQ_MASK) | (R15&MODE_MASK) | ((READ32(rbv+=4))&ADDRESS_MASK) );
931 } else
932 SetRegister( i, READ32(rbv+=4) );
933
934 result++;
935 }
936 }
937 return result;
938 }
939
loadDec(UINT32 pat,UINT32 rbv,UINT32 s,UINT32 * deferredR15,int * defer)940 static int loadDec( UINT32 pat, UINT32 rbv, UINT32 s, UINT32* deferredR15, int* defer)
941 {
942 int i,result;
943
944 result = 0;
945 for( i=15; i>=0; i-- )
946 {
947 if( (pat>>i)&1 )
948 {
949 if (i==15) {
950 *defer=1;
951 if (s) /* Pull full contents from stack */
952 *deferredR15=READ32(rbv-=4);
953 else /* Pull only address, preserve mode & status flags */
954 *deferredR15=(R15&PSR_MASK) | (R15&IRQ_MASK) | (R15&MODE_MASK) | ((READ32(rbv-=4))&ADDRESS_MASK);
955 }
956 else
957 SetRegister( i, READ32(rbv -=4) );
958 result++;
959 }
960 }
961 return result;
962 }
963
storeInc(UINT32 pat,UINT32 rbv)964 static int storeInc( UINT32 pat, UINT32 rbv)
965 {
966 int i,result;
967
968 result = 0;
969 for( i=0; i<16; i++ )
970 {
971 if( (pat>>i)&1 )
972 {
973 WRITE32( rbv += 4, GetRegister(i) );
974 result++;
975 }
976 }
977 return result;
978 } /* storeInc */
979
storeDec(UINT32 pat,UINT32 rbv)980 static int storeDec( UINT32 pat, UINT32 rbv)
981 {
982 int i,result;
983
984 result = 0;
985 for( i=15; i>=0; i-- )
986 {
987 if( (pat>>i)&1 )
988 {
989 WRITE32( rbv -= 4, GetRegister(i) );
990 result++;
991 }
992 }
993 return result;
994 } /* storeDec */
995
HandleMemBlock(UINT32 insn)996 static void HandleMemBlock( UINT32 insn)
997 {
998 UINT32 rb = (insn & INSN_RN) >> INSN_RN_SHIFT;
999 UINT32 rbp = GetRegister(rb);
1000 int result;
1001
1002 if (insn & INSN_BDT_L)
1003 {
1004 /* Loading */
1005 if (insn & INSN_BDT_U)
1006 {
1007 int mode = MODE;
1008
1009 /* Incrementing */
1010 if (!(insn & INSN_BDT_P)) rbp = rbp + (- 4);
1011
1012 // S Flag Set, but R15 not in list = Transfers to User Bank
1013 if ((insn & INSN_BDT_S) && !(insn & 0x8000))
1014 {
1015 int curmode = MODE;
1016 R15 = R15 & ~MODE_MASK;
1017 result = loadInc( insn & 0xffff, rbp, insn&INSN_BDT_S );
1018 R15 = R15 | curmode;
1019 }
1020 else
1021 result = loadInc( insn & 0xffff, rbp, insn&INSN_BDT_S );
1022
1023 if (insn & 0x8000) {
1024 R15-=4;
1025 arm_icount -= S_CYCLE + N_CYCLE;
1026 }
1027
1028 if (insn & INSN_BDT_W)
1029 {
1030 /* Arm docs notes: The base register can always be loaded without any problems.
1031 However, don't specify writeback if the base register is being loaded -
1032 you can't end up with both a written-back value and a loaded value in the base register!
1033
1034 However - Fighter's History does exactly that at 0x121e4 (LDMUW [R13], { R13-R15 })!
1035
1036 This emulator implementation skips applying writeback in this case, which is confirmed
1037 correct for this situation, but that is not necessarily true for all ARM hardware
1038 implementations (the results are officially undefined).
1039 */
1040 if ((insn&(1<<rb))==0)
1041 SetModeRegister(mode, rb, GetModeRegister(mode, rb) + result * 4);
1042 }
1043 }
1044 else
1045 {
1046 UINT32 deferredR15=0;
1047 int defer=0;
1048
1049 /* Decrementing */
1050 if (!(insn & INSN_BDT_P))
1051 {
1052 rbp = rbp - (- 4);
1053 }
1054
1055 // S Flag Set, but R15 not in list = Transfers to User Bank
1056 if ((insn & INSN_BDT_S) && !(insn & 0x8000))
1057 {
1058 int curmode = MODE;
1059 R15 = R15 & ~MODE_MASK;
1060 result = loadDec( insn&0xffff, rbp, insn&INSN_BDT_S, &deferredR15, &defer );
1061 R15 = R15 | curmode;
1062 }
1063 else
1064 result = loadDec( insn&0xffff, rbp, insn&INSN_BDT_S, &deferredR15, &defer );
1065
1066 if (insn & INSN_BDT_W)
1067 {
1068 SetRegister(rb,GetRegister(rb)-result*4);
1069 }
1070
1071 // If R15 is pulled from memory we defer setting it until after writeback
1072 // is performed, else we may writeback to the wrong context (ie, the new
1073 // context if the mode has changed as a result of the R15 read)
1074 if (defer)
1075 SetRegister(15, deferredR15);
1076
1077 if (insn & 0x8000) {
1078 arm_icount -= S_CYCLE + N_CYCLE;
1079 R15-=4;
1080 }
1081 }
1082 arm_icount -= result * S_CYCLE + N_CYCLE + I_CYCLE;
1083 } /* Loading */
1084 else
1085 {
1086 /* Storing
1087
1088 ARM docs notes: Storing a list of registers including the base register using writeback
1089 will write the value of the base register before writeback to memory only if the base
1090 register is the first in the list. Otherwise, the value which is used is not defined.
1091
1092 */
1093 if (insn & (1<<eR15))
1094 {
1095 /* special case handling if writing to PC */
1096 R15 += 12;
1097 }
1098 if (insn & INSN_BDT_U)
1099 {
1100 /* Incrementing */
1101 if (!(insn & INSN_BDT_P))
1102 {
1103 rbp = rbp + (- 4);
1104 }
1105
1106 // S bit set = Transfers to User Bank
1107 if (insn & INSN_BDT_S)
1108 {
1109 int curmode = MODE;
1110 R15 = R15 & ~MODE_MASK;
1111 result = storeInc( insn&0xffff, rbp );
1112 R15 = R15 | curmode;
1113 }
1114 else
1115 result = storeInc( insn&0xffff, rbp );
1116
1117 if( insn & INSN_BDT_W )
1118 {
1119 SetRegister(rb,GetRegister(rb)+result*4);
1120 }
1121 }
1122 else
1123 {
1124 /* Decrementing */
1125 if (!(insn & INSN_BDT_P))
1126 {
1127 rbp = rbp - (- 4);
1128 }
1129
1130 // S bit set = Transfers to User Bank
1131 if (insn & INSN_BDT_S)
1132 {
1133 int curmode = MODE;
1134 R15 = R15 & ~MODE_MASK;
1135 result = storeDec( insn&0xffff, rbp );
1136 R15 = R15 | curmode;
1137 }
1138 else
1139 result = storeDec( insn&0xffff, rbp );
1140
1141 if( insn & INSN_BDT_W )
1142 {
1143 SetRegister(rb,GetRegister(rb)-result*4);
1144 }
1145 }
1146 if( insn & (1<<eR15) )
1147 R15 -= 12;
1148
1149 arm_icount -= (result - 1) * S_CYCLE + 2 * N_CYCLE;
1150 }
1151 } /* HandleMemBlock */
1152
1153
1154
1155 /* Decodes an Op2-style shifted-register form. If @carry@ is non-zero the
1156 * shifter carry output will manifest itself as @*carry == 0@ for carry clear
1157 * and @*carry != 0@ for carry set.
1158 */
decodeShift(UINT32 insn,UINT32 * pCarry)1159 static UINT32 decodeShift( UINT32 insn, UINT32 *pCarry)
1160 {
1161 UINT32 k = (insn & INSN_OP2_SHIFT) >> INSN_OP2_SHIFT_SHIFT;
1162 UINT32 rm = GetRegister( insn & INSN_OP2_RM );
1163 UINT32 t = (insn & INSN_OP2_SHIFT_TYPE) >> INSN_OP2_SHIFT_TYPE_SHIFT;
1164
1165 if ((insn & INSN_OP2_RM)==0xf) {
1166 /* If hardwired shift, then PC is 8 bytes ahead, else if register shift
1167 is used, then 12 bytes - TODO?? */
1168 rm+=8;
1169 }
1170
1171 /* All shift types ending in 1 are Rk, not #k */
1172 if( t & 1 )
1173 {
1174 // Only the least significant byte of the contents of Rs is used to determine the shift amount
1175 k = GetRegister(k >> 1) & 0xff;
1176 arm_icount -= S_CYCLE;
1177 if( k == 0 ) /* Register shift by 0 is a no-op */
1178 {
1179 if (pCarry) *pCarry = R15 & C_MASK;
1180 return rm;
1181 }
1182 }
1183 /* Decode the shift type and perform the shift */
1184 switch (t >> 1)
1185 {
1186 case 0: /* LSL */
1187 if (k >= 32)
1188 {
1189 if (pCarry)
1190 *pCarry = (k == 32) ? rm & 1 : 0;
1191 return 0;
1192 }
1193 else if (pCarry)
1194 {
1195 *pCarry = k ? (rm & (1 << (32 - k))) : (R15 & C_MASK);
1196 }
1197 return k ? LSL(rm, k) : rm;
1198
1199 case 1: /* LSR */
1200 if (k == 0 || k == 32)
1201 {
1202 if (pCarry) *pCarry = rm & SIGN_BIT;
1203 return 0;
1204 }
1205 else if (k > 32)
1206 {
1207 if (pCarry) *pCarry = 0;
1208 return 0;
1209 }
1210 else
1211 {
1212 if (pCarry) *pCarry = (rm & (1 << (k - 1)));
1213 return LSR(rm, k);
1214 }
1215
1216 case 2: /* ASR */
1217 if (k == 0 || k > 32)
1218 k = 32;
1219 if (pCarry) *pCarry = (rm & (1 << (k - 1)));
1220 if (k >= 32)
1221 return rm & SIGN_BIT ? 0xffffffffu : 0;
1222 else
1223 {
1224 if (rm & SIGN_BIT)
1225 return LSR(rm, k) | (0xffffffffu << (32 - k));
1226 else
1227 return LSR(rm, k);
1228 }
1229 break;
1230
1231 case 3: /* ROR and RRX */
1232 if (k)
1233 {
1234 while (k > 32) k -= 32;
1235 if (pCarry) *pCarry = rm & (1 << (k - 1));
1236 return ROR(rm, k);
1237 }
1238 else
1239 {
1240 if (pCarry) *pCarry = (rm & 1);
1241 return LSR(rm, 1) | ((R15 & C_MASK) << 2);
1242 }
1243 break;
1244 }
1245
1246 return 0;
1247 } /* decodeShift */
1248
1249
BCDToDecimal(UINT32 value)1250 static UINT32 BCDToDecimal(UINT32 value)
1251 {
1252 UINT32 accumulator = 0;
1253 UINT32 multiplier = 1;
1254 int i;
1255
1256 for(i = 0; i < 8; i++)
1257 {
1258 accumulator += (value & 0xF) * multiplier;
1259
1260 multiplier *= 10;
1261 value >>= 4;
1262 }
1263
1264 return accumulator;
1265 }
1266
DecimalToBCD(UINT32 value)1267 static UINT32 DecimalToBCD(UINT32 value)
1268 {
1269 UINT32 accumulator = 0;
1270 UINT32 divisor = 10;
1271 int i;
1272
1273 for(i = 0; i < 8; i++)
1274 {
1275 UINT32 temp;
1276
1277 temp = value % divisor;
1278 value -= temp;
1279 temp /= divisor / 10;
1280
1281 accumulator += temp << (i * 4);
1282
1283 divisor *= 10;
1284 }
1285
1286 return accumulator;
1287 }
1288
HandleCoPro(UINT32 insn)1289 static void HandleCoPro( UINT32 insn)
1290 {
1291 UINT32 rn=(insn>>12)&0xf;
1292 UINT32 crn=(insn>>16)&0xf;
1293
1294 arm_icount -= S_CYCLE;
1295
1296 /* MRC - transfer copro register to main register */
1297 if( (insn&0x0f100010)==0x0e100010 )
1298 {
1299 SetRegister(rn, arm.coproRegister[crn]);
1300 }
1301 /* MCR - transfer main register to copro register */
1302 else if( (insn&0x0f100010)==0x0e000010 )
1303 {
1304 arm.coproRegister[crn]=GetRegister(rn);
1305
1306 /* Data East 156 copro specific - trigger BCD operation */
1307 if (crn==2)
1308 {
1309 if (arm.coproRegister[crn]==0)
1310 {
1311 /* Unpack BCD */
1312 int v0=BCDToDecimal(arm.coproRegister[0]);
1313 int v1=BCDToDecimal(arm.coproRegister[1]);
1314
1315 /* Repack vcd */
1316 arm.coproRegister[5]=DecimalToBCD(v0+v1);
1317 }
1318 else if (arm.coproRegister[crn]==1)
1319 {
1320 /* Unpack BCD */
1321 int v0=BCDToDecimal(arm.coproRegister[0]);
1322 int v1=BCDToDecimal(arm.coproRegister[1]);
1323
1324 /* Repack vcd */
1325 arm.coproRegister[5]=DecimalToBCD(v0*v1);
1326 }
1327 else if (arm.coproRegister[crn]==3)
1328 {
1329 /* Unpack BCD */
1330 int v0=BCDToDecimal(arm.coproRegister[0]);
1331 int v1=BCDToDecimal(arm.coproRegister[1]);
1332
1333 /* Repack vcd */
1334 arm.coproRegister[5]=DecimalToBCD(v0-v1);
1335 }
1336 }
1337 }
1338 /* CDP - perform copro operation */
1339 else if( (insn&0x0f000010)==0x0e000000 )
1340 {
1341 /* Data East 156 copro specific divider - result in reg 3/4 */
1342 if (arm.coproRegister[1])
1343 {
1344 arm.coproRegister[3]=arm.coproRegister[0] / arm.coproRegister[1];
1345 arm.coproRegister[4]=arm.coproRegister[0] % arm.coproRegister[1];
1346 }
1347 else
1348 {
1349 /* Unverified */
1350 arm.coproRegister[3]=0xffffffff;
1351 arm.coproRegister[4]=0xffffffff;
1352 }
1353 }
1354 }
1355
1356 // burn some cycles
ArmIdleCycles(int cycles)1357 void ArmIdleCycles(int cycles)
1358 {
1359 #if defined FBA_DEBUG
1360 if (!DebugCPU_ARMInitted) bprintf(PRINT_ERROR, _T("ArmIdleCycles called without init\n"));
1361 #endif
1362
1363 if (arm_icount > cycles) {
1364 arm_icount -= cycles;
1365 } else {
1366 arm_icount = 0;
1367 }
1368 }
1369
1370 // get the current position
ArmGetPc(INT32)1371 unsigned int ArmGetPc(INT32)
1372 {
1373 #if defined FBA_DEBUG
1374 if (!DebugCPU_ARMInitted) bprintf(PRINT_ERROR, _T("ArmGetPC called without init\n"));
1375 #endif
1376
1377 return arm.sArmRegister[15]&ADDRESS_MASK;
1378 }
1379
1380 // get the remaining cycles left to run
ArmRemainingCycles()1381 unsigned int ArmRemainingCycles()
1382 {
1383 #if defined FBA_DEBUG
1384 if (!DebugCPU_ARMInitted) bprintf(PRINT_ERROR, _T("ArmRemainingCycles called without init\n"));
1385 #endif
1386
1387 return (arm.ArmLeftCycles - arm_icount);
1388 }
1389
1390 // get the total of cycles run
ArmGetTotalCycles()1391 int ArmGetTotalCycles()
1392 {
1393 #if defined FBA_DEBUG
1394 if (!DebugCPU_ARMInitted) bprintf(PRINT_ERROR, _T("ArmGetTotalCycles called without init\n"));
1395 #endif
1396
1397 return arm.ArmTotalCycles + (arm.ArmLeftCycles - arm_icount);
1398 }
1399
1400 // stop the current cpu slice
ArmRunEnd()1401 void ArmRunEnd()
1402 {
1403 #if defined FBA_DEBUG
1404 if (!DebugCPU_ARMInitted) bprintf(PRINT_ERROR, _T("ArmRunEnd called without init\n"));
1405 #endif
1406
1407 arm_icount = 0;
1408 }
1409
1410 // start a new frame
ArmNewFrame()1411 void ArmNewFrame()
1412 {
1413 #if defined FBA_DEBUG
1414 if (!DebugCPU_ARMInitted) bprintf(PRINT_ERROR, _T("ArmNewFrame called without init\n"));
1415 #endif
1416
1417 arm.ArmTotalCycles = 0;
1418 arm_icount = 0;
1419 arm.ArmLeftCycles = 0;
1420 }
1421
ArmScan(int nAction)1422 int ArmScan(int nAction)
1423 {
1424 #if defined FBA_DEBUG
1425 if (!DebugCPU_ARMInitted) bprintf(PRINT_ERROR, _T("ArmScan called without init\n"));
1426 #endif
1427
1428 struct BurnArea ba;
1429
1430 if (nAction & ACB_VOLATILE) {
1431 memset(&ba, 0, sizeof(ba));
1432 ba.Data = &arm;
1433 ba.nLen = sizeof(ARM_REGS);
1434 ba.szName = "ARM Registers";
1435 BurnAcb(&ba);
1436
1437 SCAN_VAR(arm_icount);
1438 }
1439
1440 return 0;
1441 }
1442