diff --git a/src/cpu/386.c b/src/cpu/386.c index ad310d31e..5379dccf9 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -280,7 +280,10 @@ exec386_2386(int32_t cycs) cpu_state.pc++; cpu_state.eflags &= ~(RF_FLAG); + if (opcode == 0xf0) + in_lock = 1; x86_2386_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); + in_lock = 0; if (x86_was_reset) break; } diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index 0abf8e936..5c1b95e0f 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -123,11 +123,11 @@ int opcode_length[256] = { 3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 3, /* /* 0 = no, 1 = always, 2 = depends on second opcode, 3 = depends on mod/rm */ int lock_legal[256] = { 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 2, /* 0x0x */ 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, /* 0x1x */ - 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, /* 0x2x */ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x3x */ + 1, 1, 1, 1, 1, 1, 4, 0, 1, 1, 1, 1, 1, 1, 4, 0, /* 0x2x */ + 1, 1, 1, 1, 1, 1, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, /* 0x3x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x4x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x5x */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x6x */ + 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x6x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x7x */ 3, 3, 3, 3, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x8x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x9x */ @@ -423,6 +423,50 @@ x386_common_log(const char *fmt, ...) # define x386_common_log(fmt, ...) #endif +int +is_lock_legal(uint32_t fetchdat) +{ + int legal; + fetch_dat_t fetch_dat; + + fetch_dat.fd = fetchdat; + + legal = lock_legal[fetch_dat.b[0]]; + if (legal == 1) + legal = ((fetch_dat.b[1] >> 6) != 0x03); /* reg is illegal */ + else if (legal == 2) { + legal = lock_legal_0f[fetch_dat.b[1]]; + if (legal == 1) + legal = ((fetch_dat.b[2] >> 6) != 0x03); /* reg,reg is illegal */ + else if (legal == 3) { + legal = lock_legal_ba[(fetch_dat.b[2] >> 3) & 0x07]; + if (legal == 1) + legal = ((fetch_dat.b[2] >> 6) != 0x03); /* reg,imm is illegal */ + } + } else if (legal == 3) switch(fetch_dat.b[0]) { + case 0x80 ... 0x83: + legal = lock_legal_80[(fetch_dat.b[1] >> 3) & 0x07]; + if (legal == 1) + legal = ((fetch_dat.b[1] >> 6) != 0x03); /* reg is illegal */ + break; + case 0xf6 ... 0xf7: + legal = lock_legal_f6[(fetch_dat.b[1] >> 3) & 0x07]; + if (legal == 1) + legal = ((fetch_dat.b[1] >> 6) != 0x03); /* reg is illegal */ + break; + case 0xfe ... 0xff: + legal = lock_legal_fe[(fetch_dat.b[1] >> 3) & 0x07]; + if (legal == 1) + legal = ((fetch_dat.b[1] >> 6) != 0x03); /* reg is illegal */ + break; + default: + legal = 0; + break; + } + + return legal; +} + /*Prefetch emulation is a fairly simplistic model: - All instruction bytes must be fetched before it starts. - Cycles used for non-instruction memory accesses are counted and subtracted diff --git a/src/cpu/808x.c b/src/cpu/808x.c index 90563d9ab..caff0fa60 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -56,7 +56,6 @@ static uint32_t *opseg[4]; static x86seg *_opseg[4]; static int noint = 0; -static int in_lock = 0; static int cpu_alu_op, pfq_size; static uint32_t cpu_src = 0, cpu_dest = 0; @@ -545,7 +544,6 @@ reset_808x(int hard) { biu_cycles = 0; in_rep = 0; - in_lock = 0; completed = 1; repeating = 0; clear_lock = 0; diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 1456d2ee8..16a9eba10 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -829,4 +829,8 @@ extern int lock_legal_80[8]; extern int lock_legal_f6[8]; extern int lock_legal_fe[8]; +extern int in_lock; + +extern int is_lock_legal(uint32_t fetchdat); + #endif /*EMU_CPU_H*/ diff --git a/src/cpu/x86.c b/src/cpu/x86.c index 2c8c29d49..cf2867182 100644 --- a/src/cpu/x86.c +++ b/src/cpu/x86.c @@ -80,6 +80,8 @@ int hlt_reset_pending; int fpu_cycles = 0; +int in_lock = 0; + #ifdef ENABLE_X86_LOG void dumpregs(int); @@ -351,6 +353,8 @@ reset_common(int hard) if (!is286) reset_808x(hard); + in_lock = 0; + cpu_cpurst_on_sr = 0; } diff --git a/src/cpu/x86_ops_misc.h b/src/cpu/x86_ops_misc.h index dd05fb9d9..519bdbe3c 100644 --- a/src/cpu/x86_ops_misc.h +++ b/src/cpu/x86_ops_misc.h @@ -731,46 +731,15 @@ static int opLOCK(uint32_t fetchdat) { int legal; - fetch_dat_t fetch_dat; fetchdat = fastreadl_fetch(cs + cpu_state.pc); if (cpu_state.abrt) return 0; cpu_state.pc++; - fetch_dat.fd = fetchdat; + legal = is_lock_legal(fetchdat); - legal = lock_legal[fetch_dat.b[0]]; - if (legal == 1) - legal = ((fetch_dat.b[1] >> 6) != 0x03); /* reg is illegal */ - else if (legal == 2) { - legal = lock_legal_0f[fetch_dat.b[1]]; - if (legal == 1) - legal = ((fetch_dat.b[2] >> 6) != 0x03); /* reg,reg is illegal */ - else if (legal == 3) { - legal = lock_legal_ba[(fetch_dat.b[2] >> 3) & 0x07]; - if (legal == 1) - legal = ((fetch_dat.b[2] >> 6) != 0x03); /* reg,imm is illegal */ - } - } else if (legal == 3) switch(fetch_dat.b[0]) { - case 0x80 ... 0x83: - legal = lock_legal_80[(fetch_dat.b[1] >> 3) & 0x07]; - if (legal == 1) - legal = ((fetch_dat.b[1] >> 6) != 0x03); /* reg is illegal */ - break; - case 0xf6 ... 0xf7: - legal = lock_legal_f6[(fetch_dat.b[1] >> 3) & 0x07]; - if (legal == 1) - legal = ((fetch_dat.b[1] >> 6) != 0x03); /* reg is illegal */ - break; - case 0xfe ... 0xff: - legal = lock_legal_fe[(fetch_dat.b[1] >> 3) & 0x07]; - if (legal == 1) - legal = ((fetch_dat.b[1] >> 6) != 0x03); /* reg is illegal */ - break; - default: - legal = 0; - break; - } + if (legal == 4) + pclog("PREFIX: F0 %08X\n", fetchdat); ILLEGAL_ON(legal == 0); diff --git a/src/cpu/x86_ops_prefix_2386.h b/src/cpu/x86_ops_prefix_2386.h index 7c87f0bf3..87d114944 100644 --- a/src/cpu/x86_ops_prefix_2386.h +++ b/src/cpu/x86_ops_prefix_2386.h @@ -1,4 +1,110 @@ #define op_seg(name, seg, opcode_table, normal_opcode_table) \ + static int op##name##_w_a16(uint32_t fetchdat) \ + { \ + int legal; \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (cpu_state.abrt) \ + return 1; \ + cpu_state.pc++; \ + \ + if (in_lock) { \ + legal = is_lock_legal(fetchdat); \ + \ + ILLEGAL_ON(legal == 0); \ + } \ + \ + cpu_state.ea_seg = &seg; \ + cpu_state.ssegs = 1; \ + CLOCK_CYCLES(4); \ + PREFETCH_PREFIX(); \ + \ + if (opcode_table[fetchdat & 0xff]) \ + return opcode_table[fetchdat & 0xff](fetchdat >> 8); \ + return normal_opcode_table[fetchdat & 0xff](fetchdat >> 8); \ + } \ + \ + static int op##name##_l_a16(uint32_t fetchdat) \ + { \ + int legal; \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (cpu_state.abrt) \ + return 1; \ + cpu_state.pc++; \ + \ + if (in_lock) { \ + legal = is_lock_legal(fetchdat); \ + \ + ILLEGAL_ON(legal == 0); \ + } \ + \ + cpu_state.ea_seg = &seg; \ + cpu_state.ssegs = 1; \ + CLOCK_CYCLES(4); \ + PREFETCH_PREFIX(); \ + \ + if (opcode_table[(fetchdat & 0xff) | 0x100]) \ + return opcode_table[(fetchdat & 0xff) | 0x100](fetchdat >> 8); \ + return normal_opcode_table[(fetchdat & 0xff) | 0x100](fetchdat >> 8); \ + } \ + \ + static int op##name##_w_a32(uint32_t fetchdat) \ + { \ + int legal; \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (cpu_state.abrt) \ + return 1; \ + cpu_state.pc++; \ + \ + if (in_lock) { \ + legal = is_lock_legal(fetchdat); \ + \ + ILLEGAL_ON(legal == 0); \ + } \ + \ + cpu_state.ea_seg = &seg; \ + cpu_state.ssegs = 1; \ + CLOCK_CYCLES(4); \ + PREFETCH_PREFIX(); \ + \ + if (opcode_table[(fetchdat & 0xff) | 0x200]) \ + return opcode_table[(fetchdat & 0xff) | 0x200](fetchdat >> 8); \ + return normal_opcode_table[(fetchdat & 0xff) | 0x200](fetchdat >> 8); \ + } \ + \ + static int op##name##_l_a32(uint32_t fetchdat) \ + { \ + int legal; \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (cpu_state.abrt) \ + return 1; \ + cpu_state.pc++; \ + \ + if (in_lock) { \ + legal = is_lock_legal(fetchdat); \ + \ + ILLEGAL_ON(legal == 0); \ + } \ + \ + cpu_state.ea_seg = &seg; \ + cpu_state.ssegs = 1; \ + CLOCK_CYCLES(4); \ + PREFETCH_PREFIX(); \ + \ + if (opcode_table[(fetchdat & 0xff) | 0x300]) \ + return opcode_table[(fetchdat & 0xff) | 0x300](fetchdat >> 8); \ + return normal_opcode_table[(fetchdat & 0xff) | 0x300](fetchdat >> 8); \ + } + +// clang-format off +op_seg(CS, cpu_state.seg_cs, x86_2386_opcodes, x86_2386_opcodes) +op_seg(DS, cpu_state.seg_ds, x86_2386_opcodes, x86_2386_opcodes) +op_seg(ES, cpu_state.seg_es, x86_2386_opcodes, x86_2386_opcodes) +op_seg(FS, cpu_state.seg_fs, x86_2386_opcodes, x86_2386_opcodes) +op_seg(GS, cpu_state.seg_gs, x86_2386_opcodes, x86_2386_opcodes) +op_seg(SS, cpu_state.seg_ss, x86_2386_opcodes, x86_2386_opcodes) + // clang-format on + +#define op_srp(name, seg, opcode_table, normal_opcode_table) \ static int op##name##_w_a16(uint32_t fetchdat) \ { \ fetchdat = fastreadl(cs + cpu_state.pc); \ @@ -68,36 +174,36 @@ } // clang-format off -op_seg(CS, cpu_state.seg_cs, x86_2386_opcodes, x86_2386_opcodes) -op_seg(DS, cpu_state.seg_ds, x86_2386_opcodes, x86_2386_opcodes) -op_seg(ES, cpu_state.seg_es, x86_2386_opcodes, x86_2386_opcodes) -op_seg(FS, cpu_state.seg_fs, x86_2386_opcodes, x86_2386_opcodes) -op_seg(GS, cpu_state.seg_gs, x86_2386_opcodes, x86_2386_opcodes) -op_seg(SS, cpu_state.seg_ss, x86_2386_opcodes, x86_2386_opcodes) +op_srp(CS_REPE, cpu_state.seg_cs, x86_2386_opcodes_REPE, x86_2386_opcodes) +op_srp(DS_REPE, cpu_state.seg_ds, x86_2386_opcodes_REPE, x86_2386_opcodes) +op_srp(ES_REPE, cpu_state.seg_es, x86_2386_opcodes_REPE, x86_2386_opcodes) +op_srp(FS_REPE, cpu_state.seg_fs, x86_2386_opcodes_REPE, x86_2386_opcodes) +op_srp(GS_REPE, cpu_state.seg_gs, x86_2386_opcodes_REPE, x86_2386_opcodes) +op_srp(SS_REPE, cpu_state.seg_ss, x86_2386_opcodes_REPE, x86_2386_opcodes) -op_seg(CS_REPE, cpu_state.seg_cs, x86_2386_opcodes_REPE, x86_2386_opcodes) -op_seg(DS_REPE, cpu_state.seg_ds, x86_2386_opcodes_REPE, x86_2386_opcodes) -op_seg(ES_REPE, cpu_state.seg_es, x86_2386_opcodes_REPE, x86_2386_opcodes) -op_seg(FS_REPE, cpu_state.seg_fs, x86_2386_opcodes_REPE, x86_2386_opcodes) -op_seg(GS_REPE, cpu_state.seg_gs, x86_2386_opcodes_REPE, x86_2386_opcodes) -op_seg(SS_REPE, cpu_state.seg_ss, x86_2386_opcodes_REPE, x86_2386_opcodes) - -op_seg(CS_REPNE, cpu_state.seg_cs, x86_2386_opcodes_REPNE, x86_2386_opcodes) -op_seg(DS_REPNE, cpu_state.seg_ds, x86_2386_opcodes_REPNE, x86_2386_opcodes) -op_seg(ES_REPNE, cpu_state.seg_es, x86_2386_opcodes_REPNE, x86_2386_opcodes) -op_seg(FS_REPNE, cpu_state.seg_fs, x86_2386_opcodes_REPNE, x86_2386_opcodes) -op_seg(GS_REPNE, cpu_state.seg_gs, x86_2386_opcodes_REPNE, x86_2386_opcodes) -op_seg(SS_REPNE, cpu_state.seg_ss, x86_2386_opcodes_REPNE, x86_2386_opcodes) +op_srp(CS_REPNE, cpu_state.seg_cs, x86_2386_opcodes_REPNE, x86_2386_opcodes) +op_srp(DS_REPNE, cpu_state.seg_ds, x86_2386_opcodes_REPNE, x86_2386_opcodes) +op_srp(ES_REPNE, cpu_state.seg_es, x86_2386_opcodes_REPNE, x86_2386_opcodes) +op_srp(FS_REPNE, cpu_state.seg_fs, x86_2386_opcodes_REPNE, x86_2386_opcodes) +op_srp(GS_REPNE, cpu_state.seg_gs, x86_2386_opcodes_REPNE, x86_2386_opcodes) +op_srp(SS_REPNE, cpu_state.seg_ss, x86_2386_opcodes_REPNE, x86_2386_opcodes) // clang-format on static int op_66(uint32_t fetchdat) /*Data size select*/ { + int legal; fetchdat = fastreadl(cs + cpu_state.pc); if (cpu_state.abrt) return 1; cpu_state.pc++; + if (in_lock) { + legal = is_lock_legal(fetchdat); + + ILLEGAL_ON(legal == 0); + } + cpu_state.op32 = ((use32 & 0x100) ^ 0x100) | (cpu_state.op32 & 0x200); CLOCK_CYCLES(2); PREFETCH_PREFIX(); @@ -106,11 +212,18 @@ op_66(uint32_t fetchdat) /*Data size select*/ static int op_67(uint32_t fetchdat) /*Address size select*/ { + int legal; fetchdat = fastreadl(cs + cpu_state.pc); if (cpu_state.abrt) return 1; cpu_state.pc++; + if (in_lock) { + legal = is_lock_legal(fetchdat); + + ILLEGAL_ON(legal == 0); + } + cpu_state.op32 = ((use32 & 0x200) ^ 0x200) | (cpu_state.op32 & 0x100); CLOCK_CYCLES(2); PREFETCH_PREFIX();