filename | src/aica/armcore.c |
changeset | 814:f1a21df54e19 |
prev | 811:7ff871670e58 |
next | 1065:bc1cc0c54917 |
author | nkeynes |
date | Wed Jan 07 04:39:58 2009 +0000 (15 years ago) |
branch | lxdream-mem |
permissions | -rw-r--r-- |
last change | Add missed file from previous commit - remove sh4_translate_flush_cache, change exit to use pre-recovery |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
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 "dreamcast.h"
22 #include "clock.h"
23 #include "mem.h"
24 #include "aica/armcore.h"
25 #include "aica/aica.h"
27 #define STM_R15_OFFSET 12
29 struct arm_registers armr;
31 void arm_set_mode( int mode );
33 uint32_t arm_exceptions[][2] = {{ MODE_SVC, 0x00000000 },
34 { MODE_UND, 0x00000004 },
35 { MODE_SVC, 0x00000008 },
36 { MODE_ABT, 0x0000000C },
37 { MODE_ABT, 0x00000010 },
38 { MODE_IRQ, 0x00000018 },
39 { MODE_FIQ, 0x0000001C } };
41 #define EXC_RESET 0
42 #define EXC_UNDEFINED 1
43 #define EXC_SOFTWARE 2
44 #define EXC_PREFETCH_ABORT 3
45 #define EXC_DATA_ABORT 4
46 #define EXC_IRQ 5
47 #define EXC_FAST_IRQ 6
49 uint32_t arm_cpu_freq = ARM_BASE_RATE;
50 uint32_t arm_cpu_period = 1000 / ARM_BASE_RATE;
52 #define CYCLES_PER_SAMPLE ((ARM_BASE_RATE * 1000000) / AICA_SAMPLE_RATE)
54 static struct breakpoint_struct arm_breakpoints[MAX_BREAKPOINTS];
55 static int arm_breakpoint_count = 0;
57 void arm_set_breakpoint( uint32_t pc, breakpoint_type_t type )
58 {
59 arm_breakpoints[arm_breakpoint_count].address = pc;
60 arm_breakpoints[arm_breakpoint_count].type = type;
61 arm_breakpoint_count++;
62 }
64 gboolean arm_clear_breakpoint( uint32_t pc, breakpoint_type_t type )
65 {
66 int i;
68 for( i=0; i<arm_breakpoint_count; i++ ) {
69 if( arm_breakpoints[i].address == pc &&
70 arm_breakpoints[i].type == type ) {
71 while( ++i < arm_breakpoint_count ) {
72 arm_breakpoints[i-1].address = arm_breakpoints[i].address;
73 arm_breakpoints[i-1].type = arm_breakpoints[i].type;
74 }
75 arm_breakpoint_count--;
76 return TRUE;
77 }
78 }
79 return FALSE;
80 }
82 int arm_get_breakpoint( uint32_t pc )
83 {
84 int i;
85 for( i=0; i<arm_breakpoint_count; i++ ) {
86 if( arm_breakpoints[i].address == pc )
87 return arm_breakpoints[i].type;
88 }
89 return 0;
90 }
92 uint32_t arm_run_slice( uint32_t num_samples )
93 {
94 int i,j,k;
96 if( !armr.running )
97 return num_samples;
99 for( i=0; i<num_samples; i++ ) {
100 for( j=0; j < CYCLES_PER_SAMPLE; j++ ) {
101 armr.icount++;
102 if( !arm_execute_instruction() )
103 return i;
104 #ifdef ENABLE_DEBUG_MODE
105 for( k=0; k<arm_breakpoint_count; k++ ) {
106 if( arm_breakpoints[k].address == armr.r[15] ) {
107 dreamcast_stop();
108 if( arm_breakpoints[k].type == BREAK_ONESHOT )
109 arm_clear_breakpoint( armr.r[15], BREAK_ONESHOT );
110 return i;
111 }
112 }
113 #endif
114 }
116 k = MMIO_READ( AICA2, AICA_TCR );
117 uint8_t val = MMIO_READ( AICA2, AICA_TIMER );
118 val++;
119 if( val == 0 ) {
120 aica_event( AICA_EVENT_TIMER );
121 // MMIO_WRITE( AICA2, AICA_TCR, k & ~0x40 );
122 }
123 MMIO_WRITE( AICA2, AICA_TIMER, val );
124 if( !dreamcast_is_running() )
125 break;
126 }
128 return i;
129 }
131 void arm_save_state( FILE *f )
132 {
133 fwrite( &armr, sizeof(armr), 1, f );
134 }
136 int arm_load_state( FILE *f )
137 {
138 fread( &armr, sizeof(armr), 1, f );
139 return 0;
140 }
142 /* Exceptions */
143 void arm_reset( void )
144 {
145 /* Wipe all processor state */
146 memset( &armr, 0, sizeof(armr) );
148 armr.cpsr = MODE_SVC | CPSR_I | CPSR_F;
149 armr.r[15] = 0x00000000;
150 armr.running = TRUE;
151 }
153 #define SET_CPSR_CONTROL 0x00010000
154 #define SET_CPSR_EXTENSION 0x00020000
155 #define SET_CPSR_STATUS 0x00040000
156 #define SET_CPSR_FLAGS 0x00080000
158 uint32_t arm_get_cpsr( void )
159 {
160 /* write back all flags to the cpsr */
161 armr.cpsr = armr.cpsr & CPSR_COMPACT_MASK;
162 if( armr.n ) armr.cpsr |= CPSR_N;
163 if( armr.z ) armr.cpsr |= CPSR_Z;
164 if( armr.c ) armr.cpsr |= CPSR_C;
165 if( armr.v ) armr.cpsr |= CPSR_V;
166 if( armr.t ) armr.cpsr |= CPSR_T;
167 return armr.cpsr;
168 }
170 /**
171 * Return a pointer to the specified register in the user bank,
172 * regardless of the active bank
173 */
174 static uint32_t *arm_user_reg( int reg )
175 {
176 if( IS_EXCEPTION_MODE() ) {
177 if( reg == 13 || reg == 14 )
178 return &armr.user_r[reg-8];
179 if( IS_FIQ_MODE() ) {
180 if( reg >= 8 || reg <= 12 )
181 return &armr.user_r[reg-8];
182 }
183 }
184 return &armr.r[reg];
185 }
187 #define USER_R(n) *arm_user_reg(n)
189 /**
190 * Set the CPSR to the specified value.
191 *
192 * @param value values to set in CPSR
193 * @param fields set of mask values to define which sections of the
194 * CPSR to set (one of the SET_CPSR_* values above)
195 */
196 void arm_set_cpsr( uint32_t value, uint32_t fields )
197 {
198 if( IS_PRIVILEGED_MODE() ) {
199 if( fields & SET_CPSR_CONTROL ) {
200 int mode = value & CPSR_MODE;
201 arm_set_mode( mode );
202 armr.t = ( value & CPSR_T ); /* Technically illegal to change */
203 armr.cpsr = (armr.cpsr & 0xFFFFFF00) | (value & 0x000000FF);
204 }
206 /* Middle 16 bits not currently defined */
207 }
208 if( fields & SET_CPSR_FLAGS ) {
209 /* Break flags directly out of given value - don't bother writing
210 * back to CPSR
211 */
212 armr.n = ( value & CPSR_N );
213 armr.z = ( value & CPSR_Z );
214 armr.c = ( value & CPSR_C );
215 armr.v = ( value & CPSR_V );
216 }
217 }
219 void arm_set_spsr( uint32_t value, uint32_t fields )
220 {
221 /* Only defined if we actually have an SPSR register */
222 if( IS_EXCEPTION_MODE() ) {
223 if( fields & SET_CPSR_CONTROL ) {
224 armr.spsr = (armr.spsr & 0xFFFFFF00) | (value & 0x000000FF);
225 }
227 /* Middle 16 bits not currently defined */
229 if( fields & SET_CPSR_FLAGS ) {
230 armr.spsr = (armr.spsr & 0x00FFFFFF) | (value & 0xFF000000);
231 }
232 }
233 }
235 /**
236 * Raise an ARM exception (other than reset, which uses arm_reset().
237 * @param exception one of the EXC_* exception codes defined above.
238 */
239 void arm_raise_exception( int exception )
240 {
241 int mode = arm_exceptions[exception][0];
242 uint32_t spsr = arm_get_cpsr();
243 arm_set_mode( mode );
244 armr.spsr = spsr;
245 armr.r[14] = armr.r[15] + 4;
246 armr.cpsr = (spsr & 0xFFFFFF00) | mode | CPSR_I;
247 if( mode == MODE_FIQ )
248 armr.cpsr |= CPSR_F;
249 armr.r[15] = arm_exceptions[exception][1];
250 }
252 void arm_restore_cpsr( void )
253 {
254 int spsr = armr.spsr;
255 int mode = spsr & CPSR_MODE;
256 arm_set_mode( mode );
257 armr.cpsr = spsr;
258 armr.n = ( spsr & CPSR_N );
259 armr.z = ( spsr & CPSR_Z );
260 armr.c = ( spsr & CPSR_C );
261 armr.v = ( spsr & CPSR_V );
262 armr.t = ( spsr & CPSR_T );
263 }
267 /**
268 * Change the current executing ARM mode to the requested mode.
269 * Saves any required registers to banks and restores those for the
270 * correct mode. (Note does not actually update CPSR at the moment).
271 */
272 void arm_set_mode( int targetMode )
273 {
274 int currentMode = armr.cpsr & CPSR_MODE;
275 if( currentMode == targetMode )
276 return;
278 switch( currentMode ) {
279 case MODE_USER:
280 case MODE_SYS:
281 armr.user_r[5] = armr.r[13];
282 armr.user_r[6] = armr.r[14];
283 break;
284 case MODE_SVC:
285 armr.svc_r[0] = armr.r[13];
286 armr.svc_r[1] = armr.r[14];
287 armr.svc_r[2] = armr.spsr;
288 break;
289 case MODE_ABT:
290 armr.abt_r[0] = armr.r[13];
291 armr.abt_r[1] = armr.r[14];
292 armr.abt_r[2] = armr.spsr;
293 break;
294 case MODE_UND:
295 armr.und_r[0] = armr.r[13];
296 armr.und_r[1] = armr.r[14];
297 armr.und_r[2] = armr.spsr;
298 break;
299 case MODE_IRQ:
300 armr.irq_r[0] = armr.r[13];
301 armr.irq_r[1] = armr.r[14];
302 armr.irq_r[2] = armr.spsr;
303 break;
304 case MODE_FIQ:
305 armr.fiq_r[0] = armr.r[8];
306 armr.fiq_r[1] = armr.r[9];
307 armr.fiq_r[2] = armr.r[10];
308 armr.fiq_r[3] = armr.r[11];
309 armr.fiq_r[4] = armr.r[12];
310 armr.fiq_r[5] = armr.r[13];
311 armr.fiq_r[6] = armr.r[14];
312 armr.fiq_r[7] = armr.spsr;
313 armr.r[8] = armr.user_r[0];
314 armr.r[9] = armr.user_r[1];
315 armr.r[10] = armr.user_r[2];
316 armr.r[11] = armr.user_r[3];
317 armr.r[12] = armr.user_r[4];
318 break;
319 }
321 switch( targetMode ) {
322 case MODE_USER:
323 case MODE_SYS:
324 armr.r[13] = armr.user_r[5];
325 armr.r[14] = armr.user_r[6];
326 break;
327 case MODE_SVC:
328 armr.r[13] = armr.svc_r[0];
329 armr.r[14] = armr.svc_r[1];
330 armr.spsr = armr.svc_r[2];
331 break;
332 case MODE_ABT:
333 armr.r[13] = armr.abt_r[0];
334 armr.r[14] = armr.abt_r[1];
335 armr.spsr = armr.abt_r[2];
336 break;
337 case MODE_UND:
338 armr.r[13] = armr.und_r[0];
339 armr.r[14] = armr.und_r[1];
340 armr.spsr = armr.und_r[2];
341 break;
342 case MODE_IRQ:
343 armr.r[13] = armr.irq_r[0];
344 armr.r[14] = armr.irq_r[1];
345 armr.spsr = armr.irq_r[2];
346 break;
347 case MODE_FIQ:
348 armr.user_r[0] = armr.r[8];
349 armr.user_r[1] = armr.r[9];
350 armr.user_r[2] = armr.r[10];
351 armr.user_r[3] = armr.r[11];
352 armr.user_r[4] = armr.r[12];
353 armr.r[8] = armr.fiq_r[0];
354 armr.r[9] = armr.fiq_r[1];
355 armr.r[10] = armr.fiq_r[2];
356 armr.r[11] = armr.fiq_r[3];
357 armr.r[12] = armr.fiq_r[4];
358 armr.r[13] = armr.fiq_r[5];
359 armr.r[14] = armr.fiq_r[6];
360 armr.spsr = armr.fiq_r[7];
361 break;
362 }
363 }
365 /* Page references are as per ARM DDI 0100E (June 2000) */
367 #define MEM_READ_BYTE( addr ) arm_read_byte(addr)
368 #define MEM_READ_WORD( addr ) arm_read_word(addr)
369 #define MEM_READ_LONG( addr ) arm_read_long(addr)
370 #define MEM_WRITE_BYTE( addr, val ) arm_write_byte(addr, val)
371 #define MEM_WRITE_WORD( addr, val ) arm_write_word(addr, val)
372 #define MEM_WRITE_LONG( addr, val ) arm_write_long(addr, val)
375 #define IS_NOTBORROW( result, op1, op2 ) (op2 > op1 ? 0 : 1)
376 #define IS_CARRY( result, op1, op2 ) (result < op1 ? 1 : 0)
377 #define IS_SUBOVERFLOW( result, op1, op2 ) (((op1^op2) & (result^op1)) >> 31)
378 #define IS_ADDOVERFLOW( result, op1, op2 ) (((op1&op2) & (result^op1)) >> 31)
380 #define PC armr.r[15]
382 /* Instruction fields */
383 #define COND(ir) (ir>>28)
384 #define GRP(ir) ((ir>>26)&0x03)
385 #define OPCODE(ir) ((ir>>20)&0x1F)
386 #define IFLAG(ir) (ir&0x02000000)
387 #define SFLAG(ir) (ir&0x00100000)
388 #define PFLAG(ir) (ir&0x01000000)
389 #define UFLAG(ir) (ir&0x00800000)
390 #define BFLAG(ir) (ir&0x00400000)
391 #define WFLAG(ir) (ir&0x00200000)
392 #define LFLAG(ir) SFLAG(ir)
393 #define RN(ir) (armr.r[((ir>>16)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
394 #define RD(ir) (armr.r[((ir>>12)&0x0F)] + (((ir>>12)&0x0F) == 0x0F ? 4 : 0))
395 #define RDn(ir) ((ir>>12)&0x0F)
396 #define RS(ir) (armr.r[((ir>>8)&0x0F)] + (((ir>>8)&0x0F) == 0x0F ? 4 : 0))
397 #define RM(ir) (armr.r[(ir&0x0F)] + (((ir&0x0F) == 0x0F ? 4 : 0)) )
398 #define LRN(ir) armr.r[((ir>>16)&0x0F)]
399 #define LRD(ir) armr.r[((ir>>12)&0x0F)]
400 #define LRS(ir) armr.r[((ir>>8)&0x0F)]
401 #define LRM(ir) armr.r[(ir&0x0F)]
403 #define IMM8(ir) (ir&0xFF)
404 #define IMM12(ir) (ir&0xFFF)
405 #define IMMSPLIT8(ir) (((ir&0xF00)>>4)|(ir&0x0F))
406 #define SHIFTIMM(ir) ((ir>>7)&0x1F)
407 #define IMMROT(ir) ((ir>>7)&0x1E)
408 #define ROTIMM12(ir) ROTATE_RIGHT_LONG(IMM8(ir),IMMROT(ir))
409 #define SIGNEXT24(n) (((n)&0x00800000) ? ((n)|0xFF000000) : ((n)&0x00FFFFFF))
410 #define SIGNEXT8(n) ((int32_t)((int8_t)(n)))
411 #define SIGNEXT16(n) ((int32_t)((int16_t)(n)))
412 #define SHIFT(ir) ((ir>>4)&0x07)
413 #define DISP24(ir) ((ir&0x00FFFFFF))
414 #define UNDEF(ir) do{ arm_raise_exception( EXC_UNDEFINED ); return TRUE; } while(0)
415 #define UNIMP(ir) do{ PC-=4; ERROR( "Halted on unimplemented instruction at %08x, opcode = %04x", PC, ir ); dreamcast_stop(); return FALSE; }while(0)
417 /**
418 * Determine the value of the shift-operand for a data processing instruction,
419 * without determing a value for shift_C (optimized form for instructions that
420 * don't require shift_C ).
421 * @see s5.1 Addressing Mode 1 - Data-processing operands (p A5-2, 218)
422 */
423 static uint32_t arm_get_shift_operand( uint32_t ir )
424 {
425 uint32_t operand, tmp;
426 if( IFLAG(ir) == 0 ) {
427 operand = RM(ir);
428 switch(SHIFT(ir)) {
429 case 0: /* (Rm << imm) */
430 operand = operand << SHIFTIMM(ir);
431 break;
432 case 1: /* (Rm << Rs) */
433 tmp = RS(ir)&0xFF;
434 if( tmp > 31 ) operand = 0;
435 else operand = operand << tmp;
436 break;
437 case 2: /* (Rm >> imm) */
438 operand = operand >> SHIFTIMM(ir);
439 break;
440 case 3: /* (Rm >> Rs) */
441 tmp = RS(ir) & 0xFF;
442 if( tmp > 31 ) operand = 0;
443 else operand = operand >> ir;
444 break;
445 case 4: /* (Rm >>> imm) */
446 tmp = SHIFTIMM(ir);
447 if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
448 else operand = ((int32_t)operand) >> tmp;
449 break;
450 case 5: /* (Rm >>> Rs) */
451 tmp = RS(ir) & 0xFF;
452 if( tmp > 31 ) operand = ((int32_t)operand) >> 31;
453 else operand = ((int32_t)operand) >> tmp;
454 break;
455 case 6:
456 tmp = SHIFTIMM(ir);
457 if( tmp == 0 ) /* RRX aka rotate with carry */
458 operand = (operand >> 1) | (armr.c<<31);
459 else
460 operand = ROTATE_RIGHT_LONG(operand,tmp);
461 break;
462 case 7:
463 tmp = RS(ir)&0x1F;
464 operand = ROTATE_RIGHT_LONG(operand,tmp);
465 break;
466 }
467 } else {
468 operand = IMM8(ir);
469 tmp = IMMROT(ir);
470 operand = ROTATE_RIGHT_LONG(operand, tmp);
471 }
472 return operand;
473 }
475 /**
476 * Determine the value of the shift-operand for a data processing instruction,
477 * and set armr.shift_c accordingly.
478 * @see s5.1 Addressing Mode 1 - Data-processing operands (p A5-2, 218)
479 */
480 static uint32_t arm_get_shift_operand_s( uint32_t ir )
481 {
482 uint32_t operand, tmp;
483 if( IFLAG(ir) == 0 ) {
484 operand = RM(ir);
485 switch(SHIFT(ir)) {
486 case 0: /* (Rm << imm) */
487 tmp = SHIFTIMM(ir);
488 if( tmp == 0 ) { /* Rm */
489 armr.shift_c = armr.c;
490 } else { /* Rm << imm */
491 armr.shift_c = (operand >> (32-tmp)) & 0x01;
492 operand = operand << tmp;
493 }
494 break;
495 case 1: /* (Rm << Rs) */
496 tmp = RS(ir)&0xFF;
497 if( tmp == 0 ) {
498 armr.shift_c = armr.c;
499 } else {
500 if( tmp <= 32 )
501 armr.shift_c = (operand >> (32-tmp)) & 0x01;
502 else armr.shift_c = 0;
503 if( tmp < 32 )
504 operand = operand << tmp;
505 else operand = 0;
506 }
507 break;
508 case 2: /* (Rm >> imm) */
509 tmp = SHIFTIMM(ir);
510 if( tmp == 0 ) {
511 armr.shift_c = operand >> 31;
512 operand = 0;
513 } else {
514 armr.shift_c = (operand >> (tmp-1)) & 0x01;
515 operand = RM(ir) >> tmp;
516 }
517 break;
518 case 3: /* (Rm >> Rs) */
519 tmp = RS(ir) & 0xFF;
520 if( tmp == 0 ) {
521 armr.shift_c = armr.c;
522 } else {
523 if( tmp <= 32 )
524 armr.shift_c = (operand >> (tmp-1))&0x01;
525 else armr.shift_c = 0;
526 if( tmp < 32 )
527 operand = operand >> tmp;
528 else operand = 0;
529 }
530 break;
531 case 4: /* (Rm >>> imm) */
532 tmp = SHIFTIMM(ir);
533 if( tmp == 0 ) {
534 armr.shift_c = operand >> 31;
535 operand = -armr.shift_c;
536 } else {
537 armr.shift_c = (operand >> (tmp-1)) & 0x01;
538 operand = ((int32_t)operand) >> tmp;
539 }
540 break;
541 case 5: /* (Rm >>> Rs) */
542 tmp = RS(ir) & 0xFF;
543 if( tmp == 0 ) {
544 armr.shift_c = armr.c;
545 } else {
546 if( tmp < 32 ) {
547 armr.shift_c = (operand >> (tmp-1))&0x01;
548 operand = ((int32_t)operand) >> tmp;
549 } else {
550 armr.shift_c = operand >> 31;
551 operand = ((int32_t)operand) >> 31;
552 }
553 }
554 break;
555 case 6:
556 tmp = SHIFTIMM(ir);
557 if( tmp == 0 ) { /* RRX aka rotate with carry */
558 armr.shift_c = operand&0x01;
559 operand = (operand >> 1) | (armr.c<<31);
560 } else {
561 armr.shift_c = operand>>(tmp-1);
562 operand = ROTATE_RIGHT_LONG(operand,tmp);
563 }
564 break;
565 case 7:
566 tmp = RS(ir)&0xFF;
567 if( tmp == 0 ) {
568 armr.shift_c = armr.c;
569 } else {
570 tmp &= 0x1F;
571 if( tmp == 0 ) {
572 armr.shift_c = operand>>31;
573 } else {
574 armr.shift_c = (operand>>(tmp-1))&0x1;
575 operand = ROTATE_RIGHT_LONG(operand,tmp);
576 }
577 }
578 break;
579 }
580 } else {
581 operand = IMM8(ir);
582 tmp = IMMROT(ir);
583 if( tmp == 0 ) {
584 armr.shift_c = armr.c;
585 } else {
586 operand = ROTATE_RIGHT_LONG(operand, tmp);
587 armr.shift_c = operand>>31;
588 }
589 }
590 return operand;
591 }
593 /**
594 * Another variant of the shifter code for index-based memory addressing.
595 * Distinguished by the fact that it doesn't support register shifts, and
596 * ignores the I flag (WTF do the load/store instructions use the I flag to
597 * mean the _exact opposite_ of what it means for the data processing
598 * instructions ???)
599 */
600 static uint32_t arm_get_address_index( uint32_t ir )
601 {
602 uint32_t operand = RM(ir);
603 uint32_t tmp;
605 switch(SHIFT(ir)) {
606 case 0: /* (Rm << imm) */
607 operand = operand << SHIFTIMM(ir);
608 break;
609 case 2: /* (Rm >> imm) */
610 operand = operand >> SHIFTIMM(ir);
611 break;
612 case 4: /* (Rm >>> imm) */
613 tmp = SHIFTIMM(ir);
614 if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
615 else operand = ((int32_t)operand) >> tmp;
616 break;
617 case 6:
618 tmp = SHIFTIMM(ir);
619 if( tmp == 0 ) /* RRX aka rotate with carry */
620 operand = (operand >> 1) | (armr.c<<31);
621 else
622 operand = ROTATE_RIGHT_LONG(operand,tmp);
623 break;
624 default: UNIMP(ir);
625 }
626 return operand;
627 }
629 /**
630 * Determine the address operand of a load/store instruction, including
631 * applying any pre/post adjustments to the address registers.
632 * @see s5.2 Addressing Mode 2 - Load and Store Word or Unsigned Byte
633 * @param The instruction word.
634 * @return The calculated address
635 */
636 static uint32_t arm_get_address_operand( uint32_t ir )
637 {
638 uint32_t addr=0;
640 /* I P U . W */
641 switch( (ir>>21)&0x1D ) {
642 case 0: /* Rn -= imm offset (post-indexed) [5.2.8 A5-28] */
643 case 1:
644 addr = RN(ir);
645 LRN(ir) = addr - IMM12(ir);
646 break;
647 case 4: /* Rn += imm offsett (post-indexed) [5.2.8 A5-28] */
648 case 5:
649 addr = RN(ir);
650 LRN(ir) = addr + IMM12(ir);
651 break;
652 case 8: /* Rn - imm offset [5.2.2 A5-20] */
653 addr = RN(ir) - IMM12(ir);
654 break;
655 case 9: /* Rn -= imm offset (pre-indexed) [5.2.5 A5-24] */
656 addr = RN(ir) - IMM12(ir);
657 LRN(ir) = addr;
658 break;
659 case 12: /* Rn + imm offset [5.2.2 A5-20] */
660 addr = RN(ir) + IMM12(ir);
661 break;
662 case 13: /* Rn += imm offset [5.2.5 A5-24 ] */
663 addr = RN(ir) + IMM12(ir);
664 LRN(ir) = addr;
665 break;
666 case 16: /* Rn -= Rm (post-indexed) [5.2.10 A5-32 ] */
667 case 17:
668 addr = RN(ir);
669 LRN(ir) = addr - arm_get_address_index(ir);
670 break;
671 case 20: /* Rn += Rm (post-indexed) [5.2.10 A5-32 ] */
672 case 21:
673 addr = RN(ir);
674 LRN(ir) = addr - arm_get_address_index(ir);
675 break;
676 case 24: /* Rn - Rm [5.2.4 A5-23] */
677 addr = RN(ir) - arm_get_address_index(ir);
678 break;
679 case 25: /* RN -= Rm (pre-indexed) [5.2.7 A5-26] */
680 addr = RN(ir) - arm_get_address_index(ir);
681 LRN(ir) = addr;
682 break;
683 case 28: /* Rn + Rm [5.2.4 A5-23] */
684 addr = RN(ir) + arm_get_address_index(ir);
685 break;
686 case 29: /* RN += Rm (pre-indexed) [5.2.7 A5-26] */
687 addr = RN(ir) + arm_get_address_index(ir);
688 LRN(ir) = addr;
689 break;
690 }
691 return addr;
692 }
694 /**
695 * Determine the address operand of a miscellaneous load/store instruction,
696 * including applying any pre/post adjustments to the address registers.
697 * @see s5.3 Addressing Mode 3 - Miscellaneous Loads and Stores
698 * @param The instruction word.
699 * @return The calculated address
700 */
701 static uint32_t arm_get_address3_operand( uint32_t ir )
702 {
703 uint32_t addr=0;
705 /* x x P U x W */
706 switch( (ir>>21)&0x0F ) {
707 case 0: /* Rn -= Rm (post-indexed) [5.3.7 A5-48] */
708 case 1: /* UNPREDICTABLE */
709 addr = RN(ir);
710 LRN(ir) -= RM(ir);
711 break;
712 case 2: /* Rn -= imm (post-indexed) [5.3.6 A5-46] */
713 case 3: /* UNPREDICTABLE */
714 addr = RN(ir);
715 LRN(ir) -= IMMSPLIT8(ir);
716 break;
717 case 4: /* Rn += Rm (post-indexed) [5.3.7 A5-48] */
718 case 5: /* UNPREDICTABLE */
719 addr = RN(ir);
720 LRN(ir) += RM(ir);
721 break;
722 case 6: /* Rn += imm (post-indexed) [5.3.6 A5-44] */
723 case 7: /* UNPREDICTABLE */
724 addr = RN(ir);
725 LRN(ir) += IMMSPLIT8(ir);
726 break;
727 case 8: /* Rn - Rm [5.3.3 A5-38] */
728 addr = RN(ir) - RM(ir);
729 break;
730 case 9: /* Rn -= Rm (pre-indexed) [5.3.5 A5-42] */
731 addr = RN(ir) - RM(ir);
732 LRN(ir) = addr;
733 break;
734 case 10: /* Rn - imm offset [5.3.2 A5-36] */
735 addr = RN(ir) - IMMSPLIT8(ir);
736 break;
737 case 11: /* Rn -= imm offset (pre-indexed) [5.3.4 A5-40] */
738 addr = RN(ir) - IMMSPLIT8(ir);
739 LRN(ir) = addr;
740 break;
741 case 12: /* Rn + Rm [5.3.3 A5-38] */
742 addr = RN(ir) + RM(ir);
743 break;
744 case 13: /* Rn += Rm (pre-indexed) [5.3.5 A5-42] */
745 addr = RN(ir) + RM(ir);
746 LRN(ir) = addr;
747 break;
748 case 14: /* Rn + imm offset [5.3.2 A5-36] */
749 addr = RN(ir) + IMMSPLIT8(ir);
750 break;
751 case 15: /* Rn += imm offset (pre-indexed) [5.3.4 A5-40] */
752 addr = RN(ir) + IMMSPLIT8(ir);
753 LRN(ir) = addr;
754 break;
756 }
757 return addr;
758 }
760 gboolean arm_execute_instruction( void )
761 {
762 uint32_t pc;
763 uint32_t ir;
764 uint32_t operand, operand2, tmp, tmp2, cond;
765 int i;
767 tmp = armr.int_pending & (~armr.cpsr);
768 if( tmp ) {
769 if( tmp & CPSR_F ) {
770 arm_raise_exception( EXC_FAST_IRQ );
771 } else {
772 arm_raise_exception( EXC_IRQ );
773 }
774 }
776 ir = MEM_READ_LONG(PC);
777 pc = PC + 4;
778 PC = pc;
780 /**
781 * Check the condition bits first - if the condition fails return
782 * immediately without actually looking at the rest of the instruction.
783 */
784 switch( COND(ir) ) {
785 case 0: /* EQ */
786 cond = armr.z;
787 break;
788 case 1: /* NE */
789 cond = !armr.z;
790 break;
791 case 2: /* CS/HS */
792 cond = armr.c;
793 break;
794 case 3: /* CC/LO */
795 cond = !armr.c;
796 break;
797 case 4: /* MI */
798 cond = armr.n;
799 break;
800 case 5: /* PL */
801 cond = !armr.n;
802 break;
803 case 6: /* VS */
804 cond = armr.v;
805 break;
806 case 7: /* VC */
807 cond = !armr.v;
808 break;
809 case 8: /* HI */
810 cond = armr.c && !armr.z;
811 break;
812 case 9: /* LS */
813 cond = (!armr.c) || armr.z;
814 break;
815 case 10: /* GE */
816 cond = (armr.n == armr.v);
817 break;
818 case 11: /* LT */
819 cond = (armr.n != armr.v);
820 break;
821 case 12: /* GT */
822 cond = (!armr.z) && (armr.n == armr.v);
823 break;
824 case 13: /* LE */
825 cond = armr.z || (armr.n != armr.v);
826 break;
827 case 14: /* AL */
828 cond = 1;
829 break;
830 case 15: /* (NV) */
831 default:
832 cond = 0;
833 UNDEF(ir);
834 }
835 if( cond ) {
837 /**
838 * Condition passed, now for the actual instructions...
839 */
840 switch( GRP(ir) ) {
841 case 0:
842 if( (ir & 0x0D900000) == 0x01000000 ) {
843 /* Instructions that aren't actual data processing even though
844 * they sit in the DP instruction block.
845 */
846 switch( ir & 0x0FF000F0 ) {
847 case 0x01200010: /* BX Rd */
848 armr.t = ir & 0x01;
849 armr.r[15] = RM(ir) & 0xFFFFFFFE;
850 break;
851 case 0x01000000: /* MRS Rd, CPSR */
852 LRD(ir) = arm_get_cpsr();
853 break;
854 case 0x01400000: /* MRS Rd, SPSR */
855 LRD(ir) = armr.spsr;
856 break;
857 case 0x01200000: /* MSR CPSR, Rd */
858 arm_set_cpsr( RM(ir), ir );
859 break;
860 case 0x01600000: /* MSR SPSR, Rd */
861 arm_set_spsr( RM(ir), ir );
862 break;
863 case 0x03200000: /* MSR CPSR, imm */
864 arm_set_cpsr( ROTIMM12(ir), ir );
865 break;
866 case 0x03600000: /* MSR SPSR, imm */
867 arm_set_spsr( ROTIMM12(ir), ir );
868 break;
869 default:
870 UNIMP(ir);
871 }
872 } else if( (ir & 0x0E000090) == 0x00000090 ) {
873 /* Neither are these */
874 switch( (ir>>5)&0x03 ) {
875 case 0:
876 /* Arithmetic extension area */
877 switch(OPCODE(ir)) {
878 case 0: /* MUL */
879 LRN(ir) = RM(ir) * RS(ir);
880 break;
881 case 1: /* MULS */
882 tmp = RM(ir) * RS(ir);
883 LRN(ir) = tmp;
884 armr.n = tmp>>31;
885 armr.z = (tmp == 0);
886 break;
887 case 2: /* MLA */
888 LRN(ir) = RM(ir) * RS(ir) + RD(ir);
889 break;
890 case 3: /* MLAS */
891 tmp = RM(ir) * RS(ir) + RD(ir);
892 LRN(ir) = tmp;
893 armr.n = tmp>>31;
894 armr.z = (tmp == 0);
895 break;
896 case 8: /* UMULL */
897 case 9: /* UMULLS */
898 case 10: /* UMLAL */
899 case 11: /* UMLALS */
900 case 12: /* SMULL */
901 case 13: /* SMULLS */
902 case 14: /* SMLAL */
903 case 15: /* SMLALS */
904 UNIMP(ir);
905 break;
906 case 16: /* SWP */
907 tmp = arm_read_long( RN(ir) );
908 switch( RN(ir) & 0x03 ) {
909 case 1:
910 tmp = ROTATE_RIGHT_LONG(tmp, 8);
911 break;
912 case 2:
913 tmp = ROTATE_RIGHT_LONG(tmp, 16);
914 break;
915 case 3:
916 tmp = ROTATE_RIGHT_LONG(tmp, 24);
917 break;
918 }
919 arm_write_long( RN(ir), RM(ir) );
920 LRD(ir) = tmp;
921 break;
922 case 20: /* SWPB */
923 tmp = arm_read_byte( RN(ir) );
924 arm_write_byte( RN(ir), RM(ir) );
925 LRD(ir) = tmp;
926 break;
927 default:
928 UNIMP(ir);
929 }
930 break;
931 case 1:
932 operand = arm_get_address3_operand(ir);
933 if( LFLAG(ir) ) { /* LDRH */
934 LRD(ir) = MEM_READ_WORD( operand ) & 0x0000FFFF;
935 } else { /* STRH */
936 MEM_WRITE_WORD( operand, RD(ir) );
937 }
938 break;
939 case 2:
940 if( LFLAG(ir) ) { /* LDRSB */
941 operand = arm_get_address3_operand(ir);
942 LRD(ir) = SIGNEXT8( MEM_READ_BYTE( operand ) );
943 } else {
944 UNIMP(ir);
945 }
946 break;
947 case 3:
948 if( LFLAG(ir) ) { /* LDRSH */
949 operand = arm_get_address3_operand(ir);
950 LRD(ir) = SIGNEXT16( MEM_READ_WORD( operand ) );
951 } else {
952 UNIMP(ir);
953 }
954 break;
955 }
956 } else {
957 /* Data processing */
959 switch(OPCODE(ir)) {
960 case 0: /* AND Rd, Rn, operand */
961 LRD(ir) = RN(ir) & arm_get_shift_operand(ir);
962 break;
963 case 1: /* ANDS Rd, Rn, operand */
964 operand = arm_get_shift_operand_s(ir) & RN(ir);
965 LRD(ir) = operand;
966 if( RDn(ir) == 15 ) {
967 arm_restore_cpsr();
968 } else {
969 armr.n = operand>>31;
970 armr.z = (operand == 0);
971 armr.c = armr.shift_c;
972 }
973 break;
974 case 2: /* EOR Rd, Rn, operand */
975 LRD(ir) = RN(ir) ^ arm_get_shift_operand(ir);
976 break;
977 case 3: /* EORS Rd, Rn, operand */
978 operand = arm_get_shift_operand_s(ir) ^ RN(ir);
979 LRD(ir) = operand;
980 if( RDn(ir) == 15 ) {
981 arm_restore_cpsr();
982 } else {
983 armr.n = operand>>31;
984 armr.z = (operand == 0);
985 armr.c = armr.shift_c;
986 }
987 break;
988 case 4: /* SUB Rd, Rn, operand */
989 LRD(ir) = RN(ir) - arm_get_shift_operand(ir);
990 break;
991 case 5: /* SUBS Rd, Rn, operand */
992 operand = RN(ir);
993 operand2 = arm_get_shift_operand(ir);
994 tmp = operand - operand2;
995 LRD(ir) = tmp;
996 if( RDn(ir) == 15 ) {
997 arm_restore_cpsr();
998 } else {
999 armr.n = tmp>>31;
1000 armr.z = (tmp == 0);
1001 armr.c = IS_NOTBORROW(tmp,operand,operand2);
1002 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
1003 }
1004 break;
1005 case 6: /* RSB Rd, operand, Rn */
1006 LRD(ir) = arm_get_shift_operand(ir) - RN(ir);
1007 break;
1008 case 7: /* RSBS Rd, operand, Rn */
1009 operand = arm_get_shift_operand(ir);
1010 operand2 = RN(ir);
1011 tmp = operand - operand2;
1012 LRD(ir) = tmp;
1013 if( RDn(ir) == 15 ) {
1014 arm_restore_cpsr();
1015 } else {
1016 armr.n = tmp>>31;
1017 armr.z = (tmp == 0);
1018 armr.c = IS_NOTBORROW(tmp,operand,operand2);
1019 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
1020 }
1021 break;
1022 case 8: /* ADD Rd, Rn, operand */
1023 LRD(ir) = RN(ir) + arm_get_shift_operand(ir);
1024 break;
1025 case 9: /* ADDS Rd, Rn, operand */
1026 operand = arm_get_shift_operand(ir);
1027 operand2 = RN(ir);
1028 tmp = operand + operand2;
1029 LRD(ir) = tmp;
1030 if( RDn(ir) == 15 ) {
1031 arm_restore_cpsr();
1032 } else {
1033 armr.n = tmp>>31;
1034 armr.z = (tmp == 0);
1035 armr.c = IS_CARRY(tmp,operand,operand2);
1036 armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
1037 }
1038 break;
1039 case 10: /* ADC */
1040 LRD(ir) = RN(ir) + arm_get_shift_operand(ir) +
1041 (armr.c ? 1 : 0);
1042 break;
1043 case 11: /* ADCS */
1044 operand = arm_get_shift_operand(ir);
1045 operand2 = RN(ir);
1046 tmp = operand + operand2;
1047 tmp2 = tmp + armr.c ? 1 : 0;
1048 LRD(ir) = tmp2;
1049 if( RDn(ir) == 15 ) {
1050 arm_restore_cpsr();
1051 } else {
1052 armr.n = tmp >> 31;
1053 armr.z = (tmp == 0 );
1054 armr.c = IS_CARRY(tmp,operand,operand2) ||
1055 (tmp2 < tmp);
1056 armr.v = IS_ADDOVERFLOW(tmp,operand, operand2) ||
1057 ((tmp&0x80000000) != (tmp2&0x80000000));
1058 }
1059 break;
1060 case 12: /* SBC */
1061 LRD(ir) = RN(ir) - arm_get_shift_operand(ir) -
1062 (armr.c ? 0 : 1);
1063 break;
1064 case 13: /* SBCS */
1065 operand = RN(ir);
1066 operand2 = arm_get_shift_operand(ir);
1067 tmp = operand - operand2;
1068 tmp2 = tmp - (armr.c ? 0 : 1);
1069 if( RDn(ir) == 15 ) {
1070 arm_restore_cpsr();
1071 } else {
1072 armr.n = tmp >> 31;
1073 armr.z = (tmp == 0 );
1074 armr.c = IS_NOTBORROW(tmp,operand,operand2) &&
1075 (tmp2<tmp);
1076 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2) ||
1077 ((tmp&0x80000000) != (tmp2&0x80000000));
1078 }
1079 break;
1080 case 14: /* RSC */
1081 LRD(ir) = arm_get_shift_operand(ir) - RN(ir) -
1082 (armr.c ? 0 : 1);
1083 break;
1084 case 15: /* RSCS */
1085 operand = arm_get_shift_operand(ir);
1086 operand2 = RN(ir);
1087 tmp = operand - operand2;
1088 tmp2 = tmp - (armr.c ? 0 : 1);
1089 if( RDn(ir) == 15 ) {
1090 arm_restore_cpsr();
1091 } else {
1092 armr.n = tmp >> 31;
1093 armr.z = (tmp == 0 );
1094 armr.c = IS_NOTBORROW(tmp,operand,operand2) &&
1095 (tmp2<tmp);
1096 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2) ||
1097 ((tmp&0x80000000) != (tmp2&0x80000000));
1098 }
1099 break;
1100 case 17: /* TST Rn, operand */
1101 operand = arm_get_shift_operand_s(ir) & RN(ir);
1102 armr.n = operand>>31;
1103 armr.z = (operand == 0);
1104 armr.c = armr.shift_c;
1105 break;
1106 case 19: /* TEQ Rn, operand */
1107 operand = arm_get_shift_operand_s(ir) ^ RN(ir);
1108 armr.n = operand>>31;
1109 armr.z = (operand == 0);
1110 armr.c = armr.shift_c;
1111 break;
1112 case 21: /* CMP Rn, operand */
1113 operand = RN(ir);
1114 operand2 = arm_get_shift_operand(ir);
1115 tmp = operand - operand2;
1116 armr.n = tmp>>31;
1117 armr.z = (tmp == 0);
1118 armr.c = IS_NOTBORROW(tmp,operand,operand2);
1119 armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
1120 break;
1121 case 23: /* CMN Rn, operand */
1122 operand = RN(ir);
1123 operand2 = arm_get_shift_operand(ir);
1124 tmp = operand + operand2;
1125 armr.n = tmp>>31;
1126 armr.z = (tmp == 0);
1127 armr.c = IS_CARRY(tmp,operand,operand2);
1128 armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
1129 break;
1130 case 24: /* ORR Rd, Rn, operand */
1131 LRD(ir) = RN(ir) | arm_get_shift_operand(ir);
1132 break;
1133 case 25: /* ORRS Rd, Rn, operand */
1134 operand = arm_get_shift_operand_s(ir) | RN(ir);
1135 LRD(ir) = operand;
1136 if( RDn(ir) == 15 ) {
1137 arm_restore_cpsr();
1138 } else {
1139 armr.n = operand>>31;
1140 armr.z = (operand == 0);
1141 armr.c = armr.shift_c;
1142 }
1143 break;
1144 case 26: /* MOV Rd, operand */
1145 LRD(ir) = arm_get_shift_operand(ir);
1146 break;
1147 case 27: /* MOVS Rd, operand */
1148 operand = arm_get_shift_operand_s(ir);
1149 LRD(ir) = operand;
1150 if( RDn(ir) == 15 ) {
1151 arm_restore_cpsr();
1152 } else {
1153 armr.n = operand>>31;
1154 armr.z = (operand == 0);
1155 armr.c = armr.shift_c;
1156 }
1157 break;
1158 case 28: /* BIC Rd, Rn, operand */
1159 LRD(ir) = RN(ir) & (~arm_get_shift_operand(ir));
1160 break;
1161 case 29: /* BICS Rd, Rn, operand */
1162 operand = RN(ir) & (~arm_get_shift_operand_s(ir));
1163 LRD(ir) = operand;
1164 if( RDn(ir) == 15 ) {
1165 arm_restore_cpsr();
1166 } else {
1167 armr.n = operand>>31;
1168 armr.z = (operand == 0);
1169 armr.c = armr.shift_c;
1170 }
1171 break;
1172 case 30: /* MVN Rd, operand */
1173 LRD(ir) = ~arm_get_shift_operand(ir);
1174 break;
1175 case 31: /* MVNS Rd, operand */
1176 operand = ~arm_get_shift_operand_s(ir);
1177 LRD(ir) = operand;
1178 if( RDn(ir) == 15 ) {
1179 arm_restore_cpsr();
1180 } else {
1181 armr.n = operand>>31;
1182 armr.z = (operand == 0);
1183 armr.c = armr.shift_c;
1184 }
1185 break;
1186 default:
1187 UNIMP(ir);
1188 }
1189 }
1190 break;
1191 case 1: /* Load/store */
1192 operand = arm_get_address_operand(ir);
1193 switch( (ir>>20)&0x17 ) {
1194 case 0: case 16: case 18: /* STR Rd, address */
1195 arm_write_long( operand, RD(ir) );
1196 break;
1197 case 1: case 17: case 19: /* LDR Rd, address */
1198 LRD(ir) = arm_read_long(operand);
1199 break;
1200 case 2: /* STRT Rd, address */
1201 arm_write_long_user( operand, RD(ir) );
1202 break;
1203 case 3: /* LDRT Rd, address */
1204 LRD(ir) = arm_read_long_user( operand );
1205 break;
1206 case 4: case 20: case 22: /* STRB Rd, address */
1207 arm_write_byte( operand, RD(ir) );
1208 break;
1209 case 5: case 21: case 23: /* LDRB Rd, address */
1210 LRD(ir) = arm_read_byte( operand );
1211 break;
1212 case 6: /* STRBT Rd, address */
1213 arm_write_byte_user( operand, RD(ir) );
1214 break;
1215 case 7: /* LDRBT Rd, address */
1216 LRD(ir) = arm_read_byte_user( operand );
1217 break;
1218 }
1219 break;
1220 case 2: /* Load/store multiple, branch*/
1221 if( (ir & 0x02000000) == 0x02000000 ) { /* B[L] imm24 */
1222 operand = (SIGNEXT24(ir&0x00FFFFFF) << 2);
1223 if( (ir & 0x01000000) == 0x01000000 ) {
1224 armr.r[14] = pc; /* BL */
1225 }
1226 armr.r[15] = pc + 4 + operand;
1227 } else { /* Load/store multiple */
1228 gboolean needRestore = FALSE;
1229 operand = RN(ir);
1231 switch( (ir & 0x01D00000) >> 20 ) {
1232 case 0: /* STMDA */
1233 if( ir & 0x8000 ) {
1234 arm_write_long( operand, armr.r[15]+8 );
1235 operand -= 4;
1236 }
1237 for( i=14; i>= 0; i-- ) {
1238 if( (ir & (1<<i)) ) {
1239 arm_write_long( operand, armr.r[i] );
1240 operand -= 4;
1241 }
1242 }
1243 break;
1244 case 1: /* LDMDA */
1245 for( i=15; i>= 0; i-- ) {
1246 if( (ir & (1<<i)) ) {
1247 armr.r[i] = arm_read_long( operand );
1248 operand -= 4;
1249 }
1250 }
1251 break;
1252 case 4: /* STMDA (S) */
1253 if( ir & 0x8000 ) {
1254 arm_write_long( operand, armr.r[15]+8 );
1255 operand -= 4;
1256 }
1257 for( i=14; i>= 0; i-- ) {
1258 if( (ir & (1<<i)) ) {
1259 arm_write_long( operand, USER_R(i) );
1260 operand -= 4;
1261 }
1262 }
1263 break;
1264 case 5: /* LDMDA (S) */
1265 if( (ir&0x00008000) ) { /* Load PC */
1266 for( i=15; i>= 0; i-- ) {
1267 if( (ir & (1<<i)) ) {
1268 armr.r[i] = arm_read_long( operand );
1269 operand -= 4;
1270 }
1271 }
1272 needRestore = TRUE;
1273 } else {
1274 for( i=15; i>= 0; i-- ) {
1275 if( (ir & (1<<i)) ) {
1276 USER_R(i) = arm_read_long( operand );
1277 operand -= 4;
1278 }
1279 }
1280 }
1281 break;
1282 case 8: /* STMIA */
1283 for( i=0; i< 15; i++ ) {
1284 if( (ir & (1<<i)) ) {
1285 arm_write_long( operand, armr.r[i] );
1286 operand += 4;
1287 }
1288 }
1289 if( ir & 0x8000 ) {
1290 arm_write_long( operand, armr.r[15]+8 );
1291 operand += 4;
1292 }
1293 break;
1294 case 9: /* LDMIA */
1295 for( i=0; i< 16; i++ ) {
1296 if( (ir & (1<<i)) ) {
1297 armr.r[i] = arm_read_long( operand );
1298 operand += 4;
1299 }
1300 }
1301 break;
1302 case 12: /* STMIA (S) */
1303 for( i=0; i< 15; i++ ) {
1304 if( (ir & (1<<i)) ) {
1305 arm_write_long( operand, USER_R(i) );
1306 operand += 4;
1307 }
1308 }
1309 if( ir & 0x8000 ) {
1310 arm_write_long( operand, armr.r[15]+8 );
1311 operand += 4;
1312 }
1313 break;
1314 case 13: /* LDMIA (S) */
1315 if( (ir&0x00008000) ) { /* Load PC */
1316 for( i=0; i < 16; i++ ) {
1317 if( (ir & (1<<i)) ) {
1318 armr.r[i] = arm_read_long( operand );
1319 operand += 4;
1320 }
1321 }
1322 needRestore = TRUE;
1323 } else {
1324 for( i=0; i < 16; i++ ) {
1325 if( (ir & (1<<i)) ) {
1326 USER_R(i) = arm_read_long( operand );
1327 operand += 4;
1328 }
1329 }
1330 }
1331 break;
1332 case 16: /* STMDB */
1333 if( ir & 0x8000 ) {
1334 operand -= 4;
1335 arm_write_long( operand, armr.r[15]+8 );
1336 }
1337 for( i=14; i>= 0; i-- ) {
1338 if( (ir & (1<<i)) ) {
1339 operand -= 4;
1340 arm_write_long( operand, armr.r[i] );
1341 }
1342 }
1343 break;
1344 case 17: /* LDMDB */
1345 for( i=15; i>= 0; i-- ) {
1346 if( (ir & (1<<i)) ) {
1347 operand -= 4;
1348 armr.r[i] = arm_read_long( operand );
1349 }
1350 }
1351 break;
1352 case 20: /* STMDB (S) */
1353 if( ir & 0x8000 ) {
1354 operand -= 4;
1355 arm_write_long( operand, armr.r[15]+8 );
1356 }
1357 for( i=14; i>= 0; i-- ) {
1358 if( (ir & (1<<i)) ) {
1359 operand -= 4;
1360 arm_write_long( operand, USER_R(i) );
1361 }
1362 }
1363 break;
1364 case 21: /* LDMDB (S) */
1365 if( (ir&0x00008000) ) { /* Load PC */
1366 for( i=15; i>= 0; i-- ) {
1367 if( (ir & (1<<i)) ) {
1368 operand -= 4;
1369 armr.r[i] = arm_read_long( operand );
1370 }
1371 }
1372 needRestore = TRUE;
1373 } else {
1374 for( i=15; i>= 0; i-- ) {
1375 if( (ir & (1<<i)) ) {
1376 operand -= 4;
1377 USER_R(i) = arm_read_long( operand );
1378 }
1379 }
1380 }
1381 break;
1382 case 24: /* STMIB */
1383 for( i=0; i< 15; i++ ) {
1384 if( (ir & (1<<i)) ) {
1385 operand += 4;
1386 arm_write_long( operand, armr.r[i] );
1387 }
1388 }
1389 if( ir & 0x8000 ) {
1390 operand += 4;
1391 arm_write_long( operand, armr.r[15]+8 );
1392 }
1393 break;
1394 case 25: /* LDMIB */
1395 for( i=0; i< 16; i++ ) {
1396 if( (ir & (1<<i)) ) {
1397 operand += 4;
1398 armr.r[i] = arm_read_long( operand );
1399 }
1400 }
1401 break;
1402 case 28: /* STMIB (S) */
1403 for( i=0; i< 15; i++ ) {
1404 if( (ir & (1<<i)) ) {
1405 operand += 4;
1406 arm_write_long( operand, USER_R(i) );
1407 }
1408 }
1409 if( ir & 0x8000 ) {
1410 operand += 4;
1411 arm_write_long( operand, armr.r[15]+8 );
1412 }
1413 break;
1414 case 29: /* LDMIB (S) */
1415 if( (ir&0x00008000) ) { /* Load PC */
1416 for( i=0; i < 16; i++ ) {
1417 if( (ir & (1<<i)) ) {
1418 operand += 4;
1419 armr.r[i] = arm_read_long( operand );
1420 }
1421 }
1422 needRestore = TRUE;
1423 } else {
1424 for( i=0; i < 16; i++ ) {
1425 if( (ir & (1<<i)) ) {
1426 operand += 4;
1427 USER_R(i) = arm_read_long( operand );
1428 }
1429 }
1430 }
1431 break;
1432 }
1434 if( WFLAG(ir) )
1435 LRN(ir) = operand;
1436 if( needRestore )
1437 arm_restore_cpsr();
1438 }
1439 break;
1440 case 3: /* Copro */
1441 if( (ir & 0x0F000000) == 0x0F000000 ) { /* SWI */
1442 arm_raise_exception( EXC_SOFTWARE );
1443 } else {
1444 UNIMP(ir);
1445 }
1446 break;
1447 }
1449 }
1451 if( armr.r[15] >= 0x00200000 ) {
1452 armr.running = FALSE;
1453 WARN( "ARM Halted: BRANCH to invalid address %08X at %08X", armr.r[15], pc );
1454 return FALSE;
1455 }
1456 return TRUE;
1457 }
.