#include #include #include #define MAX_IOPORTS 4096 typedef void (IOPortWriteFunc)(void *opaque, unsigned int address, unsigned int data); typedef struct IDEState { void* dummy; void* curr; char* data_ptr; char* data_end; } IDEState; typedef struct PIOInfo { void* dummy; IOPortWriteFunc* write; void* opaque; char* data_ptr; char* data_end; } PIOInfo; typedef struct CPUState { void* dummy; PIOInfo* info; } CPUState; void *ioport_opaque[MAX_IOPORTS]; IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; PIOInfo* pio_info_table[MAX_IOPORTS]; unsigned int fake = 0; int testIdx = 23; int testCnt = 10; void writeFake(void *opaque, unsigned int addr, unsigned int data) { fake ^= data; } void writeLoop(void *opaque, unsigned int addr, unsigned int data) { IDEState *s = ((IDEState *)opaque)->curr; char *p; p = s->data_ptr; *(unsigned int *)p = data; p += 4; s->data_ptr = p; if (p >= s->data_end) printf("oops"); } void cpu_outl(CPUState *env, int addr, int val) { // the if overhead is 7 ns (2.4 GHz P4) ... //if(ioport_opaque[addr] == 0) ioport_write_table[2][addr](ioport_opaque[addr], addr, val); } void cpu_outx(CPUState *env, int addr, int val) { PIOInfo *i = pio_info_table[addr]; if(i->data_ptr >= i->data_end) i->write(i->opaque, addr, val); else { *(int *)(i->data_ptr) = val; i->data_ptr += 4; } } int main(int argc, char** argv) { struct timeval tss, tse; CPUState env; IDEState ide; PIOInfo pio; int irun; char buff[64]; // TEST 1 ioport_write_table[2][testIdx] = writeFake; ioport_opaque[testIdx] = 0; printf("start 1\n"); gettimeofday(&tss, NULL); for(irun=0; irun < 1000*1000*testCnt; irun++) { cpu_outl(&env, testIdx, irun); cpu_outl(&env, testIdx, irun); cpu_outl(&env, testIdx, irun); cpu_outl(&env, testIdx, irun); cpu_outl(&env, testIdx, irun); cpu_outl(&env, testIdx, irun); cpu_outl(&env, testIdx, irun); cpu_outl(&env, testIdx, irun); cpu_outl(&env, testIdx, irun); cpu_outl(&env, testIdx, irun); } gettimeofday(&tse, NULL); tse.tv_sec -= tss.tv_sec; tse.tv_usec -= tss.tv_usec; printf("done (%.6g ns/call)\n", ((double)(tse.tv_usec/1000 + tse.tv_sec*1000))/testCnt); // TEST 2 ioport_write_table[2][testIdx] = writeLoop; ioport_opaque[testIdx] = &ide; ide.curr = &ide; printf("start 2\n"); gettimeofday(&tss, NULL); for(irun=0; irun < 1000*1000*testCnt; irun++) { ide.data_ptr = buff; ide.data_end = buff + sizeof(buff); cpu_outl(&env, testIdx, irun); cpu_outl(&env, testIdx, irun); cpu_outl(&env, testIdx, irun); cpu_outl(&env, testIdx, irun); cpu_outl(&env, testIdx, irun); cpu_outl(&env, testIdx, irun); cpu_outl(&env, testIdx, irun); cpu_outl(&env, testIdx, irun); cpu_outl(&env, testIdx, irun); cpu_outl(&env, testIdx, irun); } gettimeofday(&tse, NULL); tse.tv_sec -= tss.tv_sec; tse.tv_usec -= tss.tv_usec; printf("done (%.6g ns/call)\n", ((double)(tse.tv_usec/1000 + tse.tv_sec*1000))/testCnt); // TEST 3 pio_info_table[testIdx] = &pio; pio.write = writeFake; pio.opaque = &ide; printf("start 3\n"); gettimeofday(&tss, NULL); for(irun=0; irun < 1000*1000*testCnt; irun++) { pio.data_ptr = buff + sizeof(buff); pio.data_end = 0; cpu_outx(&env, testIdx, irun); cpu_outx(&env, testIdx, irun); cpu_outx(&env, testIdx, irun); cpu_outx(&env, testIdx, irun); cpu_outx(&env, testIdx, irun); cpu_outx(&env, testIdx, irun); cpu_outx(&env, testIdx, irun); cpu_outx(&env, testIdx, irun); cpu_outx(&env, testIdx, irun); cpu_outx(&env, testIdx, irun); } gettimeofday(&tse, NULL); tse.tv_sec -= tss.tv_sec; tse.tv_usec -= tss.tv_usec; printf("done (%.6g ns/call)\n", ((double)(tse.tv_usec/1000 + tse.tv_sec*1000))/testCnt); // TEST 4 pio.write = writeFake; pio.opaque = &ide; printf("start 4\n"); gettimeofday(&tss, NULL); for(irun=0; irun < 1000*1000*testCnt; irun++) { pio.data_ptr = buff; pio.data_end = buff + sizeof(buff); cpu_outx(&env, testIdx, irun); cpu_outx(&env, testIdx, irun); cpu_outx(&env, testIdx, irun); cpu_outx(&env, testIdx, irun); cpu_outx(&env, testIdx, irun); cpu_outx(&env, testIdx, irun); cpu_outx(&env, testIdx, irun); cpu_outx(&env, testIdx, irun); cpu_outx(&env, testIdx, irun); cpu_outx(&env, testIdx, irun); } gettimeofday(&tse, NULL); tse.tv_sec -= tss.tv_sec; tse.tv_usec -= tss.tv_usec; printf("done (%.6g ns/call)\n", ((double)(tse.tv_usec/1000 + tse.tv_sec*1000))/testCnt); return 0; }