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 #define MODULE aica_module
21 #include "dreamcast.h"
23 #include "aica/armcore.h"
24 #include "aica/aica.h"
26 #define STM_R15_OFFSET 12
28 struct arm_registers armr;
30 void arm_set_mode( int mode );
32 uint32_t arm_exceptions[][2] = {{ MODE_SVC, 0x00000000 },
33 { MODE_UND, 0x00000004 },
34 { MODE_SVC, 0x00000008 },
35 { MODE_ABT, 0x0000000C },
36 { MODE_ABT, 0x00000010 },
37 { MODE_IRQ, 0x00000018 },
38 { MODE_FIQ, 0x0000001C } };
41 #define EXC_UNDEFINED 1
42 #define EXC_SOFTWARE 2
43 #define EXC_PREFETCH_ABORT 3
44 #define EXC_DATA_ABORT 4
46 #define EXC_FAST_IRQ 6
48 uint32_t arm_cpu_freq = ARM_BASE_RATE;
49 uint32_t arm_cpu_period = 1000 / ARM_BASE_RATE;
51 #define CYCLES_PER_SAMPLE ((ARM_BASE_RATE * 1000000) / AICA_SAMPLE_RATE)
53 static struct breakpoint_struct arm_breakpoints[MAX_BREAKPOINTS];
54 static int arm_breakpoint_count = 0;
56 void arm_set_breakpoint( uint32_t pc, breakpoint_type_t type )
58 arm_breakpoints[arm_breakpoint_count].address = pc;
59 arm_breakpoints[arm_breakpoint_count].type = type;
60 arm_breakpoint_count++;
63 gboolean arm_clear_breakpoint( uint32_t pc, breakpoint_type_t type )
67 for( i=0; i<arm_breakpoint_count; i++ ) {
68 if( arm_breakpoints[i].address == pc &&
69 arm_breakpoints[i].type == type ) {
70 while( ++i < arm_breakpoint_count ) {
71 arm_breakpoints[i-1].address = arm_breakpoints[i].address;
72 arm_breakpoints[i-1].type = arm_breakpoints[i].type;
74 arm_breakpoint_count--;
81 int arm_get_breakpoint( uint32_t pc )
84 for( i=0; i<arm_breakpoint_count; i++ ) {
85 if( arm_breakpoints[i].address == pc )
86 return arm_breakpoints[i].type;
91 uint32_t arm_run_slice( uint32_t num_samples )
98 for( i=0; i<num_samples; i++ ) {
99 for( j=0; j < CYCLES_PER_SAMPLE; j++ ) {
101 if( !arm_execute_instruction() )
103 #ifdef ENABLE_DEBUG_MODE
104 for( k=0; k<arm_breakpoint_count; k++ ) {
105 if( arm_breakpoints[k].address == armr.r[15] ) {
107 if( arm_breakpoints[k].type == BREAK_ONESHOT )
108 arm_clear_breakpoint( armr.r[15], BREAK_ONESHOT );
115 k = MMIO_READ( AICA2, AICA_TCR );
116 uint8_t val = MMIO_READ( AICA2, AICA_TIMER );
119 aica_event( AICA_EVENT_TIMER );
120 // MMIO_WRITE( AICA2, AICA_TCR, k & ~0x40 );
122 MMIO_WRITE( AICA2, AICA_TIMER, val );
123 if( !dreamcast_is_running() )
130 void arm_save_state( FILE *f )
132 fwrite( &armr, sizeof(armr), 1, f );
135 int arm_load_state( FILE *f )
137 fread( &armr, sizeof(armr), 1, f );
142 void arm_reset( void )
144 /* Wipe all processor state */
145 memset( &armr, 0, sizeof(armr) );
147 armr.cpsr = MODE_SVC | CPSR_I | CPSR_F;
148 armr.r[15] = 0x00000000;
152 #define SET_CPSR_CONTROL 0x00010000
153 #define SET_CPSR_EXTENSION 0x00020000
154 #define SET_CPSR_STATUS 0x00040000
155 #define SET_CPSR_FLAGS 0x00080000
157 uint32_t arm_get_cpsr( void )
159 /* write back all flags to the cpsr */
160 armr.cpsr = armr.cpsr & CPSR_COMPACT_MASK;
161 if( armr.n ) armr.cpsr |= CPSR_N;
162 if( armr.z ) armr.cpsr |= CPSR_Z;
163 if( armr.c ) armr.cpsr |= CPSR_C;
164 if( armr.v ) armr.cpsr |= CPSR_V;
165 if( armr.t ) armr.cpsr |= CPSR_T;
170 * Return a pointer to the specified register in the user bank,
171 * regardless of the active bank
173 static uint32_t *arm_user_reg( int reg )
175 if( IS_EXCEPTION_MODE() ) {
176 if( reg == 13 || reg == 14 )
177 return &armr.user_r[reg-8];
178 if( IS_FIQ_MODE() ) {
179 if( reg >= 8 || reg <= 12 )
180 return &armr.user_r[reg-8];
186 #define USER_R(n) *arm_user_reg(n)
189 * Set the CPSR to the specified value.
191 * @param value values to set in CPSR
192 * @param fields set of mask values to define which sections of the
193 * CPSR to set (one of the SET_CPSR_* values above)
195 void arm_set_cpsr( uint32_t value, uint32_t fields )
197 if( IS_PRIVILEGED_MODE() ) {
198 if( fields & SET_CPSR_CONTROL ) {
199 int mode = value & CPSR_MODE;
200 arm_set_mode( mode );
201 armr.t = ( value & CPSR_T ); /* Technically illegal to change */
202 armr.cpsr = (armr.cpsr & 0xFFFFFF00) | (value & 0x000000FF);
205 /* Middle 16 bits not currently defined */
207 if( fields & SET_CPSR_FLAGS ) {
208 /* Break flags directly out of given value - don't bother writing
211 armr.n = ( value & CPSR_N );
212 armr.z = ( value & CPSR_Z );
213 armr.c = ( value & CPSR_C );
214 armr.v = ( value & CPSR_V );
218 void arm_set_spsr( uint32_t value, uint32_t fields )
220 /* Only defined if we actually have an SPSR register */
221 if( IS_EXCEPTION_MODE() ) {
222 if( fields & SET_CPSR_CONTROL ) {
223 armr.spsr = (armr.spsr & 0xFFFFFF00) | (value & 0x000000FF);
226 /* Middle 16 bits not currently defined */
228 if( fields & SET_CPSR_FLAGS ) {
229 armr.spsr = (armr.spsr & 0x00FFFFFF) | (value & 0xFF000000);
235 * Raise an ARM exception (other than reset, which uses arm_reset().
236 * @param exception one of the EXC_* exception codes defined above.
238 void arm_raise_exception( int exception )
240 int mode = arm_exceptions[exception][0];
241 uint32_t spsr = arm_get_cpsr();
242 arm_set_mode( mode );
244 armr.r[14] = armr.r[15] + 4;
245 armr.cpsr = (spsr & 0xFFFFFF00) | mode | CPSR_I;
246 if( mode == MODE_FIQ )
248 armr.r[15] = arm_exceptions[exception][1];
251 void arm_restore_cpsr( void )
253 int spsr = armr.spsr;
254 int mode = spsr & CPSR_MODE;
255 arm_set_mode( mode );
257 armr.n = ( spsr & CPSR_N );
258 armr.z = ( spsr & CPSR_Z );
259 armr.c = ( spsr & CPSR_C );
260 armr.v = ( spsr & CPSR_V );
261 armr.t = ( spsr & CPSR_T );
267 * Change the current executing ARM mode to the requested mode.
268 * Saves any required registers to banks and restores those for the
269 * correct mode. (Note does not actually update CPSR at the moment).
271 void arm_set_mode( int targetMode )
273 int currentMode = armr.cpsr & CPSR_MODE;
274 if( currentMode == targetMode )
277 switch( currentMode ) {
280 armr.user_r[5] = armr.r[13];
281 armr.user_r[6] = armr.r[14];
284 armr.svc_r[0] = armr.r[13];
285 armr.svc_r[1] = armr.r[14];
286 armr.svc_r[2] = armr.spsr;
289 armr.abt_r[0] = armr.r[13];
290 armr.abt_r[1] = armr.r[14];
291 armr.abt_r[2] = armr.spsr;
294 armr.und_r[0] = armr.r[13];
295 armr.und_r[1] = armr.r[14];
296 armr.und_r[2] = armr.spsr;
299 armr.irq_r[0] = armr.r[13];
300 armr.irq_r[1] = armr.r[14];
301 armr.irq_r[2] = armr.spsr;
304 armr.fiq_r[0] = armr.r[8];
305 armr.fiq_r[1] = armr.r[9];
306 armr.fiq_r[2] = armr.r[10];
307 armr.fiq_r[3] = armr.r[11];
308 armr.fiq_r[4] = armr.r[12];
309 armr.fiq_r[5] = armr.r[13];
310 armr.fiq_r[6] = armr.r[14];
311 armr.fiq_r[7] = armr.spsr;
312 armr.r[8] = armr.user_r[0];
313 armr.r[9] = armr.user_r[1];
314 armr.r[10] = armr.user_r[2];
315 armr.r[11] = armr.user_r[3];
316 armr.r[12] = armr.user_r[4];
320 switch( targetMode ) {
323 armr.r[13] = armr.user_r[5];
324 armr.r[14] = armr.user_r[6];
327 armr.r[13] = armr.svc_r[0];
328 armr.r[14] = armr.svc_r[1];
329 armr.spsr = armr.svc_r[2];
332 armr.r[13] = armr.abt_r[0];
333 armr.r[14] = armr.abt_r[1];
334 armr.spsr = armr.abt_r[2];
337 armr.r[13] = armr.und_r[0];
338 armr.r[14] = armr.und_r[1];
339 armr.spsr = armr.und_r[2];
342 armr.r[13] = armr.irq_r[0];
343 armr.r[14] = armr.irq_r[1];
344 armr.spsr = armr.irq_r[2];
347 armr.user_r[0] = armr.r[8];
348 armr.user_r[1] = armr.r[9];
349 armr.user_r[2] = armr.r[10];
350 armr.user_r[3] = armr.r[11];
351 armr.user_r[4] = armr.r[12];
352 armr.r[8] = armr.fiq_r[0];
353 armr.r[9] = armr.fiq_r[1];
354 armr.r[10] = armr.fiq_r[2];
355 armr.r[11] = armr.fiq_r[3];
356 armr.r[12] = armr.fiq_r[4];
357 armr.r[13] = armr.fiq_r[5];
358 armr.r[14] = armr.fiq_r[6];
359 armr.spsr = armr.fiq_r[7];
364 /* Page references are as per ARM DDI 0100E (June 2000) */
366 #define MEM_READ_BYTE( addr ) arm_read_byte(addr)
367 #define MEM_READ_WORD( addr ) arm_read_word(addr)
368 #define MEM_READ_LONG( addr ) arm_read_long(addr)
369 #define MEM_WRITE_BYTE( addr, val ) arm_write_byte(addr, val)
370 #define MEM_WRITE_WORD( addr, val ) arm_write_word(addr, val)
371 #define MEM_WRITE_LONG( addr, val ) arm_write_long(addr, val)
374 #define IS_NOTBORROW( result, op1, op2 ) (op2 > op1 ? 0 : 1)
375 #define IS_CARRY( result, op1, op2 ) (result < op1 ? 1 : 0)
376 #define IS_SUBOVERFLOW( result, op1, op2 ) (((op1^op2) & (result^op1)) >> 31)
377 #define IS_ADDOVERFLOW( result, op1, op2 ) (((op1&op2) & (result^op1)) >> 31)
379 #define PC armr.r[15]
381 /* Instruction fields */
382 #define COND(ir) (ir>>28)
383 #define GRP(ir) ((ir>>26)&0x03)
384 #define OPCODE(ir) ((ir>>20)&0x1F)
385 #define IFLAG(ir) (ir&0x02000000)
386 #define SFLAG(ir) (ir&0x00100000)
387 #define PFLAG(ir) (ir&0x01000000)
388 #define UFLAG(ir) (ir&0x00800000)
389 #define BFLAG(ir) (ir&0x00400000)
390 #define WFLAG(ir) (ir&0x00200000)
391 #define LFLAG(ir) SFLAG(ir)
392 #define RN(ir) (armr.r[((ir>>16)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
393 #define RD(ir) (armr.r[((ir>>12)&0x0F)] + (((ir>>12)&0x0F) == 0x0F ? 4 : 0))
394 #define RDn(ir) ((ir>>12)&0x0F)
395 #define RS(ir) (armr.r[((ir>>8)&0x0F)] + (((ir>>8)&0x0F) == 0x0F ? 4 : 0))
396 #define RM(ir) (armr.r[(ir&0x0F)] + (((ir&0x0F) == 0x0F ? 4 : 0)) )
397 #define LRN(ir) armr.r[((ir>>16)&0x0F)]
398 #define LRD(ir) armr.r[((ir>>12)&0x0F)]
399 #define LRS(ir) armr.r[((ir>>8)&0x0F)]
400 #define LRM(ir) armr.r[(ir&0x0F)]
402 #define IMM8(ir) (ir&0xFF)
403 #define IMM12(ir) (ir&0xFFF)
404 #define IMMSPLIT8(ir) (((ir&0xF00)>>4)|(ir&0x0F))
405 #define SHIFTIMM(ir) ((ir>>7)&0x1F)
406 #define IMMROT(ir) ((ir>>7)&0x1E)
407 #define ROTIMM12(ir) ROTATE_RIGHT_LONG(IMM8(ir),IMMROT(ir))
408 #define SIGNEXT24(n) (((n)&0x00800000) ? ((n)|0xFF000000) : ((n)&0x00FFFFFF))
409 #define SIGNEXT8(n) ((int32_t)((int8_t)(n)))
410 #define SIGNEXT16(n) ((int32_t)((int16_t)(n)))
411 #define SHIFT(ir) ((ir>>4)&0x07)
412 #define DISP24(ir) ((ir&0x00FFFFFF))
413 #define UNDEF(ir) do{ arm_raise_exception( EXC_UNDEFINED ); return TRUE; } while(0)
414 #define UNIMP(ir) do{ PC-=4; ERROR( "Halted on unimplemented instruction at %08x, opcode = %04x", PC, ir ); dreamcast_stop(); return FALSE; }while(0)
417 * Determine the value of the shift-operand for a data processing instruction,
418 * without determing a value for shift_C (optimized form for instructions that
419 * don't require shift_C ).
420 * @see s5.1 Addressing Mode 1 - Data-processing operands (p A5-2, 218)
422 static uint32_t arm_get_shift_operand( uint32_t ir )
424 uint32_t operand, tmp;
425 if( IFLAG(ir) == 0 ) {
428 case 0: /* (Rm << imm) */
429 operand = operand << SHIFTIMM(ir);
431 case 1: /* (Rm << Rs) */
433 if( tmp > 31 ) operand = 0;
434 else operand = operand << tmp;
436 case 2: /* (Rm >> imm) */
437 operand = operand >> SHIFTIMM(ir);
439 case 3: /* (Rm >> Rs) */
441 if( tmp > 31 ) operand = 0;
442 else operand = operand >> ir;
444 case 4: /* (Rm >>> imm) */
446 if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
447 else operand = ((int32_t)operand) >> tmp;
449 case 5: /* (Rm >>> Rs) */
451 if( tmp > 31 ) operand = ((int32_t)operand) >> 31;
452 else operand = ((int32_t)operand) >> tmp;
456 if( tmp == 0 ) /* RRX aka rotate with carry */
457 operand = (operand >> 1) | (armr.c<<31);
459 operand = ROTATE_RIGHT_LONG(operand,tmp);
463 operand = ROTATE_RIGHT_LONG(operand,tmp);
469 operand = ROTATE_RIGHT_LONG(operand, tmp);
475 * Determine the value of the shift-operand for a data processing instruction,
476 * and set armr.shift_c accordingly.
477 * @see s5.1 Addressing Mode 1 - Data-processing operands (p A5-2, 218)
479 static uint32_t arm_get_shift_operand_s( uint32_t ir )
481 uint32_t operand, tmp;
482 if( IFLAG(ir) == 0 ) {
485 case 0: /* (Rm << imm) */
487 if( tmp == 0 ) { /* Rm */
488 armr.shift_c = armr.c;
489 } else { /* Rm << imm */
490 armr.shift_c = (operand >> (32-tmp)) & 0x01;
491 operand = operand << tmp;
494 case 1: /* (Rm << Rs) */
497 armr.shift_c = armr.c;
500 armr.shift_c = (operand >> (32-tmp)) & 0x01;
501 else armr.shift_c = 0;
503 operand = operand << tmp;
507 case 2: /* (Rm >> imm) */
510 armr.shift_c = operand >> 31;
513 armr.shift_c = (operand >> (tmp-1)) & 0x01;
514 operand = RM(ir) >> tmp;
517 case 3: /* (Rm >> Rs) */
520 armr.shift_c = armr.c;
523 armr.shift_c = (operand >> (tmp-1))&0x01;
524 else armr.shift_c = 0;
526 operand = operand >> tmp;
530 case 4: /* (Rm >>> imm) */
533 armr.shift_c = operand >> 31;
534 operand = -armr.shift_c;
536 armr.shift_c = (operand >> (tmp-1)) & 0x01;
537 operand = ((int32_t)operand) >> tmp;
540 case 5: /* (Rm >>> Rs) */
543 armr.shift_c = armr.c;
546 armr.shift_c = (operand >> (tmp-1))&0x01;
547 operand = ((int32_t)operand) >> tmp;
549 armr.shift_c = operand >> 31;
550 operand = ((int32_t)operand) >> 31;
556 if( tmp == 0 ) { /* RRX aka rotate with carry */
557 armr.shift_c = operand&0x01;
558 operand = (operand >> 1) | (armr.c<<31);
560 armr.shift_c = operand>>(tmp-1);
561 operand = ROTATE_RIGHT_LONG(operand,tmp);
567 armr.shift_c = armr.c;
571 armr.shift_c = operand>>31;
573 armr.shift_c = (operand>>(tmp-1))&0x1;
574 operand = ROTATE_RIGHT_LONG(operand,tmp);
583 armr.shift_c = armr.c;
585 operand = ROTATE_RIGHT_LONG(operand, tmp);
586 armr.shift_c = operand>>31;
593 * Another variant of the shifter code for index-based memory addressing.
594 * Distinguished by the fact that it doesn't support register shifts, and
595 * ignores the I flag (WTF do the load/store instructions use the I flag to
596 * mean the _exact opposite_ of what it means for the data processing
599 static uint32_t arm_get_address_index( uint32_t ir )
601 uint32_t operand = RM(ir);
605 case 0: /* (Rm << imm) */
606 operand = operand << SHIFTIMM(ir);
608 case 2: /* (Rm >> imm) */
609 operand = operand >> SHIFTIMM(ir);
611 case 4: /* (Rm >>> imm) */
613 if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
614 else operand = ((int32_t)operand) >> tmp;
618 if( tmp == 0 ) /* RRX aka rotate with carry */
619 operand = (operand >> 1) | (armr.c<<31);
621 operand = ROTATE_RIGHT_LONG(operand,tmp);
629 * Determine the address operand of a load/store instruction, including
630 * applying any pre/post adjustments to the address registers.
631 * @see s5.2 Addressing Mode 2 - Load and Store Word or Unsigned Byte
632 * @param The instruction word.
633 * @return The calculated address
635 static uint32_t arm_get_address_operand( uint32_t ir )
640 switch( (ir>>21)&0x1D ) {
641 case 0: /* Rn -= imm offset (post-indexed) [5.2.8 A5-28] */
644 LRN(ir) = addr - IMM12(ir);
646 case 4: /* Rn += imm offsett (post-indexed) [5.2.8 A5-28] */
649 LRN(ir) = addr + IMM12(ir);
651 case 8: /* Rn - imm offset [5.2.2 A5-20] */
652 addr = RN(ir) - IMM12(ir);
654 case 9: /* Rn -= imm offset (pre-indexed) [5.2.5 A5-24] */
655 addr = RN(ir) - IMM12(ir);
658 case 12: /* Rn + imm offset [5.2.2 A5-20] */
659 addr = RN(ir) + IMM12(ir);
661 case 13: /* Rn += imm offset [5.2.5 A5-24 ] */
662 addr = RN(ir) + IMM12(ir);
665 case 16: /* Rn -= Rm (post-indexed) [5.2.10 A5-32 ] */
668 LRN(ir) = addr - arm_get_address_index(ir);
670 case 20: /* Rn += Rm (post-indexed) [5.2.10 A5-32 ] */
673 LRN(ir) = addr - arm_get_address_index(ir);
675 case 24: /* Rn - Rm [5.2.4 A5-23] */
676 addr = RN(ir) - arm_get_address_index(ir);
678 case 25: /* RN -= Rm (pre-indexed) [5.2.7 A5-26] */
679 addr = RN(ir) - arm_get_address_index(ir);
682 case 28: /* Rn + Rm [5.2.4 A5-23] */
683 addr = RN(ir) + arm_get_address_index(ir);
685 case 29: /* RN += Rm (pre-indexed) [5.2.7 A5-26] */
686 addr = RN(ir) + arm_get_address_index(ir);
694 * Determine the address operand of a miscellaneous load/store instruction,
695 * including applying any pre/post adjustments to the address registers.
696 * @see s5.3 Addressing Mode 3 - Miscellaneous Loads and Stores
697 * @param The instruction word.
698 * @return The calculated address
700 static uint32_t arm_get_address3_operand( uint32_t ir )
705 switch( (ir>>21)&0x0F ) {
706 case 0: /* Rn -= Rm (post-indexed) [5.3.7 A5-48] */
707 case 1: /* UNPREDICTABLE */
711 case 2: /* Rn -= imm (post-indexed) [5.3.6 A5-46] */
712 case 3: /* UNPREDICTABLE */
714 LRN(ir) -= IMMSPLIT8(ir);
716 case 4: /* Rn += Rm (post-indexed) [5.3.7 A5-48] */
717 case 5: /* UNPREDICTABLE */
721 case 6: /* Rn += imm (post-indexed) [5.3.6 A5-44] */
722 case 7: /* UNPREDICTABLE */
724 LRN(ir) += IMMSPLIT8(ir);
726 case 8: /* Rn - Rm [5.3.3 A5-38] */
727 addr = RN(ir) - RM(ir);
729 case 9: /* Rn -= Rm (pre-indexed) [5.3.5 A5-42] */
730 addr = RN(ir) - RM(ir);
733 case 10: /* Rn - imm offset [5.3.2 A5-36] */
734 addr = RN(ir) - IMMSPLIT8(ir);
736 case 11: /* Rn -= imm offset (pre-indexed) [5.3.4 A5-40] */
737 addr = RN(ir) - IMMSPLIT8(ir);
740 case 12: /* Rn + Rm [5.3.3 A5-38] */
741 addr = RN(ir) + RM(ir);
743 case 13: /* Rn += Rm (pre-indexed) [5.3.5 A5-42] */
744 addr = RN(ir) + RM(ir);
747 case 14: /* Rn + imm offset [5.3.2 A5-36] */
748 addr = RN(ir) + IMMSPLIT8(ir);
750 case 15: /* Rn += imm offset (pre-indexed) [5.3.4 A5-40] */
751 addr = RN(ir) + IMMSPLIT8(ir);
759 gboolean arm_execute_instruction( void )
763 uint32_t operand, operand2, tmp, tmp2, cond;
766 tmp = armr.int_pending & (~armr.cpsr);
769 arm_raise_exception( EXC_FAST_IRQ );
771 arm_raise_exception( EXC_IRQ );
775 ir = MEM_READ_LONG(PC);
780 * Check the condition bits first - if the condition fails return
781 * immediately without actually looking at the rest of the instruction.
809 cond = armr.c && !armr.z;
812 cond = (!armr.c) || armr.z;
815 cond = (armr.n == armr.v);
818 cond = (armr.n != armr.v);
821 cond = (!armr.z) && (armr.n == armr.v);
824 cond = armr.z || (armr.n != armr.v);
837 * Condition passed, now for the actual instructions...
841 if( (ir & 0x0D900000) == 0x01000000 ) {
842 /* Instructions that aren't actual data processing even though
843 * they sit in the DP instruction block.
845 switch( ir & 0x0FF000F0 ) {
846 case 0x01200010: /* BX Rd */
848 armr.r[15] = RM(ir) & 0xFFFFFFFE;
850 case 0x01000000: /* MRS Rd, CPSR */
851 LRD(ir) = arm_get_cpsr();
853 case 0x01400000: /* MRS Rd, SPSR */
856 case 0x01200000: /* MSR CPSR, Rd */
857 arm_set_cpsr( RM(ir), ir );
859 case 0x01600000: /* MSR SPSR, Rd */
860 arm_set_spsr( RM(ir), ir );
862 case 0x03200000: /* MSR CPSR, imm */
863 arm_set_cpsr( ROTIMM12(ir), ir );
865 case 0x03600000: /* MSR SPSR, imm */
866 arm_set_spsr( ROTIMM12(ir), ir );
871 } else if( (ir & 0x0E000090) == 0x00000090 ) {
872 /* Neither are these */
873 switch( (ir>>5)&0x03 ) {
875 /* Arithmetic extension area */
878 LRN(ir) = RM(ir) * RS(ir);
881 tmp = RM(ir) * RS(ir);
887 LRN(ir) = RM(ir) * RS(ir) + RD(ir);
890 tmp = RM(ir) * RS(ir) + RD(ir);
898 case 11: /* UMLALS */
900 case 13: /* SMULLS */
902 case 15: /* SMLALS */
906 tmp = arm_read_long( RN(ir) );
907 switch( RN(ir) & 0x03 ) {
909 tmp = ROTATE_RIGHT_LONG(tmp, 8);
912 tmp = ROTATE_RIGHT_LONG(tmp, 16);
915 tmp = ROTATE_RIGHT_LONG(tmp, 24);
918 arm_write_long( RN(ir), RM(ir) );
922 tmp = arm_read_byte( RN(ir) );
923 arm_write_byte( RN(ir), RM(ir) );
931 operand = arm_get_address3_operand(ir);
932 if( LFLAG(ir) ) { /* LDRH */
933 LRD(ir) = MEM_READ_WORD( operand ) & 0x0000FFFF;
935 MEM_WRITE_WORD( operand, RD(ir) );
939 if( LFLAG(ir) ) { /* LDRSB */
940 operand = arm_get_address3_operand(ir);
941 LRD(ir) = SIGNEXT8( MEM_READ_BYTE( operand ) );
947 if( LFLAG(ir) ) { /* LDRSH */
948 operand = arm_get_address3_operand(ir);
949 LRD(ir) = SIGNEXT16( MEM_READ_WORD( operand ) );
956 /* Data processing */
959 case 0: /* AND Rd, Rn, operand */
960 LRD(ir) = RN(ir) & arm_get_shift_operand(ir);
962 case 1: /* ANDS Rd, Rn, operand */
963 operand = arm_get_shift_operand_s(ir) & RN(ir);
965 if( RDn(ir) == 15 ) {
968 armr.n = operand>>31;
969 armr.z = (operand == 0);
970 armr.c = armr.shift_c;
973 case 2: /* EOR Rd, Rn, operand */
974 LRD(ir) = RN(ir) ^ arm_get_shift_operand(ir);
976 case 3: /* EORS Rd, Rn, operand */
977 operand = arm_get_shift_operand_s(ir) ^ RN(ir);
979 if( RDn(ir) == 15 ) {
982 armr.n = operand>>31;
983 armr.z = (operand == 0);
984 armr.c = armr.shift_c;
987 case 4: /* SUB Rd, Rn, operand */
988 LRD(ir) = RN(ir) - arm_get_shift_operand(ir);
990 case 5: /* SUBS Rd, Rn, operand */
992 operand2 = arm_get_shift_operand(ir);
993 tmp = operand - operand2;
995 if( RDn(ir) == 15 ) {
1000 armr.c = IS_NOTBORROW(tmp,operand,operand2);
1001 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
1004 case 6: /* RSB Rd, operand, Rn */
1005 LRD(ir) = arm_get_shift_operand(ir) - RN(ir);
1007 case 7: /* RSBS Rd, operand, Rn */
1008 operand = arm_get_shift_operand(ir);
1010 tmp = operand - operand2;
1012 if( RDn(ir) == 15 ) {
1016 armr.z = (tmp == 0);
1017 armr.c = IS_NOTBORROW(tmp,operand,operand2);
1018 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
1021 case 8: /* ADD Rd, Rn, operand */
1022 LRD(ir) = RN(ir) + arm_get_shift_operand(ir);
1024 case 9: /* ADDS Rd, Rn, operand */
1025 operand = arm_get_shift_operand(ir);
1027 tmp = operand + operand2;
1029 if( RDn(ir) == 15 ) {
1033 armr.z = (tmp == 0);
1034 armr.c = IS_CARRY(tmp,operand,operand2);
1035 armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
1039 LRD(ir) = RN(ir) + arm_get_shift_operand(ir) +
1043 operand = arm_get_shift_operand(ir);
1045 tmp = operand + operand2;
1046 tmp2 = tmp + armr.c ? 1 : 0;
1048 if( RDn(ir) == 15 ) {
1052 armr.z = (tmp == 0 );
1053 armr.c = IS_CARRY(tmp,operand,operand2) ||
1055 armr.v = IS_ADDOVERFLOW(tmp,operand, operand2) ||
1056 ((tmp&0x80000000) != (tmp2&0x80000000));
1060 LRD(ir) = RN(ir) - arm_get_shift_operand(ir) -
1065 operand2 = arm_get_shift_operand(ir);
1066 tmp = operand - operand2;
1067 tmp2 = tmp - (armr.c ? 0 : 1);
1068 if( RDn(ir) == 15 ) {
1072 armr.z = (tmp == 0 );
1073 armr.c = IS_NOTBORROW(tmp,operand,operand2) &&
1075 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2) ||
1076 ((tmp&0x80000000) != (tmp2&0x80000000));
1080 LRD(ir) = arm_get_shift_operand(ir) - RN(ir) -
1084 operand = arm_get_shift_operand(ir);
1086 tmp = operand - operand2;
1087 tmp2 = tmp - (armr.c ? 0 : 1);
1088 if( RDn(ir) == 15 ) {
1092 armr.z = (tmp == 0 );
1093 armr.c = IS_NOTBORROW(tmp,operand,operand2) &&
1095 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2) ||
1096 ((tmp&0x80000000) != (tmp2&0x80000000));
1099 case 17: /* TST Rn, operand */
1100 operand = arm_get_shift_operand_s(ir) & RN(ir);
1101 armr.n = operand>>31;
1102 armr.z = (operand == 0);
1103 armr.c = armr.shift_c;
1105 case 19: /* TEQ Rn, operand */
1106 operand = arm_get_shift_operand_s(ir) ^ RN(ir);
1107 armr.n = operand>>31;
1108 armr.z = (operand == 0);
1109 armr.c = armr.shift_c;
1111 case 21: /* CMP Rn, operand */
1113 operand2 = arm_get_shift_operand(ir);
1114 tmp = operand - operand2;
1116 armr.z = (tmp == 0);
1117 armr.c = IS_NOTBORROW(tmp,operand,operand2);
1118 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
1120 case 23: /* CMN Rn, operand */
1122 operand2 = arm_get_shift_operand(ir);
1123 tmp = operand + operand2;
1125 armr.z = (tmp == 0);
1126 armr.c = IS_CARRY(tmp,operand,operand2);
1127 armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
1129 case 24: /* ORR Rd, Rn, operand */
1130 LRD(ir) = RN(ir) | arm_get_shift_operand(ir);
1132 case 25: /* ORRS Rd, Rn, operand */
1133 operand = arm_get_shift_operand_s(ir) | RN(ir);
1135 if( RDn(ir) == 15 ) {
1138 armr.n = operand>>31;
1139 armr.z = (operand == 0);
1140 armr.c = armr.shift_c;
1143 case 26: /* MOV Rd, operand */
1144 LRD(ir) = arm_get_shift_operand(ir);
1146 case 27: /* MOVS Rd, operand */
1147 operand = arm_get_shift_operand_s(ir);
1149 if( RDn(ir) == 15 ) {
1152 armr.n = operand>>31;
1153 armr.z = (operand == 0);
1154 armr.c = armr.shift_c;
1157 case 28: /* BIC Rd, Rn, operand */
1158 LRD(ir) = RN(ir) & (~arm_get_shift_operand(ir));
1160 case 29: /* BICS Rd, Rn, operand */
1161 operand = RN(ir) & (~arm_get_shift_operand_s(ir));
1163 if( RDn(ir) == 15 ) {
1166 armr.n = operand>>31;
1167 armr.z = (operand == 0);
1168 armr.c = armr.shift_c;
1171 case 30: /* MVN Rd, operand */
1172 LRD(ir) = ~arm_get_shift_operand(ir);
1174 case 31: /* MVNS Rd, operand */
1175 operand = ~arm_get_shift_operand_s(ir);
1177 if( RDn(ir) == 15 ) {
1180 armr.n = operand>>31;
1181 armr.z = (operand == 0);
1182 armr.c = armr.shift_c;
1190 case 1: /* Load/store */
1191 operand = arm_get_address_operand(ir);
1192 switch( (ir>>20)&0x17 ) {
1193 case 0: case 16: case 18: /* STR Rd, address */
1194 arm_write_long( operand, RD(ir) );
1196 case 1: case 17: case 19: /* LDR Rd, address */
1197 LRD(ir) = arm_read_long(operand);
1199 case 2: /* STRT Rd, address */
1200 arm_write_long_user( operand, RD(ir) );
1202 case 3: /* LDRT Rd, address */
1203 LRD(ir) = arm_read_long_user( operand );
1205 case 4: case 20: case 22: /* STRB Rd, address */
1206 arm_write_byte( operand, RD(ir) );
1208 case 5: case 21: case 23: /* LDRB Rd, address */
1209 LRD(ir) = arm_read_byte( operand );
1211 case 6: /* STRBT Rd, address */
1212 arm_write_byte_user( operand, RD(ir) );
1214 case 7: /* LDRBT Rd, address */
1215 LRD(ir) = arm_read_byte_user( operand );
1219 case 2: /* Load/store multiple, branch*/
1220 if( (ir & 0x02000000) == 0x02000000 ) { /* B[L] imm24 */
1221 operand = (SIGNEXT24(ir&0x00FFFFFF) << 2);
1222 if( (ir & 0x01000000) == 0x01000000 ) {
1223 armr.r[14] = pc; /* BL */
1225 armr.r[15] = pc + 4 + operand;
1226 } else { /* Load/store multiple */
1227 gboolean needRestore = FALSE;
1230 switch( (ir & 0x01D00000) >> 20 ) {
1233 arm_write_long( operand, armr.r[15]+4 );
1236 for( i=14; i>= 0; i-- ) {
1237 if( (ir & (1<<i)) ) {
1238 arm_write_long( operand, armr.r[i] );
1244 for( i=15; i>= 0; i-- ) {
1245 if( (ir & (1<<i)) ) {
1246 armr.r[i] = arm_read_long( operand );
1251 case 4: /* STMDA (S) */
1253 arm_write_long( operand, armr.r[15]+4 );
1256 for( i=14; i>= 0; i-- ) {
1257 if( (ir & (1<<i)) ) {
1258 arm_write_long( operand, USER_R(i) );
1263 case 5: /* LDMDA (S) */
1264 if( (ir&0x00008000) ) { /* Load PC */
1265 for( i=15; i>= 0; i-- ) {
1266 if( (ir & (1<<i)) ) {
1267 armr.r[i] = arm_read_long( operand );
1273 for( i=15; i>= 0; i-- ) {
1274 if( (ir & (1<<i)) ) {
1275 USER_R(i) = arm_read_long( operand );
1282 for( i=0; i< 15; i++ ) {
1283 if( (ir & (1<<i)) ) {
1284 arm_write_long( operand, armr.r[i] );
1289 arm_write_long( operand, armr.r[15]+4 );
1294 for( i=0; i< 16; i++ ) {
1295 if( (ir & (1<<i)) ) {
1296 armr.r[i] = arm_read_long( operand );
1301 case 12: /* STMIA (S) */
1302 for( i=0; i< 15; i++ ) {
1303 if( (ir & (1<<i)) ) {
1304 arm_write_long( operand, USER_R(i) );
1309 arm_write_long( operand, armr.r[15]+4 );
1313 case 13: /* LDMIA (S) */
1314 if( (ir&0x00008000) ) { /* Load PC */
1315 for( i=0; i < 16; i++ ) {
1316 if( (ir & (1<<i)) ) {
1317 armr.r[i] = arm_read_long( operand );
1323 for( i=0; i < 16; i++ ) {
1324 if( (ir & (1<<i)) ) {
1325 USER_R(i) = arm_read_long( operand );
1331 case 16: /* STMDB */
1334 arm_write_long( operand, armr.r[15]+4 );
1336 for( i=14; i>= 0; i-- ) {
1337 if( (ir & (1<<i)) ) {
1339 arm_write_long( operand, armr.r[i] );
1343 case 17: /* LDMDB */
1344 for( i=15; i>= 0; i-- ) {
1345 if( (ir & (1<<i)) ) {
1347 armr.r[i] = arm_read_long( operand );
1351 case 20: /* STMDB (S) */
1354 arm_write_long( operand, armr.r[15]+4 );
1356 for( i=14; i>= 0; i-- ) {
1357 if( (ir & (1<<i)) ) {
1359 arm_write_long( operand, USER_R(i) );
1363 case 21: /* LDMDB (S) */
1364 if( (ir&0x00008000) ) { /* Load PC */
1365 for( i=15; i>= 0; i-- ) {
1366 if( (ir & (1<<i)) ) {
1368 armr.r[i] = arm_read_long( operand );
1373 for( i=15; i>= 0; i-- ) {
1374 if( (ir & (1<<i)) ) {
1376 USER_R(i) = arm_read_long( operand );
1381 case 24: /* STMIB */
1382 for( i=0; i< 15; i++ ) {
1383 if( (ir & (1<<i)) ) {
1385 arm_write_long( operand, armr.r[i] );
1390 arm_write_long( operand, armr.r[15]+4 );
1393 case 25: /* LDMIB */
1394 for( i=0; i< 16; i++ ) {
1395 if( (ir & (1<<i)) ) {
1397 armr.r[i] = arm_read_long( operand );
1401 case 28: /* STMIB (S) */
1402 for( i=0; i< 15; i++ ) {
1403 if( (ir & (1<<i)) ) {
1405 arm_write_long( operand, USER_R(i) );
1410 arm_write_long( operand, armr.r[15]+4 );
1413 case 29: /* LDMIB (S) */
1414 if( (ir&0x00008000) ) { /* Load PC */
1415 for( i=0; i < 16; i++ ) {
1416 if( (ir & (1<<i)) ) {
1418 armr.r[i] = arm_read_long( operand );
1423 for( i=0; i < 16; i++ ) {
1424 if( (ir & (1<<i)) ) {
1426 USER_R(i) = arm_read_long( operand );
1440 if( (ir & 0x0F000000) == 0x0F000000 ) { /* SWI */
1441 arm_raise_exception( EXC_SOFTWARE );
1450 if( armr.r[15] >= 0x00200000 ) {
1451 armr.running = FALSE;
1452 WARN( "ARM Halted: BRANCH to invalid address %08X at %08X", armr.r[15], pc );
.