cosmopolitan/tool/build/lib/machine.c

1958 lines
49 KiB
C

/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/conv/conv.h"
#include "libc/dce.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/runtime/runtime.h"
#include "tool/build/lib/abp.h"
#include "tool/build/lib/address.h"
#include "tool/build/lib/alu.h"
#include "tool/build/lib/bcd.h"
#include "tool/build/lib/bitscan.h"
#include "tool/build/lib/case.h"
#include "tool/build/lib/cpuid.h"
#include "tool/build/lib/cvt.h"
#include "tool/build/lib/divmul.h"
#include "tool/build/lib/endian.h"
#include "tool/build/lib/flags.h"
#include "tool/build/lib/fpu.h"
#include "tool/build/lib/ioports.h"
#include "tool/build/lib/machine.h"
#include "tool/build/lib/memory.h"
#include "tool/build/lib/modrm.h"
#include "tool/build/lib/sse.h"
#include "tool/build/lib/ssefloat.h"
#include "tool/build/lib/ssemov.h"
#include "tool/build/lib/stack.h"
#include "tool/build/lib/stats.h"
#include "tool/build/lib/string.h"
#include "tool/build/lib/syscall.h"
#include "tool/build/lib/throw.h"
#include "tool/build/lib/time.h"
#define OpLfence OpNoop
#define OpMfence OpNoop
#define OpSfence OpNoop
#define OpClflush OpNoop
#define OpHintNopEv OpNoop
typedef void (*nexgen32e_f)(struct Machine *, uint32_t);
static uint64_t ReadMemory(uint32_t rde, uint8_t p[8]) {
if (Rexw(rde)) {
return Read64(p);
} else if (!Osz(rde)) {
return Read32(p);
} else {
return Read16(p);
}
}
static int64_t ReadMemorySigned(uint32_t rde, uint8_t p[8]) {
if (Rexw(rde)) {
return (int64_t)Read64(p);
} else if (!Osz(rde)) {
return (int32_t)Read32(p);
} else {
return (int16_t)Read16(p);
}
}
static void WriteRegister(uint32_t rde, uint8_t p[8], uint64_t x) {
if (Rexw(rde)) {
Write64(p, x);
} else if (!Osz(rde)) {
Write64(p, x & 0xffffffff);
} else {
Write16(p, x);
}
}
static void WriteMemory(uint32_t rde, uint8_t p[8], uint64_t x) {
if (Rexw(rde)) {
Write64(p, x);
} else if (!Osz(rde)) {
Write32(p, x);
} else {
Write16(p, x);
}
}
static void WriteRegisterOrMemory(uint32_t rde, uint8_t p[8], uint64_t x) {
if (IsModrmRegister(rde)) {
WriteRegister(rde, p, x);
} else {
WriteMemory(rde, p, x);
}
}
static bool IsParity(struct Machine *m) {
return GetFlag(m->flags, FLAGS_PF);
}
static bool IsBelowOrEqual(struct Machine *m) {
return GetFlag(m->flags, FLAGS_CF) | GetFlag(m->flags, FLAGS_ZF);
}
static bool IsAbove(struct Machine *m) {
return !GetFlag(m->flags, FLAGS_CF) && !GetFlag(m->flags, FLAGS_ZF);
}
static bool IsLess(struct Machine *m) {
return GetFlag(m->flags, FLAGS_SF) != GetFlag(m->flags, FLAGS_OF);
}
static bool IsGreaterOrEqual(struct Machine *m) {
return GetFlag(m->flags, FLAGS_SF) == GetFlag(m->flags, FLAGS_OF);
}
static bool IsLessOrEqual(struct Machine *m) {
return GetFlag(m->flags, FLAGS_ZF) |
(GetFlag(m->flags, FLAGS_SF) != GetFlag(m->flags, FLAGS_OF));
}
static bool IsGreater(struct Machine *m) {
return !GetFlag(m->flags, FLAGS_ZF) &
(GetFlag(m->flags, FLAGS_SF) == GetFlag(m->flags, FLAGS_OF));
}
static void OpNoop(struct Machine *m, uint32_t rde) {
}
static void OpCmc(struct Machine *m, uint32_t rde) {
m->flags = SetFlag(m->flags, FLAGS_CF, !GetFlag(m->flags, FLAGS_CF));
}
static void OpClc(struct Machine *m, uint32_t rde) {
m->flags = SetFlag(m->flags, FLAGS_CF, false);
}
static void OpStc(struct Machine *m, uint32_t rde) {
m->flags = SetFlag(m->flags, FLAGS_CF, true);
}
static void OpCli(struct Machine *m, uint32_t rde) {
m->flags = SetFlag(m->flags, FLAGS_IF, false);
}
static void OpSti(struct Machine *m, uint32_t rde) {
m->flags = SetFlag(m->flags, FLAGS_IF, true);
}
static void OpCld(struct Machine *m, uint32_t rde) {
m->flags = SetFlag(m->flags, FLAGS_DF, false);
}
static void OpStd(struct Machine *m, uint32_t rde) {
m->flags = SetFlag(m->flags, FLAGS_DF, true);
}
static void OpPushf(struct Machine *m, uint32_t rde) {
Push(m, rde, ExportFlags(m->flags) & 0xFCFFFF);
}
static void OpPopf(struct Machine *m, uint32_t rde) {
if (!Osz(rde)) {
ImportFlags(m, Pop(m, rde, 0));
} else {
ImportFlags(m, (m->flags & ~0xffff) | Pop(m, rde, 0));
}
}
static void OpLahf(struct Machine *m, uint32_t rde) {
Write8(m->ax + 1, ExportFlags(m->flags));
}
static void OpSahf(struct Machine *m, uint32_t rde) {
ImportFlags(m, (m->flags & ~0xff) | m->ax[1]);
}
static void OpLeaGvqpM(struct Machine *m, uint32_t rde) {
WriteRegister(rde, RegRexrReg(m, rde), LoadEffectiveAddress(m, rde).addr);
}
static relegated void OpPushSeg(struct Machine *m, uint32_t rde) {
uint8_t seg = (m->xedd->op.opcode & 070) >> 3;
Push(m, rde, Read64(GetSegment(m, rde, seg)) >> 4);
}
static relegated void OpPopSeg(struct Machine *m, uint32_t rde) {
uint8_t seg = (m->xedd->op.opcode & 070) >> 3;
Write64(GetSegment(m, rde, seg), Pop(m, rde, 0) << 4);
}
static relegated void OpMovEvqpSw(struct Machine *m, uint32_t rde) {
WriteRegisterOrMemory(rde, GetModrmRegisterWordPointerWriteOszRexw(m, rde),
Read64(GetSegment(m, rde, ModrmReg(rde))) >> 4);
}
static relegated void OpMovSwEvqp(struct Machine *m, uint32_t rde) {
Write64(GetSegment(m, rde, ModrmReg(rde)),
ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)) << 4);
}
static relegated void OpJmpf(struct Machine *m, uint32_t rde) {
Write64(m->cs, m->xedd->op.uimm0 << 4);
m->ip = m->xedd->op.disp;
}
static relegated void OpXlatAlBbb(struct Machine *m, uint32_t rde) {
uint64_t v;
v = MaskAddress(Eamode(rde), Read64(m->bx) + Read8(m->ax));
v = DataSegment(m, rde, v);
SetReadAddr(m, v, 1);
Write8(m->ax, Read8(ResolveAddress(m, v)));
}
static void WriteEaxAx(struct Machine *m, uint32_t rde, uint32_t x) {
if (!Osz(rde)) {
Write64(m->ax, x);
} else {
Write16(m->ax, x);
}
}
static uint32_t ReadEaxAx(struct Machine *m, uint32_t rde) {
if (!Osz(rde)) {
return Read32(m->ax);
} else {
return Read16(m->ax);
}
}
static void OpInAlImm(struct Machine *m, uint32_t rde) {
Write8(m->ax, OpIn(m, m->xedd->op.uimm0));
}
static void OpInAxImm(struct Machine *m, uint32_t rde) {
WriteEaxAx(m, rde, OpIn(m, m->xedd->op.uimm0));
}
static void OpInAlDx(struct Machine *m, uint32_t rde) {
Write8(m->ax, OpIn(m, Read16(m->dx)));
}
static void OpInAxDx(struct Machine *m, uint32_t rde) {
WriteEaxAx(m, rde, OpIn(m, Read16(m->dx)));
}
static void OpOutImmAl(struct Machine *m, uint32_t rde) {
OpOut(m, m->xedd->op.uimm0, Read8(m->ax));
}
static void OpOutImmAx(struct Machine *m, uint32_t rde) {
OpOut(m, m->xedd->op.uimm0, ReadEaxAx(m, rde));
}
static void OpOutDxAl(struct Machine *m, uint32_t rde) {
OpOut(m, Read16(m->dx), Read8(m->ax));
}
static void OpOutDxAx(struct Machine *m, uint32_t rde) {
OpOut(m, Read16(m->dx), ReadEaxAx(m, rde));
}
static void AluEb(struct Machine *m, uint32_t rde, aluop_f op) {
uint8_t *p;
p = GetModrmRegisterBytePointerWrite(m, rde);
Write8(p, op(Read8(p), 0, &m->flags));
}
static void AluEvqp(struct Machine *m, uint32_t rde, aluop_f ops[4]) {
uint8_t *p;
p = GetModrmRegisterWordPointerWriteOszRexw(m, rde);
WriteRegisterOrMemory(rde, p,
ops[RegLog2(rde)](ReadMemory(rde, p), 0, &m->flags));
}
static void OpXchgZvqp(struct Machine *m, uint32_t rde) {
uint64_t x, y;
x = Read64(m->ax);
y = Read64(RegRexbSrm(m, rde));
WriteRegister(rde, m->ax, y);
WriteRegister(rde, RegRexbSrm(m, rde), x);
}
static void OpXchgGbEb(struct Machine *m, uint32_t rde) {
uint8_t *p;
uint8_t x, y;
p = GetModrmRegisterBytePointerWrite(m, rde);
x = Read8(ByteRexrReg(m, rde));
y = Read8(p);
Write8(ByteRexrReg(m, rde), y);
Write8(p, x);
}
static void OpXchgGvqpEvqp(struct Machine *m, uint32_t rde) {
uint8_t *p;
uint64_t x, y;
p = GetModrmRegisterWordPointerWriteOszRexw(m, rde);
x = ReadMemory(rde, RegRexrReg(m, rde));
y = ReadMemory(rde, p);
WriteRegister(rde, RegRexrReg(m, rde), y);
WriteRegisterOrMemory(rde, p, x);
}
static void OpCmpxchgEbAlGb(struct Machine *m, uint32_t rde) {
uint8_t *p;
uint8_t x, y, z;
p = GetModrmRegisterBytePointerWrite(m, rde);
x = Read8(m->ax);
y = Read8(p);
z = Read8(ByteRexrReg(m, rde));
Sub8(x, y, &m->flags);
if (GetFlag(m->flags, FLAGS_ZF)) {
Write8(p, z);
} else {
Write8(m->ax, y);
}
}
static void OpCmpxchgEvqpRaxGvqp(struct Machine *m, uint32_t rde) {
uint8_t *p;
uint64_t x, y, z;
p = GetModrmRegisterWordPointerWriteOszRexw(m, rde);
x = ReadMemory(rde, m->ax);
y = ReadMemory(rde, p);
z = ReadMemory(rde, RegRexrReg(m, rde));
kAlu[ALU_SUB][RegLog2(rde)](x, y, &m->flags);
if (GetFlag(m->flags, FLAGS_ZF)) {
WriteRegisterOrMemory(rde, p, z);
} else {
WriteRegister(rde, m->ax, y);
}
}
static void OpCmpxchg8b(struct Machine *m, uint32_t rde) {
uint8_t *p;
uint32_t d, a;
p = GetModrmRegisterXmmPointerRead8(m, rde);
a = Read32(p + 0);
d = Read32(p + 4);
if (a == Read32(m->ax) && d == Read32(m->dx)) {
SetFlag(m->flags, FLAGS_ZF, true);
memcpy(p + 0, m->bx, 4);
memcpy(p + 4, m->cx, 4);
} else {
SetFlag(m->flags, FLAGS_ZF, false);
Write32(m->ax, a);
Write32(m->dx, d);
}
}
static void OpCmpxchg16b(struct Machine *m, uint32_t rde) {
uint8_t *p;
uint64_t d, a;
p = GetModrmRegisterXmmPointerRead16(m, rde);
a = Read64(p + 0);
d = Read64(p + 8);
if (a == Read64(m->ax) && d == Read64(m->dx)) {
SetFlag(m->flags, FLAGS_ZF, true);
memcpy(p + 0, m->bx, 8);
memcpy(p + 8, m->cx, 8);
} else {
SetFlag(m->flags, FLAGS_ZF, false);
Write64(m->ax, a);
Write64(m->dx, d);
}
}
static void OpCmpxchgDxAx(struct Machine *m, uint32_t rde) {
if (Rexw(rde)) {
OpCmpxchg16b(m, rde);
} else {
OpCmpxchg8b(m, rde);
}
}
static void OpXaddEbGb(struct Machine *m, uint32_t rde) {
uint8_t *p;
uint8_t x, y, z;
p = GetModrmRegisterWordPointerWriteOszRexw(m, rde);
x = Read8(p);
y = Read8(RegRexrReg(m, rde));
z = Add8(x, y, &m->flags);
Write8(p, z);
Write8(RegRexrReg(m, rde), x);
}
static void OpXaddEvqpGvqp(struct Machine *m, uint32_t rde) {
uint8_t *p;
uint64_t x, y, z;
p = GetModrmRegisterWordPointerWriteOszRexw(m, rde);
x = ReadMemory(rde, p);
y = ReadMemory(rde, RegRexrReg(m, rde));
z = kAlu[ALU_ADD][RegLog2(rde)](x, y, &m->flags);
WriteRegisterOrMemory(rde, p, z);
WriteRegister(rde, RegRexrReg(m, rde), x);
}
static uint64_t Bts(uint64_t x, uint64_t y) {
return x | y;
}
static uint64_t Btr(uint64_t x, uint64_t y) {
return x & ~y;
}
static uint64_t Btc(uint64_t x, uint64_t y) {
return (x & ~y) | (~x & y);
}
static void OpBit(struct Machine *m, uint32_t rde) {
int op;
uint8_t *p;
unsigned bit;
int64_t disp;
uint64_t v, x, y, z;
uint8_t w, W[2][2] = {{2, 3}, {1, 3}};
w = W[Osz(rde)][Rexw(rde)];
if (m->xedd->op.opcode == 0xBA) {
op = ModrmReg(rde);
bit = m->xedd->op.uimm0 & ((8 << w) - 1);
disp = 0;
} else {
op = (m->xedd->op.opcode & 070) >> 3;
disp = ReadMemorySigned(rde, RegRexrReg(m, rde));
bit = disp & ((8 << w) - 1);
disp &= -(8 << w);
disp >>= 3;
}
if (IsModrmRegister(rde)) {
p = RegRexbRm(m, rde);
} else {
v = MaskAddress(Eamode(rde), ComputeAddress(m, rde) + disp);
p = ReserveAddress(m, v, 1 << w);
if (op == 4) {
SetReadAddr(m, v, 1 << w);
} else {
SetWriteAddr(m, v, 1 << w);
}
}
y = 1;
y <<= bit;
x = ReadMemory(rde, p);
m->flags = SetFlag(m->flags, FLAGS_CF, !!(y & x));
switch (op) {
case 4:
return;
case 5:
z = Bts(x, y);
break;
case 6:
z = Btr(x, y);
break;
case 7:
z = Btc(x, y);
break;
default:
OpUd(m, rde);
}
WriteRegisterOrMemory(rde, p, z);
}
static void OpSax(struct Machine *m, uint32_t rde) {
if (Rexw(rde)) {
Write64(m->ax, (int32_t)Read32(m->ax));
} else if (!Osz(rde)) {
Write64(m->ax, (uint32_t)(int16_t)Read16(m->ax));
} else {
Write16(m->ax, (int8_t)Read8(m->ax));
}
}
static void OpConvert(struct Machine *m, uint32_t rde) {
if (Rexw(rde)) {
Write64(m->dx, Read64(m->ax) & 0x8000000000000000 ? 0xffffffffffffffff : 0);
} else if (!Osz(rde)) {
Write64(m->dx, Read32(m->ax) & 0x80000000 ? 0xffffffff : 0);
} else {
Write16(m->dx, Read16(m->ax) & 0x8000 ? 0xffff : 0);
}
}
static void OpBswapZvqp(struct Machine *m, uint32_t rde) {
uint64_t x;
x = Read64(RegRexbSrm(m, rde));
if (Rexw(rde)) {
Write64(
RegRexbSrm(m, rde),
((x & 0xff00000000000000) >> 070 | (x & 0x00000000000000ff) << 070 |
(x & 0x00ff000000000000) >> 050 | (x & 0x000000000000ff00) << 050 |
(x & 0x0000ff0000000000) >> 030 | (x & 0x0000000000ff0000) << 030 |
(x & 0x000000ff00000000) >> 010 | (x & 0x00000000ff000000) << 010));
} else if (!Osz(rde)) {
Write64(RegRexbSrm(m, rde),
((x & 0xff000000) >> 030 | (x & 0x000000ff) << 030 |
(x & 0x00ff0000) >> 010 | (x & 0x0000ff00) << 010));
} else {
Write16(RegRexbSrm(m, rde), (x & 0x00ff) << 010 | (x & 0xff00) << 010);
}
}
static void OpMovEbIb(struct Machine *m, uint32_t rde) {
Write8(GetModrmRegisterBytePointerWrite(m, rde), m->xedd->op.uimm0);
}
static void OpMovAlOb(struct Machine *m, uint32_t rde) {
int64_t addr;
addr = AddressOb(m, rde);
SetWriteAddr(m, addr, 1);
Write8(m->ax, Read8(ResolveAddress(m, addr)));
}
static void OpMovObAl(struct Machine *m, uint32_t rde) {
int64_t addr;
addr = AddressOb(m, rde);
SetReadAddr(m, addr, 1);
Write8(ResolveAddress(m, addr), Read8(m->ax));
}
static void OpMovRaxOvqp(struct Machine *m, uint32_t rde) {
uint64_t v;
v = DataSegment(m, rde, m->xedd->op.disp);
SetReadAddr(m, v, 1 << RegLog2(rde));
WriteRegister(rde, m->ax, ReadMemory(rde, ResolveAddress(m, v)));
}
static void OpMovOvqpRax(struct Machine *m, uint32_t rde) {
uint64_t v;
v = DataSegment(m, rde, m->xedd->op.disp);
SetWriteAddr(m, v, 1 << RegLog2(rde));
WriteMemory(rde, ResolveAddress(m, v), Read64(m->ax));
}
static void OpMovEbGb(struct Machine *m, uint32_t rde) {
memcpy(GetModrmRegisterBytePointerWrite(m, rde), ByteRexrReg(m, rde), 1);
}
static void OpMovGbEb(struct Machine *m, uint32_t rde) {
memcpy(ByteRexrReg(m, rde), GetModrmRegisterBytePointerRead(m, rde), 1);
}
static void OpMovZbIb(struct Machine *m, uint32_t rde) {
Write8(ByteRexbSrm(m, rde), m->xedd->op.uimm0);
}
static void OpMovZvqpIvqp(struct Machine *m, uint32_t rde) {
WriteRegister(rde, RegRexbSrm(m, rde), m->xedd->op.uimm0);
}
static void OpIncZv(struct Machine *m, uint32_t rde) {
if (!Osz(rde)) {
Write32(RegSrm(m, rde), Inc32(Read32(RegSrm(m, rde)), 0, &m->flags));
} else {
Write16(RegSrm(m, rde), Inc16(Read16(RegSrm(m, rde)), 0, &m->flags));
}
}
static void OpDecZv(struct Machine *m, uint32_t rde) {
if (!Osz(rde)) {
Write32(RegSrm(m, rde), Dec32(Read32(RegSrm(m, rde)), 0, &m->flags));
} else {
Write16(RegSrm(m, rde), Dec16(Read16(RegSrm(m, rde)), 0, &m->flags));
}
}
static void OpMovEvqpIvds(struct Machine *m, uint32_t rde) {
WriteRegisterOrMemory(rde, GetModrmRegisterWordPointerWriteOszRexw(m, rde),
m->xedd->op.uimm0);
}
static void OpMovEvqpGvqp(struct Machine *m, uint32_t rde) {
WriteRegisterOrMemory(rde, GetModrmRegisterWordPointerWriteOszRexw(m, rde),
ReadMemory(rde, RegRexrReg(m, rde)));
}
static void OpMovzbGvqpEb(struct Machine *m, uint32_t rde) {
WriteRegister(rde, RegRexrReg(m, rde),
Read8(GetModrmRegisterBytePointerRead(m, rde)));
}
static void OpMovzwGvqpEw(struct Machine *m, uint32_t rde) {
WriteRegister(rde, RegRexrReg(m, rde),
Read16(GetModrmRegisterWordPointerRead2(m, rde)));
}
static void OpMovsbGvqpEb(struct Machine *m, uint32_t rde) {
WriteRegister(rde, RegRexrReg(m, rde),
(int8_t)Read8(GetModrmRegisterBytePointerRead(m, rde)));
}
static void OpMovswGvqpEw(struct Machine *m, uint32_t rde) {
WriteRegister(rde, RegRexrReg(m, rde),
(int16_t)Read16(GetModrmRegisterWordPointerRead2(m, rde)));
}
static void OpMovsxdGdqpEd(struct Machine *m, uint32_t rde) {
Write64(RegRexrReg(m, rde),
(int32_t)Read32(GetModrmRegisterWordPointerRead4(m, rde)));
}
static void Alub(struct Machine *m, uint32_t rde, aluop_f op) {
uint8_t *a = GetModrmRegisterBytePointerWrite(m, rde);
Write8(a, op(Read8(a), Read8(ByteRexrReg(m, rde)), &m->flags));
}
static void OpAlubAdd(struct Machine *m, uint32_t rde) {
Alub(m, rde, Add8);
}
static void OpAlubOr(struct Machine *m, uint32_t rde) {
Alub(m, rde, Or8);
}
static void OpAlubAdc(struct Machine *m, uint32_t rde) {
Alub(m, rde, Adc8);
}
static void OpAlubSbb(struct Machine *m, uint32_t rde) {
Alub(m, rde, Sbb8);
}
static void OpAlubAnd(struct Machine *m, uint32_t rde) {
Alub(m, rde, And8);
}
static void OpAlubSub(struct Machine *m, uint32_t rde) {
Alub(m, rde, Sub8);
}
static void OpAlubXor(struct Machine *m, uint32_t rde) {
Alub(m, rde, Xor8);
}
static void AlubRo(struct Machine *m, uint32_t rde, aluop_f op) {
op(Read8(GetModrmRegisterBytePointerRead(m, rde)), Read8(ByteRexrReg(m, rde)),
&m->flags);
}
static void OpAlubCmp(struct Machine *m, uint32_t rde) {
AlubRo(m, rde, Sub8);
}
static void OpAlubTest(struct Machine *m, uint32_t rde) {
AlubRo(m, rde, And8);
}
static void AlubFlip(struct Machine *m, uint32_t rde, aluop_f op) {
Write8(ByteRexrReg(m, rde),
op(Read8(ByteRexrReg(m, rde)),
Read8(GetModrmRegisterBytePointerRead(m, rde)), &m->flags));
}
static void OpAlubFlipAdd(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, Add8);
}
static void OpAlubFlipOr(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, Or8);
}
static void OpAlubFlipAdc(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, Adc8);
}
static void OpAlubFlipSbb(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, Sbb8);
}
static void OpAlubFlipAnd(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, And8);
}
static void OpAlubFlipSub(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, Sub8);
}
static void OpAlubFlipXor(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, Xor8);
}
static void AlubFlipRo(struct Machine *m, uint32_t rde, aluop_f op) {
op(Read8(ByteRexrReg(m, rde)), Read8(GetModrmRegisterBytePointerRead(m, rde)),
&m->flags);
}
static void OpAlubFlipCmp(struct Machine *m, uint32_t rde) {
AlubFlipRo(m, rde, Sub8);
}
static void OpAlubFlipTest(struct Machine *m, uint32_t rde) {
AlubFlipRo(m, rde, And8);
}
static void Alubi(struct Machine *m, uint32_t rde, aluop_f op) {
uint8_t *a, x;
a = GetModrmRegisterBytePointerWrite(m, rde);
Write8(a, op(Read8(a), m->xedd->op.uimm0, &m->flags));
}
static void AlubiRo(struct Machine *m, uint32_t rde, aluop_f op) {
op(Read8(GetModrmRegisterBytePointerRead(m, rde)), m->xedd->op.uimm0,
&m->flags);
}
static void OpAlubiTest(struct Machine *m, uint32_t rde) {
AlubiRo(m, rde, And8);
}
static void OpAlubiReg(struct Machine *m, uint32_t rde) {
if (ModrmReg(rde) == ALU_CMP) {
AlubiRo(m, rde, kAlu[ModrmReg(rde)][0]);
} else {
Alubi(m, rde, kAlu[ModrmReg(rde)][0]);
}
}
static void OpAluw(struct Machine *m, uint32_t rde) {
uint8_t *a;
a = GetModrmRegisterWordPointerWriteOszRexw(m, rde);
WriteRegisterOrMemory(
rde, a,
kAlu[(m->xedd->op.opcode & 070) >> 3][RegLog2(rde)](
ReadMemory(rde, a), Read64(RegRexrReg(m, rde)), &m->flags));
}
static void AluwRo(struct Machine *m, uint32_t rde, aluop_f ops[4]) {
ops[RegLog2(rde)](
ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)),
Read64(RegRexrReg(m, rde)), &m->flags);
}
static void OpAluwCmp(struct Machine *m, uint32_t rde) {
AluwRo(m, rde, kAlu[ALU_SUB]);
}
static void OpAluwTest(struct Machine *m, uint32_t rde) {
AluwRo(m, rde, kAlu[ALU_AND]);
}
static void OpAluwFlip(struct Machine *m, uint32_t rde) {
WriteRegister(
rde, RegRexrReg(m, rde),
kAlu[(m->xedd->op.opcode & 070) >> 3][RegLog2(rde)](
Read64(RegRexrReg(m, rde)),
ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)),
&m->flags));
}
static void AluwFlipRo(struct Machine *m, uint32_t rde, aluop_f ops[4]) {
ops[RegLog2(rde)](
Read64(RegRexrReg(m, rde)),
ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)),
&m->flags);
}
static void OpAluwFlipCmp(struct Machine *m, uint32_t rde) {
AluwFlipRo(m, rde, kAlu[ALU_SUB]);
}
static void OpAluwFlipTest(struct Machine *m, uint32_t rde) {
AluwFlipRo(m, rde, kAlu[ALU_AND]);
}
static void Aluwi(struct Machine *m, uint32_t rde, aluop_f ops[4]) {
uint8_t *a;
uint64_t x;
a = GetModrmRegisterWordPointerWriteOszRexw(m, rde);
WriteRegisterOrMemory(
rde, a,
ops[RegLog2(rde)](ReadMemory(rde, a), m->xedd->op.uimm0, &m->flags));
}
static void AluwiRo(struct Machine *m, uint32_t rde, aluop_f ops[4]) {
ops[RegLog2(rde)](
ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)),
m->xedd->op.uimm0, &m->flags);
}
static void OpAluwiReg(struct Machine *m, uint32_t rde) {
if (ModrmReg(rde) == ALU_CMP) {
AluwiRo(m, rde, kAlu[ModrmReg(rde)]);
} else {
Aluwi(m, rde, kAlu[ModrmReg(rde)]);
}
}
static void AluAlIb(struct Machine *m, aluop_f op) {
Write8(m->ax, op(Read8(m->ax), m->xedd->op.uimm0, &m->flags));
}
static void OpAluAlIbAdd(struct Machine *m, uint32_t rde) {
AluAlIb(m, Add8);
}
static void OpAluAlIbOr(struct Machine *m, uint32_t rde) {
AluAlIb(m, Or8);
}
static void OpAluAlIbAdc(struct Machine *m, uint32_t rde) {
AluAlIb(m, Adc8);
}
static void OpAluAlIbSbb(struct Machine *m, uint32_t rde) {
AluAlIb(m, Sbb8);
}
static void OpAluAlIbAnd(struct Machine *m, uint32_t rde) {
AluAlIb(m, And8);
}
static void OpAluAlIbSub(struct Machine *m, uint32_t rde) {
AluAlIb(m, Sub8);
}
static void OpAluAlIbXor(struct Machine *m, uint32_t rde) {
AluAlIb(m, Xor8);
}
static void OpAluRaxIvds(struct Machine *m, uint32_t rde) {
WriteRegister(rde, m->ax,
kAlu[(m->xedd->op.opcode & 070) >> 3][RegLog2(rde)](
ReadMemory(rde, m->ax), m->xedd->op.uimm0, &m->flags));
}
static void OpCmpAlIb(struct Machine *m, uint32_t rde) {
Sub8(Read8(m->ax), m->xedd->op.uimm0, &m->flags);
}
static void OpCmpRaxIvds(struct Machine *m, uint32_t rde) {
kAlu[ALU_SUB][RegLog2(rde)](ReadMemory(rde, m->ax), m->xedd->op.uimm0,
&m->flags);
}
static void OpTestAlIb(struct Machine *m, uint32_t rde) {
And8(Read8(m->ax), m->xedd->op.uimm0, &m->flags);
}
static void OpTestRaxIvds(struct Machine *m, uint32_t rde) {
kAlu[ALU_AND][RegLog2(rde)](ReadMemory(rde, m->ax), m->xedd->op.uimm0,
&m->flags);
}
static void Bsuwi(struct Machine *m, uint32_t rde, uint64_t y) {
uint8_t *p;
p = GetModrmRegisterWordPointerWriteOszRexw(m, rde);
WriteRegisterOrMemory(
rde, p,
kBsu[ModrmReg(rde)][RegLog2(rde)](ReadMemory(rde, p), y, &m->flags));
}
static void OpBsuwi1(struct Machine *m, uint32_t rde) {
Bsuwi(m, rde, 1);
}
static void OpBsuwiCl(struct Machine *m, uint32_t rde) {
Bsuwi(m, rde, Read8(m->cx));
}
static void OpBsuwiImm(struct Machine *m, uint32_t rde) {
Bsuwi(m, rde, m->xedd->op.uimm0);
}
static void Bsubi(struct Machine *m, uint32_t rde, uint64_t y) {
uint8_t *a = GetModrmRegisterBytePointerWrite(m, rde);
Write8(a, kBsu[ModrmReg(rde)][RegLog2(rde)](Read8(a), y, &m->flags));
}
static void OpBsubi1(struct Machine *m, uint32_t rde) {
Bsubi(m, rde, 1);
}
static void OpBsubiCl(struct Machine *m, uint32_t rde) {
Bsubi(m, rde, Read8(m->cx));
}
static void OpBsubiImm(struct Machine *m, uint32_t rde) {
Bsubi(m, rde, m->xedd->op.uimm0);
}
static relegated void LoadFarPointer(struct Machine *m, uint32_t rde,
uint8_t seg[8]) {
uint32_t fp;
fp = Read32(ComputeReserveAddressRead4(m, rde));
Write64(seg, (fp & 0x0000ffff) << 4);
Write16(RegRexrReg(m, rde), fp >> 16);
}
static relegated void OpLes(struct Machine *m, uint32_t rde) {
LoadFarPointer(m, rde, m->es);
}
static relegated void OpLds(struct Machine *m, uint32_t rde) {
LoadFarPointer(m, rde, m->ds);
}
static void OpLgdtMs(struct Machine *m, uint32_t rde) {
}
static void OpPushImm(struct Machine *m, uint32_t rde) {
Push(m, rde, m->xedd->op.uimm0);
}
static void Interrupt(struct Machine *m, uint32_t rde, int i) {
HaltMachine(m, i);
}
static void OpInterruptImm(struct Machine *m, uint32_t rde) {
Interrupt(m, rde, m->xedd->op.uimm0);
}
static void OpInterrupt1(struct Machine *m, uint32_t rde) {
Interrupt(m, rde, 1);
}
static void OpInterrupt3(struct Machine *m, uint32_t rde) {
Interrupt(m, rde, 3);
}
static void OpJmp(struct Machine *m, uint32_t rde) {
m->ip += m->xedd->op.disp;
}
static void OpJe(struct Machine *m, uint32_t rde) {
if (GetFlag(m->flags, FLAGS_ZF)) {
OpJmp(m, rde);
}
}
static void OpJne(struct Machine *m, uint32_t rde) {
if (!GetFlag(m->flags, FLAGS_ZF)) {
OpJmp(m, rde);
}
}
static void OpJb(struct Machine *m, uint32_t rde) {
if (GetFlag(m->flags, FLAGS_CF)) {
OpJmp(m, rde);
}
}
static void OpJbe(struct Machine *m, uint32_t rde) {
if (IsBelowOrEqual(m)) {
OpJmp(m, rde);
}
}
static void OpJo(struct Machine *m, uint32_t rde) {
if (GetFlag(m->flags, FLAGS_OF)) {
OpJmp(m, rde);
}
}
static void OpJno(struct Machine *m, uint32_t rde) {
if (!GetFlag(m->flags, FLAGS_OF)) {
OpJmp(m, rde);
}
}
static void OpJae(struct Machine *m, uint32_t rde) {
if (!GetFlag(m->flags, FLAGS_CF)) {
OpJmp(m, rde);
}
}
static void OpJa(struct Machine *m, uint32_t rde) {
if (IsAbove(m)) {
OpJmp(m, rde);
}
}
static void OpJs(struct Machine *m, uint32_t rde) {
if (GetFlag(m->flags, FLAGS_SF)) {
OpJmp(m, rde);
}
}
static void OpJns(struct Machine *m, uint32_t rde) {
if (!GetFlag(m->flags, FLAGS_SF)) {
OpJmp(m, rde);
}
}
static void OpJp(struct Machine *m, uint32_t rde) {
if (IsParity(m)) {
OpJmp(m, rde);
}
}
static void OpJnp(struct Machine *m, uint32_t rde) {
if (!IsParity(m)) {
OpJmp(m, rde);
}
}
static void OpJl(struct Machine *m, uint32_t rde) {
if (IsLess(m)) {
OpJmp(m, rde);
}
}
static void OpJge(struct Machine *m, uint32_t rde) {
if (IsGreaterOrEqual(m)) {
OpJmp(m, rde);
}
}
static void OpJle(struct Machine *m, uint32_t rde) {
if (IsLessOrEqual(m)) {
OpJmp(m, rde);
}
}
static void OpJg(struct Machine *m, uint32_t rde) {
if (IsGreater(m)) {
OpJmp(m, rde);
}
}
static void OpMovGvqpEvqp(struct Machine *m, uint32_t rde) {
WriteRegister(
rde, RegRexrReg(m, rde),
ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)));
}
static void OpCmovo(struct Machine *m, uint32_t rde) {
if (GetFlag(m->flags, FLAGS_OF)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovno(struct Machine *m, uint32_t rde) {
if (!GetFlag(m->flags, FLAGS_OF)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovb(struct Machine *m, uint32_t rde) {
if (GetFlag(m->flags, FLAGS_CF)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovae(struct Machine *m, uint32_t rde) {
if (!GetFlag(m->flags, FLAGS_CF)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmove(struct Machine *m, uint32_t rde) {
if (GetFlag(m->flags, FLAGS_ZF)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovne(struct Machine *m, uint32_t rde) {
if (!GetFlag(m->flags, FLAGS_ZF)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovbe(struct Machine *m, uint32_t rde) {
if (IsBelowOrEqual(m)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmova(struct Machine *m, uint32_t rde) {
if (IsAbove(m)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovs(struct Machine *m, uint32_t rde) {
if (GetFlag(m->flags, FLAGS_SF)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovns(struct Machine *m, uint32_t rde) {
if (!GetFlag(m->flags, FLAGS_SF)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovp(struct Machine *m, uint32_t rde) {
if (IsParity(m)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovnp(struct Machine *m, uint32_t rde) {
if (!IsParity(m)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovl(struct Machine *m, uint32_t rde) {
if (IsLess(m)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovge(struct Machine *m, uint32_t rde) {
if (IsGreaterOrEqual(m)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovle(struct Machine *m, uint32_t rde) {
if (IsLessOrEqual(m)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovg(struct Machine *m, uint32_t rde) {
if (IsGreater(m)) {
OpMovGvqpEvqp(m, rde);
}
}
static void SetEb(struct Machine *m, uint32_t rde, bool x) {
Write8(GetModrmRegisterBytePointerWrite(m, rde), x);
}
static void OpSeto(struct Machine *m, uint32_t rde) {
SetEb(m, rde, GetFlag(m->flags, FLAGS_OF));
}
static void OpSetno(struct Machine *m, uint32_t rde) {
SetEb(m, rde, !GetFlag(m->flags, FLAGS_OF));
}
static void OpSetb(struct Machine *m, uint32_t rde) {
SetEb(m, rde, GetFlag(m->flags, FLAGS_CF));
}
static void OpSetae(struct Machine *m, uint32_t rde) {
SetEb(m, rde, !GetFlag(m->flags, FLAGS_CF));
}
static void OpSete(struct Machine *m, uint32_t rde) {
SetEb(m, rde, GetFlag(m->flags, FLAGS_ZF));
}
static void OpSetne(struct Machine *m, uint32_t rde) {
SetEb(m, rde, !GetFlag(m->flags, FLAGS_ZF));
}
static void OpSetbe(struct Machine *m, uint32_t rde) {
SetEb(m, rde, IsBelowOrEqual(m));
}
static void OpSeta(struct Machine *m, uint32_t rde) {
SetEb(m, rde, IsAbove(m));
}
static void OpSets(struct Machine *m, uint32_t rde) {
SetEb(m, rde, GetFlag(m->flags, FLAGS_SF));
}
static void OpSetns(struct Machine *m, uint32_t rde) {
SetEb(m, rde, !GetFlag(m->flags, FLAGS_SF));
}
static void OpSetp(struct Machine *m, uint32_t rde) {
SetEb(m, rde, IsParity(m));
}
static void OpSetnp(struct Machine *m, uint32_t rde) {
SetEb(m, rde, !IsParity(m));
}
static void OpSetl(struct Machine *m, uint32_t rde) {
SetEb(m, rde, IsLess(m));
}
static void OpSetge(struct Machine *m, uint32_t rde) {
SetEb(m, rde, IsGreaterOrEqual(m));
}
static void OpSetle(struct Machine *m, uint32_t rde) {
SetEb(m, rde, IsLessOrEqual(m));
}
static void OpSetg(struct Machine *m, uint32_t rde) {
SetEb(m, rde, IsGreater(m));
}
static void OpJcxz(struct Machine *m, uint32_t rde) {
if (!MaskAddress(Eamode(rde), Read64(m->cx))) {
OpJmp(m, rde);
}
}
static void Bitscan(struct Machine *m, uint32_t rde, bitscan_f op) {
WriteRegister(
rde, RegRexrReg(m, rde),
op(m, rde,
ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde))));
}
static void OpBsf(struct Machine *m, uint32_t rde) {
Bitscan(m, rde, AluBsf);
}
static void OpBsr(struct Machine *m, uint32_t rde) {
Bitscan(m, rde, AluBsr);
}
static void Op1b8(struct Machine *m, uint32_t rde) {
if (Rep(rde) == 3) {
Bitscan(m, rde, AluPopcnt);
} else {
OpUd(m, rde);
}
}
static void OpNotEb(struct Machine *m, uint32_t rde) {
AluEb(m, rde, Not8);
}
static void OpNegEb(struct Machine *m, uint32_t rde) {
AluEb(m, rde, Neg8);
}
static relegated void Loop(struct Machine *m, uint32_t rde, bool cond) {
uint64_t cx;
cx = Read64(m->cx) - 1;
if (Eamode(rde) != XED_MODE_REAL) {
if (Eamode(rde) == XED_MODE_LEGACY) {
cx &= 0xffffffff;
}
Write64(m->cx, cx);
} else {
cx &= 0xffff;
Write16(m->cx, cx);
}
if (cx && cond) {
OpJmp(m, rde);
}
}
static relegated void OpLoope(struct Machine *m, uint32_t rde) {
Loop(m, rde, GetFlag(m->flags, FLAGS_ZF));
}
static relegated void OpLoopne(struct Machine *m, uint32_t rde) {
Loop(m, rde, !GetFlag(m->flags, FLAGS_ZF));
}
static relegated void OpLoop1(struct Machine *m, uint32_t rde) {
Loop(m, rde, true);
}
static const nexgen32e_f kOp0f6[] = {
OpAlubiTest,
OpAlubiTest,
OpNotEb,
OpNegEb,
OpMulAxAlEbUnsigned,
OpMulAxAlEbSigned,
OpDivAlAhAxEbUnsigned,
OpDivAlAhAxEbSigned,
};
static void Op0f6(struct Machine *m, uint32_t rde) {
kOp0f6[ModrmReg(rde)](m, rde);
}
static void OpTestEvqpIvds(struct Machine *m, uint32_t rde) {
AluwiRo(m, rde, kAlu[ALU_AND]);
}
static void OpNotEvqp(struct Machine *m, uint32_t rde) {
AluEvqp(m, rde, kAlu[ALU_NOT]);
}
static void OpNegEvqp(struct Machine *m, uint32_t rde) {
AluEvqp(m, rde, kAlu[ALU_NEG]);
}
static const nexgen32e_f kOp0f7[] = {
OpTestEvqpIvds,
OpTestEvqpIvds,
OpNotEvqp,
OpNegEvqp,
OpMulRdxRaxEvqpUnsigned,
OpMulRdxRaxEvqpSigned,
OpDivRdxRaxEvqpUnsigned,
OpDivRdxRaxEvqpSigned,
};
static void Op0f7(struct Machine *m, uint32_t rde) {
kOp0f7[ModrmReg(rde)](m, rde);
}
static void Op0fe(struct Machine *m, uint32_t rde) {
switch (ModrmReg(rde)) {
case 0:
AluEb(m, rde, Inc8);
break;
case 1:
AluEb(m, rde, Dec8);
break;
default:
OpUd(m, rde);
}
}
static void OpIncEvqp(struct Machine *m, uint32_t rde) {
AluEvqp(m, rde, kAlu[ALU_INC]);
}
static void OpDecEvqp(struct Machine *m, uint32_t rde) {
AluEvqp(m, rde, kAlu[ALU_DEC]);
}
static const nexgen32e_f kOp0ff[] = {OpIncEvqp, OpDecEvqp, OpCallEq, OpUd,
OpJmpEq, OpUd, OpPushEvq, OpUd};
static void Op0ff(struct Machine *m, uint32_t rde) {
kOp0ff[ModrmReg(rde)](m, rde);
}
static void Op101(struct Machine *m, uint32_t rde) {
if (IsModrmRegister(rde)) {
if (ModrmReg(rde) == 0b111 && ModrmRm(rde) == 0b001) {
OpRdtscp(m, rde);
return;
}
} else {
if (ModrmReg(rde) == 2) {
OpLgdtMs(m, rde);
return;
}
}
OpUd(m, rde);
}
static void OpDoubleShift(struct Machine *m, uint32_t rde) {
uint8_t *p;
uint64_t x;
uint8_t W[2][2] = {{2, 3}, {1, 3}};
p = GetModrmRegisterWordPointerWriteOszRexw(m, rde);
WriteRegisterOrMemory(
rde, p,
BsuDoubleShift(W[Osz(rde)][Rexw(rde)], ReadMemory(rde, p),
ReadMemory(rde, RegRexrReg(m, rde)),
m->xedd->op.opcode & 1 ? Read8(m->cx) : m->xedd->op.uimm0,
m->xedd->op.opcode & 8, &m->flags));
}
static void Op1ae(struct Machine *m, uint32_t rde) {
switch (ModrmReg(rde)) {
case 5:
OpLfence(m, rde);
break;
case 6:
OpMfence(m, rde);
break;
case 7:
if (ModrmMod(rde) == 0b11 && ModrmReg(rde) == 0b111) {
OpSfence(m, rde);
} else {
OpClflush(m, rde);
}
break;
default:
OpUd(m, rde);
}
}
static void OpSalc(struct Machine *m, uint32_t rde) {
Write8(m->ax, GetFlag(m->flags, FLAGS_CF));
}
static void OpNopEv(struct Machine *m, uint32_t rde) {
if (ModrmMod(rde) == 0b01 && ModrmReg(rde) == 0 && ModrmRm(rde) == 0b101) {
OpBofram(m, rde);
} else {
OpNoop(m, rde);
}
}
static void OpNop(struct Machine *m, uint32_t rde) {
if (Rexb(rde)) {
OpXchgZvqp(m, rde);
} else if (Rep(rde) == 3) {
OpPause(m, rde);
} else {
OpNoop(m, rde);
}
}
static const nexgen32e_f kNexgen32e[] = {
[0x000] = OpAlubAdd,
[0x001] = OpAluw,
[0x002] = OpAlubFlipAdd,
[0x003] = OpAluwFlip,
[0x004] = OpAluAlIbAdd,
[0x005] = OpAluRaxIvds,
[0x006] = OpPushSeg,
[0x007] = OpPopSeg,
[0x008] = OpAlubOr,
[0x009] = OpAluw,
[0x00A] = OpAlubFlipOr,
[0x00B] = OpAluwFlip,
[0x00C] = OpAluAlIbOr,
[0x00D] = OpAluRaxIvds,
[0x00E] = OpPushSeg,
[0x00F] = OpPopSeg,
[0x010] = OpAlubAdc,
[0x011] = OpAluw,
[0x012] = OpAlubFlipAdc,
[0x013] = OpAluwFlip,
[0x014] = OpAluAlIbAdc,
[0x015] = OpAluRaxIvds,
[0x016] = OpPushSeg,
[0x017] = OpPopSeg,
[0x018] = OpAlubSbb,
[0x019] = OpAluw,
[0x01A] = OpAlubFlipSbb,
[0x01B] = OpAluwFlip,
[0x01C] = OpAluAlIbSbb,
[0x01D] = OpAluRaxIvds,
[0x01E] = OpPushSeg,
[0x01F] = OpPopSeg,
[0x020] = OpAlubAnd,
[0x021] = OpAluw,
[0x022] = OpAlubFlipAnd,
[0x023] = OpAluwFlip,
[0x024] = OpAluAlIbAnd,
[0x025] = OpAluRaxIvds,
[0x026] = OpPushSeg,
[0x027] = OpPopSeg,
[0x028] = OpAlubSub,
[0x029] = OpAluw,
[0x02A] = OpAlubFlipSub,
[0x02B] = OpAluwFlip,
[0x02C] = OpAluAlIbSub,
[0x02D] = OpAluRaxIvds,
[0x02E] = OpUd,
[0x02F] = OpDas,
[0x030] = OpAlubXor,
[0x031] = OpAluw,
[0x032] = OpAlubFlipXor,
[0x033] = OpAluwFlip,
[0x034] = OpAluAlIbXor,
[0x035] = OpAluRaxIvds,
[0x036] = OpUd,
[0x037] = OpAaa,
[0x038] = OpAlubCmp,
[0x039] = OpAluwCmp,
[0x03A] = OpAlubFlipCmp,
[0x03B] = OpAluwFlipCmp,
[0x03C] = OpCmpAlIb,
[0x03D] = OpCmpRaxIvds,
[0x03E] = OpUd,
[0x03F] = OpAas,
[0x040] = OpIncZv,
[0x041] = OpIncZv,
[0x042] = OpIncZv,
[0x043] = OpIncZv,
[0x044] = OpIncZv,
[0x045] = OpIncZv,
[0x046] = OpIncZv,
[0x047] = OpIncZv,
[0x048] = OpDecZv,
[0x049] = OpDecZv,
[0x04A] = OpDecZv,
[0x04B] = OpDecZv,
[0x04C] = OpDecZv,
[0x04D] = OpDecZv,
[0x04E] = OpDecZv,
[0x04F] = OpDecZv,
[0x050] = OpPushZvq,
[0x051] = OpPushZvq,
[0x052] = OpPushZvq,
[0x053] = OpPushZvq,
[0x054] = OpPushZvq,
[0x055] = OpPushZvq,
[0x056] = OpPushZvq,
[0x057] = OpPushZvq,
[0x058] = OpPopZvq,
[0x059] = OpPopZvq,
[0x05A] = OpPopZvq,
[0x05B] = OpPopZvq,
[0x05C] = OpPopZvq,
[0x05D] = OpPopZvq,
[0x05E] = OpPopZvq,
[0x05F] = OpPopZvq,
[0x060] = OpPusha,
[0x061] = OpPopa,
[0x062] = OpUd,
[0x063] = OpMovsxdGdqpEd,
[0x064] = OpUd,
[0x065] = OpUd,
[0x066] = OpUd,
[0x067] = OpUd,
[0x068] = OpPushImm,
[0x069] = OpImulGvqpEvqpImm,
[0x06A] = OpPushImm,
[0x06B] = OpImulGvqpEvqpImm,
[0x06C] = OpIns,
[0x06D] = OpIns,
[0x06E] = OpOuts,
[0x06F] = OpOuts,
[0x070] = OpJo,
[0x071] = OpJno,
[0x072] = OpJb,
[0x073] = OpJae,
[0x074] = OpJe,
[0x075] = OpJne,
[0x076] = OpJbe,
[0x077] = OpJa,
[0x078] = OpJs,
[0x079] = OpJns,
[0x07A] = OpJp,
[0x07B] = OpJnp,
[0x07C] = OpJl,
[0x07D] = OpJge,
[0x07E] = OpJle,
[0x07F] = OpJg,
[0x080] = OpAlubiReg,
[0x081] = OpAluwiReg,
[0x082] = OpAlubiReg,
[0x083] = OpAluwiReg,
[0x084] = OpAlubTest,
[0x085] = OpAluwTest,
[0x086] = OpXchgGbEb,
[0x087] = OpXchgGvqpEvqp,
[0x088] = OpMovEbGb,
[0x089] = OpMovEvqpGvqp,
[0x08A] = OpMovGbEb,
[0x08B] = OpMovGvqpEvqp,
[0x08C] = OpMovEvqpSw,
[0x08D] = OpLeaGvqpM,
[0x08E] = OpMovSwEvqp,
[0x08F] = OpPopEvq,
[0x090] = OpNop,
[0x091] = OpXchgZvqp,
[0x092] = OpXchgZvqp,
[0x093] = OpXchgZvqp,
[0x094] = OpXchgZvqp,
[0x095] = OpXchgZvqp,
[0x096] = OpXchgZvqp,
[0x097] = OpXchgZvqp,
[0x098] = OpSax,
[0x099] = OpConvert,
[0x09A] = OpCallf,
[0x09B] = OpFwait,
[0x09C] = OpPushf,
[0x09D] = OpPopf,
[0x09E] = OpSahf,
[0x09F] = OpLahf,
[0x0A0] = OpMovAlOb,
[0x0A1] = OpMovRaxOvqp,
[0x0A2] = OpMovObAl,
[0x0A3] = OpMovOvqpRax,
[0x0A4] = OpMovsb,
[0x0A5] = OpMovs,
[0x0A6] = OpCmps,
[0x0A7] = OpCmps,
[0x0A8] = OpTestAlIb,
[0x0A9] = OpTestRaxIvds,
[0x0AA] = OpStosb,
[0x0AB] = OpStos,
[0x0AC] = OpLods,
[0x0AD] = OpLods,
[0x0AE] = OpScas,
[0x0AF] = OpScas,
[0x0B0] = OpMovZbIb,
[0x0B1] = OpMovZbIb,
[0x0B2] = OpMovZbIb,
[0x0B3] = OpMovZbIb,
[0x0B4] = OpMovZbIb,
[0x0B5] = OpMovZbIb,
[0x0B6] = OpMovZbIb,
[0x0B7] = OpMovZbIb,
[0x0B8] = OpMovZvqpIvqp,
[0x0B9] = OpMovZvqpIvqp,
[0x0BA] = OpMovZvqpIvqp,
[0x0BB] = OpMovZvqpIvqp,
[0x0BC] = OpMovZvqpIvqp,
[0x0BD] = OpMovZvqpIvqp,
[0x0BE] = OpMovZvqpIvqp,
[0x0BF] = OpMovZvqpIvqp,
[0x0C0] = OpBsubiImm,
[0x0C1] = OpBsuwiImm,
[0x0C2] = OpRet,
[0x0C3] = OpRet,
[0x0C4] = OpLes,
[0x0C5] = OpLds,
[0x0C6] = OpMovEbIb,
[0x0C7] = OpMovEvqpIvds,
[0x0C8] = OpUd,
[0x0C9] = OpLeave,
[0x0CA] = OpRetf,
[0x0CB] = OpRetf,
[0x0CC] = OpInterrupt3,
[0x0CD] = OpInterruptImm,
[0x0CE] = OpUd,
[0x0CF] = OpUd,
[0x0D0] = OpBsubi1,
[0x0D1] = OpBsuwi1,
[0x0D2] = OpBsubiCl,
[0x0D3] = OpBsuwiCl,
[0x0D4] = OpAam,
[0x0D5] = OpAad,
[0x0D6] = OpSalc,
[0x0D7] = OpXlatAlBbb,
[0x0D8] = OpFpu,
[0x0D9] = OpFpu,
[0x0DA] = OpFpu,
[0x0DB] = OpFpu,
[0x0DC] = OpFpu,
[0x0DD] = OpFpu,
[0x0DE] = OpFpu,
[0x0DF] = OpFpu,
[0x0E0] = OpLoopne,
[0x0E1] = OpLoope,
[0x0E2] = OpLoop1,
[0x0E3] = OpJcxz,
[0x0E4] = OpInAlImm,
[0x0E5] = OpInAxImm,
[0x0E6] = OpOutImmAl,
[0x0E7] = OpOutImmAx,
[0x0E8] = OpCallJvds,
[0x0E9] = OpJmp,
[0x0EA] = OpJmpf,
[0x0EB] = OpJmp,
[0x0EC] = OpInAlDx,
[0x0ED] = OpInAxDx,
[0x0EE] = OpOutDxAl,
[0x0EF] = OpOutDxAx,
[0x0F0] = OpUd,
[0x0F1] = OpInterrupt1,
[0x0F2] = OpUd,
[0x0F3] = OpUd,
[0x0F4] = OpHlt,
[0x0F5] = OpCmc,
[0x0F6] = Op0f6,
[0x0F7] = Op0f7,
[0x0F8] = OpClc,
[0x0F9] = OpStc,
[0x0FA] = OpCli,
[0x0FB] = OpSti,
[0x0FC] = OpCld,
[0x0FD] = OpStd,
[0x0FE] = Op0fe,
[0x0FF] = Op0ff,
[0x100] = OpUd,
[0x101] = Op101,
[0x102] = OpUd,
[0x103] = OpUd,
[0x104] = OpUd,
[0x105] = OpSyscall,
[0x106] = OpUd,
[0x107] = OpUd,
[0x108] = OpUd,
[0x109] = OpUd,
[0x10A] = OpUd,
[0x10B] = OpUd,
[0x10C] = OpUd,
[0x10D] = OpHintNopEv,
[0x10E] = OpUd,
[0x10F] = OpUd,
[0x110] = OpMov0f10,
[0x111] = OpMovWpsVps,
[0x112] = OpMov0f12,
[0x113] = OpMov0f13,
[0x114] = OpUnpcklpsd,
[0x115] = OpUnpckhpsd,
[0x116] = OpMov0f16,
[0x117] = OpMov0f17,
[0x118] = OpHintNopEv,
[0x119] = OpHintNopEv,
[0x11A] = OpHintNopEv,
[0x11B] = OpHintNopEv,
[0x11C] = OpHintNopEv,
[0x11D] = OpHintNopEv,
[0x11E] = OpUd,
[0x11F] = OpNopEv,
[0x120] = OpUd,
[0x121] = OpUd,
[0x122] = OpUd,
[0x123] = OpUd,
[0x124] = OpUd,
[0x125] = OpUd,
[0x126] = OpUd,
[0x127] = OpUd,
[0x128] = OpMov0f28,
[0x129] = OpMovWpsVps,
[0x12A] = OpCvt0f2a,
[0x12B] = OpMov0f2b,
[0x12C] = OpCvtt0f2c,
[0x12D] = OpCvt0f2d,
[0x12E] = OpComissVsWs,
[0x12F] = OpComissVsWs,
[0x130] = OpUd,
[0x131] = OpRdtsc,
[0x132] = OpUd,
[0x133] = OpUd,
[0x134] = OpUd,
[0x135] = OpUd,
[0x136] = OpUd,
[0x137] = OpUd,
[0x138] = OpUd,
[0x139] = OpUd,
[0x13A] = OpUd,
[0x13B] = OpUd,
[0x13C] = OpUd,
[0x13D] = OpUd,
[0x13E] = OpUd,
[0x13F] = OpUd,
[0x140] = OpCmovo,
[0x141] = OpCmovno,
[0x142] = OpCmovb,
[0x143] = OpCmovae,
[0x144] = OpCmove,
[0x145] = OpCmovne,
[0x146] = OpCmovbe,
[0x147] = OpCmova,
[0x148] = OpCmovs,
[0x149] = OpCmovns,
[0x14A] = OpCmovp,
[0x14B] = OpCmovnp,
[0x14C] = OpCmovl,
[0x14D] = OpCmovge,
[0x14E] = OpCmovle,
[0x14F] = OpCmovg,
[0x150] = OpUd,
[0x151] = OpSqrtpsd,
[0x152] = OpRsqrtps,
[0x153] = OpRcpps,
[0x154] = OpAndpsd,
[0x155] = OpAndnpsd,
[0x156] = OpOrpsd,
[0x157] = OpXorpsd,
[0x158] = OpAddpsd,
[0x159] = OpMulpsd,
[0x15A] = OpCvt0f5a,
[0x15B] = OpCvt0f5b,
[0x15C] = OpSubpsd,
[0x15D] = OpMinpsd,
[0x15E] = OpDivpsd,
[0x15F] = OpMaxpsd,
[0x160] = OpSsePunpcklbw,
[0x161] = OpSsePunpcklwd,
[0x162] = OpSsePunpckldq,
[0x163] = OpSsePacksswb,
[0x164] = OpSsePcmpgtb,
[0x165] = OpSsePcmpgtw,
[0x166] = OpSsePcmpgtd,
[0x167] = OpSsePackuswb,
[0x168] = OpSsePunpckhbw,
[0x169] = OpSsePunpckhwd,
[0x16A] = OpSsePunpckhdq,
[0x16B] = OpSsePackssdw,
[0x16C] = OpSsePunpcklqdq,
[0x16D] = OpSsePunpckhqdq,
[0x16E] = OpMov0f6e,
[0x16F] = OpMov0f6f,
[0x170] = OpShuffle,
[0x171] = Op171,
[0x172] = Op172,
[0x173] = Op173,
[0x174] = OpSsePcmpeqb,
[0x175] = OpSsePcmpeqw,
[0x176] = OpSsePcmpeqd,
[0x177] = OpUd,
[0x178] = OpUd,
[0x179] = OpUd,
[0x17A] = OpUd,
[0x17B] = OpUd,
[0x17C] = OpHaddpsd,
[0x17D] = OpHsubpsd,
[0x17E] = OpMov0f7e,
[0x17F] = OpMov0f7f,
[0x180] = OpJo,
[0x181] = OpJno,
[0x182] = OpJb,
[0x183] = OpJae,
[0x184] = OpJe,
[0x185] = OpJne,
[0x186] = OpJbe,
[0x187] = OpJa,
[0x188] = OpJs,
[0x189] = OpJns,
[0x18A] = OpJp,
[0x18B] = OpJnp,
[0x18C] = OpJl,
[0x18D] = OpJge,
[0x18E] = OpJle,
[0x18F] = OpJg,
[0x190] = OpSeto,
[0x191] = OpSetno,
[0x192] = OpSetb,
[0x193] = OpSetae,
[0x194] = OpSete,
[0x195] = OpSetne,
[0x196] = OpSetbe,
[0x197] = OpSeta,
[0x198] = OpSets,
[0x199] = OpSetns,
[0x19A] = OpSetp,
[0x19B] = OpSetnp,
[0x19C] = OpSetl,
[0x19D] = OpSetge,
[0x19E] = OpSetle,
[0x19F] = OpSetg,
[0x1A0] = OpPushSeg,
[0x1A1] = OpPopSeg,
[0x1A2] = OpCpuid,
[0x1A3] = OpBit,
[0x1A4] = OpDoubleShift,
[0x1A5] = OpDoubleShift,
[0x1A6] = OpUd,
[0x1A7] = OpUd,
[0x1A8] = OpPushSeg,
[0x1A9] = OpPopSeg,
[0x1AA] = OpUd,
[0x1AB] = OpBit,
[0x1AC] = OpDoubleShift,
[0x1AD] = OpDoubleShift,
[0x1AE] = Op1ae,
[0x1AF] = OpImulGvqpEvqp,
[0x1B0] = OpCmpxchgEbAlGb,
[0x1B1] = OpCmpxchgEvqpRaxGvqp,
[0x1B2] = OpUd,
[0x1B3] = OpBit,
[0x1B4] = OpUd,
[0x1B5] = OpUd,
[0x1B6] = OpMovzbGvqpEb,
[0x1B7] = OpMovzwGvqpEw,
[0x1B8] = Op1b8,
[0x1B9] = OpUd,
[0x1BA] = OpBit,
[0x1BB] = OpBit,
[0x1BC] = OpBsf,
[0x1BD] = OpBsr,
[0x1BE] = OpMovsbGvqpEb,
[0x1BF] = OpMovswGvqpEw,
[0x1C0] = OpXaddEbGb,
[0x1C1] = OpXaddEvqpGvqp,
[0x1C2] = OpCmppsd,
[0x1C3] = OpMovntiMdqpGdqp,
[0x1C4] = OpPinsrwVdqEwIb,
[0x1C5] = OpPextrwGdqpUdqIb,
[0x1C6] = OpShufpsd,
[0x1C7] = OpCmpxchgDxAx,
[0x1C8] = OpBswapZvqp,
[0x1C9] = OpBswapZvqp,
[0x1CA] = OpBswapZvqp,
[0x1CB] = OpBswapZvqp,
[0x1CC] = OpBswapZvqp,
[0x1CD] = OpBswapZvqp,
[0x1CE] = OpBswapZvqp,
[0x1CF] = OpBswapZvqp,
[0x1D0] = OpAddsubpsd,
[0x1D1] = OpSsePsrlwv,
[0x1D2] = OpSsePsrldv,
[0x1D3] = OpSsePsrlqv,
[0x1D4] = OpSsePaddq,
[0x1D5] = OpSsePmullw,
[0x1D6] = OpMov0fD6,
[0x1D7] = OpPmovmskbGdqpNqUdq,
[0x1D8] = OpSsePsubusb,
[0x1D9] = OpSsePsubusw,
[0x1DA] = OpSsePminub,
[0x1DB] = OpSsePand,
[0x1DC] = OpSsePaddusb,
[0x1DD] = OpSsePaddusw,
[0x1DE] = OpSsePmaxub,
[0x1DF] = OpSsePandn,
[0x1E0] = OpSsePavgb,
[0x1E1] = OpSsePsrawv,
[0x1E2] = OpSsePsradv,
[0x1E3] = OpSsePavgw,
[0x1E4] = OpSsePmulhuw,
[0x1E5] = OpSsePmulhw,
[0x1E6] = OpCvt0fE6,
[0x1E7] = OpMov0fE7,
[0x1E8] = OpSsePsubsb,
[0x1E9] = OpSsePsubsw,
[0x1EA] = OpSsePminsw,
[0x1EB] = OpSsePor,
[0x1EC] = OpSsePaddsb,
[0x1ED] = OpSsePaddsw,
[0x1EE] = OpSsePmaxsw,
[0x1EF] = OpSsePxor,
[0x1F0] = OpLddquVdqMdq,
[0x1F1] = OpSsePsllwv,
[0x1F2] = OpSsePslldv,
[0x1F3] = OpSsePsllqv,
[0x1F4] = OpSsePmuludq,
[0x1F5] = OpSsePmaddwd,
[0x1F6] = OpSsePsadbw,
[0x1F7] = OpMaskMovDiXmmRegXmmRm,
[0x1F8] = OpSsePsubb,
[0x1F9] = OpSsePsubw,
[0x1FA] = OpSsePsubd,
[0x1FB] = OpSsePsubq,
[0x1FC] = OpSsePaddb,
[0x1FD] = OpSsePaddw,
[0x1FE] = OpSsePaddd,
[0x1FF] = OpUd,
[0x200] = OpSsePshufb,
[0x201] = OpSsePhaddw,
[0x202] = OpSsePhaddd,
[0x203] = OpSsePhaddsw,
[0x204] = OpSsePmaddubsw,
[0x205] = OpSsePhsubw,
[0x206] = OpSsePhsubd,
[0x207] = OpSsePhsubsw,
[0x208] = OpSsePsignb,
[0x209] = OpSsePsignw,
[0x20A] = OpSsePsignd,
[0x20B] = OpSsePmulhrsw,
};
void ExecuteSparseInstruction(struct Machine *m, uint32_t rde, uint32_t d) {
switch (d) {
CASE(0x21c, OpSsePabsb(m, rde));
CASE(0x21d, OpSsePabsw(m, rde));
CASE(0x21e, OpSsePabsd(m, rde));
CASE(0x22a, OpMovntdqaVdqMdq(m, rde));
CASE(0x240, OpSsePmulld(m, rde));
CASE(0x30f, OpSsePalignr(m, rde));
default:
OpUd(m, rde);
}
}
void ExecuteInstruction(struct Machine *m) {
m->ip += m->xedd->length;
if (m->xedd->op.dispatch < ARRAYLEN(kNexgen32e)) {
kNexgen32e[m->xedd->op.dispatch](m, m->xedd->op.rde);
} else {
ExecuteSparseInstruction(m, m->xedd->op.rde, m->xedd->op.dispatch);
}
if (m->stashaddr) {
VirtualRecv(m, m->stashaddr, m->stash, m->stashsize);
m->stashaddr = 0;
}
}