Bits CPU_Core_Full_Run(void) { FullData inst; while (CPU_Cycles-->0) { #if C_DEBUG cycle_count++; #if C_HEAVY_DEBUG if (DEBUG_HeavyIsBreakpoint()) { FillFlags(); return debugCallback; }; #endif #endif LoadIP(); inst.entry=cpu.code.big*0x200; inst.prefix=cpu.code.big; restartopcode: inst.entry=(inst.entry & 0xffffff00) | Fetchb(); inst.code=OpCodeTable[inst.entry]; #include "core_full/load.h" #include "core_full/op.h" #include "core_full/save.h" nextopcode:; SaveIP(); continue; illegalopcode: LOG(LOG_CPU,LOG_NORMAL)("Illegal opcode"); CPU_Exception(0x6,0); } FillFlags(); return CBRET_NONE; }
Bits CPU_Core_Simple_Run(void) { while (CPU_Cycles-->0) { LOADIP; core.opcode_index=cpu.code.big*0x200; core.prefixes=cpu.code.big; core.ea_table=&EATable[cpu.code.big*256]; BaseDS=SegBase(ds); BaseSS=SegBase(ss); core.base_val_ds=ds; #if C_DEBUG #if C_HEAVY_DEBUG if (DEBUG_HeavyIsBreakpoint()) { FillFlags(); return debugCallback; }; #endif #endif cycle_count++; restart_opcode: switch (core.opcode_index+Fetchb()) { #include "core_normal/prefix_none.h" #include "core_normal/prefix_0f.h" #include "core_normal/prefix_66.h" #include "core_normal/prefix_66_0f.h" default: illegal_opcode: #if C_DEBUG { Bitu len=(GETIP-reg_eip); LOADIP; if (len>16) len=16; char tempcode[16*2+1];char * writecode=tempcode; for (;len>0;len--) { // sprintf(writecode,"%X",mem_readb(core.cseip++)); writecode+=2; } LOG(LOG_CPU,LOG_NORMAL)("Illegal/Unhandled opcode %s",tempcode); } #endif CPU_Exception(6,0); continue; } SAVEIP; } FillFlags(); return CBRET_NONE; decode_end: SAVEIP; FillFlags(); return CBRET_NONE; }
Bits CPU_Core_Prefetch_Run(void) { bool invalidate_pq=false; while (CPU_Cycles-->0) { if (invalidate_pq) { pq_valid=false; invalidate_pq=false; } LOADIP; core.opcode_index=cpu.code.big*0x200; core.prefixes=cpu.code.big; core.ea_table=&EATable[cpu.code.big*256]; BaseDS=SegBase(ds); BaseSS=SegBase(ss); core.base_val_ds=ds; #if C_DEBUG #if C_HEAVY_DEBUG if (DEBUG_HeavyIsBreakpoint()) { FillFlags(); return debugCallback; }; #endif cycle_count++; #endif restart_opcode: Bit8u next_opcode=Fetchb(); invalidate_pq=false; if (core.opcode_index&OPCODE_0F) invalidate_pq=true; else switch (next_opcode) { case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: // jcc case 0x9a: // call case 0xc2: case 0xc3: // retn case 0xc8: // enter case 0xc9: // leave case 0xca: case 0xcb: // retf case 0xcc: // int3 case 0xcd: // int case 0xce: // into case 0xcf: // iret case 0xe0: // loopnz case 0xe1: // loopz case 0xe2: // loop case 0xe3: // jcxz case 0xe8: // call case 0xe9: case 0xea: case 0xeb: // jmp case 0xff: invalidate_pq=true; break; default: break; } switch (core.opcode_index+next_opcode) { #include "core_normal/prefix_none.h" #include "core_normal/prefix_0f.h" #include "core_normal/prefix_66.h" #include "core_normal/prefix_66_0f.h" default: illegal_opcode: #if C_DEBUG { bool ignore=false; Bitu len=(GETIP-reg_eip); LOADIP; if (len>16) len=16; char tempcode[16*2+1];char * writecode=tempcode; if (ignore_opcode_63 && mem_readb(core.cseip) == 0x63) ignore = true; for (;len>0;len--) { sprintf(writecode,"%02X",mem_readb(core.cseip++)); writecode+=2; } if (!ignore) LOG(LOG_CPU,LOG_NORMAL)("Illegal/Unhandled opcode %s",tempcode); } #endif CPU_Exception(6,0); invalidate_pq=true; continue; } SAVEIP; } FillFlags(); return CBRET_NONE; decode_end: SAVEIP; FillFlags(); return CBRET_NONE; }
Bits CPU_Core_Dynrec_Run(void) { for (;;) { // Determine the linear address of CS:EIP PhysPt ip_point=SegPhys(cs)+reg_eip; #if C_HEAVY_DEBUG if (DEBUG_HeavyIsBreakpoint()) return debugCallback; #endif CodePageHandlerDynRec * chandler=0; // see if the current page is present and contains code if (GCC_UNLIKELY(MakeCodePage(ip_point,chandler))) { // page not present, throw the exception CPU_Exception(cpu.exception.which,cpu.exception.error); continue; } // page doesn't contain code or is special if (GCC_UNLIKELY(!chandler)) return CPU_Core_Normal_Run(); // find correct Dynamic Block to run CacheBlockDynRec * block=chandler->FindCacheBlock(ip_point&4095); if (!block) { // no block found, thus translate the instruction stream // unless the instruction is known to be modified if (!chandler->invalidation_map || (chandler->invalidation_map[ip_point&4095]<4)) { // translate up to 32 instructions block=CreateCacheBlock(chandler,ip_point,32); } else { // let the normal core handle this instruction to avoid zero-sized blocks Bitu old_cycles=CPU_Cycles; CPU_Cycles=1; Bits nc_retcode=CPU_Core_Normal_Run(); if (!nc_retcode) { CPU_Cycles=old_cycles-1; continue; } CPU_CycleLeft+=old_cycles; return nc_retcode; } } run_block: cache.block.running=0; // now we're ready to run the dynamic code block // BlockReturn ret=((BlockReturn (*)(void))(block->cache.start))(); BlockReturn ret=core_dynrec.runcode(block->cache.start); switch (ret) { case BR_Iret: #if C_HEAVY_DEBUG if (DEBUG_HeavyIsBreakpoint()) return debugCallback; #endif if (!GETFLAG(TF)) { if (GETFLAG(IF) && PIC_IRQCheck) return CBRET_NONE; break; } // trapflag is set, switch to the trap-aware decoder cpudecoder=CPU_Core_Dynrec_Trap_Run; return CBRET_NONE; case BR_Normal: // the block was exited due to a non-predictable control flow // modifying instruction (like ret) or some nontrivial cpu state // changing instruction (for example switch to/from pmode), // or the maximal number of instructions to translate was reached #if C_HEAVY_DEBUG if (DEBUG_HeavyIsBreakpoint()) return debugCallback; #endif break; case BR_Cycles: // cycles went negative, return from the core to handle // external events, schedule the pic... #if C_HEAVY_DEBUG if (DEBUG_HeavyIsBreakpoint()) return debugCallback; #endif return CBRET_NONE; case BR_CallBack: // the callback code is executed in dosbox.conf, return the callback number FillFlags(); return core_dynrec.callback; case BR_SMCBlock: // LOG_MSG("selfmodification of running block at %x:%x",SegValue(cs),reg_eip); cpu.exception.which=0; // fallthrough, let the normal core handle the block-modifying instruction case BR_Opcode: // some instruction has been encountered that could not be translated // (thus it is not part of the code block), the normal core will // handle this instruction CPU_CycleLeft+=CPU_Cycles; CPU_Cycles=1; return CPU_Core_Normal_Run(); #if (C_DEBUG) case BR_OpcodeFull: CPU_CycleLeft+=CPU_Cycles; CPU_Cycles=1; return CPU_Core_Full_Run(); #endif case BR_Link1: case BR_Link2: block=LinkBlocks(ret); if (block) goto run_block; break; default: E_Exit("Invalid return code %d", ret); } } return CBRET_NONE; }
Bits CPU_Core286_Normal_Run(void) { if (CPU_Cycles <= 0) return CBRET_NONE; while (CPU_Cycles-->0) { LOADIP; core.prefixes=0; core.opcode_index=0; core.ea_table=&EATable[0]; BaseDS=SegBase(ds); BaseSS=SegBase(ss); core.base_val_ds=ds; #if C_DEBUG #if C_HEAVY_DEBUG if (DEBUG_HeavyIsBreakpoint()) { FillFlags(); return (Bits)debugCallback; }; #endif #endif cycle_count++; restart_opcode: switch (core.opcode_index+Fetchb()) { #include "core_normal/prefix_none.h" #include "core_normal/prefix_0f.h" default: illegal_opcode: #if C_DEBUG { bool ignore=false; Bitu len=(GETIP-reg_eip); LOADIP; if (len>16) len=16; char tempcode[16*2+1];char * writecode=tempcode; if (ignore_opcode_63 && mem_readb(core.cseip) == 0x63) ignore = true; for (;len>0;len--) { sprintf(writecode,"%02X",mem_readb(core.cseip++)); writecode+=2; } if (!ignore) LOG(LOG_CPU,LOG_NORMAL)("Illegal/Unhandled opcode %s",tempcode); } #endif CPU_Exception(6,0); continue; gp_fault: CPU_Exception(EXCEPTION_GP,0); continue; } SAVEIP; } FillFlags(); return CBRET_NONE; /* 8086/286 multiple prefix interrupt bug emulation. * If an instruction is interrupted, only the last prefix is restarted. * See also [https://www.pcjs.org/pubs/pc/reference/intel/8086/] and [https://www.youtube.com/watch?v=6FC-tcwMBnU] */ prefix_out: SAVEIP_PREFIX; FillFlags(); return CBRET_NONE; decode_end: SAVEIP; FillFlags(); return CBRET_NONE; }
Bits CPU_Core_Normal_Run(void) { while (CPU_Cycles-->0) { LOADIP; dosbox_check_nonrecursive_pf_cs = SegValue(cs); dosbox_check_nonrecursive_pf_eip = reg_eip; core.opcode_index=cpu.code.big*0x200; core.prefixes=cpu.code.big; core.ea_table=&EATable[cpu.code.big*256]; BaseDS=SegBase(ds); BaseSS=SegBase(ss); core.base_val_ds=ds; #if C_DEBUG #if C_HEAVY_DEBUG if (DEBUG_HeavyIsBreakpoint()) { FillFlags(); return debugCallback; }; #endif #endif cycle_count++; restart_opcode: switch (core.opcode_index+Fetchb()) { #include "core_normal/prefix_none.h" #include "core_normal/prefix_0f.h" #include "core_normal/prefix_66.h" #include "core_normal/prefix_66_0f.h" default: illegal_opcode: #if C_DEBUG { bool ignore=false; Bitu len=(GETIP-reg_eip); LOADIP; if (len>16) len=16; char tempcode[16*2+1];char * writecode=tempcode; if (ignore_opcode_63 && mem_readb(core.cseip) == 0x63) ignore = true; for (;len>0;len--) { sprintf(writecode,"%02X",mem_readb(core.cseip++)); writecode+=2; } if (!ignore) LOG(LOG_CPU,LOG_NORMAL)("Illegal/Unhandled opcode %s",tempcode); } #endif CPU_Exception(6,0); continue; gp_fault: LOG_MSG("Segment limit violation"); CPU_Exception(EXCEPTION_GP,0); continue; } SAVEIP; } FillFlags(); return CBRET_NONE; decode_end: SAVEIP; FillFlags(); return CBRET_NONE; }