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