void BGEZALL_OUT(void) { local_rs = irs; reg[31]=PC->addr+8; if((&irs)!=(reg+31)) { if (local_rs >= 0) { jump_target = (int)PC->f.i.immediate; PC++; delay_slot=1; #ifdef DBG if (g_DebuggerActive) update_debugger(PC->addr); #endif PC->ops(); update_count(); delay_slot=0; if (!skip_jump) jump_to(PC->addr + ((jump_target-1)<<2)); } else PC+=2; } else DebugMessage(M64MSG_ERROR, "error in BGEZALL_OUT"); last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void BGEZALL_OUT(void) { local_rs = irs; reg[31]=PC->addr+8; if((&irs)!=(reg+31)) { if (local_rs >= 0) { jump_target = (int)PC->f.i.immediate; PC++; delay_slot=1; #ifdef DBG if (debugger_mode) update_debugger(PC->addr); #endif PC->ops(); update_count(); delay_slot=0; if (!skip_jump) jump_to(PC->addr + ((jump_target-1)<<2)); } else PC+=2; } else printf("erreur dans bgezall\n"); last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void BLTZALL(void) { local_rs = irs; reg[31]=PC->addr+8; if((&irs)!=(reg+31)) { if (local_rs < 0) { PC++; delay_slot=1; #ifdef DBG if (g_DebuggerActive) update_debugger(PC->addr); #endif PC->ops(); update_count(); delay_slot=0; if(!skip_jump) PC += (PC-2)->f.i.immediate-1; } else PC+=2; } else DebugMessage(M64MSG_ERROR, "error in BLTZALL"); last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
int write_mi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct r4300_core* r4300 = (struct r4300_core*)opaque; uint32_t reg = mi_reg(address); const uint32_t* cp0_regs = r4300_cp0_regs(); switch(reg) { case MI_INIT_MODE_REG: if (update_mi_init_mode(&r4300->mi.regs[MI_INIT_MODE_REG], value & mask) != 0) { clear_rcp_interrupt(r4300, MI_INTR_DP); } break; case MI_INTR_MASK_REG: update_mi_intr_mask(&r4300->mi.regs[MI_INTR_MASK_REG], value & mask); check_interupt(); cp0_update_count(); if (next_interupt <= cp0_regs[CP0_COUNT_REG]) gen_interupt(); break; } return 0; }
void BLTZALL(void) { local_rs = irs; reg[31]=PC->addr+8; if((&irs)!=(reg+31)) { if (local_rs < 0) { PC++; delay_slot=1; #ifdef DBG if (debugger_mode) update_debugger(PC->addr); #endif PC->ops(); update_count(); delay_slot=0; if(!skip_jump) PC += (PC-2)->f.i.immediate-1; } else PC+=2; } else printf("erreur dans bltzall\n"); last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void J() { PC++; delay_slot=1; PC->ops(); update_count(); delay_slot=0; if (!skip_jump) PC=actual->block+ (((((PC-2)->f.j.inst_index<<2) | ((PC-1)->addr & 0xF0000000))-actual->start)>>2); last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void J_OUT() { jump_target = (PC->addr & 0xF0000000) | (PC->f.j.inst_index<<2); PC++; delay_slot=1; PC->ops(); update_count(); delay_slot=0; if (!skip_jump) jump_to(jump_target); last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void BGEZ() { local_rs = irs; PC++; delay_slot=1; PC->ops(); update_count(); delay_slot=0; if (local_rs >= 0 && !skip_jump) PC += (PC-2)->f.i.immediate - 1; last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void BC1T() { if (check_cop1_unusable()) return; PC++; delay_slot=1; PC->ops(); update_count(); delay_slot=0; if ((FCR31 & 0x800000)!=0 && !skip_jump) PC += (PC-2)->f.i.immediate-1; last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void BC1T_OUT() { if (check_cop1_unusable()) return; jump_target = (long)PC->f.i.immediate; PC++; delay_slot=1; PC->ops(); update_count(); delay_slot=0; if (!skip_jump && (FCR31 & 0x800000)!=0) jump_to(PC->addr + ((jump_target-1)<<2)); last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void BGEZ_OUT() { local_rs = irs; jump_target = (long)PC->f.i.immediate; PC++; delay_slot=1; PC->ops(); update_count(); delay_slot=0; if (!skip_jump && local_rs >= 0) jump_to(PC->addr + ((jump_target-1)<<2)); last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void J_OUT(void) { jump_target = (PC->addr & 0xF0000000) | (PC->f.j.inst_index<<2); PC++; delay_slot=1; #ifdef DBG if (g_DebuggerActive) update_debugger(PC->addr); #endif PC->ops(); update_count(); delay_slot=0; if (!skip_jump) jump_to(jump_target); last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void BGEZ(void) { local_rs = irs; PC++; delay_slot=1; #ifdef DBG if (g_DebuggerActive) update_debugger(PC->addr); #endif PC->ops(); update_count(); delay_slot=0; if (local_rs >= 0 && !skip_jump) PC += (PC-2)->f.i.immediate - 1; last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void BC1T(void) { if (check_cop1_unusable()) return; PC++; delay_slot=1; #ifdef DBG if (g_DebuggerActive) update_debugger(PC->addr); #endif PC->ops(); update_count(); delay_slot=0; if ((FCR31 & 0x800000)!=0 && !skip_jump) PC += (PC-2)->f.i.immediate-1; last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void J(void) { PC++; delay_slot=1; #ifdef DBG if (g_DebuggerActive) update_debugger(PC->addr); #endif PC->ops(); update_count(); delay_slot=0; if (!skip_jump) PC=actual->block+ (((((PC-2)->f.j.inst_index<<2) | ((PC-1)->addr & 0xF0000000))-actual->start)>>2); last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void BC1T_OUT(void) { if (check_cop1_unusable()) return; jump_target = (int)PC->f.i.immediate; PC++; delay_slot=1; #ifdef DBG if (g_DebuggerActive) update_debugger(PC->addr); #endif PC->ops(); update_count(); delay_slot=0; if (!skip_jump && (FCR31 & 0x800000)!=0) jump_to(PC->addr + ((jump_target-1)<<2)); last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void BGEZL() { if (irs >= 0) { PC++; delay_slot=1; PC->ops(); update_count(); delay_slot=0; if(!skip_jump) PC += (PC-2)->f.i.immediate-1; } else PC+=2; last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void BLTZ_OUT(void) { local_rs = irs; jump_target = (int)PC->f.i.immediate; PC++; delay_slot=1; #ifdef DBG if (g_DebuggerActive) update_debugger(PC->addr); #endif PC->ops(); update_count(); delay_slot=0; if (!skip_jump && local_rs < 0) jump_to(PC->addr + ((jump_target-1)<<2)); last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void BGEZAL() { local_rs = irs; reg[31]=PC->addr+8; if((&irs)!=(long long int *)(reg+31)) { PC++; delay_slot=1; PC->ops(); update_count(); delay_slot=0; if(local_rs >= 0 && !skip_jump) PC += (PC-2)->f.i.immediate-1; } else printf("erreur dans bgezal\n"); last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void BGEZL_OUT() { if (irs >= 0) { jump_target = (long)PC->f.i.immediate; PC++; delay_slot=1; PC->ops(); update_count(); delay_slot=0; if (!skip_jump) jump_to(PC->addr + ((jump_target-1)<<2)); } else PC+=2; last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void BGEZAL_OUT() { local_rs = irs; reg[31]=PC->addr+8; if((&irs)!=(long long int *)(reg+31)) { jump_target = (long)PC->f.i.immediate; PC++; delay_slot=1; PC->ops(); update_count(); delay_slot=0; if(!skip_jump && local_rs >= 0) jump_to(PC->addr + ((jump_target-1)<<2)); } else printf("erreur dans bgezal\n"); last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void BGEZL(void) { if (irs >= 0) { PC++; delay_slot=1; #ifdef DBG if (debugger_mode) update_debugger(PC->addr); #endif PC->ops(); update_count(); delay_slot=0; if(!skip_jump) PC += (PC-2)->f.i.immediate-1; } else PC+=2; last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void BGEZL_OUT(void) { if (irs >= 0) { jump_target = (int)PC->f.i.immediate; PC++; delay_slot=1; #ifdef DBG if (debugger_mode) update_debugger(PC->addr); #endif PC->ops(); update_count(); delay_slot=0; if (!skip_jump) jump_to(PC->addr + ((jump_target-1)<<2)); } else PC+=2; last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void BC1TL(void) { if (check_cop1_unusable()) return; if ((FCR31 & 0x800000)!=0) { PC++; delay_slot=1; #ifdef DBG if (debugger_mode) update_debugger(PC->addr); #endif PC->ops(); update_count(); delay_slot=0; if(!skip_jump) PC += (PC-2)->f.i.immediate-1; } else { PC+=2; update_count(); } last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void BC1FL_OUT(void) { if (check_cop1_unusable()) return; if ((FCR31 & 0x800000)==0) { jump_target = (int)PC->f.i.immediate; PC++; delay_slot=1; #ifdef DBG if (debugger_mode) update_debugger(PC->addr); #endif PC->ops(); update_count(); delay_slot=0; if (!skip_jump) jump_to(PC->addr + ((jump_target-1)<<2)); } else { PC+=2; update_count(); } last_addr = PC->addr; if (next_interupt <= Count) gen_interupt(); }
void MTC0() { switch(PC->f.r.nrd) { case 0: // Index Index = rrt & 0x8000003F; if ((Index & 0x3F) > 31) { printf ("il y a plus de 32 TLB\n"); stop=1; } break; case 1: // Random break; case 2: // EntryLo0 EntryLo0 = rrt & 0x3FFFFFFF; break; case 3: // EntryLo1 EntryLo1 = rrt & 0x3FFFFFFF; break; case 4: // Context Context = (rrt & 0xFF800000) | (Context & 0x007FFFF0); break; case 5: // PageMask PageMask = rrt & 0x01FFE000; break; case 6: // Wired Wired = rrt; Random = 31; break; case 8: // BadVAddr break; case 9: // Count update_count(); if (next_interupt <= Count) gen_interupt(); translate_event_queue(rrt & 0xFFFFFFFF); Count = rrt & 0xFFFFFFFF; break; case 10: // EntryHi EntryHi = rrt & 0xFFFFE0FF; break; case 11: // Compare update_count(); remove_event(COMPARE_INT); add_interupt_event_count(COMPARE_INT, (unsigned long)rrt); Compare = rrt; Cause = Cause & 0xFFFF7FFF; //Timer interupt is clear break; case 12: // Status if((rrt & 0x04000000) != (Status & 0x04000000)) { shuffle_fpr_data(Status, rrt); set_fpr_pointers(rrt); } Status = rrt; update_count(); PC++; check_interupt(); if (next_interupt <= Count) gen_interupt(); PC--; break; case 13: // Cause if (rrt!=0) { printf("écriture dans Cause\n"); stop = 1; } else Cause = rrt; break; case 14: // EPC EPC = rrt; break; case 15: // PRevID break; case 16: // Config Config = rrt; break; case 18: // WatchLo WatchLo = rrt & 0xFFFFFFFF; break; case 19: // WatchHi WatchHi = rrt & 0xFFFFFFFF; break; case 27: // CacheErr break; case 28: // TagLo TagLo = rrt & 0x0FFFFFC0; break; case 29: // TagHi TagHi =0; break; default: printf("unknown mtc0 write : %d\n", PC->f.r.nrd); stop=1; } PC++; }
void MTC0() { switch(PC->f.r.nrd) { case 0: // Index Index = rrt & 0x8000003F; if ((Index & 0x3F) > 31) { printf ("il y a plus de 32 TLB\n"); stop=1; } break; case 1: // Random break; case 2: // EntryLo0 EntryLo0 = rrt & 0x3FFFFFFF; break; case 3: // EntryLo1 EntryLo1 = rrt & 0x3FFFFFFF; break; case 4: // Context Context = (rrt & 0xFF800000) | (Context & 0x007FFFF0); break; case 5: // PageMask PageMask = rrt & 0x01FFE000; break; case 6: // Wired Wired = rrt; Random = 31; break; case 8: // BadVAddr break; case 9: // Count update_count(); if (next_interupt <= Count) gen_interupt(); debug_count += Count; translate_event_queue(rrt & 0xFFFFFFFF); Count = rrt & 0xFFFFFFFF; debug_count -= Count; break; case 10: // EntryHi EntryHi = rrt & 0xFFFFE0FF; break; case 11: // Compare update_count(); remove_event(COMPARE_INT); add_interupt_event_count(COMPARE_INT, (unsigned long)rrt); Compare = rrt; Cause = Cause & 0xFFFF7FFF; //Timer interupt is clear break; case 12: // Status if((rrt & 0x04000000) != (Status & 0x04000000)) { if (rrt & 0x04000000) { int i; for (i=0; i<32; i++) { reg_cop1_double[i]=(double*)®_cop1_fgr_64[i]; reg_cop1_simple[i]=(float*)®_cop1_fgr_64[i]; } } else { int i; for (i=0; i<32; i++) { if(!(i&1)) reg_cop1_double[i]=(double*)®_cop1_fgr_64[i>>1]; #ifndef _BIG_ENDIAN reg_cop1_simple[i]=(float*)®_cop1_fgr_64[i>>1]+(i&1); #else reg_cop1_simple[i]=(float*)®_cop1_fgr_64[i>>1]+(1-(i&1)); #endif } } } Status = rrt; PC++; check_interupt(); update_count(); if (next_interupt <= Count) gen_interupt(); PC--; break; case 13: // Cause if (rrt!=0) { printf("écriture dans Cause\n"); stop = 1; } else Cause = rrt; break; case 14: // EPC EPC = rrt; break; case 15: // PRevID break; case 16: // Config Config = rrt; break; case 18: // WatchLo WatchLo = rrt & 0xFFFFFFFF; break; case 19: // WatchHi WatchHi = rrt & 0xFFFFFFFF; break; case 27: // CacheErr break; case 28: // TagLo TagLo = rrt & 0x0FFFFFC0; break; case 29: // TagHi TagHi =0; break; default: printf("unknown mtc0 write : %d\n", PC->f.r.nrd); stop=1; } PC++; }
void MTC0(void) { switch(PC->f.r.nrd) { case 0: // Index Index = rrt & 0x8000003F; if ((Index & 0x3F) > 31) { DebugMessage(M64MSG_ERROR, "MTC0 instruction writing Index register with TLB index > 31"); stop=1; } break; case 1: // Random break; case 2: // EntryLo0 EntryLo0 = rrt & 0x3FFFFFFF; break; case 3: // EntryLo1 EntryLo1 = rrt & 0x3FFFFFFF; break; case 4: // Context Context = (rrt & 0xFF800000) | (Context & 0x007FFFF0); break; case 5: // PageMask PageMask = rrt & 0x01FFE000; break; case 6: // Wired Wired = rrt; Random = 31; break; case 8: // BadVAddr break; case 9: // Count update_count(); if (next_interupt <= Count) gen_interupt(); debug_count += Count; translate_event_queue(rrt & 0xFFFFFFFF); Count = rrt & 0xFFFFFFFF; debug_count -= Count; break; case 10: // EntryHi EntryHi = rrt & 0xFFFFE0FF; break; case 11: // Compare update_count(); remove_event(COMPARE_INT); add_interupt_event_count(COMPARE_INT, (unsigned int)rrt); Compare = rrt; Cause = Cause & 0xFFFF7FFF; //Timer interupt is clear break; case 12: // Status if((rrt & 0x04000000) != (Status & 0x04000000)) { shuffle_fpr_data(Status, rrt); set_fpr_pointers(rrt); } Status = rrt; PC++; check_interupt(); update_count(); if (next_interupt <= Count) gen_interupt(); PC--; break; case 13: // Cause if (rrt!=0) { DebugMessage(M64MSG_ERROR, "MTC0 instruction trying to write Cause register with non-0 value"); stop = 1; } else Cause = rrt; break; case 14: // EPC EPC = rrt; break; case 15: // PRevID break; case 16: // Config Config = rrt; break; case 18: // WatchLo WatchLo = rrt & 0xFFFFFFFF; break; case 19: // WatchHi WatchHi = rrt & 0xFFFFFFFF; break; case 27: // CacheErr break; case 28: // TagLo TagLo = rrt & 0x0FFFFFC0; break; case 29: // TagHi TagHi =0; break; default: DebugMessage(M64MSG_ERROR, "Unknown MTC0 write: %d", PC->f.r.nrd); stop=1; } PC++; }
void gen_interupt(void) { if (stop == 1) { vi_counter = 0; // debug dyna_stop(); } if (!interupt_unsafe_state) { if (reset_hard_job) { reset_hard(); reset_hard_job = 0; return; } } if (skip_jump) { unsigned int dest = skip_jump; skip_jump = 0; if (q->count > Count || (Count - q->count) < 0x80000000) next_interupt = q->count; else next_interupt = 0; last_addr = dest; generic_jump_to(dest); return; } switch(q->type) { case SPECIAL_INT: if (Count > 0x10000000) return; remove_interupt_event(); add_interupt_event_count(SPECIAL_INT, 0); return; break; case VI_INT: if (retro_return(false) != savestates_job_nothing) { gen_interupt(); return; } gfx.updateScreen(); refresh_stat(); if (vi_register.vi_v_sync == 0) vi_register.vi_delay = 500000; else vi_register.vi_delay = ((vi_register.vi_v_sync + 1)*1500); next_vi += vi_register.vi_delay; if (vi_register.vi_status&0x40) vi_field=1-vi_field; else vi_field=0; remove_interupt_event(); add_interupt_event_count(VI_INT, next_vi); MI_register.mi_intr_reg |= 0x08; if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg) Cause = (Cause | 0x400) & 0xFFFFFF83; else return; if ((Status & 7) != 1) return; if (!(Status & Cause & 0xFF00)) return; break; case COMPARE_INT: remove_interupt_event(); Count+=2; add_interupt_event_count(COMPARE_INT, Compare); Count-=2; Cause = (Cause | 0x8000) & 0xFFFFFF83; if ((Status & 7) != 1) return; if (!(Status & Cause & 0xFF00)) return; break; case CHECK_INT: remove_interupt_event(); break; case SI_INT: PIF_RAMb[0x3F] = 0x0; remove_interupt_event(); MI_register.mi_intr_reg |= 0x02; si_register.si_stat |= 0x1000; //si_register.si_stat &= ~0x1; if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg) Cause = (Cause | 0x400) & 0xFFFFFF83; else return; if ((Status & 7) != 1) return; if (!(Status & Cause & 0xFF00)) return; break; case PI_INT: remove_interupt_event(); MI_register.mi_intr_reg |= 0x10; pi_register.read_pi_status_reg &= ~3; if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg) Cause = (Cause | 0x400) & 0xFFFFFF83; else return; if ((Status & 7) != 1) return; if (!(Status & Cause & 0xFF00)) return; break; case AI_INT: if (ai_register.ai_status & 0x80000000) // full { unsigned int ai_event = get_event(AI_INT); remove_interupt_event(); ai_register.ai_status &= ~0x80000000; ai_register.current_delay = ai_register.next_delay; ai_register.current_len = ai_register.next_len; add_interupt_event_count(AI_INT, ai_event+ai_register.next_delay); MI_register.mi_intr_reg |= 0x04; if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg) Cause = (Cause | 0x400) & 0xFFFFFF83; else return; if ((Status & 7) != 1) return; if (!(Status & Cause & 0xFF00)) return; } else { remove_interupt_event(); ai_register.ai_status &= ~0x40000000; //------- MI_register.mi_intr_reg |= 0x04; if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg) Cause = (Cause | 0x400) & 0xFFFFFF83; else return; if ((Status & 7) != 1) return; if (!(Status & Cause & 0xFF00)) return; } break; case SP_INT: remove_interupt_event(); sp_register.sp_status_reg |= 0x203; // sp_register.sp_status_reg |= 0x303; if (!(sp_register.sp_status_reg & 0x40)) return; // !intr_on_break MI_register.mi_intr_reg |= 0x01; if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg) Cause = (Cause | 0x400) & 0xFFFFFF83; else return; if ((Status & 7) != 1) return; if (!(Status & Cause & 0xFF00)) return; break; case DP_INT: remove_interupt_event(); dpc_register.dpc_status &= ~2; dpc_register.dpc_status |= 0x81; MI_register.mi_intr_reg |= 0x20; if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg) Cause = (Cause | 0x400) & 0xFFFFFF83; else return; if ((Status & 7) != 1) return; if (!(Status & Cause & 0xFF00)) return; break; case HW2_INT: // Hardware Interrupt 2 -- remove interrupt event from queue remove_interupt_event(); // setup r4300 Status flags: reset TS, and SR, set IM2 Status = (Status & ~0x00380000) | 0x1000; Cause = (Cause | 0x1000) & 0xFFFFFF83; /* the exception_general() call below will jump to the interrupt vector (0x80000180) and setup the * interpreter or dynarec */ break; case NMI_INT: // Non Maskable Interrupt -- remove interrupt event from queue remove_interupt_event(); // setup r4300 Status flags: reset TS and SR, set BEV, ERL, and SR Status = (Status & ~0x00380000) | 0x00500004; Cause = 0x00000000; // simulate the soft reset code which would run from the PIF ROM r4300_reset_soft(); // clear all interrupts, reset interrupt counters back to 0 Count = 0; vi_counter = 0; init_interupt(); // clear the audio status register so that subsequent write_ai() calls will work properly ai_register.ai_status = 0; // set ErrorEPC with the last instruction address ErrorEPC = PC->addr; // reset the r4300 internal state if (r4300emu != CORE_PURE_INTERPRETER) { // clear all the compiled instruction blocks and re-initialize free_blocks(); init_blocks(); } // adjust ErrorEPC if we were in a delay slot, and clear the delay_slot and dyna_interp flags if(delay_slot==1 || delay_slot==3) { ErrorEPC-=4; } delay_slot = 0; dyna_interp = 0; // set next instruction address to reset vector last_addr = 0xa4000040; generic_jump_to(0xa4000040); return; default: DebugMessage(M64MSG_ERROR, "Unknown interrupt queue event type %.8X.", q->type); remove_interupt_event(); break; } #ifdef NEW_DYNAREC if (r4300emu == CORE_DYNAREC) { EPC = pcaddr; pcaddr = 0x80000180; Status |= 2; Cause &= 0x7FFFFFFF; pending_exception=1; } else { exception_general(); } #else exception_general(); #endif }