#include <stdint.h>
#include <86box/86box.h>
#include "cpu.h"
#include <86box/mem.h>

#include "x86.h"
#include "x86_flags.h"
#include "386_common.h"
#include "x87.h"
#include "codegen.h"
#include "codegen_accumulate.h"
#include "codegen_ir.h"
#include "codegen_ops.h"
#include "codegen_ops_fpu_arith.h"
#include "codegen_ops_helpers.h"

uint32_t ropFADD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int src_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FADD(ir, IREG_ST(0), IREG_ST(0), IREG_ST(src_reg));
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);

        return op_pc;
}
uint32_t ropFADDr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int dest_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FADD(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0));
        uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID);

        return op_pc;
}
uint32_t ropFADDP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int dest_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FADD(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0));
        uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID);
        fpu_POP(block, ir);

        return op_pc;
}

uint32_t ropFCOM(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int src_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(src_reg));
        uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3));
        uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W);

        return op_pc;
}
uint32_t ropFCOMP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int src_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(src_reg));
        uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3));
        uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W);
        fpu_POP(block, ir);

        return op_pc;
}
uint32_t ropFCOMPP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        uop_FP_ENTER(ir);
        uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(1));
        uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3));
        uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W);
        fpu_POP2(block, ir);

        return op_pc;
}

uint32_t ropFDIV(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int src_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FDIV(ir, IREG_ST(0), IREG_ST(0), IREG_ST(src_reg));
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);

        return op_pc;
}
uint32_t ropFDIVR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int src_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FDIV(ir, IREG_ST(0), IREG_ST(src_reg), IREG_ST(0));
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);

        return op_pc;
}
uint32_t ropFDIVr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int dest_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FDIV(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0));
        uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID);

        return op_pc;
}
uint32_t ropFDIVRr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int dest_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FDIV(ir, IREG_ST(dest_reg), IREG_ST(0), IREG_ST(dest_reg));
        uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID);

        return op_pc;
}
uint32_t ropFDIVP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int dest_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FDIV(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0));
        uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID);
        fpu_POP(block, ir);

        return op_pc;
}
uint32_t ropFDIVRP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int dest_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FDIV(ir, IREG_ST(dest_reg), IREG_ST(0), IREG_ST(dest_reg));
        uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID);
        fpu_POP(block, ir);

        return op_pc;
}

uint32_t ropFMUL(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int src_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FMUL(ir, IREG_ST(0), IREG_ST(0), IREG_ST(src_reg));
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);

        return op_pc;
}
uint32_t ropFMULr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int dest_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FMUL(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0));
        uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID);

        return op_pc;
}
uint32_t ropFMULP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int dest_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FMUL(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0));
        uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID);
        fpu_POP(block, ir);

        return op_pc;
}

uint32_t ropFSUB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int src_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FSUB(ir, IREG_ST(0), IREG_ST(0), IREG_ST(src_reg));
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);

        return op_pc;
}
uint32_t ropFSUBR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int src_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FSUB(ir, IREG_ST(0), IREG_ST(src_reg), IREG_ST(0));
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);

        return op_pc;
}
uint32_t ropFSUBr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int dest_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FSUB(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0));
        uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID);

        return op_pc;
}
uint32_t ropFSUBRr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int dest_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FSUB(ir, IREG_ST(dest_reg), IREG_ST(0), IREG_ST(dest_reg));
        uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID);

        return op_pc;
}
uint32_t ropFSUBP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int dest_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FSUB(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0));
        uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID);
        fpu_POP(block, ir);

        return op_pc;
}
uint32_t ropFSUBRP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int dest_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FSUB(ir, IREG_ST(dest_reg), IREG_ST(0), IREG_ST(dest_reg));
        uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID);
        fpu_POP(block, ir);

        return op_pc;
}

uint32_t ropFUCOM(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int src_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(src_reg));
        uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3));
        uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W);

        return op_pc;
}
uint32_t ropFUCOMP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        int src_reg = fetchdat & 7;

        uop_FP_ENTER(ir);
        uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(src_reg));
        uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3));
        uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W);
        fpu_POP(block, ir);

        return op_pc;
}
uint32_t ropFUCOMPP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        uop_FP_ENTER(ir);
        uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(1));
        uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3));
        uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W);
        fpu_POP2(block, ir);

        return op_pc;
}

#define ropF_arith_mem(name, load_uop)                                                                                          \
uint32_t ropFADD ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)  \
{                                                                                                                               \
        x86seg *target_seg;                                                                                                     \
                                                                                                                                \
        if ((cpu_state.npxc >> 10) & 3)                                                                                         \
                return 0;                                                                                                       \
        uop_FP_ENTER(ir);                                                                                                       \
        uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc);                                                                           \
        op_pc--;                                                                                                                \
        target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0);                                  \
        codegen_check_seg_read(block, ir, target_seg);                                                                          \
        load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr);                                                     \
        uop_FADD(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D);                                                                     \
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);                                                                                \
                                                                                                                                \
        return op_pc+1;                                                                                                         \
}                                                                                                                               \
uint32_t ropFCOM ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)  \
{                                                                                                                               \
        x86seg *target_seg;                                                                                                     \
                                                                                                                                \
        uop_FP_ENTER(ir);                                                                                                       \
        uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc);                                                                           \
        op_pc--;                                                                                                                \
        target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0);                                  \
        codegen_check_seg_read(block, ir, target_seg);                                                                          \
        load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr);                                                     \
        uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D);                                                                   \
        uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3));                                                                     \
        uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W);                                                                         \
                                                                                                                                \
        return op_pc+1;                                                                                                         \
}                                                                                                                               \
uint32_t ropFCOMP ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)  \
{                                                                                                                               \
        x86seg *target_seg;                                                                                                     \
                                                                                                                                \
        uop_FP_ENTER(ir);                                                                                                       \
        uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc);                                                                           \
        op_pc--;                                                                                                                \
        target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0);                                  \
        codegen_check_seg_read(block, ir, target_seg);                                                                          \
        load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr);                                                     \
        uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D);                                                                   \
        uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3));                                                                     \
        uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W);                                                                         \
        fpu_POP(block, ir);                                                                                                     \
                                                                                                                                \
        return op_pc+1;                                                                                                         \
}                                                                                                                               \
uint32_t ropFDIV ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)  \
{                                                                                                                               \
        x86seg *target_seg;                                                                                                     \
                                                                                                                                \
        uop_FP_ENTER(ir);                                                                                                       \
        uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc);                                                                           \
        op_pc--;                                                                                                                \
        target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0);                                  \
        codegen_check_seg_read(block, ir, target_seg);                                                                          \
        load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr);                                                     \
        uop_FDIV(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D);                                                                     \
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);                                                                                \
                                                                                                                                \
        return op_pc+1;                                                                                                         \
}                                                                                                                               \
uint32_t ropFDIVR ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \
{                                                                                                                               \
        x86seg *target_seg;                                                                                                     \
                                                                                                                                \
        uop_FP_ENTER(ir);                                                                                                       \
        uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc);                                                                           \
        op_pc--;                                                                                                                \
        target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0);                                  \
        codegen_check_seg_read(block, ir, target_seg);                                                                          \
        load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr);                                                     \
        uop_FDIV(ir, IREG_ST(0), IREG_temp0_D, IREG_ST(0));                                                                     \
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);                                                                                \
                                                                                                                                \
        return op_pc+1;                                                                                                         \
}                                                                                                                               \
uint32_t ropFMUL ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)  \
{                                                                                                                               \
        x86seg *target_seg;                                                                                                     \
                                                                                                                                \
        uop_FP_ENTER(ir);                                                                                                       \
        uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc);                                                                           \
        op_pc--;                                                                                                                \
        target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0);                                  \
        codegen_check_seg_read(block, ir, target_seg);                                                                          \
        load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr);                                                     \
        uop_FMUL(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D);                                                                     \
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);                                                                                \
                                                                                                                                \
        return op_pc+1;                                                                                                         \
}                                                                                                                               \
uint32_t ropFSUB ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)  \
{                                                                                                                               \
        x86seg *target_seg;                                                                                                     \
                                                                                                                                \
        uop_FP_ENTER(ir);                                                                                                       \
        uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc);                                                                           \
        op_pc--;                                                                                                                \
        target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0);                                  \
        codegen_check_seg_read(block, ir, target_seg);                                                                          \
        load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr);                                                     \
        uop_FSUB(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D);                                                                     \
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);                                                                                \
                                                                                                                                \
        return op_pc+1;                                                                                                         \
}                                                                                                                               \
uint32_t ropFSUBR ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \
{                                                                                                                               \
        x86seg *target_seg;                                                                                                     \
                                                                                                                                \
        uop_FP_ENTER(ir);                                                                                                       \
        uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc);                                                                           \
        op_pc--;                                                                                                                \
        target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0);                                  \
        codegen_check_seg_read(block, ir, target_seg);                                                                          \
        load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr);                                                     \
        uop_FSUB(ir, IREG_ST(0), IREG_temp0_D, IREG_ST(0));                                                                     \
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);                                                                                \
                                                                                                                                \
        return op_pc+1;                                                                                                         \
}

ropF_arith_mem(s, uop_MEM_LOAD_SINGLE)
ropF_arith_mem(d, uop_MEM_LOAD_DOUBLE)

#define ropFI_arith_mem(name, temp_reg)                                                                                         \
uint32_t ropFIADD ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \
{                                                                                                                               \
        x86seg *target_seg;                                                                                                     \
                                                                                                                                \
        uop_FP_ENTER(ir);                                                                                                       \
        uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc);                                                                           \
        op_pc--;                                                                                                                \
        target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0);                                  \
        codegen_check_seg_read(block, ir, target_seg);                                                                          \
        uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr);                                                 \
        uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg);                                                                         \
        uop_FADD(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D);                                                                     \
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);                                                                                \
                                                                                                                                \
        return op_pc+1;                                                                                                         \
}                                                                                                                               \
uint32_t ropFICOM ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \
{                                                                                                                               \
        x86seg *target_seg;                                                                                                     \
                                                                                                                                \
        uop_FP_ENTER(ir);                                                                                                       \
        uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc);                                                                           \
        op_pc--;                                                                                                                \
        target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0);                                  \
        codegen_check_seg_read(block, ir, target_seg);                                                                          \
        uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr);                                                 \
        uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg);                                                                         \
        uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D);                                                                   \
        uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3));                                                                     \
        uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W);                                                                         \
                                                                                                                                \
        return op_pc+1;                                                                                                         \
}                                                                                                                               \
uint32_t ropFICOMP ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \
{                                                                                                                               \
        x86seg *target_seg;                                                                                                     \
                                                                                                                                \
        uop_FP_ENTER(ir);                                                                                                       \
        uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc);                                                                           \
        op_pc--;                                                                                                                \
        target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0);                                  \
        codegen_check_seg_read(block, ir, target_seg);                                                                          \
        uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr);                                                 \
        uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg);                                                                         \
        uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D);                                                                   \
        uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3));                                                                     \
        uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W);                                                                         \
        fpu_POP(block, ir);                                                                                                     \
                                                                                                                                \
        return op_pc+1;                                                                                                         \
}                                                                                                                               \
uint32_t ropFIDIV ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \
{                                                                                                                               \
        x86seg *target_seg;                                                                                                     \
                                                                                                                                \
        uop_FP_ENTER(ir);                                                                                                       \
        uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc);                                                                           \
        op_pc--;                                                                                                                \
        target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0);                                  \
        codegen_check_seg_read(block, ir, target_seg);                                                                          \
        uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr);                                                 \
        uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg);                                                                         \
        uop_FDIV(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D);                                                                     \
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);                                                                                \
                                                                                                                                \
        return op_pc+1;                                                                                                         \
}                                                                                                                               \
uint32_t ropFIDIVR ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)\
{                                                                                                                               \
        x86seg *target_seg;                                                                                                     \
                                                                                                                                \
        uop_FP_ENTER(ir);                                                                                                       \
        uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc);                                                                           \
        op_pc--;                                                                                                                \
        target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0);                                  \
        codegen_check_seg_read(block, ir, target_seg);                                                                          \
        uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr);                                                 \
        uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg);                                                                         \
        uop_FDIV(ir, IREG_ST(0), IREG_temp0_D, IREG_ST(0));                                                                     \
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);                                                                                \
                                                                                                                                \
        return op_pc+1;                                                                                                         \
}                                                                                                                               \
uint32_t ropFIMUL ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \
{                                                                                                                               \
        x86seg *target_seg;                                                                                                     \
                                                                                                                                \
        uop_FP_ENTER(ir);                                                                                                       \
        uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc);                                                                           \
        op_pc--;                                                                                                                \
        target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0);                                  \
        codegen_check_seg_read(block, ir, target_seg);                                                                          \
        uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr);                                                 \
        uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg);                                                                         \
        uop_FMUL(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D);                                                                     \
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);                                                                                \
                                                                                                                                \
        return op_pc+1;                                                                                                         \
}                                                                                                                               \
uint32_t ropFISUB ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \
{                                                                                                                               \
        x86seg *target_seg;                                                                                                     \
                                                                                                                                \
        uop_FP_ENTER(ir);                                                                                                       \
        uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc);                                                                           \
        op_pc--;                                                                                                                \
        target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0);                                  \
        codegen_check_seg_read(block, ir, target_seg);                                                                          \
        uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr);                                                 \
        uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg);                                                                         \
        uop_FSUB(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D);                                                                     \
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);                                                                                \
                                                                                                                                \
        return op_pc+1;                                                                                                         \
}                                                                                                                               \
uint32_t ropFISUBR ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)\
{                                                                                                                               \
        x86seg *target_seg;                                                                                                     \
                                                                                                                                \
        uop_FP_ENTER(ir);                                                                                                       \
        uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc);                                                                           \
        op_pc--;                                                                                                                \
        target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0);                                  \
        codegen_check_seg_read(block, ir, target_seg);                                                                          \
        uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr);                                                 \
        uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg);                                                                         \
        uop_FSUB(ir, IREG_ST(0), IREG_temp0_D, IREG_ST(0));                                                                     \
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);                                                                                \
                                                                                                                                \
        return op_pc+1;                                                                                                         \
}

ropFI_arith_mem(l, IREG_temp0)
ropFI_arith_mem(w, IREG_temp0_W)


uint32_t ropFABS(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        uop_FP_ENTER(ir);
        uop_FABS(ir, IREG_ST(0), IREG_ST(0));
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);

        return op_pc;
}

uint32_t ropFCHS(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        uop_FP_ENTER(ir);
        uop_FCHS(ir, IREG_ST(0), IREG_ST(0));
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);

        return op_pc;
}
uint32_t ropFSQRT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        uop_FP_ENTER(ir);
        uop_FSQRT(ir, IREG_ST(0), IREG_ST(0));
        uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID);

        return op_pc;
}
uint32_t ropFTST(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
{
        uop_FP_ENTER(ir);
        uop_FTST(ir, IREG_temp0_W, IREG_ST(0));
        uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3));
        uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W);

        return op_pc;
}
