new x86 CPU core

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@14 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
bellard 2003-03-01 17:13:26 +00:00
parent 7bfdb6d18c
commit 367e86e847
11 changed files with 3834 additions and 546 deletions

View File

@ -1,8 +1,9 @@
ARCH=i386
#ARCH=ppc
HOST_CC=gcc
ifeq ($(ARCH),i386)
CFLAGS=-Wall -O2 -g
CFLAGS=-Wall -O2 -g -fomit-frame-pointer
LDFLAGS=-g
LIBS=
CC=gcc
@ -27,38 +28,59 @@ endif
#########################################################
DEFINES+=-D_GNU_SOURCE -DGEMU -DDOSEMU #-DNO_TRACE_MSGS
DEFINES+=-D_GNU_SOURCE -DGEMU -DDOSEMU -DNO_TRACE_MSGS
DEFINES+=-DCONFIG_PREFIX=\"/usr/local\"
LDSCRIPT=$(ARCH).ld
LIBS+=-ldl
OBJS= i386/fp87.o i386/interp_main.o i386/interp_modrm.o i386/interp_16_32.o \
i386/interp_32_16.o i386/interp_32_32.o i386/emu-utils.o \
i386/dis8086.o i386/emu-ldt.o
OBJS+=translate-i386.o op-i386.o
OBJS+= elfload.o main.o thunk.o syscall.o
SRCS = $(OBJS:.o=.c)
all: gemu
gemu: $(OBJS)
$(CC) -Wl,-T,$(LDSCRIPT) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
$(CC) -Wl,-T,$(LDSCRIPT) $(LDFLAGS) -o $@ $^ $(LIBS)
depend: $(SRCS)
$(CC) -MM $(CFLAGS) $^ 1>.depend
# old i386 emulator
i386/interp_32_32.o: i386/interp_32_32.c i386/interp_gen.h
i386/interp_gen.h: i386/gencode
./i386/gencode > $@
i386/gencode: i386/gencode.c
$(CC) -O2 -Wall -g $< -o $@
# new i386 emulator
dyngen: dyngen.c
$(HOST_CC) -O2 -Wall -g $< -o $@
translate-i386.o: translate-i386.c op-i386.h cpu-i386.h
op-i386.h: op-i386.o dyngen
./dyngen -o $@ $<
op-i386.o: op-i386.c opreg_template.h ops_template.h
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
%.o: %.c
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
clean:
rm -f *.o *~ i386/*.o i386/*~ gemu hello test1 test2 TAGS
rm -f *.o *~ i386/*.o i386/*~ gemu TAGS
hello: hello.c
$(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
# various test targets
test speed: gemu
make -C tests $@
test1: test1.c
$(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $<
test2: test2.c
$(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $<
TAGS:
etags *.[ch] i386/*.[ch]
ifneq ($(wildcard .depend),)
include .depend

5
TODO
View File

@ -1,2 +1,5 @@
- swap all elf paramters
- tests
- signals
- threads
- fix printf for doubles (fp87.c bug ?)
- make it self runnable (use same trick as ld.so : include its own relocator and libc)

148
cpu-i386.h Normal file
View File

@ -0,0 +1,148 @@
#ifndef CPU_I386_H
#define CPU_I386_H
#define R_EAX 0
#define R_ECX 1
#define R_EDX 2
#define R_EBX 3
#define R_ESP 4
#define R_EBP 5
#define R_ESI 6
#define R_EDI 7
#define R_AL 0
#define R_CL 1
#define R_DL 2
#define R_BL 3
#define R_AH 4
#define R_CH 5
#define R_DH 6
#define R_BH 7
#define R_ES 0
#define R_CS 1
#define R_SS 2
#define R_DS 3
#define R_FS 4
#define R_GS 5
#define CC_C 0x0001
#define CC_P 0x0004
#define CC_A 0x0010
#define CC_Z 0x0040
#define CC_S 0x0080
#define CC_O 0x0800
#define TRAP_FLAG 0x0100
#define INTERRUPT_FLAG 0x0200
#define DIRECTION_FLAG 0x0400
#define IOPL_FLAG_MASK 0x3000
#define NESTED_FLAG 0x4000
#define BYTE_FL 0x8000 /* Intel reserved! */
#define RF_FLAG 0x10000
#define VM_FLAG 0x20000
/* AC 0x40000 */
enum {
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */
CC_OP_MUL, /* modify all flags, C, O = (CC_SRC != 0) */
CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_ADDW,
CC_OP_ADDL,
CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_SUBW,
CC_OP_SUBL,
CC_OP_LOGICB, /* modify all flags, CC_DST = res */
CC_OP_LOGICW,
CC_OP_LOGICL,
CC_OP_INCB, /* modify all flags except, CC_DST = res */
CC_OP_INCW,
CC_OP_INCL,
CC_OP_DECB, /* modify all flags except, CC_DST = res */
CC_OP_DECW,
CC_OP_DECL,
CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */
CC_OP_SHLW,
CC_OP_SHLL,
CC_OP_NB,
};
typedef struct CPU86State {
/* standard registers */
uint32_t regs[8];
uint32_t pc; /* cs_case + eip value */
/* eflags handling */
uint32_t eflags;
uint32_t cc_src;
uint32_t cc_dst;
uint32_t cc_op;
int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */
/* segments */
uint8_t *segs_base[6];
uint32_t segs[6];
/* emulator internal variables */
uint32_t t0; /* temporary t0 storage */
uint32_t t1; /* temporary t1 storage */
uint32_t a0; /* temporary a0 storage (address) */
} CPU86State;
static inline int ldub(void *ptr)
{
return *(uint8_t *)ptr;
}
static inline int ldsb(void *ptr)
{
return *(int8_t *)ptr;
}
static inline int lduw(void *ptr)
{
return *(uint16_t *)ptr;
}
static inline int ldsw(void *ptr)
{
return *(int16_t *)ptr;
}
static inline int ldl(void *ptr)
{
return *(uint32_t *)ptr;
}
static inline void stb(void *ptr, int v)
{
*(uint8_t *)ptr = v;
}
static inline void stw(void *ptr, int v)
{
*(uint16_t *)ptr = v;
}
static inline void stl(void *ptr, int v)
{
*(uint32_t *)ptr = v;
}
void port_outb(int addr, int val);
void port_outw(int addr, int val);
void port_outl(int addr, int val);
int port_inb(int addr);
int port_inw(int addr);
int port_inl(int addr);
#endif /* CPU_I386_H */

521
dyngen.c Normal file
View File

@ -0,0 +1,521 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <inttypes.h>
#include <elf.h>
#include <unistd.h>
#include <fcntl.h>
#include "thunk.h"
/* all dynamically generated functions begin with this code */
#define OP_PREFIX "op"
int elf_must_swap(Elf32_Ehdr *h)
{
union {
uint32_t i;
uint8_t b[4];
} swaptest;
swaptest.i = 1;
return (h->e_ident[EI_DATA] == ELFDATA2MSB) !=
(swaptest.b[0] == 0);
}
void swab16s(uint16_t *p)
{
*p = bswap16(*p);
}
void swab32s(uint32_t *p)
{
*p = bswap32(*p);
}
void swab64s(uint32_t *p)
{
*p = bswap64(*p);
}
void elf_swap_ehdr(Elf32_Ehdr *h)
{
swab16s(&h->e_type); /* Object file type */
swab16s(&h-> e_machine); /* Architecture */
swab32s(&h-> e_version); /* Object file version */
swab32s(&h-> e_entry); /* Entry point virtual address */
swab32s(&h-> e_phoff); /* Program header table file offset */
swab32s(&h-> e_shoff); /* Section header table file offset */
swab32s(&h-> e_flags); /* Processor-specific flags */
swab16s(&h-> e_ehsize); /* ELF header size in bytes */
swab16s(&h-> e_phentsize); /* Program header table entry size */
swab16s(&h-> e_phnum); /* Program header table entry count */
swab16s(&h-> e_shentsize); /* Section header table entry size */
swab16s(&h-> e_shnum); /* Section header table entry count */
swab16s(&h-> e_shstrndx); /* Section header string table index */
}
void elf_swap_shdr(Elf32_Shdr *h)
{
swab32s(&h-> sh_name); /* Section name (string tbl index) */
swab32s(&h-> sh_type); /* Section type */
swab32s(&h-> sh_flags); /* Section flags */
swab32s(&h-> sh_addr); /* Section virtual addr at execution */
swab32s(&h-> sh_offset); /* Section file offset */
swab32s(&h-> sh_size); /* Section size in bytes */
swab32s(&h-> sh_link); /* Link to another section */
swab32s(&h-> sh_info); /* Additional section information */
swab32s(&h-> sh_addralign); /* Section alignment */
swab32s(&h-> sh_entsize); /* Entry size if section holds table */
}
void elf_swap_phdr(Elf32_Phdr *h)
{
swab32s(&h->p_type); /* Segment type */
swab32s(&h->p_offset); /* Segment file offset */
swab32s(&h->p_vaddr); /* Segment virtual address */
swab32s(&h->p_paddr); /* Segment physical address */
swab32s(&h->p_filesz); /* Segment size in file */
swab32s(&h->p_memsz); /* Segment size in memory */
swab32s(&h->p_flags); /* Segment flags */
swab32s(&h->p_align); /* Segment alignment */
}
int do_swap;
int e_machine;
uint16_t get16(uint16_t *p)
{
uint16_t val;
val = *p;
if (do_swap)
val = bswap16(val);
return val;
}
uint32_t get32(uint32_t *p)
{
uint32_t val;
val = *p;
if (do_swap)
val = bswap32(val);
return val;
}
void put16(uint16_t *p, uint16_t val)
{
if (do_swap)
val = bswap16(val);
*p = val;
}
void put32(uint32_t *p, uint32_t val)
{
if (do_swap)
val = bswap32(val);
*p = val;
}
void __attribute__((noreturn)) error(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "dyngen: ");
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
exit(1);
}
Elf32_Shdr *find_elf_section(Elf32_Shdr *shdr, int shnum, const char *shstr,
const char *name)
{
int i;
const char *shname;
Elf32_Shdr *sec;
for(i = 0; i < shnum; i++) {
sec = &shdr[i];
if (!sec->sh_name)
continue;
shname = shstr + sec->sh_name;
if (!strcmp(shname, name))
return sec;
}
return NULL;
}
void *load_data(int fd, long offset, unsigned int size)
{
char *data;
data = malloc(size);
if (!data)
return NULL;
lseek(fd, offset, SEEK_SET);
if (read(fd, data, size) != size) {
free(data);
return NULL;
}
return data;
}
int strstart(const char *str, const char *val, const char **ptr)
{
const char *p, *q;
p = str;
q = val;
while (*q != '\0') {
if (*p != *q)
return 0;
p++;
q++;
}
if (ptr)
*ptr = p;
return 1;
}
#define MAX_ARGS 3
/* generate op code */
void gen_code(const char *name, unsigned long offset, unsigned long size,
FILE *outfile, uint8_t *text, void *relocs, int nb_relocs, int reloc_sh_type,
Elf32_Sym *symtab, char *strtab)
{
int copy_size = 0;
uint8_t *p_start, *p_end;
int nb_args, i;
uint8_t args_present[MAX_ARGS];
const char *sym_name, *p;
/* compute exact size excluding return instruction */
p_start = text + offset;
p_end = p_start + size;
switch(e_machine) {
case EM_386:
{
uint8_t *p;
p = p_end - 1;
/* find ret */
while (p > p_start && *p != 0xc3)
p--;
/* skip double ret */
if (p > p_start && p[-1] == 0xc3)
p--;
if (p == p_start)
error("empty code for %s", name);
copy_size = p - p_start;
}
break;
case EM_PPC:
{
uint8_t *p;
p = (void *)(p_end - 4);
/* find ret */
while (p > p_start && get32((uint32_t *)p) != 0x4e800020)
p -= 4;
/* skip double ret */
if (p > p_start && get32((uint32_t *)(p - 4)) == 0x4e800020)
p -= 4;
if (p == p_start)
error("empty code for %s", name);
copy_size = p - p_start;
}
break;
default:
error("unsupported CPU (%d)", e_machine);
}
/* compute the number of arguments by looking at the relocations */
for(i = 0;i < MAX_ARGS; i++)
args_present[i] = 0;
if (reloc_sh_type == SHT_REL) {
Elf32_Rel *rel;
int n;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
if (strstart(sym_name, "__op_param", &p)) {
n = strtoul(p, NULL, 10);
if (n >= MAX_ARGS)
error("too many arguments in %s", name);
args_present[n - 1] = 1;
}
}
}
} else {
Elf32_Rela *rel;
int n;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
if (strstart(sym_name, "__op_param", &p)) {
n = strtoul(p, NULL, 10);
if (n >= MAX_ARGS)
error("too many arguments in %s", name);
args_present[n - 1] = 1;
}
}
}
}
nb_args = 0;
while (nb_args < MAX_ARGS && args_present[nb_args])
nb_args++;
for(i = nb_args; i < MAX_ARGS; i++) {
if (args_present[i])
error("inconsistent argument numbering in %s", name);
}
/* output C code */
fprintf(outfile, "extern void %s();\n", name);
fprintf(outfile, "static inline void gen_%s(", name);
if (nb_args == 0) {
fprintf(outfile, "void");
} else {
for(i = 0; i < nb_args; i++) {
if (i != 0)
fprintf(outfile, ", ");
fprintf(outfile, "long param%d", i + 1);
}
}
fprintf(outfile, ")\n");
fprintf(outfile, "{\n");
fprintf(outfile, " memcpy(gen_code_ptr, &%s, %d);\n", name, copy_size);
/* patch relocations */
switch(e_machine) {
case EM_386:
{
Elf32_Rel *rel;
char name[256];
int type;
long addend;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, sizeof(name), "param%s", p);
} else {
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
}
type = ELF32_R_TYPE(rel->r_info);
addend = get32((uint32_t *)(text + rel->r_offset));
switch(type) {
case R_386_32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s + %ld;\n",
rel->r_offset - offset, name, addend);
break;
case R_386_PC32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s - (long)(gen_code_ptr + %ld) + %ld;\n",
rel->r_offset - offset, name, rel->r_offset - offset, addend);
break;
default:
error("unsupported i386 relocation (%d)", type);
}
}
}
}
break;
default:
error("unsupported CPU for relocations (%d)", e_machine);
}
fprintf(outfile, " gen_code_ptr += %d;\n", copy_size);
fprintf(outfile, "}\n\n");
}
/* load an elf object file */
int load_elf(const char *filename, FILE *outfile)
{
int fd;
Elf32_Ehdr ehdr;
Elf32_Shdr *sec, *shdr, *symtab_sec, *strtab_sec, *text_sec;
int i, j, nb_syms;
Elf32_Sym *symtab, *sym;
const char *cpu_name;
char *shstr, *strtab;
uint8_t *text;
void *relocs;
int nb_relocs, reloc_sh_type;
fd = open(filename, O_RDONLY);
if (fd < 0)
error("can't open file '%s'", filename);
/* Read ELF header. */
if (read(fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr))
error("unable to read file header");
/* Check ELF identification. */
if (ehdr.e_ident[EI_MAG0] != ELFMAG0
|| ehdr.e_ident[EI_MAG1] != ELFMAG1
|| ehdr.e_ident[EI_MAG2] != ELFMAG2
|| ehdr.e_ident[EI_MAG3] != ELFMAG3
|| ehdr.e_ident[EI_CLASS] != ELFCLASS32
|| ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
error("bad ELF header");
}
do_swap = elf_must_swap(&ehdr);
if (do_swap)
elf_swap_ehdr(&ehdr);
if (ehdr.e_type != ET_REL)
error("ELF object file expected");
if (ehdr.e_version != EV_CURRENT)
error("Invalid ELF version");
e_machine = ehdr.e_machine;
/* read section headers */
shdr = load_data(fd, ehdr.e_shoff, ehdr.e_shnum * sizeof(Elf32_Shdr));
if (do_swap) {
for(i = 0; i < ehdr.e_shnum; i++) {
elf_swap_shdr(&shdr[i]);
}
}
sec = &shdr[ehdr.e_shstrndx];
shstr = load_data(fd, sec->sh_offset, sec->sh_size);
/* text section */
text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text");
if (!text_sec)
error("could not find .text section");
text = load_data(fd, text_sec->sh_offset, text_sec->sh_size);
/* find text relocations, if any */
nb_relocs = 0;
relocs = NULL;
reloc_sh_type = 0;
for(i = 0; i < ehdr.e_shnum; i++) {
sec = &shdr[i];
if ((sec->sh_type == SHT_REL || sec->sh_type == SHT_RELA) &&
sec->sh_info == (text_sec - shdr)) {
reloc_sh_type = sec->sh_type;
relocs = load_data(fd, sec->sh_offset, sec->sh_size);
nb_relocs = sec->sh_size / sec->sh_entsize;
if (do_swap) {
if (sec->sh_type == SHT_REL) {
Elf32_Rel *rel = relocs;
for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) {
swab32s(&rel->r_offset);
swab32s(&rel->r_info);
}
} else {
Elf32_Rela *rel = relocs;
for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) {
swab32s(&rel->r_offset);
swab32s(&rel->r_info);
swab32s(&rel->r_addend);
}
}
}
break;
}
}
symtab_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".symtab");
if (!symtab_sec)
error("could not find .symtab section");
strtab_sec = &shdr[symtab_sec->sh_link];
symtab = load_data(fd, symtab_sec->sh_offset, symtab_sec->sh_size);
strtab = load_data(fd, strtab_sec->sh_offset, strtab_sec->sh_size);
nb_syms = symtab_sec->sh_size / sizeof(Elf32_Sym);
if (do_swap) {
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
swab32s(&sym->st_name);
swab32s(&sym->st_value);
swab32s(&sym->st_size);
swab16s(&sym->st_shndx);
}
}
switch(e_machine) {
case EM_386:
cpu_name = "i386";
break;
case EM_PPC:
cpu_name = "ppc";
break;
case EM_MIPS:
cpu_name = "mips";
break;
case EM_ARM:
cpu_name = "arm";
break;
case EM_SPARC:
cpu_name = "sparc";
break;
default:
error("unsupported CPU (e_machine=%d)", e_machine);
}
fprintf(outfile, "#include \"gen-%s.h\"\n\n", cpu_name);
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
const char *name;
name = strtab + sym->st_name;
if (strstart(name, "op_", NULL) ||
strstart(name, "op1_", NULL) ||
strstart(name, "op2_", NULL) ||
strstart(name, "op3_", NULL)) {
#if 0
printf("%4d: %s pos=0x%08x len=%d\n",
i, name, sym->st_value, sym->st_size);
#endif
if (sym->st_shndx != (text_sec - shdr))
error("invalid section for opcode (0x%x)", sym->st_shndx);
gen_code(name, sym->st_value, sym->st_size, outfile,
text, relocs, nb_relocs, reloc_sh_type, symtab, strtab);
}
}
close(fd);
return 0;
}
void usage(void)
{
printf("dyngen (c) 2003 Fabrice Bellard\n"
"usage: dyngen [-o outfile] objfile\n"
"Generate a dynamic code generator from an object file\n");
exit(1);
}
int main(int argc, char **argv)
{
int c;
const char *filename, *outfilename;
FILE *outfile;
outfilename = "out.c";
for(;;) {
c = getopt(argc, argv, "ho:");
if (c == -1)
break;
switch(c) {
case 'h':
usage();
break;
case 'o':
outfilename = optarg;
break;
}
}
if (optind >= argc)
usage();
filename = argv[optind];
outfile = fopen(outfilename, "w");
if (!outfile)
error("could not open '%s'", outfilename);
load_elf(filename, outfile);
fclose(outfile);
return 0;
}

8
gen-i386.h Normal file
View File

@ -0,0 +1,8 @@
static inline void gen_start(void)
{
}
static inline void gen_end(void)
{
*gen_code_ptr++ = 0xc3; /* ret */
}

View File

@ -191,6 +191,41 @@ void INT_handler(int num, void *env)
}
/***********************************************************/
/* new CPU core */
void port_outb(int addr, int val)
{
fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
}
void port_outw(int addr, int val)
{
fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
}
void port_outl(int addr, int val)
{
fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
}
int port_inb(int addr)
{
fprintf(stderr, "inb: port=0x%04x\n", addr);
return 0;
}
int port_inw(int addr)
{
fprintf(stderr, "inw: port=0x%04x\n", addr);
return 0;
}
int port_inl(int addr)
{
fprintf(stderr, "inl: port=0x%04x\n", addr);
return 0;
}
/* XXX: currently we use LDT entries */
#define __USER_CS (0x23|4)
@ -270,6 +305,7 @@ int main(int argc, char **argv)
LDT[__USER_DS >> 3].dwSelLimit = 0xfffff;
LDT[__USER_DS >> 3].lpSelBase = NULL;
init_npu();
build_decode_tables();
for(;;) {
int err;

813
op-i386.c
View File

@ -8,6 +8,8 @@ typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
#define NULL 0
#ifdef __i386__
register int T0 asm("esi");
register int T1 asm("ebx");
@ -74,13 +76,12 @@ extern int __op_param1, __op_param2, __op_param3;
#include "cpu-i386.h"
typedef struct CCTable {
int (*compute_c)(void); /* return the C flag */
int (*compute_z)(void); /* return the Z flag */
int (*compute_s)(void); /* return the S flag */
int (*compute_o)(void); /* return the O flag */
int (*compute_all)(void); /* return all the flags */
int (*compute_c)(void); /* return the C flag */
} CCTable;
extern CCTable cc_table[];
uint8_t parity_table[256] = {
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
@ -116,121 +117,31 @@ uint8_t parity_table[256] = {
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
};
static int compute_eflags_all(void)
{
return CC_SRC;
}
static int compute_eflags_addb(void)
{
int cf, pf, af, zf, sf, of;
int src1, src2;
src1 = CC_SRC;
src2 = CC_DST - CC_SRC;
cf = (uint8_t)CC_DST < (uint8_t)src1;
pf = parity_table[(uint8_t)CC_DST];
af = (CC_DST ^ src1 ^ src2) & 0x10;
zf = ((uint8_t)CC_DST != 0) << 6;
sf = CC_DST & 0x80;
of = ((src1 ^ src2 ^ -1) & (src1 ^ CC_DST) & 0x80) << 4;
return cf | pf | af | zf | sf | of;
}
static int compute_eflags_subb(void)
{
int cf, pf, af, zf, sf, of;
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
cf = (uint8_t)src1 < (uint8_t)src2;
pf = parity_table[(uint8_t)CC_DST];
af = (CC_DST ^ src1 ^ src2) & 0x10;
zf = ((uint8_t)CC_DST != 0) << 6;
sf = CC_DST & 0x80;
of = ((src1 ^ src2 ^ -1) & (src1 ^ CC_DST) & 0x80) << 4;
return cf | pf | af | zf | sf | of;
}
static int compute_eflags_logicb(void)
{
cf = 0;
pf = parity_table[(uint8_t)CC_DST];
af = 0;
zf = ((uint8_t)CC_DST != 0) << 6;
sf = CC_DST & 0x80;
of = 0;
return cf | pf | af | zf | sf | of;
}
static int compute_eflags_incb(void)
{
int cf, pf, af, zf, sf, of;
int src2;
src1 = CC_DST - 1;
src2 = 1;
cf = CC_SRC;
pf = parity_table[(uint8_t)CC_DST];
af = (CC_DST ^ src1 ^ src2) & 0x10;
zf = ((uint8_t)CC_DST != 0) << 6;
sf = CC_DST & 0x80;
of = ((src1 ^ src2 ^ -1) & (src1 ^ CC_DST) & 0x80) << 4;
return cf | pf | af | zf | sf | of;
}
static int compute_eflags_decb(void)
{
int cf, pf, af, zf, sf, of;
int src1, src2;
src1 = CC_DST + 1;
src2 = 1;
cf = (uint8_t)src1 < (uint8_t)src2;
pf = parity_table[(uint8_t)CC_DST];
af = (CC_DST ^ src1 ^ src2) & 0x10;
zf = ((uint8_t)CC_DST != 0) << 6;
sf = CC_DST & 0x80;
of = ((src1 ^ src2 ^ -1) & (src1 ^ CC_DST) & 0x80) << 4;
return cf | pf | af | zf | sf | of;
}
static int compute_eflags_shlb(void)
{
cf = CC_SRC;
pf = parity_table[(uint8_t)CC_DST];
af = 0; /* undefined */
zf = ((uint8_t)CC_DST != 0) << 6;
sf = CC_DST & 0x80;
of = 0; /* undefined */
return cf | pf | af | zf | sf | of;
}
static int compute_eflags_shrb(void)
{
cf = CC_SRC & 1;
pf = parity_table[(uint8_t)CC_DST];
af = 0; /* undefined */
zf = ((uint8_t)CC_DST != 0) << 6;
sf = CC_DST & 0x80;
of = sf << 4;
return cf | pf | af | zf | sf | of;
}
static int compute_eflags_mul(void)
{
cf = (CC_SRC != 0);
pf = 0; /* undefined */
af = 0; /* undefined */
zf = 0; /* undefined */
sf = 0; /* undefined */
of = cf << 11;
return cf | pf | af | zf | sf | of;
}
CTable cc_table[CC_OP_NB] = {
[CC_OP_DYNAMIC] = { NULL, NULL, NULL },
[CC_OP_EFLAGS] = { NULL, NULL, NULL },
/* modulo 17 table */
const uint8_t rclw_table[32] = {
0, 1, 2, 3, 4, 5, 6, 7,
8, 9,10,11,12,13,14,15,
16, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9,10,11,12,13,14,
};
/* modulo 9 table */
const uint8_t rclb_table[32] = {
0, 1, 2, 3, 4, 5, 6, 7,
8, 0, 1, 2, 3, 4, 5, 6,
7, 8, 0, 1, 2, 3, 4, 5,
6, 7, 8, 0, 1, 2, 3, 4,
};
/* n must be a constant to be efficient */
static inline int lshift(int x, int n)
{
if (n >= 0)
return x << n;
else
return x >> (-n);
}
/* we define the various pieces of code used by the JIT */
#define REG EAX
@ -365,338 +276,6 @@ void OPPROTO op_testl_T0_T1_cc(void)
CC_DST = T0 & T1;
}
/* shifts */
void OPPROTO op_roll_T0_T1_cc(void)
{
int count;
count = T1 & 0x1f;
if (count) {
CC_SRC = T0;
T0 = (T0 << count) | (T0 >> (32 - count));
CC_DST = T0;
CC_OP = CC_OP_ROLL;
}
}
void OPPROTO op_rolw_T0_T1_cc(void)
{
int count;
count = T1 & 0xf;
if (count) {
T0 = T0 & 0xffff;
CC_SRC = T0;
T0 = (T0 << count) | (T0 >> (16 - count));
CC_DST = T0;
CC_OP = CC_OP_ROLW;
}
}
void OPPROTO op_rolb_T0_T1_cc(void)
{
int count;
count = T1 & 0x7;
if (count) {
T0 = T0 & 0xff;
CC_SRC = T0;
T0 = (T0 << count) | (T0 >> (8 - count));
CC_DST = T0;
CC_OP = CC_OP_ROLB;
}
}
void OPPROTO op_rorl_T0_T1_cc(void)
{
int count;
count = T1 & 0x1f;
if (count) {
CC_SRC = T0;
T0 = (T0 >> count) | (T0 << (32 - count));
CC_DST = T0;
CC_OP = CC_OP_RORB;
}
}
void OPPROTO op_rorw_T0_T1_cc(void)
{
int count;
count = T1 & 0xf;
if (count) {
CC_SRC = T0;
T0 = (T0 >> count) | (T0 << (16 - count));
CC_DST = T0;
CC_OP = CC_OP_RORW;
}
}
void OPPROTO op_rorb_T0_T1_cc(void)
{
int count;
count = T1 & 0x7;
if (count) {
CC_SRC = T0;
T0 = (T0 >> count) | (T0 << (8 - count));
CC_DST = T0;
CC_OP = CC_OP_RORL;
}
}
/* modulo 17 table */
const uint8_t rclw_table[32] = {
0, 1, 2, 3, 4, 5, 6, 7,
8, 9,10,11,12,13,14,15,
16, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9,10,11,12,13,14,
};
/* modulo 9 table */
const uint8_t rclb_table[32] = {
0, 1, 2, 3, 4, 5, 6, 7,
8, 0, 1, 2, 3, 4, 5, 6,
7, 8, 0, 1, 2, 3, 4, 5,
6, 7, 8, 0, 1, 2, 3, 4,
};
void helper_rcll_T0_T1_cc(void)
{
int count, res;
count = T1 & 0x1f;
if (count) {
CC_SRC = T0;
res = (T0 << count) | (cc_table[CC_OP].compute_c() << (count - 1));
if (count > 1)
res |= T0 >> (33 - count);
T0 = res;
CC_DST = T0 ^ CC_SRC; /* O is in bit 31 */
CC_SRC >>= (32 - count); /* CC is in bit 0 */
CC_OP = CC_OP_RCLL;
}
}
void OPPROTO op_rcll_T0_T1_cc(void)
{
helper_rcll_T0_T1_cc();
}
void OPPROTO op_rclw_T0_T1_cc(void)
{
int count;
count = rclw_table[T1 & 0x1f];
if (count) {
T0 = T0 & 0xffff;
CC_SRC = T0;
T0 = (T0 << count) | (cc_table[CC_OP].compute_c() << (count - 1)) |
(T0 >> (17 - count));
CC_DST = T0 ^ CC_SRC;
CC_SRC >>= (16 - count);
CC_OP = CC_OP_RCLW;
}
}
void OPPROTO op_rclb_T0_T1_cc(void)
{
int count;
count = rclb_table[T1 & 0x1f];
if (count) {
T0 = T0 & 0xff;
CC_SRC = T0;
T0 = (T0 << count) | (cc_table[CC_OP].compute_c() << (count - 1)) |
(T0 >> (9 - count));
CC_DST = T0 ^ CC_SRC;
CC_SRC >>= (8 - count);
CC_OP = CC_OP_RCLB;
}
}
void OPPROTO op_rcrl_T0_T1_cc(void)
{
int count, res;
count = T1 & 0x1f;
if (count) {
CC_SRC = T0;
res = (T0 >> count) | (cc_table[CC_OP].compute_c() << (32 - count));
if (count > 1)
res |= T0 << (33 - count);
T0 = res;
CC_DST = T0 ^ CC_SRC;
CC_SRC >>= (count - 1);
CC_OP = CC_OP_RCLL;
}
}
void OPPROTO op_rcrw_T0_T1_cc(void)
{
int count;
count = rclw_table[T1 & 0x1f];
if (count) {
T0 = T0 & 0xffff;
CC_SRC = T0;
T0 = (T0 >> count) | (cc_table[CC_OP].compute_c() << (16 - count)) |
(T0 << (17 - count));
CC_DST = T0 ^ CC_SRC;
CC_SRC >>= (count - 1);
CC_OP = CC_OP_RCLW;
}
}
void OPPROTO op_rcrb_T0_T1_cc(void)
{
int count;
count = rclb_table[T1 & 0x1f];
if (count) {
T0 = T0 & 0xff;
CC_SRC = T0;
T0 = (T0 >> count) | (cc_table[CC_OP].compute_c() << (8 - count)) |
(T0 << (9 - count));
CC_DST = T0 ^ CC_SRC;
CC_SRC >>= (count - 1);
CC_OP = CC_OP_RCLB;
}
}
void OPPROTO op_shll_T0_T1_cc(void)
{
int count;
count = T1 & 0x1f;
if (count == 1) {
CC_SRC = T0;
T0 = T0 << 1;
CC_DST = T0;
CC_OP = CC_OP_ADDL;
} else if (count) {
CC_SRC = T0 >> (32 - count);
T0 = T0 << count;
CC_DST = T0;
CC_OP = CC_OP_SHLL;
}
}
void OPPROTO op_shlw_T0_T1_cc(void)
{
int count;
count = T1 & 0x1f;
if (count == 1) {
CC_SRC = T0;
T0 = T0 << 1;
CC_DST = T0;
CC_OP = CC_OP_ADDW;
} else if (count) {
CC_SRC = T0 >> (16 - count);
T0 = T0 << count;
CC_DST = T0;
CC_OP = CC_OP_SHLW;
}
}
void OPPROTO op_shlb_T0_T1_cc(void)
{
int count;
count = T1 & 0x1f;
if (count == 1) {
CC_SRC = T0;
T0 = T0 << 1;
CC_DST = T0;
CC_OP = CC_OP_ADDB;
} else if (count) {
CC_SRC = T0 >> (8 - count);
T0 = T0 << count;
CC_DST = T0;
CC_OP = CC_OP_SHLB;
}
}
void OPPROTO op_shrl_T0_T1_cc(void)
{
int count;
count = T1 & 0x1f;
if (count == 1) {
CC_SRC = T0;
T0 = T0 >> 1;
CC_DST = T0;
CC_OP = CC_OP_SHRL;
} else if (count) {
CC_SRC = T0 >> (count - 1);
T0 = T0 >> count;
CC_DST = T0;
CC_OP = CC_OP_SHLL;
}
}
void OPPROTO op_shrw_T0_T1_cc(void)
{
int count;
count = T1 & 0x1f;
if (count == 1) {
T0 = T0 & 0xffff;
CC_SRC = T0;
T0 = T0 >> 1;
CC_DST = T0;
CC_OP = CC_OP_SHRW;
} else if (count) {
T0 = T0 & 0xffff;
CC_SRC = T0 >> (count - 1);
T0 = T0 >> count;
CC_DST = T0;
CC_OP = CC_OP_SHLW;
}
}
void OPPROTO op_shrb_T0_T1_cc(void)
{
int count;
count = T1 & 0x1f;
if (count == 1) {
T0 = T0 & 0xff;
CC_SRC = T0;
T0 = T0 >> 1;
CC_DST = T0;
CC_OP = CC_OP_SHRB;
} else if (count) {
T0 = T0 & 0xff;
CC_SRC = T0 >> (count - 1);
T0 = T0 >> count;
CC_DST = T0;
CC_OP = CC_OP_SHLB;
}
}
void OPPROTO op_sarl_T0_T1_cc(void)
{
int count;
count = T1 & 0x1f;
if (count) {
CC_SRC = (int32_t)T0 >> (count - 1);
T0 = (int32_t)T0 >> count;
CC_DST = T0;
CC_OP = CC_OP_SHLL;
}
}
void OPPROTO op_sarw_T0_T1_cc(void)
{
int count;
count = T1 & 0x1f;
if (count) {
CC_SRC = (int16_t)T0 >> (count - 1);
T0 = (int16_t)T0 >> count;
CC_DST = T0;
CC_OP = CC_OP_SHLW;
}
}
void OPPROTO op_sarb_T0_T1_cc(void)
{
int count;
count = T1 & 0x1f;
if (count) {
CC_SRC = (int8_t)T0 >> (count - 1);
T0 = (int8_t)T0 >> count;
CC_DST = T0;
CC_OP = CC_OP_SHLB;
}
}
/* multiply/divide */
void OPPROTO op_mulb_AL_T0(void)
{
@ -924,41 +503,6 @@ void OPPROTO op_stl_T0_A0(void)
stl((uint8_t *)A0, T0);
}
/* flags */
void OPPROTO op_set_cc_op(void)
{
CC_OP = PARAM1;
}
void OPPROTO op_movl_eflags_T0(void)
{
CC_SRC = T0;
DF = (T0 & DIRECTION_FLAG) ? -1 : 1;
}
void OPPROTO op_movb_eflags_T0(void)
{
int cc_o;
cc_o = cc_table[CC_OP].compute_o();
CC_SRC = T0 | (cc_o << 11);
}
void OPPROTO op_movl_T0_eflags(void)
{
cc_table[CC_OP].compute_eflags();
}
void OPPROTO op_cld(void)
{
DF = 1;
}
void OPPROTO op_std(void)
{
DF = -1;
}
/* jumps */
/* indirect jump */
@ -972,54 +516,20 @@ void OPPROTO op_jmp_im(void)
PC = PARAM1;
}
void OPPROTO op_jne_b(void)
{
if ((uint8_t)CC_DST != 0)
PC += PARAM1;
else
PC += PARAM2;
FORCE_RET();
}
void OPPROTO op_jne_w(void)
{
if ((uint16_t)CC_DST != 0)
PC += PARAM1;
else
PC += PARAM2;
FORCE_RET();
}
void OPPROTO op_jne_l(void)
{
if (CC_DST != 0)
PC += PARAM1;
else
PC += PARAM2;
FORCE_RET(); /* generate a return so that gcc does not generate an
early function return */
}
/* string ops */
#define ldul ldl
#define SUFFIX b
#define SHIFT 0
#include "opstring_template.h"
#undef SUFFIX
#include "ops_template.h"
#undef SHIFT
#define SUFFIX w
#define SHIFT 1
#include "opstring_template.h"
#undef SUFFIX
#include "ops_template.h"
#undef SHIFT
#define SUFFIX l
#define SHIFT 2
#include "opstring_template.h"
#undef SUFFIX
#include "ops_template.h"
#undef SHIFT
/* sign extend */
@ -1095,3 +605,264 @@ void op_addl_ESP_im(void)
{
ESP += PARAM1;
}
/* flags handling */
/* slow jumps cases (compute x86 flags) */
void OPPROTO op_jo_cc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
if (eflags & CC_O)
PC += PARAM1;
else
PC += PARAM2;
}
void OPPROTO op_jb_cc(void)
{
if (cc_table[CC_OP].compute_c())
PC += PARAM1;
else
PC += PARAM2;
}
void OPPROTO op_jz_cc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
if (eflags & CC_Z)
PC += PARAM1;
else
PC += PARAM2;
}
void OPPROTO op_jbe_cc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
if (eflags & (CC_Z | CC_C))
PC += PARAM1;
else
PC += PARAM2;
}
void OPPROTO op_js_cc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
if (eflags & CC_S)
PC += PARAM1;
else
PC += PARAM2;
}
void OPPROTO op_jp_cc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
if (eflags & CC_P)
PC += PARAM1;
else
PC += PARAM2;
}
void OPPROTO op_jl_cc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
if ((eflags ^ (eflags >> 4)) & 0x80)
PC += PARAM1;
else
PC += PARAM2;
}
void OPPROTO op_jle_cc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
if (((eflags ^ (eflags >> 4)) & 0x80) || (eflags & CC_Z))
PC += PARAM1;
else
PC += PARAM2;
}
/* slow set cases (compute x86 flags) */
void OPPROTO op_seto_T0_cc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
T0 = (eflags >> 11) & 1;
}
void OPPROTO op_setb_T0_cc(void)
{
T0 = cc_table[CC_OP].compute_c();
}
void OPPROTO op_setz_T0_cc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
T0 = (eflags >> 6) & 1;
}
void OPPROTO op_setbe_T0_cc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
T0 = (eflags & (CC_Z | CC_C)) != 0;
}
void OPPROTO op_sets_T0_cc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
T0 = (eflags >> 7) & 1;
}
void OPPROTO op_setp_T0_cc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
T0 = (eflags >> 2) & 1;
}
void OPPROTO op_setl_T0_cc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
T0 = ((eflags ^ (eflags >> 4)) >> 7) & 1;
}
void OPPROTO op_setle_T0_cc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
T0 = (((eflags ^ (eflags >> 4)) & 0x80) || (eflags & CC_Z)) != 0;
}
void OPPROTO op_xor_T0_1(void)
{
T0 ^= 1;
}
void OPPROTO op_set_cc_op(void)
{
CC_OP = PARAM1;
}
void OPPROTO op_movl_eflags_T0(void)
{
CC_SRC = T0;
DF = 1 - (2 * ((T0 >> 10) & 1));
}
/* XXX: compute only O flag */
void OPPROTO op_movb_eflags_T0(void)
{
int of;
of = cc_table[CC_OP].compute_all() & CC_O;
CC_SRC = T0 | of;
}
void OPPROTO op_movl_T0_eflags(void)
{
T0 = cc_table[CC_OP].compute_all();
T0 |= (DF & DIRECTION_FLAG);
}
void OPPROTO op_cld(void)
{
DF = 1;
}
void OPPROTO op_std(void)
{
DF = -1;
}
void OPPROTO op_clc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
eflags &= ~CC_C;
CC_SRC = eflags;
}
void OPPROTO op_stc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
eflags |= CC_C;
CC_SRC = eflags;
}
void OPPROTO op_cmc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
eflags ^= CC_C;
CC_SRC = eflags;
}
static int compute_all_eflags(void)
{
return CC_SRC;
}
static int compute_c_eflags(void)
{
return CC_SRC & CC_C;
}
static int compute_c_mul(void)
{
int cf;
cf = (CC_SRC != 0);
return cf;
}
static int compute_all_mul(void)
{
int cf, pf, af, zf, sf, of;
cf = (CC_SRC != 0);
pf = 0; /* undefined */
af = 0; /* undefined */
zf = 0; /* undefined */
sf = 0; /* undefined */
of = cf << 11;
return cf | pf | af | zf | sf | of;
}
CCTable cc_table[CC_OP_NB] = {
[CC_OP_DYNAMIC] = { /* should never happen */ },
[CC_OP_EFLAGS] = { compute_all_eflags, compute_c_eflags },
[CC_OP_MUL] = { compute_all_mul, compute_c_mul },
[CC_OP_ADDB] = { compute_all_addb, compute_c_addb },
[CC_OP_ADDW] = { compute_all_addw, compute_c_addw },
[CC_OP_ADDL] = { compute_all_addl, compute_c_addl },
[CC_OP_SUBB] = { compute_all_subb, compute_c_subb },
[CC_OP_SUBW] = { compute_all_subw, compute_c_subw },
[CC_OP_SUBL] = { compute_all_subl, compute_c_subl },
[CC_OP_LOGICB] = { compute_all_logicb, compute_c_logicb },
[CC_OP_LOGICW] = { compute_all_logicw, compute_c_logicw },
[CC_OP_LOGICL] = { compute_all_logicl, compute_c_logicl },
[CC_OP_INCB] = { compute_all_incb, compute_c_incb },
[CC_OP_INCW] = { compute_all_incw, compute_c_incw },
[CC_OP_INCL] = { compute_all_incl, compute_c_incl },
[CC_OP_DECB] = { compute_all_decb, compute_c_incb },
[CC_OP_DECW] = { compute_all_decw, compute_c_incw },
[CC_OP_DECL] = { compute_all_decl, compute_c_incl },
[CC_OP_SHLB] = { compute_all_shlb, compute_c_shlb },
[CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw },
[CC_OP_SHLL] = { compute_all_shll, compute_c_shll },
};

628
ops_template.h Normal file
View File

@ -0,0 +1,628 @@
#define DATA_BITS (1 << (3 + SHIFT))
#define SHIFT_MASK (DATA_BITS - 1)
#define SIGN_MASK (1 << (DATA_BITS - 1))
#if DATA_BITS == 8
#define SUFFIX b
#define DATA_TYPE uint8_t
#define DATA_STYPE int8_t
#define DATA_MASK 0xff
#elif DATA_BITS == 16
#define SUFFIX w
#define DATA_TYPE uint16_t
#define DATA_STYPE int16_t
#define DATA_MASK 0xffff
#elif DATA_BITS == 32
#define SUFFIX l
#define DATA_TYPE uint32_t
#define DATA_STYPE int32_t
#define DATA_MASK 0xffffffff
#else
#error unhandled operand size
#endif
/* dynamic flags computation */
static int glue(compute_all_add, SUFFIX)(void)
{
int cf, pf, af, zf, sf, of;
int src1, src2;
src1 = CC_SRC;
src2 = CC_DST - CC_SRC;
cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1;
pf = parity_table[(uint8_t)CC_DST];
af = (CC_DST ^ src1 ^ src2) & 0x10;
zf = ((DATA_TYPE)CC_DST != 0) << 6;
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
return cf | pf | af | zf | sf | of;
}
static int glue(compute_c_add, SUFFIX)(void)
{
int src1, cf;
src1 = CC_SRC;
cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1;
return cf;
}
static int glue(compute_all_sub, SUFFIX)(void)
{
int cf, pf, af, zf, sf, of;
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
pf = parity_table[(uint8_t)CC_DST];
af = (CC_DST ^ src1 ^ src2) & 0x10;
zf = ((DATA_TYPE)CC_DST != 0) << 6;
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
return cf | pf | af | zf | sf | of;
}
static int glue(compute_c_sub, SUFFIX)(void)
{
int src1, src2, cf;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
cf = (DATA_TYPE)src1 < (DATA_TYPE)src1;
return cf;
}
static int glue(compute_all_logic, SUFFIX)(void)
{
int cf, pf, af, zf, sf, of;
cf = 0;
pf = parity_table[(uint8_t)CC_DST];
af = 0;
zf = ((DATA_TYPE)CC_DST != 0) << 6;
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
of = 0;
return cf | pf | af | zf | sf | of;
}
static int glue(compute_c_logic, SUFFIX)(void)
{
return 0;
}
static int glue(compute_all_inc, SUFFIX)(void)
{
int cf, pf, af, zf, sf, of;
int src1, src2;
src1 = CC_DST - 1;
src2 = 1;
cf = CC_SRC;
pf = parity_table[(uint8_t)CC_DST];
af = (CC_DST ^ src1 ^ src2) & 0x10;
zf = ((DATA_TYPE)CC_DST != 0) << 6;
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
return cf | pf | af | zf | sf | of;
}
static int glue(compute_c_inc, SUFFIX)(void)
{
return CC_SRC;
}
static int glue(compute_all_dec, SUFFIX)(void)
{
int cf, pf, af, zf, sf, of;
int src1, src2;
src1 = CC_DST + 1;
src2 = 1;
cf = CC_SRC;
pf = parity_table[(uint8_t)CC_DST];
af = (CC_DST ^ src1 ^ src2) & 0x10;
zf = ((DATA_TYPE)CC_DST != 0) << 6;
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
return cf | pf | af | zf | sf | of;
}
static int glue(compute_all_shl, SUFFIX)(void)
{
int cf, pf, af, zf, sf, of;
cf = CC_SRC & 1;
pf = parity_table[(uint8_t)CC_DST];
af = 0; /* undefined */
zf = ((DATA_TYPE)CC_DST != 0) << 6;
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
of = sf << 4; /* only meaniful for shr with count == 1 */
return cf | pf | af | zf | sf | of;
}
static int glue(compute_c_shl, SUFFIX)(void)
{
return CC_SRC & 1;
}
/* various optimized jumps cases */
void OPPROTO glue(op_jb_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
if ((DATA_TYPE)src1 < (DATA_TYPE)src2)
PC += PARAM1;
else
PC += PARAM2;
FORCE_RET();
}
void OPPROTO glue(op_jz_sub, SUFFIX)(void)
{
if ((DATA_TYPE)CC_DST != 0)
PC += PARAM1;
else
PC += PARAM2;
FORCE_RET();
}
void OPPROTO glue(op_jbe_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
if ((DATA_TYPE)src1 <= (DATA_TYPE)src2)
PC += PARAM1;
else
PC += PARAM2;
FORCE_RET();
}
void OPPROTO glue(op_js_sub, SUFFIX)(void)
{
if (CC_DST & SIGN_MASK)
PC += PARAM1;
else
PC += PARAM2;
FORCE_RET();
}
void OPPROTO glue(op_jl_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
if ((DATA_STYPE)src1 < (DATA_STYPE)src2)
PC += PARAM1;
else
PC += PARAM2;
FORCE_RET();
}
void OPPROTO glue(op_jle_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
if ((DATA_STYPE)src1 <= (DATA_STYPE)src2)
PC += PARAM1;
else
PC += PARAM2;
FORCE_RET();
}
/* various optimized set cases */
void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
T0 = ((DATA_TYPE)src1 < (DATA_TYPE)src2);
}
void OPPROTO glue(op_setz_T0_sub, SUFFIX)(void)
{
T0 = ((DATA_TYPE)CC_DST != 0);
}
void OPPROTO glue(op_setbe_T0_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
T0 = ((DATA_TYPE)src1 <= (DATA_TYPE)src2);
}
void OPPROTO glue(op_sets_T0_sub, SUFFIX)(void)
{
T0 = lshift(CC_DST, -(DATA_BITS - 1)) & 1;
}
void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
T0 = ((DATA_STYPE)src1 < (DATA_STYPE)src2);
}
void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
T0 = ((DATA_STYPE)src1 <= (DATA_STYPE)src2);
}
/* shifts */
void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & SHIFT_MASK;
if (count) {
CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C);
src = T0;
T0 &= DATA_MASK;
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
(T0 & CC_C);
CC_OP = CC_OP_EFLAGS;
}
}
void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & SHIFT_MASK;
if (count) {
CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C);
src = T0;
T0 &= DATA_MASK;
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
((T0 >> (DATA_BITS - 1)) & CC_C);
CC_OP = CC_OP_EFLAGS;
}
}
void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void)
{
int count, res, eflags;
unsigned int src;
count = T1 & 0x1f;
#if DATA_BITS == 16
count = rclw_table[count];
#elif DATA_BITS == 8
count = rclb_table[count];
#endif
if (count) {
eflags = cc_table[CC_OP].compute_all();
src = T0;
res = (T0 << count) | ((eflags & CC_C) << (count - 1));
if (count > 1)
res |= T0 >> (DATA_BITS + 1 - count);
T0 = res;
CC_SRC = (eflags & ~(CC_C | CC_O)) |
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
((src >> (DATA_BITS - count)) & CC_C);
CC_OP = CC_OP_EFLAGS;
}
}
void OPPROTO glue(glue(op_rcr, SUFFIX), _T0_T1_cc)(void)
{
int count, res, eflags;
unsigned int src;
count = T1 & 0x1f;
#if DATA_BITS == 16
count = rclw_table[count];
#elif DATA_BITS == 8
count = rclb_table[count];
#endif
if (count) {
eflags = cc_table[CC_OP].compute_all();
src = T0;
res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count));
if (count > 1)
res |= T0 << (DATA_BITS + 1 - count);
T0 = res;
CC_SRC = (eflags & ~(CC_C | CC_O)) |
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
((src >> (count - 1)) & CC_C);
CC_OP = CC_OP_EFLAGS;
}
}
void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & 0x1f;
if (count == 1) {
CC_SRC = T0;
T0 = T0 << 1;
CC_DST = T0;
CC_OP = CC_OP_ADDB + SHIFT;
} else if (count) {
CC_SRC = T0 >> (DATA_BITS - count);
T0 = T0 << count;
CC_DST = T0;
CC_OP = CC_OP_SHLB + SHIFT;
}
}
void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & 0x1f;
if (count) {
T0 &= DATA_MASK;
CC_SRC = T0 >> (count - 1);
T0 = T0 >> count;
CC_DST = T0;
CC_OP = CC_OP_SHLB + SHIFT;
}
}
void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & 0x1f;
if (count) {
src = (DATA_STYPE)T0;
CC_SRC = src >> (count - 1);
T0 = src >> count;
CC_DST = T0;
CC_OP = CC_OP_SHLB + SHIFT;
}
}
/* string operations */
/* XXX: maybe use lower level instructions to ease exception handling */
void OPPROTO glue(op_movs, SUFFIX)(void)
{
int v;
v = glue(ldu, SUFFIX)((void *)ESI);
glue(st, SUFFIX)((void *)EDI, v);
ESI += (DF << SHIFT);
EDI += (DF << SHIFT);
}
void OPPROTO glue(op_rep_movs, SUFFIX)(void)
{
int v, inc;
inc = (DF << SHIFT);
while (ECX != 0) {
v = glue(ldu, SUFFIX)((void *)ESI);
glue(st, SUFFIX)((void *)EDI, v);
ESI += inc;
EDI += inc;
ECX--;
}
}
void OPPROTO glue(op_stos, SUFFIX)(void)
{
glue(st, SUFFIX)((void *)EDI, EAX);
EDI += (DF << SHIFT);
}
void OPPROTO glue(op_rep_stos, SUFFIX)(void)
{
int inc;
inc = (DF << SHIFT);
while (ECX != 0) {
glue(st, SUFFIX)((void *)EDI, EAX);
EDI += inc;
ECX--;
}
}
void OPPROTO glue(op_lods, SUFFIX)(void)
{
int v;
v = glue(ldu, SUFFIX)((void *)ESI);
#if SHIFT == 0
EAX = (EAX & ~0xff) | v;
#elif SHIFT == 1
EAX = (EAX & ~0xffff) | v;
#else
EAX = v;
#endif
ESI += (DF << SHIFT);
}
/* don't know if it is used */
void OPPROTO glue(op_rep_lods, SUFFIX)(void)
{
int v, inc;
inc = (DF << SHIFT);
while (ECX != 0) {
v = glue(ldu, SUFFIX)((void *)ESI);
#if SHIFT == 0
EAX = (EAX & ~0xff) | v;
#elif SHIFT == 1
EAX = (EAX & ~0xffff) | v;
#else
EAX = v;
#endif
ESI += inc;
ECX--;
}
}
void OPPROTO glue(op_scas, SUFFIX)(void)
{
int v;
v = glue(ldu, SUFFIX)((void *)ESI);
ESI += (DF << SHIFT);
CC_SRC = EAX;
CC_DST = EAX - v;
}
void OPPROTO glue(op_repz_scas, SUFFIX)(void)
{
int v1, v2, inc;
if (ECX != 0) {
/* NOTE: the flags are not modified if ECX == 0 */
#if SHIFT == 0
v1 = EAX & 0xff;
#elif SHIFT == 1
v1 = EAX & 0xffff;
#else
v1 = EAX;
#endif
inc = (DF << SHIFT);
do {
v2 = glue(ldu, SUFFIX)((void *)ESI);
if (v1 != v2)
break;
ESI += inc;
ECX--;
} while (ECX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
}
void OPPROTO glue(op_repnz_scas, SUFFIX)(void)
{
int v1, v2, inc;
if (ECX != 0) {
/* NOTE: the flags are not modified if ECX == 0 */
#if SHIFT == 0
v1 = EAX & 0xff;
#elif SHIFT == 1
v1 = EAX & 0xffff;
#else
v1 = EAX;
#endif
inc = (DF << SHIFT);
do {
v2 = glue(ldu, SUFFIX)((void *)ESI);
if (v1 == v2)
break;
ESI += inc;
ECX--;
} while (ECX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
}
void OPPROTO glue(op_cmps, SUFFIX)(void)
{
int v1, v2;
v1 = glue(ldu, SUFFIX)((void *)ESI);
v2 = glue(ldu, SUFFIX)((void *)EDI);
ESI += (DF << SHIFT);
EDI += (DF << SHIFT);
CC_SRC = v1;
CC_DST = v1 - v2;
}
void OPPROTO glue(op_repz_cmps, SUFFIX)(void)
{
int v1, v2, inc;
if (ECX != 0) {
inc = (DF << SHIFT);
do {
v1 = glue(ldu, SUFFIX)((void *)ESI);
v2 = glue(ldu, SUFFIX)((void *)EDI);
if (v1 != v2)
break;
ESI += inc;
EDI += inc;
ECX--;
} while (ECX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
}
void OPPROTO glue(op_repnz_cmps, SUFFIX)(void)
{
int v1, v2, inc;
if (ECX != 0) {
inc = (DF << SHIFT);
do {
v1 = glue(ldu, SUFFIX)((void *)ESI);
v2 = glue(ldu, SUFFIX)((void *)EDI);
if (v1 == v2)
break;
ESI += inc;
EDI += inc;
ECX--;
} while (ECX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
}
void OPPROTO glue(op_outs, SUFFIX)(void)
{
int v, dx;
dx = EDX & 0xffff;
v = glue(ldu, SUFFIX)((void *)ESI);
glue(port_out, SUFFIX)(dx, v);
ESI += (DF << SHIFT);
}
void OPPROTO glue(op_rep_outs, SUFFIX)(void)
{
int v, dx, inc;
inc = (DF << SHIFT);
dx = EDX & 0xffff;
while (ECX != 0) {
v = glue(ldu, SUFFIX)((void *)ESI);
glue(port_out, SUFFIX)(dx, v);
ESI += inc;
ECX--;
}
}
void OPPROTO glue(op_ins, SUFFIX)(void)
{
int v, dx;
dx = EDX & 0xffff;
v = glue(port_in, SUFFIX)(dx);
glue(st, SUFFIX)((void *)EDI, v);
EDI += (DF << SHIFT);
}
void OPPROTO glue(op_rep_ins, SUFFIX)(void)
{
int v, dx, inc;
inc = (DF << SHIFT);
dx = EDX & 0xffff;
while (ECX != 0) {
v = glue(port_in, SUFFIX)(dx);
glue(st, SUFFIX)((void *)EDI, v);
EDI += (DF << SHIFT);
ECX--;
}
}
#undef DATA_BITS
#undef SHIFT_MASK
#undef SIGN_MASK
#undef DATA_TYPE
#undef DATA_STYPE
#undef DATA_MASK
#undef SUFFIX

View File

@ -2,7 +2,9 @@ CC=gcc
CFLAGS=-Wall -O2 -g
LDFLAGS=
TESTS=hello test1 test2 sha1 test-i386
TESTS=hello test1 test2 sha1 test-i386
TESTS+=op-i386.o #op-i386.o op-ppc.o op-arm.o op-mips.o op-sparc.o
GEMU=../gemu
all: $(TESTS)
@ -25,6 +27,22 @@ test: test-i386
$(GEMU) test-i386 > test-i386.out
@if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi
# dyngen tests
op-i386.o: op.c
gcc $(CFLAGS) -c -o $@ $<
op-ppc.o: op.c
powerpc-linux-gcc $(CFLAGS) -c -o $@ $<
op-arm.o: op.c
arm-linux-gcc $(CFLAGS) -c -o $@ $<
op-mips.o: op.c
mips-linux-gcc $(CFLAGS) -mno-abicalls -c -o $@ $<
op-sparc.o: op.c
sparc-linux-gcc $(CFLAGS) -mflat -c -o $@ $<
# speed test
sha1: sha1.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<

22
thunk.h
View File

@ -28,16 +28,16 @@
#define bswap_64(x) \
({ \
__u64 __x = (x); \
((__u64)( \
(__u64)(((__u64)(__x) & (__u64)0x00000000000000ffULL) << 56) | \
(__u64)(((__u64)(__x) & (__u64)0x000000000000ff00ULL) << 40) | \
(__u64)(((__u64)(__x) & (__u64)0x0000000000ff0000ULL) << 24) | \
(__u64)(((__u64)(__x) & (__u64)0x00000000ff000000ULL) << 8) | \
(__u64)(((__u64)(__x) & (__u64)0x000000ff00000000ULL) >> 8) | \
(__u64)(((__u64)(__x) & (__u64)0x0000ff0000000000ULL) >> 24) | \
(__u64)(((__u64)(__x) & (__u64)0x00ff000000000000ULL) >> 40) | \
(__u64)(((__u64)(__x) & (__u64)0xff00000000000000ULL) >> 56) )); \
uint64_t __x = (x); \
((uint64_t)( \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \
})
#endif
@ -51,7 +51,7 @@
#define BSWAP_NEEDED
#endif
/* XXX: auto autoconf */
/* XXX: autoconf */
#define TARGET_I386
#define TARGET_LONG_BITS 32

2133
translate-i386.c Normal file

File diff suppressed because it is too large Load Diff