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
332 static int end_run = 0;
333
ArmRun(int cycles)334 int ArmRun( int cycles )
335 {
336 UINT32 pc;
337 UINT32 insn;
338
339 arm_icount = cycles;
340 arm.ArmLeftCycles = cycles;
341 end_run = 0;
342
343 do
344 {
345 /* load instruction */
346 pc = R15;
347 insn = ArmFetchLong( pc & ADDRESS_MASK );
348
349 switch (insn >> INSN_COND_SHIFT)
350 {
351 case COND_EQ:
352 if (Z_IS_CLEAR(pc)) goto L_Next;
353 break;
354 case COND_NE:
355 if (Z_IS_SET(pc)) goto L_Next;
356 break;
357 case COND_CS:
358 if (C_IS_CLEAR(pc)) goto L_Next;
359 break;
360 case COND_CC:
361 if (C_IS_SET(pc)) goto L_Next;
362 break;
363 case COND_MI:
364 if (N_IS_CLEAR(pc)) goto L_Next;
365 break;
366 case COND_PL:
367 if (N_IS_SET(pc)) goto L_Next;
368 break;
369 case COND_VS:
370 if (V_IS_CLEAR(pc)) goto L_Next;
371 break;
372 case COND_VC:
373 if (V_IS_SET(pc)) goto L_Next;
374 break;
375 case COND_HI:
376 if (C_IS_CLEAR(pc) || Z_IS_SET(pc)) goto L_Next;
377 break;
378 case COND_LS:
379 if (C_IS_SET(pc) && Z_IS_CLEAR(pc)) goto L_Next;
380 break;
381 case COND_GE:
382 if (!(pc & N_MASK) != !(pc & V_MASK)) goto L_Next; /* Use x ^ (x >> ...) method */
383 break;
384 case COND_LT:
385 if (!(pc & N_MASK) == !(pc & V_MASK)) goto L_Next;
386 break;
387 case COND_GT:
388 if (Z_IS_SET(pc) || (!(pc & N_MASK) != !(pc & V_MASK))) goto L_Next;
389 break;
390 case COND_LE:
391 if (Z_IS_CLEAR(pc) && (!(pc & N_MASK) == !(pc & V_MASK))) goto L_Next;
392 break;
393 case COND_NV:
394 goto L_Next;
395 }
396 /* Condition satisfied, so decode the instruction */
397 if ((insn & 0x0fc000f0u) == 0x00000090u) /* Multiplication */
398 {
399 HandleMul(insn);
400 R15 += 4;
401 }
402 else if (!(insn & 0x0c000000u)) /* Data processing */
403 {
404 HandleALU(insn);
405 }
406 else if ((insn & 0x0c000000u) == 0x04000000u) /* Single data access */
407 {
408 HandleMemSingle(insn);
409 R15 += 4;
410 }
411 else if ((insn & 0x0e000000u) == 0x08000000u ) /* Block data access */
412 {
413 HandleMemBlock(insn);
414 R15 += 4;
415 }
416 else if ((insn & 0x0e000000u) == 0x0a000000u) /* Branch */
417 {
418 HandleBranch(insn);
419 }
420 else if ((insn & 0x0f000000u) == 0x0e000000u) /* Coprocessor */
421 {
422 HandleCoPro(insn);
423 R15 += 4;
424 }
425 else if ((insn & 0x0f000000u) == 0x0f000000u) /* Software interrupt */
426 {
427 pc=R15+4;
428 R15 = eARM_MODE_SVC; /* Set SVC mode so PC is saved to correct R14 bank */
429 SetRegister( 14, pc ); /* save PC */
430 R15 = (pc&PSR_MASK)|(pc&IRQ_MASK)|0x8|eARM_MODE_SVC|I_MASK|(pc&MODE_MASK);
431 arm_icount -= 2 * S_CYCLE + N_CYCLE;
432 }
433 else /* Undefined */
434 {
435 L_Next:
436 arm_icount -= S_CYCLE;
437 R15 += 4;
438 }
439
440 arm_check_irq_state();
441
442 } while( arm_icount > 0 && !end_run );
443
444 cycles = cycles - arm_icount;
445
446 arm.ArmTotalCycles += cycles;
447
448 arm_icount = 0;
449 arm.ArmLeftCycles = 0;
450
451 return cycles;
452 } /* arm_execute */
453
arm_check_irq_state(void)454 static void arm_check_irq_state(void)
455 {
456 UINT32 pc = R15+4; /* save old pc (already incremented in pipeline) */;
457
458 /* Exception priorities (from ARM6, not specifically ARM2/3):
459
460 Reset
461 Data abort
462 FIRQ
463 IRQ
464 Prefetch abort
465 Undefined instruction
466 */
467
468 if (arm.pendingFiq && (pc&F_MASK)==0) {
469 R15 = eARM_MODE_FIQ; /* Set FIQ mode so PC is saved to correct R14 bank */
470 SetRegister( 14, pc ); /* save PC */
471 R15 = (pc&PSR_MASK)|(pc&IRQ_MASK)|0x1c|eARM_MODE_FIQ|I_MASK|F_MASK; /* Mask both IRQ & FIRQ, set PC=0x1c */
472 arm.pendingFiq=0;
473 return;
474 }
475
476 if (arm.pendingIrq && (pc&I_MASK)==0) {
477 R15 = eARM_MODE_IRQ; /* Set IRQ mode so PC is saved to correct R14 bank */
478 SetRegister( 14, pc ); /* save PC */
479 R15 = (pc&PSR_MASK)|(pc&IRQ_MASK)|0x18|eARM_MODE_IRQ|I_MASK|(pc&F_MASK); /* Mask only IRQ, set PC=0x18 */
480 arm.pendingIrq=0;
481 return;
482 }
483 }
484
arm_set_irq_line(int irqline,int state)485 void arm_set_irq_line(int irqline, int state)
486 {
487 #if defined FBNEO_DEBUG
488 if (!DebugCPU_ARMInitted) bprintf(PRINT_ERROR, _T("arm_set_irq_line called without init\n"));
489 #endif
490
491 switch (irqline) {
492
493 case ARM_IRQ_LINE: /* IRQ */
494 if (state && (R15&0x3)!=eARM_MODE_IRQ) /* Don't allow nested IRQs */
495 arm.pendingIrq=1;
496 else
497 arm.pendingIrq=0;
498 break;
499
500 case ARM_FIRQ_LINE: /* FIRQ */
501 if (state && (R15&0x3)!=eARM_MODE_FIQ) /* Don't allow nested FIRQs */
502 arm.pendingFiq=1;
503 else
504 arm.pendingFiq=0;
505 break;
506 }
507
508 arm_check_irq_state();
509 }
510
511 /***************************************************************************/
512
HandleBranch(UINT32 insn)513 static void HandleBranch( UINT32 insn )
514 {
515 UINT32 off = (insn & INSN_BRANCH) << 2;
516
517 /* Save PC into LR if this is a branch with link */
518 if (insn & INSN_BL)
519 {
520 SetRegister(14,R15 + 4);
521 }
522
523 /* Sign-extend the 24-bit offset in our calculations */
524 if (off & 0x2000000u)
525 {
526 R15 = ((R15 - (((~(off | 0xfc000000u)) + 1) - 8)) & ADDRESS_MASK) | (R15 & ~ADDRESS_MASK);
527 }
528 else
529 {
530 R15 = ((R15 + (off + 8)) & ADDRESS_MASK) | (R15 & ~ADDRESS_MASK);
531 }
532 arm_icount -= 2 * S_CYCLE + N_CYCLE;
533 }
534
HandleMemSingle(UINT32 insn)535 static void HandleMemSingle( UINT32 insn )
536 {
537 UINT32 rn, rnv, off, rd;
538
539 /* Fetch the offset */
540 if (insn & INSN_I)
541 {
542 off = decodeShift(insn, NULL);
543 }
544 else
545 {
546 off = insn & INSN_SDT_IMM;
547 }
548
549 /* Calculate Rn, accounting for PC */
550 rn = (insn & INSN_RN) >> INSN_RN_SHIFT;
551
552 if (insn & INSN_SDT_P)
553 {
554 /* Pre-indexed addressing */
555 if (insn & INSN_SDT_U)
556 {
557 if (rn != eR15)
558 rnv = (GetRegister(rn) + off);
559 else
560 rnv = (R15 & ADDRESS_MASK) + off;
561 }
562 else
563 {
564 if (rn != eR15)
565 rnv = (GetRegister(rn) - off);
566 else
567 rnv = (R15 & ADDRESS_MASK) - off;
568 }
569
570 /*if (insn & INSN_SDT_W)
571 {
572 SetRegister(rn,rnv);
573 }
574 else*/ if (rn == eR15)
575 {
576 rnv = rnv + 8;
577 }
578 }
579 else
580 {
581 /* Post-indexed addressing */
582 if (rn == eR15)
583 {
584 rnv = (R15 & ADDRESS_MASK) + 8;
585 }
586 else
587 {
588 rnv = GetRegister(rn);
589 }
590 }
591
592 /* Do the transfer */
593 rd = (insn & INSN_RD) >> INSN_RD_SHIFT;
594 if (insn & INSN_SDT_L)
595 {
596 /* Load */
597 arm_icount -= S_CYCLE + I_CYCLE + N_CYCLE;
598 if (insn & INSN_SDT_B)
599 {
600 SetRegister(rd,(UINT32) READ8(rnv));
601 }
602 else
603 {
604 if (rd == eR15)
605 {
606 R15 = (READ32(rnv) & ADDRESS_MASK) | (R15 & PSR_MASK) | (R15 & IRQ_MASK) | (R15 & MODE_MASK);
607
608 /*
609 The docs are explicit in that the bottom bits should be masked off
610 when writing to R15 in this way, however World Cup Volleyball 95 has
611 an example of an unaligned jump (bottom bits = 2) where execution
612 should definitely continue from the rounded up address.
613
614 In other cases, 4 is subracted from R15 here to account for pipelining.
615 */
616 if ((READ32(rnv)&3)==0)
617 R15 -= 4;
618
619 arm_icount -= S_CYCLE + N_CYCLE;
620 }
621 else
622 {
623 SetRegister(rd,READ32(rnv));
624 }
625 }
626 }
627 else
628 {
629 /* Store */
630 arm_icount -= 2 * N_CYCLE;
631 if (insn & INSN_SDT_B)
632 {
633 WRITE8(rnv, (UINT8) GetRegister(rd) & 0xffu);
634 }
635 else
636 {
637 WRITE32(rnv, rd == eR15 ? R15 + 8 : GetRegister(rd));
638 }
639 }
640
641 /* Do pre-indexing writeback */
642 if ((insn & INSN_SDT_P) && (insn & INSN_SDT_W))
643 {
644 if ((insn & INSN_SDT_L) && rd == rn)
645 SetRegister(rn, GetRegister(rd));
646 else
647 SetRegister(rn, rnv);
648 }
649
650 /* Do post-indexing writeback */
651 if (!(insn & INSN_SDT_P)/* && (insn&INSN_SDT_W)*/)
652 {
653 if (insn & INSN_SDT_U)
654 {
655 /* Writeback is applied in pipeline, before value is read from mem,
656 so writeback is effectively ignored */
657 if (rd==rn) {
658 SetRegister(rn,GetRegister(rd));
659 }
660 else {
661 SetRegister(rn,(rnv + off));
662 }
663 }
664 else
665 {
666 /* Writeback is applied in pipeline, before value is read from mem,
667 so writeback is effectively ignored */
668 if (rd==rn) {
669 SetRegister(rn,GetRegister(rd));
670 }
671 else {
672 SetRegister(rn,(rnv - off));
673 }
674 }
675 }
676 } /* HandleMemSingle */
677
678 #define IsNeg(i) ((i) >> 31)
679 #define IsPos(i) ((~(i)) >> 31)
680
681 /* Set NZCV flags for ADDS / SUBS */
682
683 #define HandleALUAddFlags(rd, rn, op2) \
684 if (insn & INSN_S) \
685 R15 = \
686 ((R15 &~ (N_MASK | Z_MASK | V_MASK | C_MASK)) \
687 | (((!SIGN_BITS_DIFFER(rn, op2)) && SIGN_BITS_DIFFER(rn, rd)) \
688 << V_BIT) \
689 | (((~(rn)) < (op2)) << C_BIT) \
690 | HandleALUNZFlags(rd)) \
691 + 4; \
692 else R15 += 4;
693
694 #define HandleALUSubFlags(rd, rn, op2) \
695 if (insn & INSN_S) \
696 R15 = \
697 ((R15 &~ (N_MASK | Z_MASK | V_MASK | C_MASK)) \
698 | ((SIGN_BITS_DIFFER(rn, op2) && SIGN_BITS_DIFFER(rn, rd)) \
699 << V_BIT) \
700 | (((IsNeg(rn) & IsPos(op2)) | (IsNeg(rn) & IsPos(rd)) | (IsPos(op2) & IsPos(rd))) ? C_MASK : 0) \
701 | HandleALUNZFlags(rd)) \
702 + 4; \
703 else R15 += 4;
704
705 /* Set NZC flags for logical operations. */
706
707 #define HandleALUNZFlags(rd) \
708 (((rd) & SIGN_BIT) | ((!(rd)) << Z_BIT))
709
710 #define HandleALULogicalFlags(rd, sc) \
711 if (insn & INSN_S) \
712 R15 = ((R15 &~ (N_MASK | Z_MASK | C_MASK)) \
713 | HandleALUNZFlags(rd) \
714 | (((sc) != 0) << C_BIT)) + 4; \
715 else R15 += 4;
716
HandleALU(UINT32 insn)717 static void HandleALU( UINT32 insn )
718 {
719 UINT32 op2, sc=0, rd, rn, opcode;
720 UINT32 by, rdn;
721
722 opcode = (insn & INSN_OPCODE) >> INSN_OPCODE_SHIFT;
723 arm_icount -= S_CYCLE;
724
725 rd = 0;
726 rn = 0;
727
728 /* Construct Op2 */
729 if (insn & INSN_I)
730 {
731 /* Immediate constant */
732 by = (insn & INSN_OP2_ROTATE) >> INSN_OP2_ROTATE_SHIFT;
733 if (by)
734 {
735 op2 = ROR(insn & INSN_OP2_IMM, by << 1);
736 sc = op2 & SIGN_BIT;
737 }
738 else
739 {
740 op2 = insn & INSN_OP2;
741 sc = R15 & C_MASK;
742 }
743 }
744 else
745 {
746 op2 = decodeShift(insn, (insn & INSN_S) ? &sc : NULL);
747
748 if (!(insn & INSN_S))
749 sc=0;
750 }
751
752 /* Calculate Rn to account for pipelining */
753 if ((opcode & 0xd) != 0xd) /* No Rn in MOV */
754 {
755 if ((rn = (insn & INSN_RN) >> INSN_RN_SHIFT) == eR15)
756 {
757 /* Docs strongly suggest the mode bits should be included here, but it breaks Captain
758 America, as it starts doing unaligned reads */
759 rn=(R15+8)&ADDRESS_MASK;
760 }
761 else
762 {
763 rn = GetRegister(rn);
764 }
765 }
766
767 /* Perform the operation */
768 switch ((insn & INSN_OPCODE) >> INSN_OPCODE_SHIFT)
769 {
770 /* Arithmetic operations */
771 case OPCODE_SBC:
772 rd = (rn - op2 - (R15 & C_MASK ? 0 : 1));
773 HandleALUSubFlags(rd, rn, op2);
774 break;
775 case OPCODE_CMP:
776 case OPCODE_SUB:
777 rd = (rn - op2);
778 HandleALUSubFlags(rd, rn, op2);
779 break;
780 case OPCODE_RSC:
781 rd = (op2 - rn - (R15 & C_MASK ? 0 : 1));
782 HandleALUSubFlags(rd, op2, rn);
783 break;
784 case OPCODE_RSB:
785 rd = (op2 - rn);
786 HandleALUSubFlags(rd, op2, rn);
787 break;
788 case OPCODE_ADC:
789 rd = (rn + op2 + ((R15 & C_MASK) >> C_BIT));
790 HandleALUAddFlags(rd, rn, op2);
791 break;
792 case OPCODE_CMN:
793 case OPCODE_ADD:
794 rd = (rn + op2);
795 HandleALUAddFlags(rd, rn, op2);
796 break;
797 /* Logical operations */
798 case OPCODE_AND:
799 case OPCODE_TST:
800 rd = rn & op2;
801 HandleALULogicalFlags(rd, sc);
802 break;
803 case OPCODE_BIC:
804 rd = rn &~ op2;
805 HandleALULogicalFlags(rd, sc);
806 break;
807 case OPCODE_TEQ:
808 case OPCODE_EOR:
809 rd = rn ^ op2;
810 HandleALULogicalFlags(rd, sc);
811 break;
812 case OPCODE_ORR:
813 rd = rn | op2;
814 HandleALULogicalFlags(rd, sc);
815 break;
816 case OPCODE_MOV:
817 rd = op2;
818 HandleALULogicalFlags(rd, sc);
819 break;
820 case OPCODE_MVN:
821 rd = (~op2);
822 HandleALULogicalFlags(rd, sc);
823 break;
824 }
825
826 /* Put the result in its register if not a test */
827 rdn = (insn & INSN_RD) >> INSN_RD_SHIFT;
828 if ((opcode & 0xc) != 0x8)
829 {
830 if (rdn == eR15 && !(insn & INSN_S))
831 {
832 /* Merge the old NZCV flags into the new PC value */
833 R15 = (rd & ADDRESS_MASK) | (R15 & PSR_MASK) | (R15 & IRQ_MASK) | (R15&MODE_MASK);
834 arm_icount -= S_CYCLE + N_CYCLE;
835 }
836 else
837 {
838 if (rdn==eR15)
839 {
840 /* S Flag is set - update PSR & mode if in non-user mode only */
841 if ((R15&MODE_MASK)!=0)
842 {
843 SetRegister(rdn,rd);
844 }
845 else
846 {
847 SetRegister(rdn,(rd&ADDRESS_MASK) | (rd&PSR_MASK) | (R15&IRQ_MASK) | (R15&MODE_MASK));
848 }
849 arm_icount -= S_CYCLE + N_CYCLE;
850 }
851 else
852 {
853 SetRegister(rdn,rd);
854 }
855 }
856 /* TST & TEQ can affect R15 (the condition code register) with the S bit set */
857 }
858 else if ((rdn==eR15) && (insn & INSN_S))
859 {
860 // update only the flags
861 if ((R15&MODE_MASK)!=0)
862 {
863 // combine the flags from rd with the address from R15
864 rd &= ~ADDRESS_MASK;
865 rd |= (R15 & ADDRESS_MASK);
866 SetRegister(rdn,rd);
867 }
868 else
869 {
870 // combine the flags from rd with the address from R15
871 rd &= ~ADDRESS_MASK; // clear address part of RD
872 rd |= (R15 & ADDRESS_MASK); // RD = address part of R15
873 SetRegister(rdn,(rd&ADDRESS_MASK) | (rd&PSR_MASK) | (R15&IRQ_MASK) | (R15&MODE_MASK));
874 }
875 arm_icount -= S_CYCLE + N_CYCLE;
876 }
877 }
878
HandleMul(UINT32 insn)879 static void HandleMul( UINT32 insn)
880 {
881 UINT32 r;
882
883 arm_icount -= S_CYCLE + I_CYCLE;
884 /* should be:
885 Range of Rs Number of cycles
886
887 &0 -- &1 1S + 1I
888 &2 -- &7 1S + 2I
889 &8 -- &1F 1S + 3I
890 &20 -- &7F 1S + 4I
891 &80 -- &1FF 1S + 5I
892 &200 -- &7FF 1S + 6I
893 &800 -- &1FFF 1S + 7I
894 &2000 -- &7FFF 1S + 8I
895 &8000 -- &1FFFF 1S + 9I
896 &20000 -- &7FFFF 1S + 10I
897 &80000 -- &1FFFFF 1S + 11I
898 &200000 -- &7FFFFF 1S + 12I
899 &800000 -- &1FFFFFF 1S + 13I
900 &2000000 -- &7FFFFFF 1S + 14I
901 &8000000 -- &1FFFFFFF 1S + 15I
902 &20000000 -- &FFFFFFFF 1S + 16I
903 */
904
905 /* Do the basic multiply of Rm and Rs */
906 r = GetRegister( insn&INSN_MUL_RM ) *
907 GetRegister( (insn&INSN_MUL_RS)>>INSN_MUL_RS_SHIFT );
908
909 /* Add on Rn if this is a MLA */
910 if (insn & INSN_MUL_A)
911 {
912 r += GetRegister((insn&INSN_MUL_RN)>>INSN_MUL_RN_SHIFT);
913 }
914
915 /* Write the result */
916 SetRegister((insn&INSN_MUL_RD)>>INSN_MUL_RD_SHIFT,r);
917
918 /* Set N and Z if asked */
919 if( insn & INSN_S )
920 {
921 R15 = (R15 &~ (N_MASK | Z_MASK)) | HandleALUNZFlags(r);
922 }
923 }
924
loadInc(UINT32 pat,UINT32 rbv,UINT32 s)925 static int loadInc ( UINT32 pat, UINT32 rbv, UINT32 s)
926 {
927 int i,result;
928
929 result = 0;
930 for( i=0; i<16; i++ )
931 {
932 if( (pat>>i)&1 )
933 {
934 if (i==15) {
935 if (s) /* Pull full contents from stack */
936 SetRegister( 15, READ32(rbv+=4) );
937 else /* Pull only address, preserve mode & status flags */
938 SetRegister( 15, (R15&PSR_MASK) | (R15&IRQ_MASK) | (R15&MODE_MASK) | ((READ32(rbv+=4))&ADDRESS_MASK) );
939 } else
940 SetRegister( i, READ32(rbv+=4) );
941
942 result++;
943 }
944 }
945 return result;
946 }
947
loadDec(UINT32 pat,UINT32 rbv,UINT32 s,UINT32 * deferredR15,int * defer)948 static int loadDec( UINT32 pat, UINT32 rbv, UINT32 s, UINT32* deferredR15, int* defer)
949 {
950 int i,result;
951
952 result = 0;
953 for( i=15; i>=0; i-- )
954 {
955 if( (pat>>i)&1 )
956 {
957 if (i==15) {
958 *defer=1;
959 if (s) /* Pull full contents from stack */
960 *deferredR15=READ32(rbv-=4);
961 else /* Pull only address, preserve mode & status flags */
962 *deferredR15=(R15&PSR_MASK) | (R15&IRQ_MASK) | (R15&MODE_MASK) | ((READ32(rbv-=4))&ADDRESS_MASK);
963 }
964 else
965 SetRegister( i, READ32(rbv -=4) );
966 result++;
967 }
968 }
969 return result;
970 }
971
storeInc(UINT32 pat,UINT32 rbv)972 static int storeInc( UINT32 pat, UINT32 rbv)
973 {
974 int i,result;
975
976 result = 0;
977 for( i=0; i<16; i++ )
978 {
979 if( (pat>>i)&1 )
980 {
981 WRITE32( rbv += 4, GetRegister(i) );
982 result++;
983 }
984 }
985 return result;
986 } /* storeInc */
987
storeDec(UINT32 pat,UINT32 rbv)988 static int storeDec( UINT32 pat, UINT32 rbv)
989 {
990 int i,result;
991
992 result = 0;
993 for( i=15; i>=0; i-- )
994 {
995 if( (pat>>i)&1 )
996 {
997 WRITE32( rbv -= 4, GetRegister(i) );
998 result++;
999 }
1000 }
1001 return result;
1002 } /* storeDec */
1003
HandleMemBlock(UINT32 insn)1004 static void HandleMemBlock( UINT32 insn)
1005 {
1006 UINT32 rb = (insn & INSN_RN) >> INSN_RN_SHIFT;
1007 UINT32 rbp = GetRegister(rb);
1008 int result;
1009
1010 if (insn & INSN_BDT_L)
1011 {
1012 /* Loading */
1013 if (insn & INSN_BDT_U)
1014 {
1015 int mode = MODE;
1016
1017 /* Incrementing */
1018 if (!(insn & INSN_BDT_P)) rbp = rbp + (- 4);
1019
1020 // S Flag Set, but R15 not in list = Transfers to User Bank
1021 if ((insn & INSN_BDT_S) && !(insn & 0x8000))
1022 {
1023 int curmode = MODE;
1024 R15 = R15 & ~MODE_MASK;
1025 result = loadInc( insn & 0xffff, rbp, insn&INSN_BDT_S );
1026 R15 = R15 | curmode;
1027 }
1028 else
1029 result = loadInc( insn & 0xffff, rbp, insn&INSN_BDT_S );
1030
1031 if (insn & 0x8000) {
1032 R15-=4;
1033 arm_icount -= S_CYCLE + N_CYCLE;
1034 }
1035
1036 if (insn & INSN_BDT_W)
1037 {
1038 /* Arm docs notes: The base register can always be loaded without any problems.
1039 However, don't specify writeback if the base register is being loaded -
1040 you can't end up with both a written-back value and a loaded value in the base register!
1041
1042 However - Fighter's History does exactly that at 0x121e4 (LDMUW [R13], { R13-R15 })!
1043
1044 This emulator implementation skips applying writeback in this case, which is confirmed
1045 correct for this situation, but that is not necessarily true for all ARM hardware
1046 implementations (the results are officially undefined).
1047 */
1048 if ((insn&(1<<rb))==0)
1049 SetModeRegister(mode, rb, GetModeRegister(mode, rb) + result * 4);
1050 }
1051 }
1052 else
1053 {
1054 UINT32 deferredR15=0;
1055 int defer=0;
1056
1057 /* Decrementing */
1058 if (!(insn & INSN_BDT_P))
1059 {
1060 rbp = rbp - (- 4);
1061 }
1062
1063 // S Flag Set, but R15 not in list = Transfers to User Bank
1064 if ((insn & INSN_BDT_S) && !(insn & 0x8000))
1065 {
1066 int curmode = MODE;
1067 R15 = R15 & ~MODE_MASK;
1068 result = loadDec( insn&0xffff, rbp, insn&INSN_BDT_S, &deferredR15, &defer );
1069 R15 = R15 | curmode;
1070 }
1071 else
1072 result = loadDec( insn&0xffff, rbp, insn&INSN_BDT_S, &deferredR15, &defer );
1073
1074 if (insn & INSN_BDT_W)
1075 {
1076 SetRegister(rb,GetRegister(rb)-result*4);
1077 }
1078
1079 // If R15 is pulled from memory we defer setting it until after writeback
1080 // is performed, else we may writeback to the wrong context (ie, the new
1081 // context if the mode has changed as a result of the R15 read)
1082 if (defer)
1083 SetRegister(15, deferredR15);
1084
1085 if (insn & 0x8000) {
1086 arm_icount -= S_CYCLE + N_CYCLE;
1087 R15-=4;
1088 }
1089 }
1090 arm_icount -= result * S_CYCLE + N_CYCLE + I_CYCLE;
1091 } /* Loading */
1092 else
1093 {
1094 /* Storing
1095
1096 ARM docs notes: Storing a list of registers including the base register using writeback
1097 will write the value of the base register before writeback to memory only if the base
1098 register is the first in the list. Otherwise, the value which is used is not defined.
1099
1100 */
1101 if (insn & (1<<eR15))
1102 {
1103 /* special case handling if writing to PC */
1104 R15 += 12;
1105 }
1106 if (insn & INSN_BDT_U)
1107 {
1108 /* Incrementing */
1109 if (!(insn & INSN_BDT_P))
1110 {
1111 rbp = rbp + (- 4);
1112 }
1113
1114 // S bit set = Transfers to User Bank
1115 if (insn & INSN_BDT_S)
1116 {
1117 int curmode = MODE;
1118 R15 = R15 & ~MODE_MASK;
1119 result = storeInc( insn&0xffff, rbp );
1120 R15 = R15 | curmode;
1121 }
1122 else
1123 result = storeInc( insn&0xffff, rbp );
1124
1125 if( insn & INSN_BDT_W )
1126 {
1127 SetRegister(rb,GetRegister(rb)+result*4);
1128 }
1129 }
1130 else
1131 {
1132 /* Decrementing */
1133 if (!(insn & INSN_BDT_P))
1134 {
1135 rbp = rbp - (- 4);
1136 }
1137
1138 // S bit set = Transfers to User Bank
1139 if (insn & INSN_BDT_S)
1140 {
1141 int curmode = MODE;
1142 R15 = R15 & ~MODE_MASK;
1143 result = storeDec( insn&0xffff, rbp );
1144 R15 = R15 | curmode;
1145 }
1146 else
1147 result = storeDec( insn&0xffff, rbp );
1148
1149 if( insn & INSN_BDT_W )
1150 {
1151 SetRegister(rb,GetRegister(rb)-result*4);
1152 }
1153 }
1154 if( insn & (1<<eR15) )
1155 R15 -= 12;
1156
1157 arm_icount -= (result - 1) * S_CYCLE + 2 * N_CYCLE;
1158 }
1159 } /* HandleMemBlock */
1160
1161
1162
1163 /* Decodes an Op2-style shifted-register form. If @carry@ is non-zero the
1164 * shifter carry output will manifest itself as @*carry == 0@ for carry clear
1165 * and @*carry != 0@ for carry set.
1166 */
decodeShift(UINT32 insn,UINT32 * pCarry)1167 static UINT32 decodeShift( UINT32 insn, UINT32 *pCarry)
1168 {
1169 UINT32 k = (insn & INSN_OP2_SHIFT) >> INSN_OP2_SHIFT_SHIFT;
1170 UINT32 rm = GetRegister( insn & INSN_OP2_RM );
1171 UINT32 t = (insn & INSN_OP2_SHIFT_TYPE) >> INSN_OP2_SHIFT_TYPE_SHIFT;
1172
1173 if ((insn & INSN_OP2_RM)==0xf) {
1174 /* If hardwired shift, then PC is 8 bytes ahead, else if register shift
1175 is used, then 12 bytes - TODO?? */
1176 rm+=8;
1177 }
1178
1179 /* All shift types ending in 1 are Rk, not #k */
1180 if( t & 1 )
1181 {
1182 // Only the least significant byte of the contents of Rs is used to determine the shift amount
1183 k = GetRegister(k >> 1) & 0xff;
1184 arm_icount -= S_CYCLE;
1185 if( k == 0 ) /* Register shift by 0 is a no-op */
1186 {
1187 if (pCarry) *pCarry = R15 & C_MASK;
1188 return rm;
1189 }
1190 }
1191 /* Decode the shift type and perform the shift */
1192 switch (t >> 1)
1193 {
1194 case 0: /* LSL */
1195 if (k >= 32)
1196 {
1197 if (pCarry)
1198 *pCarry = (k == 32) ? rm & 1 : 0;
1199 return 0;
1200 }
1201 else if (pCarry)
1202 {
1203 *pCarry = k ? (rm & (1 << (32 - k))) : (R15 & C_MASK);
1204 }
1205 return k ? LSL(rm, k) : rm;
1206
1207 case 1: /* LSR */
1208 if (k == 0 || k == 32)
1209 {
1210 if (pCarry) *pCarry = rm & SIGN_BIT;
1211 return 0;
1212 }
1213 else if (k > 32)
1214 {
1215 if (pCarry) *pCarry = 0;
1216 return 0;
1217 }
1218 else
1219 {
1220 if (pCarry) *pCarry = (rm & (1 << (k - 1)));
1221 return LSR(rm, k);
1222 }
1223
1224 case 2: /* ASR */
1225 if (k == 0 || k > 32)
1226 k = 32;
1227 if (pCarry) *pCarry = (rm & (1 << (k - 1)));
1228 if (k >= 32)
1229 return rm & SIGN_BIT ? 0xffffffffu : 0;
1230 else
1231 {
1232 if (rm & SIGN_BIT)
1233 return LSR(rm, k) | (0xffffffffu << (32 - k));
1234 else
1235 return LSR(rm, k);
1236 }
1237 break;
1238
1239 case 3: /* ROR and RRX */
1240 if (k)
1241 {
1242 while (k > 32) k -= 32;
1243 if (pCarry) *pCarry = rm & (1 << (k - 1));
1244 return ROR(rm, k);
1245 }
1246 else
1247 {
1248 if (pCarry) *pCarry = (rm & 1);
1249 return LSR(rm, 1) | ((R15 & C_MASK) << 2);
1250 }
1251 break;
1252 }
1253
1254 return 0;
1255 } /* decodeShift */
1256
1257
BCDToDecimal(UINT32 value)1258 static UINT32 BCDToDecimal(UINT32 value)
1259 {
1260 UINT32 accumulator = 0;
1261 UINT32 multiplier = 1;
1262 int i;
1263
1264 for(i = 0; i < 8; i++)
1265 {
1266 accumulator += (value & 0xF) * multiplier;
1267
1268 multiplier *= 10;
1269 value >>= 4;
1270 }
1271
1272 return accumulator;
1273 }
1274
DecimalToBCD(UINT32 value)1275 static UINT32 DecimalToBCD(UINT32 value)
1276 {
1277 UINT32 accumulator = 0;
1278 UINT32 divisor = 10;
1279 int i;
1280
1281 for(i = 0; i < 8; i++)
1282 {
1283 UINT32 temp;
1284
1285 temp = value % divisor;
1286 value -= temp;
1287 temp /= divisor / 10;
1288
1289 accumulator += temp << (i * 4);
1290
1291 divisor *= 10;
1292 }
1293
1294 return accumulator;
1295 }
1296
HandleCoPro(UINT32 insn)1297 static void HandleCoPro( UINT32 insn)
1298 {
1299 UINT32 rn=(insn>>12)&0xf;
1300 UINT32 crn=(insn>>16)&0xf;
1301
1302 arm_icount -= S_CYCLE;
1303
1304 /* MRC - transfer copro register to main register */
1305 if( (insn&0x0f100010)==0x0e100010 )
1306 {
1307 SetRegister(rn, arm.coproRegister[crn]);
1308 }
1309 /* MCR - transfer main register to copro register */
1310 else if( (insn&0x0f100010)==0x0e000010 )
1311 {
1312 arm.coproRegister[crn]=GetRegister(rn);
1313
1314 /* Data East 156 copro specific - trigger BCD operation */
1315 if (crn==2)
1316 {
1317 if (arm.coproRegister[crn]==0)
1318 {
1319 /* Unpack BCD */
1320 int v0=BCDToDecimal(arm.coproRegister[0]);
1321 int v1=BCDToDecimal(arm.coproRegister[1]);
1322
1323 /* Repack vcd */
1324 arm.coproRegister[5]=DecimalToBCD(v0+v1);
1325 }
1326 else if (arm.coproRegister[crn]==1)
1327 {
1328 /* Unpack BCD */
1329 int v0=BCDToDecimal(arm.coproRegister[0]);
1330 int v1=BCDToDecimal(arm.coproRegister[1]);
1331
1332 /* Repack vcd */
1333 arm.coproRegister[5]=DecimalToBCD(v0*v1);
1334 }
1335 else if (arm.coproRegister[crn]==3)
1336 {
1337 /* Unpack BCD */
1338 int v0=BCDToDecimal(arm.coproRegister[0]);
1339 int v1=BCDToDecimal(arm.coproRegister[1]);
1340
1341 /* Repack vcd */
1342 arm.coproRegister[5]=DecimalToBCD(v0-v1);
1343 }
1344 }
1345 }
1346 /* CDP - perform copro operation */
1347 else if( (insn&0x0f000010)==0x0e000000 )
1348 {
1349 /* Data East 156 copro specific divider - result in reg 3/4 */
1350 if (arm.coproRegister[1])
1351 {
1352 arm.coproRegister[3]=arm.coproRegister[0] / arm.coproRegister[1];
1353 arm.coproRegister[4]=arm.coproRegister[0] % arm.coproRegister[1];
1354 }
1355 else
1356 {
1357 /* Unverified */
1358 arm.coproRegister[3]=0xffffffff;
1359 arm.coproRegister[4]=0xffffffff;
1360 }
1361 }
1362 }
1363
1364 // burn some cycles
ArmIdleCycles(int cycles)1365 void ArmIdleCycles(int cycles)
1366 {
1367 #if defined FBNEO_DEBUG
1368 if (!DebugCPU_ARMInitted) bprintf(PRINT_ERROR, _T("ArmIdleCycles called without init\n"));
1369 #endif
1370
1371 if (arm_icount > cycles) {
1372 arm_icount -= cycles;
1373 } else {
1374 arm_icount = 0;
1375 }
1376 }
1377
1378 // get the current position
ArmGetPc(INT32)1379 unsigned int ArmGetPc(INT32)
1380 {
1381 #if defined FBNEO_DEBUG
1382 if (!DebugCPU_ARMInitted) bprintf(PRINT_ERROR, _T("ArmGetPC called without init\n"));
1383 #endif
1384
1385 return arm.sArmRegister[15]&ADDRESS_MASK;
1386 }
1387
1388 // get the remaining cycles left to run
ArmRemainingCycles()1389 unsigned int ArmRemainingCycles()
1390 {
1391 #if defined FBNEO_DEBUG
1392 if (!DebugCPU_ARMInitted) bprintf(PRINT_ERROR, _T("ArmRemainingCycles called without init\n"));
1393 #endif
1394
1395 return (arm.ArmLeftCycles - arm_icount);
1396 }
1397
1398 // get the total of cycles run
ArmGetTotalCycles()1399 int ArmGetTotalCycles()
1400 {
1401 #if defined FBNEO_DEBUG
1402 if (!DebugCPU_ARMInitted) bprintf(PRINT_ERROR, _T("ArmGetTotalCycles called without init\n"));
1403 #endif
1404
1405 return arm.ArmTotalCycles + (arm.ArmLeftCycles - arm_icount);
1406 }
1407
1408 // stop the current cpu slice
ArmRunEnd()1409 void ArmRunEnd()
1410 {
1411 #if defined FBNEO_DEBUG
1412 if (!DebugCPU_ARMInitted) bprintf(PRINT_ERROR, _T("ArmRunEnd called without init\n"));
1413 #endif
1414
1415 end_run = 1;
1416 }
1417
ArmIdle(INT32 cycles)1418 INT32 ArmIdle(INT32 cycles)
1419 {
1420 arm.ArmTotalCycles += cycles;
1421
1422 return cycles;
1423 }
1424
1425 // start a new frame
ArmNewFrame()1426 void ArmNewFrame()
1427 {
1428 #if defined FBNEO_DEBUG
1429 if (!DebugCPU_ARMInitted) bprintf(PRINT_ERROR, _T("ArmNewFrame called without init\n"));
1430 #endif
1431
1432 arm.ArmTotalCycles = 0;
1433 }
1434
ArmScan(int nAction)1435 int ArmScan(int nAction)
1436 {
1437 #if defined FBNEO_DEBUG
1438 if (!DebugCPU_ARMInitted) bprintf(PRINT_ERROR, _T("ArmScan called without init\n"));
1439 #endif
1440
1441 struct BurnArea ba;
1442
1443 if (nAction & ACB_VOLATILE) {
1444 memset(&ba, 0, sizeof(ba));
1445 ba.Data = &arm;
1446 ba.nLen = sizeof(ARM_REGS);
1447 ba.szName = "ARM Registers";
1448 BurnAcb(&ba);
1449
1450 SCAN_VAR(arm_icount);
1451 }
1452
1453 return 0;
1454 }
1455