/* All non fpu opcodes */ #include "types.h" #include "hw/sh4/sh4_mem.h" #include "hw/sh4/sh4_mmr.h" #include "hw/sh4/sh4_core.h" #include "hw/sh4/modules/mmu.h" #include "hw/sh4/sh4_interrupts.h" #include "debug/gdb_server.h" #include "hw/sh4/dyna/decoder.h" #include "emulator.h" #ifdef STRICT_MODE #include "hw/sh4/sh4_cache.h" #endif //Read Mem macros #define ReadMemU32(to,addr) to=ReadMem32(addr) #define ReadMemS32(to,addr) to=(s32)ReadMem32(addr) #define ReadMemS16(to,addr) to=(u32)(s32)(s16)ReadMem16(addr) #define ReadMemS8(to,addr) to=(u32)(s32)(s8)ReadMem8(addr) //Base,offset format #define ReadMemBOU32(to,addr,offset) ReadMemU32(to,addr+offset) #define ReadMemBOS16(to,addr,offset) ReadMemS16(to,addr+offset) #define ReadMemBOS8(to,addr,offset) ReadMemS8(to,addr+offset) //Write Mem Macros #define WriteMemU32(addr,data) WriteMem32(addr,(u32)data) #define WriteMemU16(addr,data) WriteMem16(addr,(u16)data) #define WriteMemU8(addr,data) WriteMem8(addr,(u8)data) //Base,offset format #define WriteMemBOU32(addr,offset,data) WriteMemU32(addr+offset,data) #define WriteMemBOU16(addr,offset,data) WriteMemU16(addr+offset,data) #define WriteMemBOU8(addr,offset,data) WriteMemU8(addr+offset,data) // 0xxx //stc GBR, sh4op(i0000_nnnn_0001_0010) { u32 n = GetN(op); ctx->r[n] = ctx->gbr; } //stc VBR, sh4op(i0000_nnnn_0010_0010) { u32 n = GetN(op); ctx->r[n] = ctx->vbr; } //stc SSR, sh4op(i0000_nnnn_0011_0010) { u32 n = GetN(op); ctx->r[n] = ctx->ssr; } //stc SGR, sh4op(i0000_nnnn_0011_1010) { u32 n = GetN(op); ctx->r[n] = ctx->sgr; } //stc SPC, sh4op(i0000_nnnn_0100_0010) { u32 n = GetN(op); ctx->r[n] = ctx->spc; } //stc RM_BANK, sh4op(i0000_nnnn_1mmm_0010) { u32 n = GetN(op); u32 m = GetM(op) & 0x7; ctx->r[n] = ctx->r_bank[m]; } //sts FPUL, sh4op(i0000_nnnn_0101_1010) { u32 n = GetN(op); ctx->r[n] = ctx->fpul; } //stc DBR, sh4op(i0000_nnnn_1111_1010) { u32 n = GetN(op); ctx->r[n] = ctx->dbr; } //sts MACH, sh4op(i0000_nnnn_0000_1010) { u32 n = GetN(op); ctx->r[n] = ctx->mac.h; } //sts MACL, sh4op(i0000_nnnn_0001_1010) { u32 n = GetN(op); ctx->r[n] = ctx->mac.l; } //sts PR, sh4op(i0000_nnnn_0010_1010) { u32 n = GetN(op); ctx->r[n] = ctx->pr; } //mov.b @(R0,), sh4op(i0000_nnnn_mmmm_1100) { u32 n = GetN(op); u32 m = GetM(op); ReadMemBOS8(ctx->r[n], ctx->r[0], ctx->r[m]); } //mov.w @(R0,), sh4op(i0000_nnnn_mmmm_1101) { u32 n = GetN(op); u32 m = GetM(op); ReadMemBOS16(ctx->r[n], ctx->r[0], ctx->r[m]); } //mov.l @(R0,), sh4op(i0000_nnnn_mmmm_1110) { u32 n = GetN(op); u32 m = GetM(op); ReadMemBOU32(ctx->r[n], ctx->r[0], ctx->r[m]); } //mov.b ,@(R0,) sh4op(i0000_nnnn_mmmm_0100) { u32 n = GetN(op); u32 m = GetM(op); WriteMemBOU8(ctx->r[0], ctx->r[n], ctx->r[m]); } //mov.w ,@(R0,) sh4op(i0000_nnnn_mmmm_0101) { u32 n = GetN(op); u32 m = GetM(op); WriteMemBOU16(ctx->r[0] , ctx->r[n], ctx->r[m]); } //mov.l ,@(R0,) sh4op(i0000_nnnn_mmmm_0110) { u32 n = GetN(op); u32 m = GetM(op); WriteMemBOU32(ctx->r[0], ctx->r[n], ctx->r[m]); } // // 1xxx //mov.l ,@(,) sh4op(i0001_nnnn_mmmm_iiii) { u32 n = GetN(op); u32 m = GetM(op); u32 disp = GetImm4(op); WriteMemBOU32(ctx->r[n] , (disp <<2), ctx->r[m]); } // // 2xxx //mov.b ,@ sh4op(i0010_nnnn_mmmm_0000) { u32 n = GetN(op); u32 m = GetM(op); WriteMemU8(ctx->r[n], ctx->r[m]); } // mov.w ,@ sh4op(i0010_nnnn_mmmm_0001) { u32 n = GetN(op); u32 m = GetM(op); WriteMemU16(ctx->r[n], ctx->r[m]); } // mov.l ,@ sh4op(i0010_nnnn_mmmm_0010) { u32 n = GetN(op); u32 m = GetM(op); WriteMemU32(ctx->r[n], ctx->r[m]); } // mov.b ,@- sh4op(i0010_nnnn_mmmm_0100) { u32 n = GetN(op); u32 m = GetM(op); u32 addr = ctx->r[n] - 1; WriteMemBOU8(ctx->r[n], (u32)-1, ctx->r[m]); ctx->r[n] = addr; } //mov.w ,@- sh4op(i0010_nnnn_mmmm_0101) { u32 n = GetN(op); u32 m = GetM(op); u32 addr = ctx->r[n] - 2; WriteMemU16(addr, ctx->r[m]); ctx->r[n] = addr; } //mov.l ,@- sh4op(i0010_nnnn_mmmm_0110) { u32 n = GetN(op); u32 m = GetM(op); u32 addr = ctx->r[n] - 4; WriteMemU32(addr, ctx->r[m]); ctx->r[n] = addr; } // // 4xxx //sts.l FPUL,@- sh4op(i0100_nnnn_0101_0010) { u32 n = GetN(op); u32 addr = ctx->r[n] - 4; WriteMemU32(addr, ctx->fpul); ctx->r[n] = addr; } //sts.l MACH,@- sh4op(i0100_nnnn_0000_0010) { u32 n = GetN(op); u32 addr = ctx->r[n] - 4; WriteMemU32(addr, ctx->mac.h); ctx->r[n] = addr; } //sts.l MACL,@- sh4op(i0100_nnnn_0001_0010) { u32 n = GetN(op); u32 addr = ctx->r[n] - 4; WriteMemU32(addr, ctx->mac.l); ctx->r[n] = addr; } //sts.l PR,@- sh4op(i0100_nnnn_0010_0010) { u32 n = GetN(op); u32 addr = ctx->r[n] - 4; WriteMemU32(addr, ctx->pr); ctx->r[n] = addr; } //sts.l DBR,@- sh4op(i0100_nnnn_1111_0010) { u32 n = GetN(op); u32 addr = ctx->r[n] - 4; WriteMemU32(addr, ctx->dbr); ctx->r[n] = addr; } //stc.l GBR,@- sh4op(i0100_nnnn_0001_0011) { u32 n = GetN(op); u32 addr = ctx->r[n] - 4; WriteMemU32(addr, ctx->gbr); ctx->r[n] = addr; } //stc.l VBR,@- sh4op(i0100_nnnn_0010_0011) { u32 n = GetN(op); u32 addr = ctx->r[n] - 4; WriteMemU32(addr, ctx->vbr); ctx->r[n] = addr; } //stc.l SSR,@- sh4op(i0100_nnnn_0011_0011) { u32 n = GetN(op); u32 addr = ctx->r[n] - 4; WriteMemU32(addr, ctx->ssr); ctx->r[n] = addr; } //stc.l SGR,@- sh4op(i0100_nnnn_0011_0010) { u32 n = GetN(op); u32 addr = ctx->r[n] - 4; WriteMemU32(addr, ctx->sgr); ctx->r[n] = addr; } //stc.l SPC,@- sh4op(i0100_nnnn_0100_0011) { u32 n = GetN(op); u32 addr = ctx->r[n] - 4; WriteMemU32(addr, ctx->spc); ctx->r[n] = addr; } //stc RM_BANK,@- sh4op(i0100_nnnn_1mmm_0011) { u32 n = GetN(op); u32 m = GetM(op) & 0x07; u32 addr = ctx->r[n] - 4; WriteMemU32(addr, ctx->r_bank[m]); ctx->r[n] = addr; } //lds.l @+,MACH sh4op(i0100_nnnn_0000_0110) { u32 n = GetN(op); ReadMemU32(ctx->mac.h, ctx->r[n]); ctx->r[n] += 4; } //lds.l @+,MACL sh4op(i0100_nnnn_0001_0110) { u32 n = GetN(op); ReadMemU32(ctx->mac.l, ctx->r[n]); ctx->r[n] += 4; } //lds.l @+,PR sh4op(i0100_nnnn_0010_0110) { u32 n = GetN(op); ReadMemU32(ctx->pr, ctx->r[n]); ctx->r[n] += 4; } //lds.l @+,FPUL sh4op(i0100_nnnn_0101_0110) { u32 n = GetN(op); ReadMemU32(ctx->fpul, ctx->r[n]); ctx->r[n] += 4; } //lds.l @+,DBR sh4op(i0100_nnnn_1111_0110) { u32 n = GetN(op); ReadMemU32(ctx->dbr, ctx->r[n]); ctx->r[n] += 4; } //ldc.l @+,GBR sh4op(i0100_nnnn_0001_0111) { u32 n = GetN(op); ReadMemU32(ctx->gbr, ctx->r[n]); ctx->r[n] += 4; } //ldc.l @+,VBR sh4op(i0100_nnnn_0010_0111) { u32 n = GetN(op); ReadMemU32(ctx->vbr, ctx->r[n]); ctx->r[n] += 4; } //ldc.l @+,SSR sh4op(i0100_nnnn_0011_0111) { u32 n = GetN(op); ReadMemU32(ctx->ssr, ctx->r[n]); ctx->r[n] += 4; } //ldc.l @+,SGR sh4op(i0100_nnnn_0011_0110) { u32 n = GetN(op); ReadMemU32(ctx->sgr, ctx->r[n]); ctx->r[n] += 4; } //ldc.l @+,SPC sh4op(i0100_nnnn_0100_0111) { u32 n = GetN(op); ReadMemU32(ctx->spc, ctx->r[n]); ctx->r[n] += 4; } //ldc.l @+,RM_BANK sh4op(i0100_nnnn_1mmm_0111) { u32 n = GetN(op); u32 m = GetM(op) & 7; ReadMemU32(ctx->r_bank[m], ctx->r[n]); ctx->r[n] += 4; } //lds ,MACH sh4op(i0100_nnnn_0000_1010) { u32 n = GetN(op); ctx->mac.h = ctx->r[n]; } //lds ,MACL sh4op(i0100_nnnn_0001_1010) { u32 n = GetN(op); ctx->mac.l = ctx->r[n]; } //lds ,PR sh4op(i0100_nnnn_0010_1010) { u32 n = GetN(op); ctx->pr = ctx->r[n]; } //lds ,FPUL sh4op(i0100_nnnn_0101_1010) { u32 n = GetN(op); ctx->fpul = ctx->r[n]; } //ldc ,DBR sh4op(i0100_nnnn_1111_1010) { u32 n = GetN(op); ctx->dbr = ctx->r[n]; } //ldc ,GBR sh4op(i0100_nnnn_0001_1110) { u32 n = GetN(op); ctx->gbr = ctx->r[n]; } //ldc ,VBR sh4op(i0100_nnnn_0010_1110) { u32 n = GetN(op); ctx->vbr = ctx->r[n]; } //ldc ,SSR sh4op(i0100_nnnn_0011_1110) { u32 n = GetN(op); ctx->ssr = ctx->r[n]; } //ldc ,SGR sh4op(i0100_nnnn_0011_1010) { u32 n = GetN(op); ctx->sgr = ctx->r[n]; } //ldc ,SPC sh4op(i0100_nnnn_0100_1110) { u32 n = GetN(op); ctx->spc = ctx->r[n]; } //ldc ,RM_BANK sh4op(i0100_nnnn_1mmm_1110) { u32 n = GetN(op); u32 m = GetM(op) & 7; ctx->r_bank[m] = ctx->r[n]; } // // 5xxx //mov.l @(,), sh4op(i0101_nnnn_mmmm_iiii) { u32 n = GetN(op); u32 m = GetM(op); u32 disp = GetImm4(op) << 2; ReadMemBOU32(ctx->r[n], ctx->r[m], disp); } // // 6xxx //mov.b @, sh4op(i0110_nnnn_mmmm_0000) { u32 n = GetN(op); u32 m = GetM(op); ReadMemS8(ctx->r[n], ctx->r[m]); } //mov.w @, sh4op(i0110_nnnn_mmmm_0001) { u32 n = GetN(op); u32 m = GetM(op); ReadMemS16(ctx->r[n], ctx->r[m]); } //mov.l @, sh4op(i0110_nnnn_mmmm_0010) { u32 n = GetN(op); u32 m = GetM(op); ReadMemU32(ctx->r[n], ctx->r[m]); } //mov , sh4op(i0110_nnnn_mmmm_0011) { u32 n = GetN(op); u32 m = GetM(op); ctx->r[n] = ctx->r[m]; } //mov.b @+, sh4op(i0110_nnnn_mmmm_0100) { u32 n = GetN(op); u32 m = GetM(op); ReadMemS8(ctx->r[n], ctx->r[m]); if (n != m) ctx->r[m] += 1; } //mov.w @+, sh4op(i0110_nnnn_mmmm_0101) { u32 n = GetN(op); u32 m = GetM(op); ReadMemS16(ctx->r[n], ctx->r[m]); if (n != m) ctx->r[m] += 2; } //mov.l @+, sh4op(i0110_nnnn_mmmm_0110) { u32 n = GetN(op); u32 m = GetM(op); ReadMemU32(ctx->r[n], ctx->r[m]); if (n != m) ctx->r[m] += 4; } // //8xxx // mov.b R0,@(,) sh4op(i1000_0000_mmmm_iiii) { u32 n = GetM(op); u32 disp = GetImm4(op); WriteMemBOU8(ctx->r[n], disp, ctx->r[0]); } // mov.w R0,@(,) sh4op(i1000_0001_mmmm_iiii) { u32 disp = GetImm4(op); u32 m = GetM(op); WriteMemBOU16(ctx->r[m], (disp << 1), ctx->r[0]); } // mov.b @(,),R0 sh4op(i1000_0100_mmmm_iiii) { u32 disp = GetImm4(op); u32 m = GetM(op); ReadMemBOS8(ctx->r[0], ctx->r[m] , disp); } // mov.w @(,),R0 sh4op(i1000_0101_mmmm_iiii) { u32 disp = GetImm4(op); u32 m = GetM(op); ReadMemBOS16(ctx->r[0], ctx->r[m], (disp << 1)); } // // 9xxx //mov.w @(,PC), sh4op(i1001_nnnn_iiii_iiii) { u32 n = GetN(op); u32 disp = GetImm8(op); ReadMemS16(ctx->r[n], (disp << 1) + ctx->pc + 2); } // // Cxxx // mov.b R0,@(,GBR) sh4op(i1100_0000_iiii_iiii) { u32 disp = GetImm8(op); WriteMemBOU8(ctx->gbr, disp, ctx->r[0]); } // mov.w R0,@(,GBR) sh4op(i1100_0001_iiii_iiii) { u32 disp = GetImm8(op); WriteMemBOU16(ctx->gbr, (disp << 1), ctx->r[0]); } // mov.l R0,@(,GBR) sh4op(i1100_0010_iiii_iiii) { u32 disp = GetImm8(op); WriteMemBOU32(ctx->gbr, (disp << 2), ctx->r[0]); } // mov.b @(,GBR),R0 sh4op(i1100_0100_iiii_iiii) { u32 disp = GetImm8(op); ReadMemBOS8(ctx->r[0], ctx->gbr, disp); } // mov.w @(,GBR),R0 sh4op(i1100_0101_iiii_iiii) { u32 disp = GetImm8(op); ReadMemBOS16(ctx->r[0], ctx->gbr, (disp << 1)); } // mov.l @(,GBR),R0 sh4op(i1100_0110_iiii_iiii) { u32 disp = GetImm8(op); ReadMemBOU32(ctx->r[0], ctx->gbr, (disp << 2)); } // mova @(,PC),R0 sh4op(i1100_0111_iiii_iiii) { ctx->r[0] = ((ctx->pc + 2) & 0xFFFFFFFC) + (GetImm8(op) << 2); } // // Dxxx // mov.l @(,PC), sh4op(i1101_nnnn_iiii_iiii) { u32 n = GetN(op); u32 disp = GetImm8(op); ReadMemU32(ctx->r[n], (disp << 2) + ((ctx->pc + 2) & 0xFFFFFFFC)); } // // Exxx // mov #, sh4op(i1110_nnnn_iiii_iiii) { u32 n = GetN(op); ctx->r[n] = (u32)(s32)(s8)GetSImm8(op); } //movca.l R0, @ sh4op(i0000_nnnn_1100_0011) { u32 n = GetN(op); WriteMemU32(ctx->r[n], ctx->r[0]); // TODO ocache } //clrmac sh4op(i0000_0000_0010_1000) { ctx->mac.full = 0; } static void executeDelaySlot() { Sh4Interpreter::Instance->ExecuteDelayslot(); } //braf sh4op(i0000_nnnn_0010_0011) { u32 n = GetN(op); u32 newpc = ctx->r[n] + ctx->pc + 2; executeDelaySlot(); //WARN : r[n] can change here ctx->pc = newpc; } //bsrf sh4op(i0000_nnnn_0000_0011) { u32 n = GetN(op); u32 newpc = ctx->r[n] + ctx->pc +2; u32 newpr = ctx->pc + 2; executeDelaySlot(); //WARN : pr and r[n] can change here ctx->pr = newpr; ctx->pc = newpc; debugger::subroutineCall(); } //rte sh4op(i0000_0000_0010_1011) { u32 newpc = ctx->spc; Sh4Interpreter::Instance->ExecuteDelayslot_RTE(); ctx->pc = newpc; if (UpdateSR()) UpdateINTC(); debugger::subroutineReturn(); } //rts sh4op(i0000_0000_0000_1011) { u32 newpc = ctx->pr; executeDelaySlot(); //WARN : pr can change here ctx->pc = newpc; debugger::subroutineReturn(); } u32 branch_target_s8(Sh4Context *ctx, u32 op) { return GetSImm8(op) * 2 + 2 + ctx->pc; } // bf sh4op(i1000_1011_iiii_iiii) { if (ctx->sr.T == 0) { //direct jump ctx->pc = branch_target_s8(ctx, op); } } // bf.s sh4op(i1000_1111_iiii_iiii) { if (ctx->sr.T == 0) { //delay 1 instruction u32 newpc = branch_target_s8(ctx, op); executeDelaySlot(); ctx->pc = newpc; } } // bt sh4op(i1000_1001_iiii_iiii) { if (ctx->sr.T != 0) { //direct jump ctx->pc = branch_target_s8(ctx, op); } } // bt.s sh4op(i1000_1101_iiii_iiii) { if (ctx->sr.T != 0) { //delay 1 instruction u32 newpc = branch_target_s8(ctx, op); executeDelaySlot(); ctx->pc = newpc; } } static u32 branch_target_s12(Sh4Context *ctx, u32 op) { return GetSImm12(op) * 2 + 2 + ctx->pc; } // bra sh4op(i1010_iiii_iiii_iiii) { u32 newpc = branch_target_s12(ctx, op); executeDelaySlot(); ctx->pc = newpc; } // bsr sh4op(i1011_iiii_iiii_iiii) { u32 newpr = ctx->pc + 2; //return after delayslot u32 newpc = branch_target_s12(ctx, op); executeDelaySlot(); ctx->pr = newpr; ctx->pc = newpc; debugger::subroutineCall(); } // trapa # sh4op(i1100_0011_iiii_iiii) { WARN_LOG(INTERPRETER, "TRAP #%X", GetImm8(op)); debugger::debugTrap(Sh4Ex_Trap); CCN_TRA = (GetImm8(op) << 2); Do_Exception(ctx->pc, Sh4Ex_Trap); } //jmp @ sh4op(i0100_nnnn_0010_1011) { u32 n = GetN(op); u32 newpc = ctx->r[n]; executeDelaySlot(); //r[n] can change here ctx->pc = newpc; } //jsr @ sh4op(i0100_nnnn_0000_1011) { u32 n = GetN(op); u32 newpr = ctx->pc + 2; //return after delayslot u32 newpc = ctx->r[n]; executeDelaySlot(); //r[n]/pr can change here ctx->pr = newpr; ctx->pc = newpc; debugger::subroutineCall(); } //sleep sh4op(i0000_0000_0001_1011) { //just wait for an Interrupt int i = 0, s = 1; while (!UpdateSystem_INTC())//448 { if (i++>1000) { s=0; break; } } //if not Interrupted , we must rexecute the sleep if (s == 0) ctx->pc -= 2;// re execute sleep } // sub , sh4op(i0011_nnnn_mmmm_1000) { u32 n = GetN(op); u32 m = GetM(op); ctx->r[n] -= ctx->r[m]; } //add , sh4op(i0011_nnnn_mmmm_1100) { u32 n = GetN(op); u32 m = GetM(op); ctx->r[n] += ctx->r[m]; } // // 7xxx //add #, sh4op(i0111_nnnn_iiii_iiii) { u32 n = GetN(op); s32 stmp1 = GetSImm8(op); ctx->r[n] += stmp1; } //Bitwise logical operations // //and , sh4op(i0010_nnnn_mmmm_1001) { u32 n = GetN(op); u32 m = GetM(op); ctx->r[n] &= ctx->r[m]; } //xor , sh4op(i0010_nnnn_mmmm_1010) { u32 n = GetN(op); u32 m = GetM(op); ctx->r[n] ^= ctx->r[m]; } //or , sh4op(i0010_nnnn_mmmm_1011) { u32 n = GetN(op); u32 m = GetM(op); ctx->r[n] |= ctx->r[m]; } //shll2 sh4op(i0100_nnnn_0000_1000) { u32 n = GetN(op); ctx->r[n] <<= 2; } //shll8 sh4op(i0100_nnnn_0001_1000) { u32 n = GetN(op); ctx->r[n] <<= 8; } //shll16 sh4op(i0100_nnnn_0010_1000) { u32 n = GetN(op); ctx->r[n] <<= 16; } //shlr2 sh4op(i0100_nnnn_0000_1001) { u32 n = GetN(op); ctx->r[n] >>= 2; } //shlr8 sh4op(i0100_nnnn_0001_1001) { u32 n = GetN(op); ctx->r[n] >>= 8; } //shlr16 sh4op(i0100_nnnn_0010_1001) { u32 n = GetN(op); ctx->r[n] >>= 16; } // and #,R0 sh4op(i1100_1001_iiii_iiii) { u32 imm = GetImm8(op); ctx->r[0] &= imm; } // xor #,R0 sh4op(i1100_1010_iiii_iiii) { u32 imm = GetImm8(op); ctx->r[0] ^= imm; } // or #,R0 sh4op(i1100_1011_iiii_iiii) { u32 imm = GetImm8(op); ctx->r[0] |= imm; } //nop sh4op(i0000_0000_0000_1001) { } //************************ TLB/Cache ************************ //ldtlb sh4op(i0000_0000_0011_1000) { UTLB[CCN_MMUCR.URC].Data = CCN_PTEL; UTLB[CCN_MMUCR.URC].Address = CCN_PTEH; UTLB[CCN_MMUCR.URC].Assistance = CCN_PTEA; UTLB_Sync(CCN_MMUCR.URC); } //ocbi @ sh4op(i0000_nnnn_1001_0011) { #ifdef STRICT_MODE ocache.WriteBack(ctx->r[GetN(op)], false, true); #endif } //ocbp @ sh4op(i0000_nnnn_1010_0011) { #ifdef STRICT_MODE ocache.WriteBack(ctx->r[GetN(op)], true, true); #endif } //ocbwb @ sh4op(i0000_nnnn_1011_0011) { #ifdef STRICT_MODE ocache.WriteBack(ctx->r[GetN(op)], true, false); #endif } //pref @ sh4op(i0000_nnnn_1000_0011) { u32 n = GetN(op); u32 Dest = ctx->r[n]; if ((Dest >> 26) == 0x38) // Store Queue { ctx->doSqWrite(Dest, ctx); } else { #ifdef STRICT_MODE ocache.Prefetch(Dest); #endif } } //************************ Set/Get T/S ************************ //sets sh4op(i0000_0000_0101_1000) { ctx->sr.S = 1; } //clrs sh4op(i0000_0000_0100_1000) { ctx->sr.S = 0; } //sett sh4op(i0000_0000_0001_1000) { ctx->sr.T = 1; } //clrt sh4op(i0000_0000_0000_1000) { ctx->sr.T = 0; } //movt sh4op(i0000_nnnn_0010_1001) { u32 n = GetN(op); ctx->r[n] = ctx->sr.T; } //************************ Reg Compares ************************ //cmp/pz sh4op(i0100_nnnn_0001_0001) { u32 n = GetN(op); if (((s32)ctx->r[n]) >= 0) ctx->sr.T = 1; else ctx->sr.T = 0; } //cmp/pl sh4op(i0100_nnnn_0001_0101) { u32 n = GetN(op); if ((s32)ctx->r[n] > 0) ctx->sr.T = 1; else ctx->sr.T = 0; } //cmp/eq #,R0 sh4op(i1000_1000_iiii_iiii) { u32 imm = (u32)(s32)(GetSImm8(op)); if (ctx->r[0] == imm) ctx->sr.T = 1; else ctx->sr.T = 0; } //cmp/eq , sh4op(i0011_nnnn_mmmm_0000) { u32 n = GetN(op); u32 m = GetM(op); if (ctx->r[m] == ctx->r[n]) ctx->sr.T = 1; else ctx->sr.T = 0; } //cmp/hs , sh4op(i0011_nnnn_mmmm_0010) { u32 n = GetN(op); u32 m = GetM(op); if (ctx->r[n] >= ctx->r[m]) ctx->sr.T = 1; else ctx->sr.T = 0; } //cmp/ge , sh4op(i0011_nnnn_mmmm_0011) { u32 n = GetN(op); u32 m = GetM(op); if ((s32)ctx->r[n] >= (s32)ctx->r[m]) ctx->sr.T = 1; else ctx->sr.T = 0; } //cmp/hi , sh4op(i0011_nnnn_mmmm_0110) { u32 n = GetN(op); u32 m = GetM(op); if (ctx->r[n] > ctx->r[m]) ctx->sr.T = 1; else ctx->sr.T = 0; } //cmp/gt , sh4op(i0011_nnnn_mmmm_0111) { u32 n = GetN(op); u32 m = GetM(op); if ((s32)ctx->r[n] > (s32)ctx->r[m]) ctx->sr.T = 1; else ctx->sr.T = 0; } //cmp/str , sh4op(i0010_nnnn_mmmm_1100) { //T -> 1 if -any- bytes are equal u32 n = GetN(op); u32 m = GetM(op); u32 temp; u32 HH, HL, LH, LL; temp = ctx->r[n] ^ ctx->r[m]; HH = (temp & 0xFF000000) >> 24; HL = (temp & 0x00FF0000) >> 16; LH = (temp & 0x0000FF00) >> 8; LL = temp & 0x000000FF; HH = HH && HL && LH && LL; if (HH == 0) ctx->sr.T = 1; else ctx->sr.T = 0; } //tst #,R0 sh4op(i1100_1000_iiii_iiii) { u32 utmp1 = ctx->r[0] & GetImm8(op); if (utmp1 == 0) ctx->sr.T = 1; else ctx->sr.T = 0; } //tst , sh4op(i0010_nnnn_mmmm_1000) { u32 n = GetN(op); u32 m = GetM(op); if ((ctx->r[n] & ctx->r[m]) != 0) ctx->sr.T = 0; else ctx->sr.T = 1; } //************************ mulls! ************************ //mulu.w , sh4op(i0010_nnnn_mmmm_1110) { u32 n = GetN(op); u32 m = GetM(op); ctx->mac.l = (u16)ctx->r[n] * (u16)ctx->r[m]; } //muls.w , sh4op(i0010_nnnn_mmmm_1111) { u32 n = GetN(op); u32 m = GetM(op); ctx->mac.l = (u32)((s16)ctx->r[n] * (s16)ctx->r[m]); } //dmulu.l , sh4op(i0011_nnnn_mmmm_0101) { u32 n = GetN(op); u32 m = GetM(op); ctx->mac.full = (u64)ctx->r[n] * (u64)ctx->r[m]; } //dmuls.l , sh4op(i0011_nnnn_mmmm_1101) { u32 n = GetN(op); u32 m = GetM(op); ctx->mac.full = (s64)(s32)ctx->r[n] * (s64)(s32)ctx->r[m]; } //mac.w @+,@+ sh4op(i0100_nnnn_mmmm_1111) { u32 n = GetN(op); u32 m = GetM(op); if (ctx->sr.S != 0) { die("mac.w @+,@+ : S=1"); } else { s32 rm,rn; rn = (s32)(s16)ReadMem16(ctx->r[n]); rm = (s32)(s16)ReadMem16(ctx->r[m] + (n == m ? 2 : 0)); ctx->r[n] += 2; ctx->r[m] += 2; s32 mul = rm * rn; ctx->mac.full += (s64)mul; } } //mac.l @+,@+ sh4op(i0000_nnnn_mmmm_1111) { u32 n = GetN(op); u32 m = GetM(op); s32 rm, rn; verify(ctx->sr.S == 0); ReadMemS32(rm, ctx->r[m]); ReadMemS32(rn, ctx->r[n] + (n == m ? 4 : 0)); ctx->r[m] += 4; ctx->r[n] += 4; ctx->mac.full += (s64)rm * (s64)rn; } //mul.l , sh4op(i0000_nnnn_mmmm_0111) { u32 n = GetN(op); u32 m = GetM(op); ctx->mac.l = (u32)((((s32)ctx->r[n]) * ((s32)ctx->r[m]))); } //************************ Div ! ************************ //div0u sh4op(i0000_0000_0001_1001) { ctx->sr.Q = 0; ctx->sr.M = 0; ctx->sr.T = 0; } //div0s , sh4op(i0010_nnnn_mmmm_0111) { u32 n = GetN(op); u32 m = GetM(op); ctx->sr.Q = ctx->r[n] >> 31; ctx->sr.M = ctx->r[m] >> 31; ctx->sr.T = ctx->sr.M ^ ctx->sr.Q; } //div1 , sh4op(i0011_nnnn_mmmm_0100) { u32 n = GetN(op); u32 m = GetM(op); const u8 old_q = ctx->sr.Q; ctx->sr.Q = (u8)((0x80000000 & ctx->r[n]) != 0); const u32 old_rm = ctx->r[m]; ctx->r[n] <<= 1; ctx->r[n] |= ctx->sr.T; const u32 old_rn = ctx->r[n]; if (old_q == 0) { if (ctx->sr.M == 0) { ctx->r[n] -= old_rm; bool tmp1 = ctx->r[n] > old_rn; ctx->sr.Q = ctx->sr.Q ^ tmp1; } else { ctx->r[n] += old_rm; bool tmp1 = ctx->r[n] < old_rn; ctx->sr.Q = !ctx->sr.Q ^ tmp1; } } else { if (ctx->sr.M == 0) { ctx->r[n] += old_rm; bool tmp1 = ctx->r[n] < old_rn; ctx->sr.Q = ctx->sr.Q ^ tmp1; } else { ctx->r[n] -= old_rm; bool tmp1 = ctx->r[n] > old_rn; ctx->sr.Q = !ctx->sr.Q ^ tmp1; } } ctx->sr.T = (ctx->sr.Q == ctx->sr.M); } //************************ Simple maths ************************ //addc , sh4op(i0011_nnnn_mmmm_1110) { u32 n = GetN(op); u32 m = GetM(op); u32 tmp1 = ctx->r[n] + ctx->r[m]; u32 tmp0 = ctx->r[n]; ctx->r[n] = tmp1 + ctx->sr.T; if (tmp0 > tmp1) ctx->sr.T = 1; else ctx->sr.T = 0; if (tmp1 > ctx->r[n]) ctx->sr.T = 1; } // addv , sh4op(i0011_nnnn_mmmm_1111) { //Retail game "Twinkle Star Sprites" "uses" this opcode. u32 n = GetN(op); u32 m = GetM(op); s64 br = (s64)(s32)ctx->r[n] + (s64)(s32)ctx->r[m]; if (br >=0x80000000) ctx->sr.T = 1; else if (br < (s64)0xFFFFFFFF80000000u) ctx->sr.T = 1; else ctx->sr.T = 0; ctx->r[n] += ctx->r[m]; } //subc , sh4op(i0011_nnnn_mmmm_1010) { u32 n = GetN(op); u32 m = GetM(op); u32 tmp1 = ctx->r[n] - ctx->r[m]; u32 tmp0 = ctx->r[n]; ctx->r[n] = tmp1 - ctx->sr.T; if (tmp0 < tmp1) ctx->sr.T = 1; else ctx->sr.T = 0; if (tmp1 < ctx->r[n]) ctx->sr.T = 1; } //subv , sh4op(i0011_nnnn_mmmm_1011) { //Retail game "Twinkle Star Sprites" "uses" this opcode. u32 n = GetN(op); u32 m = GetM(op); s64 br = (s64)(s32)ctx->r[n] - (s64)(s32)ctx->r[m]; if (br >= 0x80000000) ctx->sr.T = 1; else if (br < (s64) (0xFFFFFFFF80000000u)) ctx->sr.T = 1; else ctx->sr.T = 0; ctx->r[n] -= ctx->r[m]; } //dt sh4op(i0100_nnnn_0001_0000) { u32 n = GetN(op); ctx->r[n] -= 1; if (ctx->r[n] == 0) ctx->sr.T = 1; else ctx->sr.T = 0; } //negc , sh4op(i0110_nnnn_mmmm_1010) { u32 n = GetN(op); u32 m = GetM(op); //r[n]=-r[m]-sr.T; u32 tmp = 0 - ctx->r[m]; ctx->r[n] = tmp - ctx->sr.T; if (0 < tmp) ctx->sr.T = 1; else ctx->sr.T = 0; if (tmp < ctx->r[n]) ctx->sr.T = 1; } //neg , sh4op(i0110_nnnn_mmmm_1011) { u32 n = GetN(op); u32 m = GetM(op); ctx->r[n] = -ctx->r[m]; } //not , sh4op(i0110_nnnn_mmmm_0111) { u32 n = GetN(op); u32 m = GetM(op); ctx->r[n] = ~ctx->r[m]; } //************************ shifts/rotates ************************ //shll sh4op(i0100_nnnn_0000_0000) { u32 n = GetN(op); ctx->sr.T = ctx->r[n] >> 31; ctx->r[n] <<= 1; } //shal sh4op(i0100_nnnn_0010_0000) { u32 n = GetN(op); ctx->sr.T = ctx->r[n] >> 31; ctx->r[n] = ((s32)ctx->r[n]) << 1; } //shlr sh4op(i0100_nnnn_0000_0001) { u32 n = GetN(op); ctx->sr.T = ctx->r[n] & 0x1; ctx->r[n] >>= 1; } //shar sh4op(i0100_nnnn_0010_0001) { u32 n = GetN(op); ctx->sr.T = ctx->r[n] & 1; ctx->r[n] = ((s32)ctx->r[n]) >> 1; } //shad , sh4op(i0100_nnnn_mmmm_1100) { u32 n = GetN(op); u32 m = GetM(op); u32 sgn = ctx->r[m] & 0x80000000; if (sgn == 0) ctx->r[n] <<= ctx->r[m] & 0x1F; else if ((ctx->r[m] & 0x1F) == 0) ctx->r[n] = (s32)ctx->r[n] >> 31; else ctx->r[n] = (s32)ctx->r[n] >> ((~ctx->r[m] & 0x1F) + 1); } //shld , sh4op(i0100_nnnn_mmmm_1101) { u32 n = GetN(op); u32 m = GetM(op); u32 sgn = ctx->r[m] & 0x80000000; if (sgn == 0) ctx->r[n] <<= (ctx->r[m] & 0x1F); else if ((ctx->r[m] & 0x1F) == 0) ctx->r[n] = 0; else ctx->r[n] = ((u32)ctx->r[n]) >> ((~ctx->r[m] & 0x1F) + 1); //isn't this the same as -r[m] ? } //rotcl sh4op(i0100_nnnn_0010_0100) { u32 n = GetN(op); u32 t = ctx->sr.T; ctx->sr.T = ctx->r[n] >> 31; ctx->r[n] <<= 1; ctx->r[n] |= t; } //rotl sh4op(i0100_nnnn_0000_0100) { u32 n = GetN(op); ctx->sr.T = ctx->r[n] >> 31; ctx->r[n] <<= 1; ctx->r[n] |= ctx->sr.T; } //rotcr sh4op(i0100_nnnn_0010_0101) { u32 n = GetN(op); u32 t = ctx->r[n] & 0x1; ctx->r[n] >>= 1; ctx->r[n] |= ctx->sr.T << 31; ctx->sr.T = t; } //rotr sh4op(i0100_nnnn_0000_0101) { u32 n = GetN(op); ctx->sr.T = ctx->r[n] & 0x1; ctx->r[n] >>= 1; ctx->r[n] |= ctx->sr.T << 31; } //************************ byte reorder/sign ************************ //swap.b , sh4op(i0110_nnnn_mmmm_1000) { u32 m = GetM(op); u32 n = GetN(op); u32 rg = ctx->r[m]; ctx->r[n] = (rg & 0xFFFF0000) | ((rg & 0xFF) << 8) | ((rg >> 8) & 0xFF); } //swap.w , sh4op(i0110_nnnn_mmmm_1001) { u32 n = GetN(op); u32 m = GetM(op); u16 t = (u16)(ctx->r[m] >> 16); ctx->r[n] = (ctx->r[m] << 16) | t; } //extu.b , sh4op(i0110_nnnn_mmmm_1100) { u32 n = GetN(op); u32 m = GetM(op); ctx->r[n] = (u32)(u8)ctx->r[m]; } //extu.w , sh4op(i0110_nnnn_mmmm_1101) { u32 n = GetN(op); u32 m = GetM(op); ctx->r[n] = (u32)(u16)ctx->r[m]; } //exts.b , sh4op(i0110_nnnn_mmmm_1110) { u32 n = GetN(op); u32 m = GetM(op); ctx->r[n] = (u32)(s32)(s8)(u8)ctx->r[m]; } //exts.w , sh4op(i0110_nnnn_mmmm_1111) { u32 n = GetN(op); u32 m = GetM(op); ctx->r[n] = (u32)(s32)(s16)(u16)ctx->r[m]; } //xtrct , sh4op(i0010_nnnn_mmmm_1101) { u32 n = GetN(op); u32 m = GetM(op); ctx->r[n] = ((ctx->r[n] >> 16) & 0xFFFF) | ((ctx->r[m] << 16) & 0xFFFF0000); } //************************ xxx.b #,@(R0,GBR) ************************ //tst.b #,@(R0,GBR) sh4op(i1100_1100_iiii_iiii) { //Retail game "Twinkle Star Sprites" "uses" this opcode. u32 imm = GetImm8(op); u32 temp = (u8)ReadMem8(ctx->gbr + ctx->r[0]); temp &= imm; if (temp == 0) ctx->sr.T = 1; else ctx->sr.T = 0; } //and.b #,@(R0,GBR) sh4op(i1100_1101_iiii_iiii) { u8 temp = (u8)ReadMem8(ctx->gbr + ctx->r[0]); temp &= GetImm8(op); WriteMem8(ctx->gbr + ctx->r[0], temp); } //xor.b #,@(R0,GBR) sh4op(i1100_1110_iiii_iiii) { u8 temp = (u8)ReadMem8(ctx->gbr + ctx->r[0]); temp ^= GetImm8(op); WriteMem8(ctx->gbr + ctx->r[0], temp); } //or.b #,@(R0,GBR) sh4op(i1100_1111_iiii_iiii) { u8 temp = (u8)ReadMem8(ctx->gbr + ctx->r[0]); temp |= GetImm8(op); WriteMem8(ctx->gbr + ctx->r[0], temp); } //tas.b @ sh4op(i0100_nnnn_0001_1011) { u32 n = GetN(op); u8 val = (u8)ReadMem8(ctx->r[n]); u32 srT; if (val == 0) srT = 1; else srT = 0; val |= 0x80; WriteMem8(ctx->r[n], val); ctx->sr.T = srT; } //************************ Opcodes that read/write the status registers ************************ //stc SR, sh4op(i0000_nnnn_0000_0010)//0002 { u32 n = GetN(op); ctx->r[n] = ctx->sr.getFull(); } //sts FPSCR, sh4op(i0000_nnnn_0110_1010) { u32 n = GetN(op); ctx->r[n] = ctx->fpscr.full; } //sts.l FPSCR,@- sh4op(i0100_nnnn_0110_0010) { u32 n = GetN(op); WriteMemU32(ctx->r[n] - 4, ctx->fpscr.full); ctx->r[n] -= 4; } //stc.l SR,@- sh4op(i0100_nnnn_0000_0011) { u32 n = GetN(op); WriteMemU32(ctx->r[n] - 4, ctx->sr.getFull()); ctx->r[n] -= 4; } //lds.l @+,FPSCR sh4op(i0100_nnnn_0110_0110) { u32 n = GetN(op); ReadMemU32(ctx->fpscr.full, ctx->r[n]); Sh4Context::UpdateFPSCR(ctx); ctx->r[n] += 4; } //ldc.l @+,SR sh4op(i0100_nnnn_0000_0111) { u32 n = GetN(op); u32 sr_t; ReadMemU32(sr_t, ctx->r[n]); ctx->sr.setFull(sr_t); ctx->r[n] += 4; if (UpdateSR()) UpdateINTC(); } //lds ,FPSCR sh4op(i0100_nnnn_0110_1010) { u32 n = GetN(op); ctx->fpscr.full = ctx->r[n]; Sh4Context::UpdateFPSCR(ctx); } //ldc ,SR sh4op(i0100_nnnn_0000_1110) { u32 n = GetN(op); ctx->sr.setFull(ctx->r[n]); if (UpdateSR()) UpdateINTC(); } sh4op(iNotImplemented) { INFO_LOG(INTERPRETER, "iNimp %04X", op); debugger::debugTrap(Sh4Ex_IllegalInstr); throw SH4ThrownException(ctx->pc - 2, Sh4Ex_IllegalInstr); }