File:  [RetroPC.NET] / np2 / i386c / ia32 / cpu.c
Revision 1.2: download - view: text, annotated - select for diffs
Tue Dec 23 03:00:31 2003 JST (21 years, 10 months ago) by monaka
Branches: MAIN
CVS tags: HEAD
statsave, instruction profiling... (XXX)

/*	$Id: cpu.c,v 1.2 2003/12/22 18:00:31 monaka Exp $	*/

/*
 * Copyright (c) 2002-2003 NONAKA Kimihiro
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "compiler.h"
#include "cpu.h"
#include "ia32.mcr"

#include "inst_table.h"

#if defined(IA32_PROFILE_INSTRUCTION)
UINT32	inst_1byte_count[2][256];
UINT32	inst_2byte_count[2][256];
UINT32	ea16_count[24];
UINT32	ea32_count[24];
UINT32	sib0_count[256];
UINT32	sib1_count[256];
UINT32	sib2_count[256];

static const char *ea16_str[24] = {
	"BX + SI", "BX + SI + DISP8", "BX + SI + DISP16",
	"BX + DI", "BX + DI + DISP8", "BX + DI + DISP16",
	"BP + SI", "BP + SI + DISP8", "BP + SI + DISP16",
	"BP + DI", "BP + DI + DISP8", "BP + DI + DISP16",
	"SI",      "SI + DISP8",      "SI + DISP16",
	"DI",      "DI + DISP8",      "DI + DISP16",
	"DISP16",  "BP + DISP8",      "BP + DISP16",
	"BX",      "BX + DISP8",      "BX + DISP16",
};

static const char *ea32_str[24] = {
	"EAX", "ECX", "EDX", "EBX", "SIB", "DISP32", "ESI", "EDI",
	"EAX + DISP8",  "ECX + DISP8",  "EDX + DISP8",  "EBX + DISP8",
	"SIB + DISP8",  "EBP + DISP8",  "ESI + DISP8",  "EDI + DISP8",
	"EAX + DISP32", "ECX + DISP32", "EDX + DISP32", "EBX + DISP32",
	"SIB + DISP32", "EBP + DISP32", "ESI + DISP32", "EDI + DISP32",
};

static const char *sib0_base_str[8] = {
	"EAX", "ECX", "EDX", "EBX", "ESP", "DISP32", "ESI", "EDI",
};

static const char *sib1_base_str[8] = {
	"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI",
};

static const char *sib_index_str[8] = {
	"EAX", "ECX", "EDX", "EBX", "", "EBP", "ESI", "EDI",
};

static const char *sib_scale_str[4] = {
	"", "2", "4", "8",
};

void
clear_profile_inst(void)
{

	memset(inst_1byte_count, 0, sizeof(inst_1byte_count));
	memset(inst_2byte_count, 0, sizeof(inst_2byte_count));
	memset(ea16_count, 0, sizeof(ea16_count));
	memset(ea32_count, 0, sizeof(ea32_count));
	memset(sib0_count, 0, sizeof(sib0_count));
	memset(sib1_count, 0, sizeof(sib1_count));
	memset(sib2_count, 0, sizeof(sib2_count));
}

void
show_profile_inst(void)
{
	int i;

	printf("instruction (16bit)\n");
	for (i = 0; i < 256; i++) {
		if (inst_1byte_count[0][i] != 0) {
			printf("0x%02x: %d\n", i, inst_1byte_count[0][i]);
		}
	}
	for (i = 0; i < 256; i++) {
		if (inst_2byte_count[0][i] != 0) {
			printf("0x0f%02x: %d\n", i, inst_2byte_count[0][i]);
		}
	}

	printf("instruction (32bit)\n");
	for (i = 0; i < 256; i++) {
		if (inst_1byte_count[1][i] != 0) {
			printf("0x%02x: %d\n", i, inst_1byte_count[1][i]);
		}
	}
	for (i = 0; i < 256; i++) {
		if (inst_2byte_count[1][i] != 0) {
			printf("0x0f%02x: %d\n", i, inst_2byte_count[1][i]);
		}
	}
}

void
show_profile_ea(void)
{
	char buf[80];
	char tmp[80];
	int i;
	int t;

	printf("EA16\n");
	for (i = 0; i < NELEMENTS(ea16_count); i++) {
		if (ea16_count[i] != 0) {
			printf("%s: %d\n", ea16_str[i], ea16_count[i]);
		}
	}
	printf("EA32\n");
	for (i = 0; i < NELEMENTS(ea32_count); i++) {
		if (ea32_count[i] != 0) {
			printf("%s: %d\n", ea32_str[i], ea32_count[i]);
		}
	}
	printf("SIB0\n");
	for (i = 0; i < NELEMENTS(sib0_count); i++) {
		if (sib0_count[i] != 0) {
			sprintf(tmp, "%s", sib0_base_str[i & 7]);
			strcpy(buf, tmp);
			t = (i >> 3) & 7;
			if (t != 4) {
				sprintf(tmp, " + %s", sib_index_str[t]);
				strcat(buf, tmp);
			}
			t = (i >> 6) & 3;
			if (t != 0) {
				sprintf(tmp, " * %s", sib_scale_str[t]);
				strcat(buf, tmp);
			}
			printf("%s: %d\n", buf, sib0_count[i]);
		}
	}
	printf("SIB1\n");
	for (i = 0; i < NELEMENTS(sib1_count); i++) {
		if (sib1_count[i] != 0) {
			sprintf(tmp, "%s", sib1_base_str[i & 7]);
			strcpy(buf, tmp);
			t = (i >> 3) & 7;
			if (t != 4) {
				sprintf(tmp, " + %s", sib_index_str[t]);
				strcat(buf, tmp);
			}
			t = (i >> 6) & 3;
			if (t != 0) {
				sprintf(tmp, " * %s", sib_scale_str[t]);
				strcat(buf, tmp);
			}
			printf("%s + DISP8: %d\n", buf, sib1_count[i]);
		}
	}
	printf("SIB2\n");
	for (i = 0; i < NELEMENTS(sib2_count); i++) {
		if (sib2_count[i] != 0) {
			sprintf(tmp, "%s", sib1_base_str[i & 7]);
			strcpy(buf, tmp);
			t = (i >> 3) & 7;
			if (t != 4) {
				sprintf(tmp, " + %s", sib_index_str[t]);
				strcat(buf, tmp);
			}
			t = (i >> 6) & 3;
			if (t != 0) {
				sprintf(tmp, " * %s", sib_scale_str[t]);
				strcat(buf, tmp);
			}
			printf("%s + DISP32: %d\n", buf, sib2_count[i]);
		}
	}
}
#endif

#define	MAX_PREFIX	8

jmp_buf exec_1step_jmpbuf;

void
exec_1step(void)
{
	BYTE op;
	BYTE prefix;

	CPU_PREV_EIP = CPU_EIP;

	CPU_STATSAVE.cpu_inst = CPU_STATSAVE.cpu_inst_default;

	for (prefix = 0; prefix < MAX_PREFIX; prefix++) {
		GET_PCBYTE(op);

		/* prefix */
		if (insttable_info[op] & INST_PREFIX) {
			PROFILE_INC_INST_1BYTE(op);
			(*insttable_1byte[0][op])();
			continue;
		}
		break;
	}
	if (prefix == MAX_PREFIX) {
		EXCEPTION(UD_EXCEPTION, 0);
	}
	PROFILE_INC_INST_1BYTE(op);

	/* normal / rep, but not use */
	if (!(insttable_info[op] & INST_STRING) || !CPU_INST_REPUSE) {
		(*insttable_1byte[CPU_INST_OP32][op])();
		return;
	}

	/* rep */
	CPU_WORKCLOCK(5);
	if (!CPU_INST_AS32) {
		if (CPU_CX != 0) {
			if (!(insttable_info[op] & REP_CHECKZF)) {
				/* rep */
				do {
					(*insttable_1byte[CPU_INST_OP32][op])();
				} while (--CPU_CX);
			} else if (CPU_INST_REPUSE != 0xf2) {
				/* repe */
				do {
					(*insttable_1byte[CPU_INST_OP32][op])();
				} while (--CPU_CX && (CPU_FLAGL & Z_FLAG));
			} else {
				/* repne */
				do {
					(*insttable_1byte[CPU_INST_OP32][op])();
				} while (--CPU_CX && !(CPU_FLAGL & Z_FLAG));
			}
		}
	} else {
		if (CPU_ECX != 0) {
			if (!(insttable_info[op] & REP_CHECKZF)) {
				/* rep */
				do {
					(*insttable_1byte[CPU_INST_OP32][op])();
				} while (--CPU_ECX);
			} else if (CPU_INST_REPUSE != 0xf2) {
				/* repe */
				do {
					(*insttable_1byte[CPU_INST_OP32][op])();
				} while (--CPU_ECX && (CPU_FLAGL & Z_FLAG));
			} else {
				/* repne */
				do {
					(*insttable_1byte[CPU_INST_OP32][op])();
				} while (--CPU_ECX && !(CPU_FLAGL & Z_FLAG));
			}
		}
	}
}

RetroPC.NET-CVS <cvs@retropc.net>