/**
 * TrueReality - n64/cop1.c
 * Copyright (C) 1998 Niki W. Waibel
 *
 * This program is free software; you can redistribute it and/
 * or modify it under the terms of the GNU General Public Li-
 * cence as published by the Free Software Foundation; either
 * version 2 of the Licence, or any later version.
 *
 * This program is distributed in the hope that it will be use-
 * ful, but WITHOUT ANY WARRANTY; without even the implied war-
 * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public Licence for more details.
 *
 * You should have received a copy of the GNU General Public
 * Licence along with this program; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
 * USA.
 *
 * Information about me (the author):
 *   Niki W. Waibel, Reichenau 20, 6890 Lustenau, Austria - EUROPE
 *   niki.waibel@gmx.net
**/





#include <stdio.h>
#include <math.h>
#include "../config.h"
#include "../parser_extern.h"
#include "type_sizes.h"
#include "mnemonic.h"
#include "registers.h"
#include "cpu.h"
#include "cop1.h"

#ifdef DEBUG
   #include "../debug.h"
#endif





/******************************************************************************\
*                                                                              *
*   CoProcessor1 - Floating Point Unit (COP1 - FPU)                            *
*                                                                              *
\******************************************************************************/

/* 32 cop1 rs instructions */

void rs4300i_cop1_rs_mf()
{
#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("mfc1    :");
#endif
#ifdef DEBUG_MNEMONIC
                printf(" r%02u, f%02u", rs4300i_RT(), __fs);
                printf(" : ([r%02u]=%016llx)", rs4300i_RT(), (sDWORD)(sWORD)fs);
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif


        reg.r[rs4300i_RT()] = (sDWORD)(sWORD)fs;
   
        //cop1 unusable exception
}





void rs4300i_cop1_rs_dmf()
{
#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("dmfc1   :");
#endif
#ifdef DEBUG_MNEMONIC
                printf(" r%02u, f%02u", rs4300i_RT(), __fs);
                printf(" : ([r%02u]=%016llx)", rs4300i_RT(), fs);
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif



        reg.r[rs4300i_RT()] = fs;

        //cop1 unusable exception
        //reserved instruction exception
}





void rs4300i_cop1_rs_cf()
{
#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("cfc1    :");
#endif
#ifdef DEBUG_MNEMONIC
                printf(" r%02u, ccr%02u", rs4300i_RT(), __fs);
                printf(" : ([r%02u]=%016llx)", rs4300i_RT(), (sDWORD)(sWORD)reg.ccr[1][__fs]);
                
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif

        reg.r[rs4300i_RT()] = (sDWORD)(sWORD)reg.ccr[1][__fs];

        //cop1 unusable exception
}





void rs4300i_cop1_rs_mt()
{
#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("mtc1    :");
#endif
#ifdef DEBUG_MNEMONIC
                printf(" r%02u, f%02u", rs4300i_RT(), __fs);
                printf(" : ([f%02u]=%016llx)", __fs, (sDWORD)(sWORD)reg.r[rs4300i_RT()]);
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif

        reg.cpr[1][__fs] = (sDWORD)(sWORD)reg.r[rs4300i_RT()];
   
        //cop1 unusable exception
}





void rs4300i_cop1_rs_dmt()
{
#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("dmtc1   :");
#endif
#ifdef DEBUG_MNEMONIC
                printf(" r%02u, f%02u", rs4300i_RT(), __fs);
                printf(" : ([f%02u]=%016llx)", __fs, reg.r[rs4300i_RT()]);
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif

        if(reg.cpr[0][STATUS] & 0x04000000)
                reg.cpr[1][__fs] = reg.r[rs4300i_RT()];
        else
        {
                reg.cpr[1][__fs+0] = (sDWORD)(sWORD)(reg.r[rs4300i_RT()]);
                reg.cpr[1][__fs+1] = (sDWORD)(sWORD)(reg.r[rs4300i_RT()] >> 32);
        }
   
        //cop1 unusable exception
        //reserved instruction exception
}





void rs4300i_cop1_rs_ct()
{
#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("ctc1    :");
#endif
#ifdef DEBUG_MNEMONIC
                printf(" r%02u, ccr%02u", rs4300i_RT(), __fs);
                printf(" : ([ccr%02u]=%08lx)", __fs, (WORD)reg.r[rs4300i_RT()]);
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif

        reg.ccr[1][__fs] = reg.r[rs4300i_RT()];
   
        //cop1 unusable exception
}





void rs4300i_cop1_rs_bc()
{
#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_XINST
                printf(" cop1 bc (rt) instruction\n");
#endif
        }
#endif

        ((void (*)()) cop1_rt_instruction[rs4300i_RT()])();
}





void rs4300i_cop1_rs_reserved()
{
#ifdef DEBUG_NOTIMPLEMENTED
        printf(" reserved (NOT IMPLEMENTED) \n");
#endif

#ifdef HALT
        reg.halt = 1;
#endif
}





void rs4300i_cop1_rs_co()
{
#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_XINST
                printf(" cop1 co (funct) instruction:\n");
#endif
        }
#endif

        ((void (*)()) cop1_instruction[rs4300i_Funct()])();
   
}





/* 32 cop1 rt (bc) instructions */



void rs4300i_cop1_rt_bcf()
{
#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("bc1f    :");
#endif
#ifdef DEBUG_MNEMONIC
                printf(" %08lx", rs4300i_I());
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif

        if(!(reg.ccr[1][31] & 0x00800000))
        {
                reg.delay = 1;
                reg.pc_delay = reg.pc + 4 + (rs4300i_I() << 2);
        }           
 
        //cop1 unusable exception
}





void rs4300i_cop1_rt_bct()
{
#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("bc1t    :");
#endif
#ifdef DEBUG_MNEMONIC
                printf(" %08lx", rs4300i_I());
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif

        if(reg.ccr[1][31] & 0x00800000)
        {
                reg.delay = 1;
                reg.pc_delay = reg.pc + 4 + (rs4300i_I() << 2);
        }           
 
        //cop1 unusable exception
}





void rs4300i_cop1_rt_bcfl()
{
#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("bc1fl   :");
#endif
#ifdef DEBUG_MNEMONIC
                printf(" %08lx", rs4300i_I());
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif

        if(!(reg.ccr[1][31] & 0x00800000))
        {
                reg.delay = 1;
                reg.pc_delay = reg.pc + 4 + (rs4300i_I() << 2);
        }
        else
                reg.pc += 4;
 
        //cop1 unusable exception
}





void rs4300i_cop1_rt_bctl()
{
#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("bc1fl   :");
#endif
#ifdef DEBUG_MNEMONIC
                printf(" %08lx", rs4300i_I());
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif

        if(reg.ccr[1][31] & 0x00800000)
        {
                reg.delay = 1;
                reg.pc_delay = reg.pc + 4 + (rs4300i_I() << 2);
        }
        else
                reg.pc += 4;
 
        //cop1 unusable exception
}





void rs4300i_cop1_rt_reserved()
{
#ifdef DEBUG_NOTIMPLEMENTED
        printf(" reserved (NOT IMPLEMENTED) \n");
#endif

#ifdef HALT
        reg.halt = 1;
#endif
}





/* 64 cop1 rs (co - function) instructions */





void rs4300i_cop1_add()
{
        DWORD x, y, z;



#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("add.%c   :", fmt);
#endif
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u, f%02u", __fd, __fs, __ft);
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif



        x = fs;
        y = ft;



        switch(__fmt)
        {
            case FMT_S:
                *((float *)&z) = *((float *)&x) + *((float *)&y);
                break;

            case FMT_D:
                *((double *)&z) = *((double *)&x) + *((double *)&y);
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %g, %g, %g\n", *((double *)&z), *((double *)&x), *((double *)&y));
#endif
                break;

            case FMT_W:
            case FMT_L:
                //exception???
                return;

            default:
                //exception???
                return;
                
        } /* switch(__fmt) */



        store_fpr(z);



        //cop unusable exception
        //floating point exception
   
        //unimplemented operation exception
        //invalid operation exception
        //inexact exception
        //overflow exception
        //underflow exception
}





void rs4300i_cop1_sub()
{
        DWORD x, y, z;



#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("sub.%c   :", fmt);
#endif
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u, f%02u", __fd, __fs, __ft);
#endif
#ifdef DEBUG_INST
                putchar('\n');
#endif
        }
#endif



        x = fs;
        y = ft;



        switch(__fmt)
        {
            case FMT_S:
                *((float *)&z) = *((float *)&x) - *((float *)&y);
                break;

            case FMT_D:
                *((double *)&z) = *((double *)&x) - *((double *)&y);
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %g, %g, %g\n", *((double *)&z), *((double *)&x), *((double *)&y));
#endif
                break;

            case FMT_W:
            case FMT_L:
                //exception???
                return;

            default:
                //exception???
                return;
                
        } /* switch(__fmt) */



        store_fpr(z);



        //cop unusable exception
        //floating point exception
   
        //unimplemented operation exception
        //invalid operation exception
        //inexact exception
        //overflow exception
        //underflow exception
}





void rs4300i_cop1_mul()
{
        DWORD x, y, z;



#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("mul.%c   :", fmt);
#endif
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u, f%02u", __fd, __fs, __ft);
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif



        x = fs;
        y = ft;



        switch(__fmt)
        {
            case FMT_S:
                *((float *)&z) = *((float *)&x) * *((float *)&y);
                break;

            case FMT_D:
                *((double *)&z) = *((double *)&x) * *((double *)&y);
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %g, %g, %g\n", *((double *)&z), *((double *)&x), *((double *)&y));
#endif
                break;

            case FMT_W:
            case FMT_L:
                //exception???
                return;

            default:
                //exception???
                return;
                
        } /* switch(__fmt) */



        store_fpr(z);



        //cop unusable exception
        //floating point exception
   
        //unimplemented operation exception
        //invalid operation exception
        //inexact exception
        //overflow exception
        //underflow exception
}





void rs4300i_cop1_div()
{
        DWORD x, y, z;



#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("div.%c   :", fmt);
#endif
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u, f%02u", __fd, __fs, __ft);
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif



        x = fs;
        y = ft;



        switch(__fmt)
        {
            case FMT_S:
                if(*((float *)&y) != 0)
                        *((float *)&z) = *((float *)&x) / *((float *)&y);
                else
                {
                        // division-by-zero exception
                        return;
                }
                break;

            case FMT_D:
                if(*((double *)&y) != 0)
                {
                        *((double *)&z) = *((double *)&x) / *((double *)&y);
#ifdef DEBUG_MNEMONIC
                        if(prefs.debug & DBG_CP1_INSTR)
                                printf(" : %g, %g, %g\n", *((double *)&z), *((double *)&x), *((double *)&y));
#endif
                }
                else
                {
                        // division-by-zero exception
                        return;
                }
                break;

            case FMT_W:
            case FMT_L:
                //exception???
                return;

            default:
                //exception???
                return;
                
        } /* switch(__fmt) */



        store_fpr(z);



        //cop unusable exception
        //floating point exception
   
        //unimplemented operation exception
        //invalid operation exception
        //inexact exception
        //overflow exception
        //underflow exception
}





void rs4300i_cop1_sqrt()
{
        DWORD x, z;



#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("sqrt.%c  :", fmt);
#endif
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u", __fd, __fs);
#endif
#ifdef DEBUG_INST
                putchar('\n');
#endif
        }
#endif



        x = fs;



        switch(__fmt)
        {
            case FMT_S:
                *((float *)&z) = (float)sqrt((double)*((float *)&x));
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %g, %g\n", *((float *)&z), *((float *)&x));
#endif
                break;

            case FMT_D:
                *((double *)&z) = sqrt(*((double *)&x));
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %g, %g\n", *((double *)&z), *((double *)&x));
#endif
                break;

            case FMT_W:
            case FMT_L:
                //exception???
                return;

            default:
                //exception???
                return;
                
        } /* switch(__fmt) */



        store_fpr(z);



        //cop unusable exception
        //floating point exception
   
        //unimplemented operation exception
        //invalid operation exception
        //inexact exception

}





void rs4300i_cop1_abs()
{
        DWORD x, z;



#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("abs.%c   :", fmt);
#endif
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u", __fd, __fs);
#endif
#ifdef DEBUG_INST
                putchar('\n');
#endif
        }
#endif



        x = fs;



        switch(__fmt)
        {
            case FMT_S:
                *((float *)&z) = (float)fabs((double)*((float *)&x));
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %g, %g\n", *((float *)&z), *((float *)&x));
#endif
                break;

            case FMT_D:
                *((double *)&z) = fabs(*((double *)&x));
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %g, %g\n", *((double *)&z), *((double *)&x));
#endif
                break;

            case FMT_W:
            case FMT_L:
                //exception???
                return;

            default:
                //exception???
                return;
                
        } /* switch(__fmt) */



        store_fpr(z);



        //cop unusable exception
        //floating point exception
   
        //unimplemented operation exception
        //invalid operation exception

}





void rs4300i_cop1_mov()
{
#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("mov.%c   :", fmt);
#endif
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u", __fd, __fs);
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif



        switch(__fmt)
        {
            case FMT_S:
            case FMT_D:
                store_fpr(fs);
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %016llx, %016llx\n", fd, fs);
#endif
                break;

            case FMT_W:
            case FMT_L:
                //exception???
                return;

            default:
                //exception???
                return;
                
        } /* switch(__fmt) */



        //cop unusable exception
        //floating point exception
   
        //unimplemented operation exception
}





void rs4300i_cop1_neg()
{
        DWORD z;


        
#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("mov.%c   :", fmt);
#endif
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u", __fd, __fs);
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif



        z = fs;



        switch(__fmt)
        {
            case FMT_S:
                *((float *)&z) = -(*((float *)&z));
                store_fpr(z);
                break;

            case FMT_D:
                *((double *)&z) = -(*((double *)&z));
                store_fpr(z);
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %g, %g\n", *((double *)&z), *((double *)&z));
#endif
                break;

            case FMT_W:
            case FMT_L:
                //exception???
                return;

            default:
                //exception???
                return;
                
        } /* switch(__fmt) */



        //cop unusable exception
        //floating point exception
   
        //unimplemented operation exception
        //invalid operation exception
}





void rs4300i_cop1_roundl()
{
        DWORD   x, z;
        double  fract;



#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("roundl.%c:", fmt);
#endif
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u", __fd, __fs);
#endif
#ifdef DEBUG_INST
                putchar('\n');
#endif
        }
#endif



        x = fs;



        switch(__fmt)
        {
            case FMT_S:
                *((sDWORD *)&z) = (sDWORD)modf((double)*((float *)&x), &fract);
                if(fract >  0.5)
                        *((sDWORD *)&z) = *((sDWORD *)&z) + 1;
                else if(fract < -0.5)
                        *((sDWORD *)&z) = *((sDWORD *)&z) - 1;
                else if(abs(fract) == 0.5)
                        *((sDWORD *)&z) = *((sDWORD *)&z) & ~1LL;
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %lld, %g\n", *((sDWORD *)&z), *((float *)&x));
#endif
                break;

            case FMT_D:
                *((sDWORD *)&z) = (sDWORD)modf(*((double *)&x), &fract);
                if(fract >  0.5)
                        *((sDWORD *)&z) = *((sDWORD *)&z) + 1;
                else if(fract < -0.5)
                        *((sDWORD *)&z) = *((sDWORD *)&z) - 1;
                else if(abs(fract) == 0.5)
                        *((sDWORD *)&z) = *((sDWORD *)&z) & ~1LL;
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %lld, %g\n", *((sDWORD *)&z), *((double *)&x));
#endif
                break;

            case FMT_W:
            case FMT_L:
                //exception???
                return;

            default:
                //exception???
                return;
                
        } /* switch(__fmt) */



        store_fpr(z);



        //cop unusable exception
        //floating point exception
   
        //unimplemented operation exception
        //invalid operation exception
        //inexact exception
        //overflow exception

}





void rs4300i_cop1_truncl()
{
        DWORD z;


        
#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("truncl.%c:", fmt);
#endif
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u", __fd, __fs);
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif



        z = fs;



        switch(__fmt)
        {
            case FMT_S:
                *((sDWORD *)&z) = (sDWORD)(*((float *)&z));
                store_fpr(z);
                break;

            case FMT_D:
                *((sDWORD *)&z) = (sDWORD)(*((double *)&z));
                store_fpr(z);
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %016llx, %g\n", *((sDWORD *)&z), (double)(*((sDWORD *)&z)));
#endif
                break;

            case FMT_W:
            case FMT_L:
                //exception???
                return;

            default:
                //exception???
                return;
                
        } /* switch(__fmt) */



        //cop unusable exception
        //floating point exception
   
        //unimplemented operation exception
        //invalid operation exception
        //inexact exception
        //overflow exception
}





void rs4300i_cop1_ceill()
{
        DWORD x, z;



#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("ceil.l.%c:", fmt);
#endif
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u", __fd, __fs);
#endif
#ifdef DEBUG_INST
                putchar('\n');
#endif
        }
#endif



        x = fs;



        switch(__fmt)
        {
            case FMT_S:
                *((sDWORD *)&z) = (sDWORD)ceil((double)*((float *)&x));
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %lld, %g\n", *((sDWORD *)&z), *((float *)&x));
#endif
                break;

            case FMT_D:
                *((sDWORD *)&z) = (sDWORD)ceil(*((double *)&x));
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %lld, %g\n", *((sDWORD *)&z), *((double *)&x));
#endif
                break;

            case FMT_W:
            case FMT_L:
                //exception???
                return;

            default:
                //exception???
                return;
                
        } /* switch(__fmt) */



        store_fpr(z);



        //cop unusable exception
        //floating point exception
   
        //unimplemented operation exception
        //invalid operation exception
        //inexact exception
        //overflow exception

}





void rs4300i_cop1_floorl()
{
        DWORD x, z;



#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("floorl.%c:", fmt);
#endif
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u", __fd, __fs);
#endif
#ifdef DEBUG_INST
                putchar('\n');
#endif
        }
#endif



        x = fs;



        switch(__fmt)
        {
            case FMT_S:
                *((sDWORD *)&z) = (sDWORD)floor((double)*((float *)&x));
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %lld, %g\n", *((sDWORD *)&z), *((float *)&x));
#endif
                break;

            case FMT_D:
                *((sDWORD *)&z) = (sDWORD)floor(*((double *)&x));
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %lld, %g\n", *((sDWORD *)&z), *((double *)&x));
#endif
                break;

            case FMT_W:
            case FMT_L:
                //exception???
                return;

            default:
                //exception???
                return;
                
        } /* switch(__fmt) */



        store_fpr(z);



        //cop unusable exception
        //floating point exception
   
        //unimplemented operation exception
        //invalid operation exception
        //inexact exception
        //overflow exception

}





void rs4300i_cop1_roundw()
{
        DWORD   x, z;
        double  fract;



#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("roundw.%c:", fmt);
#endif
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u", __fd, __fs);
#endif
#ifdef DEBUG_INST
                putchar('\n');
#endif
        }
#endif



        x = fs;



        switch(__fmt)
        {
            case FMT_S:
                *((sWORD *)&z) = (sWORD)modf((double)*((float *)&x), &fract);
                if(fract >  0.5)
                        *((sWORD *)&z) = *((sWORD *)&z) + 1;
                else if(fract < -0.5)
                        *((sWORD *)&z) = *((sWORD *)&z) - 1;
                else if(abs(fract) == 0.5)
                        *((sWORD *)&z) = *((sWORD *)&z) & ~1;
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %ld, %g\n", *((sWORD *)&z), *((float *)&x));
#endif
                break;

            case FMT_D:
                *((sWORD *)&z) = (sWORD)modf(*((double *)&x), &fract);
                if(fract >  0.5)
                        *((sWORD *)&z) = *((sWORD *)&z) + 1;
                else if(fract < -0.5)
                        *((sWORD *)&z) = *((sWORD *)&z) - 1;
                else if(abs(fract) == 0.5)
                        *((sWORD *)&z) = *((sWORD *)&z) & ~1LL;
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %ld, %g\n", *((sWORD *)&z), *((double *)&x));
#endif
                break;

            case FMT_W:
            case FMT_L:
                //exception???
                return;

            default:
                //exception???
                return;
                
        } /* switch(__fmt) */



        store_fpr(z);



        //cop unusable exception
        //floating point exception
   
        //unimplemented operation exception
        //invalid operation exception
        //inexact exception
        //overflow exception

}





void rs4300i_cop1_truncw()
{
        DWORD z;


        
#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("truncw.%c:", fmt);
#endif
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u", __fd, __fs);
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif



        z = fs;



        switch(__fmt)
        {
            case FMT_S:
                *((sWORD *)&z) = (sWORD)(*((float *)&z));
                store_fpr(z);
                break;

            case FMT_D:
                *((sWORD *)&z) = (sWORD)(*((double *)&z));
                store_fpr(z);
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %08lx, %g\n", *((sWORD *)&z), (double)(*((sWORD *)&z)));
#endif
                break;

            case FMT_W:
            case FMT_L:
                //exception???
                return;

            default:
                //exception???
                return;
                
        } /* switch(__fmt) */



        //cop unusable exception
        //floating point exception
   
        //unimplemented operation exception
        //invalid operation exception
        //inexact exception
        //overflow exception
}





void rs4300i_cop1_ceilw()
{
        DWORD x, z;



#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("ceil.w.%c:", fmt);
#endif
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u", __fd, __fs);
#endif
#ifdef DEBUG_INST
                putchar('\n');
#endif
        }
#endif



        x = fs;



        switch(__fmt)
        {
            case FMT_S:
                *((sWORD *)&z) = (sWORD)ceil((double)*((float *)&x));
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %ld, %g\n", *((sWORD *)&z), *((float *)&x));
#endif
                break;

            case FMT_D:
                *((sWORD *)&z) = (sWORD)ceil(*((double *)&x));
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %ld, %g\n", *((sWORD *)&z), *((double *)&x));
#endif
                break;

            case FMT_W:
            case FMT_L:
                //exception???
                return;

            default:
                //exception???
                return;
                
        } /* switch(__fmt) */



        store_fpr(z);



        //cop unusable exception
        //floating point exception
   
        //unimplemented operation exception
        //invalid operation exception
        //inexact exception
        //overflow exception

}





void rs4300i_cop1_floorw()
{
        DWORD x, z;



#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("floorw.%c:", fmt);
#endif
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u", __fd, __fs);
#endif
#ifdef DEBUG_INST
                putchar('\n');
#endif
        }
#endif



        x = fs;



        switch(__fmt)
        {
            case FMT_S:
                *((sWORD *)&z) = (sWORD)floor((double)*((float *)&x));
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %ld, %g\n", *((sWORD *)&z), *((float *)&x));
#endif
                break;

            case FMT_D:
                *((sWORD *)&z) = (sWORD)floor(*((double *)&x));
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %ld, %g\n", *((sWORD *)&z), *((double *)&x));
#endif
                break;

            case FMT_W:
            case FMT_L:
                //exception???
                return;

            default:
                //exception???
                return;
                
        } /* switch(__fmt) */



        store_fpr(z);



        //cop unusable exception
        //floating point exception
   
        //unimplemented operation exception
        //invalid operation exception
        //inexact exception
        //overflow exception

}





void rs4300i_cop1_reserved()
{
#ifdef DEBUG_NOTIMPLEMENTED
        printf(" reserved (NOT IMPLEMENTED) \n");
#endif

#ifdef HALT
        reg.halt = 1;
#endif
}





void rs4300i_cop1_cvts()
{
        DWORD z;


        
#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("cvt.s.%c :", fmt);
#endif
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u", __fd, __fs);
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif



        z = fs;



        switch(__fmt)
        {
            case FMT_S:
                //exception???
                return;

            case FMT_D:
                *((float *)&z) = (float)(*((double *)&z));
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %g, %g\n", *((float *)&z), (double)(*((float *)&z)));
#endif
                break;

            case FMT_W:
                *((float *)&z) = (float)(*((sWORD *)&z));
                break;
                
            case FMT_L:
                *((float *)&z) = (float)(*((sDWORD *)&z));
                break;

            default:
                //exception???
                return;
                
        } /* switch(__fmt) */



        store_fpr(z);



        //cop unusable exception
        //cop exception trap
   
        //unimplemented operation exception
        //invalid operation exception
}





void rs4300i_cop1_cvtd()
{
        DWORD z;


        
#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("cvt.d.%c :", fmt);
#endif
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u", __fd, __fs);
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif



        z = fs;



        switch(__fmt)
        {
            case FMT_S:
                *((double *)&z) = (double)(*((float *)&z));
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %g, %g\n", *((double *)&z), (float)(*((double *)&z)));
#endif
                break;

            case FMT_D:
                //exception???
                return;

            case FMT_W:
                *((double *)&z) = (double)(*((sWORD *)&z));
                break;
                
            case FMT_L:
                *((double *)&z) = (double)(*((sDWORD *)&z));
                break;

            default:
                //exception???
                return;
                
        } /* switch(__fmt) */



        store_fpr(z);



        //cop unusable exception
        //cop exception trap
   
        //unimplemented operation exception
        //invalid operation exception

        //reg.halt = 1;
}





void rs4300i_cop1_cvtw()
{
        DWORD z;


        
#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("cvt.w.%c :", fmt);
#endif
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u", __fd, __fs);
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif



        z = fs;



        switch(__fmt)
        {
            case FMT_S:
                *((sWORD *)&z) = (sWORD)(*((float *)&z));
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %08lx, %g\n", *((sWORD *)&z), (float)(*((sWORD *)&z)));
#endif
                break;

            case FMT_D:
                *((sWORD *)&z) = (sWORD)(*((double *)&z));
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %08lx, %g\n", *((sWORD *)&z), (double)(*((sWORD *)&z)));
#endif
                break;

            case FMT_W:
                //exception???
                return;
                
            case FMT_L:
                *((sWORD *)&z) = (sWORD)(*((sDWORD *)&z));
                break;

            default:
                //exception???
                return;
                
        } /* switch(__fmt) */



        store_fpr(z);



        //cop unusable exception
        //cop exception trap
   
        //unimplemented operation exception
        //invalid operation exception
}





void rs4300i_cop1_cvtl()
{
        DWORD z;


        
#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf("cvt.l.%c :", fmt);
#endif
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u", __fd, __fs);
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
        }
#endif



        z = fs;



        switch(__fmt)
        {
            case FMT_S:
                *((sDWORD *)&z) = (sDWORD)(*((float *)&z));
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %016llx, %g\n", *((sDWORD *)&z), (float)(*((sDWORD *)&z)));
#endif
                break;

            case FMT_D:
                *((sDWORD *)&z) = (sDWORD)(*((double *)&z));
#ifdef DEBUG_MNEMONIC
                if(prefs.debug & DBG_CP1_INSTR)
                        printf(" : %016llx, %g\n", *((sDWORD *)&z), (double)(*((sDWORD *)&z)));
#endif
                break;

            case FMT_W:
                *((sDWORD *)&z) = (sDWORD)(*((sWORD *)&z));
                break;
                
            case FMT_L:
                //exception???
                return;

            default:
                //exception???
                return;
                
        } /* switch(__fmt) */



        store_fpr(z);



        //cop unusable exception
        //cop exception trap
   
        //unimplemented operation exception
        //invalid operation exception
}





void rs4300i_cop1_c()
{
        sDWORD x, y;



#ifdef DEBUG
        if(prefs.debug & DBG_CP1_INSTR)
        {
#ifdef DEBUG_OPCODE
                printf
                (
                        "c.%s.%c",
                        (rs4300i_Funct() == 0x30) ? "f" :
                                (rs4300i_Funct() == 0x31) ? "un" :
                                        (rs4300i_Funct() == 0x32) ? "eq" :
                                                (rs4300i_Funct() == 0x33) ? "ueq" :
                                                        (rs4300i_Funct() == 0x34) ? "olt" :
                                                                (rs4300i_Funct() == 0x35) ? "ult" :
                                                                        (rs4300i_Funct() == 0x36) ? "ole" :
                                                                                (rs4300i_Funct() == 0x37) ? "ule" :
                                                                                        (rs4300i_Funct() == 0x38) ? "sf" :
                                                                                                (rs4300i_Funct() == 0x39) ? "ngle" :
                                                                                                        (rs4300i_Funct() == 0x3a) ? "seq" :
                                                                                                                (rs4300i_Funct() == 0x3b) ? "ngl" :
                                                                                                                        (rs4300i_Funct() == 0x3c) ? "lt" :
                                                                                                                                (rs4300i_Funct() == 0x3d) ? "nge" :
                                                                                                                                        (rs4300i_Funct() == 0x3e) ? "le" : "ngt",
                        (rs4300i_RS() == 16) ? 's' :
                                (rs4300i_RS() == 17) ? 'd' : '?'
                );
#ifdef DEBUG_MNEMONIC
                printf(" f%02u, f%02u", __fs, __ft);
#endif
#ifdef DEBUG_INST
                printf("\n");
#endif
#endif
        }
#endif



        x = fs;
        y = ft;



        switch(__fmt)
        {
            case FMT_S:   /* c.*.s */
                switch(__function)
                {
                    case 0x30:   /* c.f */
                        reg.ccr[1][31] &= ~0x00800000;
                        break;
                        
                    case 0x31:   /* c.un */
                        reg.halt = 1;
                        break;
                        
                    case 0x32:   /* c.eq */
                        if( *((float *)&x) == *((float *)&y) )
                                reg.ccr[1][31] |= 0x00800000;
                        else
                                reg.ccr[1][31] &= ~0x00800000;
                        break;
                    
                    case 0x33:   /* c.ueq */
                        /* BUG: check NaN */
                        if( *((float *)&x) == *((float *)&y) )
                                reg.ccr[1][31] |= 0x00800000;
                        else
                                reg.ccr[1][31] &= ~0x00800000;
                        break;
                    
                    case 0x34:   /* c.olt */
                        reg.halt = 1;
                        break;
                    
                    case 0x35:   /* c.ult */
                        reg.halt = 1;
                        break;
                    
                    case 0x36:   /* c.ole */
                        reg.halt = 1;
                        break;
                    
                    case 0x37:   /* c.ule */
                        reg.halt = 1;
                        break;
                    
                    case 0x38:   /* c.sf */
                        reg.halt = 1;
                        break;
                    
                    case 0x39:   /* c.ngle */
                        reg.halt = 1;
                        break;
                    
                    case 0x3a:   /* c.seq */
                        reg.halt = 1;
                        break;
                    
                    case 0x3b:   /* c.ngl */
                        reg.halt = 1;
                        break;
                    
                    case 0x3c:   /* c.lt */
                        if( *((float *)&x) < *((float *)&y) )
                                reg.ccr[1][31] |= 0x00800000;
                        else
                                reg.ccr[1][31] &= ~0x00800000;
                        break;
                    
                    case 0x3d:   /* c.nge */
                        /* BUG: check NaN */
                        if( *((float *)&x) < *((float *)&y) )
                                reg.ccr[1][31] |= 0x00800000;
                        else
                                reg.ccr[1][31] &= ~0x00800000;
                        break;
                    
                    case 0x3e:   /* c.le */
                        if( *((float *)&x) <= *((float *)&y) )
                                reg.ccr[1][31] |= 0x00800000;
                        else
                                reg.ccr[1][31] &= ~0x00800000;
                        break;
                    
                    case 0x3f:   /* c.ngt */
                        /* BUG: check NaN */
                        if( *((float *)&x) <= *((float *)&y) )
                                reg.ccr[1][31] |= 0x00800000;
                        else
                                reg.ccr[1][31] &= ~0x00800000;
                        break;

                } /* switch(__function) */
                
                break;
            
            case FMT_D:   /* c.*.d */
                switch(__function)
                {
                    case 0x30:   /* c.f */
                        reg.ccr[1][31] &= ~0x00800000;
                        break;
                        
                    case 0x31:   /* c.un */
                        reg.halt = 1;
                        break;
                        
                    case 0x32:   /* c.eq */
                        if( *((double *)&x) == *((double *)&y) )
                                reg.ccr[1][31] |= 0x00800000;
                        else
                                reg.ccr[1][31] &= ~0x00800000;
                        break;
                    
                    case 0x33:   /* c.ueq */
                        /* BUG: check NaN */
                        if( *((double *)&x) == *((double *)&y) )
                                reg.ccr[1][31] |= 0x00800000;
                        else
                                reg.ccr[1][31] &= ~0x00800000;
                        break;
                    
                    case 0x34:   /* c.olt */
                        reg.halt = 1;
                        break;
                    
                    case 0x35:   /* c.ult */
                        reg.halt = 1;
                        break;
                    
                    case 0x36:   /* c.ole */
                        reg.halt = 1;
                        break;
                    
                    case 0x37:   /* c.ule */
                        reg.halt = 1;
                        break;
                    
                    case 0x38:   /* c.sf */
                        reg.halt = 1;
                        break;
                    
                    case 0x39:   /* c.ngle */
                        reg.halt = 1;
                        break;
                    
                    case 0x3a:   /* c.seq */
                        reg.halt = 1;
                        break;
                    
                    case 0x3b:   /* c.ngl */
                        reg.halt = 1;
                        break;
                    
                    case 0x3c:   /* c.lt */
                        if( *((double *)&x) < *((double *)&y) )
                                reg.ccr[1][31] |= 0x00800000;
                        else
                                reg.ccr[1][31] &= ~0x00800000;
                        break;
                    
                    case 0x3d:   /* c.nge */
                        /* BUG: check NaN */
                        if( *((double *)&x) < *((double *)&y) )
                                reg.ccr[1][31] |= 0x00800000;
                        else
                                reg.ccr[1][31] &= ~0x00800000;
                        break;
                    
                    case 0x3e:   /* c.le */
                        if( *((double *)&x) <= *((double *)&y) )
                                reg.ccr[1][31] |= 0x00800000;
                        else
                                reg.ccr[1][31] &= ~0x00800000;
                        break;
                    
                    case 0x3f:   /* c.ngt */
                        /* BUG: check NaN */
                        if( *((double *)&x) <= *((double *)&y) )
                                reg.ccr[1][31] |= 0x00800000;
                        else
                                reg.ccr[1][31] &= ~0x00800000;
                        break;

                } /* switch(__function) */
                
                break;

            default:
                // exception
                reg.halt = 1;
                
        } /* switch(__fmt) */

} /* void rs4300i_cop1_c() */




