Fixed LOCK legality with prefixes, closes #4189.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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*/
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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();
|
||||
|
Reference in New Issue
Block a user