2 #include "aica/armcore.h"
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)
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)&0x1E)
49 #define SHIFT(ir) ((ir>>4)&0x07)
50 #define DISP24(ir) ((ir&0x00FFFFFF))
51 #define UNDEF(ir) do{ ERROR( "Raising exception on undefined instruction at %08x, opcode = %04x", PC, ir ); return; } while(0)
52 #define UNIMP(ir) do{ ERROR( "Halted on unimplemented instruction at %08x, opcode = %04x", PC, ir ); return; }while(0)
55 static uint32_t arm_get_shift_operand( uint32_t ir )
57 uint32_t operand, tmp;
58 if( IFLAG(ir) == 0 ) {
61 case 0: /* (Rm << imm) */
62 operand = operand << SHIFTIMM(ir);
64 case 1: /* (Rm << Rs) */
66 if( tmp > 31 ) operand = 0;
67 else operand = operand << tmp;
69 case 2: /* (Rm >> imm) */
70 operand = operand >> SHIFTIMM(ir);
72 case 3: /* (Rm >> Rs) */
74 if( tmp > 31 ) operand = 0;
75 else operand = operand >> ir;
77 case 4: /* (Rm >>> imm) */
79 if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
80 else operand = ((int32_t)operand) >> tmp;
82 case 5: /* (Rm >>> Rs) */
84 if( tmp > 31 ) operand = ((int32_t)operand) >> 31;
85 else operand = ((int32_t)operand) >> tmp;
89 if( tmp == 0 ) /* RRX aka rotate with carry */
90 operand = (operand >> 1) | (armr.c<<31);
92 operand = ROTATE_RIGHT_LONG(operand,tmp);
96 operand = ROTATE_RIGHT_LONG(operand,tmp);
102 operand = ROTATE_RIGHT_LONG(operand, tmp);
108 * Compute the "shift operand" of the instruction for the data processing
109 * instructions. This variant also sets armr.shift_c (carry result for shifter)
110 * Reason for the variants is that most cases don't actually need the shift_c.
112 static uint32_t arm_get_shift_operand_s( uint32_t ir )
114 uint32_t operand, tmp;
115 if( IFLAG(ir) == 0 ) {
118 case 0: /* (Rm << imm) */
120 if( tmp == 0 ) { /* Rm */
121 armr.shift_c = armr.c;
122 } else { /* Rm << imm */
123 armr.shift_c = (operand >> (32-tmp)) & 0x01;
124 operand = operand << tmp;
127 case 1: /* (Rm << Rs) */
130 armr.shift_c = armr.c;
133 armr.shift_c = (operand >> (32-tmp)) & 0x01;
134 else armr.shift_c = 0;
136 operand = operand << tmp;
140 case 2: /* (Rm >> imm) */
143 armr.shift_c = operand >> 31;
146 armr.shift_c = (operand >> (tmp-1)) & 0x01;
147 operand = RM(ir) >> tmp;
150 case 3: /* (Rm >> Rs) */
153 armr.shift_c = armr.c;
156 armr.shift_c = (operand >> (tmp-1))&0x01;
157 else armr.shift_c = 0;
159 operand = operand >> tmp;
163 case 4: /* (Rm >>> imm) */
166 armr.shift_c = operand >> 31;
167 operand = -armr.shift_c;
169 armr.shift_c = (operand >> (tmp-1)) & 0x01;
170 operand = ((int32_t)operand) >> tmp;
173 case 5: /* (Rm >>> Rs) */
176 armr.shift_c = armr.c;
179 armr.shift_c = (operand >> (tmp-1))&0x01;
180 operand = ((int32_t)operand) >> tmp;
182 armr.shift_c = operand >> 31;
183 operand = ((int32_t)operand) >> 31;
189 if( tmp == 0 ) { /* RRX aka rotate with carry */
190 armr.shift_c = operand&0x01;
191 operand = (operand >> 1) | (armr.c<<31);
193 armr.shift_c = operand>>(tmp-1);
194 operand = ROTATE_RIGHT_LONG(operand,tmp);
200 armr.shift_c = armr.c;
204 armr.shift_c = operand>>31;
206 armr.shift_c = (operand>>(tmp-1))&0x1;
207 operand = ROTATE_RIGHT_LONG(operand,tmp);
216 armr.shift_c = armr.c;
218 operand = ROTATE_RIGHT_LONG(operand, tmp);
219 armr.shift_c = operand>>31;
226 * Another variant of the shifter code for index-based memory addressing.
227 * Distinguished by the fact that it doesn't support register shifts, and
228 * ignores the I flag (WTF do the load/store instructions use the I flag to
229 * mean the _exact opposite_ of what it means for the data processing
232 static uint32_t arm_get_address_index( uint32_t ir )
234 uint32_t operand = RM(ir);
238 case 0: /* (Rm << imm) */
239 operand = operand << SHIFTIMM(ir);
241 case 2: /* (Rm >> imm) */
242 operand = operand >> SHIFTIMM(ir);
244 case 4: /* (Rm >>> imm) */
246 if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
247 else operand = ((int32_t)operand) >> tmp;
251 if( tmp == 0 ) /* RRX aka rotate with carry */
252 operand = (operand >> 1) | (armr.c<<31);
254 operand = ROTATE_RIGHT_LONG(operand,tmp);
261 static uint32_t arm_get_address_operand( uint32_t ir )
266 switch( (ir>>21)&0x1D ) {
267 case 0: /* Rn -= imm offset (post-indexed) [5.2.8 A5-28] */
270 LRN(ir) = addr - IMM12(ir);
272 case 4: /* Rn += imm offsett (post-indexed) [5.2.8 A5-28] */
275 LRN(ir) = addr + IMM12(ir);
277 case 8: /* Rn - imm offset [5.2.2 A5-20] */
278 addr = RN(ir) - IMM12(ir);
280 case 9: /* Rn -= imm offset (pre-indexed) [5.2.5 A5-24] */
281 addr = RN(ir) - IMM12(ir);
284 case 12: /* Rn + imm offset [5.2.2 A5-20] */
285 addr = RN(ir) + IMM12(ir);
287 case 13: /* Rn += imm offset [5.2.5 A5-24 ] */
288 addr = RN(ir) + IMM12(ir);
291 case 16: /* Rn -= Rm (post-indexed) [5.2.10 A5-32 ] */
294 LRN(ir) = addr - arm_get_address_index(ir);
296 case 20: /* Rn += Rm (post-indexed) [5.2.10 A5-32 ] */
299 LRN(ir) = addr - arm_get_address_index(ir);
301 case 24: /* Rn - Rm [5.2.4 A5-23] */
302 addr = RN(ir) - arm_get_address_index(ir);
304 case 25: /* RN -= Rm (pre-indexed) [5.2.7 A5-26] */
305 addr = RN(ir) - arm_get_address_index(ir);
308 case 28: /* Rn + Rm [5.2.4 A5-23] */
309 addr = RN(ir) + arm_get_address_index(ir);
311 case 29: /* RN += Rm (pre-indexed) [5.2.7 A5-26] */
312 addr = RN(ir) + arm_get_address_index(ir);
316 UNIMP(ir); /* Unreachable */
321 void arm_execute_instruction( void )
324 uint32_t ir = MEM_READ_LONG(pc);
325 uint32_t operand, operand2, tmp, cond;
356 cond = armr.c && !armr.z;
359 cond = (!armr.c) || armr.z;
362 cond = (armr.n == armr.v);
365 cond = (armr.n != armr.v);
368 cond = (!armr.z) && (armr.n == armr.v);
371 cond = armr.z || (armr.n != armr.v);
383 if( (ir & 0x0D900000) == 0x01000000 ) {
384 /* Instructions that aren't actual data processing */
385 switch( ir & 0x0FF000F0 ) {
386 case 0x01200010: /* BX */
388 case 0x01000000: /* MRS Rd, CPSR */
390 case 0x01400000: /* MRS Rd, SPSR */
392 case 0x01200000: /* MSR CPSR, Rd */
394 case 0x01600000: /* MSR SPSR, Rd */
396 case 0x03200000: /* MSR CPSR, imm */
398 case 0x03600000: /* MSR SPSR, imm */
403 } else if( (ir & 0x0E000090) == 0x00000090 ) {
404 /* Neither are these */
405 switch( (ir>>5)&0x03 ) {
407 /* Arithmetic extension area */
423 case 11: /* UMLALS */
427 case 13: /* SMULLS */
431 case 15: /* SMLALS */
464 /* Data processing */
467 case 0: /* AND Rd, Rn, operand */
468 LRD(ir) = RN(ir) & arm_get_shift_operand(ir);
470 case 1: /* ANDS Rd, Rn, operand */
471 operand = arm_get_shift_operand_s(ir) & RN(ir);
473 if( RDn(ir) == 15 ) {
476 armr.n = operand>>31;
477 armr.z = (operand == 0);
478 armr.c = armr.shift_c;
481 case 2: /* EOR Rd, Rn, operand */
482 LRD(ir) = RN(ir) ^ arm_get_shift_operand(ir);
484 case 3: /* EORS Rd, Rn, operand */
485 operand = arm_get_shift_operand_s(ir) ^ RN(ir);
487 if( RDn(ir) == 15 ) {
490 armr.n = operand>>31;
491 armr.z = (operand == 0);
492 armr.c = armr.shift_c;
495 case 4: /* SUB Rd, Rn, operand */
496 LRD(ir) = RN(ir) - arm_get_shift_operand(ir);
498 case 5: /* SUBS Rd, Rn, operand */
500 operand2 = arm_get_shift_operand(ir);
501 tmp = operand - operand2;
503 if( RDn(ir) == 15 ) {
508 armr.c = IS_NOTBORROW(tmp,operand,operand2);
509 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
512 case 6: /* RSB Rd, operand, Rn */
513 LRD(ir) = arm_get_shift_operand(ir) - RN(ir);
515 case 7: /* RSBS Rd, operand, Rn */
516 operand = arm_get_shift_operand(ir);
518 tmp = operand - operand2;
520 if( RDn(ir) == 15 ) {
525 armr.c = IS_NOTBORROW(tmp,operand,operand2);
526 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
529 case 8: /* ADD Rd, Rn, operand */
530 LRD(ir) = RN(ir) + arm_get_shift_operand(ir);
532 case 9: /* ADDS Rd, Rn, operand */
533 operand = arm_get_shift_operand(ir);
535 tmp = operand + operand2;
537 if( RDn(ir) == 15 ) {
542 armr.c = IS_CARRY(tmp,operand,operand2);
543 armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
553 case 17: /* TST Rn, operand */
554 operand = arm_get_shift_operand_s(ir) & RN(ir);
555 armr.n = operand>>31;
556 armr.z = (operand == 0);
557 armr.c = armr.shift_c;
559 case 19: /* TEQ Rn, operand */
560 operand = arm_get_shift_operand_s(ir) ^ RN(ir);
561 armr.n = operand>>31;
562 armr.z = (operand == 0);
563 armr.c = armr.shift_c;
565 case 21: /* CMP Rn, operand */
567 operand2 = arm_get_shift_operand(ir);
568 tmp = operand - operand2;
571 armr.c = IS_NOTBORROW(tmp,operand,operand2);
572 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
574 case 23: /* CMN Rn, operand */
576 operand2 = arm_get_shift_operand(ir);
577 tmp = operand + operand2;
580 armr.c = IS_CARRY(tmp,operand,operand2);
581 armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
583 case 24: /* ORR Rd, Rn, operand */
584 LRD(ir) = RN(ir) | arm_get_shift_operand(ir);
586 case 25: /* ORRS Rd, Rn, operand */
587 operand = arm_get_shift_operand_s(ir) | RN(ir);
589 if( RDn(ir) == 15 ) {
592 armr.n = operand>>31;
593 armr.z = (operand == 0);
594 armr.c = armr.shift_c;
597 case 26: /* MOV Rd, operand */
598 LRD(ir) = arm_get_shift_operand(ir);
600 case 27: /* MOVS Rd, operand */
601 operand = arm_get_shift_operand_s(ir);
603 if( RDn(ir) == 15 ) {
606 armr.n = operand>>31;
607 armr.z = (operand == 0);
608 armr.c = armr.shift_c;
611 case 28: /* BIC Rd, Rn, operand */
612 LRD(ir) = RN(ir) & (~arm_get_shift_operand(ir));
614 case 29: /* BICS Rd, Rn, operand */
615 operand = RN(ir) & (~arm_get_shift_operand_s(ir));
617 if( RDn(ir) == 15 ) {
620 armr.n = operand>>31;
621 armr.z = (operand == 0);
622 armr.c = armr.shift_c;
625 case 30: /* MVN Rd, operand */
626 LRD(ir) = ~arm_get_shift_operand(ir);
628 case 31: /* MVNS Rd, operand */
629 operand = ~arm_get_shift_operand_s(ir);
631 if( RDn(ir) == 15 ) {
634 armr.n = operand>>31;
635 armr.z = (operand == 0);
636 armr.c = armr.shift_c;
644 case 1: /* Load/store */
646 case 2: /* Load/store multiple, branch*/
.