mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	added thumb mode emulation
This commit is contained in:
		
							parent
							
								
									c9b5b89e21
								
							
						
					
					
						commit
						7bf24c066b
					
				
					 6 changed files with 522 additions and 4 deletions
				
			
		|  | @ -145,6 +145,7 @@ | |||
|     <ClCompile Include="src\arm\armvirt.cpp" /> | ||||
|     <ClCompile Include="src\arm\disassembler\arm_disasm.cpp" /> | ||||
|     <ClCompile Include="src\arm\mmu\arm1176jzf_s_mmu.cpp" /> | ||||
|     <ClCompile Include="src\arm\thumbemu.cpp" /> | ||||
|     <ClCompile Include="src\core.cpp" /> | ||||
|     <ClCompile Include="src\core_timing.cpp" /> | ||||
|     <ClCompile Include="src\elf\elf_reader.cpp" /> | ||||
|  |  | |||
|  | @ -40,6 +40,9 @@ | |||
|     <ClCompile Include="src\arm\mmu\arm1176jzf_s_mmu.cpp"> | ||||
|       <Filter>arm\mmu</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="src\arm\thumbemu.cpp"> | ||||
|       <Filter>arm</Filter> | ||||
|     </ClCompile> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <Filter Include="arm"> | ||||
|  |  | |||
|  | @ -936,10 +936,10 @@ ARMul_Emulate26 (ARMul_State * state) | |||
|            pipelined PC value is used when executing Thumb code, and also for | ||||
|            dealing with the BL instruction.  */ | ||||
|         if (TFLAG) { | ||||
|             ARMword new; | ||||
|             ARMword new_instr; | ||||
| 
 | ||||
|             /* Check if in Thumb mode.  */ | ||||
|             switch (ARMul_ThumbDecode (state, pc, instr, &new)) { | ||||
|             switch (ARMul_ThumbDecode(state, pc, instr, &new_instr)) { | ||||
|             case t_undefined: | ||||
|                 /* This is a Thumb instruction.  */ | ||||
|                 ARMul_UndefInstr (state, instr); | ||||
|  | @ -952,7 +952,7 @@ ARMul_Emulate26 (ARMul_State * state) | |||
|             case t_decoded: | ||||
|                 /* ARM instruction available.  */ | ||||
|                 //printf("t decode %04lx -> %08lx\n", instr & 0xffff, new);
 | ||||
|                 instr = new; | ||||
|                 instr = new_instr; | ||||
|                 /* So continue instruction decoding.  */ | ||||
|                 break; | ||||
|             default: | ||||
|  |  | |||
|  | @ -140,7 +140,7 @@ ARMul_SetCPSR (ARMul_State * state, ARMword value) | |||
| 
 | ||||
| void | ||||
| ARMul_FixCPSR (ARMul_State * state, ARMword instr, ARMword rhs) | ||||
| { | ||||
| {   | ||||
| 	state->Cpsr = ARMul_GetCPSR (state); | ||||
| 	//chy 2006-02-16 , should not consider system mode, don't conside 26bit mode
 | ||||
| 	if (state->Mode != USER26MODE && state->Mode != USER32MODE ) { | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| #include "common.h" | ||||
| 
 | ||||
| #define MODE32 | ||||
| #define MODET | ||||
| 
 | ||||
| typedef struct | ||||
| { | ||||
|  |  | |||
							
								
								
									
										513
									
								
								src/core/src/arm/thumbemu.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										513
									
								
								src/core/src/arm/thumbemu.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,513 @@ | |||
| /*  thumbemu.c -- Thumb instruction emulation.
 | ||||
|     Copyright (C) 1996, Cygnus Software Technologies Ltd. | ||||
| 
 | ||||
|     This program is free software; you can redistribute it and/or modify | ||||
|     it under the terms of the GNU General Public License as published by | ||||
|     the Free Software Foundation; either version 2 of the License, or | ||||
|     (at your option) any later version. | ||||
|   | ||||
|     This program is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|     GNU General Public License for more details. | ||||
|   | ||||
|     You should have received a copy of the GNU General Public License | ||||
|     along with this program; if not, write to the Free Software | ||||
|     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||||
| 
 | ||||
| /* We can provide simple Thumb simulation by decoding the Thumb
 | ||||
| instruction into its corresponding ARM instruction, and using the | ||||
| existing ARM simulator.  */ | ||||
| 
 | ||||
| #include "skyeye_defs.h" | ||||
| 
 | ||||
| #ifndef MODET			/* required for the Thumb instruction support */ | ||||
| #if 1 | ||||
| #error "MODET needs to be defined for the Thumb world to work" | ||||
| #else | ||||
| #define MODET (1) | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
| #include "armdefs.h" | ||||
| #include "armemu.h" | ||||
| #include "armos.h" | ||||
| 
 | ||||
| 
 | ||||
| /* Decode a 16bit Thumb instruction.  The instruction is in the low
 | ||||
|    16-bits of the tinstr field, with the following Thumb instruction | ||||
|    held in the high 16-bits.  Passing in two Thumb instructions allows | ||||
|    easier simulation of the special dual BL instruction.  */ | ||||
| 
 | ||||
| tdstate | ||||
| ARMul_ThumbDecode ( | ||||
|      ARMul_State *state, | ||||
|      ARMword pc, | ||||
|      ARMword tinstr, | ||||
|      ARMword *ainstr) | ||||
| { | ||||
| 	tdstate valid = t_decoded;	/* default assumes a valid instruction */ | ||||
| 	ARMword next_instr; | ||||
| 
 | ||||
| 	if (state->bigendSig) { | ||||
| 		next_instr = tinstr & 0xFFFF; | ||||
| 		tinstr >>= 16; | ||||
| 	} | ||||
| 	else { | ||||
| 		next_instr = tinstr >> 16; | ||||
| 		tinstr &= 0xFFFF; | ||||
| 	} | ||||
| 
 | ||||
| #if 1				/* debugging to catch non updates */ | ||||
| 	*ainstr = 0xDEADC0DE; | ||||
| #endif | ||||
| 
 | ||||
| 	switch ((tinstr & 0xF800) >> 11) { | ||||
| 	case 0:		/* LSL */ | ||||
| 	case 1:		/* LSR */ | ||||
| 	case 2:		/* ASR */ | ||||
| 		/* Format 1 */ | ||||
| 		*ainstr = 0xE1B00000	/* base opcode */ | ||||
| 			| ((tinstr & 0x1800) >> (11 - 5))	/* shift type */ | ||||
| 			|((tinstr & 0x07C0) << (7 - 6))	/* imm5 */ | ||||
| 			|((tinstr & 0x0038) >> 3)	/* Rs */ | ||||
| 			|((tinstr & 0x0007) << 12);	/* Rd */ | ||||
| 		break; | ||||
| 	case 3:		/* ADD/SUB */ | ||||
| 		/* Format 2 */ | ||||
| 		{ | ||||
| 			ARMword subset[4] = { | ||||
| 				0xE0900000,	/* ADDS Rd,Rs,Rn    */ | ||||
| 				0xE0500000,	/* SUBS Rd,Rs,Rn    */ | ||||
| 				0xE2900000,	/* ADDS Rd,Rs,#imm3 */ | ||||
| 				0xE2500000	/* SUBS Rd,Rs,#imm3 */ | ||||
| 			}; | ||||
| 			/* It is quicker indexing into a table, than performing switch
 | ||||
| 			   or conditionals: */ | ||||
| 			*ainstr = subset[(tinstr & 0x0600) >> 9]	/* base opcode */ | ||||
| 				|((tinstr & 0x01C0) >> 6)	/* Rn or imm3 */ | ||||
| 				|((tinstr & 0x0038) << (16 - 3))	/* Rs */ | ||||
| 				|((tinstr & 0x0007) << (12 - 0));	/* Rd */ | ||||
| 		} | ||||
| 		break; | ||||
| 	case 4:		/* MOV */ | ||||
| 	case 5:		/* CMP */ | ||||
| 	case 6:		/* ADD */ | ||||
| 	case 7:		/* SUB */ | ||||
| 		/* Format 3 */ | ||||
| 		{ | ||||
| 			ARMword subset[4] = { | ||||
| 				0xE3B00000,	/* MOVS Rd,#imm8    */ | ||||
| 				0xE3500000,	/* CMP  Rd,#imm8    */ | ||||
| 				0xE2900000,	/* ADDS Rd,Rd,#imm8 */ | ||||
| 				0xE2500000,	/* SUBS Rd,Rd,#imm8 */ | ||||
| 			}; | ||||
| 			*ainstr = subset[(tinstr & 0x1800) >> 11]	/* base opcode */ | ||||
| 				|((tinstr & 0x00FF) >> 0)	/* imm8 */ | ||||
| 				|((tinstr & 0x0700) << (16 - 8))	/* Rn */ | ||||
| 				|((tinstr & 0x0700) << (12 - 8));	/* Rd */ | ||||
| 		} | ||||
| 		break; | ||||
| 	case 8:		/* Arithmetic and high register transfers */ | ||||
| 		/* TODO: Since the subsets for both Format 4 and Format 5
 | ||||
| 		   instructions are made up of different ARM encodings, we could | ||||
| 		   save the following conditional, and just have one large | ||||
| 		   subset. */ | ||||
| 		if ((tinstr & (1 << 10)) == 0) { | ||||
| 			/* Format 4 */ | ||||
|             enum OpcodeType { t_norm, t_shift, t_neg, t_mul }; | ||||
| 			struct ThumbOpcode { | ||||
| 				ARMword opcode; | ||||
|                 OpcodeType otype; | ||||
|             }; | ||||
| 
 | ||||
|             ThumbOpcode subset[16] = { | ||||
| 				{ | ||||
| 				0xE0100000, t_norm},	/* ANDS Rd,Rd,Rs     */ | ||||
| 				{ | ||||
| 				0xE0300000, t_norm},	/* EORS Rd,Rd,Rs     */ | ||||
| 				{ | ||||
| 				0xE1B00010, t_shift},	/* MOVS Rd,Rd,LSL Rs */ | ||||
| 				{ | ||||
| 				0xE1B00030, t_shift},	/* MOVS Rd,Rd,LSR Rs */ | ||||
| 				{ | ||||
| 				0xE1B00050, t_shift},	/* MOVS Rd,Rd,ASR Rs */ | ||||
| 				{ | ||||
| 				0xE0B00000, t_norm},	/* ADCS Rd,Rd,Rs     */ | ||||
| 				{ | ||||
| 				0xE0D00000, t_norm},	/* SBCS Rd,Rd,Rs     */ | ||||
| 				{ | ||||
| 				0xE1B00070, t_shift},	/* MOVS Rd,Rd,ROR Rs */ | ||||
| 				{ | ||||
| 				0xE1100000, t_norm},	/* TST  Rd,Rs        */ | ||||
| 				{ | ||||
| 				0xE2700000, t_neg},	/* RSBS Rd,Rs,#0     */ | ||||
| 				{ | ||||
| 				0xE1500000, t_norm},	/* CMP  Rd,Rs        */ | ||||
| 				{ | ||||
| 				0xE1700000, t_norm},	/* CMN  Rd,Rs        */ | ||||
| 				{ | ||||
| 				0xE1900000, t_norm},	/* ORRS Rd,Rd,Rs     */ | ||||
| 				{ | ||||
| 				0xE0100090, t_mul},	/* MULS Rd,Rd,Rs     */ | ||||
| 				{ | ||||
| 				0xE1D00000, t_norm},	/* BICS Rd,Rd,Rs     */ | ||||
| 				{ | ||||
| 				0xE1F00000, t_norm}	/* MVNS Rd,Rs        */ | ||||
| 			}; | ||||
| 			*ainstr = subset[(tinstr & 0x03C0) >> 6].opcode;	/* base */ | ||||
| 			switch (subset[(tinstr & 0x03C0) >> 6].otype) { | ||||
| 			case t_norm: | ||||
| 				*ainstr |= ((tinstr & 0x0007) << 16)	/* Rn */ | ||||
| 					|((tinstr & 0x0007) << 12)	/* Rd */ | ||||
| 					|((tinstr & 0x0038) >> 3);	/* Rs */ | ||||
| 				break; | ||||
| 			case t_shift: | ||||
| 				*ainstr |= ((tinstr & 0x0007) << 12)	/* Rd */ | ||||
| 					|((tinstr & 0x0007) >> 0)	/* Rm */ | ||||
| 					|((tinstr & 0x0038) << (8 - 3));	/* Rs */ | ||||
| 				break; | ||||
| 			case t_neg: | ||||
| 				*ainstr |= ((tinstr & 0x0007) << 12)	/* Rd */ | ||||
| 					|((tinstr & 0x0038) << (16 - 3));	/* Rn */ | ||||
| 				break; | ||||
| 			case t_mul: | ||||
| 				*ainstr |= ((tinstr & 0x0007) << 16)	/* Rd */ | ||||
| 					|((tinstr & 0x0007) << 8)	/* Rs */ | ||||
| 					|((tinstr & 0x0038) >> 3);	/* Rm */ | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		else { | ||||
| 			/* Format 5 */ | ||||
| 			ARMword Rd = ((tinstr & 0x0007) >> 0); | ||||
| 			ARMword Rs = ((tinstr & 0x0038) >> 3); | ||||
| 			if (tinstr & (1 << 7)) | ||||
| 				Rd += 8; | ||||
| 			if (tinstr & (1 << 6)) | ||||
| 				Rs += 8; | ||||
| 			switch ((tinstr & 0x03C0) >> 6) { | ||||
| 			case 0x1:	/* ADD Rd,Rd,Hs */ | ||||
| 			case 0x2:	/* ADD Hd,Hd,Rs */ | ||||
| 			case 0x3:	/* ADD Hd,Hd,Hs */ | ||||
| 				*ainstr = 0xE0800000	/* base */ | ||||
| 					| (Rd << 16)	/* Rn */ | ||||
| 					|(Rd << 12)	/* Rd */ | ||||
| 					|(Rs << 0);	/* Rm */ | ||||
| 				break; | ||||
| 			case 0x5:	/* CMP Rd,Hs */ | ||||
| 			case 0x6:	/* CMP Hd,Rs */ | ||||
| 			case 0x7:	/* CMP Hd,Hs */ | ||||
| 				*ainstr = 0xE1500000	/* base */ | ||||
| 					| (Rd << 16)	/* Rn */ | ||||
| 					|(Rd << 12)	/* Rd */ | ||||
| 					|(Rs << 0);	/* Rm */ | ||||
| 				break; | ||||
| 			case 0x9:	/* MOV Rd,Hs */ | ||||
| 			case 0xA:	/* MOV Hd,Rs */ | ||||
| 			case 0xB:	/* MOV Hd,Hs */ | ||||
| 				*ainstr = 0xE1A00000	/* base */ | ||||
| 					| (Rd << 16)	/* Rn */ | ||||
| 					|(Rd << 12)	/* Rd */ | ||||
| 					|(Rs << 0);	/* Rm */ | ||||
| 				break; | ||||
| 			case 0xC:	/* BX Rs */ | ||||
| 			case 0xD:	/* BX Hs */ | ||||
| 				*ainstr = 0xE12FFF10	/* base */ | ||||
| 					| ((tinstr & 0x0078) >> 3);	/* Rd */ | ||||
| 				break; | ||||
| 			case 0x0:	/* UNDEFINED */ | ||||
| 			case 0x4:	/* UNDEFINED */ | ||||
| 			case 0x8:	/* UNDEFINED */ | ||||
| 				valid = t_undefined; | ||||
| 				break; | ||||
| 			case 0xE:	/* BLX */ | ||||
| 			case 0xF:	/* BLX */ | ||||
| 				if (state->is_v5) { | ||||
| 					*ainstr = 0xE1200030	/* base */ | ||||
| 						|(Rs << 0);	/* Rm */ | ||||
| 				} else { | ||||
| 					valid = t_undefined; | ||||
| 				} | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		break; | ||||
| 	case 9:		/* LDR Rd,[PC,#imm8] */ | ||||
| 		/* Format 6 */ | ||||
| 		*ainstr = 0xE59F0000	/* base */ | ||||
| 			| ((tinstr & 0x0700) << (12 - 8))	/* Rd */ | ||||
| 			|((tinstr & 0x00FF) << (2 - 0));	/* off8 */ | ||||
| 		break; | ||||
| 	case 10: | ||||
| 	case 11: | ||||
| 		/* TODO: Format 7 and Format 8 perform the same ARM encoding, so
 | ||||
| 		   the following could be merged into a single subset, saving on | ||||
| 		   the following boolean: */ | ||||
| 		if ((tinstr & (1 << 9)) == 0) { | ||||
| 			/* Format 7 */ | ||||
| 			ARMword subset[4] = { | ||||
| 				0xE7800000,	/* STR  Rd,[Rb,Ro] */ | ||||
| 				0xE7C00000,	/* STRB Rd,[Rb,Ro] */ | ||||
| 				0xE7900000,	/* LDR  Rd,[Rb,Ro] */ | ||||
| 				0xE7D00000	/* LDRB Rd,[Rb,Ro] */ | ||||
| 			}; | ||||
| 			*ainstr = subset[(tinstr & 0x0C00) >> 10]	/* base */ | ||||
| 				|((tinstr & 0x0007) << (12 - 0))	/* Rd */ | ||||
| 				|((tinstr & 0x0038) << (16 - 3))	/* Rb */ | ||||
| 				|((tinstr & 0x01C0) >> 6);	/* Ro */ | ||||
| 		} | ||||
| 		else { | ||||
| 			/* Format 8 */ | ||||
| 			ARMword subset[4] = { | ||||
| 				0xE18000B0,	/* STRH  Rd,[Rb,Ro] */ | ||||
| 				0xE19000D0,	/* LDRSB Rd,[Rb,Ro] */ | ||||
| 				0xE19000B0,	/* LDRH  Rd,[Rb,Ro] */ | ||||
| 				0xE19000F0	/* LDRSH Rd,[Rb,Ro] */ | ||||
| 			}; | ||||
| 			*ainstr = subset[(tinstr & 0x0C00) >> 10]	/* base */ | ||||
| 				|((tinstr & 0x0007) << (12 - 0))	/* Rd */ | ||||
| 				|((tinstr & 0x0038) << (16 - 3))	/* Rb */ | ||||
| 				|((tinstr & 0x01C0) >> 6);	/* Ro */ | ||||
| 		} | ||||
| 		break; | ||||
| 	case 12:		/* STR Rd,[Rb,#imm5] */ | ||||
| 	case 13:		/* LDR Rd,[Rb,#imm5] */ | ||||
| 	case 14:		/* STRB Rd,[Rb,#imm5] */ | ||||
| 	case 15:		/* LDRB Rd,[Rb,#imm5] */ | ||||
| 		/* Format 9 */ | ||||
| 		{ | ||||
| 			ARMword subset[4] = { | ||||
| 				0xE5800000,	/* STR  Rd,[Rb,#imm5] */ | ||||
| 				0xE5900000,	/* LDR  Rd,[Rb,#imm5] */ | ||||
| 				0xE5C00000,	/* STRB Rd,[Rb,#imm5] */ | ||||
| 				0xE5D00000	/* LDRB Rd,[Rb,#imm5] */ | ||||
| 			}; | ||||
| 			/* The offset range defends on whether we are transferring a
 | ||||
| 			   byte or word value: */ | ||||
| 			*ainstr = subset[(tinstr & 0x1800) >> 11]	/* base */ | ||||
| 				|((tinstr & 0x0007) << (12 - 0))	/* Rd */ | ||||
| 				|((tinstr & 0x0038) << (16 - 3))	/* Rb */ | ||||
| 				|((tinstr & 0x07C0) >> (6 - ((tinstr & (1 << 12)) ? 0 : 2)));	/* off5 */ | ||||
| 		} | ||||
| 		break; | ||||
| 	case 16:		/* STRH Rd,[Rb,#imm5] */ | ||||
| 	case 17:		/* LDRH Rd,[Rb,#imm5] */ | ||||
| 		/* Format 10 */ | ||||
| 		*ainstr = ((tinstr & (1 << 11))	/* base */ | ||||
| 			   ? 0xE1D000B0	/* LDRH */ | ||||
| 			   : 0xE1C000B0)	/* STRH */ | ||||
| 			|((tinstr & 0x0007) << (12 - 0))	/* Rd */ | ||||
| 			|((tinstr & 0x0038) << (16 - 3))	/* Rb */ | ||||
| 			|((tinstr & 0x01C0) >> (6 - 1))	/* off5, low nibble */ | ||||
| 			|((tinstr & 0x0600) >> (9 - 8));	/* off5, high nibble */ | ||||
| 		break; | ||||
| 	case 18:		/* STR Rd,[SP,#imm8] */ | ||||
| 	case 19:		/* LDR Rd,[SP,#imm8] */ | ||||
| 		/* Format 11 */ | ||||
| 		*ainstr = ((tinstr & (1 << 11))	/* base */ | ||||
| 			   ? 0xE59D0000	/* LDR */ | ||||
| 			   : 0xE58D0000)	/* STR */ | ||||
| 			|((tinstr & 0x0700) << (12 - 8))	/* Rd */ | ||||
| 			|((tinstr & 0x00FF) << 2);	/* off8 */ | ||||
| 		break; | ||||
| 	case 20:		/* ADD Rd,PC,#imm8 */ | ||||
| 	case 21:		/* ADD Rd,SP,#imm8 */ | ||||
| 		/* Format 12 */ | ||||
| 		if ((tinstr & (1 << 11)) == 0) { | ||||
| 			/* NOTE: The PC value used here should by word aligned */ | ||||
| 			/* We encode shift-left-by-2 in the rotate immediate field,
 | ||||
| 			   so no shift of off8 is needed.  */ | ||||
| 			*ainstr = 0xE28F0F00	/* base */ | ||||
| 				| ((tinstr & 0x0700) << (12 - 8))	/* Rd */ | ||||
| 				|(tinstr & 0x00FF);	/* off8 */ | ||||
| 		} | ||||
| 		else { | ||||
| 			/* We encode shift-left-by-2 in the rotate immediate field,
 | ||||
| 			   so no shift of off8 is needed.  */ | ||||
| 			*ainstr = 0xE28D0F00	/* base */ | ||||
| 				| ((tinstr & 0x0700) << (12 - 8))	/* Rd */ | ||||
| 				|(tinstr & 0x00FF);	/* off8 */ | ||||
| 		} | ||||
| 		break; | ||||
| 	case 22: | ||||
| 	case 23: | ||||
| 		if ((tinstr & 0x0F00) == 0x0000) { | ||||
| 			/* Format 13 */ | ||||
| 			/* NOTE: The instruction contains a shift left of 2
 | ||||
| 			   equivalent (implemented as ROR #30): */ | ||||
| 			*ainstr = ((tinstr & (1 << 7))	/* base */ | ||||
| 				   ? 0xE24DDF00	/* SUB */ | ||||
| 				   : 0xE28DDF00)	/* ADD */ | ||||
| 				|(tinstr & 0x007F);	/* off7 */ | ||||
| 		} | ||||
| 		else if ((tinstr & 0x0F00) == 0x0e00) | ||||
| 			*ainstr = 0xEF000000 | SWI_Breakpoint; | ||||
| 		else { | ||||
| 			/* Format 14 */ | ||||
| 			ARMword subset[4] = { | ||||
| 				0xE92D0000,	/* STMDB sp!,{rlist}    */ | ||||
| 				0xE92D4000,	/* STMDB sp!,{rlist,lr} */ | ||||
| 				0xE8BD0000,	/* LDMIA sp!,{rlist}    */ | ||||
| 				0xE8BD8000	/* LDMIA sp!,{rlist,pc} */ | ||||
| 			}; | ||||
| 			*ainstr = subset[((tinstr & (1 << 11)) >> 10) | ((tinstr & (1 << 8)) >> 8)]	/* base */ | ||||
| 				|(tinstr & 0x00FF);	/* mask8 */ | ||||
| 		} | ||||
| 		break; | ||||
| 	case 24:		/* STMIA */ | ||||
| 	case 25:		/* LDMIA */ | ||||
| 		/* Format 15 */ | ||||
| 		*ainstr = ((tinstr & (1 << 11))	/* base */ | ||||
| 			   ? 0xE8B00000	/* LDMIA */ | ||||
| 			   : 0xE8A00000)	/* STMIA */ | ||||
| 			|((tinstr & 0x0700) << (16 - 8))	/* Rb */ | ||||
| 			|(tinstr & 0x00FF);	/* mask8 */ | ||||
| 		break; | ||||
| 	case 26:		/* Bcc */ | ||||
| 	case 27:		/* Bcc/SWI */ | ||||
| 		if ((tinstr & 0x0F00) == 0x0F00) { | ||||
| 			if (tinstr == (ARMul_ABORTWORD & 0xffff) && | ||||
| 					state->AbortAddr == pc) { | ||||
| 				*ainstr = ARMul_ABORTWORD; | ||||
| 				break; | ||||
| 			} | ||||
| 			/* Format 17 : SWI */ | ||||
| 			*ainstr = 0xEF000000; | ||||
| 			/* Breakpoint must be handled specially.  */ | ||||
| 			if ((tinstr & 0x00FF) == 0x18) | ||||
| 				*ainstr |= ((tinstr & 0x00FF) << 16); | ||||
| 			/* New breakpoint value.  See gdb/arm-tdep.c  */ | ||||
| 			else if ((tinstr & 0x00FF) == 0xFE) | ||||
| 				*ainstr |= SWI_Breakpoint; | ||||
| 			else | ||||
| 				*ainstr |= (tinstr & 0x00FF); | ||||
| 		} | ||||
| 		else if ((tinstr & 0x0F00) != 0x0E00) { | ||||
| 			/* Format 16 */ | ||||
| 			int doit = FALSE; | ||||
| 			/* TODO: Since we are doing a switch here, we could just add
 | ||||
| 			   the SWI and undefined instruction checks into this | ||||
| 			   switch to same on a couple of conditionals: */ | ||||
| 			switch ((tinstr & 0x0F00) >> 8) { | ||||
| 			case EQ: | ||||
| 				doit = ZFLAG; | ||||
| 				break; | ||||
| 			case NE: | ||||
| 				doit = !ZFLAG; | ||||
| 				break; | ||||
| 			case VS: | ||||
| 				doit = VFLAG; | ||||
| 				break; | ||||
| 			case VC: | ||||
| 				doit = !VFLAG; | ||||
| 				break; | ||||
| 			case MI: | ||||
| 				doit = NFLAG; | ||||
| 				break; | ||||
| 			case PL: | ||||
| 				doit = !NFLAG; | ||||
| 				break; | ||||
| 			case CS: | ||||
| 				doit = CFLAG; | ||||
| 				break; | ||||
| 			case CC: | ||||
| 				doit = !CFLAG; | ||||
| 				break; | ||||
| 			case HI: | ||||
| 				doit = (CFLAG && !ZFLAG); | ||||
| 				break; | ||||
| 			case LS: | ||||
| 				doit = (!CFLAG || ZFLAG); | ||||
| 				break; | ||||
| 			case GE: | ||||
| 				doit = ((!NFLAG && !VFLAG) | ||||
| 					|| (NFLAG && VFLAG)); | ||||
| 				break; | ||||
| 			case LT: | ||||
| 				doit = ((NFLAG && !VFLAG) | ||||
| 					|| (!NFLAG && VFLAG)); | ||||
| 				break; | ||||
| 			case GT: | ||||
| 				doit = ((!NFLAG && !VFLAG && !ZFLAG) | ||||
| 					|| (NFLAG && VFLAG && !ZFLAG)); | ||||
| 				break; | ||||
| 			case LE: | ||||
| 				doit = ((NFLAG && !VFLAG) | ||||
| 					|| (!NFLAG && VFLAG)) || ZFLAG; | ||||
| 				break; | ||||
| 			} | ||||
| 			if (doit) { | ||||
| 				state->Reg[15] = (pc + 4 | ||||
| 						  + (((tinstr & 0x7F) << 1) | ||||
| 						     | ((tinstr & (1 << 7)) ? | ||||
| 							0xFFFFFF00 : 0))); | ||||
| 				FLUSHPIPE; | ||||
| 			} | ||||
| 			valid = t_branch; | ||||
| 		} | ||||
| 		else		/* UNDEFINED : cc=1110(AL) uses different format */ | ||||
| 			valid = t_undefined; | ||||
| 		break; | ||||
| 	case 28:		/* B */ | ||||
| 		/* Format 18 */ | ||||
| 		state->Reg[15] = (pc + 4 + (((tinstr & 0x3FF) << 1) | ||||
| 					    | ((tinstr & (1 << 10)) ? | ||||
| 					       0xFFFFF800 : 0))); | ||||
| 		FLUSHPIPE; | ||||
| 		valid = t_branch; | ||||
| 		break; | ||||
| 	case 29: | ||||
| 		if(tinstr & 0x1) | ||||
| 			valid = t_undefined; | ||||
| 		else{ | ||||
| 			/* BLX 1 for armv5t and above */ | ||||
| 			ARMword tmp = (pc + 2); | ||||
| 			state->Reg[15] = | ||||
| 				(state->Reg[14] + ((tinstr & 0x07FF) << 1)) & 0xFFFFFFFC; | ||||
| 			state->Reg[14] = (tmp | 1); | ||||
| 			CLEART; | ||||
| 			DEBUG_LOG(ARM11, "In %s, After  BLX(1),LR=0x%x,PC=0x%x, offset=0x%x\n", __FUNCTION__, state->Reg[14], state->Reg[15], (tinstr &0x7FF) << 1); | ||||
| 			valid = t_branch; | ||||
| 			FLUSHPIPE; | ||||
| 		} | ||||
| 		break; | ||||
| 	case 30:		/* BL instruction 1 */ | ||||
| 		/* Format 19 */ | ||||
| 		/* There is no single ARM instruction equivalent for this Thumb
 | ||||
| 		   instruction. To keep the simulation simple (from the user | ||||
| 		   perspective) we check if the following instruction is the | ||||
| 		   second half of this BL, and if it is we simulate it | ||||
| 		   immediately.  */ | ||||
| 		state->Reg[14] = state->Reg[15] | ||||
| 			+ (((tinstr & 0x07FF) << 12) | ||||
| 			   | ((tinstr & (1 << 10)) ? 0xFF800000 : 0)); | ||||
| 		valid = t_branch;	/* in-case we don't have the 2nd half */ | ||||
| 		//tinstr = next_instr;	/* move the instruction down */
 | ||||
| 		//if (((tinstr & 0xF800) >> 11) != 31)
 | ||||
| 		//	break;	/* exit, since not correct instruction */
 | ||||
| 		/* else we fall through to process the second half of the BL */ | ||||
| 		//pc += 2;	/* point the pc at the 2nd half */
 | ||||
| 		state->Reg[15] = pc + 2; | ||||
| 		FLUSHPIPE; | ||||
| 		break; | ||||
| 	case 31:		/* BL instruction 2 */ | ||||
| 		/* Format 19 */ | ||||
| 		/* There is no single ARM instruction equivalent for this
 | ||||
| 		   instruction. Also, it should only ever be matched with the | ||||
| 		   fmt19 "BL instruction 1" instruction. However, we do allow | ||||
| 		   the simulation of it on its own, with undefined results if | ||||
| 		   r14 is not suitably initialised.  */ | ||||
| 		{ | ||||
| 			ARMword tmp = (pc + 2); | ||||
| 			state->Reg[15] = | ||||
| 				(state->Reg[14] + ((tinstr & 0x07FF) << 1)); | ||||
| 			state->Reg[14] = (tmp | 1); | ||||
| 			valid = t_branch; | ||||
| 			FLUSHPIPE; | ||||
| 		} | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	return valid; | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue