Implement penalties for segment load on Pentium Pro.
This commit is contained in:
parent
5c3069c561
commit
0469ab60cb
3 changed files with 36 additions and 15 deletions
|
|
@ -19,7 +19,8 @@ typedef enum uop_type_t
|
||||||
UOP_LOAD, /*Executes in port 2 Load unit*/
|
UOP_LOAD, /*Executes in port 2 Load unit*/
|
||||||
UOP_STOREADDR, /*Executes in port 3 Store Address unit*/
|
UOP_STOREADDR, /*Executes in port 3 Store Address unit*/
|
||||||
UOP_STOREDATA, /*Executes in port 4 Store Data unit*/
|
UOP_STOREDATA, /*Executes in port 4 Store Data unit*/
|
||||||
UOP_FLOAT /*Executes in port 0 Floating Point unit*/
|
UOP_FLOAT, /*Executes in port 0 Floating Point unit*/
|
||||||
|
UOP_ALU0_SEG /*Executes in port 0 ALU, loads segment, causing pipeline flush on PPro*/
|
||||||
} uop_type_t;
|
} uop_type_t;
|
||||||
|
|
||||||
#define MAX_UOPS 300
|
#define MAX_UOPS 300
|
||||||
|
|
@ -512,7 +513,7 @@ static const p6_instruction_t call_far_op =
|
||||||
.uop[2] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
|
.uop[2] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
|
||||||
.uop[3] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
|
.uop[3] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
|
||||||
.uop[4] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
|
.uop[4] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
|
||||||
.uop[5] = {.type = UOP_ALU0, .throughput = 28, .latency = 28}
|
.uop[5] = {.type = UOP_ALU0_SEG, .throughput = 28, .latency = 28}
|
||||||
};
|
};
|
||||||
static const p6_instruction_t load_call_far_op =
|
static const p6_instruction_t load_call_far_op =
|
||||||
{
|
{
|
||||||
|
|
@ -523,7 +524,7 @@ static const p6_instruction_t load_call_far_op =
|
||||||
.uop[3] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
|
.uop[3] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
|
||||||
.uop[4] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
|
.uop[4] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
|
||||||
.uop[5] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
|
.uop[5] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
|
||||||
.uop[6] = {.type = UOP_ALU0, .throughput = 28, .latency = 28}
|
.uop[6] = {.type = UOP_ALU0_SEG, .throughput = 28, .latency = 28}
|
||||||
};
|
};
|
||||||
static const p6_instruction_t cli_op =
|
static const p6_instruction_t cli_op =
|
||||||
{
|
{
|
||||||
|
|
@ -676,15 +677,15 @@ static const p6_instruction_t invd_op =
|
||||||
static const p6_instruction_t jmp_far_op =
|
static const p6_instruction_t jmp_far_op =
|
||||||
{
|
{
|
||||||
.nr_uops = 2,
|
.nr_uops = 2,
|
||||||
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
|
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
|
||||||
.uop[1] = {.type = UOP_ALU0, .throughput = 21, .latency = 21}
|
.uop[1] = {.type = UOP_ALU0_SEG, .throughput = 21, .latency = 21}
|
||||||
};
|
};
|
||||||
static const p6_instruction_t load_jmp_far_op =
|
static const p6_instruction_t load_jmp_far_op =
|
||||||
{
|
{
|
||||||
.nr_uops = 3,
|
.nr_uops = 3,
|
||||||
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
|
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
|
||||||
.uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
|
.uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
|
||||||
.uop[2] = {.type = UOP_ALU0, .throughput = 21, .latency = 21}
|
.uop[2] = {.type = UOP_ALU0_SEG, .throughput = 21, .latency = 21}
|
||||||
};
|
};
|
||||||
static const p6_instruction_t lss_op =
|
static const p6_instruction_t lss_op =
|
||||||
{
|
{
|
||||||
|
|
@ -692,7 +693,7 @@ static const p6_instruction_t lss_op =
|
||||||
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
|
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
|
||||||
.uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
|
.uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
|
||||||
.uop[2] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
|
.uop[2] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
|
||||||
.uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
|
.uop[3] = {.type = UOP_ALU0_SEG,.throughput = 1, .latency = 1},
|
||||||
.uop[4] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
|
.uop[4] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
|
||||||
.uop[5] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
|
.uop[5] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
|
||||||
.uop[6] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
|
.uop[6] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
|
||||||
|
|
@ -712,7 +713,7 @@ static const p6_instruction_t mov_seg_mem_op =
|
||||||
{
|
{
|
||||||
.nr_uops = 9,
|
.nr_uops = 9,
|
||||||
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
|
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
|
||||||
.uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
|
.uop[1] = {.type = UOP_ALU0_SEG,.throughput = 1, .latency = 1},
|
||||||
.uop[2] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
|
.uop[2] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
|
||||||
.uop[3] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
|
.uop[3] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
|
||||||
.uop[4] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
|
.uop[4] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
|
||||||
|
|
@ -725,7 +726,7 @@ static const p6_instruction_t mov_seg_reg_op =
|
||||||
{
|
{
|
||||||
.nr_uops = 8,
|
.nr_uops = 8,
|
||||||
.uop[0] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
|
.uop[0] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
|
||||||
.uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
|
.uop[1] = {.type = UOP_ALU0_SEG,.throughput = 1, .latency = 1},
|
||||||
.uop[2] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
|
.uop[2] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
|
||||||
.uop[3] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
|
.uop[3] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
|
||||||
.uop[4] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
|
.uop[4] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
|
||||||
|
|
@ -1593,11 +1594,11 @@ static const p6_port_t ports[] =
|
||||||
{UNIT_STORE_ADDR},
|
{UNIT_STORE_ADDR},
|
||||||
{UNIT_STORE_DATA}
|
{UNIT_STORE_DATA}
|
||||||
};
|
};
|
||||||
|
const int nr_ports = (sizeof(ports) / sizeof(p6_port_t));
|
||||||
|
|
||||||
static p6_unit_t units[] =
|
static p6_unit_t units[] =
|
||||||
{
|
{
|
||||||
[UNIT_INT0] = {.uop_mask = (1 << UOP_ALU0) | (1 << UOP_ALU01), .port = 0}, /*Integer 0*/
|
[UNIT_INT0] = {.uop_mask = (1 << UOP_ALU0) | (1 << UOP_ALU0_SEG) | (1 << UOP_ALU01), .port = 0}, /*Integer 0*/
|
||||||
[UNIT_INT1] = {.uop_mask = (1 << UOP_ALU1) | (1 << UOP_ALU01), .port = 1}, /*Integer 1*/
|
[UNIT_INT1] = {.uop_mask = (1 << UOP_ALU1) | (1 << UOP_ALU01), .port = 1}, /*Integer 1*/
|
||||||
[UNIT_FPU] = {.uop_mask = 1 << UOP_FLOAT, .port = 0},
|
[UNIT_FPU] = {.uop_mask = 1 << UOP_FLOAT, .port = 0},
|
||||||
[UNIT_MMX_ADD] = {.uop_mask = 0, .port = 1},
|
[UNIT_MMX_ADD] = {.uop_mask = 0, .port = 1},
|
||||||
|
|
@ -1654,6 +1655,24 @@ static int uop_run(const p6_uop_t *uop, int decode_time)
|
||||||
if (!best_unit)
|
if (!best_unit)
|
||||||
fatal("uop_run: can not find execution unit %x\n", uop->type);
|
fatal("uop_run: can not find execution unit %x\n", uop->type);
|
||||||
|
|
||||||
|
if (cpu_s->cpu_type == CPU_PENTIUMPRO && uop->type == UOP_ALU0_SEG)
|
||||||
|
{
|
||||||
|
/*Pentium Pro will flush pipeline on a segment load. Find last
|
||||||
|
execution unit to complete, then set earliest start times on
|
||||||
|
_all_ execution units to after this point*/
|
||||||
|
int last_start_cycle = 0;
|
||||||
|
|
||||||
|
for (c = 0; c < nr_units; c++)
|
||||||
|
{
|
||||||
|
p6_unit_t *unit = &units[c];
|
||||||
|
int start_cycle = unit->first_available_cycle;
|
||||||
|
|
||||||
|
if (start_cycle > last_start_cycle)
|
||||||
|
last_start_cycle = start_cycle;
|
||||||
|
}
|
||||||
|
for (c = 0; c < nr_units; c++)
|
||||||
|
units[c].first_available_cycle = last_start_cycle+1;
|
||||||
|
}
|
||||||
if (best_start_cycle < decode_time)
|
if (best_start_cycle < decode_time)
|
||||||
best_start_cycle = decode_time;
|
best_start_cycle = decode_time;
|
||||||
best_unit->first_available_cycle = best_start_cycle + uop->throughput;
|
best_unit->first_available_cycle = best_start_cycle + uop->throughput;
|
||||||
|
|
|
||||||
|
|
@ -177,10 +177,10 @@ int fpu_get_type_from_index(int model, int manu, int cpu, int c)
|
||||||
return fpus[c].type;
|
return fpus[c].type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CPU *cpu_s;
|
||||||
|
|
||||||
void cpu_set()
|
void cpu_set()
|
||||||
{
|
{
|
||||||
CPU *cpu_s;
|
|
||||||
|
|
||||||
if (!models[model].cpu[cpu_manufacturer].cpus)
|
if (!models[model].cpu[cpu_manufacturer].cpus)
|
||||||
{
|
{
|
||||||
/*CPU is invalid, set to default*/
|
/*CPU is invalid, set to default*/
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,8 @@ typedef struct
|
||||||
int atclk_div;
|
int atclk_div;
|
||||||
} CPU;
|
} CPU;
|
||||||
|
|
||||||
|
extern CPU *cpu_s;
|
||||||
|
|
||||||
extern CPU cpus_8088[];
|
extern CPU cpus_8088[];
|
||||||
extern CPU cpus_8086[];
|
extern CPU cpus_8086[];
|
||||||
extern CPU cpus_286[];
|
extern CPU cpus_286[];
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue