Fixed LOCK legality with prefixes, closes #4189.

This commit is contained in:
OBattler
2024-02-23 07:10:15 +01:00
parent 4ee4e8f2b7
commit 6de7c7cd5e
7 changed files with 193 additions and 58 deletions

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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*/

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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();