Skip to content

Commit

Permalink
Improve floating point support enough to make Lua work pretty well
Browse files Browse the repository at this point in the history
  • Loading branch information
tbodt committed Jan 2, 2018
1 parent a7969c0 commit fe13753
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 58 deletions.
42 changes: 32 additions & 10 deletions emu/decode.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ int CONCAT(decoder_name, OP_SIZE)(struct cpu_state *cpu, struct tlb *tlb) {
READMODRM; ADD(modrm_reg, modrm_val,8); break;
case 0x01: TRACEI("add reg, modrm");
READMODRM; ADD(modrm_reg, modrm_val,); break;
case 0x02: TRACEI("add modrm8, reg8");
READMODRM; ADD(modrm_val, modrm_reg,8); break;
case 0x03: TRACEI("add modrm, reg");
READMODRM; ADD(modrm_val, modrm_reg,); break;
case 0x05: TRACEI("add imm, oax\t");
Expand Down Expand Up @@ -601,37 +603,57 @@ int CONCAT(decoder_name, OP_SIZE)(struct cpu_state *cpu, struct tlb *tlb) {
TRACEI("fpu\t\t"); READMODRM;
if (modrm.type != mod_reg) {
switch (insn << 4 | modrm.opcode) {
case 0xd81: TRACE("fmul mem32"); FMUL(mem_addr_real,32); break;
case 0xd80: TRACE("fadd mem32"); FADDM(mem_addr_real,32); break;
case 0xd81: TRACE("fmul mem32"); FMULM(mem_addr_real,32); break;
case 0xd90: TRACE("fld mem32"); FLDM(mem_addr_real,32); break;
case 0xd95: TRACE("fldcw mem16"); FLDCW(mem_addr); break;
case 0xd97: TRACE("fnstcw mem16"); FSTCW(mem_addr); break;
case 0xda1: TRACE("fimul mem32"); FIMUL(mem_addr,32); break;
case 0xda4: TRACE("fisub mem32"); FISUB(mem_addr,32); break;
case 0xdb0: TRACE("fild mem32"); FILD(mem_addr,32); break;
case 0xdb2: TRACE("fist mem32"); FIST(mem_addr,32); break;
case 0xdb3: TRACE("fistp mem32"); FIST(mem_addr,32); FPOP; break;
case 0xdb7: TRACE("fstp mem80"); FSTM(mem_addr_real,80); FPOP; break;
case 0xdb5: TRACE("fld mem80"); FLDM(mem_addr_real,80); break;
case 0xdc0: TRACE("fadd mem64"); FADDM(mem_addr_real,64); break;
case 0xdd0: TRACE("fld mem64"); FLD(mem_addr_real,64); break;
case 0xdc1: TRACE("fmul mem64"); FMULM(mem_addr_real,64); break;
case 0xdd0: TRACE("fld mem64"); FLDM(mem_addr_real,64); break;
case 0xdc4: TRACE("fsub mem64"); FSUBM(mem_addr_real,64); break;
case 0xdc6: TRACE("fdiv mem64"); FDIVM(mem_addr_real,64); break;
case 0xdd2: TRACE("fst mem64"); FSTM(mem_addr_real,64); break;
case 0xdd3: TRACE("fstp mem64"); FSTM(mem_addr_real,64); FPOP; break;
case 0xdf5: TRACE("fild mem64"); FILD(mem_addr,64); break;
case 0xdf7: TRACE("fistp mem64"); FIST(mem_addr,64); FPOP; break;
default: TRACE("undefined"); UNDEFINED;
}
} else {
switch (insn << 4 | modrm.opcode) {
case 0xd80: TRACE("fadd st(i), st"); FADD(st_i, st_0); break;
case 0xd81: TRACE("fmul st(i), st"); FMUL(st_i, st_0); break;
case 0xd84: TRACE("fsub st(i), st"); FSUB(st_i, st_0); break;
case 0xd90: TRACE("fld st(i)"); FLD(); break;
case 0xd91: TRACE("fxch st"); FXCH(); break;
case 0xd95:
switch (modrm.rm_opcode) {
case 6: TRACE("fldz"); FLDC(zero); break;
default: TRACE("undefined"); UNDEFINED;
}
break;
case 0xdb5: TRACE("fucomi st"); FUCOMI(); break;
case 0xdc0: TRACE("fadd st, st(i)"); FADD(st_0, st_i); break;
case 0xdc1: TRACE("fmul st, st(i)"); FMUL(st_0, st_i); break;
case 0xdd3: TRACE("fstp st"); FST(); FPOP; break;
case 0xdd4: TRACE("fucom st"); FUCOM(); break;
case 0xdd5: TRACE("fucomp st"); FUCOM(); FPOP; break;
case 0xda5: TRACE("fucompp st"); FUCOM(); FPOP; FPOP; break;
case 0xde0: TRACE("faddp st, st(i)"); FADD(st_0, st_i); FPOP; break;
case 0xdf4: TRACE("fnstsw ax"); FSTSW(ax); break;
case 0xde1: TRACE("fmulp st, st(i)"); FMUL(st_0, st_i); FPOP; break;
case 0xde4: TRACE("fsubrp st, st(i)"); FSUB(st_i, st_0); FPOP; break;
case 0xde5: TRACE("fsubp st, st(i)"); FSUB(st_0, st_i); FPOP; break;
case 0xdf5: TRACE("fucomip st"); FUCOMI(); FPOP; break;
default: switch (insn << 8 | modrm.opcode << 4 | modrm.rm_opcode) {
case 0xd940: TRACE("fchs"); FCHS(); break;
case 0xd941: TRACE("fabs"); FABS(); break;
case 0xd950: TRACE("fld1"); FLDC(one); break;
case 0xd956: TRACE("fldz"); FLDC(zero); break;
case 0xd970: TRACE("fprem"); FPREM(); break;
case 0xdf40: TRACE("fnstsw ax"); FSTSW(ax); break;
default: TRACE("undefined"); UNDEFINED;
}
}}
}
break;

Expand Down
53 changes: 28 additions & 25 deletions emu/interp.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,20 @@
\
uint64_t imm; \
union xmm_reg xmm_src; \
union xmm_reg xmm_dst
union xmm_reg xmm_dst; \
\
extFloat80_t ftmp;

#define READMODRM modrm_decode32(cpu, tlb, &addr, &modrm)
#define READIMM_(name,size) \
name = mem_read_(cpu->eip, size); \
name = mem_read(cpu->eip, size); \
cpu->eip += size/8; \
TRACE("imm %llx ", (long long) name)
#define READIMM READIMM_(imm, OP_SIZE)
#define READIMM8 READIMM_(imm, 8)
#define READIMM16 READIMM_(imm, 16)
#define READINSN \
insn = mem_read_(cpu->eip, 8); \
insn = mem_read(cpu->eip, 8); \
cpu->eip++; \
TRACE("%02x ", insn);

Expand All @@ -35,6 +37,7 @@
#define sz_16 16
#define sz_32 32
#define sz_64 64
#define sz_80 80
#define sz_128 128
#define twice(x) CONCAT(twice_, x)
#define twice_8 16
Expand All @@ -49,25 +52,25 @@
#define ty_64 uint64_t
#define ty_128 union xmm_reg

#define mem_read_type(addr, type) ({ \
#define mem_read_ts(addr, type, size) ({ \
type val; \
if (!tlb_read(tlb, addr, &val)) { \
if (!tlb_read(tlb, addr, &val, size/8)) { \
cpu->eip = saved_ip; \
cpu->segfault_addr = addr; \
return INT_GPF; \
} \
val; \
})
#define mem_write_type(addr, val, type) ({ \
#define mem_write_ts(addr, val, type, size) ({ \
type _val = val; \
if (!tlb_write(tlb, addr, &_val)) { \
if (!tlb_write(tlb, addr, &_val, size/8)) { \
cpu->eip = saved_ip; \
cpu->segfault_addr = addr; \
return INT_GPF; \
} \
})
#define mem_read_(addr, size) mem_read_type(addr, ty(size))
#define mem_write_(addr, val, size) mem_write_type(addr, val, ty(size))
#define mem_read(addr, size) mem_read_ts(addr, ty(size), size)
#define mem_write(addr, val, size) mem_write_ts(addr, val, ty(size), size)

#define get(what, size) get_##what(sz(size))
#define set(what, to, size) set_##what(to, sz(size))
Expand All @@ -83,25 +86,25 @@
#define get_modrm_val(size) \
(modrm.type == mod_reg ? \
REGISTER(modrm.modrm_regid, size) : \
mem_read_(addr, size))
mem_read(addr, size))

#define set_modrm_val(to, size) \
if (modrm.type == mod_reg) { \
REGISTER(modrm.modrm_regid, size) = to; \
} else { \
mem_write_(addr, to, size); \
mem_write(addr, to, size); \
}(void)0

#define get_imm(size) ((uint(size)) imm)
#define get_imm8(size) ((int8_t) (uint8_t) imm)

#define get_mem_addr(size) mem_read_(addr, size)
#define set_mem_addr(to, size) mem_write_(addr, to, size)
#define get_mem_addr(size) mem_read(addr, size)
#define set_mem_addr(to, size) mem_write(addr, to, size)

#define get_mem_si(size) mem_read_(cpu->osi, size)
#define set_mem_si(size) mem_write_(cpu->osi, size)
#define get_mem_di(size) mem_read_(cpu->odi, size)
#define set_mem_di(size) mem_write_(cpu->osi, size)
#define get_mem_si(size) mem_read(cpu->osi, size)
#define set_mem_si(size) mem_write(cpu->osi, size)
#define get_mem_di(size) mem_read(cpu->odi, size)
#define set_mem_di(size) mem_write(cpu->osi, size)

// DEFINE ALL THE MACROS
#define get_oax(size) cpu->oax
Expand Down Expand Up @@ -208,10 +211,10 @@
} while (0)

#define PUSH(thing) \
mem_write_(cpu->osp - OP_SIZE/8, get(thing, OP_SIZE), OP_SIZE); \
mem_write(cpu->osp - OP_SIZE/8, get(thing, OP_SIZE), OP_SIZE); \
cpu->osp -= OP_SIZE/8
#define POP(thing) \
set(thing, mem_read_(cpu->osp, OP_SIZE),); \
set(thing, mem_read(cpu->osp, OP_SIZE),); \
cpu->osp += OP_SIZE/8

#define INT(code) \
Expand Down Expand Up @@ -241,15 +244,15 @@
#define ADC(src, dst,z) \
SETAF(src, dst,z); \
cpu->of = signed_overflow(add, get(dst,z), get(src,z) + cpu->cf, cpu->res,z) \
|| (get(src,z) + cpu->cf == (uint(sz(z))) -1); \
|| (cpu->cf && get(src,z) == ((uint(sz(z))) -1) / 2); \
cpu->cf = unsigned_overflow(add, get(dst,z), get(src,z) + cpu->cf, cpu->res,z) \
|| (cpu->cf && get(src,z) == (uint(sz(z))) -1); \
set(dst, cpu->res,z); SETRESFLAGS

#define SBB(src, dst,z) \
SETAF(src, dst,z); \
cpu->of = signed_overflow(sub, get(dst,z), get(src,z) + cpu->cf, cpu->res,z) \
|| (get(src,z) + cpu->cf == (uint(sz(z))) -1); \
|| (cpu->cf && get(src,z) == ((uint(sz(z))) -1) / 2); \
cpu->cf = unsigned_overflow(sub, get(dst,z), get(src,z) + cpu->cf, cpu->res,z) \
|| (cpu->cf && get(src,z) == (uint(sz(z))) -1); \
set(dst, cpu->res,z); SETRESFLAGS
Expand Down Expand Up @@ -429,7 +432,7 @@

#define get_bit(bit, val,z) \
((is_memory(val) ? \
mem_read_(addr + get(bit,z) / sz(z) * (sz(z)/8), sz(z)) : \
mem_read(addr + get(bit,z) / sz(z) * (sz(z)/8), sz(z)) : \
get(val,z)) & (1 << (get(bit,z) % sz(z)))) ? 1 : 0

#define msk(bit,z) (1 << (get(bit,z) % sz(z)))
Expand Down Expand Up @@ -470,15 +473,15 @@
BUMP_SI(size); BUMP_DI(size)

#define MOVS(z) \
mem_write_(cpu->edi, mem_read_(cpu->esi, sz(z)), sz(z)); \
mem_write(cpu->edi, mem_read(cpu->esi, sz(z)), sz(z)); \
BUMP_SI_DI(z)

#define STOS(z) \
mem_write_(cpu->edi, REG_VAL(cpu, REG_ID(eax), sz(z)), sz(z)); \
mem_write(cpu->edi, REG_VAL(cpu, REG_ID(eax), sz(z)), sz(z)); \
BUMP_DI(z)

#define LODS(z) \
REG_VAL(cpu, REG_ID(eax), sz(z)) = mem_read_(cpu->esi, sz(z)); \
REG_VAL(cpu, REG_ID(eax), sz(z)) = mem_read(cpu->esi, sz(z)); \
BUMP_SI(z)

// found an alternative to al, see above, needs polishing
Expand Down
60 changes: 49 additions & 11 deletions emu/interp/fpu.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
#include <softfloat.h>
#include <softfloat.h>//0xffffb390

// a few extra things not included in the softfloat library
static inline extFloat80_t extF80_to_f80(extFloat80_t f) { return f; }
static inline extFloat80_t f80_to_extF80(extFloat80_t f) { return f; }

static inline extFloat80_t extF80_neg(extFloat80_t f) {
f.signExp ^= 1 << 15; // flip the sign bit
return f;
}
static inline extFloat80_t extF80_abs(extFloat80_t f) {
f.signExp &= ~(1 << 15); // clear the sign bit
return f;
}

#define ty_real(x) ty_real_##x
#define ty_real_16 float16_t
#define ty_real_32 float32_t
#define ty_real_64 float64_t
#define ty_real_80 extFloat80_t

#define mem_read_real(addr, size) mem_read_type(addr, ty_real(size))
#define mem_write_real(addr, val, size) mem_write_type(addr, val, ty_real(size))
#define mem_read_real(addr, size) mem_read_ts(addr, ty_real(size), size)
#define mem_write_real(addr, val, size) mem_write_ts(addr, val, ty_real(size), size)
#define get_mem_addr_real(size) mem_read_real(addr, size)
#define set_mem_addr_real(to, size) mem_write_real(addr, to, size)

Expand All @@ -19,15 +32,12 @@
#define ST(i) cpu->fp[cpu->top + i]
#define ST_i ST(modrm.rm_opcode)
#define FPUSH(val) \
cpu->top--; ST(0) = val
ftmp = val; cpu->top--; ST(0) = ftmp
#define FPOP \
cpu->top++

#define FXCH() { \
extFloat80_t tmp = ST(0); \
ST(0) = ST_i; \
ST_i = tmp; \
}
#define FXCH() \
extFloat80_t ftmp = ST(0); ST(0) = ST_i; ST_i = ftmp

#define st_0 ST(0)
#define st_i ST(modrm.rm_opcode)
Expand All @@ -36,10 +46,36 @@
dst = extF80_add(dst, src)
#define FADDM(val,z) \
ST(0) = extF80_add(ST(0), f_to_extF80(get(val,z),z))
#define FSUB(src, dst) \
dst = extF80_sub(dst, src)
#define FSUBM(val,z) \
ST(0) = extF80_sub(ST(0), f_to_extF80(get(val,z),z))
#define FISUB(val,z) \
ST(0) = extF80_sub(ST(0), i64_to_extF80((sint(z)) get(val,z)))
#define FMUL(val,z) \
#define FMUL(src, dst) \
dst = extF80_mul(dst, src)
#define FIMUL(val,z) \
ST(0) = extF80_mul(ST(0), i64_to_extF80((sint(z)) get(val,z)))
#define FMULM(val,z) \
ST(0) = extF80_mul(ST(0), f_to_extF80(get(val,z),z))
#define FDIV(src, dst) \
dst = extF80_div(dst, src)
#define FIDIV(val,z) \
ST(0) = extF80_div(ST(0), i64_to_extF80((sint(z)) get(val,z)))
#define FDIVM(val,z) \
ST(0) = extF80_div(ST(0), f_to_extF80(get(val,z),z))

#define FCHS() \
ST(0) = extF80_neg(ST(0))
#define FABS() \
ST(0) = extF80_abs(ST(0))

// FIXME this is the IEEE ABSOLUTELY CORRECT AND AWESOME REMAINDER which is
// computed by fprem1, not fprem
// only known case of intel naming an instruction by taking another instruction
// that does the same thing but wrong and adding a 1
#define FPREM() \
ST(0) = extF80_rem(ST(0), ST(1))

#define FUCOMI() \
cpu->zf = extF80_eq(ST(0), ST_i); cpu->zf_res = 0; \
Expand All @@ -55,10 +91,12 @@

#define FILD(val,z) \
FPUSH(i64_to_extF80((sint(z)) get(val,z)))
#define FLD(val,z) \
#define FLD() FPUSH(ST_i)
#define FLDM(val,z) \
FPUSH(f_to_extF80(get(val,z),z))

#define FLDC(what) FPUSH(fconst_##what)
#define fconst_one i64_to_extF80(1)
#define fconst_zero i64_to_extF80(0)

#define FSTM(dst,z) \
Expand Down
12 changes: 4 additions & 8 deletions emu/modrm.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
#include "emu/modrm.h"

#define MOD(byte) ((byte & 0b11000000) >> 6)
#define REG(byte) ((byte & 0b00111000) >> 3)
#define RM(byte) ((byte & 0b00000111) >> 0)

#define MAKE_REGPTR(r32, r16, r8, xmm) ((struct regptr) { \
.reg32_id = REG_ID(r32), \
.reg16_id = REG_ID(r16), \
Expand Down Expand Up @@ -85,7 +81,7 @@ extern inline struct modrm_info modrm_get_info(byte_t byte);
// FIXME doesn't check for segfaults
void modrm_decode32(struct cpu_state *cpu, struct tlb *tlb, addr_t *addr_out, struct modrm_info *info_out) {
byte_t modrm;
tlb_read(tlb, cpu->eip, &modrm);
tlb_read(tlb, cpu->eip, &modrm, sizeof(modrm));
struct modrm_info info = modrm_get_info(modrm);
cpu->eip++;
*info_out = info;
Expand All @@ -98,7 +94,7 @@ void modrm_decode32(struct cpu_state *cpu, struct tlb *tlb, addr_t *addr_out, st
} else {
// sib is simple enough to not use a table for
byte_t sib;
tlb_read(tlb, cpu->eip, &sib);
tlb_read(tlb, cpu->eip, &sib, sizeof(sib));
TRACE("sib %x ", sib);
cpu->eip++;
dword_t reg = 0;
Expand Down Expand Up @@ -139,15 +135,15 @@ void modrm_decode32(struct cpu_state *cpu, struct tlb *tlb, addr_t *addr_out, st
switch (info.type) {
case mod_disp8: {
int8_t disp;
tlb_read(tlb, cpu->eip, &disp);
tlb_read(tlb, cpu->eip, &disp, sizeof(disp));
TRACE("disp %s0x%x ", (disp < 0 ? "-" : ""), (disp < 0 ? -disp : disp));
*addr_out += disp;
cpu->eip++;
break;
}
case mod_disp32: {
int32_t disp;
tlb_read(tlb, cpu->eip, &disp);
tlb_read(tlb, cpu->eip, &disp, sizeof(disp));
TRACE("disp %s0x%x ", (disp < 0 ? "-" : ""), (disp < 0 ? -disp : disp));
*addr_out += disp;
cpu->eip += 4;
Expand Down
Loading

0 comments on commit fe13753

Please sign in to comment.