/**
 * TrueReality - N64/cpu.c
 * Copyright (C) 1998, 1999 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 <stdlib.h>
#include <math.h>

#include <config.h>
#include <type_sizes.h>
#include <memory_extern.h>
#include <dispatch.h>
#include <parser_extern.h>

#include "memory.h"
#include "mnemonic.h"
#include "registers.h"
#include "exceptions.h"
#include "interrupts.h"
#include "rsp.h"
#include "rsp_registers.h"
#include "cpu.h"



#ifdef NATIVE
        #include <native.h>

        #define IF_NATIVE(num, name)                                            \
                if(__PREV_CODE == native_jal_table[num])                        \
                {                                                               \
                        if(prefs.debug & DBG_NATIVE)                            \
                                printf("NATIVE: " #name " @ %llx (pc=$%08lx)\n", reg.cpr[0][COUNT], reg.pc);   \
                        native_##name();                                        \
                        reg.cpr[0][COUNT] += sizeof(native_code_##name) / 4;    \
                        reg.pc += 4;                                            \
                }                                                               \
                else
#endif

#ifdef DEBUG
        #include <debug.h>
#endif










static void rs4300i_reserved();
static void rs4300i_invalid();
static void rs4300i_special();
static void rs4300i_regimm();
static void rs4300i_j();
static void rs4300i_jal();
static void rs4300i_beq();
static void rs4300i_bne();
static void rs4300i_blez();
static void rs4300i_bgtz();
static void rs4300i_addi();
static void rs4300i_addiu();
static void rs4300i_slti();
static void rs4300i_sltiu();
static void rs4300i_andi();
static void rs4300i_ori();
static void rs4300i_xori();
static void rs4300i_lui();
static void rs4300i_cop0();
static void rs4300i_cop1();
static void rs4300i_cop2();
static void rs4300i_beql();
static void rs4300i_bnel();
static void rs4300i_blezl();
static void rs4300i_bgtzl();
static void rs4300i_daddi();
static void rs4300i_daddiu();
static void rs4300i_ldl();
static void rs4300i_ldr();
static void rs4300i_lb();
static void rs4300i_lh();
static void rs4300i_lwl();
static void rs4300i_lw();
static void rs4300i_lbu();
static void rs4300i_lhu();
static void rs4300i_lwr();
static void rs4300i_lwu();
static void rs4300i_sb();
static void rs4300i_sh();
static void rs4300i_swl();
static void rs4300i_sw();
static void rs4300i_sdl();
static void rs4300i_sdr();
static void rs4300i_swr();
static void rs4300i_cache();
static void rs4300i_ll();
static void rs4300i_lwc1();
static void rs4300i_lwc2();
static void rs4300i_lld();
static void rs4300i_ldc1();
static void rs4300i_ldc2();
static void rs4300i_ld();
static void rs4300i_sc();
static void rs4300i_swc1();
static void rs4300i_swc2();
static void rs4300i_scd();
static void rs4300i_sdc1();
static void rs4300i_sdc2();
static void rs4300i_sd();
static void rs4300i_special_sll();
static void rs4300i_special_srl();
static void rs4300i_special_sra();
static void rs4300i_special_sllv();
static void rs4300i_special_srlv();
static void rs4300i_special_srav();
static void rs4300i_special_jr();
static void rs4300i_special_jalr();
static void rs4300i_special_syscall();
static void rs4300i_special_break();
static void rs4300i_special_sync();
static void rs4300i_special_mfhi();
static void rs4300i_special_mthi();
static void rs4300i_special_mflo();
static void rs4300i_special_mtlo();
static void rs4300i_special_dsllv();
static void rs4300i_special_dsrlv();
static void rs4300i_special_dsrav();
static void rs4300i_special_mult();
static void rs4300i_special_multu();
static void rs4300i_special_div();
static void rs4300i_special_divu();
static void rs4300i_special_dmult();
static void rs4300i_special_dmultu();
static void rs4300i_special_ddiv();
static void rs4300i_special_ddivu();
static void rs4300i_special_add();
static void rs4300i_special_addu();
static void rs4300i_special_sub();
static void rs4300i_special_subu();
static void rs4300i_special_and();
static void rs4300i_special_or();
static void rs4300i_special_xor();
static void rs4300i_special_nor();
static void rs4300i_special_slt();
static void rs4300i_special_sltu();
static void rs4300i_special_dadd();
static void rs4300i_special_daddu();
static void rs4300i_special_dsub();
static void rs4300i_special_dsubu();
static void rs4300i_special_tge();
static void rs4300i_special_tgeu();
static void rs4300i_special_tlt();
static void rs4300i_special_tltu();
static void rs4300i_special_teq();
static void rs4300i_special_tne();
static void rs4300i_special_dsll();
static void rs4300i_special_dsrl();
static void rs4300i_special_dsra();
static void rs4300i_special_dsll32();
static void rs4300i_special_dsrl32();
static void rs4300i_special_dsra32();
static void rs4300i_regimm_bltz();
static void rs4300i_regimm_bgez();
static void rs4300i_regimm_bltzl();
static void rs4300i_regimm_bgezl();
static void rs4300i_regimm_tgei();
static void rs4300i_regimm_tgeiu();
static void rs4300i_regimm_tlti();
static void rs4300i_regimm_tltiu();
static void rs4300i_regimm_teqi();
static void rs4300i_regimm_tnei();
static void rs4300i_regimm_bltzal();
static void rs4300i_regimm_bgezal();
static void rs4300i_regimm_bltzall();
static void rs4300i_regimm_bgezall();
static void rs4300i_cop0_rs_mf();
static void rs4300i_cop0_rs_dmf();
static void rs4300i_cop0_rs_cf();
static void rs4300i_cop0_rs_mt();
static void rs4300i_cop0_rs_dmt();
static void rs4300i_cop0_rs_ct();
static void rs4300i_cop0_rs_bc();
static void rs4300i_cop0_rs_co();
static void rs4300i_cop0_rt_bcf();
static void rs4300i_cop0_rt_bct();
static void rs4300i_cop0_rt_bcfl();
static void rs4300i_cop0_rt_bctl();
static void rs4300i_cop0_tlbr();
static void rs4300i_cop0_tlbwi();
static void rs4300i_cop0_tlbwr();
static void rs4300i_cop0_tlbp();
static void rs4300i_cop0_eret();
static void rs4300i_cop1_rs_mf();
static void rs4300i_cop1_rs_dmf();
static void rs4300i_cop1_rs_cf();
static void rs4300i_cop1_rs_mt();
static void rs4300i_cop1_rs_dmt();
static void rs4300i_cop1_rs_ct();
static void rs4300i_cop1_rs_bc();
static void rs4300i_cop1_rs_co();
static void rs4300i_cop1_rt_bcf();
static void rs4300i_cop1_rt_bct();
static void rs4300i_cop1_rt_bcfl();
static void rs4300i_cop1_rt_bctl();
static void rs4300i_cop1_add();
static void rs4300i_cop1_sub();
static void rs4300i_cop1_mul();
static void rs4300i_cop1_div();
static void rs4300i_cop1_sqrt();
static void rs4300i_cop1_abs();
static void rs4300i_cop1_mov();
static void rs4300i_cop1_neg();
static void rs4300i_cop1_roundl();
static void rs4300i_cop1_truncl();
static void rs4300i_cop1_ceill();
static void rs4300i_cop1_floorl();
static void rs4300i_cop1_roundw();
static void rs4300i_cop1_truncw();
static void rs4300i_cop1_ceilw();
static void rs4300i_cop1_floorw();
static void rs4300i_cop1_cvts();
static void rs4300i_cop1_cvtd();
static void rs4300i_cop1_cvtw();
static void rs4300i_cop1_cvtl();
static void rs4300i_cop1_c();
static void rs4300i_cop2_rs_not_implemented();










struct rs4300i_reg reg;



                      

static cpu_instr instruction[64] =
{
        rs4300i_special,
        rs4300i_regimm,
        rs4300i_j,
        rs4300i_jal,
        rs4300i_beq,
        rs4300i_bne,
        rs4300i_blez,
        rs4300i_bgtz,
        rs4300i_addi,
        rs4300i_addiu,
        rs4300i_slti,
        rs4300i_sltiu,
        rs4300i_andi,
        rs4300i_ori,
        rs4300i_xori,
        rs4300i_lui,
        rs4300i_cop0,
        rs4300i_cop1,
        rs4300i_cop2,
        rs4300i_reserved,
        rs4300i_beql,
        rs4300i_bnel,
        rs4300i_blezl,
        rs4300i_bgtzl,
        rs4300i_daddi,
        rs4300i_daddiu,
        rs4300i_ldl,
        rs4300i_ldr,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_lb,
        rs4300i_lh,
        rs4300i_lwl,
        rs4300i_lw,
        rs4300i_lbu,
        rs4300i_lhu,
        rs4300i_lwr,
        rs4300i_lwu,
        rs4300i_sb,
        rs4300i_sh,
        rs4300i_swl,
        rs4300i_sw,
        rs4300i_sdl,
        rs4300i_sdr,
        rs4300i_swr,
        rs4300i_cache,
        rs4300i_ll,
        rs4300i_lwc1,
        rs4300i_lwc2,
        rs4300i_reserved,
        rs4300i_lld,
        rs4300i_ldc1,
        rs4300i_ldc2,
        rs4300i_ld,
        rs4300i_sc,
        rs4300i_swc1,
        rs4300i_swc2,
        rs4300i_reserved,
        rs4300i_scd,
        rs4300i_sdc1,
        rs4300i_sdc2,
        rs4300i_sd
};





static cpu_instr special_instruction[64] =
{
        rs4300i_special_sll,
        rs4300i_reserved,
        rs4300i_special_srl,
        rs4300i_special_sra,
        rs4300i_special_sllv,
        rs4300i_reserved,
        rs4300i_special_srlv,
        rs4300i_special_srav,
        rs4300i_special_jr,
        rs4300i_special_jalr,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_special_syscall,
        rs4300i_special_break,
        rs4300i_reserved,
        rs4300i_special_sync,
        rs4300i_special_mfhi,
        rs4300i_special_mthi,
        rs4300i_special_mflo,
        rs4300i_special_mtlo,
        rs4300i_special_dsllv,
        rs4300i_reserved,
        rs4300i_special_dsrlv,
        rs4300i_special_dsrav,
        rs4300i_special_mult,
        rs4300i_special_multu,
        rs4300i_special_div,
        rs4300i_special_divu,
        rs4300i_special_dmult,
        rs4300i_special_dmultu,
        rs4300i_special_ddiv,
        rs4300i_special_ddivu,
        rs4300i_special_add,
        rs4300i_special_addu,
        rs4300i_special_sub,
        rs4300i_special_subu,
        rs4300i_special_and,
        rs4300i_special_or,
        rs4300i_special_xor,
        rs4300i_special_nor,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_special_slt,
        rs4300i_special_sltu,
        rs4300i_special_dadd,
        rs4300i_special_daddu,
        rs4300i_special_dsub,
        rs4300i_special_dsubu,
        rs4300i_special_tge,
        rs4300i_special_tgeu,
        rs4300i_special_tlt,
        rs4300i_special_tltu,
        rs4300i_special_teq,
        rs4300i_reserved,
        rs4300i_special_tne,
        rs4300i_reserved,
        rs4300i_special_dsll,
        rs4300i_reserved,
        rs4300i_special_dsrl,
        rs4300i_special_dsra,
        rs4300i_special_dsll32,
        rs4300i_reserved,
        rs4300i_special_dsrl32,
        rs4300i_special_dsra32
};





static cpu_instr regimm_instruction[32] =
{
        rs4300i_regimm_bltz,
        rs4300i_regimm_bgez,
        rs4300i_regimm_bltzl,
        rs4300i_regimm_bgezl,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_regimm_tgei,
        rs4300i_regimm_tgeiu,
        rs4300i_regimm_tlti,
        rs4300i_regimm_tltiu,
        rs4300i_regimm_teqi,
        rs4300i_reserved,
        rs4300i_regimm_tnei,
        rs4300i_reserved,
        rs4300i_regimm_bltzal,
        rs4300i_regimm_bgezal,
        rs4300i_regimm_bltzall,
        rs4300i_regimm_bgezall,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved
};





static cpu_instr cop0_rs_instruction[32] =
{
        rs4300i_cop0_rs_mf,
        rs4300i_cop0_rs_dmf,
        rs4300i_cop0_rs_cf,
        rs4300i_reserved,
        rs4300i_cop0_rs_mt,
        rs4300i_cop0_rs_dmt,
        rs4300i_cop0_rs_ct,
        rs4300i_reserved,
        rs4300i_cop0_rs_bc,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_cop0_rs_co,
        rs4300i_cop0_rs_co,
        rs4300i_cop0_rs_co,
        rs4300i_cop0_rs_co,
        rs4300i_cop0_rs_co,
        rs4300i_cop0_rs_co,
        rs4300i_cop0_rs_co,
        rs4300i_cop0_rs_co,
        rs4300i_cop0_rs_co,
        rs4300i_cop0_rs_co,
        rs4300i_cop0_rs_co,
        rs4300i_cop0_rs_co,
        rs4300i_cop0_rs_co,
        rs4300i_cop0_rs_co,
        rs4300i_cop0_rs_co,
        rs4300i_cop0_rs_co
};





static cpu_instr cop0_rt_instruction[32] =
{
        rs4300i_cop0_rt_bcf,
        rs4300i_cop0_rt_bct,
        rs4300i_cop0_rt_bcfl,
        rs4300i_cop0_rt_bctl,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved
};





static cpu_instr cop0_instruction[64] =
{
        rs4300i_invalid,
        rs4300i_cop0_tlbr,
        rs4300i_cop0_tlbwi,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_cop0_tlbwr,
        rs4300i_invalid,
        rs4300i_cop0_tlbp,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_reserved,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_cop0_eret,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid
};





static cpu_instr cop1_rs_instruction[32] =
{
        rs4300i_cop1_rs_mf,
        rs4300i_cop1_rs_dmf,
        rs4300i_cop1_rs_cf,
        rs4300i_reserved,
        rs4300i_cop1_rs_mt,
        rs4300i_cop1_rs_dmt,
        rs4300i_cop1_rs_ct,
        rs4300i_reserved,
        rs4300i_cop1_rs_bc,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_cop1_rs_co,
        rs4300i_cop1_rs_co,
        rs4300i_cop1_rs_co,
        rs4300i_cop1_rs_co,
        rs4300i_cop1_rs_co,
        rs4300i_cop1_rs_co,
        rs4300i_cop1_rs_co,
        rs4300i_cop1_rs_co,
        rs4300i_cop1_rs_co,
        rs4300i_cop1_rs_co,
        rs4300i_cop1_rs_co,
        rs4300i_cop1_rs_co,
        rs4300i_cop1_rs_co,
        rs4300i_cop1_rs_co,
        rs4300i_cop1_rs_co,
        rs4300i_cop1_rs_co
};





static cpu_instr cop1_rt_instruction[32] =
{
        rs4300i_cop1_rt_bcf,
        rs4300i_cop1_rt_bct,
        rs4300i_cop1_rt_bcfl,
        rs4300i_cop1_rt_bctl,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved,
        rs4300i_reserved
};





static cpu_instr cop1_instruction[64] =
{
        rs4300i_cop1_add,
        rs4300i_cop1_sub,
        rs4300i_cop1_mul,
        rs4300i_cop1_div,
        rs4300i_cop1_sqrt,
        rs4300i_cop1_abs,
        rs4300i_cop1_mov,
        rs4300i_cop1_neg,
        rs4300i_cop1_roundl,
        rs4300i_cop1_truncl,
        rs4300i_cop1_ceill,
        rs4300i_cop1_floorl,
        rs4300i_cop1_roundw,
        rs4300i_cop1_truncw,
        rs4300i_cop1_ceilw,
        rs4300i_cop1_floorw,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_cop1_cvts,
        rs4300i_cop1_cvtd,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_cop1_cvtw,
        rs4300i_cop1_cvtl,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_invalid,
        rs4300i_cop1_c,
        rs4300i_cop1_c,
        rs4300i_cop1_c,
        rs4300i_cop1_c,
        rs4300i_cop1_c,
        rs4300i_cop1_c,
        rs4300i_cop1_c,
        rs4300i_cop1_c,
        rs4300i_cop1_c,
        rs4300i_cop1_c,
        rs4300i_cop1_c,
        rs4300i_cop1_c,
        rs4300i_cop1_c,
        rs4300i_cop1_c,
        rs4300i_cop1_c,
        rs4300i_cop1_c
};





static cpu_instr cop2_rs_instruction[32] =
{
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented,
        rs4300i_cop2_rs_not_implemented
};










void cpu_step()
{
        if(reg.do_or_check_sthg)
        {
                if(reg.do_or_check_sthg & RS4300I_DO_SI_INTERRUPT)
                        rs4300i_MI_Intr_SI();

                if(reg.do_or_check_sthg & RS4300I_DO_SP_INTERRUPT)
                        rs4300i_MI_Intr_SP();

                if(reg.do_or_check_sthg & RS4300I_DO_DP_INTERRUPT)
                        rs4300i_MI_Intr_DP();

                if(reg.do_or_check_sthg & RS4300I_DO_AI_INTERRUPT)
                        rs4300i_MI_Intr_AI();

                if(reg.do_or_check_sthg & RS4300I_DO_PI_INTERRUPT)
                        rs4300i_MI_Intr_PI();

                if(reg.do_or_check_sthg & RS4300I_CHECK_MI_INTERRUPTS)
                        rs4300i_Check_MI_Interrupts();

                if(reg.do_or_check_sthg & RS4300I_CHECK_CPU_INTERRUPTS)
                        rs4300i_Check_CPU_Interrupts();

                if(reg.do_or_check_sthg & RS4300I_DO_INTEGER_OVERFLOW_EXCEPTION)
                        rs4300i_integer_overflow_exception();

                if(reg.do_or_check_sthg & RS4300I_DO_FLOATING_POINT_EXCEPTION)
                        rs4300i_floating_point_exception();

                if(reg.do_or_check_sthg & RS4300I_DO_TRAP_EXCEPTION)
                        rs4300i_trap_exception();

                if(reg.do_or_check_sthg & RS4300I_DO_SYSCALL_EXCEPTION)
                        rs4300i_syscall_exception();

                if(reg.do_or_check_sthg & RS4300I_DO_BREAK_EXCEPTION)
                        rs4300i_break_exception();

                if(reg.do_or_check_sthg & RS4300I_DO_RESERVED_INSTRUCTION_EXCEPTION)
                        rs4300i_reserved_instruction_exception();

                reg.do_or_check_sthg = RS4300I_DO_OR_CHECK_NOTHING;
        }



        /* if (COUNT reg == COMPARE reg) then { generate a comp intr } */
        if((reg.cpr[0][COUNT] & 0xffffffff) == reg.cpr[0][COMPARE])
        {
#ifdef DEBUG
                if(prefs.debug & DBG_INTR_COMP)
                        printf("call compare interrupt handler (COUNT=%016llx, PC=%08lx)\n", reg.cpr[0][9], reg.pc);
#endif
                rs4300i_CompareInterrupt();
        }




        if(reg.cpr[0][COUNT] == next_vi_interrupt)
        {
#ifdef DEBUG
                if(prefs.debug & DBG_INTR_VI)
                        printf("call vi interrupt handler (COUNT=%016llx, PC=%08lx)\n", reg.cpr[0][9], reg.pc);
#endif
                rs4300i_MI_Intr_VI();
        }




        /* execute instruction */

        instruction[__OPCODE]();



        switch(reg.delay)
        {
            case EXEC_DELAY:    /* next instruction is at pc_delay */
                reg.delay = NO_DELAY;
#ifdef NATIVE
                IF_NATIVE(0, set_sr)
                IF_NATIVE(1, get_sr)
                IF_NATIVE(2, disable_interrupts)
                IF_NATIVE(3, restore_interrupts)
                IF_NATIVE(4, set_vi_mode)
#endif
                {
                        reg.pc = reg.pc_delay;
                }
                break;

            case DO_DELAY:      /* a delayed pc was stored into pc_delay      */
                                /* next instr is at pc+4 (case 0 is executed) */
                                /* next instr is at pc_delay                  */
                reg.delay = EXEC_DELAY;

            case NO_DELAY:      /* normal execution */
                reg.pc += 4;

        } /* switch(reg.delay) */



        /* do common things */

        reg.r[0] = 0;
        reg.cpr[0][COUNT]++;



        if(!rsp_reg.halt)
                rsp_step();

} /* void cpu_step() */




  
void cpu_reset()
{
        int i, j;





        /* rsp */

        rsp_reset();



        /* debugging */
#ifdef HALT
        reg.halt = 0;
#endif
        reg.do_or_check_sthg = RS4300I_DO_OR_CHECK_NOTHING;

   
   
        /* cpu registers */
   
        /* reg.pc = 0xbfc00000; */
        reg.pc = 0xa4000040;

        for(i=0; i<32; i++)
                reg.r[i] = 0;
      
        reg.r[20] = 0x0000000000000001ULL;
        reg.r[22] = 0x000000000000003fULL;
        reg.r[29] = 0x0000000000400000ULL;

        reg.hi = 0;
        reg.lo = 0;

        reg.llbit = 0;

        reg.delay = NO_DELAY;



        /* cop0/1/2 registers */
   
        for(j=0; j<=2; j++)
                for(i=0; i<32; i++)
                {
                        reg.cpr[j][i] = 0;
                        reg.ccr[j][i] = 0;
                }
      
        reg.cpr[0][STATUS] = 0x70400004;
        reg.cpr[0][RANDOM] = 0x0000002f;
        reg.cpr[0][CONFIG] = 0x00066463;
        reg.cpr[0][PRID]   = 0x00000b00;
        
        reg.ccr[1][0]      = 0x00000511;


   
        /* interrupts */
   
        rs4300i_InitInterrupts();



        /* memory */
        


} /* void cpu_reset() */











void cpu_print_gpr()
{
        int i;


        for(i=0; i<16; i++)
        {
                printf("r[%2d]=%16llx  ", i,    reg.r[i]);
                printf("r[%2d]=%16llx\n", i+16, reg.r[i+16]);
        }

        printf(" [hi]=%016llx   [lo]=%016llx\n", reg.hi, reg.lo);

        printf(" [pc]=%08lx\n\n", reg.pc);
}





void cpu_print_cp0()
{
        int i;


        for(i=0; i<16; i++)
        {
                printf("cpr[0][%2d]=%16llx  ", i,    reg.cpr[0][i]);
                printf("cpr[0][%2d]=%16llx\n", i+16, reg.cpr[0][i+16]);
        }
}





void cpu_print_cp1()
{
        int i;


        for(i=0; i<16; i++)
        {
                printf("f[%02d]=%16llx  ", i,    reg.cpr[1][i]);
                printf("f[%02d]=%16llx\n", i+16, reg.cpr[1][i+16]);
        }

        printf("ccr[1][00] =  %8llx  ccr[1][31] =  %8llx\n", reg.ccr[1][0], reg.ccr[1][31]);
}





void cpu_print_cp2()
{
        int i;


        for(i=0; i<16; i++)
        {
                printf("cpr[2][%2d]=%16llx  ", i,    reg.cpr[2][i]);
                printf("cpr[2][%2d]=%16llx\n", i+16, reg.cpr[2][i+16]);
        }
}










static void rs4300i_reserved()
{
        PRINT_XINST("reserved instruction")

        reg.do_or_check_sthg = RS4300I_DO_RESERVED_INSTRUCTION_EXCEPTION;

}





static void rs4300i_invalid()
{
        PRINT_XINST("invalid instruction")

}





/******************************************************************************\
*                                                                              *
*   Central Processing Unit (CPU)                                              *
*                                                                              *
\******************************************************************************/



static void rs4300i_special()
{
        PRINT_XINST("special instruction")

        special_instruction[__F]();

}





static void rs4300i_regimm()
{
        PRINT_XINST("regimm instructioni")

        regimm_instruction[__RT]();

}





static void rs4300i_j()
{
        DWORD count;

        PRINT_DEBUGGING_INFO("J", T)

        if(__T == reg.pc)   /* if jump to same myself  */
                if(__NEXT_CODE == 0x00000000)                  /*    if next instr == nop */
                {
                        //printf("count: %llx\n", reg.cpr[0][COUNT]);

                        count = next_vi_interrupt;

                        //if(reg.cpr[0][STATUS] & 0x00008000)   /* timer interrupt set */
                        if(reg.cpr[0][COMPARE] < (count & 0xffffffff))
                                if(reg.cpr[0][COMPARE] > (reg.cpr[0][COUNT] & 0xffffffff))
                                        count = reg.cpr[0][COMPARE] | (reg.cpr[0][COUNT] & 0xffffffff00000000ULL);

                        reg.cpr[0][COUNT] = count - 1;

                        //printf("count: %llx\n\n", reg.cpr[0][COUNT]);
                }
   
        reg.delay = DO_DELAY;
        reg.pc_delay = __T;
   
}





static void rs4300i_jal()
{
        PRINT_DEBUGGING_INFO("JAL", T)

        reg.delay = DO_DELAY;
        reg.pc_delay = __T;
        reg.r[31] = reg.pc + 8;

}





static void rs4300i_beq()
{
        DWORD count;

        PRINT_DEBUGGING_INFO("BEQ", RS_RT_O)

        if(reg.r[__RS] == reg.r[__RT])
        {
                if(__I == -1)                                  /* if jump to same myself  */
                        if(__NEXT_CODE == 0x00000000)                  /*    if next instr == nop */
                        {
                                count = next_vi_interrupt;

                                if(reg.cpr[0][COMPARE] < (count & 0xffffffff))
                                        if(reg.cpr[0][COMPARE] > (reg.cpr[0][COUNT] & 0xffffffff))
                                                count = reg.cpr[0][COMPARE] | (reg.cpr[0][COUNT] & 0xffffffff00000000ULL);

                                reg.cpr[0][COUNT] = count - 1;

                        }

                reg.delay = DO_DELAY;
                reg.pc_delay = __O;
        }

}





static void rs4300i_bne()
{
        PRINT_DEBUGGING_INFO("BNE", RS_RT_O)

        if(reg.r[__RS] != reg.r[__RT])
        {
                reg.delay = DO_DELAY;
                reg.pc_delay = __O;
        }

}





static void rs4300i_blez()
{
        PRINT_DEBUGGING_INFO("BLEZ", RS_O)

        if(((signed)reg.r[__RS]) <= 0)
        {
                reg.delay = DO_DELAY;
                reg.pc_delay = __O;
        }

}





static void rs4300i_bgtz()
{
        PRINT_DEBUGGING_INFO("BGTZ", RS_O);

        if(((signed)reg.r[__RS]) > 0)
        {
                reg.delay = DO_DELAY;
                reg.pc_delay = __O;
        }

}





static void rs4300i_addi()
{
        sDWORD x, y, z;



        PRINT_DEBUGGING_INFO("ADDI", RT_RS_I);


        x = (sWORD)reg.r[__RS];
        y = (sWORD)__I;
        
        z = x + y;

        
        
        if((z > 0x7fffffffLL) || (z < -0x80000000LL))
                reg.do_or_check_sthg = RS4300I_DO_INTEGER_OVERFLOW_EXCEPTION;
        else
                reg.r[__RT] = (sDWORD)(sWORD)z;

}





static void rs4300i_addiu()
{
        PRINT_DEBUGGING_INFO("ADDIU", RT_RS_I);

        reg.r[__RT] = (sDWORD)(sWORD)(reg.r[__RS] + __I);

}





static void rs4300i_slti()
{
        PRINT_DEBUGGING_INFO("SLTI", RT_RS_I);

        if(reg.r[__RS] < __I)
                reg.r[__RT] = 1;
        else
                reg.r[__RT] = 0;

}





static void rs4300i_sltiu()
{
        PRINT_DEBUGGING_INFO("SLTIU", RT_RS_I);

        if((DWORD)reg.r[__RS] < (DWORD)__I)
                reg.r[__RT] = 1;
        else
                reg.r[__RT] = 0;

}





static void rs4300i_andi()
{
        PRINT_DEBUGGING_INFO("ANDI", RT_RS_I);

        reg.r[__RT] = reg.r[__RS] & (HWORD)__I;

}





static void rs4300i_ori()
{
        PRINT_DEBUGGING_INFO("ORI", RT_RS_I);

        reg.r[__RT] = reg.r[__RS] | (HWORD)__I;

}





static void rs4300i_xori()
{
        PRINT_DEBUGGING_INFO("XORI", RT_RS_I);

        reg.r[__RT] = reg.r[__RS] ^ (HWORD)__I;

}





static void rs4300i_lui()
{
        PRINT_DEBUGGING_INFO("LUI", RT_I);

        reg.r[__RT] = __I << 16;

}





static void rs4300i_cop0()
{
        PRINT_XINST("cop0 instruction");

        cop0_rs_instruction[__RS]();

}





static void rs4300i_cop1()
{
        PRINT_XINST("cop1 instruction");

        cop1_rs_instruction[__RS]();

}





static void rs4300i_cop2()
{
        PRINT_XINST("cop2 instruction");

        cop2_rs_instruction[__RS]();

}





static void rs4300i_beql()
{
        PRINT_DEBUGGING_INFO("BEQL", RS_RT_O);

        if(reg.r[__RS] == reg.r[__RT])
        {
                reg.delay = DO_DELAY;
                reg.pc_delay = __O;
        }
        else
                reg.pc += 4;

}





static void rs4300i_bnel()
{
        PRINT_DEBUGGING_INFO("BNEL", RS_RT_O);

        if(reg.r[__RS] != reg.r[__RT])
        {
                reg.delay = DO_DELAY;
                reg.pc_delay = __O;
        }
        else
                reg.pc += 4;

}





static void rs4300i_blezl()
{
        PRINT_DEBUGGING_INFO("BLEZL", RS_O);

        if(((sDWORD)reg.r[__RS]) <= 0)
        {
                reg.delay = DO_DELAY;
                reg.pc_delay = __O;
        }
        else
                reg.pc += 4;

}





static void rs4300i_bgtzl()
{
        PRINT_DEBUGGING_INFO("BGTZL", RS_O);

        if(((sDWORD)reg.r[__RS]) > 0)
        {
                reg.delay = DO_DELAY;
                reg.pc_delay = __O;
        }
        else
                reg.pc += 4;

}





static void rs4300i_daddi()
{
        sDWORD x, y, z;



        PRINT_DEBUGGING_INFO("DADDI", RT_RS_I);



        x = (sDWORD)reg.r[__RS];
        y = (sDWORD)__I;
        
        z = x + y;

        
        
        if( (x>>63) ^ (y>>63) )   /* different sign ? */
                reg.r[__RT] = z;
        else
        {
                if( (x>>63) ^ (z>>63) )   /* different sign ? */
                        reg.do_or_check_sthg = RS4300I_DO_INTEGER_OVERFLOW_EXCEPTION;
                else
                        reg.r[__RT] = z;
        }

}





static void rs4300i_daddiu()
{
        PRINT_DEBUGGING_INFO("DADDIU", RT_RS_I);


        // reserved instruction exception (in 32bit mode)
        reg.r[__RT] = reg.r[__RS] + __I;

}





static void rs4300i_ldl()
{
        WORD    offset;
        DWORD   data;



        PRINT_DEBUGGING_INFO("LDL", RT_O_B);



        offset = reg.r[__RS] + __I;

        data = doReadMemDoubleWord(offset & 0xfffffff8);

        switch(offset % 8)
        {
            case 0:
                reg.r[__RT] = data;
                break;

            case 1:
                reg.r[__RT]  = (reg.r[__RT] & 0x00000000000000ffLL) + (data << 8);
                break;

            case 2:
                reg.r[__RT]  = (reg.r[__RT] & 0x000000000000ffffLL) + (data << 16);
                break;

            case 3:
                reg.r[__RT]  = (reg.r[__RT] & 0x0000000000ffffffLL) + (data << 24);
                break;

            case 4:
                reg.r[__RT]  = (reg.r[__RT] & 0x00000000ffffffffLL) + (data << 32);
                break;

            case 5:
                reg.r[__RT]  = (reg.r[__RT] & 0x000000ffffffffffLL) + (data << 40);
                break;

            case 6:
                reg.r[__RT]  = (reg.r[__RT] & 0x0000ffffffffffffLL) + (data << 48);
                break;

            case 7:
                reg.r[__RT]  = (reg.r[__RT] & 0x00ffffffffffffffLL) + (data << 56);
                break;

        } /* switch(offset % 8) */



        // tlb miss exception
        // tlb invalid exception
        // bus error exception
        // address error exception
        // reserved instruction exception (vr4300 in 32-bit user or supervisor mode)

}





static void rs4300i_ldr()
{
        WORD    offset;
        DWORD   data;



        PRINT_DEBUGGING_INFO("LDR", RT_O_B);



        offset = reg.r[__RS] + __I;

        data = doReadMemDoubleWord(offset & 0xfffffff8);

        switch(offset % 8)
        {
            case 7:
                reg.r[__RT] = data;
                break;

            case 6:
                reg.r[__RT]  = (reg.r[__RT] & 0xff00000000000000LL) + (data >> 8);
                break;

            case 5:
                reg.r[__RT]  = (reg.r[__RT] & 0xffff000000000000LL) + (data >> 16);
                break;

            case 4:
                reg.r[__RT]  = (reg.r[__RT] & 0xffffff0000000000LL) + (data >> 24);
                break;

            case 3:
                reg.r[__RT]  = (reg.r[__RT] & 0xffffffff00000000LL) + (data >> 32);
                break;

            case 2:
                reg.r[__RT]  = (reg.r[__RT] & 0xffffffffff000000LL) + (data >> 40);
                break;

            case 1:
                reg.r[__RT]  = (reg.r[__RT] & 0xffffffffffff0000LL) + (data >> 48);
                break;

            case 0:
                reg.r[__RT]  = (reg.r[__RT] & 0xffffffffffffff00LL) + (data >> 56);
                break;

        } /* switch(offset % 8) */



        // tlb miss exception
        // tlb invalid exception
        // bus error exception
        // address error exception
        // reserved instruction exception (vr4300 in 32-bit user or supervisor mode)

}





static void rs4300i_lb()
{
        PRINT_DEBUGGING_INFO("LB", RT_O_B);

        reg.r[__RT] = (sDWORD)((sBYTE)doReadMemByte(reg.r[__RS] + __I));

        // exception
      
}



static void rs4300i_lh()
{
        PRINT_DEBUGGING_INFO("LH", RT_O_B);

        reg.r[__RT] = (sDWORD)((sHWORD)doReadMemHalfWord(reg.r[__RS] + __I));

        // exception

}



static void rs4300i_lwl()
{
        DWORD offset;
        WORD  data;



        PRINT_DEBUGGING_INFO("LWL", RT_O_B);

        offset = (DWORD)(reg.r[__RS] + __I);

        data = doReadMemWord(offset & 0xfffffffc);

        switch(offset % 4)
        {
            case 0:
                reg.r[__RT] = (sDWORD)(sWORD)data;
                break;

            case 1:
                reg.r[__RT]  = (sDWORD)(sWORD)((reg.r[__RT] & 0x000000ff) + (data << 8));
                break;

            case 2:
                reg.r[__RT]  = (sDWORD)(sWORD)((reg.r[__RT] & 0x0000ffff) + (data << 16));
                break;

            case 3:
                reg.r[__RT]  = (sDWORD)(sWORD)((reg.r[__RT] & 0x00ffffff) + (data << 24));
                break;
        }

        // exception

}





static void rs4300i_lw()
{
        PRINT_DEBUGGING_INFO("LW", RT_O_B);

        reg.r[__RT] = (sDWORD)((sWORD)doReadMemWord(reg.r[__RS] + __I));

        // exception

}





static void rs4300i_lbu()
{
        PRINT_DEBUGGING_INFO("LBU", RT_O_B);

        reg.r[__RT] = (sDWORD)((BYTE)doReadMemByte(reg.r[__RS] + __I));

}





static void rs4300i_lhu()
{
        PRINT_DEBUGGING_INFO("LHU", RT_O_B);

        reg.r[__RT] = (sDWORD)((HWORD)doReadMemHalfWord(reg.r[__RS] + __I));

        // exception

}





static void rs4300i_lwr()
{
        DWORD offset;
        WORD  data;



        PRINT_DEBUGGING_INFO("LWR", RT_O_B);

        offset = (DWORD)(reg.r[__RS] + __I);

        data = doReadMemWord(offset & 0xfffffffc);
   
        switch(offset % 4)
        {
            case 0:
                reg.r[__RT]  = (reg.r[__RT] & 0xffffff00) + (data >> 24);
                break;

            case 1:
                reg.r[__RT]  = (reg.r[__RT] & 0xffff0000) + (data >> 16);
                break;

            case 2:
                reg.r[__RT]  = (reg.r[__RT] & 0xff000000) + (data >> 8);
                break;

            case 3:
                reg.r[__RT]  = (sDWORD)(sWORD)data;
                break;
        }

        // exception
      
}





static void rs4300i_lwu()
{
        PRINT_DEBUGGING_INFO("LWU", RT_O_B);

        reg.r[__RT] = (sDWORD)((WORD)doReadMemWord(reg.r[__RS] + __I));

        // exception

}





static void rs4300i_sb()
{
        PRINT_DEBUGGING_INFO("SB", RT_O_B);

        doWriteMemByte((BYTE)reg.r[__RT], reg.r[__RS] + __I);

        // exception

}





static void rs4300i_sh()
{
        PRINT_DEBUGGING_INFO("SH", RT_O_B);

        doWriteMemHalfWord((HWORD)reg.r[__RT], reg.r[__RS] + __I);

        // exception

}





static void rs4300i_swl()
{
        DWORD offset;
        WORD  data;
        WORD  old_data;

        PRINT_DEBUGGING_INFO("SWL", RT_O_B);

        offset = (DWORD)reg.r[__RS] + __I;
   
        old_data = doReadMemWord(offset & 0xfffffffc);

        switch(offset % 4)
        {
            case 0:
                data = (WORD)reg.r[__RT];
                break;

            case 1:
                data = (old_data & 0xff000000) + ((WORD)reg.r[__RT] >> 8);
                break;

            case 2:
                data = (old_data & 0xffff0000) + ((WORD)reg.r[__RT] >> 16);
                break;

            case 3:
                data = (old_data & 0xffffff00) + ((WORD)reg.r[__RT] >> 24);
                break;

            default:
                data = 0;   /* to make compiler happy */
        }

        doWriteMemWord(data, offset & 0xfffffffc);

        // exception
   
}





static void rs4300i_sw()
{
        PRINT_DEBUGGING_INFO("SW", RT_O_B);

        doWriteMemWord((WORD)reg.r[__RT], reg.r[__RS] + __I);

        // exception
      
}





static void rs4300i_sdl()
{
        WORD    offset;
        DWORD   data;



        PRINT_DEBUGGING_INFO("SDL", RT_O_B);



        offset = reg.r[__RS] + __I;

        data = doReadMemDoubleWord(offset & 0xfffffff8);

        switch(offset % 8)
        {
            case 0:
                doWriteMemDoubleWord(reg.r[__RT], offset & 0xfffffff8);
                break;

            case 1:
                doWriteMemDoubleWord((data & 0xff00000000000000LL) + (reg.r[__RT] >> 8), offset & 0xfffffff8);
                break;

            case 2:
                doWriteMemDoubleWord((data & 0xffff000000000000LL) + (reg.r[__RT] >> 16), offset & 0xfffffff8);
                break;

            case 3:
                doWriteMemDoubleWord((data & 0xffffff0000000000LL) + (reg.r[__RT] >> 24), offset & 0xfffffff8);
                break;

            case 4:
                doWriteMemDoubleWord((data & 0xffffffff00000000LL) + (reg.r[__RT] >> 32), offset & 0xfffffff8);
                break;

            case 5:
                doWriteMemDoubleWord((data & 0xffffffffff000000LL) + (reg.r[__RT] >> 40), offset & 0xfffffff8);
                break;

            case 6:
                doWriteMemDoubleWord((data & 0xffffffffffff0000LL) + (reg.r[__RT] >> 48), offset & 0xfffffff8);
                break;

            case 7:
                doWriteMemDoubleWord((data & 0xffffffffffffff00LL) + (reg.r[__RT] >> 56), offset & 0xfffffff8);
                break;

        } /* switch(offset % 8) */



        // tlb miss exception
        // tlb invalid exception
        // tlb modification exception
        // bus error exception
        // address error exception
        // reserved instruction exception (vr4300 in 32-bit user or supervisor mode)

}





static void rs4300i_sdr()
{
        WORD    offset;
        DWORD   data;



        PRINT_DEBUGGING_INFO("SDR", RT_O_B);



        offset = reg.r[__RS] + __I;

        data = doReadMemDoubleWord(offset & 0xfffffff8);

        switch(offset % 8)
        {
            case 7:
                doWriteMemDoubleWord(reg.r[__RT], offset & 0xfffffff8);
                break;

            case 6:
                doWriteMemDoubleWord((data & 0x00000000000000ffLL) + (reg.r[__RT] << 8), offset & 0xfffffff8);
                break;

            case 5:
                doWriteMemDoubleWord((data & 0x000000000000ffffLL) + (reg.r[__RT] << 16), offset & 0xfffffff8);
                break;

            case 4:
                doWriteMemDoubleWord((data & 0x0000000000ffffffLL) + (reg.r[__RT] << 24), offset & 0xfffffff8);
                break;

            case 3:
                doWriteMemDoubleWord((data & 0x00000000ffffffffLL) + (reg.r[__RT] << 32), offset & 0xfffffff8);
                break;

            case 2:
                doWriteMemDoubleWord((data & 0x000000ffffffffffLL) + (reg.r[__RT] << 40), offset & 0xfffffff8);
                break;

            case 1:
                doWriteMemDoubleWord((data & 0x0000ffffffffffffLL) + (reg.r[__RT] << 48), offset & 0xfffffff8);
                break;

            case 0:
                doWriteMemDoubleWord((data & 0x00ffffffffffffffLL) + (reg.r[__RT] << 56), offset & 0xfffffff8);
                break;

        } /* switch(offset % 8) */



        // tlb miss exception
        // tlb invalid exception
        // tlb modification exception
        // bus error exception
        // address error exception
        // reserved instruction exception (vr4300 in 32-bit user or supervisor mode)

}





static void rs4300i_swr()
{
        DWORD offset;
        WORD  data;
        WORD  old_data;



        PRINT_DEBUGGING_INFO("SWR", RT_O_B);

        offset = (DWORD)reg.r[__RS] + __I;
   
        old_data = doReadMemWord(offset & 0xfffffffc);
   
        switch(offset % 4)
        {
            case 0:
                data = (old_data & 0x00ffffff) + ((WORD)reg.r[__RT] << 24);
                break;

            case 1:
                data = (old_data & 0x0000ffff) + ((WORD)reg.r[__RT] << 16);
                break;

            case 2:
                data = (old_data & 0x000000ff) + ((WORD)reg.r[__RT] << 8);
                break;

            case 3:
                data = (WORD)reg.r[__RT];
                break;

            default:
                data = 0;   /* to make compiler happy */
        }

        doWriteMemWord(data, offset & 0xfffffffc);

        // exception

}





static void rs4300i_cache()
{
        PRINT_DEBUGGING_INFO("CACHE (IGNORED!)", NOTHING);

}





static void rs4300i_ll()
{
        PRINT_DEBUGGING_INFO("LL", RT_O_B);



        reg.r[__RT] = (sDWORD)(sWORD)doReadMemWord(reg.r[__RS] + __I);

        reg.cpr[0][LLADDR] = (sDWORD)(sWORD)(reg.r[__RS] + __I);

        reg.llbit = 1;



        // tlb miss exception
        // tlb invalid exception
        // bus error exception
        // address error exception

}





static void rs4300i_lwc1()
{
        PRINT_DEBUGGING_INFO("LWC1", FT_O_B);

        reg.cpr[1][__FT] = (sDWORD)((sWORD)doReadMemWord(reg.r[__RS] + __I));

        // exception
      
}





static void rs4300i_lwc2()
{
        PRINT_DEBUGGING_INFO("LWC2", C2_O_B);

        reg.cpr[2][__RT] = (sDWORD)((sWORD)doReadMemWord(reg.r[__RS] + __I));

        // exception
      
}





static void rs4300i_lld()
{
        PRINT_DEBUGGING_INFO("LLD", RT_O_B);



        reg.r[__RT] = doReadMemDoubleWord(reg.r[__RS] + __I);

        reg.cpr[0][LLADDR] = (sDWORD)(sWORD)(reg.r[__RS] + __I);

        reg.llbit = 1;



        // tlb miss exception
        // tlb invalid exception
        // bus error exception
        // address error exception
        // reserved instruction exception (vr4300 in 32-bit user or supervisor mode)

}





static void rs4300i_ldc1()
{
        DWORD value;



        PRINT_DEBUGGING_INFO("LDC1", FT_O_B);

        
        value = doReadMemDoubleWord(reg.r[__RS] + __I);
        
        if(reg.cpr[0][STATUS] & 0x04000000)
        {
                reg.cpr[1][__FT] = value;
        }
        else
        {
                reg.cpr[1][__FT+0] = (sDWORD)(sWORD)value;
                reg.cpr[1][__FT+1] = (sDWORD)(sWORD)(value >> 32);
        }

        // exception
      
}





static void rs4300i_ldc2()
{
        PRINT_DEBUGGING_INFO("LDC2", C2_O_B);

        reg.cpr[2][__RT] = doReadMemDoubleWord(reg.r[__RS] + __I);

        // exception

}





static void rs4300i_ld()
{
        PRINT_DEBUGGING_INFO("LD", RT_O_B);

        reg.r[__RT] = doReadMemDoubleWord(reg.r[__RS] + __I);

        // exception

}





static void rs4300i_sc()
{
        PRINT_DEBUGGING_INFO("SC", RT_O_B);



        if(reg.llbit)
        {
                doWriteMemWord((WORD)reg.r[__RT], reg.r[__RS] + __I);
        
        } /* if(reg.llbit) */

        reg.r[__RT] = (sDWORD)(sBYTE)reg.llbit;



        // tlb miss exception
        // tlb invalid exception
        // tlb modification exception
        // bus error exception
        // address error exception

}





static void rs4300i_swc1()
{
        PRINT_DEBUGGING_INFO("SWC1", FT_O_B);

        doWriteMemWord(reg.cpr[1][__FT], reg.r[__RS] + __I);

        // exception

}





static void rs4300i_swc2()
{
        PRINT_DEBUGGING_INFO("SWC2", C2_O_B);

        doWriteMemWord(reg.cpr[2][__RT], reg.r[__RS] + __I);

        // exception

}





static void rs4300i_scd()
{
        PRINT_DEBUGGING_INFO("SCD", RT_O_B);



        if(reg.llbit)
        {
                doWriteMemDoubleWord(reg.r[__RT], reg.r[__RS] + __I);
        
        } /* if(reg.llbit) */

        reg.r[__RT] = (sDWORD)(sBYTE)reg.llbit;



        // tlb miss exception
        // tlb invalid exception
        // tlb modification exception
        // bus error exception
        // address error exception
        // reserved instruction exception (vr4300 in 32-bit user or supervisor mode)

}





static void rs4300i_sdc1()
{
        DWORD value;



        PRINT_DEBUGGING_INFO("SDC1", FT_O_B);


        if(reg.cpr[0][STATUS] & 0x04000000)
                value = reg.cpr[1][__FT];
        else
                value = (reg.cpr[1][__FT+1] << 32) + reg.cpr[1][__FT+0];
        
        doWriteMemDoubleWord(value, reg.r[__RS] + __I);

        // exception

}





static void rs4300i_sdc2()
{
        PRINT_DEBUGGING_INFO("SDC2", C2_O_B);

        doWriteMemDoubleWord(reg.cpr[2][__RT], reg.r[__RS] + __I);

        // exception

}





static void rs4300i_sd()
{
        PRINT_DEBUGGING_INFO("SD", RT_O_B);

        doWriteMemDoubleWord(reg.r[__RT], reg.r[__RS] + __I);

        // exception

}





static void rs4300i_special_sll()
{
        PRINT_DEBUGGING_INFO("SLL", RD_RT_SA);

        reg.r[__RD] = (sDWORD)(((WORD)reg.r[__RT]) << __SA);

}





static void rs4300i_special_srl()
{
        PRINT_DEBUGGING_INFO("SRL", RD_RT_SA);

        reg.r[__RD] = (sDWORD)(sWORD)((WORD)reg.r[__RT] >> __SA);

}





static void rs4300i_special_sra()
{
        PRINT_DEBUGGING_INFO("SRA", RD_RT_SA);

        reg.r[__RD] = (sDWORD)((sWORD)reg.r[__RT] >> __SA);

}





static void rs4300i_special_sllv()
{
        PRINT_DEBUGGING_INFO("SLLV", RD_RT_RS);

        reg.r[__RD] = (sDWORD)((sWORD)((reg.r[__RT]) << (reg.r[__RS] & 0x1f)));

}





static void rs4300i_special_srlv()
{
        PRINT_DEBUGGING_INFO("SRLV", RD_RT_RS);

        reg.r[__RD] = (sDWORD)(sWORD)((WORD)reg.r[__RT] >> (reg.r[__RS] & 0x1f));

}





static void rs4300i_special_srav()
{
        PRINT_DEBUGGING_INFO("SRAV", RD_RT_RS);

        reg.r[__RD] = (sDWORD)((sWORD)reg.r[__RT] >> (reg.r[__RS] & 0x1f));

}





static void rs4300i_special_jr()
{
        PRINT_DEBUGGING_INFO("JR", RS);

        reg.delay = DO_DELAY;
        reg.pc_delay = reg.r[__RS];

}





static void rs4300i_special_jalr()
{
        PRINT_DEBUGGING_INFO("JALR", RD_RS);

        reg.delay = DO_DELAY;
        reg.pc_delay = reg.r[__RS];
        reg.r[__RD] = reg.pc + 8;

}





static void rs4300i_special_syscall()
{
        PRINT_DEBUGGING_INFO("SYSCALL", NOTHING);

        reg.do_or_check_sthg |= RS4300I_DO_SYSCALL_EXCEPTION;

}





static void rs4300i_special_break()
{
        PRINT_DEBUGGING_INFO("BREAK", NOTHING);

        reg.do_or_check_sthg |= RS4300I_DO_BREAK_EXCEPTION;

}





static void rs4300i_special_sync()
{
        PRINT_DEBUGGING_INFO("SYNC (IGNORED!)", NOTHING);

}





static void rs4300i_special_mfhi()
{
        PRINT_DEBUGGING_INFO("MFHI", RD);

        reg.r[__RD] = reg.hi;

}





static void rs4300i_special_mthi()
{
        PRINT_DEBUGGING_INFO("MTHI", RS);

        reg.hi = reg.r[__RS];
   
}





static void rs4300i_special_mflo()
{
        PRINT_DEBUGGING_INFO("MFLO", RD);

        reg.r[__RD] = reg.lo;
   
}





static void rs4300i_special_mtlo()
{
        PRINT_DEBUGGING_INFO("MTLO", RS);

        reg.lo = reg.r[__RS];
   
}





static void rs4300i_special_dsllv()
{
        PRINT_DEBUGGING_INFO("DSLLV", RD_RT_RS);

        // reserved instruction exception (in 32bit mode)
        reg.r[__RD] = reg.r[__RT] << (reg.r[__RS] & 0x1f);

}





static void rs4300i_special_dsrlv()
{
        PRINT_DEBUGGING_INFO("DSRLV", RD_RT_RS);

        // reserved instruction exception (in 32bit mode)
        reg.r[__RD] = (DWORD)reg.r[__RT] >> (reg.r[__RS] & 0x1f);

}



static void rs4300i_special_dsrav()
{
        PRINT_DEBUGGING_INFO("DSRAV", RD_RT_RS);

        // reserved instruction exception (in 32bit mode)
        reg.r[__RD] = reg.r[__RT] >> (reg.r[__RS] & 0x1f);

}





static void rs4300i_special_mult()
{
        sDWORD temp;



        PRINT_DEBUGGING_INFO("MULT", RS_RT);

        temp = (sDWORD)((sWORD)reg.r[__RS]) * ((sWORD)reg.r[__RT]);
        reg.lo = (sDWORD)(sWORD)(temp);
        reg.hi = (sDWORD)(sWORD)(temp >> 32);

} /* static void rs4300i_special_mult() */





static void rs4300i_special_multu()
{
        DWORD temp;
   

   
        PRINT_DEBUGGING_INFO("MULTU", RS_RT);

        temp = (DWORD)((WORD)reg.r[__RS]) * ((WORD)reg.r[__RT]);
        reg.lo = (sDWORD)(sWORD)(temp);
        reg.hi = (sDWORD)(sWORD)(temp >> 32);

} /* static void rs4300i_special_multu() */





static void rs4300i_special_div()
{
        PRINT_DEBUGGING_INFO("DIV", RS_RT);

        if((sWORD)reg.r[__RT] != 0)
        {
                reg.lo = (sDWORD)(sWORD)((sWORD)reg.r[__RS] / (sWORD)reg.r[__RT]);
                reg.hi = (sDWORD)(sWORD)((sWORD)reg.r[__RS] % (sWORD)reg.r[__RT]);
        }

} /* static void rs4300i_special_div() */





static void rs4300i_special_divu()
{
        PRINT_DEBUGGING_INFO("DIVU", RS_RT);

        if((WORD)reg.r[__RT] != 0)
        {
                reg.lo = (sDWORD)(sWORD)((WORD)reg.r[__RS] / (WORD)reg.r[__RT]);
                reg.hi = (sDWORD)(sWORD)((WORD)reg.r[__RS] % (WORD)reg.r[__RT]);
        }

} /* static void rs4300i_special_divu() */





static void rs4300i_special_dmult()
{
        PRINT_DEBUGGING_INFO("DMULT", RS_RT);

        // reserved instruction exception (in 32bit mode)
        reg.lo = reg.r[__RS] * reg.r[__RT];
        reg.hi = 0;

} /* static void rs4300i_special_dmult() */





static void rs4300i_special_dmultu()
{
        PRINT_DEBUGGING_INFO("DMULTU", RS_RT);

        // reserved instruction exception (in 32bit mode)
        reg.lo = (DWORD)reg.r[__RS] * (DWORD)reg.r[__RT];
        reg.hi = 0;

} /* static void rs4300i_special_dmultu() */





static void rs4300i_special_ddiv()
{
        PRINT_DEBUGGING_INFO("DDIV", RS_RT);

        // reserved instruction exception (in 32bit mode)
        if(reg.r[__RT] != 0)
        {
                reg.lo = reg.r[__RS] / reg.r[__RT];
                reg.hi = reg.r[__RS] % reg.r[__RT];
        }

} /* static void rs4300i_special_ddiv() */





static void rs4300i_special_ddivu()
{
        PRINT_DEBUGGING_INFO("DDIVU", RS_RT);

        // reserved instruction exception (in 32bit mode)
        if((DWORD)reg.r[__RT] != 0)
        {
                reg.lo = (DWORD)reg.r[__RS] / (DWORD)reg.r[__RT];
                reg.hi = (DWORD)reg.r[__RS] % (DWORD)reg.r[__RT];
        }

} /* static void rs4300i_special_ddivu() */





static void rs4300i_special_add()
{
        sDWORD x, y, z;



        PRINT_DEBUGGING_INFO("ADD", RD_RS_RT);

        x = (sWORD)reg.r[__RS];
        y = (sWORD)reg.r[__RT];
        
        z = x + y;

        
        
        if((z > 0x7fffffffLL) || (z < -0x80000000LL))
                reg.do_or_check_sthg = RS4300I_DO_INTEGER_OVERFLOW_EXCEPTION;
        else
                reg.r[__RD] = (sDWORD)(sWORD)z;

}





static void rs4300i_special_addu()
{
        PRINT_DEBUGGING_INFO("ADDU", RD_RS_RT);

        reg.r[__RD] = (sDWORD)(sWORD)(reg.r[__RS] + reg.r[__RT]);

}





static void rs4300i_special_sub()
{
        sDWORD x, y, z;



        PRINT_DEBUGGING_INFO("SUB", RD_RS_RT);

        x = (sWORD)reg.r[__RS];
        y = (sWORD)reg.r[__RT];
        
        z = x - y;

        
        
        if((z > 0x7fffffffLL) || (z < -0x80000000LL))
                reg.do_or_check_sthg = RS4300I_DO_INTEGER_OVERFLOW_EXCEPTION;
        else
                reg.r[__RD] = (sDWORD)(sWORD)z;

}





static void rs4300i_special_subu()
{
        PRINT_DEBUGGING_INFO("SUBU", RD_RS_RT);

        reg.r[__RD] = (sDWORD)((sWORD)reg.r[__RS] - (sWORD)reg.r[__RT]);

}





static void rs4300i_special_and()
{
        PRINT_DEBUGGING_INFO("AND", RD_RS_RT);

        reg.r[__RD] = reg.r[__RS] & reg.r[__RT];

}





static void rs4300i_special_or()
{
        PRINT_DEBUGGING_INFO("OR", RD_RS_RT);

        reg.r[__RD] = reg.r[__RS] | reg.r[__RT];

}





static void rs4300i_special_xor()
{
        PRINT_DEBUGGING_INFO("XOR", RD_RS_RT);

        reg.r[__RD] = reg.r[__RS] ^ reg.r[__RT];

}





static void rs4300i_special_nor()
{
        PRINT_DEBUGGING_INFO("NOR", RD_RS_RT);

        reg.r[__RD] = ~(reg.r[__RS] | reg.r[__RT]);
}





static void rs4300i_special_slt()
{
        PRINT_DEBUGGING_INFO("SLT", RD_RS_RT);

        if(reg.r[__RS] < reg.r[__RT])
                reg.r[__RD] = 1;
        else
                reg.r[__RD] = 0;

}





static void rs4300i_special_sltu()
{
        PRINT_DEBUGGING_INFO("SLTU", RD_RS_RT);

        if((DWORD)reg.r[__RS] < (DWORD)reg.r[__RT])
                reg.r[__RD] = 1;
        else
                reg.r[__RD] = 0;

}





static void rs4300i_special_dadd()
{
        sDWORD x, y, z;



        PRINT_DEBUGGING_INFO("DADD", RD_RS_RT);

        // reserved instruction exception (in 32bit mode)
        
        x = (sDWORD)reg.r[__RS];
        y = (sDWORD)reg.r[__RT];
        
        z = x + y;

        
        
        if( (x>>63) ^ (y>>63) )   /* different sign ? */
                reg.r[__RD] = z;
        else
        {
                if( (x>>63) ^ (z>>63) )   /* different sign ? */
                        reg.do_or_check_sthg = RS4300I_DO_INTEGER_OVERFLOW_EXCEPTION;
                else
                        reg.r[__RD] = z;
        }

}





static void rs4300i_special_daddu()
{
        PRINT_DEBUGGING_INFO("DADDU", RD_RS_RT);

        // reserved instruction exception (in 32bit mode)

        reg.r[__RD] = reg.r[__RS] + reg.r[__RT];

}



static void rs4300i_special_dsub()
{
        sDWORD x, y, z;



        PRINT_DEBUGGING_INFO("DSUB", RD_RS_RT);

        // reserved instruction exception (in 32bit mode)
        
        x = (sDWORD)reg.r[__RS];
        y = (sDWORD)reg.r[__RT];
        
        z = x - y;

        if( (x>>63) ^ (y>>63) )   /* different sign ? */
        {
                if( (x>>63) ^ (z>>63) )   /* different sign ? */
                        reg.do_or_check_sthg = RS4300I_DO_INTEGER_OVERFLOW_EXCEPTION;
                else
                        reg.r[__RD] = z;
        }
        else
                reg.r[__RD] = z;

}





static void rs4300i_special_dsubu()
{
        sDWORD temp;



        PRINT_DEBUGGING_INFO("DSUBU", RD_RS_RT);

        // reserved instruction exception (in 32bit mode)
        temp = reg.r[__RS] - reg.r[__RT];
        reg.r[__RD] = temp;

}





static void rs4300i_special_tge()
{
        PRINT_DEBUGGING_INFO("TGE", RS_RT);

        if((sDWORD)reg.r[__RS] >= (sDWORD)reg.r[__RT])
        {
                reg.do_or_check_sthg |= RS4300I_DO_TRAP_EXCEPTION;
        }

}





static void rs4300i_special_tgeu()
{
        PRINT_DEBUGGING_INFO("TGEU", RS_RT);

        if((DWORD)reg.r[__RS] >= (DWORD)reg.r[__RT])
        {
                reg.do_or_check_sthg |= RS4300I_DO_TRAP_EXCEPTION;
        }

}





static void rs4300i_special_tlt()
{
        PRINT_DEBUGGING_INFO("TLT", RS_RT);

        if((sDWORD)reg.r[__RS] < (sDWORD)reg.r[__RT])
        {
                reg.do_or_check_sthg |= RS4300I_DO_TRAP_EXCEPTION;
        }

}





static void rs4300i_special_tltu()
{
        PRINT_DEBUGGING_INFO("TLTU", RS_RT);

        if((DWORD)reg.r[__RS] < (DWORD)reg.r[__RT])
        {
                reg.do_or_check_sthg |= RS4300I_DO_TRAP_EXCEPTION;
        }

}





static void rs4300i_special_teq()
{
        PRINT_DEBUGGING_INFO("TEQ", RS_RT);

        if(reg.r[__RS] == reg.r[__RT])
        {
                reg.do_or_check_sthg |= RS4300I_DO_TRAP_EXCEPTION;
        }

}





static void rs4300i_special_tne()
{
        PRINT_DEBUGGING_INFO("TNE", RS_RT);

        if(reg.r[__RS] != reg.r[__RT])
        {
                reg.do_or_check_sthg |= RS4300I_DO_TRAP_EXCEPTION;
        }

}





static void rs4300i_special_dsll()
{
        PRINT_DEBUGGING_INFO("DSLL", RD_RT_SA);

        // reserved instruction exception (in 32bit mode)
        reg.r[__RD] = reg.r[__RT] << __SA;

}





static void rs4300i_special_dsrl()
{
        PRINT_DEBUGGING_INFO("DSRL", RD_RT_SA);

        // reserved instruction exception (in 32bit mode)
        reg.r[__RD] = (DWORD)reg.r[__RT] >> __SA;

}





static void rs4300i_special_dsra()
{
        PRINT_DEBUGGING_INFO("DSRA", RD_RT_SA);

        // reserved instruction exception (in 32bit mode)
        reg.r[__RD] = reg.r[__RT] >> __SA;

}





static void rs4300i_special_dsll32()
{
        PRINT_DEBUGGING_INFO("DSLL32", RD_RT_SA);

        // reserved instruction exception (in 32bit mode)
        reg.r[__RD] = reg.r[__RT] << (32 + __SA);

}





static void rs4300i_special_dsrl32()
{
        PRINT_DEBUGGING_INFO("DSRL32", RD_RT_SA);

        // reserved instruction exception (in 32bit mode)
        reg.r[__RD] = (DWORD)reg.r[__RT] >> (32 + __SA);

}





static void rs4300i_special_dsra32()
{
        PRINT_DEBUGGING_INFO("DSRA32", RD_RT_SA);

        // reserved instruction exception (in 32bit mode)
        reg.r[__RD] = reg.r[__RT] >> (32 + __SA);

}





static void rs4300i_regimm_bltz()
{
        PRINT_DEBUGGING_INFO("BLTZ", RS_O);

        if(((sDWORD)reg.r[__RS]) < 0)
        {
                reg.delay = DO_DELAY;
                reg.pc_delay = __O;
        }

}





static void rs4300i_regimm_bgez()
{
        PRINT_DEBUGGING_INFO("BGEZ", RS_O);

        if(((sDWORD)reg.r[__RS]) >= 0)
        {
                reg.delay = DO_DELAY;
                reg.pc_delay = __O;
        }

}





static void rs4300i_regimm_bltzl()
{
        PRINT_DEBUGGING_INFO("BLTZL", RS_O);

        if(((sDWORD)reg.r[__RS]) < 0)
        {
                reg.delay = DO_DELAY;
                reg.pc_delay = __O;
        }
        else
                reg.pc += 4;

}





static void rs4300i_regimm_bgezl()
{
        PRINT_DEBUGGING_INFO("BGEZL", RS_O);

        if(((sDWORD)reg.r[__RS]) >= 0)
        {
                reg.delay = DO_DELAY;
                reg.pc_delay = __O;
        }
        else
                reg.pc += 4;

}





static void rs4300i_regimm_tgei()
{
        PRINT_DEBUGGING_INFO("TGEI", RS_I);

        if((sDWORD)reg.r[__RS] >= (sDWORD)(sWORD)__I)
        {
                reg.do_or_check_sthg |= RS4300I_DO_TRAP_EXCEPTION;
        }

}





static void rs4300i_regimm_tgeiu()
{
        PRINT_DEBUGGING_INFO("TGEIU", RS_I);

        if((DWORD)reg.r[__RS] >= (DWORD)(sDWORD)(sWORD)__I)
        {
                reg.do_or_check_sthg |= RS4300I_DO_TRAP_EXCEPTION;
        }

}





static void rs4300i_regimm_tlti()
{
        PRINT_DEBUGGING_INFO("TLTI", RS_I);

        if((sDWORD)reg.r[__RS] < (sDWORD)(sWORD)__I)
        {
                reg.do_or_check_sthg |= RS4300I_DO_TRAP_EXCEPTION;
        }

}





static void rs4300i_regimm_tltiu()
{
        PRINT_DEBUGGING_INFO("TLTIU", RS_I);

        if((DWORD)reg.r[__RS] < (DWORD)(sDWORD)(sWORD)__I)
        {
                reg.do_or_check_sthg |= RS4300I_DO_TRAP_EXCEPTION;
        }

}





static void rs4300i_regimm_teqi()
{
        PRINT_DEBUGGING_INFO("TEQI", RS_I);

        if(reg.r[__RS] == (sDWORD)(sWORD)__I)
        {
                reg.do_or_check_sthg |= RS4300I_DO_TRAP_EXCEPTION;
        }

}





static void rs4300i_regimm_tnei()
{
        PRINT_DEBUGGING_INFO("TNEI", RS_I);

        if(reg.r[__RS] != (DWORD)(sDWORD)(sWORD)__I)
        {
                reg.do_or_check_sthg |= RS4300I_DO_TRAP_EXCEPTION;
        }

}





static void rs4300i_regimm_bltzal()
{
        PRINT_DEBUGGING_INFO("BLTZAL", RS_O);

        reg.r[31] = reg.pc + 8;

        if(((sDWORD)reg.r[__RS]) < 0)
        {
                reg.delay = DO_DELAY;
                reg.pc_delay = __O;
        }

}





static void rs4300i_regimm_bgezal()
{
        PRINT_DEBUGGING_INFO("BGEZAL", RS_O);

        reg.r[31] = reg.pc + 8;

        if(((sDWORD)reg.r[__RS]) >= 0)
        {
                reg.delay = DO_DELAY;
                reg.pc_delay = __O;
        }

}





static void rs4300i_regimm_bltzall()
{
        PRINT_DEBUGGING_INFO("BLTZALL", RS_O);

        reg.r[31] = reg.pc + 8;

        if(((sDWORD)reg.r[__RS]) < 0)
        {
                reg.delay = DO_DELAY;
                reg.pc_delay = __O;
        }
        else
                reg.pc += 4;

}





static void rs4300i_regimm_bgezall()
{
        PRINT_DEBUGGING_INFO("BGEZALL", RS_O);

        reg.r[31] = reg.pc + 8;

        if(((sDWORD)reg.r[__RS]) >= 0)
        {
                reg.delay = DO_DELAY;
                reg.pc_delay = __O;
        }
        else
                reg.pc += 4;

}





/******************************************************************************\
*                                                                              *
*   CoProcessor0 (COP0)                                                        *
*                                                                              *
\******************************************************************************/



static void rs4300i_cop0_rs_mf()
{
        PRINT_DEBUGGING_INFO("MFC0", C0);

        reg.r[__RT] = (sDWORD)(sWORD)reg.cpr[0][__RD];

        //cop0 unusable exception
}





static void rs4300i_cop0_rs_dmf()
{
        PRINT_DEBUGGING_INFO("DMFC0", C0);

        reg.r[__RT] = reg.cpr[0][__RD];

        //cop0 unusable exception
        //reserved instruction exception
}





static void rs4300i_cop0_rs_cf()
{
        PRINT_DEBUGGING_INFO("CFC0", C0C);

        reg.r[__RT] = (sDWORD)reg.ccr[0][__RD];

        //cop0 unusable exception
}





static void rs4300i_cop0_rs_mt()
{
        PRINT_DEBUGGING_INFO("MTC0", C0);

        /* if write to COMPARE reg clr IP7 (timer interrupt) in CAUSE reg*/
        if(__RD == COMPARE)
                reg.cpr[0][CAUSE] &= ~0x00008000;
   
        /* if write to CAUSE reg mask out all bits except IP0 & IP1 */
        if(__RD == CAUSE)
        {
                reg.cpr[0][CAUSE] = reg.r[__RT] & 0x00000300;
                return;
        }
   
        reg.cpr[0][__RD] = reg.r[__RT];
   
        /**
         * if
         *    write to STATUS reg &&
         *    write included any interrupt bits
         *
         * check for cpu interrupts
        **/

        if((__RD == STATUS) && (reg.r[__RT] & 0xff01))
                reg.do_or_check_sthg |= RS4300I_CHECK_CPU_INTERRUPTS;

        //cop0 unusable exception

}





static void rs4300i_cop0_rs_dmt()
{
        PRINT_DEBUGGING_INFO("DMTC0", C0);

        /* if write to COMPARE reg clr IP7 (timer interrupt) in CAUSE reg*/
        if(__RD == COMPARE)
                reg.cpr[0][CAUSE] &= ~0x00008000;

        /* if write to CAUSE reg mask out all bits except IP0 & IP1 */
        if(__RD == CAUSE)
        {
                reg.cpr[0][CAUSE] = reg.r[__RT] & 0x00000300;
                return;
        }
   
        reg.cpr[0][__RD] = reg.r[__RT];

        /*
        ** if
        **    write to STATUS reg &&
        **    write included any interrupt bits
        **
        **    check for rs4300i interrupts
        */
   
        if((__RD == STATUS) && (reg.r[__RT] & 0xff01))
                reg.do_or_check_sthg |= RS4300I_CHECK_CPU_INTERRUPTS;

        //cop0 unusable exception
        //reserved instruction exception
}





static void rs4300i_cop0_rs_ct()
{
        PRINT_DEBUGGING_INFO("CTC0", C0C);

        reg.ccr[0][__RD] = reg.r[__RT];
   
        //cop0 unusable exception
}





static void rs4300i_cop0_rs_bc()
{
        PRINT_XINST("cop0 bc (rt) instruction");

        cop0_rt_instruction[__RT]();
  
}





static void rs4300i_cop0_rs_co()
{
        PRINT_XINST("cop0 co (funct) instruction");

        cop0_instruction[__F]();
   
}





static void rs4300i_cop0_rt_bcf()
{
        PRINT_NOT_IMPLEMENTED("BCF0");

        CPU_HALT

}





static void rs4300i_cop0_rt_bct()
{
        PRINT_NOT_IMPLEMENTED("BCT0");

        CPU_HALT

}





static void rs4300i_cop0_rt_bcfl()
{
        PRINT_NOT_IMPLEMENTED("BCFL0");

        CPU_HALT

}





static void rs4300i_cop0_rt_bctl()
{
        PRINT_NOT_IMPLEMENTED("BCTL0");

        CPU_HALT

}






static void rs4300i_cop0_tlbr()
{
        DWORD index;



        PRINT_DEBUGGING_INFO("TLBR", NOTHING);



        index = reg.cpr[0][INDEX] & 0x1f;

        reg.cpr[0][PAGEMASK] = reg.tlb[index].hh;
        reg.cpr[0][ENTRYHI]  = reg.tlb[index].hl & ~reg.tlb[index].hh;
        reg.cpr[0][ENTRYLO1] = reg.tlb[index].lh | reg.tlb[index].g;
        reg.cpr[0][ENTRYLO0] = reg.tlb[index].ll | reg.tlb[index].g;



        // coprozessor unusable exception

} /* static void rs4300i_cop0_tlbr() */





static void rs4300i_cop0_tlbwi()
{
        DWORD index;



        PRINT_DEBUGGING_INFO("TLBWI", NOTHING);



        index = reg.cpr[0][INDEX];

        reg.tlb[index].hh = reg.cpr[0][PAGEMASK];
        reg.tlb[index].hl = reg.cpr[0][ENTRYHI] & ~reg.cpr[0][PAGEMASK];
        reg.tlb[index].lh = reg.cpr[0][ENTRYLO1] & 0xfffffffe;
        reg.tlb[index].ll = reg.cpr[0][ENTRYLO0] & 0xfffffffe;
        reg.tlb[index].g  = 0x01 & reg.cpr[0][ENTRYLO1] & reg.cpr[0][ENTRYLO0];



        // coprozessor unusable exception

} /* static void rs4300i_cop0_tlbwi() */





static void rs4300i_cop0_tlbwr()
{
        DWORD index;

        PRINT_DEBUGGING_INFO("TLBWR", NOTHING);



        index = reg.cpr[0][RANDOM];

        reg.tlb[index].hh = reg.cpr[0][PAGEMASK];
        reg.tlb[index].hl = reg.cpr[0][ENTRYHI] & ~reg.cpr[0][PAGEMASK];
        reg.tlb[index].lh = reg.cpr[0][ENTRYLO1] & 0xfffffffe;
        reg.tlb[index].ll = reg.cpr[0][ENTRYLO0] & 0xfffffffe;
        reg.tlb[index].g  = 0x01 & reg.cpr[0][ENTRYLO1] & reg.cpr[0][ENTRYLO0];



        // coprozessor unusable exception

} /* static void rs4300i_cop0_tlbwr() */





static void rs4300i_cop0_tlbp()
{
        int i;

        PRINT_DEBUGGING_INFO("TLBP", NOTHING);



        reg.cpr[0][INDEX] = 0x80000000;

        for(i=0; i<32; i++)
        {
                if
                (
                        ( (reg.tlb[i].hl & ~0x1fff) == (reg.cpr[0][ENTRYHI] & ~0x1fff) )
                        &&
                        (
                                reg.tlb[i].g
                                ||
                                ( (reg.tlb[i].hl & 0xff) == (reg.cpr[0][ENTRYHI] & 0xff) )
                        )
                )
                {
                        reg.cpr[0][INDEX] = i;
                        break;
                }
                
        } /* for(i=0; i<32; i++) */



        // coprozessor unusable exception

} /* static void rs4300i_cop0_tlbp() */










static void rs4300i_cop0_eret()
{
        PRINT_DEBUGGING_INFO("ERET", NOTHING);

        if(reg.cpr[0][STATUS] & 0x0004)                   /* if(ERL exception)           */
        {
                reg.pc = reg.cpr[0][ERROREPC] - 4;             /*    PC = ErrorEPC            */
                reg.cpr[0][STATUS] &= 0xfffffffffffffffbULL;   /*    STATUS -= ERL            */
        }
        else                                              /* else ("normal" exception)   */
        {
                reg.pc = reg.cpr[0][EPC] - 4;                  /*    PC = EPC                 */
                reg.cpr[0][STATUS] &= 0xfffffffffffffffdULL;   /*    STATUS -= EXL            */
        }

        reg.delay = NO_DELAY;
        reg.llbit = 0;

} /* static void rs4300i_cop0_eret() */





/******************************************************************************\
*                                                                              *
*   CoProcessor1 (COP1)                                                        *
*                                                                              *
\******************************************************************************/



static void rs4300i_cop1_rs_mf()
{
        PRINT_DEBUGGING_INFO("MFC1", RT_FS)

        reg.r[__RT] = (sDWORD)(sWORD)FS;

        //cop1 unusable exception

}





static void rs4300i_cop1_rs_dmf()
{
        PRINT_DEBUGGING_INFO("DMFC1", RT_FS)

        reg.r[__RT] = FS;

        //cop1 unusable exception
        //reserved instruction exception

}





static void rs4300i_cop1_rs_cf()
{
        PRINT_DEBUGGING_INFO("CFC1", RT_C1)

        reg.r[__RT] = (sDWORD)(sWORD)reg.ccr[1][__FS];

        //cop1 unusable exception

}





static void rs4300i_cop1_rs_mt()
{
        PRINT_DEBUGGING_INFO("MTC1", RT_FS)

        reg.cpr[1][__FS] = (sDWORD)(sWORD)reg.r[__RT];

        //cop1 unusable exception

}





static void rs4300i_cop1_rs_dmt()
{
        PRINT_DEBUGGING_INFO("DMTC1", RT_FS)

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

}





static void rs4300i_cop1_rs_ct()
{
        PRINT_DEBUGGING_INFO("CFC1", RT_C1)

        reg.ccr[1][__FS] = reg.r[__RT];

        //cop1 unusable exception

}





static void rs4300i_cop1_rs_bc()
{
        PRINT_XINST("cop1 bc (rt) instruction")

        cop1_rt_instruction[__RT]();

}





static void rs4300i_cop1_rs_co()
{
        PRINT_XINST("cop1 co (funct) instruction")

        cop1_instruction[__F]();
   
}





static void rs4300i_cop1_rt_bcf()
{
        PRINT_DEBUGGING_INFO("BCF1", O)

        if(!(reg.ccr[1][31] & 0x00800000))
        {
                reg.delay = DO_DELAY;
                reg.pc_delay = __O;
        }           
 
        //cop1 unusable exception

}





static void rs4300i_cop1_rt_bct()
{
        PRINT_DEBUGGING_INFO("BCT1", O)

        if(reg.ccr[1][31] & 0x00800000)
        {
                reg.delay = DO_DELAY;
                reg.pc_delay = __O;
        }           
 
        //cop1 unusable exception

}





static void rs4300i_cop1_rt_bcfl()
{
        PRINT_DEBUGGING_INFO("BCFL1", O)

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

}





static void rs4300i_cop1_rt_bctl()
{
        PRINT_DEBUGGING_INFO("BCTL1", O)

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

}





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



        PRINT_DEBUGGING_INFO_FPU("ADD.", FD_FS_FT)



        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);
                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

}





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



        PRINT_DEBUGGING_INFO_FPU("SUB.", FD_FS_FT)



        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);
                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

}





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



        PRINT_DEBUGGING_INFO_FPU("MUL.", FD_FS_FT)



        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);
                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

}





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



        PRINT_DEBUGGING_INFO_FPU("DIV.", FD_FS_FT)



        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);
                }
                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

}





static void rs4300i_cop1_sqrt()
{
        DWORD x, z;



        PRINT_DEBUGGING_INFO_FPU("SQRT.", FD_FS)



        x = FS;



        switch(__FMT)
        {
            case FMT_S:
                *((float *)&z) = (float)sqrt((double)*((float *)&x));
                break;

            case FMT_D:
                *((double *)&z) = sqrt(*((double *)&x));
                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


}





static void rs4300i_cop1_abs()
{
        DWORD x, z;



        PRINT_DEBUGGING_INFO_FPU("ABS.", FD_FS)



        x = FS;



        switch(__FMT)
        {
            case FMT_S:
                *((float *)&z) = (float)fabs((double)*((float *)&x));
                break;

            case FMT_D:
                *((double *)&z) = fabs(*((double *)&x));
                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

}





static void rs4300i_cop1_mov()
{
        PRINT_DEBUGGING_INFO_FPU("MOV.", FD_FS)



        switch(__FMT)
        {
            case FMT_S:
            case FMT_D:
                STORE_FPR(FS);
                break;

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

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



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

}





static void rs4300i_cop1_neg()
{
        DWORD z;


        
        PRINT_DEBUGGING_INFO_FPU("NEG.", FD_FS)



        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);
                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

}





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



        PRINT_DEBUGGING_INFO_FPU("ROUND.L.", FD_FS)



        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;
                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;
                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

}





static void rs4300i_cop1_truncl()
{
        DWORD z;


        
        PRINT_DEBUGGING_INFO_FPU("TRUNC.L.", FD_FS)



        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);
                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

}





static void rs4300i_cop1_ceill()
{
        DWORD x, z;



        PRINT_DEBUGGING_INFO_FPU("CEIL.L.", FD_FS)



        x = FS;



        switch(__FMT)
        {
            case FMT_S:
                *((sDWORD *)&z) = (sDWORD)ceil((double)*((float *)&x));
                break;

            case FMT_D:
                *((sDWORD *)&z) = (sDWORD)ceil(*((double *)&x));
                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

}





static void rs4300i_cop1_floorl()
{
        DWORD x, z;



        PRINT_DEBUGGING_INFO_FPU("FLOOR.L.", FD_FS)



        x = FS;



        switch(__FMT)
        {
            case FMT_S:
                *((sDWORD *)&z) = (sDWORD)floor((double)*((float *)&x));
                break;

            case FMT_D:
                *((sDWORD *)&z) = (sDWORD)floor(*((double *)&x));
                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

}





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



        PRINT_DEBUGGING_INFO_FPU("FLOOR.W.", FD_FS)



        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;
                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;
                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

}





static void rs4300i_cop1_truncw()
{
        DWORD z;


        
        PRINT_DEBUGGING_INFO_FPU("TRUNC.W.", FD_FS)



        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);
                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

}





static void rs4300i_cop1_ceilw()
{
        DWORD x, z;



        PRINT_DEBUGGING_INFO_FPU("CEIL.W.", FD_FS)



        x = FS;



        switch(__FMT)
        {
            case FMT_S:
                *((sWORD *)&z) = (sWORD)ceil((double)*((float *)&x));
                break;

            case FMT_D:
                *((sWORD *)&z) = (sWORD)ceil(*((double *)&x));
                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

}





static void rs4300i_cop1_floorw()
{
        DWORD x, z;



        PRINT_DEBUGGING_INFO_FPU("FLOOR.W.", FD_FS)



        x = FS;



        switch(__FMT)
        {
            case FMT_S:
                *((sWORD *)&z) = (sWORD)floor((double)*((float *)&x));
                break;

            case FMT_D:
                *((sWORD *)&z) = (sWORD)floor(*((double *)&x));
                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

}





static void rs4300i_cop1_cvts()
{
        DWORD z;


        
        PRINT_DEBUGGING_INFO_FPU("CVT.S.", FD_FS)



        z = FS;



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

            case FMT_D:
                *((float *)&z) = (float)(*((double *)&z));
                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

}





static void rs4300i_cop1_cvtd()
{
        DWORD z;


        
        PRINT_DEBUGGING_INFO_FPU("CVT.S.", FD_FS)



        z = FS;



        switch(__FMT)
        {
            case FMT_S:
                *((double *)&z) = (double)(*((float *)&z));
                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;

}





static void rs4300i_cop1_cvtw()
{
        DWORD z;


        
        PRINT_DEBUGGING_INFO_FPU("CVT.W.", FD_FS)



        z = FS;



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

            case FMT_D:
                *((sWORD *)&z) = (sWORD)(*((double *)&z));
                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

}





static void rs4300i_cop1_cvtl()
{
        DWORD z;


        
        PRINT_DEBUGGING_INFO_FPU("CVT.L.", FD_FS)



        z = FS;



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

            case FMT_D:
                *((sDWORD *)&z) = (sDWORD)(*((double *)&z));
                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

}





static void rs4300i_cop1_c()
{
        sDWORD x, y;



        PRINT_DEBUGGING_INFO_FPU_COND



        x = FS;
        y = FT;



        switch(__FMT)
        {
            case FMT_S:   /* c.*.s */
                switch(__F)
                {
                    case 0x30:   /* c.f */
                        reg.ccr[1][31] &= ~0x00800000;
                        break;
                        
                    case 0x31:   /* c.un */
                        CPU_HALT
                        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 */
                        CPU_HALT
                        break;
                    
                    case 0x35:   /* c.ult */
                        CPU_HALT
                        break;
                    
                    case 0x36:   /* c.ole */
                        CPU_HALT
                        break;
                    
                    case 0x37:   /* c.ule */
                        CPU_HALT
                        break;
                    
                    case 0x38:   /* c.sf */
                        CPU_HALT
                        break;
                    
                    case 0x39:   /* c.ngle */
                        CPU_HALT
                        break;
                    
                    case 0x3a:   /* c.seq */
                        CPU_HALT
                        break;
                    
                    case 0x3b:   /* c.ngl */
                        CPU_HALT
                        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(__F) */
                
                break;
            
            case FMT_D:   /* c.*.d */
                switch(__F)
                {
                    case 0x30:   /* c.f */
                        reg.ccr[1][31] &= ~0x00800000;
                        break;
                        
                    case 0x31:   /* c.un */
                        CPU_HALT
                        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 */
                        CPU_HALT
                        break;
                    
                    case 0x35:   /* c.ult */
                        CPU_HALT
                        break;
                    
                    case 0x36:   /* c.ole */
                        CPU_HALT
                        break;
                    
                    case 0x37:   /* c.ule */
                        CPU_HALT
                        break;
                    
                    case 0x38:   /* c.sf */
                        CPU_HALT
                        break;
                    
                    case 0x39:   /* c.ngle */
                        CPU_HALT
                        break;
                    
                    case 0x3a:   /* c.seq */
                        CPU_HALT
                        break;
                    
                    case 0x3b:   /* c.ngl */
                        CPU_HALT
                        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(__F) */
                
                break;

            default:
                // exception
                CPU_HALT
                
        } /* switch(__FMT) */

} /* void rs4300i_cop1_c() */






/******************************************************************************\
*                                                                              *
*   CoProcessor2 (COP2)                                                        *
*                                                                              *
\******************************************************************************/

/* 32 cop2 rs instructions */

static void rs4300i_cop2_rs_not_implemented()
{
        PRINT_NOT_IMPLEMENTED("cop2");

        CPU_HALT
}

