pcsx2/FPU.c

175 lines
5.3 KiB
C

/* Pcsx2 - Pc Ps2 Emulator
* Copyright (C) 2002-2003 Pcsx2 Team
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <math.h>
#include "Common.h"
#include "R5900.h"
#include "InterTables.h"
// Helper Macros
//****************************************************************
#define _Ft_ ( ( cpuRegs.code >> 16 ) & 0x1F )
#define _Fs_ ( ( cpuRegs.code >> 11 ) & 0x1F )
#define _Fd_ ( ( cpuRegs.code >> 6 ) & 0x1F )
#define _FtValf_ fpuRegs.fpr[ _Ft_ ].f
#define _FsValf_ fpuRegs.fpr[ _Fs_ ].f
#define _FdValf_ fpuRegs.fpr[ _Fd_ ].f
#define _FAValf_ fpuRegs.ACC.f
#define _ContVal_ fpuRegs.fprc[ 31 ]
// Testing
#define _FtValUl_ fpuRegs.fpr[ _Ft_ ].UL
#define _FsValUl_ fpuRegs.fpr[ _Fs_ ].UL
#define _FdValUl_ fpuRegs.fpr[ _Fd_ ].UL
#define _FAValUl_ fpuRegs.ACC.UL
//****************************************************************
void COP1() {
#ifdef FPU_LOG
FPU_LOG("%s\n", disR5900F(cpuRegs.code, cpuRegs.pc));
#endif
Int_COP1PrintTable[_Rs_]();
}
/*********************************************************
* Load and store for COP1 *
* Format: OP rt, offset(base) *
*********************************************************/
void LWC1() {
s32 addr;
addr = cpuRegs.GPR.r[_Rs_].UL[0] + (s16)(cpuRegs.code);// ((cpuRegs.code & 0x8000 ? 0xFFFF8000 : 0)| (cpuRegs.code & 0x7fff));
memRead32(addr, &fpuRegs.fpr[_Rt_].UL);
}
void SWC1() {
s32 addr;
addr = cpuRegs.GPR.r[_Rs_].UL[0] + (s16)(cpuRegs.code);//((cpuRegs.code & 0x8000 ? 0xFFFF8000 : 0)| (cpuRegs.code & 0x7fff));
memWrite32(addr, fpuRegs.fpr[_Rt_].UL);
}
void COP1_BC1() {
Int_COP1BC1PrintTable[_Rt_]();
}
void COP1_S() {
Int_COP1SPrintTable[_Funct_]();
}
void COP1_W() {
Int_COP1WPrintTable[_Funct_]();
}
void COP1_Unknown() {
#ifdef FPU_LOG
FPU_LOG("Unknown FPU opcode called\n");
#endif
}
void MFC1() {
if ( !_Rt_ ) return;
cpuRegs.GPR.r[_Rt_].UD[0] = (s32)_FsValUl_;
}
void CFC1() {
if ( !_Rt_ || ( _Fs_ != 0 && _Fs_ != 31 ) ) return;
cpuRegs.GPR.r[_Rt_].UD[0] = (s32)fpuRegs.fprc[_Fs_];
}
void MTC1() {
_FsValUl_ = cpuRegs.GPR.r[_Rt_].UL[0];
}
void CTC1() {
if(_Fs_!=31) return;
fpuRegs.fprc[_Fs_] = cpuRegs.GPR.r[_Rt_].UL[0];
}
#define C_cond_S(cond) \
_ContVal_ = ( _FsValf_ cond _FtValf_ ) ? \
( _ContVal_ | 0x00800000 ) : \
( _ContVal_ & ~0x00800000 );
void C_F() { _ContVal_ &= ~0x00800000;} //clears C regardless
void C_EQ() { C_cond_S(==); }
void C_LT() { C_cond_S(<); }
void C_LE() { C_cond_S(<=); }
#define BC1(cond) \
if ( ( _ContVal_ & 0x00800000 ) cond 0 ) { \
intDoBranch( _BranchTarget_ ); \
}
void BC1F() { BC1(==); }
void BC1T() { BC1(!=); }
#define BC1L(cond) \
if ( ( _ContVal_ & 0x00800000 ) cond 0 ) { \
intDoBranch( _BranchTarget_ ); \
} else cpuRegs.pc += 4;
void BC1FL() { BC1L(==); } // Equal to 0
void BC1TL() { BC1L(!=); } // different from 0
void ADD_S() { _FdValf_ = _FsValf_ + _FtValf_; }
void SUB_S() { _FdValf_ = _FsValf_ - _FtValf_; }
void MUL_S() { _FdValf_ = _FsValf_ * _FtValf_; }
void MOV_S() { _FdValf_ = _FsValf_; }
void NEG_S() { _FdValf_ = -_FsValf_; }
void ADDA_S() { _FAValf_ = _FsValf_ + _FtValf_; }
void SUBA_S() { _FAValf_ = _FsValf_ - _FtValf_; }
void MULA_S() { _FAValf_ = _FsValf_ * _FtValf_; }
void MADD_S() { _FdValf_ = _FAValf_ + ( _FsValf_ * _FtValf_ ); }
void MSUB_S() { _FdValf_ = _FAValf_ - ( _FsValf_ * _FtValf_ ); }
void MADDA_S() { _FAValf_ += _FsValf_ * _FtValf_; }
void MSUBA_S() { _FAValf_ -= _FsValf_ * _FtValf_; }
void ABS_S() { _FdValf_ = fpufabsf(_FsValf_); }
void MAX_S() { _FdValf_ = max( _FsValf_, _FtValf_ ); }
void MIN_S() { _FdValf_ = min( _FsValf_, _FtValf_ ); }
void DIV_S() { if ( _FtValf_ ) { _FdValf_ = _FsValf_ / _FtValf_; } }
void SQRT_S() {
//if ( _FtValf_ >= 0.0f ) { _FdValf_ = fpusqrtf( _FtValf_ ); }
//else {
_FdValf_ = fpusqrtf(fpufabsf(_FtValf_));
//}
}
void CVT_S() { _FdValf_ = (float)(s32)_FsValUl_; }
void CVT_W() {
if ( ( _FsValUl_ & 0x7F800000 ) <= 0x4E800000 ) { _FdValUl_ = (s32)(float)_FsValf_; }
else if ( _FsValUl_ & 0x80000000 ) { _FdValUl_ = 0x80000000; }
else { _FdValUl_ = 0x7fffffff; }
}
void RSQRT_S() {
if ( _FtValf_ >= 0.0f ) {
float tmp = fpusqrtf( _FtValf_ );
if ( tmp != 0 ) { _FdValf_ = _FsValf_ / tmp; }
}
}
//3322 2222 2222 1111 1111 1100 0000 0000
//1098 7654 3210 9876 5432 1098 7654 3210
//0000 0000 0000 0000 0000 0000 0000 0000