4 struct arm_registers armr;
6 /* NB: The arm has a different memory map, but for the meantime... */
7 /* Page references are as per ARM DDI 0100E (June 2000) */
9 #define MEM_READ_BYTE( addr ) mem_read_byte(addr)
10 #define MEM_READ_WORD( addr ) mem_read_word(addr)
11 #define MEM_READ_LONG( addr ) mem_read_long(addr)
12 #define MEM_WRITE_BYTE( addr, val ) mem_write_byte(addr, val)
13 #define MEM_WRITE_WORD( addr, val ) mem_write_word(addr, val)
14 #define MEM_WRITE_LONG( addr, val ) mem_write_long(addr, val)
17 #define IS_NOTBORROW( result, op1, op2 ) (op2 > op1 ? 0 : 1)
18 #define IS_CARRY( result, op1, op2 ) (result < op1 ? 1 : 0)
19 #define IS_SUBOVERFLOW( result, op1, op2 ) (((op1^op2) & (result^op1)) >> 31)
20 #define IS_ADDOVERFLOW( result, op1, op2 ) (((op1&op2) & (result^op1)) >> 31)
22 #define PC armr.r[15];
24 /* Instruction fields */
25 #define COND(ir) (ir>>28)
26 #define GRP(ir) ((ir>>26)&0x03)
27 #define OPCODE(ir) ((ir>>20)&0x1F)
28 #define IFLAG(ir) (ir&0x02000000)
29 #define SFLAG(ir) (ir&0x00100000)
30 #define PFLAG(ir) (ir&0x01000000)
31 #define UFLAG(ir) (ir&0x00800000)
32 #define BFLAG(ir) (ir&0x00400000)
33 #define WFLAG(ir) (IR&0x00200000)
34 #define LFLAG(ir) SFLAG(ir)
35 #define RN(ir) (armr.r[((ir>>16)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
36 #define RD(ir) (armr.r[((ir>>12)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
37 #define RDn(ir) ((ir>>12)&0x0F)
38 #define RS(ir) (armr.r[((ir>>8)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
39 #define RM(ir) (armr.r[(ir&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
40 #define LRN(ir) armr.r[((ir>>16)&0x0F)]
41 #define LRD(ir) armr.r[((ir>>12)&0x0F)]
42 #define LRS(ir) armr.r[((ir>>8)&0x0F)]
43 #define LRM(ir) armr.r[(ir&0x0F)]
45 #define IMM8(ir) (ir&0xFF)
46 #define IMM12(ir) (ir&0xFFF)
47 #define SHIFTIMM(ir) ((ir>>7)0x1F)
48 #define IMMROT(ir) ((ir>>7)&1E)
49 #define SHIFT(ir) ((ir>>4)&0x07)
50 #define DISP24(ir) ((ir&0x00FFFFFF))
52 static uint32_t arm_get_shift_operand( uint32_t ir )
54 uint32_t operand, tmp;
55 if( IFLAG(ir) == 0 ) {
58 case 0: /* (Rm << imm) */
59 operand = operand << SHIFTIMM(ir);
61 case 1: /* (Rm << Rs) */
63 if( tmp > 31 ) operand = 0;
64 else operand = operand << tmp;
66 case 2: /* (Rm >> imm) */
67 operand = operand >> SHIFTIMM(ir);
69 case 3: /* (Rm >> Rs) */
71 if( tmp > 31 ) operand = 0;
72 else operand = operand >> ir;
74 case 4: /* (Rm >>> imm) */
76 if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
77 else operand = ((int32_t)operand) >> tmp;
79 case 5: /* (Rm >>> Rs) */
81 if( tmp > 31 ) operand = ((int32_t)operand) >> 31;
82 else operand = ((int32_t)operand) >> tmp;
86 if( tmp == 0 ) /* RRX aka rotate with carry */
87 operand = (operand >> 1) | (arm4.c<<31);
89 operand = ROTATE_RIGHT_LONG(operand,tmp);
93 operand = ROTATE_RIGHT_LONG(operand,tmp);
99 operand = ROTATE_RIGHT_LONG(operand, tmp);
105 * Compute the "shift operand" of the instruction for the data processing
106 * instructions. This variant also sets armr.shift_c (carry result for shifter)
107 * Reason for the variants is that most cases don't actually need the shift_c.
109 static uint32_t arm_get_shift_operand_s( uint32_t ir )
111 uint32_t operand, tmp;
112 if( IFLAG(ir) == 0 ) {
115 case 0: /* (Rm << imm) */
117 if( tmp == 0 ) { /* Rm */
118 armr.shift_c = armr.c;
119 } else { /* Rm << imm */
120 armr.shift_c = (operand >> (32-tmp)) & 0x01;
121 operand = operand << tmp;
124 case 1: /* (Rm << Rs) */
127 armr.shift_c = armr.c;
130 armr.shift_c = (operand >> (32-tmp)) & 0x01;
131 else armr.shift_c = 0;
133 operand = operand << tmp;
137 case 2: /* (Rm >> imm) */
140 armr.shift_c = operand >> 31;
143 armr.shift_c = (operand >> (tmp-1)) & 0x01;
144 operand = RM(ir) >> tmp;
147 case 3: /* (Rm >> Rs) */
150 armr.shift_c = armr.c;
153 armr.shift_c = (operand >> (tmp-1))&0x01;
154 else armr.shift_c = 0;
156 operand = operand >> tmp;
160 case 4: /* (Rm >>> imm) */
163 armr.shift_c = operand >> 31;
164 operand = -armr.shift_c;
166 armr.shift_c = (operand >> (tmp-1)) & 0x01;
167 operand = ((int32_t)operand) >> tmp;
170 case 5: /* (Rm >>> Rs) */
173 armr.shift_c = armr.c;
176 armr.shift_c = (operand >> (tmp-1))&0x01;
177 operand = ((int32_t)operand) >> tmp;
179 armr.shift_c = operand >> 31;
180 operand = ((int32_t)operand) >> 31;
186 if( tmp == 0 ) { /* RRX aka rotate with carry */
187 armr.shift_c = operand&0x01;
188 operand = (operand >> 1) | (arm4.c<<31);
190 armr.shift_c = operand>>(tmp-1);
191 operand = ROTATE_RIGHT_LONG(operand,tmp);
197 armr.shift_c = armr.c;
201 armr.shift_c = operand>>31;
203 armr.shift_c = (operand>>(tmp-1))&0x1;
204 operand = ROTATE_RIGHT_LONG(operand,tmp);
213 armr.shift_c = armr.c;
215 operand = ROTATE_RIGHT_LONG(operand, tmp);
216 armr.shift_c = operand>>31;
223 * Another variant of the shifter code for index-based memory addressing.
224 * Distinguished by the fact that it doesn't support register shifts, and
225 * ignores the I flag (WTF do the load/store instructions use the I flag to
226 * mean the _exact opposite_ of what it means for the data processing
229 static uint32_t arm_get_address_index( uint32_t ir )
231 uint32_t operand = RM(ir);
233 case 0: /* (Rm << imm) */
234 operand = operand << SHIFTIMM(ir);
236 case 2: /* (Rm >> imm) */
237 operand = operand >> SHIFTIMM(ir);
239 case 4: /* (Rm >>> imm) */
241 if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
242 else operand = ((int32_t)operand) >> tmp;
246 if( tmp == 0 ) /* RRX aka rotate with carry */
247 operand = (operand >> 1) | (arm4.c<<31);
249 operand = ROTATE_RIGHT_LONG(operand,tmp);
256 static uint32_t arm_get_address_operand( uint32_t ir )
261 switch( (ir>>21)&0x1D ) {
262 case 0: /* Rn -= imm offset (post-indexed) [5.2.8 A5-28] */
265 RN(ir) = addr - IMM12(ir);
267 case 4: /* Rn += imm offsett (post-indexed) [5.2.8 A5-28] */
270 RN(ir) = addr + IMM12(ir);
272 case 8: /* Rn - imm offset [5.2.2 A5-20] */
273 addr = RN(ir) - IMM12(ir);
275 case 9: /* Rn -= imm offset (pre-indexed) [5.2.5 A5-24] */
276 addr = RN(ir) - IMM12(ir);
279 case 12: /* Rn + imm offset [5.2.2 A5-20] */
280 addr = RN(ir) + IMM12(ir);
282 case 13: /* Rn += imm offset [5.2.5 A5-24 ] */
283 addr = RN(ir) + IMM12(ir);
286 case 16: /* Rn -= Rm (post-indexed) [5.2.10 A5-32 ] */
289 RN(ir) = addr - arm_get_address_index(ir);
291 case 20: /* Rn += Rm (post-indexed) [5.2.10 A5-32 ] */
294 RN(ir) = addr - arm_get_address_index(ir);
296 case 24: /* Rn - Rm [5.2.4 A5-23] */
297 addr = RN(ir) - arm_get_address_index(ir);
299 case 25: /* RN -= Rm (pre-indexed) [5.2.7 A5-26] */
300 addr = RN(ir) - arm_get_address_index(ir);
303 case 28: /* Rn + Rm [5.2.4 A5-23] */
304 addr = RN(ir) + arm_get_address_index(ir);
306 case 29: /* RN += Rm (pre-indexed) [5.2.7 A5-26] */
307 addr = RN(ir) + arm_get_address_index(ir);
311 UNIMP(ir); /* Unreachable */
316 void arm_execute_instruction( void )
319 uint32_t ir = MEM_READ_LONG(PC);
320 uint32_t operand, operand2, tmp, armr.shift_c;
351 cond = armr.c && !armr.z;
354 cond = (!armr.c) || armr.z;
357 cond = (armr.n == armr.v);
360 cond = (armr.n != armr.v);
363 cond = (!armr.z) && (armr.n == armr.v);
366 cond = armr.z || (armr.n != armr.v);
378 if( (ir & 0x0D900000) == 0x01000000 ) {
379 /* Instructions that aren't actual data processing */
380 switch( ir & 0x0FF000F0 ) {
381 case 0x01200010: /* BX */
383 case 0x01000000: /* MRS Rd, CPSR */
385 case 0x01400000: /* MRS Rd, SPSR */
387 case 0x01200000: /* MSR CPSR, Rd */
389 case 0x01600000: /* MSR SPSR, Rd */
391 case 0x03200000: /* MSR CPSR, imm */
393 case 0x03600000: /* MSR SPSR, imm */
398 } else if( (ir & 0x0E000090) == 0x00000090 ) {
399 /* Neither are these */
400 switch( (ir>>5)&0x03 ) {
402 /* Arithmetic extension area */
418 case 11: /* UMLALS */
422 case 13: /* SMULLS */
426 case 15: /* SMLALS */
459 /* Data processing */
462 case 0: /* AND Rd, Rn, operand */
463 RD(ir) = RN(ir) & arm_get_shift_operand(ir);
465 case 1: /* ANDS Rd, Rn, operand */
466 operand = arm_get_shift_operand_s(ir) & RN(ir);
468 if( RDn(ir) == 15 ) {
471 armr.n = operand>>31;
472 armr.z = (operand == 0);
473 armr.c = armr.shift_c;
476 case 2: /* EOR Rd, Rn, operand */
477 RD(ir) = RN(ir) ^ arm_get_shift_operand(ir);
479 case 3: /* EORS Rd, Rn, operand */
480 operand = arm_get_shift_operand_s(ir) ^ RN(ir);
482 if( RDn(ir) == 15 ) {
485 armr.n = operand>>31;
486 armr.z = (operand == 0);
487 armr.c = armr.shift_c;
490 case 4: /* SUB Rd, Rn, operand */
491 RD(ir) = RN(ir) - arm_get_shift_operand(ir);
493 case 5: /* SUBS Rd, Rn, operand */
495 operand2 = arm_get_shift_operand(ir)
496 tmp = operand - operand2;
498 if( RDn(ir) == 15 ) {
503 armr.c = IS_NOTBORROW(tmp,operand,operand2);
504 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
507 case 6: /* RSB Rd, operand, Rn */
508 RD(ir) = arm_get_shift_operand(ir) - RN(ir);
510 case 7: /* RSBS Rd, operand, Rn */
511 operand = arm_get_shift_operand(ir);
513 tmp = operand - operand2;
515 if( RDn(ir) == 15 ) {
520 armr.c = IS_NOTBORROW(tmp,operand,operand2);
521 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
524 case 8: /* ADD Rd, Rn, operand */
525 RD(ir) = RN(ir) + arm_get_shift_operand(ir);
527 case 9: /* ADDS Rd, Rn, operand */
528 operand = arm_get_shift_operand(ir);
530 tmp = operand + operand2
532 if( RDn(ir) == 15 ) {
537 armr.c = IS_CARRY(tmp,operand,operand2);
538 armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
548 case 17: /* TST Rn, operand */
549 operand = arm_get_shift_operand_s(ir) & RN(ir);
550 armr.n = operand>>31;
551 armr.z = (operand == 0);
552 armr.c = armr.shift_c;
554 case 19: /* TEQ Rn, operand */
555 operand = arm_get_shift_operand_s(ir) ^ RN(ir);
556 armr.n = operand>>31;
557 armr.z = (operand == 0);
558 armr.c = armr.shift_c;
560 case 21: /* CMP Rn, operand */
562 operand2 = arm_get_shift_operand(ir)
563 tmp = operand - operand2;
566 armr.c = IS_NOTBORROW(tmp,operand,operand2);
567 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
569 case 23: /* CMN Rn, operand */
571 operand2 = arm_get_shift_operand(ir)
572 tmp = operand + operand2;
575 armr.c = IS_CARRY(tmp,operand,operand2);
576 armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
578 case 24: /* ORR Rd, Rn, operand */
579 RD(ir) = RN(ir) | arm_get_shift_operand(ir);
581 case 25: /* ORRS Rd, Rn, operand */
582 operand = arm_get_shift_operand_s(ir) | RN(ir);
584 if( RDn(ir) == 15 ) {
587 armr.n = operand>>31;
588 armr.z = (operand == 0);
589 armr.c = armr.shift_c;
592 case 26: /* MOV Rd, operand */
593 RD(ir) = arm_get_shift_operand(ir);
595 case 27: /* MOVS Rd, operand */
596 operand = arm_get_shift_operand_s(ir);
598 if( RDn(ir) == 15 ) {
601 armr.n = operand>>31;
602 armr.z = (operand == 0);
603 armr.c = armr.shift_c;
606 case 28: /* BIC Rd, Rn, operand */
607 RD(ir) = RN(ir) & (~arm_get_shift_operand(ir));
609 case 29: /* BICS Rd, Rn, operand */
610 operand = RN(ir) & (~arm_get_shift_operand_s(ir));
612 if( RDn(ir) == 15 ) {
615 armr.n = operand>>31;
616 armr.z = (operand == 0);
617 armr.c = armr.shift_c;
620 case 30: /* MVN Rd, operand */
621 RD(ir) = ~arm_get_shift_operand(ir);
623 case 31: /* MVNS Rd, operand */
624 operand = ~arm_get_shift_operand_s(ir);
626 if( RDn(ir) == 15 ) {
629 armr.n = operand>>31;
630 armr.z = (operand == 0);
631 armr.c = armr.shift_c;
639 case 1: /* Load/store */
641 case 2: /* Load/store multiple, branch*/
.