diff --git a/src/cpu/386_ops.h b/src/cpu/386_ops.h index 790216cb9..73b7cdc7d 100644 --- a/src/cpu/386_ops.h +++ b/src/cpu/386_ops.h @@ -364,6 +364,96 @@ static int op0F_l_a32(uint32_t fetchdat) return x86_opcodes_0f[opcode | 0x300](fetchdat >> 8); } +const OpFn OP_TABLE(186_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; const OpFn OP_TABLE(286_0f)[1024] = { @@ -1916,6 +2006,97 @@ const OpFn OP_TABLE(pentium2d_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, }; +const OpFn OP_TABLE(186)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_186, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_186, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_186, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_186, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_186, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_186, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_186, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_186, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, +}; + const OpFn OP_TABLE(286)[1024] = { /*16-bit data, 16-bit addr*/ diff --git a/src/cpu/8080.c b/src/cpu/8080.c new file mode 100644 index 000000000..6d9849e24 --- /dev/null +++ b/src/cpu/8080.c @@ -0,0 +1,218 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * 8080 CPU emulation. + * + * Authors: Cacodemon345 + * + * Copyright 2022 Cacodemon345 + */ + + +#include +#include +#include "cpu.h" +#include <86box/timer.h> +#include <86box/i8080.h> +#include <86box/mem.h> + +static int prefetching = 1, completed = 1; +static int in_rep = 0, repeating = 0, rep_c_flag = 0; +static int oldc, clear_lock = 0; +static int refresh = 0, cycdiff; + +static uint32_t cpu_src = 0, cpu_dest = 0; +static uint32_t cpu_data = 0; + +static void +clock_start(void) +{ + cycdiff = cycles; +} + + +static void +clock_end(void) +{ + int diff = cycdiff - cycles; + + /* On 808x systems, clock speed is usually crystal frequency divided by an integer. */ + tsc += (uint64_t)diff * ((uint64_t)xt_cpu_multi >> 32ULL); /* Shift xt_cpu_multi by 32 bits to the right and then multiply. */ + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) + timer_process(); +} + +static void +8080_wait(int c, int bus) +{ + cycles -= c; + if (bus < 2) { + clock_end(); + clock_start(); + } +} + +static uint8_t +readmemb(uint32_t a) +{ + uint8_t ret; + + 8080_wait(4, 1); + ret = read_mem_b(a); + + return ret; +} + +static uint8_t +ins_fetch(i8080* cpu) +{ + uint8_t ret = cpu->readmembyte(cpu->pmembase + cpu->pc); + + cpu->pc++; + return ret; +} + +void +transfer_from_808x(i8080* cpu) +{ + cpu->hl = BX; + cpu->bc = CX; + cpu->de = DX; + cpu->a = AL; + cpu->flags = cpu_state.flags & 0xFF; + cpu->sp = BP; + cpu->pc = cpu_state.pc; + cpu->oldpc = cpu_state.oldpc; + cpu->pmembase = cs; + cpu->dmembase = ds; +} + +void +transfer_to_808x(i8080* cpu) +{ + BX = cpu->hl; + CX = cpu->bc; + DX = cpu->de; + AL = cpu->a; + cpu_state.flags &= 0xFF00; + cpu_state.flags |= cpu->flags & 0xFF; + BP = cpu->sp; + cpu_state.pc = cpu->pc; +} + +uint8_t +getreg_i8080(i8080 *cpu, uint8_t reg) +{ + uint8_t ret = 0xFF; + switch(reg) + { + case 0x0: ret = cpu->b; break; + case 0x1: ret = cpu->c; break; + case 0x2: ret = cpu->d; break; + case 0x3: ret = cpu->e; break; + case 0x4: ret = cpu->h; break; + case 0x5: ret = cpu->l; break; + case 0x6: ret = cpu->readmembyte(cpu->dmembase + cpu->sp); break; + case 0x7: ret = cpu->a; break; + } + return ret; +} + +uint8_t +getreg_i8080_emu(i8080 *cpu, uint8_t reg) +{ + uint8_t ret = 0xFF; + switch(reg) + { + case 0x0: ret = CH; break; + case 0x1: ret = CL; break; + case 0x2: ret = DH; break; + case 0x3: ret = DL; break; + case 0x4: ret = BH; break; + case 0x5: ret = BL; break; + case 0x6: ret = cpu->readmembyte(cpu->dmembase + BP); break; + case 0x7: ret = AL; break; + } + return ret; +} + +void +setreg_i8080_emu(i8080 *cpu, uint8_t reg, uint8_t val) +{ + switch(reg) + { + case 0x0: CH = val; break; + case 0x1: CL = val; break; + case 0x2: DH = val; break; + case 0x3: DL = val; break; + case 0x4: BH = val; break; + case 0x5: BL = val; break; + case 0x6: cpu->writemembyte(cpu->dmembase + BP, val); break; + case 0x7: AL = val; break; + } +} + +void +setreg_i8080(i8080 *cpu, uint8_t reg, uint8_t val) +{ + switch(reg) + { + case 0x0: cpu->b = val; break; + case 0x1: cpu->c = val; break; + case 0x2: cpu->d = val; break; + case 0x3: cpu->e = val; break; + case 0x4: cpu->h = val; break; + case 0x5: cpu->l = val; break; + case 0x6: cpu->writemembyte(cpu->dmembase + cpu->sp, val); break; + case 0x7: cpu->a = val; break; + } +} + +void +interpret_exec8080(i8080* cpu, uint8_t opcode) +{ + switch (opcode) { + case 0x00: + { + break; + } + } +} + +/* Actually implement i8080 emulation. */ +void +exec8080(i8080* cpu, int cycs) +{ + uint8_t temp = 0, temp2; + uint8_t old_af; + uint8_t handled = 0; + uint16_t addr, tempw; + uint16_t new_ip; + int bits; + + cycles += cycs; + + while (cycles > 0) { + cpu->startclock(); + + if (!repeating) { + cpu->oldpc = cpu->pc; + opcode = cpu->fetchinstruction(cpu); + oldc = cpu->flags & C_FLAG_I8080; + 8080_wait(1, 0); + } + completed = 1; + if (completed) { + repeating = 0; + in_rep = 0; + rep_c_flag = 0; + cpu->endclock(); + if (cpu->checkinterrupts) cpu->checkinterrupts(); + } + } +} \ No newline at end of file diff --git a/src/cpu/808x.c b/src/cpu/808x.c index 01bfba24b..60188faff 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -66,8 +66,8 @@ static uint16_t last_addr = 0x0000; static uint32_t *ovr_seg = NULL; static int prefetching = 1, completed = 1; -static int in_rep = 0, repeating = 0; -static int oldc, clear_lock = 0; +static int in_rep = 0, repeating = 0, rep_c_flag = 0; +static int oldc, clear_lock = 0; static int refresh = 0, cycdiff; /* Various things needed for 8087. */ @@ -313,7 +313,7 @@ readmemw(uint32_t s, uint16_t a) else { wait(4, 1); ret = read_mem_b(s + a); - ret |= read_mem_b(s + ((a + 1) & 0xffff)) << 8; + ret |= read_mem_b(s + (is186 ? (a + 1) : (a + 1) & 0xffff)) << 8; } return ret; @@ -385,7 +385,7 @@ writememw(uint32_t s, uint32_t a, uint16_t v) else { write_mem_b(addr, v & 0xff); wait(4, 1); - addr = s + ((a + 1) & 0xffff); + addr = s + (is186 ? (a + 1) : ((a + 1) & 0xffff)); write_mem_b(addr, v >> 8); } @@ -568,7 +568,8 @@ reset_808x(int hard) load_cs(0xFFFF); cpu_state.pc = 0; - rammask = 0xfffff; + cpu_state.flags |= MD_FLAG; + rammask = 0xfffff; prefetching = 1; cpu_alu_op = 0; @@ -793,6 +794,11 @@ seteaq(uint64_t val) static void push(uint16_t *val) { + if (is186 && SP == 1) { + writememw(ss - 1, 0, *val); + SP = cpu_state.eaaddr = 0xFFFF; + return; + } SP -= 2; cpu_state.eaaddr = (SP & 0xffff); writememw(ss, cpu_state.eaaddr, *val); @@ -957,7 +963,7 @@ interrupt(uint16_t addr) pfq_clear(); ovr_seg = NULL; access(39, 16); - tempf = cpu_state.flags & 0x0fd7; + tempf = cpu_state.flags & (is_nec && cpu_state.inside_emulation_mode ? 0x8fd7 : 0x0fd7); push(&tempf); cpu_state.flags &= ~(I_FLAG | T_FLAG); access(40, 16); @@ -970,6 +976,12 @@ interrupt(uint16_t addr) push(&old_ip); } +void +interrupt_808x(uint16_t addr) +{ + interrupt(addr); +} + static void custom_nmi(void) { @@ -1393,9 +1405,8 @@ set_co_mul(int bits, int carry) { set_cf(carry); set_of(carry); - /* NOTE: When implementing the V20, care should be taken to not change - the zero flag. */ - set_zf_ex(!carry); + if (!is_nec) + set_zf_ex(!carry); if (!carry) wait(1, 0); } @@ -1606,12 +1617,37 @@ cpu_data_opff_rm(void) } } +uint16_t +cpu_inw(uint16_t port) +{ + if (is8086 && !(port & 1)) { + wait(4, 0); + } else { + wait(8, 0); + } + + return inw(port); +} + +void +cpu_outw(uint16_t port, uint16_t val) +{ + if (is8086 && !(port & 1)) { + wait(4, 0); + } else { + wait(8, 0); + } + + return outw(port, val); +} + /* Executes instructions up to the specified number of cycles. */ void execx86(int cycs) { uint8_t temp = 0, temp2; uint8_t old_af; + uint8_t handled = 0; uint16_t addr, tempw; uint16_t new_cs, new_ip; int bits; @@ -1634,1258 +1670,1830 @@ execx86(int cycs) completed = 1; // pclog("[%04X:%04X] Opcode: %02X\n", CS, cpu_state.pc, opcode); - switch (opcode) { - case 0x06: - case 0x0E: - case 0x16: - case 0x1E: /* PUSH seg */ - access(29, 16); - push(&(_opseg[(opcode >> 3) & 0x03]->seg)); - break; - case 0x07: - case 0x0F: - case 0x17: - case 0x1F: /* POP seg */ - access(22, 16); - if (opcode == 0x0F) { - load_cs(pop()); - pfq_pos = 0; - } else - load_seg(pop(), _opseg[(opcode >> 3) & 0x03]); - wait(1, 0); - /* All POP segment instructions suppress interrupts for one instruction. */ - noint = 1; - break; + if (is186) { + switch (opcode) { + case 0x6c: + case 0x6d: /* INM dst, DW/INS dst, DX */ + { + bits = 8 << (opcode & 1); + handled = 1; + if (!repeating) + wait(2, 0); - case 0x26: /*ES:*/ - case 0x2E: /*CS:*/ - case 0x36: /*SS:*/ - case 0x3E: /*DS:*/ - wait(1, 0); - ovr_seg = opseg[(opcode >> 3) & 0x03]; - completed = 0; - break; + if (rep_action(bits)) { + break; + } else if (!repeating) { + wait(7, 0); + } + if (bits == 16) { + writememw(es, DI, cpu_inw(DX)); + DI += (cpu_state.flags & D_FLAG) ? -2 : 2; + } else { + wait(4, 0); + writememb(es, DI, inb(DX)); + DI += (cpu_state.flags & D_FLAG) ? -1 : 1; + } + if (in_rep == 0) { + break; + } + repeating = 1; + clock_end(); + break; + } + case 0x6e: + case 0x6f: /* OUTM DW, src/OUTS DX, src */ + { + uint32_t dest_seg = ovr_seg ? *ovr_seg : ds; + bits = 8 << (opcode & 1); + handled = 1; + if (!repeating) + wait(2, 0); - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x18: - case 0x19: - case 0x1a: - case 0x1b: - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x28: - case 0x29: - case 0x2a: - case 0x2b: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x38: - case 0x39: - case 0x3a: - case 0x3b: - /* alu rm, r / r, rm */ - bits = 8 << (opcode & 1); - do_mod_rm(); - access(46, bits); - tempw = get_ea(); - cpu_alu_op = (opcode >> 3) & 7; - if ((opcode & 2) == 0) { - cpu_dest = tempw; - cpu_src = get_reg(cpu_reg); - } else { - cpu_dest = get_reg(cpu_reg); - cpu_src = tempw; - } - if (cpu_mod != 3) - wait(2, 0); - wait(1, 0); - alu_op(bits); - if (cpu_alu_op != 7) { + if (rep_action(bits)) { + break; + } else if (!repeating) { + wait(7, 0); + } + if (bits == 16) { + cpu_outw(DX, readmemw(dest_seg, SI)); + SI += (cpu_state.flags & D_FLAG) ? -2 : 2; + } else { + wait(4, 0); + outb(DX, readmemb(dest_seg + SI)); + SI += (cpu_state.flags & D_FLAG) ? -1 : 1; + } + if (in_rep == 0) { + break; + } + repeating = 1; + clock_end(); + break; + } + case 0xC8: /* ENTER/PREPARE */ + { + uint16_t temp = 0; + uint16_t size = pfq_fetchw(); + uint8_t nests = pfq_fetchb(); + uint32_t i = 0; + + push(&BP); + temp = SP; + if (nests > 0) { + while (--nests) { + uint16_t tempbp = 0; + BP -= 2; + tempbp = readmemw(ss, BP); + push(&tempbp); + } + push(&temp); + } + BP = temp; + SP -= size; + handled = 1; + break; + } + case 0xC9: /* LEAVE/DISPOSE */ + { + SP = BP; + BP = pop(); + handled = 1; + break; + } + case 0x62: /* BOUND r/m */ + { + uint16_t oldpc = cpu_state.oldpc; + uint16_t lowbound = 0, highbound = 0; + uint16_t regval = 0; + do_mod_rm(); + + lowbound = readmemw(easeg, cpu_state.eaaddr); + highbound = readmemw(easeg, cpu_state.eaaddr + 2); + regval = get_reg(cpu_reg); + if (lowbound > regval || highbound < regval) { + cpu_state.pc = cpu_state.oldpc; + interrupt(5); + } + handled = 1; + break; + } + case 0xC0: + case 0xC1: /*rot imm8 */ + bits = 8 << (opcode & 1); + do_mod_rm(); + if (cpu_mod == 3) + wait(1, 0); + access(53, bits); + cpu_data = get_ea(); + cpu_src = pfq_fetchb(); + + wait((cpu_mod != 3) ? 9 : 6, 0); + + if (!is_nec) + cpu_src &= 0x1F; + while (cpu_src != 0) { + cpu_dest = cpu_data; + oldc = cpu_state.flags & C_FLAG; + switch (rmdat & 0x38) { + case 0x00: /* ROL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data <<= 1; + cpu_data |= ((cpu_state.flags & C_FLAG) ? 1 : 0); + set_of_rotate(bits); + set_af(0); + break; + case 0x08: /* ROR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (cpu_state.flags & C_FLAG) + cpu_data |= (!(opcode & 1) ? 0x80 : 0x8000); + set_of_rotate(bits); + set_af(0); + break; + case 0x10: /* RCL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data = (cpu_data << 1) | (oldc ? 1 : 0); + set_of_rotate(bits); + set_af(0); + break; + case 0x18: /* RCR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (oldc) + cpu_data |= (!(opcode & 0x01) ? 0x80 : 0x8000); + set_cf((cpu_dest & 1) != 0); + set_of_rotate(bits); + set_af(0); + break; + case 0x20: /* SHL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data <<= 1; + set_of_rotate(bits); + set_af((cpu_data & 0x10) != 0); + set_pzs(bits); + break; + case 0x28: /* SHR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + set_of_rotate(bits); + set_af(0); + set_pzs(bits); + break; + case 0x30: /* SETMO - undocumented? */ + bitwise(bits, 0xffff); + set_cf(0); + set_of_rotate(bits); + set_af(0); + set_pzs(bits); + break; + case 0x38: /* SAR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (!(opcode & 1)) + cpu_data |= (cpu_dest & 0x80); + else + cpu_data |= (cpu_dest & 0x8000); + set_of_rotate(bits); + set_af(0); + set_pzs(bits); + break; + } + if ((opcode & 2) != 0) + wait(4, 0); + --cpu_src; + } + access(17, bits); + set_ea(cpu_data); + handled = 1; + break; + } + } + if (!handled) { + switch (opcode) { + case 0x06: + case 0x0E: + case 0x16: + case 0x1E: /* PUSH seg */ + access(29, 16); + push(&(_opseg[(opcode >> 3) & 0x03]->seg)); + break; + case 0x07: + case 0x0F: + case 0x17: + case 0x1F: /* POP seg */ + if (is_nec && opcode == 0x0F) { + uint8_t orig_opcode = opcode; + opcode = pfq_fetchb(); + switch (opcode) { + case 0x28: /* ROL4 r/m */ + { + do_mod_rm(); + wait(21, 0); + { + uint8_t temp_val = geteab(); + uint8_t temp_al = AL; + + temp_al &= 0xF; + temp_al |= (temp_val & 0xF0); + temp_val = (temp_al & 0xF) | ((temp_val & 0xF) << 4); + temp_al >>= 4; + temp_al &= 0xF; + seteab(temp_val); + AL = temp_al; + } + handled = 1; + break; + } + case 0x2a: /* ROR4 r/m */ + { + do_mod_rm(); + wait(21, 0); + { + uint8_t temp_val = geteab(); + uint8_t temp_al = AL; + + AL = temp_val & 0xF; + temp_val = (temp_val >> 4) | ((temp_al & 0xF) << 4); + + seteab(temp_val); + } + handled = 1; + break; + } + case 0x10: /* TEST1 r8/m8, CL*/ + case 0x11: /* TEST1 r16/m16, CL*/ + case 0x18: /* TEST1 r8/m8, imm3 */ + case 0x19: /* TEST1 r16/m16, imm4 */ + { + bits = 8 << (opcode & 0x1); + do_mod_rm(); + wait(3, 0); + { + uint8_t bit = (opcode & 0x8) ? (pfq_fetchb()) : (CL); + bit &= ((1 << (3 + (opcode & 0x1))) - 1); + read_ea(0, bits); + + set_zf_ex(!(cpu_data & (1 << bit))); + cpu_state.flags &= ~(V_FLAG | C_FLAG); + } + handled = 1; + break; + } + case 0x16: /* NOT1 r8/m8, CL*/ + case 0x17: /* NOT1 r16/m16, CL*/ + case 0x1e: /* NOT1 r8/m8, imm3 */ + case 0x1f: /* NOT1 r16/m16, imm4 */ + { + bits = 8 << (opcode & 0x1); + do_mod_rm(); + wait(3, 0); + { + uint8_t bit = (opcode & 0x8) ? (pfq_fetchb()) : (CL); + bit &= ((1 << (3 + (opcode & 0x1))) - 1); + read_ea(0, bits); + + if (bits == 8) + seteab((cpu_data & 0xFF) ^ (1 << bit)); + else + seteaw((cpu_data & 0xFFFF) ^ (1 << bit)); + } + handled = 1; + break; + } + case 0x14: /* SET1 r8/m8, CL*/ + case 0x15: /* SET1 r16/m16, CL*/ + case 0x1c: /* SET1 r8/m8, imm3 */ + case 0x1d: /* SET1 r16/m16, imm4 */ + { + bits = 8 << (opcode & 0x1); + do_mod_rm(); + wait(3, 0); + { + uint8_t bit = (opcode & 0x8) ? (pfq_fetchb()) : (CL); + bit &= ((1 << (3 + (opcode & 0x1))) - 1); + read_ea(0, bits); + + if (bits == 8) + seteab((cpu_data & 0xFF) | (1 << bit)); + else + seteaw((cpu_data & 0xFFFF) | (1 << bit)); + } + handled = 1; + break; + } + case 0x12: /* CLR1 r8/m8, CL*/ + case 0x13: /* CLR1 r16/m16, CL*/ + case 0x1a: /* CLR1 r8/m8, imm3 */ + case 0x1b: /* CLR1 r16/m16, imm4 */ + { + bits = 8 << (opcode & 0x1); + do_mod_rm(); + wait(3, 0); + { + uint8_t bit = (opcode & 0x8) ? (pfq_fetchb()) : (CL); + bit &= ((1 << (3 + (opcode & 0x1))) - 1); + read_ea(0, bits); + + if (bits == 8) + seteab((cpu_data & 0xFF) & ~(1 << bit)); + else + seteaw((cpu_data & 0xFFFF) & ~(1 << bit)); + } + handled = 1; + break; + } + case 0x20: /* ADD4S */ + { + uint8_t odd = !!(CL % 2); + uint8_t zero = 1; + uint8_t nibbles_count = CL - odd; + uint32_t i = 0, carry = 0, nibble = 0; + uint32_t srcseg = ovr_seg ? *ovr_seg : ds; + + wait(5, 0); + for (i = 0; i < ((nibbles_count / 2) + odd); i++) { + wait(19, 0); + uint8_t destcmp = read_mem_b((es) + DI + i); + for (nibble = 0; nibble < 2; nibble++) { + uint8_t destbyte = destcmp >> (nibble ? 4 : 0); + uint8_t srcbyte = read_mem_b(srcseg + SI + i) >> (nibble ? 4 : 0); + destbyte &= 0xF; + srcbyte &= 0xF; + uint8_t nibble_result = (i == (nibbles_count / 2) && nibble == 1) ? (destbyte + carry) : ((uint8_t) (destbyte)) + ((uint8_t) (srcbyte)) + ((uint32_t) carry); + carry = 0; + while (nibble_result >= 10) { + nibble_result -= 10; + carry++; + } + if (zero != 0 || (i == (nibbles_count / 2) && nibble == 1)) + zero = (nibble_result == 0); + destcmp = ((destcmp & (nibble ? 0x0F : 0xF0)) | (nibble_result << (4 * nibble))); + } + write_mem_b(es + DI + i, destcmp); + } + set_cf(!!carry); + set_zf(!!zero); + handled = 1; + break; + } + case 0x22: /* SUB4S */ + { + uint8_t odd = !!(CL % 2); + uint8_t zero = 1; + uint8_t nibbles_count = CL - odd; + uint32_t i = 0, carry = 0, nibble = 0; + uint32_t srcseg = ovr_seg ? *ovr_seg : ds; + + wait(5, 0); + for (i = 0; i < ((nibbles_count / 2) + odd); i++) { + wait(19, 0); + uint8_t destcmp = read_mem_b((es) + DI + i); + for (nibble = 0; nibble < 2; nibble++) { + uint8_t destbyte = destcmp >> (nibble ? 4 : 0); + uint8_t srcbyte = read_mem_b(srcseg + SI + i) >> (nibble ? 4 : 0); + destbyte &= 0xF; + srcbyte &= 0xF; + int8_t nibble_result = (i == (nibbles_count / 2) && nibble == 1) ? ((int8_t) destbyte - (int8_t) carry) : ((int8_t) (destbyte)) - ((int8_t) (srcbyte)) - ((int8_t) carry); + carry = 0; + while (nibble_result < 0) { + nibble_result += 10; + carry++; + } + if (zero != 0 || (i == (nibbles_count / 2) && nibble == 1)) + zero = (nibble_result == 0); + destcmp = ((destcmp & (nibble ? 0x0F : 0xF0)) | (nibble_result << (4 * nibble))); + } + write_mem_b(es + DI + i, destcmp); + } + set_cf(!!carry); + set_zf(!!zero); + handled = 1; + break; + } + case 0x26: /* CMP4S */ + { + uint8_t odd = !!(CL % 2); + uint8_t zero = 1; + uint8_t nibbles_count = CL - odd; + uint32_t i = 0, carry = 0, nibble = 0; + uint32_t srcseg = ovr_seg ? *ovr_seg : ds; + + wait(5, 0); + for (i = 0; i < ((nibbles_count / 2) + odd); i++) { + wait(19, 0); + uint8_t destcmp = read_mem_b((es) + DI + i); + for (nibble = 0; nibble < 2; nibble++) { + uint8_t destbyte = destcmp >> (nibble ? 4 : 0); + uint8_t srcbyte = read_mem_b(srcseg + SI + i) >> (nibble ? 4 : 0); + destbyte &= 0xF; + srcbyte &= 0xF; + int8_t nibble_result = ((int8_t) (destbyte)) - ((int8_t) (srcbyte)) - ((int8_t) carry); + carry = 0; + while (nibble_result < 0) { + nibble_result += 10; + carry++; + } + if (zero != 0 || (i == (nibbles_count / 2) && nibble == 1)) + zero = (nibble_result == 0); + destcmp = ((destcmp & (nibble ? 0x0F : 0xF0)) | (nibble_result << (4 * nibble))); + } + } + set_cf(!!carry); + set_zf(!!zero); + handled = 1; + break; + } + case 0x31: /* INS reg1, reg2 */ + case 0x39: /* INS reg8, imm4 */ + { + do_mod_rm(); + wait(1, 0); + { + uint8_t bit_length = ((opcode & 0x8) ? (pfq_fetchb() & 0xF) : (getr8(cpu_reg) & 0xF)) + 1; + uint8_t bit_offset = getr8(cpu_rm) & 0xF; + uint32_t byteaddr = (es) + DI; + uint32_t i = 0; + if (bit_offset >= 8) { + DI++; + byteaddr++; + bit_offset -= 8; + } + for (i = 0; i < bit_length; i++) { + byteaddr = (es) + DI; + writememb(es, DI, (read_mem_b(byteaddr) & ~(1 << (bit_offset))) | ((!!(AX & (1 << i))) << bit_offset)); + bit_offset++; + if (bit_offset == 8) { + DI++; + bit_offset = 0; + } + } + setr8(cpu_rm, bit_offset); + } + handled = 1; + break; + } + case 0x33: /* EXT reg1, reg2 */ + case 0x3b: /* EXT reg8, imm4 */ + { + do_mod_rm(); + wait(1, 0); + { + uint8_t bit_length = ((opcode & 0x8) ? (pfq_fetchb() & 0xF) : (getr8(cpu_reg) & 0xF)) + 1; + uint8_t bit_offset = getr8(cpu_rm) & 0xF; + uint32_t byteaddr = (ds) + SI; + uint32_t i = 0; + + if (bit_offset >= 8) { + SI++; + byteaddr++; + bit_offset -= 8; + } + + AX = 0; + for (i = 0; i < bit_length; i++) { + byteaddr = (ds) + SI; + AX |= (!!(readmemb(byteaddr) & (1 << bit_offset))) << i; + bit_offset++; + if (bit_offset == 8) { + SI++; + bit_offset = 0; + } + } + setr8(cpu_rm, bit_offset); + } + handled = 1; + break; + } + + case 0xFF: + { /* BRKEM */ + /* Unimplemented for now. */ + fatal("808x: Unsupported 8080 emulation mode attempted to enter into!"); + break; + } + default: + { + opcode = orig_opcode; + cpu_state.pc--; + break; + } + } + } else + handled = 0; + if (handled) + break; + access(22, 16); + if (opcode == 0x0F) { + load_cs(pop()); + pfq_pos = 0; + } else + load_seg(pop(), _opseg[(opcode >> 3) & 0x03]); + wait(1, 0); + /* All POP segment instructions suppress interrupts for one instruction. */ + noint = 1; + break; + + case 0x26: /*ES:*/ + case 0x2E: /*CS:*/ + case 0x36: /*SS:*/ + case 0x3E: /*DS:*/ + wait(1, 0); + ovr_seg = opseg[(opcode >> 3) & 0x03]; + completed = 0; + break; + + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x28: + case 0x29: + case 0x2a: + case 0x2b: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x38: + case 0x39: + case 0x3a: + case 0x3b: + /* alu rm, r / r, rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(46, bits); + tempw = get_ea(); + cpu_alu_op = (opcode >> 3) & 7; if ((opcode & 2) == 0) { - access(10, bits); - set_ea(cpu_data); + cpu_dest = tempw; + cpu_src = get_reg(cpu_reg); + } else { + cpu_dest = get_reg(cpu_reg); + cpu_src = tempw; + } + if (cpu_mod != 3) + wait(2, 0); + wait(1, 0); + alu_op(bits); + if (cpu_alu_op != 7) { + if ((opcode & 2) == 0) { + access(10, bits); + set_ea(cpu_data); + if (cpu_mod == 3) + wait(1, 0); + } else { + set_reg(cpu_reg, cpu_data); + wait(1, 0); + } + } else + wait(1, 0); + break; + + case 0x04: + case 0x05: + case 0x0c: + case 0x0d: + case 0x14: + case 0x15: + case 0x1c: + case 0x1d: + case 0x24: + case 0x25: + case 0x2c: + case 0x2d: + case 0x34: + case 0x35: + case 0x3c: + case 0x3d: + /* alu A, imm */ + bits = 8 << (opcode & 1); + wait(1, 0); + cpu_data = pfq_fetch(); + cpu_dest = get_accum(bits); /* AX/AL */ + cpu_src = cpu_data; + cpu_alu_op = (opcode >> 3) & 7; + alu_op(bits); + if (cpu_alu_op != 7) + set_accum(bits, cpu_data); + wait(1, 0); + break; + + case 0x27: /*DAA*/ + cpu_dest = AL; + set_of(0); + old_af = !!(cpu_state.flags & A_FLAG); + if ((cpu_state.flags & A_FLAG) || (AL & 0x0f) > 9) { + cpu_src = 6; + cpu_data = cpu_dest + cpu_src; + set_of_add(8); + cpu_dest = cpu_data; + set_af(1); + } + if ((cpu_state.flags & C_FLAG) || AL > (old_af ? 0x9f : 0x99)) { + cpu_src = 0x60; + cpu_data = cpu_dest + cpu_src; + set_of_add(8); + cpu_dest = cpu_data; + set_cf(1); + } + AL = cpu_dest; + set_pzs(8); + wait(3, 0); + break; + case 0x2F: /*DAS*/ + cpu_dest = AL; + set_of(0); + old_af = !!(cpu_state.flags & A_FLAG); + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { + cpu_src = 6; + cpu_data = cpu_dest - cpu_src; + set_of_sub(8); + cpu_dest = cpu_data; + set_af(1); + } + if ((cpu_state.flags & C_FLAG) || AL > (old_af ? 0x9f : 0x99)) { + cpu_src = 0x60; + cpu_data = cpu_dest - cpu_src; + set_of_sub(8); + cpu_dest = cpu_data; + set_cf(1); + } + AL = cpu_dest; + set_pzs(8); + wait(3, 0); + break; + case 0x37: /*AAA*/ + wait(1, 0); + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { + cpu_src = 6; + ++AH; + set_ca(); + } else { + cpu_src = 0; + clear_ca(); + wait(1, 0); + } + cpu_dest = AL; + cpu_data = cpu_dest + cpu_src; + set_of_add(8); + aa(); + break; + case 0x3F: /*AAS*/ + wait(1, 0); + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { + cpu_src = 6; + --AH; + set_ca(); + } else { + cpu_src = 0; + clear_ca(); + wait(1, 0); + } + cpu_dest = AL; + cpu_data = cpu_dest - cpu_src; + set_of_sub(8); + aa(); + break; + + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + /* INCDEC rw */ + wait(1, 0); + cpu_dest = cpu_state.regs[opcode & 7].w; + cpu_src = 1; + bits = 16; + if ((opcode & 8) == 0) { + cpu_data = cpu_dest + cpu_src; + set_of_add(bits); + } else { + cpu_data = cpu_dest - cpu_src; + set_of_sub(bits); + } + do_af(); + set_pzs(16); + cpu_state.regs[opcode & 7].w = cpu_data; + break; + + case 0x50: + case 0x51: + case 0x52: + case 0x53: /*PUSH r16*/ + case 0x54: + case 0x55: + case 0x56: + case 0x57: + access(30, 16); + push(&(cpu_state.regs[opcode & 0x07].w)); + break; + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: /*POP r16*/ + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + access(23, 16); + cpu_state.regs[opcode & 0x07].w = pop(); + wait(1, 0); + break; + + case 0x60: /*JO alias*/ + if (is186) { /* PUSHA/PUSH R*/ + uint16_t orig_sp = SP; + wait(1, 0); + push(&AX); + push(&CX); + push(&DX); + push(&BX); + push(&orig_sp); + push(&BP); + push(&SI); + push(&DI); + } else + jcc(opcode, cpu_state.flags & V_FLAG); + break; + case 0x70: /*JO*/ + case 0x61: /*JNO alias*/ + if (is186) { /* POPA/POP R*/ + uint16_t orig_sp = 0; /* deliberately unused. */ + wait(9, 0); + DI = pop(); + SI = pop(); + BP = pop(); + orig_sp = pop(); + BX = pop(); + DX = pop(); + CX = pop(); + AX = pop(); + break; + } + case 0x71: /*JNO*/ + jcc(opcode, cpu_state.flags & V_FLAG); + break; + case 0x62: /*JB alias*/ + case 0x72: /*JB*/ + case 0x63: /*JNB alias*/ + case 0x73: /*JNB*/ + jcc(opcode, cpu_state.flags & C_FLAG); + break; + case 0x64: /*JE alias*/ + case 0x74: /*JE*/ + case 0x65: /*JNE alias*/ + case 0x75: /*JNE*/ + if (is_nec && (opcode & 0xFE) == 0x64) { + /* REPC/REPNC */ + wait(1, 0); + in_rep = (opcode == 0x64 ? 1 : 2); + rep_c_flag = 1; + completed = 0; + } else + jcc(opcode, cpu_state.flags & Z_FLAG); + break; + case 0x66: /*JBE alias*/ + case 0x76: /*JBE*/ + case 0x67: /*JNBE alias*/ + case 0x77: /*JNBE*/ + jcc(opcode, cpu_state.flags & (C_FLAG | Z_FLAG)); + break; + case 0x68: /*JS alias*/ + if (is186) { /* PUSH imm16 */ + uint16_t wordtopush = pfq_fetchw(); + wait(1, 0); + push(&wordtopush); + break; + } + case 0x78: /*JS*/ + case 0x69: /*JNS alias*/ + if (is186 && opcode == 0x69) { /* IMUL reg16,reg16/mem16,imm16 */ + uint16_t immediate = 0; + bits = 16; + do_mod_rm(); + read_ea(0, 16); + immediate = pfq_fetchw(); + mul(cpu_data & 0xFFFF, immediate); + set_reg(cpu_reg, cpu_data); + set_co_mul(16, cpu_dest != 0); + break; + } + case 0x79: /*JNS*/ + jcc(opcode, cpu_state.flags & N_FLAG); + break; + case 0x6A: /*JP alias*/ + if (is186) { /* PUSH imm8 */ + uint16_t wordtopush = sign_extend(pfq_fetchb()); + push(&wordtopush); + break; + } + case 0x7A: /*JP*/ + case 0x6B: /*JNP alias*/ + if (is186 && opcode == 0x6B) { /* IMUL reg16,reg16/mem16,imm8 */ + uint16_t immediate = 0; + bits = 16; + do_mod_rm(); + read_ea(0, 16); + immediate = pfq_fetchb(); + mul(cpu_data & 0xFFFF, immediate); + set_reg(cpu_reg, cpu_data); + set_co_mul(16, cpu_dest != 0); + break; + } + case 0x7B: /*JNP*/ + jcc(opcode, cpu_state.flags & P_FLAG); + break; + case 0x6C: /*JL alias*/ + case 0x7C: /*JL*/ + case 0x6D: /*JNL alias*/ + case 0x7D: /*JNL*/ + temp = (cpu_state.flags & N_FLAG) ? 1 : 0; + temp2 = (cpu_state.flags & V_FLAG) ? 1 : 0; + jcc(opcode, temp ^ temp2); + break; + case 0x6E: /*JLE alias*/ + case 0x7E: /*JLE*/ + case 0x6F: /*JNLE alias*/ + case 0x7F: /*JNLE*/ + temp = (cpu_state.flags & N_FLAG) ? 1 : 0; + temp2 = (cpu_state.flags & V_FLAG) ? 1 : 0; + jcc(opcode, (cpu_state.flags & Z_FLAG) || (temp != temp2)); + break; + + case 0x80: + case 0x81: + case 0x82: + case 0x83: + /* alu rm, imm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(47, bits); + cpu_data = get_ea(); + cpu_dest = cpu_data; + if (cpu_mod != 3) + wait(3, 0); + if (opcode == 0x81) { if (cpu_mod == 3) wait(1, 0); + cpu_src = pfq_fetchw(); } else { - set_reg(cpu_reg, cpu_data); - wait(1, 0); + if (cpu_mod == 3) + wait(1, 0); + if (opcode == 0x83) + cpu_src = sign_extend(pfq_fetchb()); + else + cpu_src = pfq_fetchb() | 0xff00; } - } else wait(1, 0); - break; + cpu_alu_op = (rmdat & 0x38) >> 3; + alu_op(bits); + if (cpu_alu_op != 7) { + access(11, bits); + set_ea(cpu_data); + } else { + if (cpu_mod != 3) + wait(1, 0); + } + break; - case 0x04: - case 0x05: - case 0x0c: - case 0x0d: - case 0x14: - case 0x15: - case 0x1c: - case 0x1d: - case 0x24: - case 0x25: - case 0x2c: - case 0x2d: - case 0x34: - case 0x35: - case 0x3c: - case 0x3d: - /* alu A, imm */ - bits = 8 << (opcode & 1); - wait(1, 0); - cpu_data = pfq_fetch(); - cpu_dest = get_accum(bits); /* AX/AL */ - cpu_src = cpu_data; - cpu_alu_op = (opcode >> 3) & 7; - alu_op(bits); - if (cpu_alu_op != 7) - set_accum(bits, cpu_data); - wait(1, 0); - break; - - case 0x27: /*DAA*/ - cpu_dest = AL; - set_of(0); - old_af = !!(cpu_state.flags & A_FLAG); - if ((cpu_state.flags & A_FLAG) || (AL & 0x0f) > 9) { - cpu_src = 6; - cpu_data = cpu_dest + cpu_src; - set_of_add(8); - cpu_dest = cpu_data; - set_af(1); - } - if ((cpu_state.flags & C_FLAG) || AL > (old_af ? 0x9f : 0x99)) { - cpu_src = 0x60; - cpu_data = cpu_dest + cpu_src; - set_of_add(8); - cpu_dest = cpu_data; - set_cf(1); - } - AL = cpu_dest; - set_pzs(8); - wait(3, 0); - break; - case 0x2F: /*DAS*/ - cpu_dest = AL; - set_of(0); - old_af = !!(cpu_state.flags & A_FLAG); - if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { - cpu_src = 6; - cpu_data = cpu_dest - cpu_src; - set_of_sub(8); - cpu_dest = cpu_data; - set_af(1); - } - if ((cpu_state.flags & C_FLAG) || AL > (old_af ? 0x9f : 0x99)) { - cpu_src = 0x60; - cpu_data = cpu_dest - cpu_src; - set_of_sub(8); - cpu_dest = cpu_data; - set_cf(1); - } - AL = cpu_dest; - set_pzs(8); - wait(3, 0); - break; - case 0x37: /*AAA*/ - wait(1, 0); - if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { - cpu_src = 6; - ++AH; - set_ca(); - } else { - cpu_src = 0; - clear_ca(); - wait(1, 0); - } - cpu_dest = AL; - cpu_data = cpu_dest + cpu_src; - set_of_add(8); - aa(); - break; - case 0x3F: /*AAS*/ - wait(1, 0); - if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { - cpu_src = 6; - --AH; - set_ca(); - } else { - cpu_src = 0; - clear_ca(); - wait(1, 0); - } - cpu_dest = AL; - cpu_data = cpu_dest - cpu_src; - set_of_sub(8); - aa(); - break; - - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - /* INCDEC rw */ - wait(1, 0); - cpu_dest = cpu_state.regs[opcode & 7].w; - cpu_src = 1; - bits = 16; - if ((opcode & 8) == 0) { - cpu_data = cpu_dest + cpu_src; - set_of_add(bits); - } else { - cpu_data = cpu_dest - cpu_src; - set_of_sub(bits); - } - do_af(); - set_pzs(16); - cpu_state.regs[opcode & 7].w = cpu_data; - break; - - case 0x50: - case 0x51: - case 0x52: - case 0x53: /*PUSH r16*/ - case 0x54: - case 0x55: - case 0x56: - case 0x57: - access(30, 16); - push(&(cpu_state.regs[opcode & 0x07].w)); - break; - case 0x58: - case 0x59: - case 0x5A: - case 0x5B: /*POP r16*/ - case 0x5C: - case 0x5D: - case 0x5E: - case 0x5F: - access(23, 16); - cpu_state.regs[opcode & 0x07].w = pop(); - wait(1, 0); - break; - - case 0x60: /*JO alias*/ - case 0x70: /*JO*/ - case 0x61: /*JNO alias*/ - case 0x71: /*JNO*/ - jcc(opcode, cpu_state.flags & V_FLAG); - break; - case 0x62: /*JB alias*/ - case 0x72: /*JB*/ - case 0x63: /*JNB alias*/ - case 0x73: /*JNB*/ - jcc(opcode, cpu_state.flags & C_FLAG); - break; - case 0x64: /*JE alias*/ - case 0x74: /*JE*/ - case 0x65: /*JNE alias*/ - case 0x75: /*JNE*/ - jcc(opcode, cpu_state.flags & Z_FLAG); - break; - case 0x66: /*JBE alias*/ - case 0x76: /*JBE*/ - case 0x67: /*JNBE alias*/ - case 0x77: /*JNBE*/ - jcc(opcode, cpu_state.flags & (C_FLAG | Z_FLAG)); - break; - case 0x68: /*JS alias*/ - case 0x78: /*JS*/ - case 0x69: /*JNS alias*/ - case 0x79: /*JNS*/ - jcc(opcode, cpu_state.flags & N_FLAG); - break; - case 0x6A: /*JP alias*/ - case 0x7A: /*JP*/ - case 0x6B: /*JNP alias*/ - case 0x7B: /*JNP*/ - jcc(opcode, cpu_state.flags & P_FLAG); - break; - case 0x6C: /*JL alias*/ - case 0x7C: /*JL*/ - case 0x6D: /*JNL alias*/ - case 0x7D: /*JNL*/ - temp = (cpu_state.flags & N_FLAG) ? 1 : 0; - temp2 = (cpu_state.flags & V_FLAG) ? 1 : 0; - jcc(opcode, temp ^ temp2); - break; - case 0x6E: /*JLE alias*/ - case 0x7E: /*JLE*/ - case 0x6F: /*JNLE alias*/ - case 0x7F: /*JNLE*/ - temp = (cpu_state.flags & N_FLAG) ? 1 : 0; - temp2 = (cpu_state.flags & V_FLAG) ? 1 : 0; - jcc(opcode, (cpu_state.flags & Z_FLAG) || (temp != temp2)); - break; - - case 0x80: - case 0x81: - case 0x82: - case 0x83: - /* alu rm, imm */ - bits = 8 << (opcode & 1); - do_mod_rm(); - access(47, bits); - cpu_data = get_ea(); - cpu_dest = cpu_data; - if (cpu_mod != 3) + case 0x84: + case 0x85: + /* TEST rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(48, bits); + cpu_data = get_ea(); + test(bits, cpu_data, get_reg(cpu_reg)); + if (cpu_mod == 3) + wait(2, 0); + wait(2, 0); + break; + case 0x86: + case 0x87: + /* XCHG rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(49, bits); + cpu_data = get_ea(); + cpu_src = get_reg(cpu_reg); + set_reg(cpu_reg, cpu_data); wait(3, 0); - if (opcode == 0x81) { - if (cpu_mod == 3) - wait(1, 0); - cpu_src = pfq_fetchw(); - } else { - if (cpu_mod == 3) - wait(1, 0); - if (opcode == 0x83) - cpu_src = sign_extend(pfq_fetchb()); - else - cpu_src = pfq_fetchb() | 0xff00; - } - wait(1, 0); - cpu_alu_op = (rmdat & 0x38) >> 3; - alu_op(bits); - if (cpu_alu_op != 7) { - access(11, bits); - set_ea(cpu_data); - } else { + access(12, bits); + set_ea(cpu_src); + break; + + case 0x88: + case 0x89: + /* MOV rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + wait(1, 0); + access(13, bits); + set_ea(get_reg(cpu_reg)); + break; + case 0x8A: + case 0x8B: + /* MOV reg, rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(50, bits); + set_reg(cpu_reg, get_ea()); + wait(1, 0); if (cpu_mod != 3) + wait(2, 0); + break; + + case 0x8C: /*MOV w,sreg*/ + do_mod_rm(); + if (cpu_mod == 3) wait(1, 0); - } - break; + access(14, 16); + seteaw(_opseg[(rmdat & 0x18) >> 3]->seg); + break; - case 0x84: - case 0x85: - /* TEST rm, reg */ - bits = 8 << (opcode & 1); - do_mod_rm(); - access(48, bits); - cpu_data = get_ea(); - test(bits, cpu_data, get_reg(cpu_reg)); - if (cpu_mod == 3) - wait(2, 0); - wait(2, 0); - break; - case 0x86: - case 0x87: - /* XCHG rm, reg */ - bits = 8 << (opcode & 1); - do_mod_rm(); - access(49, bits); - cpu_data = get_ea(); - cpu_src = get_reg(cpu_reg); - set_reg(cpu_reg, cpu_data); - wait(3, 0); - access(12, bits); - set_ea(cpu_src); - break; - - case 0x88: - case 0x89: - /* MOV rm, reg */ - bits = 8 << (opcode & 1); - do_mod_rm(); - wait(1, 0); - access(13, bits); - set_ea(get_reg(cpu_reg)); - break; - case 0x8A: - case 0x8B: - /* MOV reg, rm */ - bits = 8 << (opcode & 1); - do_mod_rm(); - access(50, bits); - set_reg(cpu_reg, get_ea()); - wait(1, 0); - if (cpu_mod != 3) - wait(2, 0); - break; - - case 0x8C: /*MOV w,sreg*/ - do_mod_rm(); - if (cpu_mod == 3) + case 0x8D: /*LEA*/ + do_mod_rm(); + cpu_state.regs[cpu_reg].w = cpu_state.eaaddr; wait(1, 0); - access(14, 16); - seteaw(_opseg[(rmdat & 0x18) >> 3]->seg); - break; + if (cpu_mod != 3) + wait(2, 0); + break; - case 0x8D: /*LEA*/ - do_mod_rm(); - cpu_state.regs[cpu_reg].w = cpu_state.eaaddr; - wait(1, 0); - if (cpu_mod != 3) - wait(2, 0); - break; - - case 0x8E: /*MOV sreg,w*/ - do_mod_rm(); - access(51, 16); - tempw = geteaw(); - if ((rmdat & 0x18) == 0x08) { - load_cs(tempw); - pfq_pos = 0; - } else - load_seg(tempw, _opseg[(rmdat & 0x18) >> 3]); - wait(1, 0); - if (cpu_mod != 3) - wait(2, 0); - if (((rmdat & 0x18) >> 3) == 2) - noint = 1; - break; - - case 0x8F: /*POPW*/ - do_mod_rm(); - wait(1, 0); - cpu_src = cpu_state.eaaddr; - access(24, 16); - if (cpu_mod != 3) - wait(2, 0); - cpu_data = pop(); - cpu_state.eaaddr = cpu_src; - wait(2, 0); - access(15, 16); - seteaw(cpu_data); - break; - - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - /* XCHG AX, rw */ - wait(1, 0); - cpu_data = cpu_state.regs[opcode & 7].w; - cpu_state.regs[opcode & 7].w = AX; - AX = cpu_data; - wait(1, 0); - break; - - case 0x98: /*CBW*/ - wait(1, 0); - AX = sign_extend(AL); - break; - case 0x99: /*CWD*/ - wait(4, 0); - if (!top_bit(AX, 16)) - DX = 0; - else { + case 0x8E: /*MOV sreg,w*/ + do_mod_rm(); + access(51, 16); + tempw = geteaw(); + if ((rmdat & 0x18) == 0x08) { + load_cs(tempw); + pfq_pos = 0; + } else + load_seg(tempw, _opseg[(rmdat & 0x18) >> 3]); wait(1, 0); - DX = 0xffff; - } - break; - case 0x9A: /*CALL FAR*/ - wait(1, 0); - new_ip = pfq_fetchw(); - wait(1, 0); - new_cs = pfq_fetchw(); - pfq_clear(); - access(31, 16); - push(&(CS)); - access(60, 16); - cpu_state.oldpc = cpu_state.pc; - load_cs(new_cs); - set_ip(new_ip); - access(32, 16); - push((uint16_t *) &(cpu_state.oldpc)); - break; - case 0x9B: /*WAIT*/ - if (!repeating) + if (cpu_mod != 3) + wait(2, 0); + if (((rmdat & 0x18) >> 3) == 2) + noint = 1; + break; + + case 0x8F: /*POPW*/ + do_mod_rm(); + wait(1, 0); + cpu_src = cpu_state.eaaddr; + access(24, 16); + if (cpu_mod != 3) + wait(2, 0); + cpu_data = pop(); + cpu_state.eaaddr = cpu_src; wait(2, 0); - wait(5, 0); + access(15, 16); + seteaw(cpu_data); + break; + + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + /* XCHG AX, rw */ + wait(1, 0); + cpu_data = cpu_state.regs[opcode & 7].w; + cpu_state.regs[opcode & 7].w = AX; + AX = cpu_data; + wait(1, 0); + break; + + case 0x98: /*CBW*/ + wait(1, 0); + AX = sign_extend(AL); + break; + case 0x99: /*CWD*/ + wait(4, 0); + if (!top_bit(AX, 16)) + DX = 0; + else { + wait(1, 0); + DX = 0xffff; + } + break; + case 0x9A: /*CALL FAR*/ + wait(1, 0); + new_ip = pfq_fetchw(); + wait(1, 0); + new_cs = pfq_fetchw(); + pfq_clear(); + access(31, 16); + push(&(CS)); + access(60, 16); + cpu_state.oldpc = cpu_state.pc; + load_cs(new_cs); + set_ip(new_ip); + access(32, 16); + push((uint16_t *) &(cpu_state.oldpc)); + break; + case 0x9B: /*WAIT*/ + if (!repeating) + wait(2, 0); + wait(5, 0); #ifdef NO_HACK - if (irq_pending()) { + if (irq_pending()) { + wait(7, 0); + check_interrupts(); + } else { + repeating = 1; + completed = 0; + clock_end(); + } +#else wait(7, 0); check_interrupts(); - } else { - repeating = 1; - completed = 0; - clock_end(); - } -#else - wait(7, 0); - check_interrupts(); #endif - break; - case 0x9C: /*PUSHF*/ - access(33, 16); - tempw = (cpu_state.flags & 0x0fd7) | 0xf000; - push(&tempw); - break; - case 0x9D: /*POPF*/ - access(25, 16); - cpu_state.flags = pop() | 2; - wait(1, 0); - break; - case 0x9E: /*SAHF*/ - wait(1, 0); - cpu_state.flags = (cpu_state.flags & 0xff02) | AH; - wait(2, 0); - break; - case 0x9F: /*LAHF*/ - wait(1, 0); - AH = cpu_state.flags & 0xd7; - break; - - case 0xA0: - case 0xA1: - /* MOV A, [iw] */ - bits = 8 << (opcode & 1); - wait(1, 0); - cpu_state.eaaddr = pfq_fetchw(); - access(1, bits); - set_accum(bits, readmem((ovr_seg ? *ovr_seg : ds))); - wait(1, 0); - break; - case 0xA2: - case 0xA3: - /* MOV [iw], A */ - bits = 8 << (opcode & 1); - wait(1, 0); - cpu_state.eaaddr = pfq_fetchw(); - access(7, bits); - writemem((ovr_seg ? *ovr_seg : ds), get_accum(bits)); - break; - - case 0xA4: - case 0xA5: /* MOVS */ - case 0xAC: - case 0xAD: /* LODS */ - bits = 8 << (opcode & 1); - if (!repeating) { - wait(1, 0); - if ((opcode & 8) == 0 && in_rep != 0) - wait(1, 0); - } - if (rep_action(bits)) { - wait(1, 0); - if ((opcode & 8) != 0) - wait(1, 0); break; - } - if (in_rep != 0 && (opcode & 8) != 0) - wait(1, 0); - access(20, bits); - lods(bits); - if ((opcode & 8) == 0) { - access(27, bits); - stos(bits); - } else { - set_accum(bits, cpu_data); - if (in_rep != 0) - wait(2, 0); - } - if (in_rep == 0) { - wait(3, 0); - if ((opcode & 8) != 0) - wait(1, 0); + case 0x9C: /*PUSHF*/ + access(33, 16); + tempw = cpu_state.flags & (is_nec && cpu_state.inside_emulation_mode ? MD_FLAG | 0x0fd7 : 0x0fd7); + push(&tempw); break; - } - repeating = 1; - clock_end(); - break; - - case 0xA6: - case 0xA7: /* CMPS */ - case 0xAE: - case 0xAF: /* SCAS */ - bits = 8 << (opcode & 1); - if (!repeating) + case 0x9D: /*POPF*/ + access(25, 16); + cpu_state.flags = pop() | 2; wait(1, 0); - if (rep_action(bits)) { + break; + case 0x9E: /*SAHF*/ + wait(1, 0); + cpu_state.flags = (cpu_state.flags & 0xff02) | AH; wait(2, 0); break; - } - if (in_rep != 0) + case 0x9F: /*LAHF*/ wait(1, 0); - wait(1, 0); - cpu_dest = get_accum(bits); - if ((opcode & 8) == 0) { - access(21, bits); + AH = cpu_state.flags & 0xd7; + break; + + case 0xA0: + case 0xA1: + /* MOV A, [iw] */ + bits = 8 << (opcode & 1); + wait(1, 0); + cpu_state.eaaddr = pfq_fetchw(); + access(1, bits); + set_accum(bits, readmem((ovr_seg ? *ovr_seg : ds))); + wait(1, 0); + break; + case 0xA2: + case 0xA3: + /* MOV [iw], A */ + bits = 8 << (opcode & 1); + wait(1, 0); + cpu_state.eaaddr = pfq_fetchw(); + access(7, bits); + writemem((ovr_seg ? *ovr_seg : ds), get_accum(bits)); + break; + + case 0xA4: + case 0xA5: /* MOVS */ + case 0xAC: + case 0xAD: /* LODS */ + bits = 8 << (opcode & 1); + if (!repeating) { + wait(1, 0); + if ((opcode & 8) == 0 && in_rep != 0) + wait(1, 0); + } + if (rep_action(bits)) { + wait(1, 0); + if ((opcode & 8) != 0) + wait(1, 0); + break; + } + if (in_rep != 0 && (opcode & 8) != 0) + wait(1, 0); + access(20, bits); lods(bits); - wait(1, 0); - cpu_dest = cpu_data; - } - access(2, bits); - cpu_state.eaaddr = DI; - cpu_data = readmem(es); - DI = string_increment(bits); - cpu_src = cpu_data; - sub(bits); - wait(2, 0); - if (in_rep == 0) { - wait(3, 0); + if ((opcode & 8) == 0) { + access(27, bits); + stos(bits); + } else { + set_accum(bits, cpu_data); + if (in_rep != 0) + wait(2, 0); + } + if (in_rep == 0) { + wait(3, 0); + if ((opcode & 8) != 0) + wait(1, 0); + break; + } + repeating = 1; + clock_end(); break; - } - if ((!!(cpu_state.flags & Z_FLAG)) == (in_rep == 1)) { - completed = 1; - wait(4, 0); - break; - } - repeating = 1; - clock_end(); - break; - case 0xA8: - case 0xA9: - /* TEST A, imm */ - bits = 8 << (opcode & 1); - wait(1, 0); - cpu_data = pfq_fetch(); - test(bits, get_accum(bits), cpu_data); - wait(1, 0); - break; - - case 0xAA: - case 0xAB: /* STOS */ - bits = 8 << (opcode & 1); - if (!repeating) { - wait(1, 0); + case 0xA6: + case 0xA7: /* CMPS */ + case 0xAE: + case 0xAF: /* SCAS */ + bits = 8 << (opcode & 1); + if (!repeating) + wait(1, 0); + if (rep_action(bits)) { + wait(2, 0); + break; + } if (in_rep != 0) wait(1, 0); - } - if (rep_action(bits)) { wait(1, 0); - break; - } - cpu_data = AX; - access(28, bits); - stos(bits); - if (in_rep == 0) { - wait(3, 0); - break; - } - repeating = 1; - clock_end(); - break; - - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: /*MOV cpu_reg,#8*/ - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - wait(1, 0); - if (opcode & 0x04) - cpu_state.regs[opcode & 0x03].b.h = pfq_fetchb(); - else - cpu_state.regs[opcode & 0x03].b.l = pfq_fetchb(); - wait(1, 0); - break; - - case 0xB8: - case 0xB9: - case 0xBA: - case 0xBB: /*MOV cpu_reg,#16*/ - case 0xBC: - case 0xBD: - case 0xBE: - case 0xBF: - wait(1, 0); - cpu_state.regs[opcode & 0x07].w = pfq_fetchw(); - wait(1, 0); - break; - - case 0xC0: - case 0xC1: - case 0xC2: - case 0xC3: - case 0xC8: - case 0xC9: - case 0xCA: - case 0xCB: - /* RET */ - bits = 8 + (opcode & 0x08); - if ((opcode & 9) != 1) - wait(1, 0); - if (!(opcode & 1)) { - cpu_src = pfq_fetchw(); - wait(1, 0); - } - if ((opcode & 9) == 9) - wait(1, 0); - pfq_clear(); - access(26, bits); - new_ip = pop(); - wait(2, 0); - if ((opcode & 8) == 0) - new_cs = CS; - else { - access(42, bits); - new_cs = pop(); - if (opcode & 1) + cpu_dest = get_accum(bits); + if ((opcode & 8) == 0) { + access(21, bits); + lods(bits); wait(1, 0); - } - if (!(opcode & 1)) { - SP += cpu_src; - wait(1, 0); - } - load_cs(new_cs); - access(72, bits); - set_ip(new_ip); - break; - - case 0xC4: - case 0xC5: - /* LsS rw, rmd */ - do_mod_rm(); - bits = 16; - access(52, bits); - read_ea(1, bits); - cpu_state.regs[cpu_reg].w = cpu_data; - access(57, bits); - read_ea2(bits); - load_seg(cpu_data, (opcode & 0x01) ? &cpu_state.seg_ds : &cpu_state.seg_es); - wait(1, 0); - break; - - case 0xC6: - case 0xC7: - /* MOV rm, imm */ - bits = 8 << (opcode & 1); - do_mod_rm(); - wait(1, 0); - if (cpu_mod != 3) - wait(2, 0); - cpu_data = pfq_fetch(); - if (cpu_mod == 3) - wait(1, 0); - access(16, bits); - set_ea(cpu_data); - break; - - case 0xCC: /*INT 3*/ - interrupt(3); - break; - case 0xCD: /*INT*/ - wait(1, 0); - interrupt(pfq_fetchb()); - break; - case 0xCE: /*INTO*/ - wait(3, 0); - if (cpu_state.flags & V_FLAG) { - wait(2, 0); - interrupt(4); - } - break; - - case 0xCF: /*IRET*/ - access(43, 8); - new_ip = pop(); - wait(3, 0); - access(44, 8); - new_cs = pop(); - load_cs(new_cs); - access(62, 8); - set_ip(new_ip); - access(45, 8); - cpu_state.flags = pop() | 2; - wait(5, 0); - noint = 1; - nmi_enable = 1; - break; - - case 0xD0: - case 0xD1: - case 0xD2: - case 0xD3: - /* rot rm */ - bits = 8 << (opcode & 1); - do_mod_rm(); - if (cpu_mod == 3) - wait(1, 0); - access(53, bits); - cpu_data = get_ea(); - if ((opcode & 2) == 0) { - cpu_src = 1; - wait((cpu_mod != 3) ? 4 : 0, 0); - } else { - cpu_src = CL; - wait((cpu_mod != 3) ? 9 : 6, 0); - } - while (cpu_src != 0) { - cpu_dest = cpu_data; - oldc = cpu_state.flags & C_FLAG; - switch (rmdat & 0x38) { - case 0x00: /* ROL */ - set_cf(top_bit(cpu_data, bits)); - cpu_data <<= 1; - cpu_data |= ((cpu_state.flags & C_FLAG) ? 1 : 0); - set_of_rotate(bits); - set_af(0); - break; - case 0x08: /* ROR */ - set_cf((cpu_data & 1) != 0); - cpu_data >>= 1; - if (cpu_state.flags & C_FLAG) - cpu_data |= (!(opcode & 1) ? 0x80 : 0x8000); - set_of_rotate(bits); - set_af(0); - break; - case 0x10: /* RCL */ - set_cf(top_bit(cpu_data, bits)); - cpu_data = (cpu_data << 1) | (oldc ? 1 : 0); - set_of_rotate(bits); - set_af(0); - break; - case 0x18: /* RCR */ - set_cf((cpu_data & 1) != 0); - cpu_data >>= 1; - if (oldc) - cpu_data |= (!(opcode & 0x01) ? 0x80 : 0x8000); - set_cf((cpu_dest & 1) != 0); - set_of_rotate(bits); - set_af(0); - break; - case 0x20: /* SHL */ - set_cf(top_bit(cpu_data, bits)); - cpu_data <<= 1; - set_of_rotate(bits); - set_af((cpu_data & 0x10) != 0); - set_pzs(bits); - break; - case 0x28: /* SHR */ - set_cf((cpu_data & 1) != 0); - cpu_data >>= 1; - set_of_rotate(bits); - set_af(0); - set_pzs(bits); - break; - case 0x30: /* SETMO - undocumented? */ - bitwise(bits, 0xffff); - set_cf(0); - set_of_rotate(bits); - set_af(0); - set_pzs(bits); - break; - case 0x38: /* SAR */ - set_cf((cpu_data & 1) != 0); - cpu_data >>= 1; - if (!(opcode & 1)) - cpu_data |= (cpu_dest & 0x80); - else - cpu_data |= (cpu_dest & 0x8000); - set_of_rotate(bits); - set_af(0); - set_pzs(bits); - break; - } - if ((opcode & 2) != 0) - wait(4, 0); - --cpu_src; - } - access(17, bits); - set_ea(cpu_data); - break; - - case 0xD4: /*AAM*/ - wait(1, 0); - cpu_src = pfq_fetchb(); - if (x86_div(AL, 0)) - set_pzs(16); - break; - case 0xD5: /*AAD*/ - wait(1, 0); - mul(pfq_fetchb(), AH); - cpu_dest = AL; - cpu_src = cpu_data; - add(8); - AL = cpu_data; - AH = 0x00; - break; - case 0xD6: /*SALC*/ - wait(1, 0); - AL = (cpu_state.flags & C_FLAG) ? 0xff : 0x00; - wait(1, 0); - break; - case 0xD7: /*XLATB*/ - cpu_state.eaaddr = (BX + AL) & 0xffff; - access(4, 8); - AL = readmemb((ovr_seg ? *ovr_seg : ds) + cpu_state.eaaddr); - wait(1, 0); - break; - - case 0xD8: - case 0xD9: - case 0xDA: - case 0xDB: - case 0xDD: - case 0xDC: - case 0xDE: - case 0xDF: - /* esc i, r, rm */ - do_mod_rm(); - access(54, 16); - tempw = cpu_state.pc; - if (!hasfpu) - geteaw(); - else - switch (opcode) { - case 0xD8: - ops_fpu_8087_d8[(rmdat >> 3) & 0x1f]((uint32_t) rmdat); - break; - case 0xD9: - ops_fpu_8087_d9[rmdat & 0xff]((uint32_t) rmdat); - break; - case 0xDA: - ops_fpu_8087_da[rmdat & 0xff]((uint32_t) rmdat); - break; - case 0xDB: - ops_fpu_8087_db[rmdat & 0xff]((uint32_t) rmdat); - break; - case 0xDC: - ops_fpu_8087_dc[(rmdat >> 3) & 0x1f]((uint32_t) rmdat); - break; - case 0xDD: - ops_fpu_8087_dd[rmdat & 0xff]((uint32_t) rmdat); - break; - case 0xDE: - ops_fpu_8087_de[rmdat & 0xff]((uint32_t) rmdat); - break; - case 0xDF: - ops_fpu_8087_df[rmdat & 0xff]((uint32_t) rmdat); - break; - } - cpu_state.pc = tempw; /* Do this as the x87 code advances it, which is needed on - the 286+ core, but not here. */ - wait(1, 0); - if (cpu_mod != 3) - wait(2, 0); - break; - - case 0xE0: - case 0xE1: - case 0xE2: - case 0xE3: - /* LOOP */ - wait(3, 0); - cpu_data = pfq_fetchb(); - if (opcode != 0xe2) - wait(1, 0); - if (opcode != 0xe3) { - --CX; - oldc = (CX != 0); - switch (opcode) { - case 0xE0: - if (cpu_state.flags & Z_FLAG) - oldc = 0; - break; - case 0xE1: - if (!(cpu_state.flags & Z_FLAG)) - oldc = 0; - break; - } - } else - oldc = (CX == 0); - if (oldc) - jump_short(); - break; - - case 0xE4: - case 0xE5: - case 0xE6: - case 0xE7: - case 0xEC: - case 0xED: - case 0xEE: - case 0xEF: - bits = 8 << (opcode & 1); - if ((opcode & 0x0e) != 0x0c) - wait(1, 0); - if ((opcode & 8) == 0) - cpu_data = pfq_fetchb(); - else - cpu_data = DX; - cpu_state.eaaddr = cpu_data; - if ((opcode & 2) == 0) { - access(3, bits); - if (opcode & 1) - cpu_io(16, 0, cpu_data); - else - cpu_io(8, 0, cpu_data); - wait(1, 0); - } else { - if ((opcode & 8) == 0) - access(8, bits); - else - access(9, bits); - if (opcode & 1) - cpu_io(16, 1, cpu_data); - else - cpu_io(8, 1, cpu_data); - } - break; - - case 0xE8: /*CALL rel 16*/ - wait(1, 0); - cpu_state.oldpc = jump_near(); - access(34, 8); - push((uint16_t *) &(cpu_state.oldpc)); - break; - case 0xE9: /*JMP rel 16*/ - wait(1, 0); - jump_near(); - break; - case 0xEA: /*JMP far*/ - wait(1, 0); - addr = pfq_fetchw(); - wait(1, 0); - tempw = pfq_fetchw(); - load_cs(tempw); - access(70, 8); - pfq_clear(); - set_ip(addr); - break; - case 0xEB: /*JMP rel*/ - wait(1, 0); - cpu_data = (int8_t) pfq_fetchb(); - jump_short(); - wait(1, 0); - break; - - case 0xF0: - case 0xF1: /*LOCK - F1 is alias*/ - in_lock = 1; - wait(1, 0); - completed = 0; - break; - - case 0xF2: /*REPNE*/ - case 0xF3: /*REPE*/ - wait(1, 0); - in_rep = (opcode == 0xf2 ? 1 : 2); - completed = 0; - break; - - case 0xF4: /*HLT*/ - if (!repeating) { - wait(1, 0); - pfq_clear(); - } - wait(1, 0); - if (irq_pending()) { - wait(cycles & 1, 0); - check_interrupts(); - } else { - repeating = 1; - completed = 0; - clock_end(); - } - break; - case 0xF5: /*CMC*/ - wait(1, 0); - cpu_state.flags ^= C_FLAG; - break; - - case 0xF6: - case 0xF7: - bits = 8 << (opcode & 1); - do_mod_rm(); - access(55, bits); - cpu_data = get_ea(); - switch (rmdat & 0x38) { - case 0x00: - case 0x08: - /* TEST */ - wait(2, 0); - if (cpu_mod != 3) - wait(1, 0); - cpu_src = pfq_fetch(); - wait(1, 0); - test(bits, cpu_data, cpu_src); - if (cpu_mod != 3) - wait(1, 0); - break; - case 0x10: /* NOT */ - case 0x18: /* NEG */ - wait(2, 0); - if ((rmdat & 0x38) == 0x10) - cpu_data = ~cpu_data; - else { - cpu_src = cpu_data; - cpu_dest = 0; - sub(bits); - } - access(18, bits); - set_ea(cpu_data); - break; - case 0x20: /* MUL */ - case 0x28: /* IMUL */ - wait(1, 0); - mul(get_accum(bits), cpu_data); - if (opcode & 1) { - AX = cpu_data; - DX = cpu_dest; - set_co_mul(bits, DX != ((AX & 0x8000) == 0 || (rmdat & 0x38) == 0x20 ? 0 : 0xffff)); - cpu_data = DX; - } else { - AL = (uint8_t) cpu_data; - AH = (uint8_t) cpu_dest; - set_co_mul(bits, AH != ((AL & 0x80) == 0 || (rmdat & 0x38) == 0x20 ? 0 : 0xff)); - cpu_data = AH; - } - /* NOTE: When implementing the V20, care should be taken to not change - the zero flag. */ - set_sf(bits); - set_pf(); - if (cpu_mod != 3) - wait(1, 0); - break; - case 0x30: /* DIV */ - case 0x38: /* IDIV */ - if (cpu_mod != 3) - wait(1, 0); - cpu_src = cpu_data; - if (x86_div(AL, AH)) - wait(1, 0); - break; - } - break; - - case 0xF8: - case 0xF9: - /* CLCSTC */ - wait(1, 0); - set_cf(opcode & 1); - break; - case 0xFA: - case 0xFB: - /* CLISTI */ - wait(1, 0); - set_if(opcode & 1); - break; - case 0xFC: - case 0xFD: - /* CLDSTD */ - wait(1, 0); - set_df(opcode & 1); - break; - - case 0xFE: - case 0xFF: - /* misc */ - bits = 8 << (opcode & 1); - do_mod_rm(); - access(56, bits); - read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); - switch (rmdat & 0x38) { - case 0x00: /* INC rm */ - case 0x08: /* DEC rm */ cpu_dest = cpu_data; - cpu_src = 1; - if ((rmdat & 0x38) == 0x00) { - cpu_data = cpu_dest + cpu_src; - set_of_add(bits); - } else { - cpu_data = cpu_dest - cpu_src; - set_of_sub(bits); - } - do_af(); - set_pzs(bits); - wait(2, 0); - access(19, bits); - set_ea(cpu_data); + } + access(2, bits); + cpu_state.eaaddr = DI; + cpu_data = readmem(es); + DI = string_increment(bits); + cpu_src = cpu_data; + sub(bits); + wait(2, 0); + if (in_rep == 0) { + wait(3, 0); break; - case 0x10: /* CALL rm */ - cpu_data_opff_rm(); - access(63, bits); + } + if ((!!(cpu_state.flags & (rep_c_flag ? C_FLAG : Z_FLAG))) == (in_rep == 1)) { + completed = 1; + wait(4, 0); + break; + } + repeating = 1; + clock_end(); + break; + + case 0xA8: + case 0xA9: + /* TEST A, imm */ + bits = 8 << (opcode & 1); + wait(1, 0); + cpu_data = pfq_fetch(); + test(bits, get_accum(bits), cpu_data); + wait(1, 0); + break; + + case 0xAA: + case 0xAB: /* STOS */ + bits = 8 << (opcode & 1); + if (!repeating) { + wait(1, 0); + if (in_rep != 0) + wait(1, 0); + } + if (rep_action(bits)) { + wait(1, 0); + break; + } + cpu_data = AX; + access(28, bits); + stos(bits); + if (in_rep == 0) { + wait(3, 0); + break; + } + repeating = 1; + clock_end(); + break; + + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: /*MOV cpu_reg,#8*/ + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + wait(1, 0); + if (opcode & 0x04) + cpu_state.regs[opcode & 0x03].b.h = pfq_fetchb(); + else + cpu_state.regs[opcode & 0x03].b.l = pfq_fetchb(); + wait(1, 0); + break; + + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: /*MOV cpu_reg,#16*/ + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + wait(1, 0); + cpu_state.regs[opcode & 0x07].w = pfq_fetchw(); + wait(1, 0); + break; + + case 0xC0: + case 0xC1: + case 0xC2: + case 0xC3: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + /* RET */ + bits = 8 + (opcode & 0x08); + if ((opcode & 9) != 1) + wait(1, 0); + if (!(opcode & 1)) { + cpu_src = pfq_fetchw(); + wait(1, 0); + } + if ((opcode & 9) == 9) + wait(1, 0); + pfq_clear(); + access(26, bits); + new_ip = pop(); + wait(2, 0); + if ((opcode & 8) == 0) + new_cs = CS; + else { + access(42, bits); + new_cs = pop(); + if (opcode & 1) + wait(1, 0); + } + if (!(opcode & 1)) { + SP += cpu_src; + wait(1, 0); + } + load_cs(new_cs); + access(72, bits); + set_ip(new_ip); + break; + + case 0xC4: + case 0xC5: + /* LsS rw, rmd */ + do_mod_rm(); + bits = 16; + access(52, bits); + read_ea(1, bits); + cpu_state.regs[cpu_reg].w = cpu_data; + access(57, bits); + read_ea2(bits); + load_seg(cpu_data, (opcode & 0x01) ? &cpu_state.seg_ds : &cpu_state.seg_es); + wait(1, 0); + break; + + case 0xC6: + case 0xC7: + /* MOV rm, imm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + cpu_data = pfq_fetch(); + if (cpu_mod == 3) + wait(1, 0); + access(16, bits); + set_ea(cpu_data); + break; + + case 0xCC: /*INT 3*/ + interrupt(3); + break; + case 0xCD: /*INT*/ + wait(1, 0); + interrupt(pfq_fetchb()); + break; + case 0xCE: /*INTO*/ + wait(3, 0); + if (cpu_state.flags & V_FLAG) { + wait(2, 0); + interrupt(4); + } + break; + + case 0xCF: /*IRET*/ + access(43, 8); + new_ip = pop(); + wait(3, 0); + access(44, 8); + new_cs = pop(); + load_cs(new_cs); + access(62, 8); + set_ip(new_ip); + access(45, 8); + cpu_state.flags = pop() | 2 | (!is_nec ? 0 : (!cpu_state.inside_emulation_mode ? MD_FLAG : 0)); + wait(5, 0); + noint = 1; + nmi_enable = 1; + break; + + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + /* rot rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + if (cpu_mod == 3) + wait(1, 0); + access(53, bits); + cpu_data = get_ea(); + if ((opcode & 2) == 0) { + cpu_src = 1; + wait((cpu_mod != 3) ? 4 : 0, 0); + } else { + cpu_src = CL; + wait((cpu_mod != 3) ? 9 : 6, 0); + } + if (is186 && !is_nec) + cpu_src &= 0x1F; + while (cpu_src != 0) { + cpu_dest = cpu_data; + oldc = cpu_state.flags & C_FLAG; + switch (rmdat & 0x38) { + case 0x00: /* ROL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data <<= 1; + cpu_data |= ((cpu_state.flags & C_FLAG) ? 1 : 0); + set_of_rotate(bits); + set_af(0); + break; + case 0x08: /* ROR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (cpu_state.flags & C_FLAG) + cpu_data |= (!(opcode & 1) ? 0x80 : 0x8000); + set_of_rotate(bits); + set_af(0); + break; + case 0x10: /* RCL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data = (cpu_data << 1) | (oldc ? 1 : 0); + set_of_rotate(bits); + set_af(0); + break; + case 0x18: /* RCR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (oldc) + cpu_data |= (!(opcode & 0x01) ? 0x80 : 0x8000); + set_cf((cpu_dest & 1) != 0); + set_of_rotate(bits); + set_af(0); + break; + case 0x20: /* SHL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data <<= 1; + set_of_rotate(bits); + set_af((cpu_data & 0x10) != 0); + set_pzs(bits); + break; + case 0x28: /* SHR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + set_of_rotate(bits); + set_af(0); + set_pzs(bits); + break; + case 0x30: /* SETMO - undocumented? */ + bitwise(bits, 0xffff); + set_cf(0); + set_of_rotate(bits); + set_af(0); + set_pzs(bits); + break; + case 0x38: /* SAR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (!(opcode & 1)) + cpu_data |= (cpu_dest & 0x80); + else + cpu_data |= (cpu_dest & 0x8000); + set_of_rotate(bits); + set_af(0); + set_pzs(bits); + break; + } + if ((opcode & 2) != 0) + wait(4, 0); + --cpu_src; + } + access(17, bits); + set_ea(cpu_data); + break; + + case 0xD4: /*AAM*/ + wait(1, 0); + cpu_src = pfq_fetchb(); + if (x86_div(AL, 0)) + set_pzs(16); + break; + case 0xD5: /*AAD*/ + wait(1, 0); + mul(pfq_fetchb(), AH); + cpu_dest = AL; + cpu_src = cpu_data; + add(8); + AL = cpu_data; + AH = 0x00; + break; + case 0xD6: /*SALC*/ + wait(1, 0); + AL = (cpu_state.flags & C_FLAG) ? 0xff : 0x00; + wait(1, 0); + break; + case 0xD7: /*XLATB*/ + cpu_state.eaaddr = (BX + AL) & 0xffff; + access(4, 8); + AL = readmemb((ovr_seg ? *ovr_seg : ds) + cpu_state.eaaddr); + wait(1, 0); + break; + + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDD: + case 0xDC: + case 0xDE: + case 0xDF: + /* esc i, r, rm */ + do_mod_rm(); + access(54, 16); + tempw = cpu_state.pc; + if (!hasfpu) + geteaw(); + else + switch (opcode) { + case 0xD8: + ops_fpu_8087_d8[(rmdat >> 3) & 0x1f]((uint32_t) rmdat); + break; + case 0xD9: + ops_fpu_8087_d9[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDA: + ops_fpu_8087_da[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDB: + ops_fpu_8087_db[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDC: + ops_fpu_8087_dc[(rmdat >> 3) & 0x1f]((uint32_t) rmdat); + break; + case 0xDD: + ops_fpu_8087_dd[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDE: + ops_fpu_8087_de[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDF: + ops_fpu_8087_df[rmdat & 0xff]((uint32_t) rmdat); + break; + } + cpu_state.pc = tempw; /* Do this as the x87 code advances it, which is needed on + the 286+ core, but not here. */ + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + break; + + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + /* LOOP */ + wait(3, 0); + cpu_data = pfq_fetchb(); + if (opcode != 0xe2) + wait(1, 0); + if (opcode != 0xe3) { + --CX; + oldc = (CX != 0); + switch (opcode) { + case 0xE0: + if (cpu_state.flags & Z_FLAG) + oldc = 0; + break; + case 0xE1: + if (!(cpu_state.flags & Z_FLAG)) + oldc = 0; + break; + } + } else + oldc = (CX == 0); + if (oldc) + jump_short(); + break; + + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xEC: + case 0xED: + case 0xEE: + case 0xEF: + bits = 8 << (opcode & 1); + if ((opcode & 0x0e) != 0x0c) + wait(1, 0); + if ((opcode & 8) == 0) + cpu_data = pfq_fetchb(); + else + cpu_data = DX; + cpu_state.eaaddr = cpu_data; + if ((opcode & 2) == 0) { + access(3, bits); + if (opcode & 1) + cpu_io(16, 0, cpu_data); + else + cpu_io(8, 0, cpu_data); + wait(1, 0); + } else { + if ((opcode & 8) == 0) + access(8, bits); + else + access(9, bits); + if (opcode & 1) + cpu_io(16, 1, cpu_data); + else + cpu_io(8, 1, cpu_data); + } + break; + + case 0xE8: /*CALL rel 16*/ + wait(1, 0); + cpu_state.oldpc = jump_near(); + access(34, 8); + push((uint16_t *) &(cpu_state.oldpc)); + break; + case 0xE9: /*JMP rel 16*/ + wait(1, 0); + jump_near(); + break; + case 0xEA: /*JMP far*/ + wait(1, 0); + addr = pfq_fetchw(); + wait(1, 0); + tempw = pfq_fetchw(); + load_cs(tempw); + access(70, 8); + pfq_clear(); + set_ip(addr); + break; + case 0xEB: /*JMP rel*/ + wait(1, 0); + cpu_data = (int8_t) pfq_fetchb(); + jump_short(); + wait(1, 0); + break; + + case 0xF0: + case 0xF1: /*LOCK - F1 is alias*/ + in_lock = 1; + wait(1, 0); + completed = 0; + break; + + case 0xF2: /*REPNE*/ + case 0xF3: /*REPE*/ + wait(1, 0); + in_rep = (opcode == 0xf2 ? 1 : 2); + completed = 0; + rep_c_flag = 0; + break; + + case 0xF4: /*HLT*/ + if (!repeating) { wait(1, 0); pfq_clear(); - wait(4, 0); - if (cpu_mod != 3) - wait(1, 0); - wait(1, 0); /* Wait. */ - cpu_state.oldpc = cpu_state.pc; - set_ip(cpu_data); - wait(2, 0); - access(35, bits); - push((uint16_t *) &(cpu_state.oldpc)); - break; - case 0x18: /* CALL rmd */ - new_ip = cpu_data; - access(58, bits); - read_ea2(bits); - if (!(opcode & 1)) - cpu_data |= 0xff00; - new_cs = cpu_data; - access(36, bits); - push(&(CS)); - access(64, bits); - wait(4, 0); - cpu_state.oldpc = cpu_state.pc; - load_cs(new_cs); - set_ip(new_ip); - access(37, bits); - push((uint16_t *) &(cpu_state.oldpc)); - break; - case 0x20: /* JMP rm */ - cpu_data_opff_rm(); - access(65, bits); - set_ip(cpu_data); - break; - case 0x28: /* JMP rmd */ - new_ip = cpu_data; - access(59, bits); - read_ea2(bits); - if (!(opcode & 1)) - cpu_data |= 0xff00; - new_cs = cpu_data; - load_cs(new_cs); - access(66, bits); - set_ip(new_ip); - break; - case 0x30: /* PUSH rm */ - case 0x38: - if (cpu_mod != 3) - wait(1, 0); - access(38, bits); - push((uint16_t *) &(cpu_data)); - break; - } - break; + } + wait(1, 0); + if (irq_pending()) { + wait(cycles & 1, 0); + check_interrupts(); + } else { + repeating = 1; + completed = 0; + clock_end(); + } + break; + case 0xF5: /*CMC*/ + wait(1, 0); + cpu_state.flags ^= C_FLAG; + break; - default: - x808x_log("Illegal opcode: %02X\n", opcode); - pfq_fetchb(); - wait(8, 0); - break; + case 0xF6: + case 0xF7: + bits = 8 << (opcode & 1); + do_mod_rm(); + access(55, bits); + cpu_data = get_ea(); + switch (rmdat & 0x38) { + case 0x00: + case 0x08: + /* TEST */ + wait(2, 0); + if (cpu_mod != 3) + wait(1, 0); + cpu_src = pfq_fetch(); + wait(1, 0); + test(bits, cpu_data, cpu_src); + if (cpu_mod != 3) + wait(1, 0); + break; + case 0x10: /* NOT */ + case 0x18: /* NEG */ + wait(2, 0); + if ((rmdat & 0x38) == 0x10) + cpu_data = ~cpu_data; + else { + cpu_src = cpu_data; + cpu_dest = 0; + sub(bits); + } + access(18, bits); + set_ea(cpu_data); + break; + case 0x20: /* MUL */ + case 0x28: /* IMUL */ + wait(1, 0); + mul(get_accum(bits), cpu_data); + if (opcode & 1) { + AX = cpu_data; + DX = cpu_dest; + set_co_mul(bits, DX != ((AX & 0x8000) == 0 || (rmdat & 0x38) == 0x20 ? 0 : 0xffff)); + cpu_data = DX; + } else { + AL = (uint8_t) cpu_data; + AH = (uint8_t) cpu_dest; + set_co_mul(bits, AH != ((AL & 0x80) == 0 || (rmdat & 0x38) == 0x20 ? 0 : 0xff)); + if (!is_nec) + cpu_data = AH; + } + /* NOTE: When implementing the V20, care should be taken to not change + the zero flag. */ + set_sf(bits); + set_pf(); + if (cpu_mod != 3) + wait(1, 0); + break; + case 0x30: /* DIV */ + case 0x38: /* IDIV */ + if (cpu_mod != 3) + wait(1, 0); + cpu_src = cpu_data; + if (x86_div(AL, AH)) + wait(1, 0); + break; + } + break; + + case 0xF8: + case 0xF9: + /* CLCSTC */ + wait(1, 0); + set_cf(opcode & 1); + break; + case 0xFA: + case 0xFB: + /* CLISTI */ + wait(1, 0); + set_if(opcode & 1); + break; + case 0xFC: + case 0xFD: + /* CLDSTD */ + wait(1, 0); + set_df(opcode & 1); + break; + + case 0xFE: + case 0xFF: + /* misc */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(56, bits); + read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); + switch (rmdat & 0x38) { + case 0x00: /* INC rm */ + case 0x08: /* DEC rm */ + cpu_dest = cpu_data; + cpu_src = 1; + if ((rmdat & 0x38) == 0x00) { + cpu_data = cpu_dest + cpu_src; + set_of_add(bits); + } else { + cpu_data = cpu_dest - cpu_src; + set_of_sub(bits); + } + do_af(); + set_pzs(bits); + wait(2, 0); + access(19, bits); + set_ea(cpu_data); + break; + case 0x10: /* CALL rm */ + cpu_data_opff_rm(); + access(63, bits); + wait(1, 0); + pfq_clear(); + wait(4, 0); + if (cpu_mod != 3) + wait(1, 0); + wait(1, 0); /* Wait. */ + cpu_state.oldpc = cpu_state.pc; + set_ip(cpu_data); + wait(2, 0); + access(35, bits); + push((uint16_t *) &(cpu_state.oldpc)); + break; + case 0x18: /* CALL rmd */ + new_ip = cpu_data; + access(58, bits); + read_ea2(bits); + if (!(opcode & 1)) + cpu_data |= 0xff00; + new_cs = cpu_data; + access(36, bits); + push(&(CS)); + access(64, bits); + wait(4, 0); + cpu_state.oldpc = cpu_state.pc; + load_cs(new_cs); + set_ip(new_ip); + access(37, bits); + push((uint16_t *) &(cpu_state.oldpc)); + break; + case 0x20: /* JMP rm */ + cpu_data_opff_rm(); + access(65, bits); + set_ip(cpu_data); + break; + case 0x28: /* JMP rmd */ + new_ip = cpu_data; + access(59, bits); + read_ea2(bits); + if (!(opcode & 1)) + cpu_data |= 0xff00; + new_cs = cpu_data; + load_cs(new_cs); + access(66, bits); + set_ip(new_ip); + break; + case 0x30: /* PUSH rm */ + case 0x38: + if (cpu_mod != 3) + wait(1, 0); + access(38, bits); + push((uint16_t *) &(cpu_data)); + break; + } + break; + + default: + x808x_log("Illegal opcode: %02X\n", opcode); + pfq_fetchb(); + wait(8, 0); + break; + } } if (completed) { - repeating = 0; - ovr_seg = NULL; - in_rep = 0; + repeating = 0; + ovr_seg = NULL; + in_rep = 0; + rep_c_flag = 0; if (in_lock) clear_lock = 1; clock_end(); diff --git a/src/cpu/CMakeLists.txt b/src/cpu/CMakeLists.txt index 20452bf88..c91bcbe78 100644 --- a/src/cpu/CMakeLists.txt +++ b/src/cpu/CMakeLists.txt @@ -14,7 +14,7 @@ # add_library(cpu OBJECT cpu.c cpu_table.c fpu.c x86.c 808x.c 386.c 386_common.c - 386_dynarec.c x86seg.c x87.c x87_timings.c) + 386_dynarec.c x86seg.c x87.c x87_timings.c 8080.c) if(AMD_K5) target_compile_definitions(cpu PRIVATE USE_AMD_K5) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 7a35e2589..f806f3805 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -13,10 +13,10 @@ * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. + * Copyright 2008-2020 Sarah Walker. * Copyright 2016-2018 leilei. - * Copyright 2016-2018 Miran Grca. - * Copyright 2018 Fred N. van Kempen. + * Copyright 2016-2020 Miran Grca. + * Copyright 2018-2021 Fred N. van Kempen. */ #include #include @@ -112,6 +112,7 @@ int isa_cycles, cpu_inited, cpu_override, cpu_effective, cpu_multi, cpu_16bitbus, cpu_64bitbus, cpu_busspeed, cpu_cyrix_alignment, CPUID, + is186, is_nec, is286, is386, is6117, is486 = 1, cpu_isintel, cpu_iscyrix, hascache, isibm486, israpidcad, is_vpc, is_am486, is_am486dxl, is_pentium, is_k5, is_k6, is_p6, is_cxsmm, hasfpu, @@ -356,7 +357,9 @@ cpu_set(void) unmask_a20_in_smm = 0; CPUID = cpu_s->cpuid_model; - is8086 = (cpu_s->cpu_type > CPU_8088); + is8086 = (cpu_s->cpu_type > CPU_8088) && !(cpu_s->cpu_type == CPU_V20); + is_nec = (cpu_s->cpu_type == CPU_V20) || (cpu_s->cpu_type == CPU_V30); + is186 = (cpu_s->cpu_type == CPU_186) || (cpu_s->cpu_type == CPU_188) || (cpu_s->cpu_type == CPU_V20) || (cpu_s->cpu_type == CPU_V30); is286 = (cpu_s->cpu_type >= CPU_286); is386 = (cpu_s->cpu_type >= CPU_386SX); israpidcad = (cpu_s->cpu_type == CPU_RAPIDCAD); @@ -514,6 +517,17 @@ cpu_set(void) case CPU_8086: break; + case CPU_V20: + case CPU_V30: + case CPU_186: + case CPU_188: +#ifdef USE_DYNAREC + x86_setopcodes(ops_186, ops_186_0f, dynarec_ops_186, dynarec_ops_186_0f); +#else + x86_setopcodes(ops_186, ops_186_0f); +#endif + break; + case CPU_286: #ifdef USE_DYNAREC x86_setopcodes(ops_286, ops_286_0f, dynarec_ops_286, dynarec_ops_286_0f); diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 04b379127..b8e10661c 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -14,9 +14,9 @@ * leilei, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. + * Copyright 2008-2020 Sarah Walker. * Copyright 2016-2018 leilei. - * Copyright 2016,2018 Miran Grca. + * Copyright 2016-2020 Miran Grca. */ #ifndef EMU_CPU_H #define EMU_CPU_H @@ -24,6 +24,7 @@ enum { FPU_NONE, FPU_8087, + FPU_80187, FPU_287, FPU_287XL, FPU_387, @@ -34,10 +35,10 @@ enum { enum { CPU_8088 = 1, /* 808x class CPUs */ CPU_8086, -#ifdef USE_NEC_808X - CPU_V20, /* NEC 808x class CPUs - future proofing */ + CPU_V20, /* NEC 808x class CPUs */ CPU_V30, -#endif + CPU_188, /* 18x class CPUs */ + CPU_186, CPU_286, /* 286 class CPUs */ CPU_386SX, /* 386 class CPUs */ CPU_IBM386SLC, @@ -86,26 +87,30 @@ enum { CPU_PKG_8088 = (1 << 0), CPU_PKG_8088_EUROPC = (1 << 1), CPU_PKG_8086 = (1 << 2), - CPU_PKG_286 = (1 << 3), - CPU_PKG_386SX = (1 << 4), - CPU_PKG_386DX = (1 << 5), - CPU_PKG_M6117 = (1 << 6), - CPU_PKG_386SLC_IBM = (1 << 7), - CPU_PKG_486SLC = (1 << 8), - CPU_PKG_486SLC_IBM = (1 << 9), - CPU_PKG_486BL = (1 << 10), - CPU_PKG_486DLC = (1 << 11), - CPU_PKG_SOCKET1 = (1 << 12), - CPU_PKG_SOCKET3 = (1 << 13), - CPU_PKG_SOCKET3_PC330 = (1 << 14), - CPU_PKG_STPC = (1 << 15), - CPU_PKG_SOCKET4 = (1 << 16), - CPU_PKG_SOCKET5_7 = (1 << 17), - CPU_PKG_SOCKET8 = (1 << 18), - CPU_PKG_SLOT1 = (1 << 19), - CPU_PKG_SLOT2 = (1 << 20), - CPU_PKG_SOCKET370 = (1 << 21), - CPU_PKG_EBGA368 = (1 << 22) + CPU_PKG_188 = (1 << 3), + CPU_PKG_186 = (1 << 4), + CPU_PKG_286 = (1 << 5), + CPU_PKG_386SX = (1 << 6), + CPU_PKG_386DX = (1 << 7), + CPU_PKG_M6117 = (1 << 8), + CPU_PKG_386SLC_IBM = (1 << 9), + CPU_PKG_486SLC = (1 << 10), + CPU_PKG_486SLC_IBM = (1 << 11), + CPU_PKG_486BL = (1 << 12), + CPU_PKG_486DLC = (1 << 13), + CPU_PKG_SOCKET1 = (1 << 14), + CPU_PKG_SOCKET3 = (1 << 15), + CPU_PKG_SOCKET3_PC330 = (1 << 16), + CPU_PKG_STPC = (1 << 17), + CPU_PKG_SOCKET4 = (1 << 18), + CPU_PKG_SOCKET5_7 = (1 << 19), + CPU_PKG_SOCKET8 = (1 << 20), + CPU_PKG_SLOT1 = (1 << 21), + CPU_PKG_SLOT2 = (1 << 22), + CPU_PKG_SLOTA = (1 << 23), + CPU_PKG_SOCKET370 = (1 << 24), + CPU_PKG_SOCKETA = (1 << 25), + CPU_PKG_EBGA368 = (1 << 26) }; #define MANU_INTEL 0 @@ -113,6 +118,7 @@ enum { #define MANU_CYRIX 2 #define MANU_IDT 3 #define MANU_NEC 4 +#define MANU_IBM 5 #define CPU_SUPPORTS_DYNAREC 1 #define CPU_REQUIRES_DYNAREC 2 @@ -176,6 +182,7 @@ typedef struct { #define D_FLAG 0x0400 #define V_FLAG 0x0800 #define NT_FLAG 0x4000 +#define MD_FLAG 0x8000 #define RF_FLAG 0x0001 /* in EFLAGS */ #define VM_FLAG 0x0002 /* in EFLAGS */ @@ -386,6 +393,8 @@ typedef struct { uint16_t flags, eflags; uint32_t _smbase; + + uint8_t inside_emulation_mode; } cpu_state_t; #define in_smm cpu_state._in_smm @@ -487,10 +496,11 @@ extern double fpu_multi; extern int cpu_cyrix_alignment; /*Cyrix 5x86/6x86 only has data misalignment penalties when crossing 8-byte boundaries*/ -extern int is8086, is286, is386, is6117, is486; +extern int is8086, is186, is286, is386, is6117, is486; extern int is_am486, is_am486dxl, is_pentium, is_k5, is_k6, is_p6, is_cxsmm; extern int hascache; extern int isibm486; +extern int is_nec; extern int is_rapidcad; extern int hasfpu; #define CPU_FEATURE_RDTSC (1 << 0) @@ -500,6 +510,7 @@ extern int hasfpu; #define CPU_FEATURE_VME (1 << 4) #define CPU_FEATURE_CX8 (1 << 5) #define CPU_FEATURE_3DNOW (1 << 6) +#define CPU_FEATURE_SYSCALL (1 << 7) extern uint32_t cpu_features; @@ -721,6 +732,7 @@ extern void (*cpu_exec)(int cycs); extern uint8_t do_translate, do_translate2; extern void reset_808x(int hard); +extern void interrupt_808x(uint16_t addr); extern void cpu_register_fast_off_handler(void *timer); extern void cpu_fast_off_advance(void); diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index 96d8eafd5..97e832ed1 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -20,7 +20,7 @@ * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 leilei. * Copyright 2016-2019 Miran Grca. - * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2017-2020 Fred N. van Kempen. * Copyright 2020 RichardG. * Copyright 2021 dob205. */ @@ -43,6 +43,13 @@ FPU fpus_8088[] = {"8087", "8087", FPU_8087}, {NULL, NULL, 0} }; +FPU fpus_80186[] = +{ + {"None", "none", FPU_NONE}, + {"8087", "8087", FPU_8087}, + {"80187", "80187", FPU_80187}, + {NULL, NULL, 0} +}; FPU fpus_80286[] = { {"None", "none", FPU_NONE}, @@ -79,6 +86,7 @@ const cpu_family_t cpu_families[] = { {"4.77", CPU_8088, fpus_8088, 4772728, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, {"7.16", CPU_8088, fpus_8088, 7159092, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, {"8", CPU_8088, fpus_8088, 8000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, +// {"9.54", CPU_8088, fpus_8088, 9545456, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, {"10", CPU_8088, fpus_8088, 10000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, {"12", CPU_8088, fpus_8088, 12000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, {"16", CPU_8088, fpus_8088, 16000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, @@ -109,6 +117,66 @@ const cpu_family_t cpu_families[] = { {"16", CPU_8086, fpus_8088, 16000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 2}, {"", 0} } + }, { + .package = CPU_PKG_188, + .manufacturer = "Intel", + .name = "80188", + .internal_name = "80188", + .cpus = (const CPU[]) { + {"6", CPU_188, fpus_8088, 6000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"7.16", CPU_188, fpus_8088, 7159092, 1, 5000, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"8", CPU_188, fpus_8088, 8000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"9.54", CPU_188, fpus_8088, 9545456, 1, 5000, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"10", CPU_188, fpus_8088, 10000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"12", CPU_188, fpus_8088, 12000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"16", CPU_188, fpus_8088, 16000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 2}, + {"20", CPU_188, fpus_8088, 20000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 3}, + {"25", CPU_188, fpus_8088, 25000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 3}, + {"", 0} + } + }, { + .package = CPU_PKG_8088, + .manufacturer = "NEC", + .name = "V20", + .internal_name = "necv20", + .cpus = (const CPU[]) { + {"5", CPU_V20, fpus_8088, 5000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8", CPU_V20, fpus_8088, 8000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"10", CPU_V20, fpus_8088, 10000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"12", CPU_V20, fpus_8088, 12000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"16", CPU_V20, fpus_8088, 16000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 2}, + {"", 0} + } + }, { + .package = CPU_PKG_186, + .manufacturer = "Intel", + .name = "80186", + .internal_name = "80186", + .cpus = (const CPU[]) { + {"6", CPU_186, fpus_80186, 6000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"7.16", CPU_186, fpus_80186, 7159092, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"8", CPU_186, fpus_80186, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"9.54", CPU_186, fpus_80186, 9545456, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"10", CPU_186, fpus_80186, 10000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"12", CPU_186, fpus_80186, 12000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"16", CPU_186, fpus_80186, 16000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 2}, + {"20", CPU_186, fpus_80186, 20000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 3}, + {"25", CPU_186, fpus_80186, 25000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 3}, + {"", 0} + } + }, { + .package = CPU_PKG_186, + .manufacturer = "NEC", + .name = "V30", + .internal_name = "necv30", + .cpus = (const CPU[]) { + {"5", CPU_V30, fpus_80186, 5000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8", CPU_V30, fpus_80186, 8000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"10", CPU_V30, fpus_80186, 10000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"12", CPU_V30, fpus_80186, 12000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"16", CPU_V30, fpus_80186, 16000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 2}, + {"", 0} + } }, { .package = CPU_PKG_286, .manufacturer = "Intel", diff --git a/src/cpu/x86_ops.h b/src/cpu/x86_ops.h index 2c8812570..6afac81f2 100644 --- a/src/cpu/x86_ops.h +++ b/src/cpu/x86_ops.h @@ -72,6 +72,9 @@ extern const OpFn *x86_dynarec_opcodes_REPE; extern const OpFn *x86_dynarec_opcodes_REPNE; extern const OpFn *x86_dynarec_opcodes_3DNOW; +extern const OpFn dynarec_ops_186[1024]; +extern const OpFn dynarec_ops_186_0f[1024]; + extern const OpFn dynarec_ops_286[1024]; extern const OpFn dynarec_ops_286_0f[1024]; @@ -171,6 +174,9 @@ extern const OpFn *x86_opcodes_REPE; extern const OpFn *x86_opcodes_REPNE; extern const OpFn *x86_opcodes_3DNOW; +extern const OpFn ops_186[1024]; +extern const OpFn ops_186_0f[1024]; + extern const OpFn ops_286[1024]; extern const OpFn ops_286_0f[1024]; diff --git a/src/cpu/x86_ops_flag.h b/src/cpu/x86_ops_flag.h index ce0cb4cd6..3da048dd5 100644 --- a/src/cpu/x86_ops_flag.h +++ b/src/cpu/x86_ops_flag.h @@ -163,6 +163,33 @@ static int opPUSHFD(uint32_t fetchdat) return cpu_state.abrt; } +static int opPOPF_186(uint32_t fetchdat) +{ + uint16_t tempw; + + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 1; + } + + tempw = POP_W(); if (cpu_state.abrt) return 1; + + if (!(msw & 1)) cpu_state.flags = (cpu_state.flags & 0x7000) | (tempw & 0x0fd5) | 2; + else if (!(CPL)) cpu_state.flags = (tempw & 0x7fd5) | 2; + else if (IOPLp) cpu_state.flags = (cpu_state.flags & 0x3000) | (tempw & 0x4fd5) | 2; + else cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2; + flags_extract(); + + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); + +#if (defined(USE_DYNAREC) && defined(USE_NEW_DYNAREC)) + codegen_flags_changed = 0; +#endif + + return 0; +} static int opPOPF_286(uint32_t fetchdat) { uint16_t tempw; diff --git a/src/cpu/x86_ops_ret.h b/src/cpu/x86_ops_ret.h index 222eb5243..693fb0393 100644 --- a/src/cpu/x86_ops_ret.h +++ b/src/cpu/x86_ops_ret.h @@ -96,6 +96,51 @@ static int opRETF_a32_imm(uint32_t fetchdat) return 0; } +static int opIRET_186(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + if (msw&1) + { + optype = IRET; + pmodeiret(0); + optype = 0; + } + else + { + uint16_t new_cs; + CPU_SET_OXPC + if (stack32) + { + cpu_state.pc = readmemw(ss, ESP); + new_cs = readmemw(ss, ESP + 2); + cpu_state.flags = (cpu_state.flags & 0x7000) | (readmemw(ss, ESP + 4) & 0xffd5) | 2; + ESP += 6; + } + else + { + cpu_state.pc = readmemw(ss, SP); + new_cs = readmemw(ss, ((SP + 2) & 0xffff)); + cpu_state.flags = (cpu_state.flags & 0x7000) | (readmemw(ss, ((SP + 4) & 0xffff)) & 0x0fd5) | 2; + SP += 6; + } + loadcs(new_cs); + cycles -= timing_iret_rm; + } + flags_extract(); + nmi_enable = 1; + CPU_BLOCK_END(); + + PREFETCH_RUN(cycles_old-cycles, 1, -1, 2,0,0,0, 0); + PREFETCH_FLUSH(); + return cpu_state.abrt; +} + static int opIRET_286(uint32_t fetchdat) { int cycles_old = cycles; UN_USED(cycles_old); diff --git a/src/cpu/x87_timings.c b/src/cpu/x87_timings.c index d769affaf..70ec4b95e 100644 --- a/src/cpu/x87_timings.c +++ b/src/cpu/x87_timings.c @@ -85,6 +85,82 @@ const x87_timings_t x87_timings_8087 = { .fyl2xp1 = (700 + 1000) / 2 }; +const x87_timings_t x87_timings_80187 = +{ + .f2xm1 = (310 + 630) / 2, + .fabs = (10 + 17) / 2, + .fadd = (70 + 100) / 2, + .fadd_32 = (90 + 120) / 2, + .fadd_64 = (95 + 125) / 2, + .fbld = (290 + 310) / 2, + .fbstp = (520 + 540) / 2, + .fchs = (10 + 17) / 2, + .fclex = (2 + 8) / 2, + .fcom = (40 + 50) / 2, + .fcom_32 = (60 + 70) / 2, + .fcom_64 = (65 + 75) / 2, + .fcos = 0, /*387+*/ + .fincdecstp = (6 + 12) / 2, + .fdisi_eni = (6 + 12) / 2, + .fdiv = (193 + 203) / 2, + .fdiv_32 = (215 + 225) / 2, + .fdiv_64 = (220 + 230) / 2, + .ffree = (9 + 16) / 2, + .fadd_i16 = (102 + 137) / 2, + .fadd_i32 = (108 + 143) / 2, + .fcom_i16 = (72 + 86) / 2, + .fcom_i32 = (78 + 91) / 2, + .fdiv_i16 = (224 + 238) / 2, + .fdiv_i32 = (230 + 243) / 2, + .fild_16 = (46 + 54) / 2, + .fild_32 = (50 + 60) / 2, + .fild_64 = (60 + 68) / 2, + .fmul_i16 = (124 + 138) / 2, + .fmul_i32 = (130 + 144) / 2, + .finit = (2 + 8) / 2, + .fist_16 = (80 + 90) / 2, + .fist_32 = (82 + 92) / 2, + .fist_64 = (94 + 105) / 2, + .fld = (17 + 22) / 2, + .fld_32 = (38 + 56) / 2, + .fld_64 = (40 + 60) / 2, + .fld_80 = (53 + 65) / 2, + .fld_z1 = (11 + 21) / 2, + .fld_const = (15 + 24) / 2, + .fldcw = (7 + 14) / 2, + .fldenv = (35 + 45) / 2, + .fmul = (90 + 145) / 2, + .fmul_32 = (110 + 125) / 2, + .fmul_64 = (154 + 168) / 2, + .fnop = (10 + 16) / 2, + .fpatan = (250 + 800) / 2, + .fprem = (15 + 190) / 2, + .fprem1 = 0, /*387+*/ + .fptan = (30 + 540) / 2, + .frndint = (16 + 50) / 2, + .frstor = (197 + 207) / 2, + .fsave = (197 + 207) / 2, + .fscale = (32 + 38) / 2, + .fsetpm = 0, /*287+*/ + .fsin_cos = 0, /*387+*/ + .fsincos = 0, /*387+*/ + .fsqrt = (180 + 186) / 2, + .fst = (15 + 22) / 2, + .fst_32 = (84 + 90) / 2, + .fst_64 = (96 + 104) / 2, + .fst_80 = (52 + 58) / 2, + .fstcw_sw = (12 + 18) / 2, + .fstenv = (40 + 50) / 2, + .ftst = (38 + 48) / 2, + .fucom = 0, /*387+*/ + .fwait = 4, + .fxam = (12 + 23) / 2, + .fxch = (10 + 15) / 2, + .fxtract = (27 + 55) / 2, + .fyl2x = (900 + 1100) / 2, + .fyl2xp1 = (700 + 1000) / 2 +}; + /*Mostly the same as 8087*/ const x87_timings_t x87_timings_287 = { .f2xm1 = (310 + 630) / 2, diff --git a/src/cpu/x87_timings.h b/src/cpu/x87_timings.h index ad16231db..7389ddeb6 100644 --- a/src/cpu/x87_timings.h +++ b/src/cpu/x87_timings.h @@ -49,6 +49,7 @@ typedef struct } x87_timings_t; extern const x87_timings_t x87_timings_8087; +extern const x87_timings_t x87_timings_80187; extern const x87_timings_t x87_timings_287; extern const x87_timings_t x87_timings_387; extern const x87_timings_t x87_timings_486; diff --git a/src/include/86box/i8080.h b/src/include/86box/i8080.h new file mode 100644 index 000000000..05d227da8 --- /dev/null +++ b/src/include/86box/i8080.h @@ -0,0 +1,56 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * 8080 CPU emulation (header). + * + * Authors: Cacodemon345 + * + * Copyright 2022 Cacodemon345 + */ + +#include + +typedef struct i8080 +{ + union { + uint16_t af; /* Intended in case we also go for μPD9002 emulation, which also has a Z80 emulation mode. */ + struct { uint8_t a, flags; }; + }; + union + { + uint16_t bc; + struct { uint8_t b, c; }; + }; + union + { + uint16_t de; + struct { uint8_t d, e; }; + }; + union + { + uint16_t hl; + struct { uint8_t h, l; }; + }; + uint16_t pc, sp; + uint16_t oldpc, ei; + uint32_t pmembase, dmembase; /* Base from where i8080 starts. */ + uint8_t emulated; /* 0 = not emulated, use separate registers, 1 = emulated, use x86 registers. */ + uint16_t* cpu_flags; + void (*writemembyte)(uint32_t, uint8_t); + uint8_t (*readmembyte)(uint32_t); + void (*startclock)(); + void (*endclock)(); + void (*checkinterrupts)(); + uint8_t (*fetchinstruction)(); +} i8080; + +#define C_FLAG_I8080 (1 << 0) +#define P_FLAG_I8080 (1 << 2) +#define AC_FLAG_I8080 (1 << 4) +#define Z_FLAG_I8080 (1 << 6) +#define S_FLAG_I8080 (1 << 7)