Search
lxdream.org :: lxdream/src/aica/armcore.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/aica/armcore.c
changeset 30:89b30313d757
prev11:0a82ef380c45
next35:21a4be098304
author nkeynes
date Sun Dec 25 05:57:00 2005 +0000 (15 years ago)
permissions -rw-r--r--
last change Change timeslice to nanoseconds (was microseconds)
Generize single step (now steps through active CPU)
Add lots of header blocks
view annotate diff log raw
     1 /**
     2  * $Id: armcore.c,v 1.5 2005-12-25 05:57:00 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 #include "aica/armcore.h"
    21 struct arm_registers armr;
    23 /* NB: The arm has a different memory map, but for the meantime... */
    24 /* Page references are as per ARM DDI 0100E (June 2000) */
    26 #define MEM_READ_BYTE( addr ) arm_read_byte(addr)
    27 #define MEM_READ_WORD( addr ) arm_read_word(addr)
    28 #define MEM_READ_LONG( addr ) arm_read_long(addr)
    29 #define MEM_WRITE_BYTE( addr, val ) arm_write_byte(addr, val)
    30 #define MEM_WRITE_WORD( addr, val ) arm_write_word(addr, val)
    31 #define MEM_WRITE_LONG( addr, val ) arm_write_long(addr, val)
    34 #define IS_NOTBORROW( result, op1, op2 ) (op2 > op1 ? 0 : 1)
    35 #define IS_CARRY( result, op1, op2 ) (result < op1 ? 1 : 0)
    36 #define IS_SUBOVERFLOW( result, op1, op2 ) (((op1^op2) & (result^op1)) >> 31)
    37 #define IS_ADDOVERFLOW( result, op1, op2 ) (((op1&op2) & (result^op1)) >> 31)
    39 #define PC armr.r[15]
    41 /* Instruction fields */
    42 #define COND(ir) (ir>>28)
    43 #define GRP(ir) ((ir>>26)&0x03)
    44 #define OPCODE(ir) ((ir>>20)&0x1F)
    45 #define IFLAG(ir) (ir&0x02000000)
    46 #define SFLAG(ir) (ir&0x00100000)
    47 #define PFLAG(ir) (ir&0x01000000)
    48 #define UFLAG(ir) (ir&0x00800000)
    49 #define BFLAG(ir) (ir&0x00400000)
    50 #define WFLAG(ir) (IR&0x00200000)
    51 #define LFLAG(ir) SFLAG(ir)
    52 #define RN(ir) (armr.r[((ir>>16)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
    53 #define RD(ir) (armr.r[((ir>>12)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
    54 #define RDn(ir) ((ir>>12)&0x0F)
    55 #define RS(ir) (armr.r[((ir>>8)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
    56 #define RM(ir) (armr.r[(ir&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
    57 #define LRN(ir) armr.r[((ir>>16)&0x0F)]
    58 #define LRD(ir) armr.r[((ir>>12)&0x0F)]
    59 #define LRS(ir) armr.r[((ir>>8)&0x0F)]
    60 #define LRM(ir) armr.r[(ir&0x0F)]
    62 #define IMM8(ir) (ir&0xFF)
    63 #define IMM12(ir) (ir&0xFFF)
    64 #define SHIFTIMM(ir) ((ir>>7)&0x1F)
    65 #define IMMROT(ir) ((ir>>7)&0x1E)
    66 #define SHIFT(ir) ((ir>>4)&0x07)
    67 #define DISP24(ir) ((ir&0x00FFFFFF))
    68 #define UNDEF(ir) do{ ERROR( "Raising exception on undefined instruction at %08x, opcode = %04x", PC, ir ); return TRUE; } while(0)
    69 #define UNIMP(ir) do{ ERROR( "Halted on unimplemented instruction at %08x, opcode = %04x", PC, ir ); return FALSE; }while(0)
    71 void arm_restore_cpsr()
    72 {
    74 }
    76 static uint32_t arm_get_shift_operand( uint32_t ir )
    77 {
    78 	uint32_t operand, tmp;
    79 	if( IFLAG(ir) == 0 ) {
    80 		operand = RM(ir);
    81 		switch(SHIFT(ir)) {
    82 		case 0: /* (Rm << imm) */
    83 			operand = operand << SHIFTIMM(ir);
    84 			break;
    85 		case 1: /* (Rm << Rs) */
    86 			tmp = RS(ir)&0xFF;
    87 			if( tmp > 31 ) operand = 0;
    88 			else operand = operand << tmp;
    89 			break;
    90 		case 2: /* (Rm >> imm) */
    91 			operand = operand >> SHIFTIMM(ir);
    92 			break;
    93 		case 3: /* (Rm >> Rs) */
    94 			tmp = RS(ir) & 0xFF;
    95 			if( tmp > 31 ) operand = 0;
    96 			else operand = operand >> ir;
    97 			break;
    98 		case 4: /* (Rm >>> imm) */
    99 			tmp = SHIFTIMM(ir);
   100 			if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
   101 			else operand = ((int32_t)operand) >> tmp;
   102 			break;
   103 		case 5: /* (Rm >>> Rs) */
   104 			tmp = RS(ir) & 0xFF;
   105 			if( tmp > 31 ) operand = ((int32_t)operand) >> 31;
   106 			else operand = ((int32_t)operand) >> tmp;
   107 			break;
   108 		case 6:
   109 			tmp = SHIFTIMM(ir);
   110 			if( tmp == 0 ) /* RRX aka rotate with carry */
   111 				operand = (operand >> 1) | (armr.c<<31);
   112 			else
   113 				operand = ROTATE_RIGHT_LONG(operand,tmp);
   114 			break;
   115 		case 7:
   116 			tmp = RS(ir)&0x1F;
   117 			operand = ROTATE_RIGHT_LONG(operand,tmp);
   118 			break;
   119 		}
   120 	} else {
   121 		operand = IMM8(ir);
   122 		tmp = IMMROT(ir);
   123 		operand = ROTATE_RIGHT_LONG(operand, tmp);
   124 	}
   125 	return operand;
   126 }
   128 /**
   129  * Compute the "shift operand" of the instruction for the data processing
   130  * instructions. This variant also sets armr.shift_c (carry result for shifter)
   131  * Reason for the variants is that most cases don't actually need the shift_c.
   132  */
   133 static uint32_t arm_get_shift_operand_s( uint32_t ir )
   134 {
   135 	uint32_t operand, tmp;
   136 	if( IFLAG(ir) == 0 ) {
   137 		operand = RM(ir);
   138 		switch(SHIFT(ir)) {
   139 		case 0: /* (Rm << imm) */
   140 			tmp = SHIFTIMM(ir);
   141 			if( tmp == 0 ) { /* Rm */
   142 				armr.shift_c = armr.c;
   143 			} else { /* Rm << imm */
   144 				armr.shift_c = (operand >> (32-tmp)) & 0x01;
   145 				operand = operand << tmp;
   146 			}
   147 			break;
   148 		case 1: /* (Rm << Rs) */
   149 			tmp = RS(ir)&0xFF;
   150 			if( tmp == 0 ) {
   151 				armr.shift_c = armr.c;
   152 			} else {
   153 				if( tmp <= 32 )
   154 					armr.shift_c = (operand >> (32-tmp)) & 0x01;
   155 				else armr.shift_c = 0;
   156 				if( tmp < 32 )
   157 					operand = operand << tmp;
   158 				else operand = 0;
   159 			}
   160 			break;
   161 		case 2: /* (Rm >> imm) */
   162 			tmp = SHIFTIMM(ir);
   163 			if( tmp == 0 ) {
   164 				armr.shift_c = operand >> 31;
   165 				operand = 0;
   166 			} else {
   167 				armr.shift_c = (operand >> (tmp-1)) & 0x01;
   168 				operand = RM(ir) >> tmp;
   169 			}
   170 			break;
   171 		case 3: /* (Rm >> Rs) */
   172 			tmp = RS(ir) & 0xFF;
   173 			if( tmp == 0 ) {
   174 				armr.shift_c = armr.c;
   175 			} else {
   176 				if( tmp <= 32 )
   177 					armr.shift_c = (operand >> (tmp-1))&0x01;
   178 				else armr.shift_c = 0;
   179 				if( tmp < 32 )
   180 					operand = operand >> tmp;
   181 				else operand = 0;
   182 			}
   183 			break;
   184 		case 4: /* (Rm >>> imm) */
   185 			tmp = SHIFTIMM(ir);
   186 			if( tmp == 0 ) {
   187 				armr.shift_c = operand >> 31;
   188 				operand = -armr.shift_c;
   189 			} else {
   190 				armr.shift_c = (operand >> (tmp-1)) & 0x01;
   191 				operand = ((int32_t)operand) >> tmp;
   192 			}
   193 			break;
   194 		case 5: /* (Rm >>> Rs) */
   195 			tmp = RS(ir) & 0xFF;
   196 			if( tmp == 0 ) {
   197 				armr.shift_c = armr.c;
   198 			} else {
   199 				if( tmp < 32 ) {
   200 					armr.shift_c = (operand >> (tmp-1))&0x01;
   201 					operand = ((int32_t)operand) >> tmp;
   202 				} else {
   203 					armr.shift_c = operand >> 31;
   204 					operand = ((int32_t)operand) >> 31;
   205 				}
   206 			}
   207 			break;
   208 		case 6:
   209 			tmp = SHIFTIMM(ir);
   210 			if( tmp == 0 ) { /* RRX aka rotate with carry */
   211 				armr.shift_c = operand&0x01;
   212 				operand = (operand >> 1) | (armr.c<<31);
   213 			} else {
   214 				armr.shift_c = operand>>(tmp-1);
   215 				operand = ROTATE_RIGHT_LONG(operand,tmp);
   216 			}
   217 			break;
   218 		case 7:
   219 			tmp = RS(ir)&0xFF;
   220 			if( tmp == 0 ) {
   221 				armr.shift_c = armr.c;
   222 			} else {
   223 				tmp &= 0x1F;
   224 				if( tmp == 0 ) {
   225 					armr.shift_c = operand>>31;
   226 				} else {
   227 					armr.shift_c = (operand>>(tmp-1))&0x1;
   228 					operand = ROTATE_RIGHT_LONG(operand,tmp);
   229 				}
   230 			}
   231 			break;
   232 		}
   233 	} else {
   234 		operand = IMM8(ir);
   235 		tmp = IMMROT(ir);
   236 		if( tmp == 0 ) {
   237 			armr.shift_c = armr.c;
   238 		} else {
   239 			operand = ROTATE_RIGHT_LONG(operand, tmp);
   240 			armr.shift_c = operand>>31;
   241 		}
   242 	}
   243 	return operand;
   244 }
   246 /**
   247  * Another variant of the shifter code for index-based memory addressing.
   248  * Distinguished by the fact that it doesn't support register shifts, and
   249  * ignores the I flag (WTF do the load/store instructions use the I flag to
   250  * mean the _exact opposite_ of what it means for the data processing 
   251  * instructions ???)
   252  */
   253 static uint32_t arm_get_address_index( uint32_t ir )
   254 {
   255 	uint32_t operand = RM(ir);
   256 	uint32_t tmp;
   258 	switch(SHIFT(ir)) {
   259 	case 0: /* (Rm << imm) */
   260 		operand = operand << SHIFTIMM(ir);
   261 		break;
   262 	case 2: /* (Rm >> imm) */
   263 		operand = operand >> SHIFTIMM(ir);
   264 		break;
   265 	case 4: /* (Rm >>> imm) */
   266 		tmp = SHIFTIMM(ir);
   267 		if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
   268 		else operand = ((int32_t)operand) >> tmp;
   269 		break;
   270 	case 6:
   271 		tmp = SHIFTIMM(ir);
   272 		if( tmp == 0 ) /* RRX aka rotate with carry */
   273 			operand = (operand >> 1) | (armr.c<<31);
   274 		else
   275 			operand = ROTATE_RIGHT_LONG(operand,tmp);
   276 		break;
   277 	default: UNIMP(ir);
   278 	}
   279 	return operand;	
   280 }
   282 static uint32_t arm_get_address_operand( uint32_t ir )
   283 {
   284 	uint32_t addr;
   286 	/* I P U . W */
   287 	switch( (ir>>21)&0x1D ) {
   288 	case 0: /* Rn -= imm offset (post-indexed) [5.2.8 A5-28] */
   289 	case 1:
   290 		addr = RN(ir);
   291 		LRN(ir) = addr - IMM12(ir);
   292 		break;
   293 	case 4: /* Rn += imm offsett (post-indexed) [5.2.8 A5-28] */
   294 	case 5:
   295 		addr = RN(ir);
   296 		LRN(ir) = addr + IMM12(ir);
   297 		break;
   298 	case 8: /* Rn - imm offset  [5.2.2 A5-20] */
   299 		addr = RN(ir) - IMM12(ir);
   300 		break;
   301 	case 9: /* Rn -= imm offset (pre-indexed)  [5.2.5 A5-24] */
   302 		addr = RN(ir) - IMM12(ir);
   303 		LRN(ir) = addr;
   304 		break;
   305 	case 12: /* Rn + imm offset  [5.2.2 A5-20] */
   306 		addr = RN(ir) + IMM12(ir);
   307 		break;
   308 	case 13: /* Rn += imm offset  [5.2.5 A5-24 ] */
   309 		addr = RN(ir) + IMM12(ir);
   310 		LRN(ir) = addr;
   311 		break;
   312 	case 16: /* Rn -= Rm (post-indexed)  [5.2.10 A5-32 ] */
   313 	case 17:
   314 		addr = RN(ir);
   315 		LRN(ir) = addr - arm_get_address_index(ir);
   316 		break;
   317 	case 20: /* Rn += Rm (post-indexed)  [5.2.10 A5-32 ] */
   318 	case 21:
   319 		addr = RN(ir);
   320 		LRN(ir) = addr - arm_get_address_index(ir);
   321 		break;
   322 	case 24: /* Rn - Rm  [5.2.4 A5-23] */
   323 		addr = RN(ir) - arm_get_address_index(ir);
   324 		break;
   325 	case 25: /* RN -= Rm (pre-indexed)  [5.2.7 A5-26] */
   326 		addr = RN(ir) - arm_get_address_index(ir);
   327 		LRN(ir) = addr;
   328 		break;
   329 	case 28: /* Rn + Rm  [5.2.4 A5-23] */
   330 		addr = RN(ir) + arm_get_address_index(ir);
   331 		break;
   332 	case 29: /* RN += Rm (pre-indexed) [5.2.7 A5-26] */
   333 		addr = RN(ir) + arm_get_address_index(ir);
   334 		LRN(ir) = addr;
   335 		break;
   336 	default:
   337 		UNIMP(ir); /* Unreachable */
   338 	}
   339 	return addr;
   340 }
   342 gboolean arm_execute_instruction( void ) 
   343 {
   344 	uint32_t pc = PC;
   345 	uint32_t ir = MEM_READ_LONG(pc);
   346 	uint32_t operand, operand2, tmp, cond;
   348 	pc += 4;
   349 	PC = pc;
   351 	switch( COND(ir) ) {
   352 		case 0: /* EQ */ 
   353 			cond = armr.z;
   354 			break;
   355 		case 1: /* NE */
   356 			cond = !armr.z;
   357 			break;
   358 		case 2: /* CS/HS */
   359 			cond = armr.c;
   360 			break;
   361 		case 3: /* CC/LO */
   362 			cond = !armr.c;
   363 			break;
   364 		case 4: /* MI */
   365 			cond = armr.n;
   366 			break;
   367 		case 5: /* PL */
   368 			cond = !armr.n;
   369 			break;
   370 		case 6: /* VS */
   371 			cond = armr.v;
   372 			break;
   373 		case 7: /* VC */
   374 			cond = !armr.v;
   375 			break;
   376 		case 8: /* HI */
   377 			cond = armr.c && !armr.z;
   378 			break;
   379 		case 9: /* LS */
   380 			cond = (!armr.c) || armr.z;
   381 			break;
   382 		case 10: /* GE */
   383 			cond = (armr.n == armr.v);
   384 			break;
   385 		case 11: /* LT */
   386 			cond = (armr.n != armr.v);
   387 			break;
   388 		case 12: /* GT */
   389 			cond = (!armr.z) && (armr.n == armr.v);
   390 			break;
   391 		case 13: /* LE */
   392 			cond = armr.z || (armr.n != armr.v);
   393 			break;
   394 		case 14: /* AL */
   395 			cond = 1;
   396 			break;
   397 		case 15: /* (NV) */
   398 			cond = 0;
   399 			UNDEF(ir);
   400 	}
   402 	switch( GRP(ir) ) {
   403 	case 0:
   404 		if( (ir & 0x0D900000) == 0x01000000 ) {
   405 			/* Instructions that aren't actual data processing */
   406 			switch( ir & 0x0FF000F0 ) {
   407 			case 0x01200010: /* BX */
   408 				break;
   409 			case 0x01000000: /* MRS Rd, CPSR */
   410 				break;
   411 			case 0x01400000: /* MRS Rd, SPSR */
   412 				break;
   413 			case 0x01200000: /* MSR CPSR, Rd */
   414 				break;
   415 			case 0x01600000: /* MSR SPSR, Rd */
   416 				break;
   417 			case 0x03200000: /* MSR CPSR, imm */
   418 				break;
   419 			case 0x03600000: /* MSR SPSR, imm */
   420 				break;
   421 			default:
   422 				UNIMP(ir);
   423 			}
   424 		} else if( (ir & 0x0E000090) == 0x00000090 ) {
   425 			/* Neither are these */
   426 			switch( (ir>>5)&0x03 ) {
   427 			case 0:
   428 				/* Arithmetic extension area */
   429 				switch(OPCODE(ir)) {
   430 				case 0: /* MUL */
   431 					break;
   432 				case 1: /* MULS */
   433 					break;
   434 				case 2: /* MLA */
   435 					break;
   436 				case 3: /* MLAS */
   437 					break;
   438 				case 8: /* UMULL */
   439 					break;
   440 				case 9: /* UMULLS */
   441 					break;
   442 				case 10: /* UMLAL */
   443 					break;
   444 				case 11: /* UMLALS */
   445 					break;
   446 				case 12: /* SMULL */
   447 					break;
   448 				case 13: /* SMULLS */
   449 					break;
   450 				case 14: /* SMLAL */
   451 					break;
   452 				case 15: /* SMLALS */
   453 					break;
   454 				case 16: /* SWP */
   455 					break;
   456 				case 20: /* SWPB */
   457 					break;
   458 				default:
   459 					UNIMP(ir);
   460 				}
   461 				break;
   462 			case 1:
   463 				if( LFLAG(ir) ) {
   464 					/* LDRH */
   465 				} else {
   466 					/* STRH */
   467 				}
   468 				break;
   469 			case 2:
   470 				if( LFLAG(ir) ) {
   471 					/* LDRSB */
   472 				} else {
   473 					UNIMP(ir);
   474 				}
   475 				break;
   476 			case 3:
   477 				if( LFLAG(ir) ) {
   478 					/* LDRSH */
   479 				} else {
   480 					UNIMP(ir);
   481 				}
   482 				break;
   483 			}
   484 		} else {
   485 			/* Data processing */
   487 			switch(OPCODE(ir)) {
   488 			case 0: /* AND Rd, Rn, operand */
   489 				LRD(ir) = RN(ir) & arm_get_shift_operand(ir);
   490 				break;
   491 			case 1: /* ANDS Rd, Rn, operand */
   492 				operand = arm_get_shift_operand_s(ir) & RN(ir);
   493 				LRD(ir) = operand;
   494 				if( RDn(ir) == 15 ) {
   495 					arm_restore_cpsr();
   496 				} else {
   497 					armr.n = operand>>31;
   498 					armr.z = (operand == 0);
   499 					armr.c = armr.shift_c;
   500 				}
   501 				break;
   502 			case 2: /* EOR Rd, Rn, operand */
   503 				LRD(ir) = RN(ir) ^ arm_get_shift_operand(ir);
   504 				break;
   505 			case 3: /* EORS Rd, Rn, operand */
   506 				operand = arm_get_shift_operand_s(ir) ^ RN(ir);
   507 				LRD(ir) = operand;
   508 				if( RDn(ir) == 15 ) {
   509 					arm_restore_cpsr();
   510 				} else {
   511 					armr.n = operand>>31;
   512 					armr.z = (operand == 0);
   513 					armr.c = armr.shift_c;
   514 				}
   515 				break;
   516 			case 4: /* SUB Rd, Rn, operand */
   517 				LRD(ir) = RN(ir) - arm_get_shift_operand(ir);
   518 				break;
   519 			case 5: /* SUBS Rd, Rn, operand */
   520 			    operand = RN(ir);
   521 				operand2 = arm_get_shift_operand(ir);
   522 				tmp = operand - operand2;
   523 				LRD(ir) = tmp;
   524 				if( RDn(ir) == 15 ) {
   525 					arm_restore_cpsr();
   526 				} else {
   527 					armr.n = tmp>>31;
   528 					armr.z = (tmp == 0);
   529 					armr.c = IS_NOTBORROW(tmp,operand,operand2);
   530 					armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
   531 				}
   532 				break;
   533 			case 6: /* RSB Rd, operand, Rn */
   534 				LRD(ir) = arm_get_shift_operand(ir) - RN(ir);
   535 				break;
   536 			case 7: /* RSBS Rd, operand, Rn */
   537 				operand = arm_get_shift_operand(ir);
   538 			    operand2 = RN(ir);
   539 				tmp = operand - operand2;
   540 				LRD(ir) = tmp;
   541 				if( RDn(ir) == 15 ) {
   542 					arm_restore_cpsr();
   543 				} else {
   544 					armr.n = tmp>>31;
   545 					armr.z = (tmp == 0);
   546 					armr.c = IS_NOTBORROW(tmp,operand,operand2);
   547 					armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
   548 				}
   549 				break;
   550 			case 8: /* ADD Rd, Rn, operand */
   551 				LRD(ir) = RN(ir) + arm_get_shift_operand(ir);
   552 				break;
   553 			case 9: /* ADDS Rd, Rn, operand */
   554 				operand = arm_get_shift_operand(ir);
   555 			    operand2 = RN(ir);
   556 				tmp = operand + operand2;
   557 				LRD(ir) = tmp;
   558 				if( RDn(ir) == 15 ) {
   559 					arm_restore_cpsr();
   560 				} else {
   561 					armr.n = tmp>>31;
   562 					armr.z = (tmp == 0);
   563 					armr.c = IS_CARRY(tmp,operand,operand2);
   564 					armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
   565 				}
   566 				break;			
   567 			case 10: /* ADC */
   568 			case 11: /* ADCS */
   569 			case 12: /* SBC */
   570 			case 13: /* SBCS */
   571 			case 14: /* RSC */
   572 			case 15: /* RSCS */
   573 				break;
   574 			case 17: /* TST Rn, operand */
   575 				operand = arm_get_shift_operand_s(ir) & RN(ir);
   576 				armr.n = operand>>31;
   577 				armr.z = (operand == 0);
   578 				armr.c = armr.shift_c;
   579 				break;
   580 			case 19: /* TEQ Rn, operand */
   581 				operand = arm_get_shift_operand_s(ir) ^ RN(ir);
   582 				armr.n = operand>>31;
   583 				armr.z = (operand == 0);
   584 				armr.c = armr.shift_c;
   585 				break;				
   586 			case 21: /* CMP Rn, operand */
   587 			    operand = RN(ir);
   588 				operand2 = arm_get_shift_operand(ir);
   589 				tmp = operand - operand2;
   590 				armr.n = tmp>>31;
   591 				armr.z = (tmp == 0);
   592 				armr.c = IS_NOTBORROW(tmp,operand,operand2);
   593 				armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
   594 				break;
   595 			case 23: /* CMN Rn, operand */
   596 			    operand = RN(ir);
   597 				operand2 = arm_get_shift_operand(ir);
   598 				tmp = operand + operand2;
   599 				armr.n = tmp>>31;
   600 				armr.z = (tmp == 0);
   601 				armr.c = IS_CARRY(tmp,operand,operand2);
   602 				armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
   603 				break;
   604 			case 24: /* ORR Rd, Rn, operand */
   605 				LRD(ir) = RN(ir) | arm_get_shift_operand(ir);
   606 				break;
   607 			case 25: /* ORRS Rd, Rn, operand */
   608 				operand = arm_get_shift_operand_s(ir) | RN(ir);
   609 				LRD(ir) = operand;
   610 				if( RDn(ir) == 15 ) {
   611 					arm_restore_cpsr();
   612 				} else {
   613 					armr.n = operand>>31;
   614 					armr.z = (operand == 0);
   615 					armr.c = armr.shift_c;
   616 				}
   617 				break;
   618 			case 26: /* MOV Rd, operand */
   619 				LRD(ir) = arm_get_shift_operand(ir);
   620 				break;
   621 			case 27: /* MOVS Rd, operand */
   622 				operand = arm_get_shift_operand_s(ir);
   623 				LRD(ir) = operand;
   624 				if( RDn(ir) == 15 ) {
   625 					arm_restore_cpsr();
   626 				} else {
   627 					armr.n = operand>>31;
   628 					armr.z = (operand == 0);
   629 					armr.c = armr.shift_c;
   630 				}
   631 				break;
   632 			case 28: /* BIC Rd, Rn, operand */
   633 				LRD(ir) = RN(ir) & (~arm_get_shift_operand(ir));
   634 				break;
   635 			case 29: /* BICS Rd, Rn, operand */
   636 				operand = RN(ir) & (~arm_get_shift_operand_s(ir));
   637 				LRD(ir) = operand;
   638 				if( RDn(ir) == 15 ) {
   639 					arm_restore_cpsr();
   640 				} else {
   641 					armr.n = operand>>31;
   642 					armr.z = (operand == 0);
   643 					armr.c = armr.shift_c;
   644 				}
   645 				break;
   646 			case 30: /* MVN Rd, operand */
   647 				LRD(ir) = ~arm_get_shift_operand(ir);
   648 				break;
   649 			case 31: /* MVNS Rd, operand */
   650 				operand = ~arm_get_shift_operand_s(ir);
   651 				LRD(ir) = operand;
   652 				if( RDn(ir) == 15 ) {
   653 					arm_restore_cpsr();
   654 				} else {
   655 					armr.n = operand>>31;
   656 					armr.z = (operand == 0);
   657 					armr.c = armr.shift_c;
   658 				}
   659 				break;
   660 			default:
   661 				UNIMP(ir);
   662 			}
   663 		}
   664 		break;
   665 	case 1: /* Load/store */
   666 		break;
   667 	case 2: /* Load/store multiple, branch*/
   668 		break;
   669 	case 3: /* Copro */
   670 		break;
   671 	}
   672 	return TRUE;
   673 }
.