- fix CP15 register 1 (control register);
- fix CP15 register 2 (TCM size);
- remove CP15 from ARM7;
- fix some CPU bugs in THUMB mode (added comments from official reference);
- added loops for HLE BIOS exceptions;
This commit is contained in:
mtabachenko 2010-04-06 15:44:03 +00:00
parent 47bb26f093
commit 3eb9de4614
8 changed files with 506 additions and 247 deletions

View File

@ -3756,7 +3756,7 @@ static char * OP_BL_10(u32 adr, u32 i, char * txt)
}
static char * OP_BL_THUMB(u32 adr, u32 i, char * txt)
static char * OP_BL_11(u32 adr, u32 i, char * txt)
{
sprintf(txt, "BL #%X", (int)(part + ((i&0x7FF)<<1))&0xFFFFFFFC);
return txt;

View File

@ -43,6 +43,16 @@
#include "path.h"
//#define LOG_ARM9
//#define LOG_ARM7
bool dolog = true;
//#define LOG_TO_FILE
//#define LOG_TO_FILE_REGS
//===============================================================
FILE *fp_dis7 = NULL;
FILE *fp_dis9 = NULL;
PathInfo path;
TCommonSettings CommonSettings;
@ -147,6 +157,21 @@ void NDS_DeInit(void) {
if (cheatSearch)
delete cheatSearch;
#ifdef LOG_ARM7
if (fp_dis7 != NULL)
{
fclose(fp_dis7);
fp_dis7 = NULL;
}
#endif
#ifdef LOG_ARM9
if (fp_dis9 != NULL)
{
fclose(fp_dis9);
fp_dis9 = NULL;
}
#endif
}
BOOL NDS_SetROM(u8 * rom, u32 mask)
@ -355,8 +380,8 @@ static void loadrom(std::string fname) {
int NDS_LoadROM(const char *filename, const char *logicalFilename)
{
int type = ROM_NDS;
char buf[MAX_PATH];
int type = ROM_NDS;
char buf[MAX_PATH];
if (filename == NULL)
return -1;
@ -391,7 +416,7 @@ int NDS_LoadROM(const char *filename, const char *logicalFilename)
if (gameInfo.romsize < 352) {
return -1;
}
//decrypt if necessary..
@ -1677,10 +1702,6 @@ bool nds_loadstate(EMUFILE* is, int size)
return temp;
}
//#define LOG_ARM9
//#define LOG_ARM7
//bool dolog = false;
FORCEINLINE void arm9log()
{
#ifdef LOG_ARM9
@ -1692,18 +1713,34 @@ FORCEINLINE void arm9log()
else
des_arm_instructions_set[INDEX(NDS_ARM9.instruction)](NDS_ARM9.instruct_adr, NDS_ARM9.instruction, dasmbuf);
#ifdef LOG_TO_FILE
if (!fp_dis9) return;
#ifdef LOG_TO_FILE_REGS
fprintf(fp_dis9, "\t\t;R0:%08X R1:%08X R2:%08X R3:%08X R4:%08X R5:%08X R6:%08X R7:%08X R8:%08X R9:%08X\n\t\t;R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X| next %08X, N:%i Z:%i C:%i V:%i\n",
NDS_ARM9.R[0], NDS_ARM9.R[1], NDS_ARM9.R[2], NDS_ARM9.R[3], NDS_ARM9.R[4], NDS_ARM9.R[5], NDS_ARM9.R[6], NDS_ARM9.R[7],
NDS_ARM9.R[8], NDS_ARM9.R[9], NDS_ARM9.R[10], NDS_ARM9.R[11], NDS_ARM9.R[12], NDS_ARM9.R[13], NDS_ARM9.R[14], NDS_ARM9.R[15],
NDS_ARM9.next_instruction, NDS_ARM9.CPSR.bits.N, NDS_ARM9.CPSR.bits.Z, NDS_ARM9.CPSR.bits.C, NDS_ARM9.CPSR.bits.V);
#endif
fprintf(fp_dis9, "%s %08X\t%08X \t%s\n", NDS_ARM9.CPSR.bits.T?"THUMB":"ARM", NDS_ARM9.instruct_adr, NDS_ARM9.instruction, dasmbuf);
/*if (NDS_ARM9.instruction == 0)
{
dolog = false;
INFO("Disassembler is stopped\n");
}*/
#else
printf("%05d:%03d %12lld 9:%08X %08X %-30s R00:%08X R01:%08X R02:%08X R03:%08X R04:%08X R05:%08X R06:%08X R07:%08X R08:%08X R09:%08X R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X\n",
currFrameCounter, nds.VCount, nds_timer,
NDS_ARM9.instruct_adr,NDS_ARM9.instruction, dasmbuf,
NDS_ARM9.R[0], NDS_ARM9.R[1], NDS_ARM9.R[2], NDS_ARM9.R[3], NDS_ARM9.R[4], NDS_ARM9.R[5], NDS_ARM9.R[6], NDS_ARM9.R[7],
NDS_ARM9.R[8], NDS_ARM9.R[9], NDS_ARM9.R[10], NDS_ARM9.R[11], NDS_ARM9.R[12], NDS_ARM9.R[13], NDS_ARM9.R[14], NDS_ARM9.R[15]);
#endif
}
#endif
}
FORCEINLINE void arm7log()
{
#ifdef LOG_ARM7
#ifdef LOG_ARM7
if(dolog)
{
char dasmbuf[4096];
@ -1711,14 +1748,29 @@ FORCEINLINE void arm7log()
des_thumb_instructions_set[((NDS_ARM7.instruction)>>6)&1023](NDS_ARM7.instruct_adr, NDS_ARM7.instruction, dasmbuf);
else
des_arm_instructions_set[INDEX(NDS_ARM7.instruction)](NDS_ARM7.instruct_adr, NDS_ARM7.instruction, dasmbuf);
#ifdef LOG_TO_FILE
if (!fp_dis7) return;
#ifdef LOG_TO_FILE_REGS
fprintf(fp_dis7, "\t\t;R0:%08X R1:%08X R2:%08X R3:%08X R4:%08X R5:%08X R6:%08X R7:%08X R8:%08X R9:%08X\n\t\t;R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X| next %08X, N:%i Z:%i C:%i V:%i\n",
NDS_ARM7.R[0], NDS_ARM7.R[1], NDS_ARM7.R[2], NDS_ARM7.R[3], NDS_ARM7.R[4], NDS_ARM7.R[5], NDS_ARM7.R[6], NDS_ARM7.R[7],
NDS_ARM7.R[8], NDS_ARM7.R[9], NDS_ARM7.R[10], NDS_ARM7.R[11], NDS_ARM7.R[12], NDS_ARM7.R[13], NDS_ARM7.R[14], NDS_ARM7.R[15],
NDS_ARM7.next_instruction, NDS_ARM7.CPSR.bits.N, NDS_ARM7.CPSR.bits.Z, NDS_ARM7.CPSR.bits.C, NDS_ARM7.CPSR.bits.V);
#endif
fprintf(fp_dis7, "%s %08X\t%08X \t%s\n", NDS_ARM7.CPSR.bits.T?"THUMB":"ARM", NDS_ARM7.instruct_adr, NDS_ARM7.instruction, dasmbuf);
/*if (NDS_ARM7.instruction == 0)
{
dolog = false;
INFO("Disassembler is stopped\n");
}*/
#else
printf("%05d:%03d %12lld 7:%08X %08X %-30s R00:%08X R01:%08X R02:%08X R03:%08X R04:%08X R05:%08X R06:%08X R07:%08X R08:%08X R09:%08X R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X\n",
currFrameCounter, nds.VCount, nds_timer,
NDS_ARM7.instruct_adr,NDS_ARM7.instruction, dasmbuf,
NDS_ARM7.R[0], NDS_ARM7.R[1], NDS_ARM7.R[2], NDS_ARM7.R[3], NDS_ARM7.R[4], NDS_ARM7.R[5], NDS_ARM7.R[6], NDS_ARM7.R[7],
NDS_ARM7.R[8], NDS_ARM7.R[9], NDS_ARM7.R[10], NDS_ARM7.R[11], NDS_ARM7.R[12], NDS_ARM7.R[13], NDS_ARM7.R[14], NDS_ARM7.R[15]);
#endif
}
#endif
#endif
}
//these have not been tuned very well yet.
@ -2000,6 +2052,11 @@ void NDS_Reset()
MMU_Reset();
NDS_ARM7.BIOS_loaded = false;
NDS_ARM9.BIOS_loaded = false;
memset(MMU.ARM7_BIOS, 0, sizeof(MMU.ARM7_BIOS));
memset(MMU.ARM9_BIOS, 0, sizeof(MMU.ARM9_BIOS));
//ARM7 BIOS IRQ HANDLER
if(CommonSettings.UseExtBIOS == true)
inf = fopen(CommonSettings.ARM7BIOS,"rb");
@ -2008,33 +2065,39 @@ void NDS_Reset()
if(inf)
{
fread(MMU.ARM7_BIOS,1,16384,inf);
if (fread(MMU.ARM7_BIOS,1,16384,inf) == 16384) NDS_ARM7.BIOS_loaded = true;
fclose(inf);
if(CommonSettings.SWIFromBIOS == true) NDS_ARM7.swi_tab = 0;
if((CommonSettings.SWIFromBIOS) && (NDS_ARM7.BIOS_loaded)) NDS_ARM7.swi_tab = 0;
else NDS_ARM7.swi_tab = ARM7_swi_tab;
if (CommonSettings.PatchSWI3)
_MMU_write16<ARMCPU_ARM7>(0x00002F08, 0x4770);
INFO("ARM7 BIOS is loaded.\n");
INFO("ARM7 BIOS is %s.\n", NDS_ARM7.BIOS_loaded?"loaded":"failed");
}
else
{
NDS_ARM7.swi_tab = ARM7_swi_tab;
for (int t = 0; t < 16384; t++)
MMU.ARM7_BIOS[t] = 0xFF;
T1WriteLong(MMU.ARM7_BIOS,0x00, 0xE25EF002);
T1WriteLong(MMU.ARM7_BIOS,0x04, 0xEAFFFFFE);
T1WriteLong(MMU.ARM7_BIOS,0x18, 0xEA000000);
T1WriteLong(MMU.ARM7_BIOS,0x20, 0xE92D500F);
T1WriteLong(MMU.ARM7_BIOS,0x24, 0xE3A00301);
T1WriteLong(MMU.ARM7_BIOS,0x28, 0xE28FE000);
T1WriteLong(MMU.ARM7_BIOS,0x2C, 0xE510F004);
T1WriteLong(MMU.ARM7_BIOS,0x30, 0xE8BD500F);
T1WriteLong(MMU.ARM7_BIOS,0x34, 0xE25EF004);
#if 0
// TODO
T1WriteLong(MMU.ARM7_BIOS, 0x0000, 0xEAFFFFFE); // loop for Reset !!!
T1WriteLong(MMU.ARM7_BIOS, 0x0004, 0xEAFFFFFE); // loop for Undef instr expection
T1WriteLong(MMU.ARM7_BIOS, 0x0008, 0xEA00009C); // SWI
T1WriteLong(MMU.ARM7_BIOS, 0x000C, 0xEAFFFFFE); // loop for Prefetch Abort
T1WriteLong(MMU.ARM7_BIOS, 0x0010, 0xEAFFFFFE); // loop for Data Abort
T1WriteLong(MMU.ARM7_BIOS, 0x0014, 0x00000000); // Reserved
T1WriteLong(MMU.ARM7_BIOS, 0x001C, 0x00000000); // Fast IRQ
#endif
T1WriteLong(MMU.ARM7_BIOS, 0x0000, 0xE25EF002);
T1WriteLong(MMU.ARM7_BIOS, 0x0018, 0xEA000000);
T1WriteLong(MMU.ARM7_BIOS, 0x0020, 0xE92D500F);
T1WriteLong(MMU.ARM7_BIOS, 0x0024, 0xE3A00301);
T1WriteLong(MMU.ARM7_BIOS, 0x0028, 0xE28FE000);
T1WriteLong(MMU.ARM7_BIOS, 0x002C, 0xE510F004);
T1WriteLong(MMU.ARM7_BIOS, 0x0030, 0xE8BD500F);
T1WriteLong(MMU.ARM7_BIOS, 0x0034, 0xE25EF004);
}
//ARM9 BIOS IRQ HANDLER
@ -2042,44 +2105,63 @@ void NDS_Reset()
inf = fopen(CommonSettings.ARM9BIOS,"rb");
else
inf = NULL;
//memcpy(MMU.ARM9_BIOS + 0x20, gba_header_data_0x04, 156);
if(inf)
{
fread(MMU.ARM9_BIOS,1,4096,inf);
if (fread(MMU.ARM9_BIOS,1,4096,inf) == 4096) NDS_ARM9.BIOS_loaded = true;
fclose(inf);
if(CommonSettings.SWIFromBIOS == true) NDS_ARM9.swi_tab = 0;
if((CommonSettings.SWIFromBIOS) && (NDS_ARM9.BIOS_loaded)) NDS_ARM9.swi_tab = 0;
else NDS_ARM9.swi_tab = ARM9_swi_tab;
if (CommonSettings.PatchSWI3)
_MMU_write16<ARMCPU_ARM9>(0xFFFF07CC, 0x4770);
INFO("ARM9 BIOS is loaded.\n");
INFO("ARM9 BIOS is %s.\n", NDS_ARM9.BIOS_loaded?"loaded":"failed");
}
else
{
NDS_ARM9.swi_tab = ARM9_swi_tab;
for (int t = 0; t < 4096; t++)
MMU.ARM9_BIOS[t] = 0xFF;
_MMU_write32<ARMCPU_ARM9>(0xFFFF0018, 0xEA000095);
for (int t = 0; t < 156; t++) // load logo
T1WriteLong(MMU.ARM9_BIOS, 0x0000, 0xEAFFFFFE); // loop for Reset !!!
T1WriteLong(MMU.ARM9_BIOS, 0x0004, 0xEAFFFFFE); // loop for Undef instr expection
T1WriteLong(MMU.ARM9_BIOS, 0x0008, 0xEA00009C); // SWI
T1WriteLong(MMU.ARM9_BIOS, 0x000C, 0xEAFFFFFE); // loop for Prefetch Abort
T1WriteLong(MMU.ARM9_BIOS, 0x0010, 0xEAFFFFFE); // loop for Data Abort
T1WriteLong(MMU.ARM9_BIOS, 0x0014, 0x00000000); // Reserved
T1WriteLong(MMU.ARM9_BIOS, 0x0018, 0xEA000095); // Normal IRQ
T1WriteLong(MMU.ARM9_BIOS, 0x001C, 0x00000000); // Fast IRQ
for (int t = 0; t < 156; t++) // logo
MMU.ARM9_BIOS[t + 0x20] = logo_data[t];
_MMU_write32<ARMCPU_ARM9>(0xFFFF0274, 0xE92D500F);
_MMU_write32<ARMCPU_ARM9>(0xFFFF0278, 0xEE190F11);
_MMU_write32<ARMCPU_ARM9>(0xFFFF027C, 0xE1A00620);
_MMU_write32<ARMCPU_ARM9>(0xFFFF0280, 0xE1A00600);
_MMU_write32<ARMCPU_ARM9>(0xFFFF0284, 0xE2800C40);
_MMU_write32<ARMCPU_ARM9>(0xFFFF0288, 0xE28FE000);
_MMU_write32<ARMCPU_ARM9>(0xFFFF028C, 0xE510F004);
_MMU_write32<ARMCPU_ARM9>(0xFFFF0290, 0xE8BD500F);
_MMU_write32<ARMCPU_ARM9>(0xFFFF0294, 0xE25EF004);
T1WriteLong(MMU.ARM9_BIOS, 0x0274, 0xE92D500F);
T1WriteLong(MMU.ARM9_BIOS, 0x0278, 0xEE190F11);
T1WriteLong(MMU.ARM9_BIOS, 0x027C, 0xE1A00620);
T1WriteLong(MMU.ARM9_BIOS, 0x0280, 0xE1A00600);
T1WriteLong(MMU.ARM9_BIOS, 0x0284, 0xE2800C40);
T1WriteLong(MMU.ARM9_BIOS, 0x0288, 0xE28FE000);
T1WriteLong(MMU.ARM9_BIOS, 0x028C, 0xE510F004);
T1WriteLong(MMU.ARM9_BIOS, 0x0290, 0xE8BD500F);
T1WriteLong(MMU.ARM9_BIOS, 0x0294, 0xE25EF004);
}
#ifdef LOG_ARM7
if (fp_dis7 != NULL)
{
fclose(fp_dis7);
fp_dis7 = NULL;
}
fp_dis7 = fopen("D:\\desmume_dis7.asm", "w");
#endif
#ifdef LOG_ARM9
if (fp_dis9 != NULL)
{
fclose(fp_dis9);
fp_dis9 = NULL;
}
fp_dis9 = fopen("D:\\desmume_dis9.asm", "w");
#endif
if (firmware)
{
delete firmware;
@ -2087,7 +2169,7 @@ void NDS_Reset()
}
firmware = new CFIRMWARE();
fw_success = firmware->load();
if ((CommonSettings.UseExtBIOS == true) && (CommonSettings.BootFromFirmware == true) && (fw_success == TRUE))
if (NDS_ARM7.BIOS_loaded && NDS_ARM9.BIOS_loaded && CommonSettings.BootFromFirmware && fw_success)
{
// Copy secure area to memory if needed
if ((header->ARM9src >= 0x4000) && (header->ARM9src < 0x8000))
@ -2220,8 +2302,8 @@ void NDS_Reset()
std::string rompath = "fat:/" + path.RomName;
const u32 kCommandline = 0x027E0000;
//const u32 kCommandline = 0x027FFF84;
//
//
_MMU_write32<ARMCPU_ARM9>(0x02FFFE70, 0x5f617267);
_MMU_write32<ARMCPU_ARM9>(0x02FFFE74, kCommandline); //(commandline starts here)
_MMU_write32<ARMCPU_ARM9>(0x02FFFE78, rompath.size()+1);
@ -2654,6 +2736,25 @@ void NDS_suspendProcessingInput(bool suspend)
void emu_halt() {
//printf("halting emu: ARM9 PC=%08X/%08X, ARM7 PC=%08X/%08X\n", NDS_ARM9.R[15], NDS_ARM9.instruct_adr, NDS_ARM7.R[15], NDS_ARM7.instruct_adr);
execute = false;
#ifdef LOG_ARM9
if (fp_dis9)
{
char buf[256] = { 0 };
sprintf(buf, "halting emu: ARM9 PC=%08X/%08X\n", NDS_ARM9.R[15], NDS_ARM9.instruct_adr);
fwrite(buf, 1, strlen(buf), fp_dis9);
INFO("ARM9 halted\n");
}
#endif
#ifdef LOG_ARM7
if (fp_dis7)
{
char buf[256] = { 0 };
sprintf(buf, "halting emu: ARM7 PC=%08X/%08X\n", NDS_ARM7.R[15], NDS_ARM7.instruct_adr);
fwrite(buf, 1, strlen(buf), fp_dis7);
INFO("ARM7 halted\n");
}
#endif
}
//these templates needed to be instantiated manually

View File

@ -230,11 +230,10 @@ void armcpu_init(armcpu_t *armcpu, u32 adr)
armcpu->irq_flag = 0;
#endif
if(armcpu->coproc[15]) free(armcpu->coproc[15]);
for(i = 0; i < 15; ++i)
{
armcpu->R[i] = 0;
if(armcpu->coproc[i]) free(armcpu->coproc[i]);
armcpu->coproc[i] = NULL;
}
@ -258,7 +257,9 @@ void armcpu_init(armcpu_t *armcpu, u32 adr)
armcpu->next_instruction = adr;
armcpu->coproc[15] = (armcp_t*)armcp15_new(armcpu);
// only ARM9 have co-processor
if (armcpu->proc_ID==0)
armcpu->coproc[15] = (armcp_t*)armcp15_new(armcpu);
#ifndef GDB_STUB
armcpu_prefetch(armcpu);
@ -380,10 +381,10 @@ FORCEINLINE static u32 armcpu_prefetch()
#ifdef GDB_STUB
u32 temp_instruction;
#endif
u32 curInstruction = armcpu->next_instruction;
if(armcpu->CPSR.bits.T == 0)
{
u32 curInstruction = armcpu->next_instruction;
#ifdef GDB_STUB
temp_instruction =
armcpu->mem_if->prefetch32( armcpu->mem_if->data,
@ -396,7 +397,8 @@ FORCEINLINE static u32 armcpu_prefetch()
armcpu->R[15] = armcpu->next_instruction + 4;
}
#else
armcpu->instruction = _MMU_read32<PROCNUM,MMU_AT_CODE>(curInstruction&0xFFFFFFFC);
curInstruction &= 0x0FFFFFFC;
armcpu->instruction = _MMU_read32<PROCNUM, MMU_AT_CODE>(curInstruction);
armcpu->instruct_adr = curInstruction;
armcpu->next_instruction = curInstruction + 4;
armcpu->R[15] = curInstruction + 8;
@ -405,7 +407,6 @@ FORCEINLINE static u32 armcpu_prefetch()
return MMU_codeFetchCycles<PROCNUM,32>(curInstruction);
}
u32 curInstruction = armcpu->next_instruction;
#ifdef GDB_STUB
temp_instruction =
armcpu->mem_if->prefetch16( armcpu->mem_if->data,
@ -418,7 +419,8 @@ FORCEINLINE static u32 armcpu_prefetch()
armcpu->R[15] = armcpu->next_instruction + 2;
}
#else
armcpu->instruction = _MMU_read16<PROCNUM, MMU_AT_CODE>(curInstruction&0xFFFFFFFE);
curInstruction &= 0x0FFFFFFE;
armcpu->instruction = _MMU_read16<PROCNUM, MMU_AT_CODE>(curInstruction);
armcpu->instruct_adr = curInstruction;
armcpu->next_instruction = curInstruction + 2;
armcpu->R[15] = curInstruction + 4;
@ -524,6 +526,43 @@ u32 armcpu_exec()
//this assert is annoying. but sometimes it is handy.
//assert(ARMPROC.instruct_adr!=0x00000000);
#ifdef DEVELOPER
if ((((ARMPROC.instruct_adr & 0x0F000000) == 0x0F000000) && (PROCNUM == 0)) ||
(((ARMPROC.instruct_adr & 0x0F000000) == 0x00000000) && (PROCNUM == 1)))
{
switch (ARMPROC.instruct_adr & 0xFFFF)
{
case 0x00000000:
printf("BIOS%c: Reset!!!\n", PROCNUM?'7':'9');
emu_halt();
break;
case 0x00000004:
printf("BIOS%c: Undefined instruction\n", PROCNUM?'7':'9');
emu_halt();
break;
case 0x00000008:
//printf("BIOS%c: SWI\n", PROCNUM?'7':'9');
break;
case 0x0000000C:
printf("BIOS%c: Prefetch Abort!!!\n", PROCNUM?'7':'9');
emu_halt();
break;
case 0x00000010:
printf("BIOS%c: Data Abort!!!\n", PROCNUM?'7':'9');
emu_halt();
break;
case 0x00000014:
printf("BIOS%c: Reserved!!!\n", PROCNUM?'7':'9');
break;
case 0x00000018:
//printf("BIOS%c: IRQ\n", PROCNUM?'7':'9');
break;
case 0x0000001C:
printf("BIOS%c: Fast IRQ\n", PROCNUM?'7':'9');
break;
}
}
#endif
#ifdef GDB_STUB
if (ARMPROC.stalled) {

View File

@ -45,6 +45,31 @@ inline T SIGNED_OVERFLOW(T a,T b,T c) { return BIT31(((a)&(b)&(~c)) | ((~a)&(~(b
template<typename T>
inline T SIGNED_UNDERFLOW(T a,T b,T c) { return BIT31(((a)&(~(b))&(~c)) | ((~a)&(b)&(c))); }
// ============================= CPRS flags funcs
static bool CarryFrom(s32 left, s32 right)
{
u32 res = (0xFFFFFFFF - (u32)left);
return ((u32)right > res);
}
static bool BorrowFrom(s32 left, s32 right)
{
return ((u32)right > (u32)left);
}
static bool OverflowFromADD(s32 alu_out, s32 left, s32 right)
{
return ((left >= 0 && right >= 0) || (left < 0 && right < 0))
&& ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
}
static bool OverflowFromSUB(s32 alu_out, s32 left, s32 right)
{
return ((left < 0 && right >= 0) || (left >= 0 && right < 0))
&& ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
}
//zero 15-feb-2009 - these werent getting used and they were getting in my way
//#define EQ 0x0
//#define NE 0x1
@ -175,6 +200,8 @@ struct armcpu_t
BOOL waitIRQ;
BOOL wirq;
BOOL BIOS_loaded;
u32 (* *swi_tab)();
// flag indicating if the processor is stalled (for debugging)

View File

@ -31,11 +31,12 @@ armcp15_t *armcp15_new(armcpu_t * c)
armcp15_t *armcp15 = (armcp15_t*)malloc(sizeof(armcp15_t));
if(!armcp15) return NULL;
armcp15->cpu = c;
armcp15->IDCode = 0x41049460;
armcp15->cacheType = 0x0F0D2112;
armcp15->TCMSize = 0x00140140;
armcp15->ctrl = 0x00000000;
armcp15->TCMSize = 0x00140180;
armcp15->ctrl = 0x00012078;
armcp15->DCConfig = 0x0;
armcp15->ICConfig = 0x0;
armcp15->writeBuffCtrl = 0x0;
@ -57,6 +58,10 @@ armcp15_t *armcp15_new(armcpu_t * c)
armcp15->DTCMRegion = 0x0080000A;
armcp15->processID = 0;
MMU.ARM9_RW_MODE = BIT7(armcp15->ctrl);
armcp15->cpu->intVector = 0xFFFF0000 * (BIT13(armcp15->ctrl));
armcp15->cpu->LDTBit = !BIT15(armcp15->ctrl); //TBit
/* preset calculated regionmasks */
for (i=0;i<8;i++) {
armcp15->regionWriteMask_USR[i] = 0 ;
@ -291,6 +296,7 @@ BOOL armcp15_moveCP2ARM(armcp15_t *armcp15, u32 * R, u8 CRn, u8 CRm, u8 opcode1,
if((opcode1==0) && (opcode2==0) && (CRm==0))
{
*R = armcp15->ctrl;
//LOG("CP15: CPtoARM ctrl %08X\n", armcp15->ctrl);
return TRUE;
}
return FALSE;
@ -315,6 +321,7 @@ BOOL armcp15_moveCP2ARM(armcp15_t *armcp15, u32 * R, u8 CRn, u8 CRm, u8 opcode1,
if((opcode1==0) && (opcode2==0) && (CRm==0))
{
*R = armcp15->writeBuffCtrl;
//LOG("CP15: CPtoARM writeBuffer ctrl %08X\n", armcp15->writeBuffCtrl);
return TRUE;
}
return FALSE;
@ -406,33 +413,38 @@ BOOL armcp15_moveCP2ARM(armcp15_t *armcp15, u32 * R, u8 CRn, u8 CRm, u8 opcode1,
}
}
static u32 CP15wait4IRQ(armcpu_t *cpu)
{
#if 1
u32 instructAddr = cpu->instruct_adr;
/* on the first call, wirq is not set */
// on the first call, wirq is not set
if(cpu->wirq)
{
/* check wether an irq was issued */
// check wether an irq was issued
if(!cpu->waitIRQ)
{
cpu->waitIRQ = 0;
cpu->wirq = 0;
return 1; /* return execution */
return 1; // return execution
}
/* otherwise, repeat this instruction */
// otherwise, repeat this instruction
cpu->R[15] = instructAddr;
cpu->next_instruction = instructAddr;
return 1;
}
/* first run, set us into waiting state */
// first run, set us into waiting state
cpu->waitIRQ = 1;
cpu->wirq = 1;
/* and set next instruction to repeat this */
// and set next instruction to repeat this
cpu->R[15] = instructAddr;
cpu->next_instruction = instructAddr;
/* CHECKME: IME shouldn't be modified (?) */
MMU.reg_IME[0] = 1;
#else
//printf("CP15: IME %X, IE %08X, IF %08X res %08X\n", MMU.reg_IME[0], MMU.reg_IE[0], MMU.reg_IF[0], MMU.reg_IE[0] & MMU.reg_IF[0]);
//if ((MMU.reg_IE[0] & MMU.reg_IF[0]) == 0) return 1;
cpu->waitIRQ = 1;
#endif
// only SWI set IME to 1
return 1;
}
@ -445,7 +457,9 @@ BOOL armcp15_moveARM2CP(armcp15_t *armcp15, u32 val, u8 CRn, u8 CRm, u8 opcode1,
case 1 :
if((opcode1==0) && (opcode2==0) && (CRm==0))
{
armcp15->ctrl = val;
//On the NDS bit0,2,7,12..19 are R/W, Bit3..6 are always set, all other bits are always zero.
armcp15->ctrl = (val & 0x000FF085) | 0x00000078;
MMU.ARM9_RW_MODE = BIT7(val);
//zero 31-jan-2010: change from 0x0FFF0000 to 0xFFFF0000 per gbatek
armcp15->cpu->intVector = 0xFFFF0000 * (BIT13(val));
@ -458,6 +472,8 @@ BOOL armcp15_moveARM2CP(armcp15_t *armcp15, u32 val, u8 CRn, u8 CRm, u8 opcode1,
{
log::ajouter("outch !!!!!!!");
}*/
//LOG("CP15: ARMtoCP ctrl %08X (val %08X)\n", armcp15->ctrl, val);
return TRUE;
}
return FALSE;
@ -481,6 +497,7 @@ BOOL armcp15_moveARM2CP(armcp15_t *armcp15, u32 val, u8 CRn, u8 CRm, u8 opcode1,
if((opcode1==0) && (opcode2==0) && (CRm==0))
{
armcp15->writeBuffCtrl = val;
//LOG("CP15: ARMtoCP writeBuffer ctrl %08X\n", armcp15->writeBuffCtrl);
return TRUE;
}
return FALSE;
@ -572,8 +589,10 @@ BOOL armcp15_moveARM2CP(armcp15_t *armcp15, u32 val, u8 CRn, u8 CRm, u8 opcode1,
switch(opcode2)
{
case 0 :
armcp15->DTCMRegion = val;
MMU.DTCMRegion = val & 0x0FFFFFFC0;
MMU.DTCMRegion = armcp15->DTCMRegion = val & 0x0FFFF000;
//MMU.DTCMRegion = val;
//MMU.DTCMRegion = val & 0x0FFFFFFC0;
//LOG("CP15: set DTCM %08X (size %i)\n", MMU.DTCMRegion, 512<<(val & 0x00000FFF));
/*sprintf(logbuf, "%08X", val);
log::ajouter(logbuf);*/
return TRUE;

View File

@ -497,10 +497,11 @@ static void cp15_saveone(armcp15_t *cp15, EMUFILE* os)
static void cp15_savestate(EMUFILE* os)
{
//version
write32le(0,os);
write32le(1,os);
cp15_saveone((armcp15_t *)NDS_ARM9.coproc[15],os);
cp15_saveone((armcp15_t *)NDS_ARM7.coproc[15],os);
//ARM7 not have coprocessor
//cp15_saveone((armcp15_t *)NDS_ARM7.coproc[15],os);
}
static bool cp15_loadone(armcp15_t *cp15, EMUFILE* is)
@ -553,10 +554,19 @@ static bool cp15_loadstate(EMUFILE* is, int size)
//read version
u32 version;
if(read32le(&version,is) != 1) return false;
if(version != 0) return false;
if(version > 1) return false;
if(!cp15_loadone((armcp15_t *)NDS_ARM9.coproc[15],is)) return false;
if(!cp15_loadone((armcp15_t *)NDS_ARM7.coproc[15],is)) return false;
if(version == 0)
{
//ARM7 not have coprocessor
u8 *tmp_buf = new u8 [sizeof(armcp15_t)];
if (!tmp_buf) return false;
if(!cp15_loadone((armcp15_t *)tmp_buf,is)) return false;
delete [] tmp_buf;
tmp_buf = NULL;
}
return true;
}

View File

@ -44,6 +44,7 @@
TEMPLATE static u32 FASTCALL OP_UND_THUMB(const u32 i)
{
INFO("THUMB%c: Undefined instruction: 0x%08X PC=0x%08X. Stopped!!!\n", cpu->proc_ID?'7':'9', cpu->instruction, cpu->instruct_adr);
emu_halt();
return 1;
}
@ -74,7 +75,7 @@ TEMPLATE static u32 FASTCALL OP_LSL(const u32 i)
TEMPLATE static u32 FASTCALL OP_LSL_REG(const u32 i)
{
u32 v = cpu->R[REG_NUM(i, 3)]&0xFF;
u32 v = cpu->R[REG_NUM(i, 3)] & 0xFF;
if(v == 0)
{
@ -129,7 +130,7 @@ TEMPLATE static u32 FASTCALL OP_LSR(const u32 i)
TEMPLATE static u32 FASTCALL OP_LSR_REG(const u32 i)
{
u32 v = cpu->R[REG_NUM(i, 3)]&0xFF;
u32 v = cpu->R[REG_NUM(i, 3)] & 0xFF;
if(v == 0)
{
@ -174,7 +175,7 @@ TEMPLATE static u32 FASTCALL OP_ASR(const u32 i)
{
u32 v = (i>>6) & 0x1F;
cpu->CPSR.bits.C = BIT_N(cpu->R[REG_NUM(i, 3)], v-1);
cpu->R[REG_NUM(i, 0)] = (((s32)cpu->R[REG_NUM(i, 3)]) >> v);
cpu->R[REG_NUM(i, 0)] = (u32)(((s32)cpu->R[REG_NUM(i, 3)]) >> v);
cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
@ -183,7 +184,7 @@ TEMPLATE static u32 FASTCALL OP_ASR(const u32 i)
TEMPLATE static u32 FASTCALL OP_ASR_REG(const u32 i)
{
u32 v = cpu->R[REG_NUM(i, 3)]&0xFF;
u32 v = cpu->R[REG_NUM(i, 3)] & 0xFF;
if(v == 0)
{
@ -212,47 +213,63 @@ TEMPLATE static u32 FASTCALL OP_ASR_REG(const u32 i)
// ADD
//-----------------------------------------------------------------------------
TEMPLATE static u32 FASTCALL OP_ADD_REG(const u32 i)
{
u32 a = cpu->R[REG_NUM(i, 3)];
u32 b = cpu->R[REG_NUM(i, 6)];
cpu->R[REG_NUM(i, 0)] = a + b;
cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
cpu->CPSR.bits.C = UNSIGNED_OVERFLOW(a, b, cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.V = SIGNED_OVERFLOW(a, b, cpu->R[REG_NUM(i, 0)]);
return 1;
}
TEMPLATE static u32 FASTCALL OP_ADD_IMM3(const u32 i)
{
u32 a = cpu->R[REG_NUM(i, 3)];
u32 imm3 = (i >> 6) & 0x07;
u32 Rn = cpu->R[REG_NUM(i, 3)];
cpu->R[REG_NUM(i, 0)] = a + REG_NUM(i, 6);
if (imm3 == 0) // mov 2
{
cpu->R[REG_NUM(i, 0)] = Rn;
cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
cpu->CPSR.bits.C = 0;
cpu->CPSR.bits.V = 0;
return 1;
}
cpu->R[REG_NUM(i, 0)] = Rn + imm3;
cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
cpu->CPSR.bits.C = UNSIGNED_OVERFLOW(a, REG_NUM(i, 6), cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.V = SIGNED_OVERFLOW(a, REG_NUM(i, 6), cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.C = CarryFrom(Rn, imm3);
cpu->CPSR.bits.V = OverflowFromADD(cpu->R[REG_NUM(i, 0)], Rn, imm3);
return 1;
}
TEMPLATE static u32 FASTCALL OP_ADD_IMM8(const u32 i)
{
u32 tmp = cpu->R[REG_NUM(i, 8)] + (i & 0xFF);
cpu->CPSR.bits.N = BIT31(tmp);
cpu->CPSR.bits.Z = tmp == 0;
cpu->CPSR.bits.C = UNSIGNED_OVERFLOW(cpu->R[REG_NUM(i, 8)], (i & 0xFF), tmp);
cpu->CPSR.bits.V = SIGNED_OVERFLOW(cpu->R[REG_NUM(i, 8)], (i & 0xFF), tmp);
cpu->R[REG_NUM(i, 8)] = tmp;
u32 imm8 = (i & 0xFF);
u32 Rd = cpu->R[REG_NUM(i, 8)];
cpu->R[REG_NUM(i, 8)] = Rd + imm8;
cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 8)]);
cpu->CPSR.bits.Z = (cpu->R[REG_NUM(i, 8)] == 0);
cpu->CPSR.bits.C = CarryFrom(Rd, imm8);
cpu->CPSR.bits.V = OverflowFromADD(cpu->R[REG_NUM(i, 8)], Rd, imm8);
return 1;
}
TEMPLATE static u32 FASTCALL OP_ADD_REG(const u32 i)
{
u32 Rn = cpu->R[REG_NUM(i, 3)];
u32 Rm = cpu->R[REG_NUM(i, 6)];
cpu->R[REG_NUM(i, 0)] = Rn + Rm;
cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
cpu->CPSR.bits.C = CarryFrom(Rn, Rm);
cpu->CPSR.bits.V = OverflowFromADD(cpu->R[REG_NUM(i, 0)], Rn, Rm);
return 1;
}
TEMPLATE static u32 FASTCALL OP_ADD_SPE(const u32 i)
{
u32 Rd = (i&7) | ((i>>4)&8);
u32 Rd = REG_NUM(i, 0) | ((i>>4)&8);
cpu->R[Rd] += cpu->R[REG_POS(i, 3)];
if(Rd==15)
@ -264,7 +281,6 @@ TEMPLATE static u32 FASTCALL OP_ADD_SPE(const u32 i)
return 1;
}
TEMPLATE static u32 FASTCALL OP_ADD_2PC(const u32 i)
{
cpu->R[REG_NUM(i, 8)] = (cpu->R[15]&0xFFFFFFFC) + ((i&0xFF)<<2);
@ -283,39 +299,44 @@ TEMPLATE static u32 FASTCALL OP_ADD_2SP(const u32 i)
// SUB
//-----------------------------------------------------------------------------
TEMPLATE static u32 FASTCALL OP_SUB_REG(const u32 i)
{
u32 a = cpu->R[REG_NUM(i, 3)];
u32 b = cpu->R[REG_NUM(i, 6)];
cpu->R[REG_NUM(i, 0)] = a - b;
cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
cpu->CPSR.bits.C = !UNSIGNED_UNDERFLOW(a, b, cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.V = SIGNED_UNDERFLOW(a, b, cpu->R[REG_NUM(i, 0)]);
return 1;
}
TEMPLATE static u32 FASTCALL OP_SUB_IMM3(const u32 i)
{
u32 a = cpu->R[REG_NUM(i, 3)];
cpu->R[REG_NUM(i, 0)] = a - REG_NUM(i, 6);
u32 imm3 = (i>>6) & 0x07;
u32 Rn = cpu->R[REG_NUM(i, 3)];
cpu->R[REG_NUM(i, 0)] = Rn - imm3;
cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
cpu->CPSR.bits.C = !UNSIGNED_UNDERFLOW(a, REG_NUM(i, 6), cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.V = SIGNED_UNDERFLOW(a, REG_NUM(i, 6), cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.C = !BorrowFrom(Rn, imm3);
cpu->CPSR.bits.V = OverflowFromSUB(REG_NUM(i, 0), Rn, imm3);
return 1;
}
TEMPLATE static u32 FASTCALL OP_SUB_IMM8(const u32 i)
{
u32 tmp = cpu->R[REG_NUM(i, 8)] - (i & 0xFF);
cpu->CPSR.bits.N = BIT31(tmp);
cpu->CPSR.bits.Z = tmp == 0;
cpu->CPSR.bits.C = !UNSIGNED_UNDERFLOW(cpu->R[REG_NUM(i, 8)], (i & 0xFF), tmp);
cpu->CPSR.bits.V = SIGNED_UNDERFLOW(cpu->R[REG_NUM(i, 8)], (i & 0xFF), tmp);
cpu->R[REG_NUM(i, 8)] = tmp;
u32 imm8 = (i & 0xFF);
u32 Rd = cpu->R[REG_NUM(i, 8)];
cpu->R[REG_NUM(i, 8)] = Rd - imm8;
cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 8)]);
cpu->CPSR.bits.Z = (cpu->R[REG_NUM(i, 8)] == 0);
cpu->CPSR.bits.C = !BorrowFrom(Rd, imm8);
cpu->CPSR.bits.V = OverflowFromSUB(cpu->R[REG_NUM(i, 8)], Rd, imm8);
return 1;
}
TEMPLATE static u32 FASTCALL OP_SUB_REG(const u32 i)
{
u32 Rn = cpu->R[REG_NUM(i, 3)];
u32 Rm = cpu->R[REG_NUM(i, 6)];
cpu->R[REG_NUM(i, 0)] = Rn - Rm;
cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.Z = (cpu->R[REG_NUM(i, 0)] == 0);
cpu->CPSR.bits.C = !BorrowFrom(Rn, Rm);
cpu->CPSR.bits.V = OverflowFromSUB(cpu->R[REG_NUM(i, 0)], Rn, Rm);
return 1;
}
@ -326,7 +347,7 @@ TEMPLATE static u32 FASTCALL OP_SUB_IMM8(const u32 i)
TEMPLATE static u32 FASTCALL OP_MOV_IMM8(const u32 i)
{
cpu->R[REG_NUM(i, 8)] = i & 0xFF;
cpu->R[REG_NUM(i, 8)] = (i & 0xFF);
cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 8)]);
cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 8)] == 0;
@ -335,7 +356,8 @@ TEMPLATE static u32 FASTCALL OP_MOV_IMM8(const u32 i)
TEMPLATE static u32 FASTCALL OP_MOV_SPE(const u32 i)
{
u32 Rd = (i&7) | ((i>>4)&8);
u32 Rd = REG_NUM(i, 0) | ((i>>4)&8);
cpu->R[Rd] = cpu->R[REG_POS(i, 3)];
if(Rd==15)
@ -350,40 +372,40 @@ TEMPLATE static u32 FASTCALL OP_MOV_SPE(const u32 i)
//-----------------------------------------------------------------------------
// CMP
//-----------------------------------------------------------------------------
TEMPLATE static u32 FASTCALL OP_CMP(const u32 i)
{
u32 tmp = cpu->R[REG_NUM(i, 0)] -cpu->R[REG_NUM(i, 3)];
cpu->CPSR.bits.N = BIT31(tmp);
cpu->CPSR.bits.Z = tmp == 0;
cpu->CPSR.bits.C = !UNSIGNED_UNDERFLOW(cpu->R[REG_NUM(i, 0)], cpu->R[REG_NUM(i, 3)], tmp);
cpu->CPSR.bits.V = SIGNED_UNDERFLOW(cpu->R[REG_NUM(i, 0)], cpu->R[REG_NUM(i, 3)], tmp);
return 1;
}
TEMPLATE static u32 FASTCALL OP_CMP_IMM8(const u32 i)
{
u32 tmp = cpu->R[REG_NUM(i, 8)] - (i & 0xFF);
cpu->CPSR.bits.N = BIT31(tmp);
cpu->CPSR.bits.Z = tmp == 0;
cpu->CPSR.bits.C = !UNSIGNED_UNDERFLOW(cpu->R[REG_NUM(i, 8)], (i & 0xFF), tmp);
cpu->CPSR.bits.V = SIGNED_UNDERFLOW(cpu->R[REG_NUM(i, 8)], (i & 0xFF), tmp);
cpu->CPSR.bits.C = !BorrowFrom(cpu->R[REG_NUM(i, 8)], (i & 0xFF));
cpu->CPSR.bits.V = OverflowFromSUB(tmp, cpu->R[REG_NUM(i, 8)], (i & 0xFF));
return 1;
}
TEMPLATE static u32 FASTCALL OP_CMP(const u32 i)
{
u32 tmp = cpu->R[REG_NUM(i, 0)] - cpu->R[REG_NUM(i, 3)];
cpu->CPSR.bits.N = BIT31(tmp);
cpu->CPSR.bits.Z = tmp == 0;
cpu->CPSR.bits.C = !BorrowFrom(cpu->R[REG_NUM(i, 0)], cpu->R[REG_NUM(i, 3)]);
cpu->CPSR.bits.V = OverflowFromSUB(tmp, cpu->R[REG_NUM(i, 0)], cpu->R[REG_NUM(i, 3)]);
return 1;
}
TEMPLATE static u32 FASTCALL OP_CMP_SPE(const u32 i)
{
u32 Rn = (i&7) | ((i>>4)&8);
u32 tmp = cpu->R[Rn] -cpu->R[REG_POS(i, 3)];
u32 tmp = cpu->R[Rn] - cpu->R[REG_POS(i, 3)];
cpu->CPSR.bits.N = BIT31(tmp);
cpu->CPSR.bits.Z = tmp == 0;
cpu->CPSR.bits.C = !UNSIGNED_UNDERFLOW(cpu->R[Rn], cpu->R[REG_POS(i, 3)], tmp);
cpu->CPSR.bits.V = SIGNED_UNDERFLOW(cpu->R[Rn], cpu->R[REG_POS(i, 3)], tmp);
cpu->CPSR.bits.C = !BorrowFrom(cpu->R[Rn], cpu->R[REG_NUM(i, 3)]);
cpu->CPSR.bits.V = OverflowFromSUB(tmp, cpu->R[Rn], cpu->R[REG_NUM(i, 3)]);
return 1;
}
@ -397,7 +419,6 @@ TEMPLATE static u32 FASTCALL OP_AND(const u32 i)
cpu->R[REG_NUM(i, 0)] &= cpu->R[REG_NUM(i, 3)];
cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
return 1;
}
@ -420,6 +441,22 @@ TEMPLATE static u32 FASTCALL OP_EOR(const u32 i)
TEMPLATE static u32 FASTCALL OP_ADC_REG(const u32 i)
{
#if 0
printf("THUMB%c: ADC\n", PROCNUM?'7':'9');
u32 Rd = cpu->R[REG_NUM(i, 0)];
u32 Rm = cpu->R[REG_NUM(i, 3)];
cpu->R[REG_NUM(i, 0)] = Rd + Rm + cpu->CPSR.bits.C;
cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.Z = (cpu->R[REG_NUM(i, 0)] == 0);
// TODO!!!!
cpu->CPSR.bits.C = CarryFrom(Rd, Rm + cpu->CPSR.bits.C);
cpu->CPSR.bits.V = OverflowFromADD(cpu->R[REG_NUM(i, 0)], Rd, Rm + cpu->CPSR.bits.C);
//cpu->CPSR.bits.C = UNSIGNED_OVERFLOW(b, (u32) cpu->CPSR.bits.C, tmp) | UNSIGNED_OVERFLOW(tmp, a, res);
//cpu->CPSR.bits.V = SIGNED_OVERFLOW(b, (u32) cpu->CPSR.bits.C, tmp) | SIGNED_OVERFLOW(tmp, a, res);
#else
u32 a = cpu->R[REG_NUM(i, 0)];
u32 b = cpu->R[REG_NUM(i, 3)];
u32 tmp = b + cpu->CPSR.bits.C;
@ -430,19 +467,9 @@ TEMPLATE static u32 FASTCALL OP_ADC_REG(const u32 i)
cpu->CPSR.bits.N = BIT31(res);
cpu->CPSR.bits.Z = res == 0;
#if 0
//the below UNSIGNED_OVERFLOW calculation is the clever way of doing it
//but just to keep from making a mistake, lets assert that it matches the precise definition of unsigned overflow
static long passcount = 0;
assert(++passcount);
assert(
((((u64)a+(u64)b+cpu->CPSR.bits.C)>>32)&1)
== (UNSIGNED_OVERFLOW(b, (u32) cpu->CPSR.bits.C, tmp) | UNSIGNED_OVERFLOW(tmp, a, res))
);
#endif
cpu->CPSR.bits.C = UNSIGNED_OVERFLOW(b, (u32) cpu->CPSR.bits.C, tmp) | UNSIGNED_OVERFLOW(tmp, a, res);
cpu->CPSR.bits.V = SIGNED_OVERFLOW(b, (u32) cpu->CPSR.bits.C, tmp) | SIGNED_OVERFLOW(tmp, a, res);
#endif
return 1;
}
@ -453,6 +480,17 @@ TEMPLATE static u32 FASTCALL OP_ADC_REG(const u32 i)
TEMPLATE static u32 FASTCALL OP_SBC_REG(const u32 i)
{
#if 0
u32 Rd = cpu->R[REG_NUM(i, 0)];
u32 Rm = cpu->R[REG_NUM(i, 3)];
cpu->R[REG_NUM(i, 0)] = Rd - Rm - !cpu->CPSR.bits.C;
cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.Z = (cpu->R[REG_NUM(i, 0)] == 0);
// TODO
#else
u32 a = cpu->R[REG_NUM(i, 0)];
u32 b = cpu->R[REG_NUM(i, 3)];
u32 tmp = a - (!cpu->CPSR.bits.C);
@ -462,22 +500,12 @@ TEMPLATE static u32 FASTCALL OP_SBC_REG(const u32 i)
cpu->CPSR.bits.N = BIT31(res);
cpu->CPSR.bits.Z = res == 0;
#if 0
//the below UNSIGNED_UNDERFLOW calculation is the clever way of doing it
//but just to keep from making a mistake, lets assert that it matches the precise definition of unsigned overflow
static long passcount = 0;
assert(++passcount);
assert(
((((u64)a-(u64)b-(!cpu->CPSR.bits.C))>>32)&1)
== UNSIGNED_UNDERFLOW(a, b, res)
);
#endif
//zero 31-dec-2008 - apply normatt's fixed logic from the arm SBC instruction
//although it seemed a bit odd to me and to whomever wrote this for SBC not to work similar to ADC..
//but thats how it is.
cpu->CPSR.bits.C = !UNSIGNED_UNDERFLOW(a, b, res);
cpu->CPSR.bits.V = SIGNED_UNDERFLOW(a, b, res);
#endif
return 1;
}
@ -488,7 +516,7 @@ TEMPLATE static u32 FASTCALL OP_SBC_REG(const u32 i)
TEMPLATE static u32 FASTCALL OP_ROR_REG(const u32 i)
{
u32 v = cpu->R[REG_NUM(i, 3)]&0xFF;
u32 v = cpu->R[REG_NUM(i, 3)] & 0xFF;
if(v == 0)
{
@ -496,6 +524,7 @@ TEMPLATE static u32 FASTCALL OP_ROR_REG(const u32 i)
cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
return 2;
}
v &= 0x1F;
if(v == 0)
{
@ -520,7 +549,7 @@ TEMPLATE static u32 FASTCALL OP_TST(const u32 i)
{
u32 tmp = cpu->R[REG_NUM(i, 0)] & cpu->R[REG_NUM(i, 3)];
cpu->CPSR.bits.N = BIT31(tmp);
cpu->CPSR.bits.Z = tmp == 0;
cpu->CPSR.bits.Z = (tmp == 0);
return 1;
}
@ -531,13 +560,14 @@ TEMPLATE static u32 FASTCALL OP_TST(const u32 i)
TEMPLATE static u32 FASTCALL OP_NEG(const u32 i)
{
u32 a = cpu->R[REG_NUM(i, 3)];
cpu->R[REG_NUM(i, 0)] = -((signed int)a);
u32 Rm = cpu->R[REG_NUM(i, 3)];
cpu->R[REG_NUM(i, 0)] = (u32)((s32)0 - (s32)Rm);
cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
cpu->CPSR.bits.C = !UNSIGNED_UNDERFLOW((u32)0, a, cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.V = SIGNED_UNDERFLOW((u32)0, a, cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.Z = (cpu->R[REG_NUM(i, 0)] == 0);
cpu->CPSR.bits.C = !BorrowFrom(0, Rm);
cpu->CPSR.bits.V = OverflowFromSUB(cpu->R[REG_NUM(i, 0)], 0, Rm);
return 1;
}
@ -567,8 +597,9 @@ TEMPLATE static u32 FASTCALL OP_CMN(const u32 i)
TEMPLATE static u32 FASTCALL OP_ORR(const u32 i)
{
cpu->R[REG_NUM(i, 0)] |= cpu->R[REG_NUM(i, 3)];
cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
cpu->CPSR.bits.Z = (cpu->R[REG_NUM(i, 0)] == 0);
return 1;
}
@ -580,8 +611,9 @@ TEMPLATE static u32 FASTCALL OP_ORR(const u32 i)
TEMPLATE static u32 FASTCALL OP_BIC(const u32 i)
{
cpu->R[REG_NUM(i, 0)] &= (~cpu->R[REG_NUM(i, 3)]);
cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
cpu->CPSR.bits.Z = (cpu->R[REG_NUM(i, 0)] == 0);
return 1;
}
@ -593,6 +625,7 @@ TEMPLATE static u32 FASTCALL OP_BIC(const u32 i)
TEMPLATE static u32 FASTCALL OP_MVN(const u32 i)
{
cpu->R[REG_NUM(i, 0)] = (~cpu->R[REG_NUM(i, 3)]);
cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
@ -618,9 +651,19 @@ TEMPLATE static u32 FASTCALL OP_MVN(const u32 i)
TEMPLATE static u32 FASTCALL OP_MUL_REG(const u32 i)
{
u32 v = cpu->R[REG_NUM(i, 3)];
// FIXME:
//------ Rd = (Rm * Rd)[31:0]
//------ u64 res = ((u64)cpu->R[REG_NUM(i, 0)] * (u64)v));
//------ cpu->R[REG_NUM(i, 0)] = (u32)(res & 0xFFFFFFFF);
//------
cpu->R[REG_NUM(i, 0)] *= v;
cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
//The MUL instruction is defined to leave the C flag unchanged in ARMv5 and above.
//In earlier versions of the architecture, the value of the C flag was UNPREDICTABLE
//after a MUL instruction.
if (PROCNUM == 1) // ARM4T 1S + mI, m = 3
return 4;
@ -643,7 +686,7 @@ TEMPLATE static u32 FASTCALL OP_STRB_IMM_OFF(const u32 i)
TEMPLATE static u32 FASTCALL OP_LDRB_IMM_OFF(const u32 i)
{
u32 adr = cpu->R[REG_NUM(i, 3)] + ((i>>6)&0x1F);
cpu->R[REG_NUM(i, 0)] = READ8(cpu->mem_if->data, adr);
cpu->R[REG_NUM(i, 0)] = (u32)READ8(cpu->mem_if->data, adr);
return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3, adr);
}
@ -652,7 +695,7 @@ TEMPLATE static u32 FASTCALL OP_LDRB_IMM_OFF(const u32 i)
TEMPLATE static u32 FASTCALL OP_STRB_REG_OFF(const u32 i)
{
u32 adr = cpu->R[REG_NUM(i, 3)] + cpu->R[REG_NUM(i, 6)];
WRITE8(cpu->mem_if->data, adr, ((u8)cpu->R[REG_NUM(i, 0)]));
WRITE8(cpu->mem_if->data, adr, (u8)cpu->R[REG_NUM(i, 0)]);
return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2, adr);
}
@ -672,7 +715,7 @@ TEMPLATE static u32 FASTCALL OP_LDRB_REG_OFF(const u32 i)
TEMPLATE static u32 FASTCALL OP_LDRSB_REG_OFF(const u32 i)
{
u32 adr = cpu->R[REG_NUM(i, 3)] + cpu->R[REG_NUM(i, 6)];
cpu->R[REG_NUM(i, 0)] = (s32)((s8)READ8(cpu->mem_if->data, adr));
cpu->R[REG_NUM(i, 0)] = (u32)((s8)READ8(cpu->mem_if->data, adr));
return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3, adr);
}
@ -692,7 +735,7 @@ TEMPLATE static u32 FASTCALL OP_STRH_IMM_OFF(const u32 i)
TEMPLATE static u32 FASTCALL OP_LDRH_IMM_OFF(const u32 i)
{
u32 adr = cpu->R[REG_NUM(i, 3)] + ((i>>5)&0x3E);
cpu->R[REG_NUM(i, 0)] = READ16(cpu->mem_if->data, adr);
cpu->R[REG_NUM(i, 0)] = (u32)READ16(cpu->mem_if->data, adr);
return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3, adr);
}
@ -721,7 +764,7 @@ TEMPLATE static u32 FASTCALL OP_LDRH_REG_OFF(const u32 i)
TEMPLATE static u32 FASTCALL OP_LDRSH_REG_OFF(const u32 i)
{
u32 adr = cpu->R[REG_NUM(i, 3)] + cpu->R[REG_NUM(i, 6)];
cpu->R[REG_NUM(i, 0)] = (s32)((s16)READ16(cpu->mem_if->data, adr));
cpu->R[REG_NUM(i, 0)] = (u32)((s16)READ16(cpu->mem_if->data, adr));
return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3, adr);
}
@ -741,11 +784,8 @@ TEMPLATE static u32 FASTCALL OP_STR_IMM_OFF(const u32 i)
TEMPLATE static u32 FASTCALL OP_LDR_IMM_OFF(const u32 i)
{
u32 adr = cpu->R[REG_NUM(i, 3)] + ((i>>4)&0x7C);
u32 tempValue = READ32(cpu->mem_if->data, adr);
adr = (adr&3)*8;
tempValue = (tempValue>>adr) | (tempValue<<(32-adr));
cpu->R[REG_NUM(i, 0)] = tempValue;
cpu->R[REG_NUM(i, 0)] = READ32(cpu->mem_if->data, adr);
return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_READ>(3, adr);
}
@ -761,11 +801,7 @@ TEMPLATE static u32 FASTCALL OP_STR_REG_OFF(const u32 i)
TEMPLATE static u32 FASTCALL OP_LDR_REG_OFF(const u32 i)
{
u32 adr = (cpu->R[REG_NUM(i, 3)] + cpu->R[REG_NUM(i, 6)]);
u32 tempValue = READ32(cpu->mem_if->data, adr);
adr = (adr&3)*8;
tempValue = (tempValue>>adr) | (tempValue<<(32-adr));
cpu->R[REG_NUM(i, 0)] = tempValue;
cpu->R[REG_NUM(i, 0)] = READ32(cpu->mem_if->data, adr);
return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_READ>(3, adr);
}
@ -782,16 +818,16 @@ TEMPLATE static u32 FASTCALL OP_STR_SPREL(const u32 i)
TEMPLATE static u32 FASTCALL OP_LDR_SPREL(const u32 i)
{
u32 adr = cpu->R[13] + ((i&0xFF)<<2);
cpu->R[REG_NUM(i, 8)] = READ32(cpu->mem_if->data, adr);
cpu->R[REG_NUM(i, 8)] = READ32(cpu->mem_if->data, adr);
return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_READ>(3, adr);
}
TEMPLATE static u32 FASTCALL OP_LDR_PCREL(const u32 i)
{
u32 adr = (cpu->R[15]&0xFFFFFFFC) + ((cpu->instruction&0xFF)<<2);
u32 adr = (cpu->R[15]&0xFFFFFFFC) + ((i&0xFF)<<2);
cpu->R[REG_NUM(cpu->instruction, 8)] = READ32(cpu->mem_if->data, adr);
cpu->R[REG_NUM(i, 8)] = READ32(cpu->mem_if->data, adr);
return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_READ>(3, adr);
}
@ -802,14 +838,14 @@ TEMPLATE static u32 FASTCALL OP_LDR_PCREL(const u32 i)
TEMPLATE static u32 FASTCALL OP_ADJUST_P_SP(const u32 i)
{
cpu->R[13] += ((cpu->instruction&0x7F)<<2);
cpu->R[13] += ((i&0x7F)<<2);
return 1;
}
TEMPLATE static u32 FASTCALL OP_ADJUST_M_SP(const u32 i)
{
cpu->R[13] -= ((cpu->instruction&0x7F)<<2);
cpu->R[13] -= ((i&0x7F)<<2);
return 1;
}
@ -823,7 +859,7 @@ TEMPLATE static u32 FASTCALL OP_PUSH(const u32 i)
u32 adr = cpu->R[13] - 4;
u32 c = 0, j;
for(j = 0; j<8; ++j)
for(j = 0; j<8; j++)
if(BIT_N(i, 7-j))
{
WRITE32(cpu->mem_if->data, adr, cpu->R[7-j]);
@ -844,7 +880,7 @@ TEMPLATE static u32 FASTCALL OP_PUSH_LR(const u32 i)
c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(adr);
adr -= 4;
for(j = 0; j<8; ++j)
for(j = 0; j<8; j++)
if(BIT_N(i, 7-j))
{
WRITE32(cpu->mem_if->data, adr, cpu->R[7-j]);
@ -861,7 +897,7 @@ TEMPLATE static u32 FASTCALL OP_POP(const u32 i)
u32 adr = cpu->R[13];
u32 c = 0, j;
for(j = 0; j<8; ++j)
for(j = 0; j<8; j++)
if(BIT_N(i, j))
{
cpu->R[j] = READ32(cpu->mem_if->data, adr);
@ -877,9 +913,9 @@ TEMPLATE static u32 FASTCALL OP_POP_PC(const u32 i)
{
u32 adr = cpu->R[13];
u32 c = 0, j;
u32 v;
u32 v = 0;
for(j = 0; j<8; ++j)
for(j = 0; j<8; j++)
if(BIT_N(i, j))
{
cpu->R[j] = READ32(cpu->mem_if->data, adr);
@ -909,10 +945,14 @@ TEMPLATE static u32 FASTCALL OP_STMIA_THUMB(const u32 i)
u32 c = 0, j;
u32 erList = 1; //Empty Register List
// ------ ARM_REF:
// ------ If <Rn> is specified in <registers>:
// ------ * If <Rn> is the lowest-numbered register specified in <registers>, the original value of <Rn> is stored.
// ------ * Otherwise, the stored value of <Rn> is UNPREDICTABLE.
if (BIT_N(i, REG_NUM(i, 8)))
printf("STMIA with Rb in Rlist\n");
for(j = 0; j<8; ++j)
for(j = 0; j<8; j++)
{
if(BIT_N(i, j))
{
@ -940,7 +980,7 @@ TEMPLATE static u32 FASTCALL OP_LDMIA_THUMB(const u32 i)
//if (BIT_N(i, regIndex))
// printf("LDMIA with Rb in Rlist at %08X\n",cpu->instruct_adr);
for(j = 0; j<8; ++j)
for(j = 0; j<8; j++)
{
if(BIT_N(i, j))
{
@ -954,8 +994,10 @@ TEMPLATE static u32 FASTCALL OP_LDMIA_THUMB(const u32 i)
if (erList)
printf("LDMIA with Empty Rlist\n");
// Only over-write if not on the read list
if(!BIT_N(i, regIndex))
// ARM_REF: THUMB: Causes base register write-back, and is not optional
// ARM_REF: If the base register <Rn> is specified in <registers>, the final value of <Rn> is the loaded value
// (not the written-back value).
if (!BIT_N(i, regIndex))
cpu->R[regIndex] = adr;
return MMU_aluMemCycles<PROCNUM>(3, c);
@ -967,6 +1009,8 @@ TEMPLATE static u32 FASTCALL OP_LDMIA_THUMB(const u32 i)
TEMPLATE static u32 FASTCALL OP_BKPT_THUMB(const u32 i)
{
// TODO
printf("THUMB%c: Unimplemented opcode BKPT\n", PROCNUM?'7':'9');
return 1;
}
@ -976,7 +1020,7 @@ TEMPLATE static u32 FASTCALL OP_BKPT_THUMB(const u32 i)
TEMPLATE static u32 FASTCALL OP_SWI_THUMB(const u32 i)
{
u32 swinum = cpu->instruction & 0xFF;
u32 swinum = i & 0xFF;
//ideas-style debug prints (execute this SWI with the null terminated string address in R0)
if(swinum==0xFC) {
@ -1026,7 +1070,7 @@ TEMPLATE static u32 FASTCALL OP_B_COND(const u32 i)
if(!TEST_COND((i>>8)&0xF, 0, cpu->CPSR))
return 1;
cpu->R[15] += ((s32)((s8)(i&0xFF)))<<1;
cpu->R[15] += (u32)((s8)(i&0xFF))<<1;
cpu->next_instruction = cpu->R[15];
return 3;
}
@ -1064,7 +1108,7 @@ TEMPLATE static u32 FASTCALL OP_BL_10(const u32 i)
return 1;
}
TEMPLATE static u32 FASTCALL OP_BL_THUMB(const u32 i)
TEMPLATE static u32 FASTCALL OP_BL_11(const u32 i)
{
cpu->R[15] = (cpu->R[14] + ((i&0x7FF)<<1));
cpu->R[14] = cpu->next_instruction | 1;
@ -1076,7 +1120,9 @@ TEMPLATE static u32 FASTCALL OP_BX_THUMB(const u32 i)
{
// When using PC as operand with BX opcode, switch to ARM state and jump to (instruct_adr+4)
// Reference: http://nocash.emubase.de/gbatek.htm#thumb5hiregisteroperationsbranchexchange
if (REG_POS(cpu->instruction, 3) == 15)
#if 0
if (REG_POS(i, 3) == 15)
{
cpu->CPSR.bits.T = 0;
cpu->R[15] &= 0xFFFFFFFC;
@ -1084,23 +1130,40 @@ TEMPLATE static u32 FASTCALL OP_BX_THUMB(const u32 i)
}
else
{
u32 Rm = cpu->R[REG_POS(cpu->instruction, 3)];
u32 Rm = cpu->R[REG_POS(i, 3)];
cpu->CPSR.bits.T = BIT0(Rm);
cpu->R[15] = (Rm & 0xFFFFFFFE);
cpu->next_instruction = cpu->R[15];
}
#else
u32 Rm = cpu->R[REG_POS(i, 3)];
//----- ARM_REF:
//----- Register 15 can be specified for <Rm>. If this is done, R15 is read as normal for Thumb code,
//----- that is, it is the address of the BX instruction itself plus 4. If the BX instruction is at a
//----- word-aligned address, this results in a branch to the next word, executing in ARM state.
//----- However, if the BX instruction is not at a word-aligned address, this means that the results of
//----- the instruction are UNPREDICTABLE (because the value read for R15 has bits[1:0]==0b10).
if (Rm == 15)
{
printf("THUMB%c: BX using PC as operand\n", PROCNUM?'7':'9');
//emu_halt();
}
cpu->CPSR.bits.T = BIT0(Rm);
cpu->R[15] = (Rm & (0xFFFFFFFC|(1<<cpu->CPSR.bits.T)));
cpu->next_instruction = cpu->R[15];
#endif
return 3;
}
TEMPLATE static u32 FASTCALL OP_BLX_THUMB(const u32 i)
{
u32 Rm = cpu->R[REG_POS(cpu->instruction, 3)];
u32 Rm = cpu->R[REG_POS(i, 3)];
cpu->CPSR.bits.T = BIT0(Rm);
cpu->R[14] = cpu->next_instruction | 1;
cpu->R[15] = (Rm & 0xFFFFFFFE);
//cpu->R[15] = (Rm & (0xFFFFFFFC|(1<<cpu->CPSR.bits.T)));
cpu->R[15] = (Rm & (0xFFFFFFFC|(1<<cpu->CPSR.bits.T)));
cpu->next_instruction = cpu->R[15];
return 4;

View File

@ -1072,36 +1072,36 @@ TABDECL( OP_BL_10), //11 1101 1101
TABDECL( OP_BL_10), //11 1101 1110
TABDECL( OP_BL_10), //11 1101 1111
TABDECL( OP_BL_THUMB), //11 1110 0000
TABDECL( OP_BL_THUMB), //11 1110 0001
TABDECL( OP_BL_THUMB), //11 1110 0010
TABDECL( OP_BL_THUMB), //11 1110 0011
TABDECL( OP_BL_THUMB), //11 1110 0100
TABDECL( OP_BL_THUMB), //11 1110 0101
TABDECL( OP_BL_THUMB), //11 1110 0110
TABDECL( OP_BL_THUMB), //11 1110 0111
TABDECL( OP_BL_THUMB), //11 1110 1000
TABDECL( OP_BL_THUMB), //11 1110 1001
TABDECL( OP_BL_THUMB), //11 1110 1010
TABDECL( OP_BL_THUMB), //11 1110 1011
TABDECL( OP_BL_THUMB), //11 1110 1100
TABDECL( OP_BL_THUMB), //11 1110 1101
TABDECL( OP_BL_THUMB), //11 1110 1110
TABDECL( OP_BL_THUMB), //11 1110 1111
TABDECL( OP_BL_11), //11 1110 0000
TABDECL( OP_BL_11), //11 1110 0001
TABDECL( OP_BL_11), //11 1110 0010
TABDECL( OP_BL_11), //11 1110 0011
TABDECL( OP_BL_11), //11 1110 0100
TABDECL( OP_BL_11), //11 1110 0101
TABDECL( OP_BL_11), //11 1110 0110
TABDECL( OP_BL_11), //11 1110 0111
TABDECL( OP_BL_11), //11 1110 1000
TABDECL( OP_BL_11), //11 1110 1001
TABDECL( OP_BL_11), //11 1110 1010
TABDECL( OP_BL_11), //11 1110 1011
TABDECL( OP_BL_11), //11 1110 1100
TABDECL( OP_BL_11), //11 1110 1101
TABDECL( OP_BL_11), //11 1110 1110
TABDECL( OP_BL_11), //11 1110 1111
TABDECL( OP_BL_THUMB), //11 1111 0000
TABDECL( OP_BL_THUMB), //11 1111 0001
TABDECL( OP_BL_THUMB), //11 1111 0010
TABDECL( OP_BL_THUMB), //11 1111 0011
TABDECL( OP_BL_THUMB), //11 1111 0100
TABDECL( OP_BL_THUMB), //11 1111 0101
TABDECL( OP_BL_THUMB), //11 1111 0110
TABDECL( OP_BL_THUMB), //11 1111 0111
TABDECL( OP_BL_THUMB), //11 1111 1000
TABDECL( OP_BL_THUMB), //11 1111 1001
TABDECL( OP_BL_THUMB), //11 1111 1010
TABDECL( OP_BL_THUMB), //11 1111 1011
TABDECL( OP_BL_THUMB), //11 1111 1100
TABDECL( OP_BL_THUMB), //11 1111 1101
TABDECL( OP_BL_THUMB), //11 1111 1110
TABDECL( OP_BL_THUMB), //11 1111 1111
TABDECL( OP_BL_11), //11 1111 0000
TABDECL( OP_BL_11), //11 1111 0001
TABDECL( OP_BL_11), //11 1111 0010
TABDECL( OP_BL_11), //11 1111 0011
TABDECL( OP_BL_11), //11 1111 0100
TABDECL( OP_BL_11), //11 1111 0101
TABDECL( OP_BL_11), //11 1111 0110
TABDECL( OP_BL_11), //11 1111 0111
TABDECL( OP_BL_11), //11 1111 1000
TABDECL( OP_BL_11), //11 1111 1001
TABDECL( OP_BL_11), //11 1111 1010
TABDECL( OP_BL_11), //11 1111 1011
TABDECL( OP_BL_11), //11 1111 1100
TABDECL( OP_BL_11), //11 1111 1101
TABDECL( OP_BL_11), //11 1111 1110
TABDECL( OP_BL_11), //11 1111 1111