#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>

#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "emu/x87emu_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "custommem.h"

#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "../dynarec_helper.h"
#include "dynarec_arm64_functions.h"


uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
{
    uint8_t opcode = F8;
    uint8_t nextop, u8;
    int16_t i16;
    uint16_t u16;
    uint64_t u64;
    int32_t i32;
    int64_t j64;
    uint8_t gd, ed;
    uint8_t wback, wb1;
    int64_t fixedaddress;
    int unscaled;
    int lock;
    MAYUSE(u8);
    MAYUSE(u16);
    MAYUSE(u64);
    MAYUSE(j64);
    MAYUSE(lock);

    while((opcode==0x2E) || (opcode==0x36) || (opcode==0x26) || (opcode==0x66))   // ignoring CS:, SS:, ES: or multiple 0x66
        opcode = F8;

    while((opcode==0xF2) || (opcode==0xF3)) {
        rep = opcode-0xF1;
        opcode = F8;
    }
    GETREX();

    if(rex.w && !(opcode==0x0f || opcode==0xf0 || opcode==0x64 || opcode==0x65))   // rex.w cancels "66", but not for 66 0f type of prefix
        return dynarec64_00(dyn, addr-1, ip, ninst, rex, rep, ok, need_epilog); // addr-1, to "put back" opcode

    switch(opcode) {
        case 0x01:
            INST_NAME("ADD Ew, Gw");
            SETFLAGS(X_ALL, SF_SET_PENDING);
            nextop = F8;
            GETGW(x2);
            GETEW(x1, 0);
            emit_add16(dyn, ninst, x1, x2, x4, x5);
            EWBACK;
            break;
        case 0x03:
            INST_NAME("ADD Gw, Ew");
            SETFLAGS(X_ALL, SF_SET_PENDING);
            nextop = F8;
            GETGW(x1);
            GETEW(x2, 0);
            emit_add16(dyn, ninst, x1, x2, x3, x4);
            GWBACK;
            break;
        case 0x05:
            INST_NAME("ADD AX, Iw");
            SETFLAGS(X_ALL, SF_SET_PENDING);
            i16 = F16;
            UXTHw(x1, xRAX);
            MOV32w(x2, i16);
            emit_add16(dyn, ninst, x1, x2, x3, x4);
            BFIz(xRAX, x1, 0, 16);
            break;
        case 0x06:
            INST_NAME("PUSH ES");
            LDRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_ES]));
            PUSH1_16(x1);
            break;
        case 0x07:
            INST_NAME("POP ES");
            POP1_16(x1);
            STRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_ES]));
            STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_ES]));
            break;

        case 0x09:
            INST_NAME("OR Ew, Gw");
            SETFLAGS(X_ALL, SF_SET_PENDING);
            nextop = F8;
            GETGW(x2);
            GETEW(x1, 0);
            emit_or16(dyn, ninst, x1, x2, x4, x5);
            EWBACK;
            break;
        case 0x0B:
            INST_NAME("OR Gw, Ew");
            SETFLAGS(X_ALL, SF_SET_PENDING);
            nextop = F8;
            GETGW(x1);
            GETEW(x2, 0);
            emit_or16(dyn, ninst, x1, x2, x4, x3);
            GWBACK;
            break;
        case 0x0D:
            INST_NAME("OR AX, Iw");
            SETFLAGS(X_ALL, SF_SET_PENDING);
            i16 = F16;
            UXTHw(x1, xRAX);
            emit_or16c(dyn, ninst, x1, i16, x3, x4);
            BFIz(xRAX, x1, 0, 16);
            break;

        case 0x0F:
            switch(rep) {
                case 0: addr = dynarec64_660F(dyn, addr, ip, ninst, rex, ok, need_epilog); break;
                case 1: addr = dynarec64_66F20F(dyn, addr, ip, ninst, rex, ok, need_epilog); break;
                case 2: addr = dynarec64_66F30F(dyn, addr, ip, ninst, rex, ok, need_epilog); break;
            }
            break;
        case 0x11:
            INST_NAME("ADC Ew, Gw");
            READFLAGS(X_CF);
            SETFLAGS(X_ALL, SF_SET_PENDING);
            nextop = F8;
            GETGW(x2);
            GETEW(x1, 0);
            emit_adc16(dyn, ninst, x1, x2, x4, x5);
            EWBACK;
            break;
        case 0x13:
            INST_NAME("ADC Gw, Ew");
            READFLAGS(X_CF);
            SETFLAGS(X_ALL, SF_SET_PENDING);
            nextop = F8;
            GETGW(x1);
            GETEW(x2, 0);
            emit_adc16(dyn, ninst, x1, x2, x4, x3);
            GWBACK;
            break;
        case 0x15:
            INST_NAME("ADC AX, Iw");
            READFLAGS(X_CF);
            SETFLAGS(X_ALL, SF_SET_PENDING);
            u16 = F16;
            UXTHw(x1, xRAX);
            MOV32w(x2, u16);
            emit_adc16(dyn, ninst, x1, x2, x3, x4);
            BFIz(xRAX, x1, 0, 16);
            break;

        case 0x19:
            INST_NAME("SBB Ew, Gw");
            READFLAGS(X_CF);
            SETFLAGS(X_ALL, SF_SET_PENDING);
            nextop = F8;
            GETGW(x2);
            GETEW(x1, 0);
            emit_sbb16(dyn, ninst, x1, x2, x4, x5);
            EWBACK;
            break;
        case 0x1B:
            INST_NAME("SBB Gw, Ew");
            READFLAGS(X_CF);
            SETFLAGS(X_ALL, SF_SET_PENDING);
            nextop = F8;
            GETGW(x1);
            GETEW(x2, 0);
            emit_sbb16(dyn, ninst, x1, x2, x4, x3);
            GWBACK;
            break;
        case 0x1D:
            INST_NAME("SBB AX, Iw");
            READFLAGS(X_CF);
            SETFLAGS(X_ALL, SF_SET_PENDING);
            i16 = F16S;
            UXTHw(x1, xRAX);
            MOVZw(x2, i16);
            emit_sbb16(dyn, ninst, x1, x2, x3, x4);
            BFIz(xRAX, x1, 0, 16);
            break;
        case 0x1E:
            INST_NAME("PUSH DS");
            LDRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_DS]));
            PUSH1_16(x1);
            break;
        case 0x1F:
            INST_NAME("POP DS");
            POP1_16(x1);
            STRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_DS]));
            STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_DS]));
            break;

        case 0x21:
            INST_NAME("AND Ew, Gw");
            SETFLAGS(X_ALL, SF_SET_PENDING);
            nextop = F8;
            GETGW(x2);
            GETEW(x1, 0);
            emit_and16(dyn, ninst, x1, x2, x4, x5);
            EWBACK;
            break;
        case 0x23:
            INST_NAME("AND Gw, Ew");
            SETFLAGS(X_ALL, SF_SET_PENDING);
            nextop = F8;
            GETGW(x1);
            GETEW(x2, 0);
            emit_and16(dyn, ninst, x1, x2, x3, x4);
            GWBACK;
            break;
        case 0x25:
            INST_NAME("AND AX, Iw");
            SETFLAGS(X_ALL, SF_SET_PENDING);
            i16 = F16;
            UXTHw(x1, xRAX);
            emit_and16c(dyn, ninst, x1, i16, x3, x4);
            BFIz(xRAX, x1, 0, 16);
            break;

        case 0x29:
            INST_NAME("SUB Ew, Gw");
            SETFLAGS(X_ALL, SF_SET_PENDING);
            nextop = F8;
            GETGW(x2);
            GETEW(x1, 0);
            emit_sub16(dyn, ninst, x1, x2, x4, x5);
            EWBACK;
            break;
        case 0x2B:
            INST_NAME("SUB Gw, Ew");
            SETFLAGS(X_ALL, SF_SET_PENDING);
            nextop = F8;
            GETGW(x1);
            GETEW(x2, 0);
            emit_sub16(dyn, ninst, x1, x2, x3, x4);
            GWBACK;
            break;
        case 0x2D:
            INST_NAME("SUB AX, Iw");
            SETFLAGS(X_ALL, SF_SET_PENDING);
            i16 = F16;
            UXTHw(x1, xRAX);
            MOV32w(x2, i16);
            emit_sub16(dyn, ninst, x1, x2, x3, x4);
            BFIz(xRAX, x1, 0, 16);
            break;

        case 0x31:
            INST_NAME("XOR Ew, Gw");
            SETFLAGS(X_ALL, SF_SET_PENDING);
            nextop = F8;
            GETGW(x2);
            GETEW(x1, 0);
            emit_xor16(dyn, ninst, x1, x2, x4, x5);
            EWBACK;
            break;
        case 0x33:
            INST_NAME("XOR Gw, Ew");
            SETFLAGS(X_ALL, SF_SET_PENDING);
            nextop = F8;
            GETGW(x1);
            GETEW(x2, 0);
            emit_xor16(dyn, ninst, x1, x2, x3, x4);
            GWBACK;
            break;
        case 0x35:
            INST_NAME("XOR AX, Iw");
            SETFLAGS(X_ALL, SF_SET_PENDING);
            i16 = F16;
            UXTHw(x1, xRAX);
            emit_xor16c(dyn, ninst, x1, i16, x3, x4);
            BFIz(xRAX, x1, 0, 16);
            break;

        case 0x39:
            INST_NAME("CMP Ew, Gw");
            SETFLAGS(X_ALL, SF_SET_PENDING);
            nextop = F8;
            GETGW(x2);
            GETEW(x1, 0);
            emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
            break;
        case 0x3B:
            INST_NAME("CMP Gw, Ew");
            SETFLAGS(X_ALL, SF_SET_PENDING);
            nextop = F8;
            GETGW(x1);
            GETEW(x2, 0);
            emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
            break;
        case 0x3D:
            INST_NAME("CMP AX, Iw");
            SETFLAGS(X_ALL, SF_SET_PENDING);
            u16 = F16;
            UXTHw(x1, xRAX);
            if(u16) {
                MOV32w(x2, u16);
                emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
            } else {
                emit_cmp16_0(dyn, ninst, x1, x3, x4);
            }
            break;

        case 0x40:
        case 0x41:
        case 0x42:
        case 0x43:
        case 0x44:
        case 0x45:
        case 0x46:
        case 0x47:
            INST_NAME("INC Reg16 (32bits)");
            SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
            gd = TO_NAT (opcode&7);
            UXTHw(x1, gd);
            emit_inc16(dyn, ninst, x1, x2, x3);
            BFIz(gd, x1, 0, 16);
            break;
        case 0x48:
        case 0x49:
        case 0x4A:
        case 0x4B:
        case 0x4C:
        case 0x4D:
        case 0x4E:
        case 0x4F:
            INST_NAME("DEC Reg16 (32bits)");
            SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
            gd = TO_NAT (opcode&7);
            UXTHw(x1, gd);
            emit_dec16(dyn, ninst, x1, x2, x3);
            BFIz(gd, x1, 0, 16);
            break;
        case 0x50:
        case 0x51:
        case 0x52:
        case 0x53:
        case 0x54:
        case 0x55:
        case 0x56:
        case 0x57:
            INST_NAME("PUSH reg");
            gd = TO_NAT((opcode & 0x07) + (rex.b << 3));
            if (gd==xRSP) {
                MOVw_REG(x1, xRSP);
                PUSH1_16(x1);
            } else {
                PUSH1_16(gd);
            }
            break;
        case 0x58:
        case 0x59:
        case 0x5A:
        case 0x5B:
        case 0x5C:
        case 0x5D:
        case 0x5E:
        case 0x5F:
            INST_NAME("POP reg");
            gd = TO_NAT((opcode & 0x07) + (rex.b << 3));
            POP1_16(x1);
            BFIz(gd, x1, 0, 16);
            break;
        case 0x60:
            if(rex.is32bits) {
                INST_NAME("PUSHA 16bits (32bits)");
                MOVw_REG(x1, xRSP);
                PUSH1_16(xRAX);
                PUSH1_16(xRCX);
                PUSH1_16(xRDX);
                PUSH1_16(xRBX);
                PUSH1_16(x1);
                PUSH1_16(xRBP);
                PUSH1_16(xRSI);
                PUSH1_16(xRDI);
            } else {
                DEFAULT;
            }
            break;
        case 0x61:
            if(rex.is32bits) {
                INST_NAME("POPA 16bits (32bits)");
                POP1_16(x1);
                BFIz(xRDI, x1, 0, 16);
                POP1_16(x1);
                BFIz(xRSI, x1, 0, 16);
                POP1_16(x1);
                BFIz(xRBP, x1, 0, 16);
                POP1_16(x1); // RSP ignored
                POP1_16(x1);
                BFIz(xRBX, x1, 0, 16);
                POP1_16(x1);
                BFIz(xRDX, x1, 0, 16);
                POP1_16(x1);
                BFIz(xRCX, x1, 0, 16);
                POP1_16(x1);
                BFIz(xRAX, x1, 0, 16);
            } else {
                DEFAULT;
            }
            break;

        case 0x64:
            addr = dynarec64_6664(dyn, addr, ip, ninst, rex, _FS, ok, need_epilog);
            break;
        case 0x65:
            addr = dynarec64_6664(dyn, addr, ip, ninst, rex, _GS, ok, need_epilog);
            break;
        case 0x66:
            addr = dynarec64_66(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
            break;

        case 0x68:
            INST_NAME("PUSH Iw");
            u16 = F16;
            MOV32w(x2, u16);
            PUSH1_16(x2);
            break;
        case 0x69:
        case 0x6B:
            if(opcode==0x69) {
                INST_NAME("IMUL Gw,Ew,Iw");
            } else {
                INST_NAME("IMUL Gw,Ew,Ib");
            }
            if(BOX64ENV(dynarec_safeflags)>1 && BOX64ENV(cputype)) {
                SETFLAGS(X_OF|X_CF, SF_SET);
            } else {
                SETFLAGS(X_ALL, SF_SET);
            }
            nextop = F8;
            GETSEW(x1, (opcode==0x69)?2:1);
            if(opcode==0x69) i32 = F16S; else i32 = F8S;
            MOV32w(x2, i32);
            MULw(x2, x2, x1);
            gd=x2;
            GWBACK;
            SET_DFNONE();
            IFX(X_CF|X_OF) {
                ASRw(x1, x2, 15);
                CMPSw_REG_ASR(x1, x2, 31);
                CSETw(x3, cNE);
                IFX(X_CF) {
                    BFIw(xFlags, x3, F_CF, 1);
                }
                IFX(X_OF) {
                    BFIw(xFlags, x3, F_OF, 1);
                }
            }
            IFX2(X_AF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_AF, 1);}
            IFX2(X_ZF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_ZF, 1);}
            IFX2(X_SF, && !BOX64ENV(cputype)) {
                LSRw(x3, x2, 15);
                BFIw(xFlags, x3, F_SF, 1);
            }
            IFX2(X_PF, && !BOX64ENV(cputype)) emit_pf(dyn, ninst, x2, x3);
            break;
        case 0x6A:
            INST_NAME("PUSH Ib");
            i16 = F8S;
            MOV32w(x2, (uint16_t)i16);
            PUSH1_16(x2);
            break;

        case 0x70:
        case 0x71:
        case 0x72:
        case 0x73:
        case 0x74:
        case 0x75:
        case 0x76:
        case 0x77:
        case 0x78:
        case 0x79:
        case 0x7a:
        case 0x7b:
        case 0x7c:
        case 0x7d:
        case 0x7e:
        case 0x7f:
            // just use regular conditional jump
            return dynarec64_00(dyn, addr-1, ip, ninst, rex, rep, ok, need_epilog);

        case 0x81:
        case 0x83:
            nextop = F8;
            switch((nextop>>3)&7) {
                case 0: //ADD
                    if(opcode==0x81) {INST_NAME("ADD Ew, Iw");} else {INST_NAME("ADD Ew, Ib");}
                    SETFLAGS(X_ALL, SF_SET_PENDING);
                    GETEW(x1, (opcode==0x81)?2:1);
                    if(opcode==0x81) i16 = F16S; else i16 = F8S;
                    MOVZw(x5, i16);
                    emit_add16(dyn, ninst, ed, x5, x2, x4);
                    EWBACK;
                    break;
                case 1: //OR
                    if(opcode==0x81) {INST_NAME("OR Ew, Iw");} else {INST_NAME("OR Ew, Ib");}
                    SETFLAGS(X_ALL, SF_SET_PENDING);
                    GETEW(x1, (opcode==0x81)?2:1);
                    if(opcode==0x81) i16 = F16S; else i16 = F8S;
                    emit_or16c(dyn, ninst, x1, i16, x2, x4);
                    EWBACK;
                    break;
                case 2: //ADC
                    if(opcode==0x81) {INST_NAME("ADC Ew, Iw");} else {INST_NAME("ADC Ew, Ib");}
                    READFLAGS(X_CF);
                    SETFLAGS(X_ALL, SF_SET_PENDING);
                    GETEW(x1, (opcode==0x81)?2:1);
                    if(opcode==0x81) i16 = F16S; else i16 = F8S;
                    MOVZw(x5, (uint16_t)i16);
                    emit_adc16(dyn, ninst, x1, x5, x2, x4);
                    EWBACK;
                    break;
                case 3: //SBB
                    if(opcode==0x81) {INST_NAME("SBB Ew, Iw");} else {INST_NAME("SBB Ew, Ib");}
                    READFLAGS(X_CF);
                    SETFLAGS(X_ALL, SF_SET_PENDING);
                    GETEW(x1, (opcode==0x81)?2:1);
                    if(opcode==0x81) i16 = F16S; else i16 = F8S;
                    MOVZw(x5, (uint16_t)i16);
                    emit_sbb16(dyn, ninst, x1, x5, x2, x4);
                    EWBACK;
                    break;
                case 4: //AND
                    if(opcode==0x81) {INST_NAME("AND Ew, Iw");} else {INST_NAME("AND Ew, Ib");}
                    SETFLAGS(X_ALL, SF_SET_PENDING);
                    GETEW(x1, (opcode==0x81)?2:1);
                    if(opcode==0x81) i16 = F16S; else i16 = F8S;
                    emit_and16c(dyn, ninst, x1, i16, x2, x4);
                    EWBACK;
                    break;
                case 5: //SUB
                    if(opcode==0x81) {INST_NAME("SUB Ew, Iw");} else {INST_NAME("SUB Ew, Ib");}
                    SETFLAGS(X_ALL, SF_SET_PENDING);
                    GETEW(x1, (opcode==0x81)?2:1);
                    if(opcode==0x81) i16 = F16S; else i16 = F8S;
                    MOVZw(x5, i16);
                    emit_sub16(dyn, ninst, x1, x5, x2, x4);
                    EWBACK;
                    break;
                case 6: //XOR
                    if(opcode==0x81) {INST_NAME("XOR Ew, Iw");} else {INST_NAME("XOR Ew, Ib");}
                    SETFLAGS(X_ALL, SF_SET_PENDING);
                    GETEW(x1, (opcode==0x81)?2:1);
                    if(opcode==0x81) i16 = F16S; else i16 = F8S;
                    emit_xor16c(dyn, ninst, x1, i16, x2, x4);
                    EWBACK;
                    break;
                case 7: //CMP
                    if(opcode==0x81) {INST_NAME("CMP Ew, Iw");} else {INST_NAME("CMP Ew, Ib");}
                    SETFLAGS(X_ALL, SF_SET_PENDING);
                    GETEW(x1, (opcode==0x81)?2:1);
                    if(opcode==0x81) i16 = F16S; else i16 = F8S;
                    if(i16) {
                        MOVZw(x2, i16);
                        emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
                    } else
                        emit_cmp16_0(dyn, ninst, x1, x3, x4);
                    break;
            }
            break;

        case 0x85:
            INST_NAME("TEST Ew, Gw");
            SETFLAGS(X_ALL, SF_SET_PENDING);
            nextop = F8;
            GETEW(x1, 0);
            GETGW(x2);
            emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
            break;

        case 0x87:
            INST_NAME("(LOCK)XCHG Ew, Gw");
            nextop = F8;
            if(MODREG) {
                GETGD;
                GETED(0);
                MOVxw_REG(x1, gd);
                BFIz(gd, ed, 0, 16);
                BFIz(ed, x1, 0, 16);
            } else {
                GETGD;
                addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
                if(!ALIGNED_ATOMICH) {
                    TBNZ_MARK(ed, 0);
                }
                if(arm64_atomics) {
                    SWPALH(gd, x1, ed);
                    SMDMB();
                    if(!ALIGNED_ATOMICH) {
                        B_MARK2_nocond;
                    }
                } else {
                    MARKLOCK;
                    LDAXRH(x1, ed);
                    STLXRH(x3, gd, ed);
                    CBNZx_MARKLOCK(x3);
                    SMDMB();
                    if(!ALIGNED_ATOMICH) {
                        B_MARK2_nocond;
                    }
                }
                if(!ALIGNED_ATOMICH) {
                    MARK;
                    LDRH_U12(x1, ed, 0);
                    LDAXRB(x3, ed);
                    STLXRB(x3, gd, ed);
                    CBNZx_MARK(x3);
                    STRH_U12(gd, ed, 0);
                    SMDMB();
                    MARK2;
                }
                BFIz(gd, x1, 0, 16);
            }
            break;

        case 0x89:
            INST_NAME("MOV Ew, Gw");
            nextop = F8;
            GETGD;  // don't need GETGW here
            if(MODREG) {
                ed = TO_NAT((nextop & 7) + (rex.b << 3));
                if(ed!=gd) {
                    BFIz(ed, gd, 0, 16);
                }
            } else {
                addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, &lock, 0, 0);
                STH(gd, ed, fixedaddress);
                SMWRITELOCK(lock);
            }
            break;
        case 0x8B:
            INST_NAME("MOV Gw, Ew");
            nextop = F8;
            GETGD;  // don't need GETGW neither
            if(MODREG) {
                ed = TO_NAT((nextop & 7) + (rex.b << 3));
                if(ed!=gd) {
                    BFIz(gd, ed, 0, 16);
                }
            } else {
                addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, &lock, 0, 0);
                SMREADLOCK(lock);
                LDH(x1, ed, fixedaddress);
                BFIz(gd, x1, 0, 16);
            }
            break;
        case 0x8C:
            INST_NAME("MOV EW, Seg");
            nextop=F8;
            u8 = (nextop&0x38)>>3;
            LDRH_U12(x3, xEmu, offsetof(x64emu_t, segs[u8]));
            if (MODREG) {
                BFIz(TO_NAT((nextop & 7) + (rex.b << 3)), x3, 0, 16);
            } else {
                addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
                STH(x3, wback, fixedaddress);
                SMWRITE2();
            }
            break;

        case 0x8E:
            INST_NAME("MOV Seg,Ew");
            nextop = F8;
            u8 = (nextop&0x38)>>3;
            if (MODREG) {
                ed = TO_NAT((nextop & 7) + (rex.b << 3));
            } else {
                SMREAD();
                addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
                LDH(x1, wback, fixedaddress);
                ed = x1;
            }
            STRH_U12(ed, xEmu, offsetof(x64emu_t, segs[u8]));
            STRw_U12(wZR, xEmu, offsetof(x64emu_t, segs_serial[u8]));
            break;
        case 0x8F:
            INST_NAME("POP Ew");
            nextop = F8;
            POP1_16(x1);
            if (MODREG) {
                wback = TO_NAT((nextop & 7) + (rex.b << 3));
                BFIz(wback, x1, 0, 16);
            } else {
                SMREAD();
                addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
                STH(x1, wback, fixedaddress);
            }
            break;
        case 0x90:
        case 0x91:
        case 0x92:
        case 0x93:
        case 0x94:
        case 0x95:
        case 0x96:
        case 0x97:
            gd = TO_NAT((opcode & 0x07) + (rex.b << 3));
            if(gd==xRAX) {
                INST_NAME("NOP");
            } else {
                INST_NAME("XCHG AX, Reg");
                MOVw_REG(x2, xRAX);
                BFIz(xRAX, gd, 0, 16);
                BFIz(gd, x2, 0, 16);
            }
            break;
        case 0x98:
            INST_NAME("CBW");
            SXTBw(x1, xRAX);
            BFIz(xRAX, x1, 0, 16);
            break;
        case 0x99:
            INST_NAME("CWD");
            SXTHw(x1, xRAX);    // sign extend ax to x1
            BFXILx(xRDX, x1, 16, 16);   // insert high 16bits of x1 as low DX
            break;
        case 0x9C:
            INST_NAME("PUSHF");
            READFLAGS(X_ALL);
            PUSH1_16(xFlags);
            SMWRITE();
            break;
        case 0x9D:
            INST_NAME("POPF");
            SETFLAGS(X_ALL, SF_SET);
            SMREAD();
            POP1_16(x1);
            MOV32w(x2, 0x7FD7);
            ANDw_REG(x1, x1, x2);
            ORRw_mask(x1, x1, 0b011111, 0);   //mask=0x00000002
            BFIw(xFlags, x1, 0, 16);
            SET_DFNONE();
            if(box64_wine) {    // should this be done all the time?
                TBZ_NEXT(xFlags, F_TF);
                // go to epilog, TF should trigger at end of next opcode, so using Interpreter only
                jump_to_epilog(dyn, addr, 0, ninst);
            }
            break;

        case 0xA1:
            INST_NAME("MOV AX,Od");
            if(rex.is32bits)
                u64 = F32;
            else
                u64 = F64;
            MOV64z(x1, u64);
            if(isLockAddress(u64)) lock=1; else lock = 0;
            SMREADLOCK(lock);
            LDRH_U12(x2, x1, 0);
            BFIz(xRAX, x2, 0, 16);
            break;

        case 0xA3:
            INST_NAME("MOV Od,AX");
            if(rex.is32bits)
                u64 = F32;
            else
                u64 = F64;
            MOV64z(x1, u64);
            lock = isLockAddress(u64);
            STRH_U12(xRAX, x1, 0);
            SMWRITELOCK(lock);
            break;
        case 0xA4:
            SMREAD();
            if(rep) {
                INST_NAME("REP MOVSB");
                CBZx_NEXT(xRCX);
                TBNZ_MARK2(xFlags, F_DF);
                IF_UNALIGNED(ip) {
                    // special optim for large RCX value on forward case only
                    // but because it's unaligned path, check if a byte per byt is needed, and do 4-bytes per 4-bytes only instead
                    if(BOX64DRENV(dynarec_safeflags)) {
                        SUBx_REG(x2, xRDI, xRSI);
                        CMPSx_U12(x2, 4);
                        B_MARK(cCC);
                    }
                    ORRw_REG(x1, xRSI, xRDI);
                    ANDw_mask(x1, x1, 0, 1);    //mask = 3
                    CBNZw_MARK(x1);
                    MARK3;
                    CMPSx_U12(xRCX, 4);
                    B_MARK(cCC);
                    LDRw_S9_postindex(x1, xRSI, 4);
                    STRw_S9_postindex(x1, xRDI, 4);
                    SUBx_U12(xRCX, xRCX, 4);
                    CBNZx_MARK3(xRCX);
                    CBZx_MARKLOCK(xRCX);
                } else {
                    if(BOX64DRENV(dynarec_safeflags)) {
                        SUBx_REG(x2, xRDI, xRSI);
                        CMPSx_U12(x2, 8);
                        B_MARK(cCC);
                    }
                    // special optim for large RCX value on forward case only
                    MARK3;
                    CMPSx_U12(xRCX, 8);
                    B_MARK(cCC);
                    LDRx_S9_postindex(x1, xRSI, 8);
                    STRx_S9_postindex(x1, xRDI, 8);
                    SUBx_U12(xRCX, xRCX, 8);
                    CBNZx_MARK3(xRCX);
                    CBZx_MARKLOCK(xRCX);
                }
                MARK;   // Part with DF==0
                LDRB_S9_postindex(x1, xRSI, 1);
                STRB_S9_postindex(x1, xRDI, 1);
                SUBx_U12(xRCX, xRCX, 1);
                CBNZx_MARK(xRCX);
                B_MARKLOCK_nocond;
                MARK2;  // Part with DF==1
                LDRB_S9_postindex(x1, xRSI, -1);
                STRB_S9_postindex(x1, xRDI, -1);
                SUBx_U12(xRCX, xRCX, 1);
                CBNZx_MARK2(xRCX);
                MARKLOCK;
                // done
            } else {
                INST_NAME("MOVSB");
                GETDIR(x3, 1);
                LDRB_U12(x1, xRSI, 0);
                STRB_U12(x1, xRDI, 0);
                ADDx_REG(xRSI, xRSI, x3);
                ADDx_REG(xRDI, xRDI, x3);
            }
            SMWRITE();
            break;
        case 0xA5:
            SMREAD();
            if(rep) {
                INST_NAME("REP MOVSW");
                CBZx_NEXT(xRCX);
                TBNZ_MARK2(xFlags, F_DF);
                MARK;   // Part with DF==0
                LDRH_S9_postindex(x1, xRSI, 2);
                STRH_S9_postindex(x1, xRDI, 2);
                SUBx_U12(xRCX, xRCX, 1);
                CBNZx_MARK(xRCX);
                B_NEXT_nocond;
                MARK2;  // Part with DF==1
                LDRH_S9_postindex(x1, xRSI, -2);
                STRH_S9_postindex(x1, xRDI, -2);
                SUBx_U12(xRCX, xRCX, 1);
                CBNZx_MARK2(xRCX);
                // done
            } else {
                INST_NAME("MOVSW");
                GETDIR(x3, 2);
                LDRH_U12(x1, xRSI, 0);
                STRH_U12(x1, xRDI, 0);
                ADDx_REG(xRSI, xRSI, x3);
                ADDx_REG(xRDI, xRDI, x3);
            }
            SMWRITE();
            break;

        case 0xA7:
            SMREAD();
            switch(rep) {
            case 1:
            case 2:
                if(rep==1) {INST_NAME("REPNZ CMPSW");} else {INST_NAME("REPZ CMPSW");}
                if(BOX64DRENV(dynarec_safeflags)>1) {
                    READFLAGS(X_ALL);
                    SETFLAGS(X_ALL, SF_SET);
                } else
                    SETFLAGS(X_ALL, SF_SET_PENDING);
                CBZx_NEXT(xRCX);
                TBNZ_MARK2(xFlags, F_DF);
                MARK;   // Part with DF==0
                LDRH_S9_postindex(x1, xRSI, 2);
                LDRH_S9_postindex(x2, xRDI, 2);
                SUBx_U12(xRCX, xRCX, 1);
                CMPSw_REG(x1, x2);
                B_MARK3((rep==1)?cEQ:cNE);
                CBNZx_MARK(xRCX);
                B_MARK3_nocond;
                MARK2;  // Part with DF==1
                LDRH_S9_postindex(x1, xRSI, -2);
                LDRH_S9_postindex(x2, xRDI, -2);
                SUBx_U12(xRCX, xRCX, 1);
                CMPSw_REG(x1, x2);
                B_MARK3((rep==1)?cEQ:cNE);
                CBNZx_MARK2(xRCX);
                MARK3;  // end
                emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
                break;
            default:
                INST_NAME("CMPSW");
                SETFLAGS(X_ALL, SF_SET_PENDING);
                GETDIR(x3, 2);
                LDRH_U12(x1, xRSI, 0);
                LDRH_U12(x2, xRDI, 0);
                ADDx_REG(xRSI, xRSI, x3);
                ADDx_REG(xRDI, xRDI, x3);
                emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
                break;
            }
            break;

        case 0xA9:
            INST_NAME("TEST AX,Iw");
            SETFLAGS(X_ALL, SF_SET_PENDING);
            u16 = F16;
            UBFXx(x1, xRAX, 0, 16);
            emit_test16c(dyn, ninst, x1, u16, x3, x4, x5);
            break;

        case 0xAB:
            if(rep) {
                INST_NAME("REP STOSW");
                CBZx_NEXT(xRCX);
                TBNZ_MARK2(xFlags, F_DF);
                MARK;   // Part with DF==0
                STRH_S9_postindex(xRAX, xRDI, 2);
                SUBx_U12(xRCX, xRCX, 1);
                CBNZx_MARK(xRCX);
                B_MARK3_nocond;
                MARK2;  // Part with DF==1
                STRH_S9_postindex(xRAX, xRDI, -2);
                SUBx_U12(xRCX, xRCX, 1);
                CBNZx_MARK2(xRCX);
                MARK3;
                // done
            } else {
                INST_NAME("STOSW");
                GETDIR(x3, 2);
                STRH_U12(xRAX, xRDI, 0);
                ADDx_REG(xRDI, xRDI, x3);
            }
            SMWRITE();
            break;

        case 0xAD:
            if(rep) {
                INST_NAME("REP LODSW");
                CBZx_NEXT(xRCX);
                TBNZ_MARK2(xFlags, F_DF);
                MARK;   // Part with DF==0
                LDRH_S9_postindex(x2, xRSI, 2);
                SUBx_U12(xRCX, xRCX, 1);
                CBNZx_MARK(xRCX);
                B_MARK3_nocond;
                MARK2;  // Part with DF==1
                LDRH_S9_postindex(x2, xRSI, -2);
                SUBx_U12(xRCX, xRCX, 1);
                CBNZx_MARK2(xRCX);
                MARK3;
                BFIz(xRAX, x2, 0, 16);
                // done
            } else {
                INST_NAME("LODSW");
                GETDIR(x3, 2);
                LDRH_U12(x2, xRSI, 0);
                ADDx_REG(xRSI, xRSI, x3);
                BFIz(xRAX, x2, 0, 16);
            }
            break;

        case 0xAF:
            switch(rep) {
            case 1:
            case 2:
                if(rep==1) {INST_NAME("REPNZ SCASW");} else {INST_NAME("REPZ SCASW");}
                if(BOX64DRENV(dynarec_safeflags)>1) {
                    READFLAGS(X_ALL);
                    SETFLAGS(X_ALL, SF_SET);
                } else
                    SETFLAGS(X_ALL, SF_SET_PENDING);
                CBZx_NEXT(xRCX);
                UXTHw(x1, xRAX);
                TBNZ_MARK2(xFlags, F_DF);
                MARK;   // Part with DF==0
                LDRH_S9_postindex(x2, xRDI, 2);
                SUBx_U12(xRCX, xRCX, 1);
                CMPSw_REG(x1, x2);
                B_MARK3((rep==1)?cEQ:cNE);
                CBNZx_MARK(xRCX);
                B_MARK3_nocond;
                MARK2;  // Part with DF==1
                LDRH_S9_postindex(x2, xRDI, -2);
                SUBx_U12(xRCX, xRCX, 1);
                CMPSw_REG(x1, x2);
                B_MARK3((rep==1)?cEQ:cNE);
                CBNZx_MARK2(xRCX);
                MARK3;  // end
                emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
                break;
            default:
                INST_NAME("SCASW");
                SETFLAGS(X_ALL, SF_SET_PENDING);
                GETDIR(x3, 2);
                UXTHw(x1, xRAX);
                LDRH_U12(x2, xRDI, 0);
                ADDx_REG(xRDI, xRDI, x3);
                emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
                break;
            }
            break;

        case 0xB8:
        case 0xB9:
        case 0xBA:
        case 0xBB:
        case 0xBC:
        case 0xBD:
        case 0xBE:
        case 0xBF:
            INST_NAME("MOV Reg16, Iw");
            u16 = F16;
            gd = TO_NAT((opcode & 7) + (rex.b << 3));
            if(u16) {
                MOV32w(x1, u16);
                BFIz(gd, x1, 0, 16);
            } else
                BFCz(gd, 0, 16);
            break;

        case 0xC1:
            nextop = F8;
            switch((nextop>>3)&7) {
                case 0:
                    INST_NAME("ROL Ew, Ib");
                    u8 = geted_ib(dyn, addr, ninst, nextop) & 0x1f;
                    if (u8) {
                        SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
                        GETEW(x1, 1);
                        u8 = (F8)&0x1f;
                        emit_rol16c(dyn, ninst, x1, u8, x4, x5);
                        EWBACK;
                    } else {
                        FAKEED;
                        F8;
                    }
                    break;
                case 1:
                    INST_NAME("ROR Ew, Ib");
                    if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
                        SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
                        GETEW(x1, 1);
                        u8 = (F8)&0x1f;
                        emit_ror16c(dyn, ninst, x1, u8, x4, x5);
                        EWBACK;
                    } else {
                        FAKEED;
                        F8;
                    }
                    break;
                case 2:
                    INST_NAME("RCL Ew, Ib");
                    if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
                        READFLAGS(X_CF);
                        SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
                        GETEW(x1, 1);
                        u8 = (F8)&0x1f;
                        emit_rcl16c(dyn, ninst, ed, u8, x4, x5);
                        EWBACK;
                    } else {
                        FAKEED;
                        F8;
                    }
                    break;
                case 3:
                    INST_NAME("RCR Ew, Ib");
                    if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
                        READFLAGS(X_CF);
                        SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
                        GETEW(x1, 1);
                        u8 = (F8)&0x1f;
                        emit_rcr16c(dyn, ninst, ed, u8, x4, x5);
                        EWBACK;
                    } else {
                        FAKEED;
                        F8;
                    }
                    break;
                case 4:
                case 6:
                    INST_NAME("SHL Ew, Ib");
                    if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
                        SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
                        GETEW(x1, 0);
                        u8 = (F8)&0x1f;
                        emit_shl16c(dyn, ninst, x1, u8, x5, x4);
                        EWBACK;
                    } else {
                        FAKEED;
                        F8;
                    }
                    break;
                case 5:
                    INST_NAME("SHR Ew, Ib");
                    if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
                        SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
                        GETEW(x1, 0);
                        u8 = (F8)&0x1f;
                        emit_shr16c(dyn, ninst, x1, u8, x5, x4);
                        EWBACK;
                    } else {
                        FAKEED;
                        F8;
                    }
                    break;
                case 7:
                    INST_NAME("SAR Ew, Ib");
                    if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
                        SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
                        GETSEW(x1, 0);
                        u8 = (F8)&0x1f;
                        emit_sar16c(dyn, ninst, x1, u8, x5, x4);
                        EWBACK;
                    } else {
                        FAKEED;
                        F8;
                    }
                    break;
            }
            break;

        case 0xC7:
            INST_NAME("MOV Ew, Iw");
            nextop = F8;
            if(MODREG) {
                ed = TO_NAT((nextop & 7) + (rex.b << 3));
                u16 = F16;
                if(u16) {
                    MOV32w(x1, u16);
                    BFIz(ed, x1, 0, 16);
                } else
                    BFCz(ed, 0, 16);
            } else {
                addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, &lock, 0, 2);
                u16 = F16;
                if(u16) {
                    MOV32w(x1, u16);
                    STH(x1, ed, fixedaddress);
                } else {
                    STH(xZR, ed, fixedaddress);
                }
                SMWRITELOCK(lock);
            }
            break;

        case 0xD1:
            nextop = F8;
            switch((nextop>>3)&7) {
                case 0:
                    INST_NAME("ROL Ew, 1");
                    SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
                    GETEW(x1, 0);
                    emit_rol16c(dyn, ninst, x1, 1, x5, x4);
                    EWBACK;
                    break;
                case 1:
                    INST_NAME("ROR Ew, 1");
                    SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
                    GETEW(x1, 0);
                    emit_ror16c(dyn, ninst, x1, 1, x5, x4);
                    EWBACK;
                    break;
                case 2:
                    INST_NAME("RCL Ew, 1");
                    READFLAGS(X_CF);
                    SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
                    GETEW(x1, 0);
                    emit_rcl16c(dyn, ninst, x1, 1, x5, x4);
                    EWBACK;
                    break;
                case 3:
                    INST_NAME("RCR Ew, 1");
                    READFLAGS(X_CF);
                    SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
                    GETEW(x1, 0);
                    emit_rcr16c(dyn, ninst, x1, 1, x5, x4);
                    EWBACK;
                    break;
                case 4:
                case 6:
                    INST_NAME("SHL Ew, 1");
                    SETFLAGS(X_ALL, SF_SET_PENDING);    // some flags are left undefined
                    GETEW(x1, 0);
                    emit_shl16c(dyn, ninst, x1, 1, x5, x4);
                    EWBACK;
                    break;
                case 5:
                    INST_NAME("SHR Ew, 1");
                    SETFLAGS(X_ALL, SF_SET_PENDING);    // some flags are left undefined
                    GETEW(x1, 0);
                    emit_shr16c(dyn, ninst, x1, 1, x5, x4);
                    EWBACK;
                    break;
                case 7:
                    INST_NAME("SAR Ew, 1");
                    SETFLAGS(X_ALL, SF_SET_PENDING);    // some flags are left undefined
                    GETSEW(x1, 0);
                    emit_sar16c(dyn, ninst, x1, 1, x5, x4);
                    EWBACK;
                    break;
            }
            break;

        case 0xD3:
            nextop = F8;
            switch((nextop>>3)&7) {
                case 0:
                    INST_NAME("ROL Ew, CL");
                    if(BOX64DRENV(dynarec_safeflags)>1) {
                        READFLAGS(X_OF|X_CF);
                    }
                    SETFLAGS(X_OF|X_CF, SF_SUBSET);
                    UFLAG_IF {
                        ANDw_mask(x2, xRCX, 0, 0b00100);  //mask=0x00000001f
                        CBZw_NEXT(x2);
                    }
                    ANDw_mask(x2, xRCX, 0, 0b00011);  //mask=0x00000000f
                    MOV32w(x4, 16);
                    SUBx_REG(x2, x4, x2);
                    GETEW(x1, 0);
                    IFX2(X_OF, && !BOX64ENV(cputype)) {
                        LSRw(x4, ed, 14);
                        EORw_REG_LSR(x4, x4, x4, 1);
                        BFIw(xFlags, x4, F_OF, 1);
                    }
                    ORRw_REG_LSL(ed, ed, ed, 16);
                    LSRw_REG(ed, ed, x2);
                    EWBACK;
                    IFX2(X_OF, && BOX64ENV(cputype)) {
                        EORxw_REG_LSR(x3, ed, ed, 15);
                        BFIw(xFlags, x3, F_OF, 1);
                    }
                    IFX(X_CF) {
                        BFIw(xFlags, ed, F_CF, 1);
                    }
                    break;
                case 1:
                    INST_NAME("ROR Ew, CL");
                    if(BOX64DRENV(dynarec_safeflags)>1) {
                        READFLAGS(X_OF|X_CF);
                    }
                    SETFLAGS(X_OF|X_CF, SF_SUBSET);
                    UFLAG_IF {
                        ANDw_mask(x2, xRCX, 0, 0b00100);  //mask=0x00000001f
                        CBZw_NEXT(x2);
                    }
                    ANDw_mask(x2, xRCX, 0, 0b00011);  //mask=0x00000000f
                    GETEW(x1, 0);
                    IFX2(X_OF, && !BOX64ENV(cputype)) {
                        EORw_REG_LSR(x4, ed, ed, 15);
                        BFIw(xFlags, x4, F_OF, 1);
                    }
                    ORRw_REG_LSL(ed, ed, ed, 16);
                    LSRw_REG(ed, ed, x2);
                    EWBACK;
                    IFX2(X_OF, && BOX64ENV(cputype)) {
                        LSRxw(x2, ed, 14); // x2 = d>>6
                        EORw_REG_LSR(x2, x2, x2, 1); // x2 = ((d>>14) ^ ((d>>14)>>1))
                        BFIw(xFlags, x2, F_OF, 1);
                    }
                    IFX(X_CF) {
                        BFXILw(xFlags, ed, 15, 1);
                    }
                    break;
                case 2:
                    INST_NAME("RCL Ew, CL");
                    MESSAGE(LOG_DUMP, "Need Optimization (RCL Ex, CL)\n");
                    if(BOX64DRENV(dynarec_safeflags)>1) {
                        READFLAGS(X_OF|X_CF);
                    } else {
                        READFLAGS(X_CF);
                    }
                    SETFLAGS(X_OF|X_CF, SF_SET_DF);
                    ANDw_mask(x2, xRCX, 0, 0b00100);
                    GETEW(x1, 0);
                    CALL_(rcl16, x1, x3);
                    EWBACK;
                    break;
                case 3:
                    INST_NAME("RCR Ew, CL");
                    MESSAGE(LOG_DUMP, "Need Optimization (RCR Ew, CL)\n");
                    if(BOX64DRENV(dynarec_safeflags)>1) {
                        READFLAGS(X_OF|X_CF);
                    } else {
                        READFLAGS(X_CF);
                    }
                    SETFLAGS(X_OF|X_CF, SF_SET_DF);
                    ANDw_mask(x2, xRCX, 0, 0b00100);
                    GETEW(x1, 0);
                    CALL_(rcr16, x1, x3);
                    EWBACK;
                    break;
                case 4:
                case 6:
                    INST_NAME("SHL Ew, CL");
                    if(BOX64DRENV(dynarec_safeflags)>1) {
                        READFLAGS(X_ALL);
                        SETFLAGS(X_ALL, SF_SET);
                    } else
                        SETFLAGS(X_ALL, SF_SET_PENDING);
                    ANDw_mask(x2, xRCX, 0, 0b00100);  //mask=0x00000001f
                    UFLAG_IF {
                        CBZw_NEXT(x2);
                    }
                    GETEW(x1, 0);
                    emit_shl16(dyn, ninst, x1, x2, x5, x4);
                    EWBACK;
                    break;
                case 5:
                    INST_NAME("SHR Ew, CL");
                    if(BOX64DRENV(dynarec_safeflags)>1) {
                        READFLAGS(X_ALL);
                        SETFLAGS(X_ALL, SF_SET);
                    } else
                        SETFLAGS(X_ALL, SF_SET_PENDING);
                    ANDw_mask(x2, xRCX, 0, 0b00100);  //mask=0x00000001f
                    UFLAG_IF {
                        CBZw_NEXT(x2);
                    }
                    GETEW(x1, 0);
                    emit_shr16(dyn, ninst, x1, x2, x5, x4);
                    EWBACK;
                    break;
                case 7:
                    INST_NAME("SAR Ew, CL");
                    if(BOX64DRENV(dynarec_safeflags)>1) {
                        READFLAGS(X_ALL);
                        SETFLAGS(X_ALL, SF_SET);
                    } else
                        SETFLAGS(X_ALL, SF_SET_PENDING);
                    ANDw_mask(x2, xRCX, 0, 0b00100);  //mask=0x00000001f
                    UFLAG_IF {
                        CBZw_NEXT(x2);
                    } else {
                    }
                    GETSEW(x1, 0);
                    emit_sar16(dyn, ninst, x1, x2, x5, x4);
                    EWBACK;
                    break;
            }
            break;

        case 0xD9:
            nextop = F8;
            if(MODREG) {
                DEFAULT;
            } else
                switch((nextop>>3)&7) {
                    case 6:
                        INST_NAME("FNSTENV Ed");
                        MESSAGE(LOG_DUMP, "Need Optimization (FNSTENV16)\n");
                        fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
                        addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
                        if(ed!=x1) {MOVx_REG(x1, ed);}
                        MOV32w(x2, 1);
                        CALL(fpu_savenv, -1);
                        break;
                    default:
                        DEFAULT;
            }
            break;

        case 0xDD:
            nextop = F8;
            if(MODREG) {
                DEFAULT;
            } else
                switch((nextop>>3)&7) {
                    case 4:
                        INST_NAME("FRSTOR Ed");
                        MESSAGE(LOG_DUMP, "Need Optimization (FRSTOR16)\n");
                        fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
                        addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
                        if(ed!=x1) {MOVx_REG(x1, ed);}
                        CALL(native_frstor16, -1);
                        break;
                    case 6:
                        INST_NAME("FNSAVE Ed");
                        MESSAGE(LOG_DUMP, "Need Optimization (FNSAVE16)\n");
                        fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
                        addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
                        if(ed!=x1) {MOVx_REG(x1, ed);}
                        CALL(native_fsave16, -1);
                        CALL(reset_fpu, -1);
                        break;
                    default:
                        DEFAULT;
            }
            break;

        case 0xF0:
            return dynarec64_66F0(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);

        case 0xF7:
            nextop = F8;
            switch((nextop>>3)&7) {
                case 0:
                case 1:
                    INST_NAME("TEST Ew, Iw");
                    SETFLAGS(X_ALL, SF_SET_PENDING);
                    GETEW(x1, 2);
                    u16 = F16;
                    emit_test16c(dyn, ninst, x1, u16, x3, x4, x5);
                    break;
                case 2:
                    INST_NAME("NOT Ew");
                    if(MODREG) {
                        CALCEW();
                        int mask = convert_bitmask_x(0xffff);
                        EORx_mask(wback, wback, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
                    } else {
                        GETEW(x1, 0);
                        MVNw_REG(ed, ed);
                        EWBACK;
                    }
                    break;
                case 3:
                    INST_NAME("NEG Ew");
                    SETFLAGS(X_ALL, SF_SET_PENDING);
                    GETEW(x1, 0);
                    emit_neg16(dyn, ninst, ed, x2, x4);
                    EWBACK;
                    break;
                case 4:
                    INST_NAME("MUL AX, Ew");
                    if(BOX64ENV(dynarec_safeflags) && BOX64ENV(cputype)) {
                        SETFLAGS(X_OF|X_CF, SF_SET);
                    } else {
                        SETFLAGS(X_ALL, SF_SET);
                    }
                    GETEW(x1, 0);
                    UXTHw(x2, xRAX);
                    MULw(x1, x2, x1);
                    BFIz(xRAX, x1, 0, 16);
                    BFXILx(xRDX, x1, 16, 16);
                    SET_DFNONE();
                    IFX(X_CF|X_OF) {
                        CMPSw_REG_LSR(xZR, x1, 16);
                        CSETw(x3, cNE);
                        IFX(X_CF) {
                            BFIw(xFlags, x3, F_CF, 1);
                        }
                        IFX(X_OF) {
                            BFIw(xFlags, x3, F_OF, 1);
                        }
                    }
                    IFX2(X_AF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_AF, 1);}
                    IFX2(X_ZF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_ZF, 1);}
                    IFX2(X_SF, && !BOX64ENV(cputype)) {
                        LSRxw(x3, xRAX, 15);
                        BFIw(xFlags, x3, F_SF, 1);
                    }
                    IFX2(X_PF, && !BOX64ENV(cputype)) emit_pf(dyn, ninst, xRAX, x3);
                    break;
                case 5:
                    INST_NAME("IMUL AX, Ew");
                    if(BOX64ENV(dynarec_safeflags) && BOX64ENV(cputype)) {
                        SETFLAGS(X_OF|X_CF, SF_SET);
                    } else {
                        SETFLAGS(X_ALL, SF_SET);
                    }
                    GETSEW(x1, 0);
                    SXTHw(x2, xRAX);
                    MULw(x1, x2, x1);
                    BFIz(xRAX, x1, 0, 16);
                    BFXILx(xRDX, x1, 16, 16);
                    SET_DFNONE();
                    IFX(X_CF|X_OF) {
                        ASRw(x2, x1, 15);
                        CMPSw_REG_ASR(x2, x1, 31);
                        CSETw(x3, cNE);
                        IFX(X_CF) {
                            BFIw(xFlags, x3, F_CF, 1);
                        }
                        IFX(X_OF) {
                            BFIw(xFlags, x3, F_OF, 1);
                        }
                    }
                    IFX2(X_AF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_AF, 1);}
                    IFX2(X_ZF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_ZF, 1);}
                    IFX2(X_SF, && !BOX64ENV(cputype)) {
                        LSRxw(x3, xRAX, 15);
                        BFIw(xFlags, x3, F_SF, 1);
                    }
                    IFX2(X_PF, && !BOX64ENV(cputype)) emit_pf(dyn, ninst, xRAX, x3);
                    break;
                case 6:
                    INST_NAME("DIV Ew");
                    SETFLAGS(X_ALL, SF_SET);
                    GETEW(x1, 0);
                    UXTHw(x2, xRAX);
                    BFIw(x2, xRDX, 16, 16);
                    if(BOX64ENV(dynarec_div0)) {
                        CBNZw_MARK3(ed);
                        GETIP_(ip);
                        STORE_XEMU_CALL(xRIP);
                        CALL(native_div0, -1);
                        CLEARIP();
                        LOAD_XEMU_CALL(xRIP);
                        jump_to_epilog(dyn, 0, xRIP, ninst);
                        MARK3;
                    }
                    UDIVw(x3, x2, ed);
                    MSUBw(x4, x3, ed, x2);  // x4 = x2 mod ed (i.e. x2 - x3*ed)
                    BFIz(xRAX, x3, 0, 16);
                    BFIz(xRDX, x4, 0, 16);
                    SET_DFNONE();
                    IFX(X_OF)                         {BFCw(xFlags, F_OF, 1);}
                    IFX(X_CF)                         {BFCw(xFlags, F_CF, 1);}
                    IFX2(X_AF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_AF, 1);}
                    IFX2(X_AF, && BOX64ENV(cputype))  {ORRw_mask(xFlags, xFlags, 28, 0);}   //mask=0x10
                    IFX2(X_ZF, && !BOX64ENV(cputype)) {ORRw_mask(xFlags, xFlags, 26, 0);}   //mask=0x40
                    IFX2(X_ZF, && BOX64ENV(cputype))  {BFCw(xFlags, F_ZF, 1);}
                    IFX(X_SF)                         {BFCw(xFlags, F_SF, 1);}
                    IFX2(X_PF, && !BOX64ENV(cputype)) {ORRw_mask(xFlags, xFlags, 30, 0);}   //mask=0x04
                    IFX2(X_PF, && BOX64ENV(cputype))  {BFCw(xFlags, F_PF, 1);}
                    break;
                case 7:
                    INST_NAME("IDIV Ew");
                    SKIPTEST(x1);
                    if(!BOX64ENV(dynarec_safeflags)) {
                        SETFLAGS(X_ALL, SF_SET);
                    } else if(BOX64ENV(cputype)) {
                        SETFLAGS(X_SF|X_PF|X_ZF|X_AF, SF_SET);
                    }
                    GETSEW(x1, 0);
                    if(BOX64ENV(dynarec_div0)) {
                        CBNZw_MARK3(ed);
                        GETIP_(ip);
                        STORE_XEMU_CALL(xRIP);
                        CALL(native_div0, -1);
                        CLEARIP();
                        LOAD_XEMU_CALL(xRIP);
                        jump_to_epilog(dyn, 0, xRIP, ninst);
                        MARK3;
                    }
                    UXTHw(x2, xRAX);
                    BFIw(x2, xRDX, 16, 16);
                    SDIVw(x3, x2, ed);
                    MSUBw(x4, x3, ed, x2);  // x4 = x2 mod ed (i.e. x2 - x3*ed)
                    BFIz(xRAX, x3, 0, 16);
                    BFIz(xRDX, x4, 0, 16);
                    if(!BOX64ENV(dynarec_safeflags)) {
                        SET_DFNONE();
                    }
                    IFX2(X_AF, && BOX64ENV(cputype))  {ORRw_mask(xFlags, xFlags, 28, 0);}   //mask=0x10
                    IFX2(X_ZF, && BOX64ENV(cputype))  {BFCw(xFlags, F_ZF, 1);}
                    IFX2(X_SF, && BOX64ENV(cputype))  {BFCw(xFlags, F_SF, 1);}
                    IFX2(X_PF, && BOX64ENV(cputype))  {BFCw(xFlags, F_PF, 1);}
                    break;
            }
            break;
        case 0xF8:
            INST_NAME("CLC");
            SETFLAGS(X_CF, SF_SUBSET);
            SET_DFNONE();
            BFCx(xFlags, F_CF, 1);
            break;
        case 0xF9:
            INST_NAME("STC");
            SETFLAGS(X_CF, SF_SUBSET);
            SET_DFNONE();
            ORRx_mask(xFlags, xFlags, 1, 0, 0); // xFlags | 1
            break;

        case 0xFF:
            nextop = F8;
            switch((nextop>>3)&7) {
                case 0:
                    INST_NAME("INC Ew");
                    SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
                    GETEW(x1, 0);
                    emit_inc16(dyn, ninst, x1, x2, x4);
                    EWBACK;
                    break;
                case 1:
                    INST_NAME("DEC Ew");
                    SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
                    GETEW(x1, 0);
                    emit_dec16(dyn, ninst, x1, x2, x4);
                    EWBACK;
                    break;
                case 6: // Push Ew
                    INST_NAME("PUSH Ew");
                    GETEW(x1, 0);
                    PUSH1_16(ed);
                    break;

                default:
                    DEFAULT;
            }
            break;

        default:
            DEFAULT;
    }
    return addr;
}
