static uint32_t ropFXCH(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();

        FP_FXCH(opcode & 7);
        
        return op_pc;
}

static uint32_t ropFLD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();

        FP_FLD(opcode & 7);
        
        return op_pc;
}

static uint32_t ropFST(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();

        FP_FST(opcode & 7);
        
        return op_pc;
}
static uint32_t ropFSTP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();

        FP_FST(opcode & 7);
        FP_POP();
        
        return op_pc;
}


static uint32_t ropFLDs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        x86seg *target_seg;
        
        FP_ENTER();
        op_pc--;
        target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);

        STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc);
        
        CHECK_SEG_READ(target_seg);
        MEM_LOAD_ADDR_EA_L(target_seg);

        FP_LOAD_S();

        return op_pc + 1;
}
static uint32_t ropFLDd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        x86seg *target_seg;
        
        FP_ENTER();
        op_pc--;
        target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);

        STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc);
        
        CHECK_SEG_READ(target_seg);
        MEM_LOAD_ADDR_EA_Q(target_seg);

        FP_LOAD_D();

        return op_pc + 1;
}

static uint32_t ropFILDw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        x86seg *target_seg;
        
        FP_ENTER();
        op_pc--;
        target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);

        STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc);
        
        CHECK_SEG_READ(target_seg);
        MEM_LOAD_ADDR_EA_W(target_seg);

        FP_LOAD_IW();

        return op_pc + 1;
}
static uint32_t ropFILDl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        x86seg *target_seg;
        
        FP_ENTER();
        op_pc--;
        target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);

        STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc);
        
        CHECK_SEG_READ(target_seg);
        MEM_LOAD_ADDR_EA_L(target_seg);

        FP_LOAD_IL();

        return op_pc + 1;
}
static uint32_t ropFILDq(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        x86seg *target_seg;
        
        FP_ENTER();
        op_pc--;
        target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);

        STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc);
        
        CHECK_SEG_READ(target_seg);
        MEM_LOAD_ADDR_EA_Q(target_seg);

        FP_LOAD_IQ();

        codegen_fpu_loaded_iq[(TOP - 1) & 7] = 1;
        
        return op_pc + 1;
}

static uint32_t ropFSTs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        x86seg *target_seg;
        int host_reg;
        
        FP_ENTER();
        op_pc--;
        target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);

        host_reg = FP_LOAD_REG(0);

        STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc);

        CHECK_SEG_WRITE(target_seg);
                
        MEM_STORE_ADDR_EA_L(target_seg, host_reg);

        return op_pc + 1;
}
static uint32_t ropFSTd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        x86seg *target_seg;
        int host_reg1, host_reg2;
        
        FP_ENTER();
        op_pc--;
        target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);

        FP_LOAD_REG_D(0, &host_reg1, &host_reg2);

        STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc);

        CHECK_SEG_WRITE(target_seg);
        CHECK_SEG_LIMITS(target_seg, 7);
                
        MEM_STORE_ADDR_EA_Q(target_seg, host_reg1, host_reg2);

        return op_pc + 1;
}

static uint32_t ropFSTPs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        uint32_t new_pc = ropFSTs(opcode, fetchdat, op_32, op_pc, block);
        
        FP_POP();
        
        return new_pc;
}
static uint32_t ropFSTPd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        uint32_t new_pc = ropFSTd(opcode, fetchdat, op_32, op_pc, block);
        
        FP_POP();
        
        return new_pc;
}

#define ropFarith(name, size, load, op) \
static uint32_t ropF ## name ## size(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)     \
{                                                                                                                               \
        x86seg *target_seg;                                                                                                     \
                                                                                                                                \
        FP_ENTER();                                                                                                             \
        op_pc--;                                                                                                                \
        target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);                                                    \
                                                                                                                                \
        STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc);                                                                         \
                                                                                                                                \
        CHECK_SEG_READ(target_seg);                                                                                             \
        load(target_seg);                                                                                                       \
                                                                                                                                \
        op(FPU_ ## name);                                                                                                       \
                                                                                                                                \
        return op_pc + 1;                                                                                                       \
}

ropFarith(ADD,  s, MEM_LOAD_ADDR_EA_L, FP_OP_S);
ropFarith(DIV,  s, MEM_LOAD_ADDR_EA_L, FP_OP_S);
ropFarith(DIVR, s, MEM_LOAD_ADDR_EA_L, FP_OP_S);
ropFarith(MUL,  s, MEM_LOAD_ADDR_EA_L, FP_OP_S);
ropFarith(SUB,  s, MEM_LOAD_ADDR_EA_L, FP_OP_S);
ropFarith(SUBR, s, MEM_LOAD_ADDR_EA_L, FP_OP_S);
ropFarith(ADD,  d, MEM_LOAD_ADDR_EA_Q, FP_OP_D);
ropFarith(DIV,  d, MEM_LOAD_ADDR_EA_Q, FP_OP_D);
ropFarith(DIVR, d, MEM_LOAD_ADDR_EA_Q, FP_OP_D);
ropFarith(MUL,  d, MEM_LOAD_ADDR_EA_Q, FP_OP_D);
ropFarith(SUB,  d, MEM_LOAD_ADDR_EA_Q, FP_OP_D);
ropFarith(SUBR, d, MEM_LOAD_ADDR_EA_Q, FP_OP_D);
ropFarith(ADD,  iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW);
ropFarith(DIV,  iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW);
ropFarith(DIVR, iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW);
ropFarith(MUL,  iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW);
ropFarith(SUB,  iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW);
ropFarith(SUBR, iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW);
ropFarith(ADD,  il, MEM_LOAD_ADDR_EA_L, FP_OP_IL);
ropFarith(DIV,  il, MEM_LOAD_ADDR_EA_L, FP_OP_IL);
ropFarith(DIVR, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL);
ropFarith(MUL,  il, MEM_LOAD_ADDR_EA_L, FP_OP_IL);
ropFarith(SUB,  il, MEM_LOAD_ADDR_EA_L, FP_OP_IL);
ropFarith(SUBR, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL);

#define ropFcompare(name, size, load, op) \
static uint32_t ropF ## name ## size(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)     \
{                                                                                                                               \
        x86seg *target_seg;                                                                                                     \
                                                                                                                                \
        FP_ENTER();                                                                                                             \
        op_pc--;                                                                                                                \
        target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);                                                    \
                                                                                                                                \
        STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc);                                                                         \
                                                                                                                                \
        CHECK_SEG_READ(target_seg);                                                                                             \
        load(target_seg);                                                                                                       \
                                                                                                                                \
        op();                                                                                                                   \
                                                                                                                                \
        return op_pc + 1;                                                                                                       \
}                                                                                                                               \
static uint32_t ropF ## name ## P ## size(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)        \
{                                                                                                                               \
        uint32_t new_pc = ropF ## name ## size(opcode, fetchdat, op_32, op_pc, block);                                           \
                                                                                                                                \
        FP_POP();                                                                                                               \
                                                                                                                                \
        return new_pc;                                                                                                          \
}

ropFcompare(COM, s, MEM_LOAD_ADDR_EA_L, FP_COMPARE_S);
ropFcompare(COM, d, MEM_LOAD_ADDR_EA_Q, FP_COMPARE_D);
ropFcompare(COM, iw, MEM_LOAD_ADDR_EA_W, FP_COMPARE_IW);
ropFcompare(COM, il, MEM_LOAD_ADDR_EA_L, FP_COMPARE_IL);

/*static uint32_t ropFADDs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        x86seg *target_seg;
        
        FP_ENTER();
        op_pc--;
        target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);

        STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc);
        
        CHECK_SEG_READ(target_seg);
        MEM_LOAD_ADDR_EA_L(target_seg);

        FP_OP_S(FPU_ADD);

        return op_pc + 1;
}
static uint32_t ropFDIVs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        x86seg *target_seg;
        
        FP_ENTER();
        op_pc--;
        target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);

        STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc);
        
        CHECK_SEG_READ(target_seg);
        MEM_LOAD_ADDR_EA_L(target_seg);

        FP_OP_S(FPU_DIV);

        return op_pc + 1;
}
static uint32_t ropFMULs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        x86seg *target_seg;
        
        FP_ENTER();
        op_pc--;
        target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);

        STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc);
        
        CHECK_SEG_READ(target_seg);
        MEM_LOAD_ADDR_EA_L(target_seg);

        FP_OP_S(FPU_MUL);

        return op_pc + 1;
}
static uint32_t ropFSUBs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        x86seg *target_seg;
        
        FP_ENTER();
        op_pc--;
        target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);

        STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc);
        
        CHECK_SEG_READ(target_seg);
        MEM_LOAD_ADDR_EA_L(target_seg);

        FP_OP_S(FPU_SUB);

        return op_pc + 1;
}*/


static uint32_t ropFADD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();
        FP_OP_REG(FPU_ADD, 0, opcode & 7);
       
        return op_pc;
}
static uint32_t ropFCOM(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();
        FP_COMPARE_REG(0, opcode & 7);
       
        return op_pc;
}
static uint32_t ropFDIV(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();
        FP_OP_REG(FPU_DIV, 0, opcode & 7);
       
        return op_pc;
}
static uint32_t ropFDIVR(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();
        FP_OP_REG(FPU_DIVR, 0, opcode & 7);
       
        return op_pc;
}
static uint32_t ropFMUL(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();
        FP_OP_REG(FPU_MUL, 0, opcode & 7);
       
        return op_pc;
}
static uint32_t ropFSUB(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();
        FP_OP_REG(FPU_SUB, 0, opcode & 7);
       
        return op_pc;
}
static uint32_t ropFSUBR(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();
        FP_OP_REG(FPU_SUBR, 0, opcode & 7);
       
        return op_pc;
}

static uint32_t ropFADDr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();
        FP_OP_REG(FPU_ADD, opcode & 7, 0);
       
        return op_pc;
}
static uint32_t ropFDIVr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();
        FP_OP_REG(FPU_DIV, opcode & 7, 0);
       
        return op_pc;
}
static uint32_t ropFDIVRr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();
        FP_OP_REG(FPU_DIVR, opcode & 7, 0);
       
        return op_pc;
}
static uint32_t ropFMULr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();
        FP_OP_REG(FPU_MUL, opcode & 7, 0);
       
        return op_pc;
}
static uint32_t ropFSUBr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();
        FP_OP_REG(FPU_SUB, opcode & 7, 0);
       
        return op_pc;
}
static uint32_t ropFSUBRr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();
        FP_OP_REG(FPU_SUBR, opcode & 7, 0);
       
        return op_pc;
}

static uint32_t ropFADDP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();
        FP_OP_REG(FPU_ADD, opcode & 7, 0);
        FP_POP();
       
        return op_pc;
}
static uint32_t ropFCOMP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();
        FP_COMPARE_REG(0, opcode & 7);
        FP_POP();
       
        return op_pc;
}
static uint32_t ropFDIVP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();
        FP_OP_REG(FPU_DIV, opcode & 7, 0);
        FP_POP();
       
        return op_pc;
}
static uint32_t ropFDIVRP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();
        FP_OP_REG(FPU_DIVR, opcode & 7, 0);
        FP_POP();
       
        return op_pc;
}
static uint32_t ropFMULP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();
        FP_OP_REG(FPU_MUL, opcode & 7, 0);
        FP_POP();
       
        return op_pc;
}
static uint32_t ropFSUBP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();
        FP_OP_REG(FPU_SUB, opcode & 7, 0);
        FP_POP();
       
        return op_pc;
}
static uint32_t ropFSUBRP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        FP_ENTER();
        FP_OP_REG(FPU_SUBR, opcode & 7, 0);
        FP_POP();
       
        return op_pc;
}


static uint32_t ropFSTSW_AX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        int host_reg;
        
        FP_ENTER();
        host_reg = LOAD_VAR_W(&npxs);
        STORE_REG_TARGET_W_RELEASE(host_reg, REG_AX);
        
        return op_pc;
}


static uint32_t ropFISTw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        x86seg *target_seg;
        int host_reg;

        FP_ENTER();
        op_pc--;
        target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);

        host_reg = FP_LOAD_REG_INT_W(0);

        STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc);

        CHECK_SEG_WRITE(target_seg);
                
        MEM_STORE_ADDR_EA_W(target_seg, host_reg);

        return op_pc + 1;
}
static uint32_t ropFISTl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        x86seg *target_seg;
        int host_reg;

        FP_ENTER();
        op_pc--;
        target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);

        host_reg = FP_LOAD_REG_INT(0);

        STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc);

        CHECK_SEG_WRITE(target_seg);
                
        MEM_STORE_ADDR_EA_L(target_seg, host_reg);

        return op_pc + 1;
}

static uint32_t ropFISTPw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        uint32_t new_pc = ropFISTw(opcode, fetchdat, op_32, op_pc, block);
        
        FP_POP();
        
        return new_pc;
}
static uint32_t ropFISTPl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        uint32_t new_pc = ropFISTl(opcode, fetchdat, op_32, op_pc, block);
        
        FP_POP();
        
        return new_pc;
}
static uint32_t ropFISTPq(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        x86seg *target_seg;
        int host_reg1, host_reg2;

        FP_ENTER();
        op_pc--;
        target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);

        FP_LOAD_REG_INT_Q(0, &host_reg1, &host_reg2);

        STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc);

        CHECK_SEG_WRITE(target_seg);
                
        MEM_STORE_ADDR_EA_Q(target_seg, host_reg1, host_reg2);

        FP_POP();
        
        return op_pc + 1;
}


static uint32_t ropFLDCW(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        x86seg *target_seg;

        FP_ENTER();
        op_pc--;
        target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);

        CHECK_SEG_READ(target_seg);
        
        MEM_LOAD_ADDR_EA_W(target_seg);
        STORE_HOST_REG_ADDR_W((uintptr_t)&npxc, 0);
        
        return op_pc + 1;
}
static uint32_t ropFSTCW(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
        int host_reg;
        x86seg *target_seg;

        FP_ENTER();
        op_pc--;
        target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);

        CHECK_SEG_WRITE(target_seg);

        host_reg = LOAD_VAR_W((uintptr_t)&npxc);
        MEM_STORE_ADDR_EA_W(target_seg, host_reg);
        
        return op_pc + 1;
}
