filename | src/aica/armcore.c |
changeset | 59:dceb8ef1da55 |
prev | 52:429b7fc6b843 |
next | 63:be4fec751961 |
author | nkeynes |
date | Mon Jan 02 14:49:29 2006 +0000 (16 years ago) |
permissions | -rw-r--r-- |
last change | Change LDM in accordance with the second part of 5.4.6 Fix arm_raise_exception to actually work |
view | annotate | diff | log | raw |
1 /**
2 * $Id: armcore.c,v 1.14 2006-01-02 14:49:29 nkeynes Exp $
3 *
4 * ARM7TDMI CPU emulation core.
5 *
6 * Copyright (c) 2005 Nathan Keynes.
7 *
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.
12 *
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.
17 */
19 #define MODULE aica_module
20 #include "dream.h"
21 #include "aica/armcore.h"
22 #include "mem.h"
24 #define STM_R15_OFFSET 12
26 struct arm_registers armr;
28 void arm_set_mode( int mode );
30 uint32_t arm_exceptions[][2] = {{ MODE_SVC, 0x00000000 },
31 { MODE_UND, 0x00000004 },
32 { MODE_SVC, 0x00000008 },
33 { MODE_ABT, 0x0000000C },
34 { MODE_ABT, 0x00000010 },
35 { MODE_IRQ, 0x00000018 },
36 { MODE_FIQ, 0x0000001C } };
38 #define EXC_RESET 0
39 #define EXC_UNDEFINED 1
40 #define EXC_SOFTWARE 2
41 #define EXC_PREFETCH_ABORT 3
42 #define EXC_DATA_ABORT 4
43 #define EXC_IRQ 5
44 #define EXC_FAST_IRQ 6
46 uint32_t arm_cpu_freq = ARM_BASE_RATE;
47 uint32_t arm_cpu_period = 1000 / ARM_BASE_RATE;
50 static struct breakpoint_struct arm_breakpoints[MAX_BREAKPOINTS];
51 static int arm_breakpoint_count = 0;
53 void arm_set_breakpoint( uint32_t pc, int type )
54 {
55 arm_breakpoints[arm_breakpoint_count].address = pc;
56 arm_breakpoints[arm_breakpoint_count].type = type;
57 arm_breakpoint_count++;
58 }
60 gboolean arm_clear_breakpoint( uint32_t pc, int type )
61 {
62 int i;
64 for( i=0; i<arm_breakpoint_count; i++ ) {
65 if( arm_breakpoints[i].address == pc &&
66 arm_breakpoints[i].type == type ) {
67 while( ++i < arm_breakpoint_count ) {
68 arm_breakpoints[i-1].address = arm_breakpoints[i].address;
69 arm_breakpoints[i-1].type = arm_breakpoints[i].type;
70 }
71 arm_breakpoint_count--;
72 return TRUE;
73 }
74 }
75 return FALSE;
76 }
78 int arm_get_breakpoint( uint32_t pc )
79 {
80 int i;
81 for( i=0; i<arm_breakpoint_count; i++ ) {
82 if( arm_breakpoints[i].address == pc )
83 return arm_breakpoints[i].type;
84 }
85 return 0;
86 }
88 uint32_t arm_run_slice( uint32_t nanosecs )
89 {
90 int i;
91 uint32_t target = armr.icount + nanosecs / arm_cpu_period;
92 uint32_t start = armr.icount;
93 while( armr.icount < target ) {
94 armr.icount++;
95 if( !arm_execute_instruction() )
96 break;
97 #ifdef ENABLE_DEBUG_MODE
98 for( i=0; i<arm_breakpoint_count; i++ ) {
99 if( arm_breakpoints[i].address == armr.r[15] ) {
100 break;
101 }
102 }
103 if( i != arm_breakpoint_count ) {
104 dreamcast_stop();
105 if( arm_breakpoints[i].type == BREAK_ONESHOT )
106 arm_clear_breakpoint( armr.r[15], BREAK_ONESHOT );
107 break;
108 }
109 #endif
110 }
112 if( target != armr.icount ) {
113 /* Halted - compute time actually executed */
114 nanosecs = (armr.icount - start) * arm_cpu_period;
115 }
116 return nanosecs;
117 }
119 void arm_save_state( FILE *f )
120 {
121 fwrite( &armr, sizeof(armr), 1, f );
122 }
124 int arm_load_state( FILE *f )
125 {
126 fread( &armr, sizeof(armr), 1, f );
127 return 0;
128 }
130 /* Exceptions */
131 void arm_reset( void )
132 {
133 /* Wipe all processor state */
134 memset( &armr, 0, sizeof(armr) );
136 armr.cpsr = MODE_SVC | CPSR_I | CPSR_F;
137 armr.r[15] = 0x00000000;
138 }
140 #define SET_CPSR_CONTROL 0x00010000
141 #define SET_CPSR_EXTENSION 0x00020000
142 #define SET_CPSR_STATUS 0x00040000
143 #define SET_CPSR_FLAGS 0x00080000
145 uint32_t arm_get_cpsr( void )
146 {
147 /* write back all flags to the cpsr */
148 armr.cpsr = armr.cpsr & CPSR_COMPACT_MASK;
149 if( armr.n ) armr.cpsr |= CPSR_N;
150 if( armr.z ) armr.cpsr |= CPSR_Z;
151 if( armr.c ) armr.cpsr |= CPSR_C;
152 if( armr.v ) armr.cpsr |= CPSR_V;
153 if( armr.t ) armr.cpsr |= CPSR_T;
154 return armr.cpsr;
155 }
157 /**
158 * Set the CPSR to the specified value.
159 *
160 * @param value values to set in CPSR
161 * @param fields set of mask values to define which sections of the
162 * CPSR to set (one of the SET_CPSR_* values above)
163 */
164 void arm_set_cpsr( uint32_t value, uint32_t fields )
165 {
166 if( IS_PRIVILEGED_MODE() ) {
167 if( fields & SET_CPSR_CONTROL ) {
168 int mode = value & CPSR_MODE;
169 arm_set_mode( mode );
170 armr.t = ( value & CPSR_T ); /* Technically illegal to change */
171 armr.cpsr = (armr.cpsr & 0xFFFFFF00) | (value & 0x000000FF);
172 }
174 /* Middle 16 bits not currently defined */
175 }
176 if( fields & SET_CPSR_FLAGS ) {
177 /* Break flags directly out of given value - don't bother writing
178 * back to CPSR
179 */
180 armr.n = ( value & CPSR_N );
181 armr.z = ( value & CPSR_Z );
182 armr.c = ( value & CPSR_C );
183 armr.v = ( value & CPSR_V );
184 }
185 }
187 void arm_set_spsr( uint32_t value, uint32_t fields )
188 {
189 /* Only defined if we actually have an SPSR register */
190 if( IS_EXCEPTION_MODE() ) {
191 if( fields & SET_CPSR_CONTROL ) {
192 armr.spsr = (armr.spsr & 0xFFFFFF00) | (value & 0x000000FF);
193 }
195 /* Middle 16 bits not currently defined */
197 if( fields & SET_CPSR_FLAGS ) {
198 armr.spsr = (armr.spsr & 0x00FFFFFF) | (value & 0xFF000000);
199 }
200 }
201 }
203 /**
204 * Raise an ARM exception (other than reset, which uses arm_reset().
205 * @param exception one of the EXC_* exception codes defined above.
206 */
207 void arm_raise_exception( int exception )
208 {
209 int mode = arm_exceptions[exception][0];
210 uint32_t spsr = arm_get_cpsr();
211 arm_set_mode( mode );
212 armr.spsr = spsr;
213 armr.r[14] = armr.r[15];
214 armr.cpsr = (spsr & 0xFFFFFF00) | mode | CPSR_I;
215 if( mode == MODE_FIQ )
216 armr.cpsr |= CPSR_F;
217 armr.r[15] = arm_exceptions[exception][1];
218 }
220 void arm_restore_cpsr( void )
221 {
222 int spsr = armr.spsr;
223 int mode = spsr & CPSR_MODE;
224 arm_set_mode( mode );
225 armr.cpsr = spsr;
226 armr.n = ( spsr & CPSR_N );
227 armr.z = ( spsr & CPSR_Z );
228 armr.c = ( spsr & CPSR_C );
229 armr.v = ( spsr & CPSR_V );
230 armr.t = ( spsr & CPSR_T );
231 }
235 /**
236 * Change the current executing ARM mode to the requested mode.
237 * Saves any required registers to banks and restores those for the
238 * correct mode. (Note does not actually update CPSR at the moment).
239 */
240 void arm_set_mode( int targetMode )
241 {
242 int currentMode = armr.cpsr & CPSR_MODE;
243 if( currentMode == targetMode )
244 return;
246 switch( currentMode ) {
247 case MODE_USER:
248 case MODE_SYS:
249 armr.user_r[5] = armr.r[13];
250 armr.user_r[6] = armr.r[14];
251 break;
252 case MODE_SVC:
253 armr.svc_r[0] = armr.r[13];
254 armr.svc_r[1] = armr.r[14];
255 armr.svc_r[2] = armr.spsr;
256 break;
257 case MODE_ABT:
258 armr.abt_r[0] = armr.r[13];
259 armr.abt_r[1] = armr.r[14];
260 armr.abt_r[2] = armr.spsr;
261 break;
262 case MODE_UND:
263 armr.und_r[0] = armr.r[13];
264 armr.und_r[1] = armr.r[14];
265 armr.und_r[2] = armr.spsr;
266 break;
267 case MODE_IRQ:
268 armr.irq_r[0] = armr.r[13];
269 armr.irq_r[1] = armr.r[14];
270 armr.irq_r[2] = armr.spsr;
271 break;
272 case MODE_FIQ:
273 armr.fiq_r[0] = armr.r[8];
274 armr.fiq_r[1] = armr.r[9];
275 armr.fiq_r[2] = armr.r[10];
276 armr.fiq_r[3] = armr.r[11];
277 armr.fiq_r[4] = armr.r[12];
278 armr.fiq_r[5] = armr.r[13];
279 armr.fiq_r[6] = armr.r[14];
280 armr.fiq_r[7] = armr.spsr;
281 armr.r[8] = armr.user_r[0];
282 armr.r[9] = armr.user_r[1];
283 armr.r[10] = armr.user_r[2];
284 armr.r[11] = armr.user_r[3];
285 armr.r[12] = armr.user_r[4];
286 break;
287 }
289 switch( targetMode ) {
290 case MODE_USER:
291 case MODE_SYS:
292 armr.r[13] = armr.user_r[5];
293 armr.r[14] = armr.user_r[6];
294 break;
295 case MODE_SVC:
296 armr.r[13] = armr.svc_r[0];
297 armr.r[14] = armr.svc_r[1];
298 armr.spsr = armr.svc_r[2];
299 break;
300 case MODE_ABT:
301 armr.r[13] = armr.abt_r[0];
302 armr.r[14] = armr.abt_r[1];
303 armr.spsr = armr.abt_r[2];
304 break;
305 case MODE_UND:
306 armr.r[13] = armr.und_r[0];
307 armr.r[14] = armr.und_r[1];
308 armr.spsr = armr.und_r[2];
309 break;
310 case MODE_IRQ:
311 armr.r[13] = armr.irq_r[0];
312 armr.r[14] = armr.irq_r[1];
313 armr.spsr = armr.irq_r[2];
314 break;
315 case MODE_FIQ:
316 armr.user_r[0] = armr.r[8];
317 armr.user_r[1] = armr.r[9];
318 armr.user_r[2] = armr.r[10];
319 armr.user_r[3] = armr.r[11];
320 armr.user_r[4] = armr.r[12];
321 armr.r[8] = armr.fiq_r[0];
322 armr.r[9] = armr.fiq_r[1];
323 armr.r[10] = armr.fiq_r[2];
324 armr.r[11] = armr.fiq_r[3];
325 armr.r[12] = armr.fiq_r[4];
326 armr.r[13] = armr.fiq_r[5];
327 armr.r[14] = armr.fiq_r[6];
328 armr.spsr = armr.fiq_r[7];
329 break;
330 }
331 }
333 /* Page references are as per ARM DDI 0100E (June 2000) */
335 #define MEM_READ_BYTE( addr ) arm_read_byte(addr)
336 #define MEM_READ_WORD( addr ) arm_read_word(addr)
337 #define MEM_READ_LONG( addr ) arm_read_long(addr)
338 #define MEM_WRITE_BYTE( addr, val ) arm_write_byte(addr, val)
339 #define MEM_WRITE_WORD( addr, val ) arm_write_word(addr, val)
340 #define MEM_WRITE_LONG( addr, val ) arm_write_long(addr, val)
343 #define IS_NOTBORROW( result, op1, op2 ) (op2 > op1 ? 0 : 1)
344 #define IS_CARRY( result, op1, op2 ) (result < op1 ? 1 : 0)
345 #define IS_SUBOVERFLOW( result, op1, op2 ) (((op1^op2) & (result^op1)) >> 31)
346 #define IS_ADDOVERFLOW( result, op1, op2 ) (((op1&op2) & (result^op1)) >> 31)
348 #define PC armr.r[15]
350 /* Instruction fields */
351 #define COND(ir) (ir>>28)
352 #define GRP(ir) ((ir>>26)&0x03)
353 #define OPCODE(ir) ((ir>>20)&0x1F)
354 #define IFLAG(ir) (ir&0x02000000)
355 #define SFLAG(ir) (ir&0x00100000)
356 #define PFLAG(ir) (ir&0x01000000)
357 #define UFLAG(ir) (ir&0x00800000)
358 #define BFLAG(ir) (ir&0x00400000)
359 #define WFLAG(ir) (ir&0x00200000)
360 #define LFLAG(ir) SFLAG(ir)
361 #define RN(ir) (armr.r[((ir>>16)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
362 #define RD(ir) (armr.r[((ir>>12)&0x0F)] + (((ir>>12)&0x0F) == 0x0F ? 4 : 0))
363 #define RDn(ir) ((ir>>12)&0x0F)
364 #define RS(ir) (armr.r[((ir>>8)&0x0F)] + (((ir>>8)&0x0F) == 0x0F ? 4 : 0))
365 #define RM(ir) (armr.r[(ir&0x0F)] + (((ir&0x0F) == 0x0F ? 4 : 0)) )
366 #define LRN(ir) armr.r[((ir>>16)&0x0F)]
367 #define LRD(ir) armr.r[((ir>>12)&0x0F)]
368 #define LRS(ir) armr.r[((ir>>8)&0x0F)]
369 #define LRM(ir) armr.r[(ir&0x0F)]
371 #define IMM8(ir) (ir&0xFF)
372 #define IMM12(ir) (ir&0xFFF)
373 #define SHIFTIMM(ir) ((ir>>7)&0x1F)
374 #define IMMROT(ir) ((ir>>7)&0x1E)
375 #define ROTIMM12(ir) ROTATE_RIGHT_LONG(IMM8(ir),IMMROT(ir))
376 #define SIGNEXT24(n) ((n&0x00800000) ? (n|0xFF000000) : (n&0x00FFFFFF))
377 #define SHIFT(ir) ((ir>>4)&0x07)
378 #define DISP24(ir) ((ir&0x00FFFFFF))
379 #define UNDEF(ir) do{ arm_raise_exception( EXC_UNDEFINED ); return TRUE; } while(0)
380 #define UNIMP(ir) do{ PC-=4; ERROR( "Halted on unimplemented instruction at %08x, opcode = %04x", PC, ir ); dreamcast_stop(); return FALSE; }while(0)
382 /**
383 * Determine the value of the shift-operand for a data processing instruction,
384 * without determing a value for shift_C (optimized form for instructions that
385 * don't require shift_C ).
386 * @see s5.1 Addressing Mode 1 - Data-processing operands (p A5-2, 218)
387 */
388 static uint32_t arm_get_shift_operand( uint32_t ir )
389 {
390 uint32_t operand, tmp;
391 if( IFLAG(ir) == 0 ) {
392 operand = RM(ir);
393 switch(SHIFT(ir)) {
394 case 0: /* (Rm << imm) */
395 operand = operand << SHIFTIMM(ir);
396 break;
397 case 1: /* (Rm << Rs) */
398 tmp = RS(ir)&0xFF;
399 if( tmp > 31 ) operand = 0;
400 else operand = operand << tmp;
401 break;
402 case 2: /* (Rm >> imm) */
403 operand = operand >> SHIFTIMM(ir);
404 break;
405 case 3: /* (Rm >> Rs) */
406 tmp = RS(ir) & 0xFF;
407 if( tmp > 31 ) operand = 0;
408 else operand = operand >> ir;
409 break;
410 case 4: /* (Rm >>> imm) */
411 tmp = SHIFTIMM(ir);
412 if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
413 else operand = ((int32_t)operand) >> tmp;
414 break;
415 case 5: /* (Rm >>> Rs) */
416 tmp = RS(ir) & 0xFF;
417 if( tmp > 31 ) operand = ((int32_t)operand) >> 31;
418 else operand = ((int32_t)operand) >> tmp;
419 break;
420 case 6:
421 tmp = SHIFTIMM(ir);
422 if( tmp == 0 ) /* RRX aka rotate with carry */
423 operand = (operand >> 1) | (armr.c<<31);
424 else
425 operand = ROTATE_RIGHT_LONG(operand,tmp);
426 break;
427 case 7:
428 tmp = RS(ir)&0x1F;
429 operand = ROTATE_RIGHT_LONG(operand,tmp);
430 break;
431 }
432 } else {
433 operand = IMM8(ir);
434 tmp = IMMROT(ir);
435 operand = ROTATE_RIGHT_LONG(operand, tmp);
436 }
437 return operand;
438 }
440 /**
441 * Determine the value of the shift-operand for a data processing instruction,
442 * and set armr.shift_c accordingly.
443 * @see s5.1 Addressing Mode 1 - Data-processing operands (p A5-2, 218)
444 */
445 static uint32_t arm_get_shift_operand_s( uint32_t ir )
446 {
447 uint32_t operand, tmp;
448 if( IFLAG(ir) == 0 ) {
449 operand = RM(ir);
450 switch(SHIFT(ir)) {
451 case 0: /* (Rm << imm) */
452 tmp = SHIFTIMM(ir);
453 if( tmp == 0 ) { /* Rm */
454 armr.shift_c = armr.c;
455 } else { /* Rm << imm */
456 armr.shift_c = (operand >> (32-tmp)) & 0x01;
457 operand = operand << tmp;
458 }
459 break;
460 case 1: /* (Rm << Rs) */
461 tmp = RS(ir)&0xFF;
462 if( tmp == 0 ) {
463 armr.shift_c = armr.c;
464 } else {
465 if( tmp <= 32 )
466 armr.shift_c = (operand >> (32-tmp)) & 0x01;
467 else armr.shift_c = 0;
468 if( tmp < 32 )
469 operand = operand << tmp;
470 else operand = 0;
471 }
472 break;
473 case 2: /* (Rm >> imm) */
474 tmp = SHIFTIMM(ir);
475 if( tmp == 0 ) {
476 armr.shift_c = operand >> 31;
477 operand = 0;
478 } else {
479 armr.shift_c = (operand >> (tmp-1)) & 0x01;
480 operand = RM(ir) >> tmp;
481 }
482 break;
483 case 3: /* (Rm >> Rs) */
484 tmp = RS(ir) & 0xFF;
485 if( tmp == 0 ) {
486 armr.shift_c = armr.c;
487 } else {
488 if( tmp <= 32 )
489 armr.shift_c = (operand >> (tmp-1))&0x01;
490 else armr.shift_c = 0;
491 if( tmp < 32 )
492 operand = operand >> tmp;
493 else operand = 0;
494 }
495 break;
496 case 4: /* (Rm >>> imm) */
497 tmp = SHIFTIMM(ir);
498 if( tmp == 0 ) {
499 armr.shift_c = operand >> 31;
500 operand = -armr.shift_c;
501 } else {
502 armr.shift_c = (operand >> (tmp-1)) & 0x01;
503 operand = ((int32_t)operand) >> tmp;
504 }
505 break;
506 case 5: /* (Rm >>> Rs) */
507 tmp = RS(ir) & 0xFF;
508 if( tmp == 0 ) {
509 armr.shift_c = armr.c;
510 } else {
511 if( tmp < 32 ) {
512 armr.shift_c = (operand >> (tmp-1))&0x01;
513 operand = ((int32_t)operand) >> tmp;
514 } else {
515 armr.shift_c = operand >> 31;
516 operand = ((int32_t)operand) >> 31;
517 }
518 }
519 break;
520 case 6:
521 tmp = SHIFTIMM(ir);
522 if( tmp == 0 ) { /* RRX aka rotate with carry */
523 armr.shift_c = operand&0x01;
524 operand = (operand >> 1) | (armr.c<<31);
525 } else {
526 armr.shift_c = operand>>(tmp-1);
527 operand = ROTATE_RIGHT_LONG(operand,tmp);
528 }
529 break;
530 case 7:
531 tmp = RS(ir)&0xFF;
532 if( tmp == 0 ) {
533 armr.shift_c = armr.c;
534 } else {
535 tmp &= 0x1F;
536 if( tmp == 0 ) {
537 armr.shift_c = operand>>31;
538 } else {
539 armr.shift_c = (operand>>(tmp-1))&0x1;
540 operand = ROTATE_RIGHT_LONG(operand,tmp);
541 }
542 }
543 break;
544 }
545 } else {
546 operand = IMM8(ir);
547 tmp = IMMROT(ir);
548 if( tmp == 0 ) {
549 armr.shift_c = armr.c;
550 } else {
551 operand = ROTATE_RIGHT_LONG(operand, tmp);
552 armr.shift_c = operand>>31;
553 }
554 }
555 return operand;
556 }
558 /**
559 * Another variant of the shifter code for index-based memory addressing.
560 * Distinguished by the fact that it doesn't support register shifts, and
561 * ignores the I flag (WTF do the load/store instructions use the I flag to
562 * mean the _exact opposite_ of what it means for the data processing
563 * instructions ???)
564 */
565 static uint32_t arm_get_address_index( uint32_t ir )
566 {
567 uint32_t operand = RM(ir);
568 uint32_t tmp;
570 switch(SHIFT(ir)) {
571 case 0: /* (Rm << imm) */
572 operand = operand << SHIFTIMM(ir);
573 break;
574 case 2: /* (Rm >> imm) */
575 operand = operand >> SHIFTIMM(ir);
576 break;
577 case 4: /* (Rm >>> imm) */
578 tmp = SHIFTIMM(ir);
579 if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
580 else operand = ((int32_t)operand) >> tmp;
581 break;
582 case 6:
583 tmp = SHIFTIMM(ir);
584 if( tmp == 0 ) /* RRX aka rotate with carry */
585 operand = (operand >> 1) | (armr.c<<31);
586 else
587 operand = ROTATE_RIGHT_LONG(operand,tmp);
588 break;
589 default: UNIMP(ir);
590 }
591 return operand;
592 }
594 /**
595 * Determine the address operand of a load/store instruction, including
596 * applying any pre/post adjustments to the address registers.
597 * @see s5.2 Addressing Mode 2 - Load and Store Word or Unsigned Byte
598 * @param The instruction word.
599 * @return The calculated address
600 */
601 static uint32_t arm_get_address_operand( uint32_t ir )
602 {
603 uint32_t addr;
605 /* I P U . W */
606 switch( (ir>>21)&0x1D ) {
607 case 0: /* Rn -= imm offset (post-indexed) [5.2.8 A5-28] */
608 case 1:
609 addr = RN(ir);
610 LRN(ir) = addr - IMM12(ir);
611 break;
612 case 4: /* Rn += imm offsett (post-indexed) [5.2.8 A5-28] */
613 case 5:
614 addr = RN(ir);
615 LRN(ir) = addr + IMM12(ir);
616 break;
617 case 8: /* Rn - imm offset [5.2.2 A5-20] */
618 addr = RN(ir) - IMM12(ir);
619 break;
620 case 9: /* Rn -= imm offset (pre-indexed) [5.2.5 A5-24] */
621 addr = RN(ir) - IMM12(ir);
622 LRN(ir) = addr;
623 break;
624 case 12: /* Rn + imm offset [5.2.2 A5-20] */
625 addr = RN(ir) + IMM12(ir);
626 break;
627 case 13: /* Rn += imm offset [5.2.5 A5-24 ] */
628 addr = RN(ir) + IMM12(ir);
629 LRN(ir) = addr;
630 break;
631 case 16: /* Rn -= Rm (post-indexed) [5.2.10 A5-32 ] */
632 case 17:
633 addr = RN(ir);
634 LRN(ir) = addr - arm_get_address_index(ir);
635 break;
636 case 20: /* Rn += Rm (post-indexed) [5.2.10 A5-32 ] */
637 case 21:
638 addr = RN(ir);
639 LRN(ir) = addr - arm_get_address_index(ir);
640 break;
641 case 24: /* Rn - Rm [5.2.4 A5-23] */
642 addr = RN(ir) - arm_get_address_index(ir);
643 break;
644 case 25: /* RN -= Rm (pre-indexed) [5.2.7 A5-26] */
645 addr = RN(ir) - arm_get_address_index(ir);
646 LRN(ir) = addr;
647 break;
648 case 28: /* Rn + Rm [5.2.4 A5-23] */
649 addr = RN(ir) + arm_get_address_index(ir);
650 break;
651 case 29: /* RN += Rm (pre-indexed) [5.2.7 A5-26] */
652 addr = RN(ir) + arm_get_address_index(ir);
653 LRN(ir) = addr;
654 break;
655 }
656 return addr;
657 }
659 gboolean arm_execute_instruction( void )
660 {
661 uint32_t pc;
662 uint32_t ir;
663 uint32_t operand, operand2, tmp, tmp2, cond;
665 tmp = armr.int_pending & (~armr.cpsr);
666 if( tmp ) {
667 if( tmp & CPSR_F ) {
668 arm_raise_exception( EXC_FAST_IRQ );
669 } else {
670 arm_raise_exception( EXC_IRQ );
671 }
672 }
674 ir = MEM_READ_LONG(PC);
675 pc = PC + 4;
676 PC = pc;
678 /**
679 * Check the condition bits first - if the condition fails return
680 * immediately without actually looking at the rest of the instruction.
681 */
682 switch( COND(ir) ) {
683 case 0: /* EQ */
684 cond = armr.z;
685 break;
686 case 1: /* NE */
687 cond = !armr.z;
688 break;
689 case 2: /* CS/HS */
690 cond = armr.c;
691 break;
692 case 3: /* CC/LO */
693 cond = !armr.c;
694 break;
695 case 4: /* MI */
696 cond = armr.n;
697 break;
698 case 5: /* PL */
699 cond = !armr.n;
700 break;
701 case 6: /* VS */
702 cond = armr.v;
703 break;
704 case 7: /* VC */
705 cond = !armr.v;
706 break;
707 case 8: /* HI */
708 cond = armr.c && !armr.z;
709 break;
710 case 9: /* LS */
711 cond = (!armr.c) || armr.z;
712 break;
713 case 10: /* GE */
714 cond = (armr.n == armr.v);
715 break;
716 case 11: /* LT */
717 cond = (armr.n != armr.v);
718 break;
719 case 12: /* GT */
720 cond = (!armr.z) && (armr.n == armr.v);
721 break;
722 case 13: /* LE */
723 cond = armr.z || (armr.n != armr.v);
724 break;
725 case 14: /* AL */
726 cond = 1;
727 break;
728 case 15: /* (NV) */
729 cond = 0;
730 UNDEF(ir);
731 }
732 if( !cond )
733 return TRUE;
735 /**
736 * Condition passed, now for the actual instructions...
737 */
738 switch( GRP(ir) ) {
739 case 0:
740 if( (ir & 0x0D900000) == 0x01000000 ) {
741 /* Instructions that aren't actual data processing even though
742 * they sit in the DP instruction block.
743 */
744 switch( ir & 0x0FF000F0 ) {
745 case 0x01200010: /* BX Rd */
746 armr.t = ir & 0x01;
747 armr.r[15] = RM(ir) & 0xFFFFFFFE;
748 break;
749 case 0x01000000: /* MRS Rd, CPSR */
750 LRD(ir) = arm_get_cpsr();
751 break;
752 case 0x01400000: /* MRS Rd, SPSR */
753 LRD(ir) = armr.spsr;
754 break;
755 case 0x01200000: /* MSR CPSR, Rd */
756 arm_set_cpsr( RM(ir), ir );
757 break;
758 case 0x01600000: /* MSR SPSR, Rd */
759 arm_set_spsr( RM(ir), ir );
760 break;
761 case 0x03200000: /* MSR CPSR, imm */
762 arm_set_cpsr( ROTIMM12(ir), ir );
763 break;
764 case 0x03600000: /* MSR SPSR, imm */
765 arm_set_spsr( ROTIMM12(ir), ir );
766 break;
767 default:
768 UNIMP(ir);
769 }
770 } else if( (ir & 0x0E000090) == 0x00000090 ) {
771 /* Neither are these */
772 UNIMP(ir);
773 switch( (ir>>5)&0x03 ) {
774 case 0:
775 /* Arithmetic extension area */
776 switch(OPCODE(ir)) {
777 case 0: /* MUL */
778 LRN(ir) = RM(ir) * RS(ir);
779 break;
780 case 1: /* MULS */
781 tmp = RM(ir) * RS(ir);
782 LRN(ir) = tmp;
783 armr.n = tmp>>31;
784 armr.z = (tmp == 0);
785 break;
786 case 2: /* MLA */
787 LRN(ir) = RM(ir) * RS(ir) + RD(ir);
788 break;
789 case 3: /* MLAS */
790 tmp = RM(ir) * RS(ir) + RD(ir);
791 LRN(ir) = tmp;
792 armr.n = tmp>>31;
793 armr.z = (tmp == 0);
794 break;
795 case 8: /* UMULL */
796 break;
797 case 9: /* UMULLS */
798 break;
799 case 10: /* UMLAL */
800 break;
801 case 11: /* UMLALS */
802 break;
803 case 12: /* SMULL */
804 break;
805 case 13: /* SMULLS */
806 break;
807 case 14: /* SMLAL */
808 break;
809 case 15: /* SMLALS */
810 break;
811 case 16: /* SWP */
812 tmp = arm_read_long( RN(ir) );
813 switch( RN(ir) & 0x03 ) {
814 case 1:
815 tmp = ROTATE_RIGHT_LONG(tmp, 8);
816 break;
817 case 2:
818 tmp = ROTATE_RIGHT_LONG(tmp, 16);
819 break;
820 case 3:
821 tmp = ROTATE_RIGHT_LONG(tmp, 24);
822 break;
823 }
824 arm_write_long( RN(ir), RM(ir) );
825 LRD(ir) = tmp;
826 break;
827 case 20: /* SWPB */
828 tmp = arm_read_byte( RN(ir) );
829 arm_write_byte( RN(ir), RM(ir) );
830 LRD(ir) = tmp;
831 break;
832 default:
833 UNIMP(ir);
834 }
835 break;
836 case 1:
837 if( LFLAG(ir) ) {
838 /* LDRH */
839 } else {
840 /* STRH */
841 }
842 UNIMP(ir);
843 break;
844 case 2:
845 if( LFLAG(ir) ) {
846 /* LDRSB */
847 } else {
848 }
849 UNIMP(ir);
850 break;
851 case 3:
852 if( LFLAG(ir) ) {
853 /* LDRSH */
854 } else {
855 }
856 UNIMP(ir);
857 break;
858 }
859 } else {
860 /* Data processing */
862 switch(OPCODE(ir)) {
863 case 0: /* AND Rd, Rn, operand */
864 LRD(ir) = RN(ir) & arm_get_shift_operand(ir);
865 break;
866 case 1: /* ANDS Rd, Rn, operand */
867 operand = arm_get_shift_operand_s(ir) & RN(ir);
868 LRD(ir) = operand;
869 if( RDn(ir) == 15 ) {
870 arm_restore_cpsr();
871 } else {
872 armr.n = operand>>31;
873 armr.z = (operand == 0);
874 armr.c = armr.shift_c;
875 }
876 break;
877 case 2: /* EOR Rd, Rn, operand */
878 LRD(ir) = RN(ir) ^ arm_get_shift_operand(ir);
879 break;
880 case 3: /* EORS Rd, Rn, operand */
881 operand = arm_get_shift_operand_s(ir) ^ RN(ir);
882 LRD(ir) = operand;
883 if( RDn(ir) == 15 ) {
884 arm_restore_cpsr();
885 } else {
886 armr.n = operand>>31;
887 armr.z = (operand == 0);
888 armr.c = armr.shift_c;
889 }
890 break;
891 case 4: /* SUB Rd, Rn, operand */
892 LRD(ir) = RN(ir) - arm_get_shift_operand(ir);
893 break;
894 case 5: /* SUBS Rd, Rn, operand */
895 operand = RN(ir);
896 operand2 = arm_get_shift_operand(ir);
897 tmp = operand - operand2;
898 LRD(ir) = tmp;
899 if( RDn(ir) == 15 ) {
900 arm_restore_cpsr();
901 } else {
902 armr.n = tmp>>31;
903 armr.z = (tmp == 0);
904 armr.c = IS_NOTBORROW(tmp,operand,operand2);
905 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
906 }
907 break;
908 case 6: /* RSB Rd, operand, Rn */
909 LRD(ir) = arm_get_shift_operand(ir) - RN(ir);
910 break;
911 case 7: /* RSBS Rd, operand, Rn */
912 operand = arm_get_shift_operand(ir);
913 operand2 = RN(ir);
914 tmp = operand - operand2;
915 LRD(ir) = tmp;
916 if( RDn(ir) == 15 ) {
917 arm_restore_cpsr();
918 } else {
919 armr.n = tmp>>31;
920 armr.z = (tmp == 0);
921 armr.c = IS_NOTBORROW(tmp,operand,operand2);
922 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
923 }
924 break;
925 case 8: /* ADD Rd, Rn, operand */
926 LRD(ir) = RN(ir) + arm_get_shift_operand(ir);
927 break;
928 case 9: /* ADDS Rd, Rn, operand */
929 operand = arm_get_shift_operand(ir);
930 operand2 = RN(ir);
931 tmp = operand + operand2;
932 LRD(ir) = tmp;
933 if( RDn(ir) == 15 ) {
934 arm_restore_cpsr();
935 } else {
936 armr.n = tmp>>31;
937 armr.z = (tmp == 0);
938 armr.c = IS_CARRY(tmp,operand,operand2);
939 armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
940 }
941 break;
942 case 10: /* ADC */
943 LRD(ir) = RN(ir) + arm_get_shift_operand(ir) +
944 (armr.c ? 1 : 0);
945 break;
946 case 11: /* ADCS */
947 operand = arm_get_shift_operand(ir);
948 operand2 = RN(ir);
949 tmp = operand + operand2;
950 tmp2 = tmp + armr.c ? 1 : 0;
951 LRD(ir) = tmp2;
952 if( RDn(ir) == 15 ) {
953 arm_restore_cpsr();
954 } else {
955 armr.n = tmp >> 31;
956 armr.z = (tmp == 0 );
957 armr.c = IS_CARRY(tmp,operand,operand2) ||
958 (tmp2 < tmp);
959 armr.v = IS_ADDOVERFLOW(tmp,operand, operand2) ||
960 ((tmp&0x80000000) != (tmp2&0x80000000));
961 }
962 break;
963 case 12: /* SBC */
964 LRD(ir) = RN(ir) - arm_get_shift_operand(ir) -
965 (armr.c ? 0 : 1);
966 break;
967 case 13: /* SBCS */
968 operand = RN(ir);
969 operand2 = arm_get_shift_operand(ir);
970 tmp = operand - operand2;
971 tmp2 = tmp - (armr.c ? 0 : 1);
972 if( RDn(ir) == 15 ) {
973 arm_restore_cpsr();
974 } else {
975 armr.n = tmp >> 31;
976 armr.z = (tmp == 0 );
977 armr.c = IS_NOTBORROW(tmp,operand,operand2) &&
978 (tmp2<tmp);
979 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2) ||
980 ((tmp&0x80000000) != (tmp2&0x80000000));
981 }
982 break;
983 case 14: /* RSC */
984 LRD(ir) = arm_get_shift_operand(ir) - RN(ir) -
985 (armr.c ? 0 : 1);
986 break;
987 case 15: /* RSCS */
988 operand = arm_get_shift_operand(ir);
989 operand2 = RN(ir);
990 tmp = operand - operand2;
991 tmp2 = tmp - (armr.c ? 0 : 1);
992 if( RDn(ir) == 15 ) {
993 arm_restore_cpsr();
994 } else {
995 armr.n = tmp >> 31;
996 armr.z = (tmp == 0 );
997 armr.c = IS_NOTBORROW(tmp,operand,operand2) &&
998 (tmp2<tmp);
999 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2) ||
1000 ((tmp&0x80000000) != (tmp2&0x80000000));
1001 }
1002 break;
1003 case 17: /* TST Rn, operand */
1004 operand = arm_get_shift_operand_s(ir) & RN(ir);
1005 armr.n = operand>>31;
1006 armr.z = (operand == 0);
1007 armr.c = armr.shift_c;
1008 break;
1009 case 19: /* TEQ Rn, operand */
1010 operand = arm_get_shift_operand_s(ir) ^ RN(ir);
1011 armr.n = operand>>31;
1012 armr.z = (operand == 0);
1013 armr.c = armr.shift_c;
1014 break;
1015 case 21: /* CMP Rn, operand */
1016 operand = RN(ir);
1017 operand2 = arm_get_shift_operand(ir);
1018 tmp = operand - operand2;
1019 armr.n = tmp>>31;
1020 armr.z = (tmp == 0);
1021 armr.c = IS_NOTBORROW(tmp,operand,operand2);
1022 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
1023 break;
1024 case 23: /* CMN Rn, operand */
1025 operand = RN(ir);
1026 operand2 = arm_get_shift_operand(ir);
1027 tmp = operand + operand2;
1028 armr.n = tmp>>31;
1029 armr.z = (tmp == 0);
1030 armr.c = IS_CARRY(tmp,operand,operand2);
1031 armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
1032 break;
1033 case 24: /* ORR Rd, Rn, operand */
1034 LRD(ir) = RN(ir) | arm_get_shift_operand(ir);
1035 break;
1036 case 25: /* ORRS Rd, Rn, operand */
1037 operand = arm_get_shift_operand_s(ir) | RN(ir);
1038 LRD(ir) = operand;
1039 if( RDn(ir) == 15 ) {
1040 arm_restore_cpsr();
1041 } else {
1042 armr.n = operand>>31;
1043 armr.z = (operand == 0);
1044 armr.c = armr.shift_c;
1045 }
1046 break;
1047 case 26: /* MOV Rd, operand */
1048 LRD(ir) = arm_get_shift_operand(ir);
1049 break;
1050 case 27: /* MOVS Rd, operand */
1051 operand = arm_get_shift_operand_s(ir);
1052 LRD(ir) = operand;
1053 if( RDn(ir) == 15 ) {
1054 arm_restore_cpsr();
1055 } else {
1056 armr.n = operand>>31;
1057 armr.z = (operand == 0);
1058 armr.c = armr.shift_c;
1059 }
1060 break;
1061 case 28: /* BIC Rd, Rn, operand */
1062 LRD(ir) = RN(ir) & (~arm_get_shift_operand(ir));
1063 break;
1064 case 29: /* BICS Rd, Rn, operand */
1065 operand = RN(ir) & (~arm_get_shift_operand_s(ir));
1066 LRD(ir) = operand;
1067 if( RDn(ir) == 15 ) {
1068 arm_restore_cpsr();
1069 } else {
1070 armr.n = operand>>31;
1071 armr.z = (operand == 0);
1072 armr.c = armr.shift_c;
1073 }
1074 break;
1075 case 30: /* MVN Rd, operand */
1076 LRD(ir) = ~arm_get_shift_operand(ir);
1077 break;
1078 case 31: /* MVNS Rd, operand */
1079 operand = ~arm_get_shift_operand_s(ir);
1080 LRD(ir) = operand;
1081 if( RDn(ir) == 15 ) {
1082 arm_restore_cpsr();
1083 } else {
1084 armr.n = operand>>31;
1085 armr.z = (operand == 0);
1086 armr.c = armr.shift_c;
1087 }
1088 break;
1089 default:
1090 UNIMP(ir);
1091 }
1092 }
1093 break;
1094 case 1: /* Load/store */
1095 operand = arm_get_address_operand(ir);
1096 switch( (ir>>20)&0x17 ) {
1097 case 0: case 16: case 18: /* STR Rd, address */
1098 arm_write_long( operand, RD(ir) );
1099 break;
1100 case 1: case 17: case 19: /* LDR Rd, address */
1101 LRD(ir) = arm_read_long(operand);
1102 break;
1103 case 2: /* STRT Rd, address */
1104 arm_write_long_user( operand, RD(ir) );
1105 break;
1106 case 3: /* LDRT Rd, address */
1107 LRD(ir) = arm_read_long_user( operand );
1108 break;
1109 case 4: case 20: case 22: /* STRB Rd, address */
1110 arm_write_byte( operand, RD(ir) );
1111 break;
1112 case 5: case 21: case 23: /* LDRB Rd, address */
1113 LRD(ir) = arm_read_byte( operand );
1114 break;
1115 case 6: /* STRBT Rd, address */
1116 arm_write_byte_user( operand, RD(ir) );
1117 break;
1118 case 7: /* LDRBT Rd, address */
1119 LRD(ir) = arm_read_byte_user( operand );
1120 break;
1121 }
1122 break;
1123 case 2: /* Load/store multiple, branch*/
1124 if( (ir & 0x02000000) == 0x02000000 ) { /* B[L] imm24 */
1125 operand = (SIGNEXT24(ir&0x00FFFFFF) << 2);
1126 if( (ir & 0x01000000) == 0x01000000 ) {
1127 armr.r[14] = pc; /* BL */
1128 }
1129 armr.r[15] = pc + 4 + operand;
1130 } else { /* Load/store multiple */
1131 int prestep, poststep;
1132 if( PFLAG(ir) ) {
1133 prestep = UFLAG(ir) ? 4 : -4;
1134 poststep = 0 ;
1135 } else {
1136 prestep = 0;
1137 poststep = UFLAG(ir) ? 4 : -4;
1138 }
1139 operand = RN(ir);
1140 if( BFLAG(ir) ) {
1141 /* Actually S - bit 22. Means "make massively complicated" */
1142 if( LFLAG(ir) && (ir&0x00008000) ) {
1143 /* LDM (3). Much like normal LDM but also copies SPSR
1144 * back to CPSR */
1145 for( tmp=0; tmp < 16; tmp++ ) {
1146 if( (ir & (1<<tmp)) ) {
1147 operand += prestep;
1148 armr.r[tmp] = arm_read_long(operand);
1149 operand += poststep;
1150 }
1151 }
1152 if( WFLAG(ir) )
1153 LRN(ir) = operand;
1154 arm_restore_cpsr();
1155 if( armr.t ) PC &= 0xFFFFFFFE;
1156 else PC &= 0xFFFFFFFC;
1157 } else {
1158 /* LDM/STM (2). As normal LDM but accesses the User banks
1159 * instead of the active ones. Aka the truly evil case
1160 */
1161 int bank_start;
1162 if( IS_FIQ_MODE() )
1163 bank_start = 8;
1164 else if( IS_EXCEPTION_MODE() )
1165 bank_start = 13;
1166 else bank_start = 15;
1167 for( tmp=0; tmp<bank_start; tmp++ ) {
1168 if( (ir & (1<<tmp)) ) {
1169 operand += prestep;
1170 if( LFLAG(ir) ) {
1171 armr.r[tmp] = arm_read_long(operand);
1172 } else {
1173 arm_write_long( operand, armr.r[tmp] );
1174 }
1175 operand += poststep;
1176 }
1177 }
1178 for( ; tmp < 15; tmp ++ ) {
1179 if( (ir & (1<<tmp)) ) {
1180 operand += prestep;
1181 if( LFLAG(ir) ) {
1182 armr.user_r[tmp-8] = arm_read_long(operand);
1183 } else {
1184 arm_write_long( operand, armr.user_r[tmp-8] );
1185 }
1186 operand += poststep;
1187 }
1188 }
1189 if( ir & 0x8000 ) {
1190 operand += prestep;
1191 if( LFLAG(ir) ) {
1192 /* Actually can't happen, but anyway... */
1193 armr.r[15] = arm_read_long(operand);
1194 } else {
1195 arm_write_long( operand, armr.r[15]+ STM_R15_OFFSET - 4 );
1196 }
1197 operand += poststep;
1198 }
1199 }
1200 } else {
1201 /* Normal LDM/STM */
1202 for( tmp=0; tmp < 16; tmp++ ) {
1203 if( (ir & (1<<tmp)) ) {
1204 operand += prestep;
1205 if( LFLAG(ir) ) {
1206 armr.r[tmp] = arm_read_long(operand);
1207 } else {
1208 if( tmp == 15 )
1209 arm_write_long( operand,
1210 armr.r[15] + STM_R15_OFFSET - 4 );
1211 else
1212 arm_write_long( operand, armr.r[tmp] );
1213 }
1214 operand += poststep;
1215 }
1216 }
1217 if( WFLAG(ir) )
1218 LRN(ir) = operand;
1219 }
1220 }
1221 break;
1222 case 3: /* Copro */
1223 if( (ir & 0x0F000000) == 0x0F000000 ) { /* SWI */
1224 arm_raise_exception( EXC_SOFTWARE );
1225 } else {
1226 UNIMP(ir);
1227 }
1228 break;
1229 }
1230 return TRUE;
1231 }
.