diff --git a/src/86box.c b/src/86box.c index b1176bb69..19465a17f 100644 --- a/src/86box.c +++ b/src/86box.c @@ -761,7 +761,7 @@ void pc_full_speed(void) { if (!atfullspeed) { - pc_log("Set fullspeed - %i %i\n", is386, AT); + pc_log("Set fullspeed - %i %i\n", is386, is486); pc_speed_changed(); } atfullspeed = 1; @@ -962,6 +962,8 @@ pc_reset_hard_close(void) video_reset_close(); cpu_close(); + + serial_set_next_inst(0); } /* diff --git a/src/chipset/sis_85c4xx.c b/src/chipset/sis_85c4xx.c index ba830ef0a..9b67c4466 100644 --- a/src/chipset/sis_85c4xx.c +++ b/src/chipset/sis_85c4xx.c @@ -38,12 +38,25 @@ typedef struct uint8_t cur_reg, tries, reg_base, reg_last, reg_00, is_471, + force_flush, shadowed, + smram_enabled, pad, regs[39], scratch[2]; uint32_t mem_state[8]; smram_t *smram; port_92_t *port_92; } sis_85c4xx_t; +static void +sis_85c4xx_recalcremap(sis_85c4xx_t *dev) +{ + if (dev->is_471) { + if ((mem_size > 8192) || (dev->shadowed & 0x3c) || (dev->regs[0x0b] & 0x02)) + mem_remap_top(0); + else + mem_remap_top(-256); + } +} + static void sis_85c4xx_recalcmapping(sis_85c4xx_t *dev) { @@ -52,6 +65,8 @@ sis_85c4xx_recalcmapping(sis_85c4xx_t *dev) uint32_t readext, writeext; uint8_t romcs = 0xc0, cur_romcs; + dev->shadowed = 0x00; + shadowbios = 0; shadowbios_write = 0; @@ -73,25 +88,34 @@ sis_85c4xx_recalcmapping(sis_85c4xx_t *dev) shadowbios_write |= (base >= 0xe0000) && !(dev->regs[0x02] & 0x40); shflags = (dev->regs[0x02] & 0x80) ? MEM_READ_INTERNAL : readext; shflags |= (dev->regs[0x02] & 0x40) ? writeext : MEM_WRITE_INTERNAL; - if (dev->mem_state[i] != shflags) { + if (dev->regs[0x02] & 0x80) + dev->shadowed |= (1 << i); + if (!(dev->regs[0x02] & 0x40)) + dev->shadowed |= (1 << i); + if (dev->force_flush || (dev->mem_state[i] != shflags)) { n++; - mem_set_mem_state(base, 0x8000, shflags); + mem_set_mem_state_both(base, 0x8000, shflags); if ((base >= 0xf0000) && (dev->mem_state[i] & MEM_READ_INTERNAL) && !(shflags & MEM_READ_INTERNAL)) mem_invalidate_range(base, base + 0x7fff); dev->mem_state[i] = shflags; } } else { shflags = readext | writeext; - if (dev->mem_state[i] != shflags) { + if (dev->force_flush || (dev->mem_state[i] != shflags)) { n++; - mem_set_mem_state(base, 0x8000, shflags); + mem_set_mem_state_both(base, 0x8000, shflags); dev->mem_state[i] = shflags; } } } - if (n > 0) + if (dev->force_flush) { + flushmmucache(); + dev->force_flush = 0; + } else if (n > 0) flushmmucache_nopc(); + + sis_85c4xx_recalcremap(dev); } static void @@ -158,12 +182,8 @@ sis_85c4xx_out(uint16_t port, uint8_t val, void *priv) case 0x0b: sis_85c4xx_sw_smi_handler(dev); - if (dev->is_471 && (valxor & 0x02)) { - if (val & 0x02) - mem_remap_top(0); - else - mem_remap_top(256); - } + if (valxor & 0x02) + sis_85c4xx_recalcremap(dev); break; case 0x13: @@ -184,8 +204,10 @@ sis_85c4xx_out(uint16_t port, uint8_t val, void *priv) ram_base = 0x00000000; break; } + dev->smram_enabled = (ram_base != 0x00000000); if (ram_base != 0x00000000) smram_enable(dev->smram, host_base, ram_base, 0x00010000, (val & 0x10), 1); + sis_85c4xx_recalcremap(dev); } break; @@ -289,7 +311,6 @@ sis_85c4xx_reset(void *priv) port_92_remove(dev->port_92); - mem_remap_top(256); soft_reset_mask = 0; } else { /* Bits 6 and 7 must be clear on the SiS 40x. */ @@ -309,6 +330,7 @@ sis_85c4xx_reset(void *priv) cpu_cache_ext_enabled = 0; cpu_update_waitstates(); + dev->force_flush = 1; sis_85c4xx_recalcmapping(dev); } 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..c427919bc --- /dev/null +++ b/src/cpu/8080.c @@ -0,0 +1,225 @@ +/* + * 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 completed = 1; +static int in_rep = 0, repeating = 0, rep_c_flag = 0; +static int oldc, cycdiff; +#ifdef UNUSED_8080_VARS +static int prefetching = 1; +static int refresh = 0, clear_lock = 0; + +static uint32_t cpu_src = 0, cpu_dest = 0; +static uint32_t cpu_data = 0; +#endif + +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 +i8080_wait(int c, int bus) +{ + cycles -= c; + if (bus < 2) { + clock_end(); + clock_start(); + } +} + +#ifdef UNUSED_8080_FUNCS +static uint8_t +readmemb(uint32_t a) +{ + uint8_t ret; + + i8080_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; +} +#endif + +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) +{ +#ifdef UNUSED_8080_VARS + uint8_t temp = 0, temp2; + uint8_t old_af; + uint8_t handled = 0; + uint16_t addr, tempw; + uint16_t new_ip; + int bits; +#endif + + cycles += cycs; + + while (cycles > 0) { + cpu->startclock(); + + if (!repeating) { + cpu->oldpc = cpu->pc; + opcode = cpu->fetchinstruction(cpu); + oldc = cpu->flags & C_FLAG_I8080; + i8080_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..eed504196 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,15 +1617,46 @@ 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; - uint16_t addr, tempw; - uint16_t new_cs, new_ip; + uint8_t temp = 0, temp2, old_af, nests; + uint8_t temp_val, temp_al, bit, handled = 0; + uint8_t odd, zero, nibbles_count, destcmp; + uint8_t destbyte, srcbyte, nibble_result, bit_length; + uint8_t bit_offset; + int8_t nibble_result_s; + uint16_t addr, tempw, new_cs, new_ip; + uint16_t tempw_int, size, tempbp, lowbound; + uint16_t highbound, regval; int bits; + uint32_t dest_seg, i, carry, nibble; + uint32_t srcseg, byteaddr; cycles += cycs; @@ -1634,1258 +1676,1817 @@ 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); - 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 (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 */ + dest_seg = ovr_seg ? *ovr_seg : ds; + bits = 8 << (opcode & 1); + handled = 1; + if (!repeating) + wait(2, 0); + + 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 */ + tempw_int = 0; + size = pfq_fetchw(); + nests = pfq_fetchb(); + i = 0; + + push(&BP); + tempw_int = SP; + if (nests > 0) { + while (--nests) { + tempbp = 0; + BP -= 2; + tempbp = readmemw(ss, BP); + push(&tempbp); + } + push(&tempw_int); + } + BP = tempw_int; + SP -= size; + handled = 1; + break; + + case 0xc9: /* LEAVE/DISPOSE */ + SP = BP; + BP = pop(); + handled = 1; + break; + + case 0x62: /* BOUND r/m */ + lowbound = 0; + highbound = 0; + 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); + + temp_val = geteab(); + 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); + + temp_val = geteab(); + 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); + + 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); + + 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); + + 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); + + 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 */ + odd = !!(CL % 2); + zero = 1; + nibbles_count = CL - odd; + i = 0; + carry = 0; + nibble = 0; + srcseg = ovr_seg ? *ovr_seg : ds; + + wait(5, 0); + for (i = 0; i < ((nibbles_count / 2) + odd); i++) { + wait(19, 0); + destcmp = read_mem_b((es) + DI + i); + for (nibble = 0; nibble < 2; nibble++) { + destbyte = destcmp >> (nibble ? 4 : 0); + srcbyte = read_mem_b(srcseg + SI + i) >> (nibble ? 4 : 0); + destbyte &= 0xF; + srcbyte &= 0xF; + 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 */ + odd = !!(CL % 2); + zero = 1; + nibbles_count = CL - odd; + i = 0; + carry = 0; + nibble = 0; + srcseg = ovr_seg ? *ovr_seg : ds; + + wait(5, 0); + for (i = 0; i < ((nibbles_count / 2) + odd); i++) { + wait(19, 0); + destcmp = read_mem_b((es) + DI + i); + for (nibble = 0; nibble < 2; nibble++) { + destbyte = destcmp >> (nibble ? 4 : 0); + srcbyte = read_mem_b(srcseg + SI + i) >> (nibble ? 4 : 0); + destbyte &= 0xF; + srcbyte &= 0xF; + nibble_result_s = (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_s < 0) { + nibble_result_s += 10; + carry++; + } + if (zero != 0 || (i == (nibbles_count / 2) && nibble == 1)) + zero = (nibble_result_s == 0); + destcmp = ((destcmp & (nibble ? 0x0F : 0xF0)) | (nibble_result_s << (4 * nibble))); + } + write_mem_b(es + DI + i, destcmp); + } + set_cf(!!carry); + set_zf(!!zero); + handled = 1; + break; + + case 0x26: /* CMP4S */ + odd = !!(CL % 2); + zero = 1; + nibbles_count = CL - odd; + i = 0; + carry = 0; + nibble = 0; + srcseg = ovr_seg ? *ovr_seg : ds; + + wait(5, 0); + for (i = 0; i < ((nibbles_count / 2) + odd); i++) { + wait(19, 0); + destcmp = read_mem_b((es) + DI + i); + for (nibble = 0; nibble < 2; nibble++) { + destbyte = destcmp >> (nibble ? 4 : 0); + srcbyte = read_mem_b(srcseg + SI + i) >> (nibble ? 4 : 0); + destbyte &= 0xF; + srcbyte &= 0xF; + nibble_result_s = ((int8_t) (destbyte)) - ((int8_t) (srcbyte)) - ((int8_t) carry); + carry = 0; + while (nibble_result_s < 0) { + nibble_result_s += 10; + carry++; + } + if (zero != 0 || (i == (nibbles_count / 2) && nibble == 1)) + zero = (nibble_result_s == 0); + destcmp = ((destcmp & (nibble ? 0x0F : 0xF0)) | (nibble_result_s << (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); + + bit_length = ((opcode & 0x8) ? (pfq_fetchb() & 0xF) : (getr8(cpu_reg) & 0xF)) + 1; + bit_offset = getr8(cpu_rm) & 0xF; + byteaddr = (es) + DI; + 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); + + bit_length = ((opcode & 0x8) ? (pfq_fetchb() & 0xF) : (getr8(cpu_reg) & 0xF)) + 1; + bit_offset = getr8(cpu_rm) & 0xF; + byteaddr = (ds) + SI; + 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*/ + wait(9, 0); + DI = pop(); + SI = pop(); + BP = pop(); + (void) pop(); /* former orig_sp */ + 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 a3c0e20bc..ea891649b 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 def3962eb..f22024f81 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 */ @@ -392,6 +399,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 @@ -493,10 +502,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) @@ -506,6 +516,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; @@ -727,6 +738,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/device/keyboard_xt.c b/src/device/keyboard_xt.c index d3db6a467..69720d9b1 100644 --- a/src/device/keyboard_xt.c +++ b/src/device/keyboard_xt.c @@ -65,6 +65,7 @@ #define KBD_TYPE_VTECH 7 #define KBD_TYPE_OLIVETTI 8 #define KBD_TYPE_ZENITH 9 +#define KBD_TYPE_PRAVETZ 10 typedef struct { int want_irq; @@ -73,7 +74,7 @@ typedef struct { uint8_t pa, pb, pd; uint8_t key_waiting; - uint8_t type; + uint8_t type, pravetz_flags; pc_timer_t send_delay_timer; } xtkbd_t; @@ -513,6 +514,7 @@ static void kbd_write(uint16_t port, uint8_t val, void *priv) { xtkbd_t *kbd = (xtkbd_t *) priv; + uint8_t bit, set; switch (port) { case 0x61: /* Keyboard Control Register (aka Port B) */ @@ -527,7 +529,8 @@ kbd_write(uint16_t port, uint8_t val, void *priv) timer_process(); - if (((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82)) && (cassette != NULL)) + if (((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_PRAVETZ)) && + (cassette != NULL)) pc_cas_set_motor(cassette, (kbd->pb & 0x08) == 0); speaker_update(); @@ -546,16 +549,25 @@ kbd_write(uint16_t port, uint8_t val, void *priv) } #ifdef ENABLE_KEYBOARD_XT_LOG - if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82)) + if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_PRAVETZ)) kbd_log("Cassette motor is %s\n", !(val & 0x08) ? "ON" : "OFF"); #endif break; #ifdef ENABLE_KEYBOARD_XT_LOG case 0x62: /* Switch Register (aka Port C) */ - if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82)) + if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_PRAVETZ)) kbd_log("Cassette IN is %i\n", !!(val & 0x10)); break; #endif + + case 0xc0 ... 0xcf: /* Pravetz Flags */ + kbd_log("Port %02X out: %02X\n", port, val); + if (kbd->type == KBD_TYPE_PRAVETZ) { + bit = (port >> 1) & 0x07; + set = (port & 0x01) << bit; + kbd->pravetz_flags = (kbd->pravetz_flags & ~(1 << bit)) | set; + } + break; } } @@ -567,8 +579,8 @@ kbd_read(uint16_t port, void *priv) switch (port) { case 0x60: /* Keyboard Data Register (aka Port A) */ - if ((kbd->pb & 0x80) && ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86) || (kbd->type == KBD_TYPE_ZENITH))) { - if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82)) + if ((kbd->pb & 0x80) && ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_PRAVETZ) || (kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86) || (kbd->type == KBD_TYPE_ZENITH))) { + if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_PRAVETZ)) ret = (kbd->pd & ~0x02) | (hasfpu ? 0x02 : 0x00); else if ((kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86)) ret = 0xff; /* According to Ruud on the PCem forum, this is supposed to return 0xFF on the XT. */ @@ -600,7 +612,7 @@ kbd_read(uint16_t port, void *priv) break; case 0x62: /* Switch Register (aka Port C) */ - if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82)) { + if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_PRAVETZ)) { if (kbd->pb & 0x04) /* PB2 */ switch (mem_size + isa_mem_size) { case 64: @@ -640,7 +652,7 @@ kbd_read(uint16_t port, void *priv) /* This is needed to avoid error 131 (cassette error). This is serial read: bit 5 = clock, bit 4 = data, cassette header is 256 x 0xff. */ - if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82)) { + if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_PRAVETZ)) { if (cassette == NULL) ret |= (ppispeakon ? 0x10 : 0); else @@ -657,6 +669,12 @@ kbd_read(uint16_t port, void *priv) || (kbd->type == KBD_TYPE_TOSHIBA)) ret = kbd->pd; break; + + case 0xc0: /* Pravetz Flags */ + if (kbd->type == KBD_TYPE_PRAVETZ) + ret = kbd->pravetz_flags; + kbd_log("Port %02X in : %02X\n", port, ret); + break; } return (ret); @@ -671,6 +689,7 @@ kbd_reset(void *priv) kbd->blocked = 0; kbd->pa = 0x00; kbd->pb = 0x00; + kbd->pravetz_flags = 0x00; keyboard_scan = 1; @@ -697,16 +716,19 @@ kbd_init(const device_t *info) keyboard_send = kbd_adddata_ex; kbd_reset(kbd); kbd->type = info->local; + if (kbd->type == KBD_TYPE_PRAVETZ) { + io_sethandler(0x00c0, 16, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); + } key_queue_start = key_queue_end = 0; video_reset(gfxcard); - if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) - || (kbd->type == KBD_TYPE_XT82) || (kbd->type <= KBD_TYPE_XT86) - || (kbd->type == KBD_TYPE_COMPAQ) - || (kbd->type == KBD_TYPE_TOSHIBA) - || (kbd->type == KBD_TYPE_OLIVETTI)) { + if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) || + (kbd->type == KBD_TYPE_PRAVETZ) || (kbd->type == KBD_TYPE_XT82) || + (kbd->type <= KBD_TYPE_XT86) || (kbd->type == KBD_TYPE_COMPAQ) || + (kbd->type == KBD_TYPE_TOSHIBA) || (kbd->type == KBD_TYPE_OLIVETTI)) { /* DIP switch readout: bit set = OFF, clear = ON. */ if (kbd->type == KBD_TYPE_OLIVETTI) @@ -894,6 +916,20 @@ const device_t keyboard_pc82_device = { .config = NULL }; +const device_t keyboard_pravetz_device = { + .name = "Pravetz Keyboard", + .internal_name = "keyboard_pravetz", + .flags = 0, + .local = KBD_TYPE_PRAVETZ, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t keyboard_xt_device = { .name = "XT (1982) Keyboard", .internal_name = "keyboard_xt", diff --git a/src/device/mouse.c b/src/device/mouse.c index 88a068e07..7e14129bb 100644 --- a/src/device/mouse.c +++ b/src/device/mouse.c @@ -167,14 +167,9 @@ mouse_set_buttons(int buttons) void mouse_process(void) { - static int poll_delay = 2; - if (mouse_curr == NULL) return; - if (--poll_delay) - return; - mouse_poll(); if ((mouse_dev_poll != NULL) || (mouse_curr->poll != NULL)) { @@ -186,8 +181,6 @@ mouse_process(void) /* Reset mouse deltas. */ mouse_x = mouse_y = mouse_z = 0; } - - poll_delay = 2; } void diff --git a/src/disk/hdc.c b/src/disk/hdc.c index 0f2bc8599..1df1cd39b 100644 --- a/src/disk/hdc.c +++ b/src/disk/hdc.c @@ -115,6 +115,7 @@ static const struct { { &st506_xt_wd1002a_27x_device }, { &st506_xt_wd1004_27x_device }, { &st506_xt_wd1004a_27x_device }, + { &st506_xt_victor_v86p_device }, { &esdi_at_wd1007vse1_device }, { &ide_isa_device }, { &ide_isa_2ch_device }, diff --git a/src/disk/hdc_st506_xt.c b/src/disk/hdc_st506_xt.c index cedeb1220..ddf137f9c 100644 --- a/src/disk/hdc_st506_xt.c +++ b/src/disk/hdc_st506_xt.c @@ -99,6 +99,7 @@ #define WD1002A_27X_BIOS_FILE "roms/hdd/st506/wd1002a_27x-62-000094-032.bin" #define WD1004_27X_BIOS_FILE "roms/hdd/st506/western_digital_WD1004A-27X.bin" #define WD1004A_27X_BIOS_FILE "roms/hdd/st506/western_digital_WD1004A-27X.bin" +#define VICTOR_V86P_BIOS_FILE "roms/machines/v86p/2793VG.10010688.rom" #define ST506_TIME (250 * TIMER_USEC) #define ST506_TIME_MS (1000 * TIMER_USEC) @@ -182,6 +183,7 @@ #define CMD_WRITE_BUFFER 0x0f #define CMD_ALT_TRACK 0x11 #define CMD_INQUIRY_ST11 0x12 /* ST-11 BIOS */ +#define CMD_V86P_POWEROFF 0x1a /* Victor V86P */ #define CMD_RAM_DIAGNOSTIC 0xe0 /* reserved 0xe1 */ /* reserved 0xe2 */ @@ -819,6 +821,29 @@ st506_callback(void *priv) /* For a 615/4/26 we get 666/2/31 geometry. */ st506_xt_log("ST506: drive%i: cyls=%i, heads=%i\n", dev->drive_sel, drive->cfg_cyl, drive->cfg_hpc); + if (dev->type == 23 && drive->cfg_hpc == 2) { + /* + * On Victor V86P, there's a disagreement between + * the physical geometry, what the controller + * pretends it to be, and what the BIOS uses. + * + * The disk physically has 2/34 heads/sectors per + * track, but it is treated as 4/17 in order to + * look like a regular type 3 drive (see [1], + * line 1859). The controller accepts the 4/17 + * geometry, so this should not really matter. + * + * However, the BIOS issues SPECIFY (see [1], + * line 2089) with head count of two. Let's + * hardwire the correct number instead, just like + * the real hardware seems to. + * + * [1] https://archive.org/download/v86p-hd/V86P-HD.TXT + */ + drive->cfg_hpc = 4; + st506_xt_log("ST506: drive%i: corrected to heads=%i\n", + dev->drive_sel, drive->cfg_hpc); + } st506_complete(dev); break; } @@ -949,6 +974,34 @@ st506_callback(void *priv) } break; + case CMD_V86P_POWEROFF: + if (dev->type == 23) { + /* + * Main BIOS (not the option ROM on disk) issues this. + * Not much we can do, since we don't have a physical disk + * to spin down, but handle this anyways so that we log + * something more reasonable than "unknown command". + * + * Entirely undocumented, but this is what's been observed: + * BIOS setting | Command sent + * 1 minutes | 1a 00 00 0c 02 00 + * 2 minutes | 1a 00 00 18 02 00 + * 3 minutes | 1a 00 00 24 02 00 + * 4 minutes | 1a 00 00 30 02 00 + * 5 minutes | 1a 00 00 3c 02 00 + * off | 1a 00 00 00 02 00 + */ + if (dev->command[3]) + st506_xt_log("ST506: Auto power-off in %d seconds (type=%i)\n", + dev->command[3] * 5, dev->type); + else + st506_xt_log("ST506: Auto power-off disabled (type=%i)\n", dev->type); + } else { + st506_error(dev, ERR_BAD_COMMAND); + } + st506_complete(dev); + break; + case CMD_RAM_DIAGNOSTIC: #ifdef ENABLE_ST506_XT_LOG st506_xt_log("ST506: RAM_DIAG\n"); @@ -1485,6 +1538,9 @@ st506_init(const device_t *info) dev->switches |= 0x40; dev->bios_addr = device_get_config_hex20("bios_addr"); break; + case 23: /* Victor V86P (RLL) */ + fn = VICTOR_V86P_BIOS_FILE; + break; } /* Load the ROM BIOS. */ @@ -1605,6 +1661,12 @@ wd1004a_27x_available(void) return (rom_present(WD1004A_27X_BIOS_FILE)); } +static int +victor_v86p_available(void) +{ + return (rom_present(VICTOR_V86P_BIOS_FILE)); +} + // clang-format off static const device_config_t dtc_config[] = { { @@ -2036,3 +2098,17 @@ const device_t st506_xt_wd1004a_27x_device = { .force_redraw = NULL, .config = wd_rll_config }; + +const device_t st506_xt_victor_v86p_device = { + .name = "Victor V86P RLL Fixed Disk Adapter", + .internal_name = "st506_xt_victor_v86p", + .flags = DEVICE_ISA, + .local = (HDD_BUS_MFM << 8) | 23, + .init = st506_init, + .close = st506_close, + .reset = NULL, + { .available = victor_v86p_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/floppy/fdd_td0.c b/src/floppy/fdd_td0.c index 9be4f62ce..b783c507a 100644 --- a/src/floppy/fdd_td0.c +++ b/src/floppy/fdd_td0.c @@ -1121,7 +1121,7 @@ td0_seek(int drive, int track) id[1] = dev->sects[track][side][actual_sector].head; id[2] = real_sector; id[3] = dev->sects[track][side][actual_sector].size; - pclog("track %i, side %i, %i,%i,%i,%i %i\n", track, side, id[0], id[1], id[2], id[3], dev->sects[track][side][actual_sector].flags); + td0_log("track %i, side %i, %i,%i,%i,%i %i\n", track, side, id[0], id[1], id[2], id[3], dev->sects[track][side][actual_sector].flags); fm = dev->sects[track][side][actual_sector].fm; if (((dev->sects[track][side][actual_sector].flags & 0x42) || (id[3] > (dev->max_sector_size - fm))) && !fdd_get_turbo(drive)) ssize = 3; diff --git a/src/include/86box/hdc.h b/src/include/86box/hdc.h index 0c20aaa32..bde423337 100644 --- a/src/include/86box/hdc.h +++ b/src/include/86box/hdc.h @@ -40,6 +40,7 @@ extern const device_t st506_at_wd1003_device; /* st506_at_wd1003 */ extern const device_t st506_xt_wd1004a_wx1_device; /* st506_xt_wd1004a_wx1 */ extern const device_t st506_xt_wd1004_27x_device; /* st506_xt_wd1004_27x */ extern const device_t st506_xt_wd1004a_27x_device; /* st506_xt_wd1004a_27x */ +extern const device_t st506_xt_victor_v86p_device; /* st506_xt_victor_v86p */ extern const device_t esdi_at_wd1007vse1_device; /* esdi_at */ extern const device_t esdi_ps2_device; /* esdi_mca */ 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) diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index b4252324a..b310e1553 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -146,6 +146,7 @@ extern int mouse_scan; #ifdef EMU_DEVICE_H extern const device_t keyboard_pc_device; extern const device_t keyboard_pc82_device; +extern const device_t keyboard_pravetz_device; extern const device_t keyboard_xt_device; extern const device_t keyboard_xt86_device; extern const device_t keyboard_xt_compaq_device; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 64a669b9a..78d1aaaba 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -336,6 +336,7 @@ extern int machine_get_max_ram(int m); extern int machine_get_ram_granularity(int m); extern int machine_get_type(int m); extern void machine_close(void); +extern int machine_has_mouse(void); extern uint8_t machine_get_p1(void); extern void machine_load_p1(int m); @@ -714,6 +715,9 @@ extern int machine_at_vpc2007_init(const machine_t *); /* m_at_t3100e.c */ extern int machine_at_t3100e_init(const machine_t *); +/* m_elt.c */ +extern int machine_elt_init(const machine_t *); + /* m_europc.c */ extern int machine_europc_init(const machine_t *); #ifdef EMU_DEVICE_H diff --git a/src/include/86box/nvr.h b/src/include/86box/nvr.h index 34f11efd4..d10191a79 100644 --- a/src/include/86box/nvr.h +++ b/src/include/86box/nvr.h @@ -97,6 +97,7 @@ extern const device_t ami_1994_nvr_device; extern const device_t ami_1995_nvr_device; extern const device_t via_nvr_device; extern const device_t p6rp4_nvr_device; +extern const device_t elt_nvr_device; #endif extern void rtc_tick(void); diff --git a/src/include/86box/vid_cga.h b/src/include/86box/vid_cga.h index 7f880fc1c..a8cef77fe 100644 --- a/src/include/86box/vid_cga.h +++ b/src/include/86box/vid_cga.h @@ -67,7 +67,9 @@ void cga_poll(void *p); #ifdef EMU_DEVICE_H extern const device_config_t cga_config[]; + extern const device_t cga_device; +extern const device_t cga_pravetz_device; #endif #endif /*VIDEO_CGA_H*/ diff --git a/src/machine/CMakeLists.txt b/src/machine/CMakeLists.txt index 62bd5c61f..c96747f47 100644 --- a/src/machine/CMakeLists.txt +++ b/src/machine/CMakeLists.txt @@ -16,7 +16,7 @@ add_library(mch OBJECT machine.c machine_table.c m_xt.c m_xt_compaq.c m_xt_philips.c m_xt_t1000.c m_xt_t1000_vid.c m_xt_xi8088.c m_xt_zenith.c m_pcjr.c - m_amstrad.c m_europc.c m_xt_olivetti.c m_tandy.c m_v86p.c + m_amstrad.c m_europc.c m_elt.c m_xt_olivetti.c m_tandy.c m_v86p.c m_at.c m_at_commodore.c m_at_t3100e.c m_at_t3100e_vid.c m_ps1.c m_ps1_hdc.c m_ps2_isa.c m_ps2_mca.c m_at_compaq.c m_at_286_386sx.c m_at_386dx_486.c diff --git a/src/machine/m_elt.c b/src/machine/m_elt.c new file mode 100644 index 000000000..be0e26cb3 --- /dev/null +++ b/src/machine/m_elt.c @@ -0,0 +1,199 @@ +/* + * 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. + * + * Epson Equity LT portable computer emulation. + * + * Author: Lubomir Rintel, + * + * Copyright 2022 Lubomir Rintel. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ + +// clang-format off +#include +#include +#include +#include <86box/timer.h> +#include <86box/fdd.h> +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/fdc.h> +#include <86box/fdc_ext.h> +#include <86box/io.h> +#include <86box/keyboard.h> +#include <86box/machine.h> +#include <86box/mem.h> +#include <86box/nmi.h> +#include <86box/nvr.h> +#include <86box/pit.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/vid_cga.h> +// clang-format on + +static void +elt_vid_off_poll(void *p) +{ + cga_t *cga = p; + uint8_t hdisp = cga->crtc[1]; + + /* Don't display anything. + * TODO: Do something less stupid to emulate backlight off. */ + cga->crtc[1] = 0; + cga_poll(cga); + cga->crtc[1] = hdisp; +} + +static void +sysstat_out(uint16_t port, uint8_t val, void *p) +{ + cga_t *cga = p; + + switch (val) { + case 0: + break; + case 1: + /* Backlight off. */ + if (cga) + timer_set_callback(&cga->timer, elt_vid_off_poll); + break; + case 2: + /* Backlight on. */ + if (cga) + timer_set_callback(&cga->timer, cga_poll); + break; + default: + pclog("Unknown sysstat command: 0x%02x\n", val); + } +} + +static uint8_t +sysstat_in(uint16_t port, void *p) +{ + cga_t *cga = p; + uint8_t ret = 0x0a; /* No idea what these bits are */ + + /* External CRT. We don't emulate the LCD/CRT switching, let's just + * frivolously use this bit to indicate we're using the LCD if the + * user didn't override the video card for now. */ + if (cga == NULL) + ret |= 0x40; + + return ret; +} + +static void +elt_vid_out(uint16_t addr, uint8_t val, void *p) +{ + cga_t *cga = p; + + /* The Equity LT chipset's CRTC contains more registers than the + * regular CGA. The BIOS writes one of them, register 36 (0x24). + * Nothing is known about the number or function of those registers, + * let's just ignore them so that we don't clobber the CGA register. + * Also, the BIOS writes that register via the 3D0h/3D1h alias + * instead of the usual 3D4h/3D5h, possibly to keep the wraparound + * behavior on the usual addresses (just an assumption, not + * verified). */ + switch (addr) { + case 0x3d0: + cga->crtcreg = val; + return; + case 0x3d1: + if (cga->crtcreg >= 32) + return; + /* FALLTHROUGH */ + default: + cga->crtcreg &= 31; + cga_out(addr, val, p); + } +} + +static uint8_t +elt_vid_in(uint16_t addr, void *p) +{ + cga_t *cga = p; + + /* Just make sure we don't ever let regular CGA code run with crtcreg + * pointing out of crtcregs[] bounds. */ + cga->crtcreg &= 31; + return cga_in(addr, p); +} + +static void +load_font_rom(uint32_t font_data) +{ + int c, d; + for (c = 0; c < 256; c++) + for (d = 0; d < 8; d++) + fontdat[c][d] = mem_readb_phys(font_data++); +} + +int +machine_elt_init(const machine_t *model) +{ + cga_t *cga = NULL; + int ret; + + ret = bios_load_interleavedr("roms/machines/elt/HLO-B2.rom", + "roms/machines/elt/HLO-A2.rom", + 0x000fc000, 65536, 0); + + if (bios_only || !ret) + return ret; + + /* The machine doesn't have any separate font ROM chip. The text mode + * font is likely a mask ROM in the chipset. video_reset() will try + * to load a MDA font, but let's have a reasonable fall back if it's + * not available. Read in the graphical mode font from the BIOS ROM + * image. */ + load_font_rom(0xffa6e); + + machine_common_init(model); + + nmi_init(); + + pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_xt_device); + + if (gfxcard == VID_INTERNAL) { + cga = device_add(&cga_device); + io_removehandler(0x03d0, 0x0010, cga_in, NULL, NULL, cga_out, NULL, NULL, cga); + io_sethandler(0x03d0, 0x0010, elt_vid_in, NULL, NULL, elt_vid_out, NULL, NULL, cga); + } + + /* Keyboard goes after the video, because on XT compatibles it's dealt + * with by the same PPI as the config switches and we need them to + * indicate the correct display type */ + device_add(&keyboard_xt_device); + + device_add(&elt_nvr_device); + + io_sethandler(0x11b8, 1, sysstat_in, NULL, NULL, sysstat_out, NULL, NULL, cga); + + return ret; +} diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index 17229238f..fa7059c88 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -18,6 +18,7 @@ #include <86box/rom.h> #include <86box/machine.h> #include <86box/chipset.h> +#include <86box/port_6x.h> static void machine_xt_common_init(const machine_t *model) @@ -331,15 +332,33 @@ machine_xt_iskra3104_init(const machine_t *model) int machine_xt_pravetz16_imko4_init(const machine_t *model) { - int ret; - + int ret; + ret = bios_load_linear("roms/machines/pravetz16/BIOS_IMKO4_FE00.bin", - 0x000fe000, 8192, 0); + 0x000fe000, 65536, 0); + if (ret) { + ret = bios_load_aux_linear("roms/machines/pravetz16/IMKO4-D34_SGS-M2764ADIP28.BIN", + 0x000f4000, 8192, 0); + + if (ret) { + bios_load_aux_linear("roms/machines/pravetz16/1.bin", + 0x000f6000, 8192, 0); + + bios_load_aux_linear("roms/machines/pravetz16/2.bin", + 0x000fa000, 8192, 0); + + bios_load_aux_linear("roms/machines/pravetz16/5.bin", + 0x000f8000, 8192, 0); + + bios_load_aux_linear("roms/machines/pravetz16/6.bin", + 0x000fc000, 8192, 0); + } + } if (bios_only || !ret) return ret; - device_add(&keyboard_at_device); + device_add(&keyboard_pravetz_device); machine_xt_common_init(model); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 16e680a1d..4ff1e4bc7 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -2118,6 +2118,42 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + { + .name = "[8086] Epson Equity LT", + .internal_name = "elt", + .type = MACHINE_TYPE_8086, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_elt_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8086, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_VIDEO, + .ram = { + .min = 640, + .max = 640, + .step = 640 + }, + .nvrmask = 0x3f, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, #if defined(DEV_BRANCH) && defined(USE_LASERXT) { @@ -12174,3 +12210,9 @@ machine_get_machine_from_internal_name(char *s) return(0); } + +int +machine_has_mouse(void) +{ + return(machines[machine].flags & MACHINE_MOUSE); +} diff --git a/src/mem/mem.c b/src/mem/mem.c index 9f292fd0e..ecda875a6 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -55,11 +55,12 @@ #endif mem_mapping_t ram_low_mapping, /* 0..640K mapping */ - ram_mid_mapping, + ram_mid_mapping, /* 640..1024K mapping */ + ram_mid_mapping2, /* 640..1024K mapping, second part, for SiS 471 in relocate mode */ ram_remapped_mapping, /* 640..1024K mapping */ + ram_remapped_mapping2,/* 640..1024K second mapping, for SiS 471 mode */ ram_high_mapping, /* 1024K+ mapping */ ram_2gb_mapping, /* 1024M+ mapping */ - ram_remapped_mapping, ram_split_mapping, bios_mapping, bios_high_mapping; @@ -71,6 +72,7 @@ uint32_t pages_sz; /* #pages in table */ uint8_t *ram, *ram2; /* the virtual RAM */ uint8_t page_ff[4096]; uint32_t rammask; +uint32_t addr_space_size; uint8_t *rom; /* the virtual ROM */ uint32_t biosmask, biosaddr; @@ -127,7 +129,7 @@ static mem_mapping_t *write_mapping_bus[MEM_MAPPINGS_NO]; static uint8_t *_mem_exec[MEM_MAPPINGS_NO]; static uint8_t ff_pccache[4] = { 0xff, 0xff, 0xff, 0xff }; static mem_state_t _mem_state[MEM_MAPPINGS_NO]; -static uint32_t remap_start_addr; +static uint32_t remap_start_addr, remap_start_addr2; #if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) static size_t ram_size = 0, ram2_size = 0; #else @@ -157,7 +159,8 @@ mem_addr_is_ram(uint32_t addr) { mem_mapping_t *mapping = read_mapping[addr >> MEM_GRANULARITY_BITS]; - return (mapping == &ram_low_mapping) || (mapping == &ram_high_mapping) || (mapping == &ram_mid_mapping) || (mapping == &ram_remapped_mapping); + return (mapping == &ram_low_mapping) || (mapping == &ram_high_mapping) || (mapping == &ram_mid_mapping) || + (mapping == &ram_mid_mapping2) || (mapping == &ram_remapped_mapping); } void @@ -2087,6 +2090,33 @@ mem_read_remappedl(uint32_t addr, void *priv) return *(uint32_t *) &ram[addr]; } +static uint8_t +mem_read_remapped2(uint32_t addr, void *priv) +{ + addr = 0xD0000 + (addr - remap_start_addr2); + if (is286) + addreadlookup(mem_logical_addr, addr); + return ram[addr]; +} + +static uint16_t +mem_read_remappedw2(uint32_t addr, void *priv) +{ + addr = 0xD0000 + (addr - remap_start_addr2); + if (is286) + addreadlookup(mem_logical_addr, addr); + return *(uint16_t *) &ram[addr]; +} + +static uint32_t +mem_read_remappedl2(uint32_t addr, void *priv) +{ + addr = 0xD0000 + (addr - remap_start_addr2); + if (is286) + addreadlookup(mem_logical_addr, addr); + return *(uint32_t *) &ram[addr]; +} + static void mem_write_remapped(uint32_t addr, uint8_t val, void *priv) { @@ -2123,6 +2153,42 @@ mem_write_remappedl(uint32_t addr, uint32_t val, void *priv) *(uint32_t *) &ram[addr] = val; } +static void +mem_write_remapped2(uint32_t addr, uint8_t val, void *priv) +{ + uint32_t oldaddr = addr; + addr = 0xD0000 + (addr - remap_start_addr2); + if (is286) { + addwritelookup(mem_logical_addr, addr); + mem_write_ramb_page(addr, val, &pages[oldaddr >> 12]); + } else + ram[addr] = val; +} + +static void +mem_write_remappedw2(uint32_t addr, uint16_t val, void *priv) +{ + uint32_t oldaddr = addr; + addr = 0xD0000 + (addr - remap_start_addr2); + if (is286) { + addwritelookup(mem_logical_addr, addr); + mem_write_ramw_page(addr, val, &pages[oldaddr >> 12]); + } else + *(uint16_t *) &ram[addr] = val; +} + +static void +mem_write_remappedl2(uint32_t addr, uint32_t val, void *priv) +{ + uint32_t oldaddr = addr; + addr = 0xD0000 + (addr - remap_start_addr2); + if (is286) { + addwritelookup(mem_logical_addr, addr); + mem_write_raml_page(addr, val, &pages[oldaddr >> 12]); + } else + *(uint32_t *) &ram[addr] = val; +} + void mem_invalidate_range(uint32_t start_addr, uint32_t end_addr) { @@ -2605,6 +2671,8 @@ mem_reset(void) m = 256; } + addr_space_size = m; + /* * Allocate and initialize the (new) page table. */ @@ -2687,15 +2755,26 @@ mem_reset(void) } } - if (mem_size > 768) + if (mem_size > 768) { mem_add_ram_mapping(&ram_mid_mapping, 0xa0000, 0x60000); + mem_add_ram_mapping(&ram_mid_mapping2, 0xa0000, 0x60000); + mem_mapping_disable(&ram_mid_mapping2); + } + mem_mapping_add(&ram_remapped_mapping, mem_size * 1024, 256 * 1024, mem_read_remapped, mem_read_remappedw, mem_read_remappedl, mem_write_remapped, mem_write_remappedw, mem_write_remappedl, ram + 0xa0000, MEM_MAPPING_INTERNAL, NULL); mem_mapping_disable(&ram_remapped_mapping); + /* Mapping for SiS 471 relocation which relocates A0000-BFFFF, D0000-EFFFF, which is non-contiguous. */ + mem_mapping_add(&ram_remapped_mapping2, mem_size * 1024, 256 * 1024, + mem_read_remapped2, mem_read_remappedw2, mem_read_remappedl2, + mem_write_remapped2, mem_write_remappedw2, mem_write_remappedl2, + ram + 0xd0000, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_disable(&ram_remapped_mapping2); + mem_a20_init(); #ifdef USE_NEW_DYNAREC @@ -2729,11 +2808,19 @@ mem_remap_top(int kb) int offset, size = mem_size - 640; int set = 1; static int old_kb = 0; + int sis_mode = 0; + uint32_t start_addr = 0, addr = 0; mem_log("MEM: remapping top %iKB (mem=%i)\n", kb, mem_size); if (mem_size <= 640) return; + /* SiS 471 special mode. */ + if (kb == -256) { + kb = 256; + sis_mode = 1; + } + if (kb == 0) { kb = old_kb; set = 0; @@ -2744,27 +2831,95 @@ mem_remap_top(int kb) size = kb; remap_start_addr = start << 10; + remap_start_addr2 = (start << 10) + 0x00020000; for (c = ((start * 1024) >> 12); c < (((start + size) * 1024) >> 12); c++) { offset = c - ((start * 1024) >> 12); - pages[c].mem = set ? &ram[0xa0000 + (offset << 12)] : page_ff; + /* Use A0000-BFFFF, D0000-EFFFF instead of C0000-DFFFF, E0000-FFFFF. */ + addr = 0xa0000 + (offset << 12); + if (sis_mode) { + /* A0000-DFFFF -> A0000-BFFFF, D0000-EFFFF */ + if (addr >= 0x000c0000) + addr += 0x00010000; + } + if (start_addr != 0) + start_addr = addr; + pages[c].mem = set ? &ram[addr] : page_ff; pages[c].write_b = set ? mem_write_ramb_page : NULL; pages[c].write_w = set ? mem_write_ramw_page : NULL; pages[c].write_l = set ? mem_write_raml_page : NULL; #ifdef USE_NEW_DYNAREC pages[c].evict_prev = EVICT_NOT_IN_LIST; - pages[c].byte_dirty_mask = &byte_dirty_mask[offset * 64]; - pages[c].byte_code_present_mask = &byte_code_present_mask[offset * 64]; + pages[c].byte_dirty_mask = &byte_dirty_mask[(addr >> 12) * 64]; + pages[c].byte_code_present_mask = &byte_code_present_mask[(addr >> 12) * 64]; #endif } mem_set_mem_state_both(start * 1024, size * 1024, set ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); + for (c = 0xa0; c < 0xf0; c++) { + if ((c >= 0xc0) && (c <= 0xcf)) + continue; + + if (sis_mode || ((c << 12) >= (mem_size << 10))) + pages[c].mem = page_ff; + else { +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) + if (mem_size > 1048576) { + if ((c << 12) < (1 << 30)) + pages[c].mem = &ram[c << 12]; + else + pages[c].mem = &ram2[(c << 12) - (1 << 30)]; + } else + pages[c].mem = &ram[c << 12]; +#else + pages[c].mem = &ram[c << 12]; +#endif + } + if (!sis_mode && (c < addr_space_size)) { + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + } else { + pages[c].write_b = NULL; + pages[c].write_w = NULL; + pages[c].write_l = NULL; + } +#ifdef USE_NEW_DYNAREC + pages[c].evict_prev = EVICT_NOT_IN_LIST; + pages[c].byte_dirty_mask = &byte_dirty_mask[c * 64]; + pages[c].byte_code_present_mask = &byte_code_present_mask[c * 64]; +#endif + } + if (set) { - mem_mapping_set_addr(&ram_remapped_mapping, start * 1024, size * 1024); - mem_mapping_set_exec(&ram_remapped_mapping, ram + 0xa0000); - } else + if (sis_mode) { + mem_mapping_set_addr(&ram_remapped_mapping, start * 1024, 0x00020000); + mem_mapping_set_exec(&ram_remapped_mapping, ram + 0x000a0000); + mem_mapping_set_addr(&ram_remapped_mapping2, (start * 1024) + 0x00020000, 0x00020000); + mem_mapping_set_exec(&ram_remapped_mapping2, ram + 0x000d0000); + + mem_mapping_set_addr(&ram_mid_mapping, 0x000c0000, 0x00010000); + mem_mapping_set_exec(&ram_mid_mapping, ram + 0x000c0000); + mem_mapping_set_addr(&ram_mid_mapping2, 0x000f0000, 0x00010000); + mem_mapping_set_exec(&ram_mid_mapping2, ram + 0x000f0000); + } else { + mem_mapping_set_addr(&ram_remapped_mapping, start * 1024, size * 1024); + mem_mapping_set_exec(&ram_remapped_mapping, ram + start_addr); + mem_mapping_disable(&ram_remapped_mapping2); + + mem_mapping_set_addr(&ram_mid_mapping, 0x000a0000, 0x00060000); + mem_mapping_set_exec(&ram_mid_mapping, ram + 0x000a0000); + mem_mapping_disable(&ram_mid_mapping2); + } + } else { mem_mapping_disable(&ram_remapped_mapping); + mem_mapping_disable(&ram_remapped_mapping2); + + mem_mapping_set_addr(&ram_mid_mapping, 0x000a0000, 0x00060000); + mem_mapping_set_exec(&ram_mid_mapping, ram + 0x000a0000); + mem_mapping_disable(&ram_mid_mapping2); + } flushmmucache(); } diff --git a/src/nvr_at.c b/src/nvr_at.c index 91ee4a949..ee2678ab5 100644 --- a/src/nvr_at.c +++ b/src/nvr_at.c @@ -280,6 +280,7 @@ #define REGD_VRT 0x80 #define RTC_CENTURY_AT 0x32 /* century register for AT etc */ #define RTC_CENTURY_PS 0x37 /* century register for PS/1 PS/2 */ +#define RTC_CENTURY_ELT 0x1A /* century register for Epson Equity LT */ #define RTC_ALDAY 0x7D /* VIA VT82C586B - alarm day */ #define RTC_ALMONTH 0x7E /* VIA VT82C586B - alarm month */ #define RTC_CENTURY_VIA 0x7F /* century register for VIA VT82C586B */ @@ -981,9 +982,9 @@ nvr_at_init(const device_t *info) memset(local->lock, 0x00, nvr->size); local->def = 0xff /*0x00*/; local->flags = 0x00; - switch (info->local & 7) { + switch (info->local & 0x0f) { case 0: /* standard AT, no century register */ - if (info->local == 16) { + if (info->local == 32) { local->flags |= FLAG_P6RP4_HACK; nvr->irq = 8; local->cent = RTC_CENTURY_AT; @@ -996,13 +997,13 @@ nvr_at_init(const device_t *info) case 1: /* standard AT */ case 5: /* AMI WinBIOS 1994 */ case 6: /* AMI BIOS 1995 */ - if (info->local == 9) + if ((info->local & 0x0f) == 1) local->flags |= FLAG_PIIX4; else { local->def = 0x00; - if ((info->local & 7) == 5) + if ((info->local & 0x0f) == 5) local->flags |= FLAG_AMI_1994_HACK; - else if ((info->local & 7) == 6) + else if ((info->local & 0x0f) == 6) local->flags |= FLAG_AMI_1995_HACK; else local->def = 0xff; @@ -1015,7 +1016,7 @@ nvr_at_init(const device_t *info) nvr->irq = 8; local->cent = RTC_CENTURY_PS; local->def = 0x00; - if (info->local & 8) + if (info->local & 0x10) local->flags |= FLAG_NO_NMI; break; @@ -1023,15 +1024,15 @@ nvr_at_init(const device_t *info) nvr->irq = 1; local->cent = RTC_CENTURY_AT; local->def = 0xff; - if (info->local & 8) + if (info->local & 0x10) local->flags |= FLAG_NO_NMI; break; case 4: /* IBM AT */ - if (info->local == 12) { + if (info->local & 0x10) { local->def = 0x00; local->flags |= FLAG_AMI_1992_HACK; - } else if (info->local == 20) + } else if (info->local == 36) local->def = 0x00; else local->def = 0xff; @@ -1043,6 +1044,10 @@ nvr_at_init(const device_t *info) nvr->irq = 8; local->cent = RTC_CENTURY_VIA; break; + case 8: /* Epson Equity LT */ + nvr->irq = -1; + local->cent = RTC_CENTURY_ELT; + break; } local->read_addr = 1; @@ -1067,9 +1072,14 @@ nvr_at_init(const device_t *info) timer_load_count(nvr); /* Set up the I/O handler for this device. */ - io_sethandler(0x0070, 2, - nvr_read, NULL, NULL, nvr_write, NULL, NULL, nvr); - if (info->local & 8) { + if (info->local == 8) { + io_sethandler(0x11b4, 2, + nvr_read, NULL, NULL, nvr_write, NULL, NULL, nvr); + } else { + io_sethandler(0x0070, 2, + nvr_read, NULL, NULL, nvr_write, NULL, NULL, nvr); + } + if (info->local & 0x10) { io_sethandler(0x0072, 2, nvr_read, NULL, NULL, nvr_write, NULL, NULL, nvr); } @@ -1180,7 +1190,7 @@ const device_t piix4_nvr_device = { .name = "Intel PIIX4 PC/AT NVRAM", .internal_name = "piix4_nvr", .flags = DEVICE_ISA | DEVICE_AT, - .local = 9, + .local = 0x10 | 1, .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, @@ -1220,7 +1230,7 @@ const device_t ami_1992_nvr_device = { .name = "AMI Color 1992 PC/AT NVRAM", .internal_name = "ami_1992_nvr", .flags = DEVICE_ISA | DEVICE_AT, - .local = 12, + .local = 0x10 | 4, .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, @@ -1234,7 +1244,7 @@ const device_t ami_1994_nvr_device = { .name = "AMI WinBIOS 1994 PC/AT NVRAM", .internal_name = "ami_1994_nvr", .flags = DEVICE_ISA | DEVICE_AT, - .local = 13, + .local = 0x10 | 5, .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, @@ -1248,7 +1258,7 @@ const device_t ami_1995_nvr_device = { .name = "AMI WinBIOS 1995 PC/AT NVRAM", .internal_name = "ami_1995_nvr", .flags = DEVICE_ISA | DEVICE_AT, - .local = 14, + .local = 0x10 | 6, .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, @@ -1262,7 +1272,7 @@ const device_t via_nvr_device = { .name = "VIA PC/AT NVRAM", .internal_name = "via_nvr", .flags = DEVICE_ISA | DEVICE_AT, - .local = 15, + .local = 0x10 | 7, .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, @@ -1276,7 +1286,7 @@ const device_t p6rp4_nvr_device = { .name = "ASUS P/I-P6RP4 PC/AT NVRAM", .internal_name = "p6rp4_nvr", .flags = DEVICE_ISA | DEVICE_AT, - .local = 16, + .local = 32, .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, @@ -1290,7 +1300,21 @@ const device_t amstrad_megapc_nvr_device = { .name = "Amstrad MegapC NVRAM", .internal_name = "amstrad_megapc_nvr", .flags = DEVICE_ISA | DEVICE_AT, - .local = 20, + .local = 36, + .init = nvr_at_init, + .close = nvr_at_close, + .reset = nvr_at_reset, + { .available = NULL }, + .speed_changed = nvr_at_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t elt_nvr_device = { + .name = "Epson Equity LT NVRAM", + .internal_name = "elt_nvr", + .flags = DEVICE_ISA, + .local = 8, .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, diff --git a/src/qt/qt_ui.cpp b/src/qt/qt_ui.cpp index febf4cba7..09199bdac 100644 --- a/src/qt/qt_ui.cpp +++ b/src/qt/qt_ui.cpp @@ -104,7 +104,7 @@ void plat_setfullscreen(int on) { } void plat_mouse_capture(int on) { - if (!kbd_req_capture && (mouse_type == MOUSE_TYPE_NONE)) + if (!kbd_req_capture && (mouse_type == MOUSE_TYPE_NONE) && !machine_has_mouse()) return; main_window->setMouseCapture(on > 0 ? true : false); diff --git a/src/video/vid_cga.c b/src/video/vid_cga.c index ee3987fe0..b68f093e1 100644 --- a/src/video/vid_cga.c +++ b/src/video/vid_cga.c @@ -117,6 +117,22 @@ cga_in(uint16_t addr, void *p) return ret; } +void +cga_pravetz_out(uint16_t addr, uint8_t val, void *p) +{ + cga_t *cga = (cga_t *) p; + + cga->fontbase = (((unsigned int) val) << 8); +} + +uint8_t +cga_pravetz_in(uint16_t addr, void *p) +{ + cga_t *cga = (cga_t *) p; + + return (cga->fontbase >> 8); +} + void cga_waitstates(void *p) { @@ -524,6 +540,21 @@ cga_standalone_init(const device_t *info) return cga; } +void * +cga_pravetz_init(const device_t *info) +{ + cga_t *cga = cga_standalone_init(info); + + loadfont("roms/video/cga/CGA - PRAVETZ.BIN", 10); + + io_removehandler(0x03dd, 0x0001, cga_in, NULL, NULL, cga_out, NULL, NULL, cga); + io_sethandler(0x03dd, 0x0001, cga_pravetz_in, NULL, NULL, cga_pravetz_out, NULL, NULL, cga); + + cga->fontbase = 0x0300; + + return cga; +} + void cga_close(void *p) { @@ -637,3 +668,17 @@ const device_t cga_device = { .force_redraw = NULL, .config = cga_config }; + +const device_t cga_pravetz_device = { + .name = "Pravetz VDC-2", + .internal_name = "cga_pravetz", + .flags = DEVICE_ISA, + .local = 0, + .init = cga_pravetz_init, + .close = cga_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = cga_speed_changed, + .force_redraw = NULL, + .config = cga_config +}; diff --git a/src/video/vid_pgc.c b/src/video/vid_pgc.c index dddbaee45..0decb8e65 100644 --- a/src/video/vid_pgc.c +++ b/src/video/vid_pgc.c @@ -2131,12 +2131,17 @@ void pgc_recalctimings(pgc_t *dev) { double disptime, _dispontime, _dispofftime; - double pixel_clock = (cpuclock * (double) (1ull << 32)) / (dev->cga_selected ? 25175000.0 : dev->native_pixel_clock); + double pixel_clock = (cpuclock / (dev->cga_selected ? 25175000.0 : dev->native_pixel_clock) * (double) (1ull << 32)); + uint8_t crtc0 = 97, crtc1 = 80; /* Values from MDA, taken from there due to the 25 MHz refresh rate. */ + /* Multiply pixel clock by 8. */ + pixel_clock *= 8.0; /* Use a fixed 640x400 display. */ - disptime = dev->screenw + 11; - _dispontime = dev->screenw * pixel_clock; - _dispofftime = (disptime - dev->screenw) * pixel_clock; + disptime = crtc0 + 1; + _dispontime = crtc1; + _dispofftime = disptime - _dispontime; + _dispontime *= pixel_clock; + _dispofftime *= pixel_clock; dev->dispontime = (uint64_t) (_dispontime); dev->dispofftime = (uint64_t) (_dispofftime); } diff --git a/src/video/vid_table.c b/src/video/vid_table.c index ed34e7914..73ad0cdd3 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -127,6 +127,7 @@ video_cards[] = { { ¶dise_wd90c30_device }, { &colorplus_device }, { &pgc_device }, + { &cga_pravetz_device }, { &radius_svga_multiview_isa_device }, { &realtek_rtg3106_device }, { &s3_diamond_stealth_vram_isa_device }, @@ -329,7 +330,7 @@ video_reset(int card) /* Do not initialize internal cards here. */ if (!(card == VID_NONE) && !(card == VID_INTERNAL) && !machine_has_flags(machine, MACHINE_VIDEO_ONLY)) { - vid_table_log("VIDEO: initializing '%s'\n", video_cards[card].name); + vid_table_log("VIDEO: initializing '%s'\n", video_cards[card].device->name); video_prepare(); diff --git a/src/video/video.c b/src/video/video.c index eb4997574..ae2fcf5eb 100644 --- a/src/video/video.c +++ b/src/video/video.c @@ -252,7 +252,7 @@ static uint32_t cga_2_table[16]; static void (*blit_func)(int x, int y, int w, int h, int monitor_index); #ifdef ENABLE_VIDEO_LOG -int sdl_do_log = ENABLE_VIDEO_LOG; +int video_do_log = ENABLE_VIDEO_LOG; static void video_log(const char *fmt, ...) @@ -1083,6 +1083,13 @@ loadfont_common(FILE *f, int format) for (c = 0; c < 256; c++) (void) !fread(&fontdat12x18[c][0], 1, 36, f); break; + + case 10: /* Pravetz */ + for (c = 0; c < 1024; c++) /* Allow up to 1024 chars */ + for (d = 0; d < 8; d++) + fontdat[c][d] = fgetc(f) & 0xff; + break; + } (void) fclose(f); diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 7291296a6..0e356751b 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -562,6 +562,7 @@ MCHOBJ := machine.o machine_table.o \ m_xt_xi8088.o m_xt_zenith.o \ m_pcjr.o \ m_amstrad.o m_europc.o \ + m_elt.o \ m_xt_olivetti.o m_tandy.o m_v86p.o \ m_at.o m_at_commodore.o \ m_at_t3100e.o m_at_t3100e_vid.o \ diff --git a/src/win/win_ui.c b/src/win/win_ui.c index b8902cf77..803ed2a80 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -1549,7 +1549,7 @@ plat_mouse_capture(int on) { RECT rect; - if (!kbd_req_capture && (mouse_type == MOUSE_TYPE_NONE)) + if (!kbd_req_capture && (mouse_type == MOUSE_TYPE_NONE) && !machine_has_mouse()) return; if (on && !mouse_capture) {