Split the 286/386 interpreter away from the 486+ one (the 286/386 interpreter does not use the pccache's, readlookup's, and writelookup's as the emulated CPU's are too slow for them to be required, and also has more accurate FPU timings), also added a LPT status read function for future-proofing.
This commit is contained in:
863
src/cpu/x86_ops_rep_2386.h
Normal file
863
src/cpu/x86_ops_rep_2386.h
Normal file
@@ -0,0 +1,863 @@
|
||||
#define REP_OPS(size, CNT_REG, SRC_REG, DEST_REG) \
|
||||
static int opREP_INSB_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int reads = 0, writes = 0, total_cycles = 0; \
|
||||
\
|
||||
addr64 = 0x00000000; \
|
||||
\
|
||||
if (CNT_REG > 0) { \
|
||||
uint8_t temp; \
|
||||
\
|
||||
SEG_CHECK_WRITE(&cpu_state.seg_es); \
|
||||
check_io_perm(DX, 1); \
|
||||
CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG); \
|
||||
high_page = 0; \
|
||||
do_mmut_wb(es, DEST_REG, &addr64); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
temp = inb(DX); \
|
||||
writememb_n(es, DEST_REG, addr64, temp); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
\
|
||||
if (cpu_state.flags & D_FLAG) \
|
||||
DEST_REG--; \
|
||||
else \
|
||||
DEST_REG++; \
|
||||
CNT_REG--; \
|
||||
cycles -= 15; \
|
||||
reads++; \
|
||||
writes++; \
|
||||
total_cycles += 15; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \
|
||||
if (CNT_REG > 0) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
} \
|
||||
static int opREP_INSW_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int reads = 0, writes = 0, total_cycles = 0; \
|
||||
\
|
||||
addr64a[0] = addr64a[1] = 0x00000000; \
|
||||
\
|
||||
if (CNT_REG > 0) { \
|
||||
uint16_t temp; \
|
||||
\
|
||||
SEG_CHECK_WRITE(&cpu_state.seg_es); \
|
||||
check_io_perm(DX, 2); \
|
||||
CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \
|
||||
high_page = 0; \
|
||||
do_mmut_ww(es, DEST_REG, addr64a); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
temp = inw(DX); \
|
||||
writememw_n(es, DEST_REG, addr64a, temp); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
\
|
||||
if (cpu_state.flags & D_FLAG) \
|
||||
DEST_REG -= 2; \
|
||||
else \
|
||||
DEST_REG += 2; \
|
||||
CNT_REG--; \
|
||||
cycles -= 15; \
|
||||
reads++; \
|
||||
writes++; \
|
||||
total_cycles += 15; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \
|
||||
if (CNT_REG > 0) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
} \
|
||||
static int opREP_INSL_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int reads = 0, writes = 0, total_cycles = 0; \
|
||||
\
|
||||
addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; \
|
||||
\
|
||||
if (CNT_REG > 0) { \
|
||||
uint32_t temp; \
|
||||
\
|
||||
SEG_CHECK_WRITE(&cpu_state.seg_es); \
|
||||
check_io_perm(DX, 4); \
|
||||
CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \
|
||||
high_page = 0; \
|
||||
do_mmut_wl(es, DEST_REG, addr64a); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
temp = inl(DX); \
|
||||
writememl_n(es, DEST_REG, addr64a, temp); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
\
|
||||
if (cpu_state.flags & D_FLAG) \
|
||||
DEST_REG -= 4; \
|
||||
else \
|
||||
DEST_REG += 4; \
|
||||
CNT_REG--; \
|
||||
cycles -= 15; \
|
||||
reads++; \
|
||||
writes++; \
|
||||
total_cycles += 15; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, writes, 0); \
|
||||
if (CNT_REG > 0) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
} \
|
||||
\
|
||||
static int opREP_OUTSB_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int reads = 0, writes = 0, total_cycles = 0; \
|
||||
\
|
||||
if (CNT_REG > 0) { \
|
||||
uint8_t temp; \
|
||||
SEG_CHECK_READ(cpu_state.ea_seg); \
|
||||
CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG); \
|
||||
temp = readmemb(cpu_state.ea_seg->base, SRC_REG); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
check_io_perm(DX, 1); \
|
||||
outb(DX, temp); \
|
||||
if (cpu_state.flags & D_FLAG) \
|
||||
SRC_REG--; \
|
||||
else \
|
||||
SRC_REG++; \
|
||||
CNT_REG--; \
|
||||
cycles -= 14; \
|
||||
reads++; \
|
||||
writes++; \
|
||||
total_cycles += 14; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \
|
||||
if (CNT_REG > 0) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
} \
|
||||
static int opREP_OUTSW_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int reads = 0, writes = 0, total_cycles = 0; \
|
||||
\
|
||||
if (CNT_REG > 0) { \
|
||||
uint16_t temp; \
|
||||
SEG_CHECK_READ(cpu_state.ea_seg); \
|
||||
CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 1UL); \
|
||||
temp = readmemw(cpu_state.ea_seg->base, SRC_REG); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
check_io_perm(DX, 2); \
|
||||
outw(DX, temp); \
|
||||
if (cpu_state.flags & D_FLAG) \
|
||||
SRC_REG -= 2; \
|
||||
else \
|
||||
SRC_REG += 2; \
|
||||
CNT_REG--; \
|
||||
cycles -= 14; \
|
||||
reads++; \
|
||||
writes++; \
|
||||
total_cycles += 14; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \
|
||||
if (CNT_REG > 0) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
} \
|
||||
static int opREP_OUTSL_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int reads = 0, writes = 0, total_cycles = 0; \
|
||||
\
|
||||
if (CNT_REG > 0) { \
|
||||
uint32_t temp; \
|
||||
SEG_CHECK_READ(cpu_state.ea_seg); \
|
||||
CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 3UL); \
|
||||
temp = readmeml(cpu_state.ea_seg->base, SRC_REG); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
check_io_perm(DX, 4); \
|
||||
outl(DX, temp); \
|
||||
if (cpu_state.flags & D_FLAG) \
|
||||
SRC_REG -= 4; \
|
||||
else \
|
||||
SRC_REG += 4; \
|
||||
CNT_REG--; \
|
||||
cycles -= 14; \
|
||||
reads++; \
|
||||
writes++; \
|
||||
total_cycles += 14; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, writes, 0); \
|
||||
if (CNT_REG > 0) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
} \
|
||||
\
|
||||
static int opREP_MOVSB_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int reads = 0, writes = 0, total_cycles = 0; \
|
||||
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
|
||||
addr64 = addr64_2 = 0x00000000; \
|
||||
if (trap) \
|
||||
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
|
||||
if (CNT_REG > 0) { \
|
||||
SEG_CHECK_READ(cpu_state.ea_seg); \
|
||||
SEG_CHECK_WRITE(&cpu_state.seg_es); \
|
||||
} \
|
||||
while (CNT_REG > 0) { \
|
||||
uint8_t temp; \
|
||||
\
|
||||
CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG); \
|
||||
CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \
|
||||
high_page = 0; \
|
||||
do_mmut_rb(cpu_state.ea_seg->base, SRC_REG, &addr64); \
|
||||
if (cpu_state.abrt) \
|
||||
break; \
|
||||
do_mmut_wb(es, DEST_REG, &addr64_2); \
|
||||
if (cpu_state.abrt) \
|
||||
break; \
|
||||
temp = readmemb_n(cpu_state.ea_seg->base, SRC_REG, addr64); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
writememb_n(es, DEST_REG, addr64_2, temp); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
\
|
||||
if (cpu_state.flags & D_FLAG) { \
|
||||
DEST_REG--; \
|
||||
SRC_REG--; \
|
||||
} else { \
|
||||
DEST_REG++; \
|
||||
SRC_REG++; \
|
||||
} \
|
||||
CNT_REG--; \
|
||||
cycles -= is486 ? 3 : 4; \
|
||||
reads++; \
|
||||
writes++; \
|
||||
total_cycles += is486 ? 3 : 4; \
|
||||
if (cycles < cycles_end) \
|
||||
break; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \
|
||||
if (CNT_REG > 0) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
} \
|
||||
static int opREP_MOVSW_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int reads = 0, writes = 0, total_cycles = 0; \
|
||||
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
|
||||
addr64a[0] = addr64a[1] = 0x00000000; \
|
||||
addr64a_2[0] = addr64a_2[1] = 0x00000000; \
|
||||
if (trap) \
|
||||
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
|
||||
if (CNT_REG > 0) { \
|
||||
SEG_CHECK_READ(cpu_state.ea_seg); \
|
||||
SEG_CHECK_WRITE(&cpu_state.seg_es); \
|
||||
} \
|
||||
while (CNT_REG > 0) { \
|
||||
uint16_t temp; \
|
||||
\
|
||||
CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 1UL); \
|
||||
CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \
|
||||
high_page = 0; \
|
||||
do_mmut_rw(cpu_state.ea_seg->base, SRC_REG, addr64a); \
|
||||
if (cpu_state.abrt) \
|
||||
break; \
|
||||
do_mmut_ww(es, DEST_REG, addr64a_2); \
|
||||
if (cpu_state.abrt) \
|
||||
break; \
|
||||
temp = readmemw_n(cpu_state.ea_seg->base, SRC_REG, addr64a); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
writememw_n(es, DEST_REG, addr64a_2, temp); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
\
|
||||
if (cpu_state.flags & D_FLAG) { \
|
||||
DEST_REG -= 2; \
|
||||
SRC_REG -= 2; \
|
||||
} else { \
|
||||
DEST_REG += 2; \
|
||||
SRC_REG += 2; \
|
||||
} \
|
||||
CNT_REG--; \
|
||||
cycles -= is486 ? 3 : 4; \
|
||||
reads++; \
|
||||
writes++; \
|
||||
total_cycles += is486 ? 3 : 4; \
|
||||
if (cycles < cycles_end) \
|
||||
break; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \
|
||||
if (CNT_REG > 0) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
} \
|
||||
static int opREP_MOVSL_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int reads = 0, writes = 0, total_cycles = 0; \
|
||||
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
|
||||
addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; \
|
||||
addr64a_2[0] = addr64a_2[1] = addr64a_2[2] = addr64a_2[3] = 0x00000000; \
|
||||
if (trap) \
|
||||
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
|
||||
if (CNT_REG > 0) { \
|
||||
SEG_CHECK_READ(cpu_state.ea_seg); \
|
||||
SEG_CHECK_WRITE(&cpu_state.seg_es); \
|
||||
} \
|
||||
while (CNT_REG > 0) { \
|
||||
uint32_t temp; \
|
||||
\
|
||||
CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 3UL); \
|
||||
CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \
|
||||
high_page = 0; \
|
||||
do_mmut_rl(cpu_state.ea_seg->base, SRC_REG, addr64a); \
|
||||
if (cpu_state.abrt) \
|
||||
break; \
|
||||
do_mmut_wl(es, DEST_REG, addr64a_2); \
|
||||
if (cpu_state.abrt) \
|
||||
break; \
|
||||
temp = readmeml_n(cpu_state.ea_seg->base, SRC_REG, addr64a); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
writememl_n(es, DEST_REG, addr64a_2, temp); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
\
|
||||
if (cpu_state.flags & D_FLAG) { \
|
||||
DEST_REG -= 4; \
|
||||
SRC_REG -= 4; \
|
||||
} else { \
|
||||
DEST_REG += 4; \
|
||||
SRC_REG += 4; \
|
||||
} \
|
||||
CNT_REG--; \
|
||||
cycles -= is486 ? 3 : 4; \
|
||||
reads++; \
|
||||
writes++; \
|
||||
total_cycles += is486 ? 3 : 4; \
|
||||
if (cycles < cycles_end) \
|
||||
break; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \
|
||||
if (CNT_REG > 0) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
} \
|
||||
\
|
||||
static int opREP_STOSB_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int writes = 0, total_cycles = 0; \
|
||||
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
|
||||
if (trap) \
|
||||
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
|
||||
if (CNT_REG > 0) \
|
||||
SEG_CHECK_WRITE(&cpu_state.seg_es); \
|
||||
while (CNT_REG > 0) { \
|
||||
CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \
|
||||
writememb(es, DEST_REG, AL); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
if (cpu_state.flags & D_FLAG) \
|
||||
DEST_REG--; \
|
||||
else \
|
||||
DEST_REG++; \
|
||||
CNT_REG--; \
|
||||
cycles -= is486 ? 4 : 5; \
|
||||
writes++; \
|
||||
total_cycles += is486 ? 4 : 5; \
|
||||
if (cycles < cycles_end) \
|
||||
break; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, 0, 0, writes, 0, 0); \
|
||||
if (CNT_REG > 0) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
} \
|
||||
static int opREP_STOSW_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int writes = 0, total_cycles = 0; \
|
||||
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
|
||||
if (trap) \
|
||||
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
|
||||
if (CNT_REG > 0) \
|
||||
SEG_CHECK_WRITE(&cpu_state.seg_es); \
|
||||
while (CNT_REG > 0) { \
|
||||
CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \
|
||||
writememw(es, DEST_REG, AX); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
if (cpu_state.flags & D_FLAG) \
|
||||
DEST_REG -= 2; \
|
||||
else \
|
||||
DEST_REG += 2; \
|
||||
CNT_REG--; \
|
||||
cycles -= is486 ? 4 : 5; \
|
||||
writes++; \
|
||||
total_cycles += is486 ? 4 : 5; \
|
||||
if (cycles < cycles_end) \
|
||||
break; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, 0, 0, writes, 0, 0); \
|
||||
if (CNT_REG > 0) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
} \
|
||||
static int opREP_STOSL_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int writes = 0, total_cycles = 0; \
|
||||
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
|
||||
if (trap) \
|
||||
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
|
||||
if (CNT_REG > 0) \
|
||||
SEG_CHECK_WRITE(&cpu_state.seg_es); \
|
||||
while (CNT_REG > 0) { \
|
||||
CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \
|
||||
writememl(es, DEST_REG, EAX); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
if (cpu_state.flags & D_FLAG) \
|
||||
DEST_REG -= 4; \
|
||||
else \
|
||||
DEST_REG += 4; \
|
||||
CNT_REG--; \
|
||||
cycles -= is486 ? 4 : 5; \
|
||||
writes++; \
|
||||
total_cycles += is486 ? 4 : 5; \
|
||||
if (cycles < cycles_end) \
|
||||
break; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, 0, 0, 0, writes, 0); \
|
||||
if (CNT_REG > 0) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
} \
|
||||
\
|
||||
static int opREP_LODSB_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int reads = 0, total_cycles = 0; \
|
||||
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
|
||||
if (trap) \
|
||||
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
|
||||
if (CNT_REG > 0) \
|
||||
SEG_CHECK_READ(cpu_state.ea_seg); \
|
||||
while (CNT_REG > 0) { \
|
||||
CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG); \
|
||||
AL = readmemb(cpu_state.ea_seg->base, SRC_REG); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
if (cpu_state.flags & D_FLAG) \
|
||||
SRC_REG--; \
|
||||
else \
|
||||
SRC_REG++; \
|
||||
CNT_REG--; \
|
||||
cycles -= is486 ? 4 : 5; \
|
||||
reads++; \
|
||||
total_cycles += is486 ? 4 : 5; \
|
||||
if (cycles < cycles_end) \
|
||||
break; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \
|
||||
if (CNT_REG > 0) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
} \
|
||||
static int opREP_LODSW_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int reads = 0, total_cycles = 0; \
|
||||
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
|
||||
if (trap) \
|
||||
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
|
||||
if (CNT_REG > 0) \
|
||||
SEG_CHECK_READ(cpu_state.ea_seg); \
|
||||
while (CNT_REG > 0) { \
|
||||
CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 1UL); \
|
||||
AX = readmemw(cpu_state.ea_seg->base, SRC_REG); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
if (cpu_state.flags & D_FLAG) \
|
||||
SRC_REG -= 2; \
|
||||
else \
|
||||
SRC_REG += 2; \
|
||||
CNT_REG--; \
|
||||
cycles -= is486 ? 4 : 5; \
|
||||
reads++; \
|
||||
total_cycles += is486 ? 4 : 5; \
|
||||
if (cycles < cycles_end) \
|
||||
break; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \
|
||||
if (CNT_REG > 0) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
} \
|
||||
static int opREP_LODSL_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int reads = 0, total_cycles = 0; \
|
||||
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
|
||||
if (trap) \
|
||||
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
|
||||
if (CNT_REG > 0) \
|
||||
SEG_CHECK_READ(cpu_state.ea_seg); \
|
||||
while (CNT_REG > 0) { \
|
||||
CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 3UL); \
|
||||
EAX = readmeml(cpu_state.ea_seg->base, SRC_REG); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
if (cpu_state.flags & D_FLAG) \
|
||||
SRC_REG -= 4; \
|
||||
else \
|
||||
SRC_REG += 4; \
|
||||
CNT_REG--; \
|
||||
cycles -= is486 ? 4 : 5; \
|
||||
reads++; \
|
||||
total_cycles += is486 ? 4 : 5; \
|
||||
if (cycles < cycles_end) \
|
||||
break; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, 0, 0); \
|
||||
if (CNT_REG > 0) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
}
|
||||
|
||||
#define CHEK_READ(a, b, c)
|
||||
|
||||
#define REP_OPS_CMPS_SCAS(size, CNT_REG, SRC_REG, DEST_REG, FV) \
|
||||
static int opREP_CMPSB_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int reads = 0, total_cycles = 0, tempz; \
|
||||
\
|
||||
addr64 = addr64_2 = 0x00000000; \
|
||||
\
|
||||
tempz = FV; \
|
||||
if ((CNT_REG > 0) && (FV == tempz)) { \
|
||||
uint8_t temp, temp2; \
|
||||
SEG_CHECK_READ(cpu_state.ea_seg); \
|
||||
SEG_CHECK_READ(&cpu_state.seg_es); \
|
||||
CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG); \
|
||||
CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG); \
|
||||
high_page = uncached = 0; \
|
||||
do_mmut_rb(cpu_state.ea_seg->base, SRC_REG, &addr64); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
do_mmut_rb2(es, DEST_REG, &addr64_2); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
temp = readmemb_n(cpu_state.ea_seg->base, SRC_REG, addr64); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
temp2 = readmemb_n(es, DEST_REG, addr64_2); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
\
|
||||
if (cpu_state.flags & D_FLAG) { \
|
||||
DEST_REG--; \
|
||||
SRC_REG--; \
|
||||
} else { \
|
||||
DEST_REG++; \
|
||||
SRC_REG++; \
|
||||
} \
|
||||
CNT_REG--; \
|
||||
cycles -= is486 ? 7 : 9; \
|
||||
reads += 2; \
|
||||
total_cycles += is486 ? 7 : 9; \
|
||||
setsub8(temp, temp2); \
|
||||
tempz = (ZF_SET()) ? 1 : 0; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \
|
||||
if ((CNT_REG > 0) && (FV == tempz)) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
} \
|
||||
static int opREP_CMPSW_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int reads = 0, total_cycles = 0, tempz; \
|
||||
\
|
||||
addr64a[0] = addr64a[1] = 0x00000000; \
|
||||
addr64a_2[0] = addr64a_2[1] = 0x00000000; \
|
||||
\
|
||||
tempz = FV; \
|
||||
if ((CNT_REG > 0) && (FV == tempz)) { \
|
||||
uint16_t temp, temp2; \
|
||||
SEG_CHECK_READ(cpu_state.ea_seg); \
|
||||
SEG_CHECK_READ(&cpu_state.seg_es); \
|
||||
CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 1UL); \
|
||||
CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \
|
||||
high_page = uncached = 0; \
|
||||
do_mmut_rw(cpu_state.ea_seg->base, SRC_REG, addr64a); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
do_mmut_rw2(es, DEST_REG, addr64a_2); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
temp = readmemw_n(cpu_state.ea_seg->base, SRC_REG, addr64a); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
temp2 = readmemw_n(es, DEST_REG, addr64a_2); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
\
|
||||
if (cpu_state.flags & D_FLAG) { \
|
||||
DEST_REG -= 2; \
|
||||
SRC_REG -= 2; \
|
||||
} else { \
|
||||
DEST_REG += 2; \
|
||||
SRC_REG += 2; \
|
||||
} \
|
||||
CNT_REG--; \
|
||||
cycles -= is486 ? 7 : 9; \
|
||||
reads += 2; \
|
||||
total_cycles += is486 ? 7 : 9; \
|
||||
setsub16(temp, temp2); \
|
||||
tempz = (ZF_SET()) ? 1 : 0; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \
|
||||
if ((CNT_REG > 0) && (FV == tempz)) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
} \
|
||||
static int opREP_CMPSL_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int reads = 0, total_cycles = 0, tempz; \
|
||||
\
|
||||
addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; \
|
||||
addr64a_2[0] = addr64a_2[1] = addr64a_2[2] = addr64a_2[3] = 0x00000000; \
|
||||
\
|
||||
tempz = FV; \
|
||||
if ((CNT_REG > 0) && (FV == tempz)) { \
|
||||
uint32_t temp, temp2; \
|
||||
SEG_CHECK_READ(cpu_state.ea_seg); \
|
||||
SEG_CHECK_READ(&cpu_state.seg_es); \
|
||||
CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 3UL); \
|
||||
CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \
|
||||
high_page = uncached = 0; \
|
||||
do_mmut_rl(cpu_state.ea_seg->base, SRC_REG, addr64a); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
do_mmut_rl2(es, DEST_REG, addr64a_2); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
temp = readmeml_n(cpu_state.ea_seg->base, SRC_REG, addr64a); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
temp2 = readmeml_n(es, DEST_REG, addr64a_2); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
\
|
||||
if (cpu_state.flags & D_FLAG) { \
|
||||
DEST_REG -= 4; \
|
||||
SRC_REG -= 4; \
|
||||
} else { \
|
||||
DEST_REG += 4; \
|
||||
SRC_REG += 4; \
|
||||
} \
|
||||
CNT_REG--; \
|
||||
cycles -= is486 ? 7 : 9; \
|
||||
reads += 2; \
|
||||
total_cycles += is486 ? 7 : 9; \
|
||||
setsub32(temp, temp2); \
|
||||
tempz = (ZF_SET()) ? 1 : 0; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, 0, 0); \
|
||||
if ((CNT_REG > 0) && (FV == tempz)) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
} \
|
||||
\
|
||||
static int opREP_SCASB_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int reads = 0, total_cycles = 0, tempz; \
|
||||
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
|
||||
if (trap) \
|
||||
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
|
||||
tempz = FV; \
|
||||
if ((CNT_REG > 0) && (FV == tempz)) \
|
||||
SEG_CHECK_READ(&cpu_state.seg_es); \
|
||||
while ((CNT_REG > 0) && (FV == tempz)) { \
|
||||
CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \
|
||||
uint8_t temp = readmemb(es, DEST_REG); \
|
||||
if (cpu_state.abrt) \
|
||||
break; \
|
||||
setsub8(AL, temp); \
|
||||
tempz = (ZF_SET()) ? 1 : 0; \
|
||||
if (cpu_state.flags & D_FLAG) \
|
||||
DEST_REG--; \
|
||||
else \
|
||||
DEST_REG++; \
|
||||
CNT_REG--; \
|
||||
cycles -= is486 ? 5 : 8; \
|
||||
reads++; \
|
||||
total_cycles += is486 ? 5 : 8; \
|
||||
if (cycles < cycles_end) \
|
||||
break; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \
|
||||
if ((CNT_REG > 0) && (FV == tempz)) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
} \
|
||||
static int opREP_SCASW_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int reads = 0, total_cycles = 0, tempz; \
|
||||
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
|
||||
if (trap) \
|
||||
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
|
||||
tempz = FV; \
|
||||
if ((CNT_REG > 0) && (FV == tempz)) \
|
||||
SEG_CHECK_READ(&cpu_state.seg_es); \
|
||||
while ((CNT_REG > 0) && (FV == tempz)) { \
|
||||
CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \
|
||||
uint16_t temp = readmemw(es, DEST_REG); \
|
||||
if (cpu_state.abrt) \
|
||||
break; \
|
||||
setsub16(AX, temp); \
|
||||
tempz = (ZF_SET()) ? 1 : 0; \
|
||||
if (cpu_state.flags & D_FLAG) \
|
||||
DEST_REG -= 2; \
|
||||
else \
|
||||
DEST_REG += 2; \
|
||||
CNT_REG--; \
|
||||
cycles -= is486 ? 5 : 8; \
|
||||
reads++; \
|
||||
total_cycles += is486 ? 5 : 8; \
|
||||
if (cycles < cycles_end) \
|
||||
break; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \
|
||||
if ((CNT_REG > 0) && (FV == tempz)) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
} \
|
||||
static int opREP_SCASL_##size(uint32_t fetchdat) \
|
||||
{ \
|
||||
int reads = 0, total_cycles = 0, tempz; \
|
||||
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
|
||||
if (trap) \
|
||||
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
|
||||
tempz = FV; \
|
||||
if ((CNT_REG > 0) && (FV == tempz)) \
|
||||
SEG_CHECK_READ(&cpu_state.seg_es); \
|
||||
while ((CNT_REG > 0) && (FV == tempz)) { \
|
||||
CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \
|
||||
uint32_t temp = readmeml(es, DEST_REG); \
|
||||
if (cpu_state.abrt) \
|
||||
break; \
|
||||
setsub32(EAX, temp); \
|
||||
tempz = (ZF_SET()) ? 1 : 0; \
|
||||
if (cpu_state.flags & D_FLAG) \
|
||||
DEST_REG -= 4; \
|
||||
else \
|
||||
DEST_REG += 4; \
|
||||
CNT_REG--; \
|
||||
cycles -= is486 ? 5 : 8; \
|
||||
reads++; \
|
||||
total_cycles += is486 ? 5 : 8; \
|
||||
if (cycles < cycles_end) \
|
||||
break; \
|
||||
} \
|
||||
PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, 0, 0); \
|
||||
if ((CNT_REG > 0) && (FV == tempz)) { \
|
||||
CPU_BLOCK_END(); \
|
||||
cpu_state.pc = cpu_state.oldpc; \
|
||||
return 1; \
|
||||
} \
|
||||
return cpu_state.abrt; \
|
||||
}
|
||||
|
||||
REP_OPS(a16, CX, SI, DI)
|
||||
REP_OPS(a32, ECX, ESI, EDI)
|
||||
REP_OPS_CMPS_SCAS(a16_NE, CX, SI, DI, 0)
|
||||
REP_OPS_CMPS_SCAS(a16_E, CX, SI, DI, 1)
|
||||
REP_OPS_CMPS_SCAS(a32_NE, ECX, ESI, EDI, 0)
|
||||
REP_OPS_CMPS_SCAS(a32_E, ECX, ESI, EDI, 1)
|
||||
|
||||
static int
|
||||
opREPNE(uint32_t fetchdat)
|
||||
{
|
||||
fetchdat = fastreadl(cs + cpu_state.pc);
|
||||
if (cpu_state.abrt)
|
||||
return 1;
|
||||
cpu_state.pc++;
|
||||
|
||||
CLOCK_CYCLES(2);
|
||||
PREFETCH_PREFIX();
|
||||
if (x86_2386_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32])
|
||||
return x86_2386_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8);
|
||||
return x86_2386_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8);
|
||||
}
|
||||
static int
|
||||
opREPE(uint32_t fetchdat)
|
||||
{
|
||||
fetchdat = fastreadl(cs + cpu_state.pc);
|
||||
if (cpu_state.abrt)
|
||||
return 1;
|
||||
cpu_state.pc++;
|
||||
|
||||
CLOCK_CYCLES(2);
|
||||
PREFETCH_PREFIX();
|
||||
if (x86_2386_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32])
|
||||
return x86_2386_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8);
|
||||
return x86_2386_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8);
|
||||
}
|
||||
Reference in New Issue
Block a user