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