Added prefetch timing approximation for 286/386 CPUs, with configurable memory timing.

This commit is contained in:
SarahW 2016-11-25 21:32:02 +00:00
commit 1b73963997
33 changed files with 1139 additions and 261 deletions

View file

@ -274,6 +274,89 @@ void x86illegal()
x86_int(6);
}
/*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
from the total cycles taken
- Any remaining cycles are used to refill the prefetch queue.
Note that this is only used for 286 / 386 systems. It is disabled when the
internal cache on 486+ CPUs is enabled.
*/
static int prefetch_bytes = 0;
static int prefetch_prefixes = 0;
static void prefetch_run(int instr_cycles, int bytes, int modrm, int reads, int reads_l, int writes, int writes_l, int ea32)
{
int mem_cycles = reads*cpu_cycles_read + reads_l*cpu_cycles_read_l + writes*cpu_cycles_write + writes_l*cpu_cycles_write_l;
if (instr_cycles < mem_cycles)
instr_cycles = mem_cycles;
prefetch_bytes -= prefetch_prefixes;
prefetch_bytes -= bytes;
if (modrm != -1)
{
if (ea32)
{
if ((modrm & 7) == 4)
{
if ((modrm & 0x700) == 0x500)
prefetch_bytes -= 5;
else if ((modrm & 0xc0) == 0x40)
prefetch_bytes -= 2;
else if ((modrm & 0xc0) == 0x80)
prefetch_bytes -= 5;
}
else
{
if ((modrm & 0xc7) == 0x05)
prefetch_bytes -= 4;
else if ((modrm & 0xc0) == 0x40)
prefetch_bytes--;
else if ((modrm & 0xc0) == 0x80)
prefetch_bytes -= 4;
}
}
else
{
if ((modrm & 0xc7) == 0x06)
prefetch_bytes -= 2;
else if ((modrm & 0xc0) != 0xc0)
prefetch_bytes -= ((modrm & 0xc0) >> 6);
}
}
/* Fill up prefetch queue */
while (prefetch_bytes < 0)
{
prefetch_bytes += cpu_prefetch_width;
cycles -= cpu_prefetch_cycles;
}
/* Subtract cycles used for memory access by instruction */
instr_cycles -= mem_cycles;
while (instr_cycles >= cpu_prefetch_cycles)
{
prefetch_bytes += cpu_prefetch_width;
instr_cycles -= cpu_prefetch_cycles;
}
prefetch_prefixes = 0;
}
static void prefetch_flush()
{
prefetch_bytes = 0;
}
#define PREFETCH_RUN(instr_cycles, bytes, modrm, reads, reads_l, writes, writes_l, ea32) \
do { if (cpu_prefetch_cycles) prefetch_run(instr_cycles, bytes, modrm, reads, reads_l, writes, writes_l, ea32); } while (0)
#define PREFETCH_PREFIX() prefetch_prefixes++
#define PREFETCH_FLUSH() prefetch_flush()
int rep386(int fv)
{
@ -291,6 +374,7 @@ int rep386(int fv)
that high frequency timers still work okay. This amount is different
for interpreter and recompiler*/
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100);
int reads = 0, reads_l = 0, writes = 0, writes_l = 0, total_cycles = 0;
if (trap)
cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/
@ -319,28 +403,36 @@ int rep386(int fv)
break;
case 0x26: case 0x126: case 0x226: case 0x326: /*ES:*/
cpu_state.ea_seg = &_es;
PREFETCH_PREFIX();
goto startrep;
break;
case 0x2E: case 0x12E: case 0x22E: case 0x32E: /*CS:*/
cpu_state.ea_seg = &_cs;
PREFETCH_PREFIX();
goto startrep;
case 0x36: case 0x136: case 0x236: case 0x336: /*SS:*/
cpu_state.ea_seg = &_ss;
PREFETCH_PREFIX();
goto startrep;
case 0x3E: case 0x13E: case 0x23E: case 0x33E: /*DS:*/
cpu_state.ea_seg = &_ds;
PREFETCH_PREFIX();
goto startrep;
case 0x64: case 0x164: case 0x264: case 0x364: /*FS:*/
cpu_state.ea_seg = &_fs;
PREFETCH_PREFIX();
goto startrep;
case 0x65: case 0x165: case 0x265: case 0x365: /*GS:*/
cpu_state.ea_seg = &_gs;
PREFETCH_PREFIX();
goto startrep;
case 0x66: case 0x166: case 0x266: case 0x366: /*Data size prefix*/
rep32 = (rep32 & 0x200) | ((use32 ^ 0x100) & 0x100);
PREFETCH_PREFIX();
goto startrep;
case 0x67: case 0x167: case 0x267: case 0x367: /*Address size prefix*/
rep32 = (rep32 & 0x100) | ((use32 ^ 0x200) & 0x200);
PREFETCH_PREFIX();
goto startrep;
case 0x6C: case 0x16C: /*REP INSB*/
// cpu_notreps++;
@ -354,6 +446,7 @@ int rep386(int fv)
else DI++;
c--;
cycles-=15;
reads++; writes++; total_cycles += 15;
}
if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; }
else firstrepcycle=1;
@ -370,6 +463,7 @@ int rep386(int fv)
else EDI++;
c--;
cycles-=15;
reads++; writes++; total_cycles += 15;
}
if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; }
else firstrepcycle=1;
@ -386,6 +480,7 @@ int rep386(int fv)
else DI+=2;
c--;
cycles-=15;
reads++; writes++; total_cycles += 15;
}
if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; }
else firstrepcycle=1;
@ -401,6 +496,7 @@ int rep386(int fv)
else DI+=4;
c--;
cycles-=15;
reads_l++; writes_l++; total_cycles += 15;
}
if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; }
else firstrepcycle=1;
@ -416,6 +512,7 @@ int rep386(int fv)
else EDI+=2;
c--;
cycles-=15;
reads++; writes++; total_cycles += 15;
}
if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; }
else firstrepcycle=1;
@ -431,6 +528,7 @@ int rep386(int fv)
else EDI+=4;
c--;
cycles-=15;
reads_l++; writes_l++; total_cycles += 15;
}
if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; }
else firstrepcycle=1;
@ -447,6 +545,7 @@ int rep386(int fv)
else SI++;
c--;
cycles-=14;
reads++; writes++; total_cycles += 14;
}
if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; }
else firstrepcycle=1;
@ -463,6 +562,7 @@ int rep386(int fv)
else ESI++;
c--;
cycles-=14;
reads++; writes++; total_cycles += 14;
}
if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; }
else firstrepcycle=1;
@ -479,6 +579,7 @@ int rep386(int fv)
else SI+=2;
c--;
cycles-=14;
reads++; writes++; total_cycles += 14;
}
if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; }
else firstrepcycle=1;
@ -494,6 +595,7 @@ int rep386(int fv)
else SI += 4;
c--;
cycles -= 14;
reads_l++; writes_l++; total_cycles += 14;
}
if (c > 0) { firstrepcycle = 0; cpu_state.pc = ipc; }
else firstrepcycle = 1;
@ -509,6 +611,7 @@ int rep386(int fv)
else ESI+=2;
c--;
cycles-=14;
reads++; writes++; total_cycles += 14;
}
if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; }
else firstrepcycle=1;
@ -524,6 +627,7 @@ int rep386(int fv)
else ESI += 4;
c--;
cycles -= 14;
reads_l++; writes_l++; total_cycles += 14;
}
if (c > 0) { firstrepcycle = 0; cpu_state.pc = ipc; }
else firstrepcycle = 1;
@ -544,6 +648,7 @@ int rep386(int fv)
c--;
cycles-=(is486)?3:4;
ins++;
reads++; writes++; total_cycles += is486 ? 3 : 4;
if (cycles < cycles_end)
break;
}
@ -562,6 +667,7 @@ int rep386(int fv)
c--;
cycles-=(is486)?3:4;
ins++;
reads++; writes++; total_cycles += is486 ? 3 : 4;
if (cycles < cycles_end)
break;
}
@ -580,6 +686,7 @@ int rep386(int fv)
c--;
cycles-=(is486)?3:4;
ins++;
reads++; writes++; total_cycles += is486 ? 3 : 4;
if (cycles < cycles_end)
break;
}
@ -599,6 +706,7 @@ int rep386(int fv)
c--;
cycles-=(is486)?3:4;
ins++;
reads_l++; writes_l++; total_cycles += is486 ? 3 : 4;
if (cycles < cycles_end)
break;
}
@ -618,6 +726,7 @@ int rep386(int fv)
c--;
cycles-=(is486)?3:4;
ins++;
reads++; writes++; total_cycles += is486 ? 3 : 4;
if (cycles < cycles_end)
break;
}
@ -638,6 +747,7 @@ int rep386(int fv)
c--;
cycles-=(is486)?3:4;
ins++;
reads_l++; writes_l++; total_cycles += is486 ? 3 : 4;
if (cycles < cycles_end)
break;
}
@ -657,6 +767,7 @@ int rep386(int fv)
else { DI++; SI++; }
c--;
cycles-=(is486)?7:9;
reads += 2; total_cycles += is486 ? 7 : 9;
setsub8(temp,temp2);
tempz = (ZF_SET()) ? 1 : 0;
}
@ -675,6 +786,7 @@ int rep386(int fv)
else { EDI++; ESI++; }
c--;
cycles-=(is486)?7:9;
reads += 2; total_cycles += is486 ? 7 : 9;
setsub8(temp,temp2);
tempz = (ZF_SET()) ? 1 : 0;
}
@ -696,6 +808,7 @@ int rep386(int fv)
else { DI+=2; SI+=2; }
c--;
cycles-=(is486)?7:9;
reads += 2; total_cycles += is486 ? 7 : 9;
setsub16(tempw,tempw2);
tempz = (ZF_SET()) ? 1 : 0;
}
@ -714,6 +827,7 @@ int rep386(int fv)
else { DI+=4; SI+=4; }
c--;
cycles-=(is486)?7:9;
reads_l += 2; total_cycles += is486 ? 7 : 9;
setsub32(templ,templ2);
tempz = (ZF_SET()) ? 1 : 0;
}
@ -732,6 +846,7 @@ int rep386(int fv)
else { EDI+=2; ESI+=2; }
c--;
cycles-=(is486)?7:9;
reads += 2; total_cycles += is486 ? 7 : 9;
setsub16(tempw,tempw2);
tempz = (ZF_SET()) ? 1 : 0;
}
@ -750,6 +865,7 @@ int rep386(int fv)
else { EDI+=4; ESI+=4; }
c--;
cycles-=(is486)?7:9;
reads_l += 2; total_cycles += is486 ? 7 : 9;
setsub32(templ,templ2);
tempz = (ZF_SET()) ? 1 : 0;
}
@ -767,6 +883,7 @@ int rep386(int fv)
else DI++;
c--;
cycles-=(is486)?4:5;
writes++; total_cycles += is486 ? 4 : 5;
ins++;
if (cycles < cycles_end)
break;
@ -785,6 +902,7 @@ int rep386(int fv)
else EDI++;
c--;
cycles-=(is486)?4:5;
writes++; total_cycles += is486 ? 4 : 5;
ins++;
if (cycles < cycles_end)
break;
@ -803,6 +921,7 @@ int rep386(int fv)
else DI+=2;
c--;
cycles-=(is486)?4:5;
writes++; total_cycles += is486 ? 4 : 5;
ins++;
if (cycles < cycles_end)
break;
@ -821,6 +940,7 @@ int rep386(int fv)
else EDI+=2;
c--;
cycles-=(is486)?4:5;
writes++; total_cycles += is486 ? 4 : 5;
ins++;
if (cycles < cycles_end)
break;
@ -839,6 +959,7 @@ int rep386(int fv)
else DI+=4;
c--;
cycles-=(is486)?4:5;
writes_l++; total_cycles += is486 ? 4 : 5;
ins++;
if (cycles < cycles_end)
break;
@ -857,6 +978,7 @@ int rep386(int fv)
else EDI+=4;
c--;
cycles-=(is486)?4:5;
writes_l++; total_cycles += is486 ? 4 : 5;
ins++;
if (cycles < cycles_end)
break;
@ -876,6 +998,7 @@ int rep386(int fv)
else SI++;
c--;
cycles-=5;
reads++; total_cycles += 5;
}
if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; }
else firstrepcycle=1;
@ -891,6 +1014,7 @@ int rep386(int fv)
else ESI++;
c--;
cycles-=5;
reads++; total_cycles += 5;
}
if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; }
else firstrepcycle=1;
@ -906,6 +1030,7 @@ int rep386(int fv)
else SI+=2;
c--;
cycles-=5;
reads++; total_cycles += 5;
}
if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; }
else firstrepcycle=1;
@ -921,6 +1046,7 @@ int rep386(int fv)
else SI+=4;
c--;
cycles-=5;
reads_l++; total_cycles += 5;
}
if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; }
else firstrepcycle=1;
@ -936,6 +1062,7 @@ int rep386(int fv)
else ESI+=2;
c--;
cycles-=5;
reads++; total_cycles += 5;
}
if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; }
else firstrepcycle=1;
@ -951,6 +1078,7 @@ int rep386(int fv)
else ESI+=4;
c--;
cycles-=5;
reads_l++; total_cycles += 5;
}
if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; }
else firstrepcycle=1;
@ -970,6 +1098,7 @@ int rep386(int fv)
else DI++;
c--;
cycles-=(is486)?5:8;
reads++; total_cycles += is486 ? 5 : 8;
ins++;
if (cycles < cycles_end)
break;
@ -994,6 +1123,7 @@ int rep386(int fv)
else EDI++;
c--;
cycles-=(is486)?5:8;
reads++; total_cycles += is486 ? 5 : 8;
ins++;
if (cycles < cycles_end)
break;
@ -1016,6 +1146,7 @@ int rep386(int fv)
else DI+=2;
c--;
cycles-=(is486)?5:8;
reads++; total_cycles += is486 ? 5 : 8;
ins++;
if (cycles < cycles_end)
break;
@ -1038,6 +1169,7 @@ int rep386(int fv)
else DI+=4;
c--;
cycles-=(is486)?5:8;
reads_l++; total_cycles += is486 ? 5 : 8;
ins++;
if (cycles < cycles_end)
break;
@ -1060,6 +1192,7 @@ int rep386(int fv)
else EDI+=2;
c--;
cycles-=(is486)?5:8;
reads++; total_cycles += is486 ? 5 : 8;
ins++;
if (cycles < cycles_end)
break;
@ -1082,6 +1215,7 @@ int rep386(int fv)
else EDI+=4;
c--;
cycles-=(is486)?5:8;
reads_l++; total_cycles += is486 ? 5 : 8;
ins++;
if (cycles < cycles_end)
break;
@ -1100,6 +1234,7 @@ int rep386(int fv)
if (rep32&0x200) ECX=c;
else CX=c;
CPU_BLOCK_END();
PREFETCH_RUN(total_cycles, 1, -1, reads, reads_l, writes, writes_l, 0);
return cpu_state.abrt;
//pclog("rep cpu_block_end=%d %p\n", cpu_block_end, (void *)&cpu_block_end);
// if (output) pclog("%03X %03X\n",rep32,use32);