2 * $Id: armcore.c,v 1.5 2005-12-25 05:57:00 nkeynes Exp $
4 * ARM7TDMI CPU emulation core.
6 * Copyright (c) 2005 Nathan Keynes.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
19 #include "aica/armcore.h"
21 struct arm_registers armr;
23 /* NB: The arm has a different memory map, but for the meantime... */
24 /* Page references are as per ARM DDI 0100E (June 2000) */
26 #define MEM_READ_BYTE( addr ) arm_read_byte(addr)
27 #define MEM_READ_WORD( addr ) arm_read_word(addr)
28 #define MEM_READ_LONG( addr ) arm_read_long(addr)
29 #define MEM_WRITE_BYTE( addr, val ) arm_write_byte(addr, val)
30 #define MEM_WRITE_WORD( addr, val ) arm_write_word(addr, val)
31 #define MEM_WRITE_LONG( addr, val ) arm_write_long(addr, val)
34 #define IS_NOTBORROW( result, op1, op2 ) (op2 > op1 ? 0 : 1)
35 #define IS_CARRY( result, op1, op2 ) (result < op1 ? 1 : 0)
36 #define IS_SUBOVERFLOW( result, op1, op2 ) (((op1^op2) & (result^op1)) >> 31)
37 #define IS_ADDOVERFLOW( result, op1, op2 ) (((op1&op2) & (result^op1)) >> 31)
41 /* Instruction fields */
42 #define COND(ir) (ir>>28)
43 #define GRP(ir) ((ir>>26)&0x03)
44 #define OPCODE(ir) ((ir>>20)&0x1F)
45 #define IFLAG(ir) (ir&0x02000000)
46 #define SFLAG(ir) (ir&0x00100000)
47 #define PFLAG(ir) (ir&0x01000000)
48 #define UFLAG(ir) (ir&0x00800000)
49 #define BFLAG(ir) (ir&0x00400000)
50 #define WFLAG(ir) (IR&0x00200000)
51 #define LFLAG(ir) SFLAG(ir)
52 #define RN(ir) (armr.r[((ir>>16)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
53 #define RD(ir) (armr.r[((ir>>12)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
54 #define RDn(ir) ((ir>>12)&0x0F)
55 #define RS(ir) (armr.r[((ir>>8)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
56 #define RM(ir) (armr.r[(ir&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
57 #define LRN(ir) armr.r[((ir>>16)&0x0F)]
58 #define LRD(ir) armr.r[((ir>>12)&0x0F)]
59 #define LRS(ir) armr.r[((ir>>8)&0x0F)]
60 #define LRM(ir) armr.r[(ir&0x0F)]
62 #define IMM8(ir) (ir&0xFF)
63 #define IMM12(ir) (ir&0xFFF)
64 #define SHIFTIMM(ir) ((ir>>7)&0x1F)
65 #define IMMROT(ir) ((ir>>7)&0x1E)
66 #define SHIFT(ir) ((ir>>4)&0x07)
67 #define DISP24(ir) ((ir&0x00FFFFFF))
68 #define UNDEF(ir) do{ ERROR( "Raising exception on undefined instruction at %08x, opcode = %04x", PC, ir ); return TRUE; } while(0)
69 #define UNIMP(ir) do{ ERROR( "Halted on unimplemented instruction at %08x, opcode = %04x", PC, ir ); return FALSE; }while(0)
71 void arm_restore_cpsr()
76 static uint32_t arm_get_shift_operand( uint32_t ir )
78 uint32_t operand, tmp;
79 if( IFLAG(ir) == 0 ) {
82 case 0: /* (Rm << imm) */
83 operand = operand << SHIFTIMM(ir);
85 case 1: /* (Rm << Rs) */
87 if( tmp > 31 ) operand = 0;
88 else operand = operand << tmp;
90 case 2: /* (Rm >> imm) */
91 operand = operand >> SHIFTIMM(ir);
93 case 3: /* (Rm >> Rs) */
95 if( tmp > 31 ) operand = 0;
96 else operand = operand >> ir;
98 case 4: /* (Rm >>> imm) */
100 if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
101 else operand = ((int32_t)operand) >> tmp;
103 case 5: /* (Rm >>> Rs) */
105 if( tmp > 31 ) operand = ((int32_t)operand) >> 31;
106 else operand = ((int32_t)operand) >> tmp;
110 if( tmp == 0 ) /* RRX aka rotate with carry */
111 operand = (operand >> 1) | (armr.c<<31);
113 operand = ROTATE_RIGHT_LONG(operand,tmp);
117 operand = ROTATE_RIGHT_LONG(operand,tmp);
123 operand = ROTATE_RIGHT_LONG(operand, tmp);
129 * Compute the "shift operand" of the instruction for the data processing
130 * instructions. This variant also sets armr.shift_c (carry result for shifter)
131 * Reason for the variants is that most cases don't actually need the shift_c.
133 static uint32_t arm_get_shift_operand_s( uint32_t ir )
135 uint32_t operand, tmp;
136 if( IFLAG(ir) == 0 ) {
139 case 0: /* (Rm << imm) */
141 if( tmp == 0 ) { /* Rm */
142 armr.shift_c = armr.c;
143 } else { /* Rm << imm */
144 armr.shift_c = (operand >> (32-tmp)) & 0x01;
145 operand = operand << tmp;
148 case 1: /* (Rm << Rs) */
151 armr.shift_c = armr.c;
154 armr.shift_c = (operand >> (32-tmp)) & 0x01;
155 else armr.shift_c = 0;
157 operand = operand << tmp;
161 case 2: /* (Rm >> imm) */
164 armr.shift_c = operand >> 31;
167 armr.shift_c = (operand >> (tmp-1)) & 0x01;
168 operand = RM(ir) >> tmp;
171 case 3: /* (Rm >> Rs) */
174 armr.shift_c = armr.c;
177 armr.shift_c = (operand >> (tmp-1))&0x01;
178 else armr.shift_c = 0;
180 operand = operand >> tmp;
184 case 4: /* (Rm >>> imm) */
187 armr.shift_c = operand >> 31;
188 operand = -armr.shift_c;
190 armr.shift_c = (operand >> (tmp-1)) & 0x01;
191 operand = ((int32_t)operand) >> tmp;
194 case 5: /* (Rm >>> Rs) */
197 armr.shift_c = armr.c;
200 armr.shift_c = (operand >> (tmp-1))&0x01;
201 operand = ((int32_t)operand) >> tmp;
203 armr.shift_c = operand >> 31;
204 operand = ((int32_t)operand) >> 31;
210 if( tmp == 0 ) { /* RRX aka rotate with carry */
211 armr.shift_c = operand&0x01;
212 operand = (operand >> 1) | (armr.c<<31);
214 armr.shift_c = operand>>(tmp-1);
215 operand = ROTATE_RIGHT_LONG(operand,tmp);
221 armr.shift_c = armr.c;
225 armr.shift_c = operand>>31;
227 armr.shift_c = (operand>>(tmp-1))&0x1;
228 operand = ROTATE_RIGHT_LONG(operand,tmp);
237 armr.shift_c = armr.c;
239 operand = ROTATE_RIGHT_LONG(operand, tmp);
240 armr.shift_c = operand>>31;
247 * Another variant of the shifter code for index-based memory addressing.
248 * Distinguished by the fact that it doesn't support register shifts, and
249 * ignores the I flag (WTF do the load/store instructions use the I flag to
250 * mean the _exact opposite_ of what it means for the data processing
253 static uint32_t arm_get_address_index( uint32_t ir )
255 uint32_t operand = RM(ir);
259 case 0: /* (Rm << imm) */
260 operand = operand << SHIFTIMM(ir);
262 case 2: /* (Rm >> imm) */
263 operand = operand >> SHIFTIMM(ir);
265 case 4: /* (Rm >>> imm) */
267 if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
268 else operand = ((int32_t)operand) >> tmp;
272 if( tmp == 0 ) /* RRX aka rotate with carry */
273 operand = (operand >> 1) | (armr.c<<31);
275 operand = ROTATE_RIGHT_LONG(operand,tmp);
282 static uint32_t arm_get_address_operand( uint32_t ir )
287 switch( (ir>>21)&0x1D ) {
288 case 0: /* Rn -= imm offset (post-indexed) [5.2.8 A5-28] */
291 LRN(ir) = addr - IMM12(ir);
293 case 4: /* Rn += imm offsett (post-indexed) [5.2.8 A5-28] */
296 LRN(ir) = addr + IMM12(ir);
298 case 8: /* Rn - imm offset [5.2.2 A5-20] */
299 addr = RN(ir) - IMM12(ir);
301 case 9: /* Rn -= imm offset (pre-indexed) [5.2.5 A5-24] */
302 addr = RN(ir) - IMM12(ir);
305 case 12: /* Rn + imm offset [5.2.2 A5-20] */
306 addr = RN(ir) + IMM12(ir);
308 case 13: /* Rn += imm offset [5.2.5 A5-24 ] */
309 addr = RN(ir) + IMM12(ir);
312 case 16: /* Rn -= Rm (post-indexed) [5.2.10 A5-32 ] */
315 LRN(ir) = addr - arm_get_address_index(ir);
317 case 20: /* Rn += Rm (post-indexed) [5.2.10 A5-32 ] */
320 LRN(ir) = addr - arm_get_address_index(ir);
322 case 24: /* Rn - Rm [5.2.4 A5-23] */
323 addr = RN(ir) - arm_get_address_index(ir);
325 case 25: /* RN -= Rm (pre-indexed) [5.2.7 A5-26] */
326 addr = RN(ir) - arm_get_address_index(ir);
329 case 28: /* Rn + Rm [5.2.4 A5-23] */
330 addr = RN(ir) + arm_get_address_index(ir);
332 case 29: /* RN += Rm (pre-indexed) [5.2.7 A5-26] */
333 addr = RN(ir) + arm_get_address_index(ir);
337 UNIMP(ir); /* Unreachable */
342 gboolean arm_execute_instruction( void )
345 uint32_t ir = MEM_READ_LONG(pc);
346 uint32_t operand, operand2, tmp, cond;
377 cond = armr.c && !armr.z;
380 cond = (!armr.c) || armr.z;
383 cond = (armr.n == armr.v);
386 cond = (armr.n != armr.v);
389 cond = (!armr.z) && (armr.n == armr.v);
392 cond = armr.z || (armr.n != armr.v);
404 if( (ir & 0x0D900000) == 0x01000000 ) {
405 /* Instructions that aren't actual data processing */
406 switch( ir & 0x0FF000F0 ) {
407 case 0x01200010: /* BX */
409 case 0x01000000: /* MRS Rd, CPSR */
411 case 0x01400000: /* MRS Rd, SPSR */
413 case 0x01200000: /* MSR CPSR, Rd */
415 case 0x01600000: /* MSR SPSR, Rd */
417 case 0x03200000: /* MSR CPSR, imm */
419 case 0x03600000: /* MSR SPSR, imm */
424 } else if( (ir & 0x0E000090) == 0x00000090 ) {
425 /* Neither are these */
426 switch( (ir>>5)&0x03 ) {
428 /* Arithmetic extension area */
444 case 11: /* UMLALS */
448 case 13: /* SMULLS */
452 case 15: /* SMLALS */
485 /* Data processing */
488 case 0: /* AND Rd, Rn, operand */
489 LRD(ir) = RN(ir) & arm_get_shift_operand(ir);
491 case 1: /* ANDS Rd, Rn, operand */
492 operand = arm_get_shift_operand_s(ir) & RN(ir);
494 if( RDn(ir) == 15 ) {
497 armr.n = operand>>31;
498 armr.z = (operand == 0);
499 armr.c = armr.shift_c;
502 case 2: /* EOR Rd, Rn, operand */
503 LRD(ir) = RN(ir) ^ arm_get_shift_operand(ir);
505 case 3: /* EORS Rd, Rn, operand */
506 operand = arm_get_shift_operand_s(ir) ^ RN(ir);
508 if( RDn(ir) == 15 ) {
511 armr.n = operand>>31;
512 armr.z = (operand == 0);
513 armr.c = armr.shift_c;
516 case 4: /* SUB Rd, Rn, operand */
517 LRD(ir) = RN(ir) - arm_get_shift_operand(ir);
519 case 5: /* SUBS Rd, Rn, operand */
521 operand2 = arm_get_shift_operand(ir);
522 tmp = operand - operand2;
524 if( RDn(ir) == 15 ) {
529 armr.c = IS_NOTBORROW(tmp,operand,operand2);
530 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
533 case 6: /* RSB Rd, operand, Rn */
534 LRD(ir) = arm_get_shift_operand(ir) - RN(ir);
536 case 7: /* RSBS Rd, operand, Rn */
537 operand = arm_get_shift_operand(ir);
539 tmp = operand - operand2;
541 if( RDn(ir) == 15 ) {
546 armr.c = IS_NOTBORROW(tmp,operand,operand2);
547 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
550 case 8: /* ADD Rd, Rn, operand */
551 LRD(ir) = RN(ir) + arm_get_shift_operand(ir);
553 case 9: /* ADDS Rd, Rn, operand */
554 operand = arm_get_shift_operand(ir);
556 tmp = operand + operand2;
558 if( RDn(ir) == 15 ) {
563 armr.c = IS_CARRY(tmp,operand,operand2);
564 armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
574 case 17: /* TST Rn, operand */
575 operand = arm_get_shift_operand_s(ir) & RN(ir);
576 armr.n = operand>>31;
577 armr.z = (operand == 0);
578 armr.c = armr.shift_c;
580 case 19: /* TEQ Rn, operand */
581 operand = arm_get_shift_operand_s(ir) ^ RN(ir);
582 armr.n = operand>>31;
583 armr.z = (operand == 0);
584 armr.c = armr.shift_c;
586 case 21: /* CMP Rn, operand */
588 operand2 = arm_get_shift_operand(ir);
589 tmp = operand - operand2;
592 armr.c = IS_NOTBORROW(tmp,operand,operand2);
593 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
595 case 23: /* CMN Rn, operand */
597 operand2 = arm_get_shift_operand(ir);
598 tmp = operand + operand2;
601 armr.c = IS_CARRY(tmp,operand,operand2);
602 armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
604 case 24: /* ORR Rd, Rn, operand */
605 LRD(ir) = RN(ir) | arm_get_shift_operand(ir);
607 case 25: /* ORRS Rd, Rn, operand */
608 operand = arm_get_shift_operand_s(ir) | RN(ir);
610 if( RDn(ir) == 15 ) {
613 armr.n = operand>>31;
614 armr.z = (operand == 0);
615 armr.c = armr.shift_c;
618 case 26: /* MOV Rd, operand */
619 LRD(ir) = arm_get_shift_operand(ir);
621 case 27: /* MOVS Rd, operand */
622 operand = arm_get_shift_operand_s(ir);
624 if( RDn(ir) == 15 ) {
627 armr.n = operand>>31;
628 armr.z = (operand == 0);
629 armr.c = armr.shift_c;
632 case 28: /* BIC Rd, Rn, operand */
633 LRD(ir) = RN(ir) & (~arm_get_shift_operand(ir));
635 case 29: /* BICS Rd, Rn, operand */
636 operand = RN(ir) & (~arm_get_shift_operand_s(ir));
638 if( RDn(ir) == 15 ) {
641 armr.n = operand>>31;
642 armr.z = (operand == 0);
643 armr.c = armr.shift_c;
646 case 30: /* MVN Rd, operand */
647 LRD(ir) = ~arm_get_shift_operand(ir);
649 case 31: /* MVNS Rd, operand */
650 operand = ~arm_get_shift_operand_s(ir);
652 if( RDn(ir) == 15 ) {
655 armr.n = operand>>31;
656 armr.z = (operand == 0);
657 armr.c = armr.shift_c;
665 case 1: /* Load/store */
667 case 2: /* Load/store multiple, branch*/
.