/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *   Mupen64plus - bc.c                                                    *
 *   Mupen64Plus homepage: http://code.google.com/p/mupen64plus/           *
 *   Copyright (C) 2002 Hacktarux                                          *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "r4300.h"
#include "ops.h"
#include "macros.h"
#include "interupt.h"
#include "../debugger/debugger.h"

void BC1F(void)
{
   if (check_cop1_unusable()) return;
   PC++;
   delay_slot=1;
#ifdef DBG
            if (debugger_mode) update_debugger(PC->addr);
#endif
   PC->ops();
   update_count();
   delay_slot=0;
   if ((FCR31 & 0x800000)==0 && !skip_jump)
     PC += (PC-2)->f.i.immediate-1;
   last_addr = PC->addr;
   if (next_interupt <= Count) gen_interupt();
}

void BC1F_OUT(void)
{
   if (check_cop1_unusable()) return;
   jump_target = (int)PC->f.i.immediate;
   PC++;
   delay_slot=1;
#ifdef DBG
            if (debugger_mode) update_debugger(PC->addr);
#endif
   PC->ops();
   update_count();
   delay_slot=0;
   if (!skip_jump && (FCR31 & 0x800000)==0)
     jump_to(PC->addr + ((jump_target-1)<<2));
   last_addr = PC->addr;
   if (next_interupt <= Count) gen_interupt();
}

void BC1F_IDLE(void)
{
   int skip;
   if ((FCR31 & 0x800000)==0)
     {
    update_count();
    skip = next_interupt - Count;
    if (skip > 3) Count += (skip & 0xFFFFFFFC);
    else BC1F();
     }
   else BC1F();
}

void BC1T(void)
{
   if (check_cop1_unusable()) return;
   PC++;
   delay_slot=1;
#ifdef DBG
            if (debugger_mode) update_debugger(PC->addr);
#endif
   PC->ops();
   update_count();
   delay_slot=0;
   if ((FCR31 & 0x800000)!=0 && !skip_jump)
     PC += (PC-2)->f.i.immediate-1;
   last_addr = PC->addr;
   if (next_interupt <= Count) gen_interupt();
}

void BC1T_OUT(void)
{
   if (check_cop1_unusable()) return;
   jump_target = (int)PC->f.i.immediate;
   PC++;
   delay_slot=1;
#ifdef DBG
            if (debugger_mode) update_debugger(PC->addr);
#endif
   PC->ops();
   update_count();
   delay_slot=0;
   if (!skip_jump && (FCR31 & 0x800000)!=0)
     jump_to(PC->addr + ((jump_target-1)<<2));
   last_addr = PC->addr;
   if (next_interupt <= Count) gen_interupt();
}

void BC1T_IDLE(void)
{
   int skip;
   if ((FCR31 & 0x800000)!=0)
     {
    update_count();
    skip = next_interupt - Count;
    if (skip > 3) Count += (skip & 0xFFFFFFFC);
    else BC1T();
     }
   else BC1T();
}

void BC1FL(void)
{
   if (check_cop1_unusable()) return;
   if ((FCR31 & 0x800000)==0)
     {
    PC++;
    delay_slot=1;
#ifdef DBG
            if (debugger_mode) update_debugger(PC->addr);
#endif
    PC->ops();
    update_count();
    delay_slot=0;
    if(!skip_jump)
      PC += (PC-2)->f.i.immediate-1;
     }
   else
     PC+=2;
   last_addr = PC->addr;
   if (next_interupt <= Count) gen_interupt();
}

void BC1FL_OUT(void)
{
   if (check_cop1_unusable()) return;
   if ((FCR31 & 0x800000)==0)
     {
    jump_target = (int)PC->f.i.immediate;
    PC++;
    delay_slot=1;
#ifdef DBG
            if (debugger_mode) update_debugger(PC->addr);
#endif
    PC->ops();
    update_count();
    delay_slot=0;
    if (!skip_jump)
      jump_to(PC->addr + ((jump_target-1)<<2));
     }
   else
     PC+=2;
   last_addr = PC->addr;
   if (next_interupt <= Count) gen_interupt();
}

void BC1FL_IDLE(void)
{
   int skip;
   if ((FCR31 & 0x800000)==0)
     {
    update_count();
    skip = next_interupt - Count;
    if (skip > 3) Count += (skip & 0xFFFFFFFC);
    else BC1FL();
     }
   else BC1FL();
}

void BC1TL(void)
{
   if (check_cop1_unusable()) return;
   if ((FCR31 & 0x800000)!=0)
     {
    PC++;
    delay_slot=1;
#ifdef DBG
            if (debugger_mode) update_debugger(PC->addr);
#endif
    PC->ops();
    update_count();
    delay_slot=0;
    if(!skip_jump)
      PC += (PC-2)->f.i.immediate-1;
     }
   else
     PC+=2;
   last_addr = PC->addr;
   if (next_interupt <= Count) gen_interupt();
}

void BC1TL_OUT(void)
{
   if (check_cop1_unusable()) return;
   if ((FCR31 & 0x800000)!=0)
     {
    jump_target = (int)PC->f.i.immediate;
    PC++;
    delay_slot=1;
#ifdef DBG
            if (debugger_mode) update_debugger(PC->addr);
#endif
    PC->ops();
    update_count();
    delay_slot=0;
    if (!skip_jump)
      jump_to(PC->addr + ((jump_target-1)<<2));
     }
   else
     PC+=2;
   last_addr = PC->addr;
   if (next_interupt <= Count) gen_interupt();
}

void BC1TL_IDLE(void)
{
   int skip;
   if ((FCR31 & 0x800000)!=0)
     {
    update_count();
    skip = next_interupt - Count;
    if (skip > 3) Count += (skip & 0xFFFFFFFC);
    else BC1TL();
     }
   else BC1TL();
}

