2012-11-01 16:19:01 +01:00
// Copyright (c) 2012- PPSSPP Project.
// 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
2012-11-04 23:01:49 +01:00
// the Free Software Foundation, version 2.0 or later versions.
2012-11-01 16:19:01 +01:00
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
2013-05-18 02:03:16 -07:00
# include "Core/Reporting.h"
# include "Core/MIPS/MIPS.h"
# include "Core/MIPS/MIPSVFPUUtils.h"
2012-11-01 16:19:01 +01:00
# include <limits>
2014-01-01 22:31:03 +02:00
# include <stdio.h>
2012-11-01 16:19:01 +01:00
2013-11-27 22:45:17 +01:00
# define V(i) (currentMIPS->v[voffset[i]])
# define VI(i) (currentMIPS->vi[voffset[i]])
2012-11-01 16:19:01 +01:00
2013-01-25 19:50:30 +01:00
void GetVectorRegs ( u8 regs [ 4 ] , VectorSize N , int vectorReg ) {
int mtx = ( vectorReg > > 2 ) & 7 ;
int col = vectorReg & 3 ;
int row = 0 ;
int length = 0 ;
int transpose = ( vectorReg > > 5 ) & 1 ;
2013-02-15 23:09:02 +01:00
switch ( N ) {
2013-01-25 19:50:30 +01:00
case V_Single : transpose = 0 ; row = ( vectorReg > > 5 ) & 3 ; length = 1 ; break ;
case V_Pair : row = ( vectorReg > > 5 ) & 2 ; length = 2 ; break ;
case V_Triple : row = ( vectorReg > > 6 ) & 1 ; length = 3 ; break ;
case V_Quad : row = ( vectorReg > > 5 ) & 2 ; length = 4 ; break ;
}
2013-02-15 23:09:02 +01:00
for ( int i = 0 ; i < length ; i + + ) {
2013-01-25 19:50:30 +01:00
int index = mtx * 4 ;
if ( transpose )
index + = ( ( row + i ) & 3 ) + col * 32 ;
else
index + = col + ( ( row + i ) & 3 ) * 32 ;
regs [ i ] = index ;
}
}
void GetMatrixRegs ( u8 regs [ 16 ] , MatrixSize N , int matrixReg ) {
int mtx = ( matrixReg > > 2 ) & 7 ;
int col = matrixReg & 3 ;
int row = 0 ;
int side = 0 ;
2013-02-15 23:09:02 +01:00
switch ( N ) {
2013-01-25 19:50:30 +01:00
case M_2x2 : row = ( matrixReg > > 5 ) & 2 ; side = 2 ; break ;
case M_3x3 : row = ( matrixReg > > 6 ) & 1 ; side = 3 ; break ;
case M_4x4 : row = ( matrixReg > > 5 ) & 2 ; side = 4 ; break ;
}
int transpose = ( matrixReg > > 5 ) & 1 ;
2013-02-15 23:09:02 +01:00
for ( int i = 0 ; i < side ; i + + ) {
for ( int j = 0 ; j < side ; j + + ) {
2013-01-25 19:50:30 +01:00
int index = mtx * 4 ;
if ( transpose )
index + = ( ( row + i ) & 3 ) + ( ( col + j ) & 3 ) * 32 ;
else
index + = ( ( col + j ) & 3 ) + ( ( row + i ) & 3 ) * 32 ;
regs [ j * 4 + i ] = index ;
}
}
}
2013-02-15 23:09:02 +01:00
void ReadVector ( float * rd , VectorSize size , int reg ) {
2013-05-18 01:58:28 -07:00
const int mtx = ( reg > > 2 ) & 7 ;
const int col = reg & 3 ;
int row = 0 ;
int length = 0 ;
int transpose = ( reg > > 5 ) & 1 ;
2012-11-01 16:19:01 +01:00
2013-05-18 01:58:28 -07:00
switch ( size ) {
case V_Single : transpose = 0 ; row = ( reg > > 5 ) & 3 ; length = 1 ; break ;
case V_Pair : row = ( reg > > 5 ) & 2 ; length = 2 ; break ;
case V_Triple : row = ( reg > > 6 ) & 1 ; length = 3 ; break ;
case V_Quad : row = ( reg > > 5 ) & 2 ; length = 4 ; break ;
}
2012-11-01 16:19:01 +01:00
2013-05-18 01:58:28 -07:00
u32 * rdu = ( u32 * ) rd ;
2013-02-15 22:56:38 +01:00
if ( transpose ) {
2013-05-18 01:58:28 -07:00
const int base = mtx * 4 + col * 32 ;
2013-02-15 22:56:38 +01:00
for ( int i = 0 ; i < length ; i + + )
2013-05-18 01:58:28 -07:00
rdu [ i ] = VI ( base + ( ( row + i ) & 3 ) ) ;
2013-02-15 22:56:38 +01:00
} else {
2013-05-18 01:58:28 -07:00
const int base = mtx * 4 + col ;
2013-02-15 22:56:38 +01:00
for ( int i = 0 ; i < length ; i + + )
2013-05-18 01:58:28 -07:00
rdu [ i ] = VI ( base + ( ( row + i ) & 3 ) * 32 ) ;
2013-02-15 22:56:38 +01:00
}
2012-11-01 16:19:01 +01:00
}
2013-02-15 23:09:02 +01:00
void WriteVector ( const float * rd , VectorSize size , int reg ) {
2013-05-18 01:58:28 -07:00
const int mtx = ( reg > > 2 ) & 7 ;
const int col = reg & 3 ;
int row = 0 ;
int length = 0 ;
int transpose = ( reg > > 5 ) & 1 ;
2012-11-01 16:19:01 +01:00
2013-05-18 01:58:28 -07:00
switch ( size ) {
case V_Single : transpose = 0 ; row = ( reg > > 5 ) & 3 ; length = 1 ; break ;
case V_Pair : row = ( reg > > 5 ) & 2 ; length = 2 ; break ;
case V_Triple : row = ( reg > > 6 ) & 1 ; length = 3 ; break ;
case V_Quad : row = ( reg > > 5 ) & 2 ; length = 4 ; break ;
}
2012-11-01 16:19:01 +01:00
2013-05-18 01:58:28 -07:00
u32 * rdu = ( u32 * ) rd ;
2013-02-15 22:56:38 +01:00
if ( currentMIPS - > VfpuWriteMask ( ) = = 0 ) {
if ( transpose ) {
2013-05-18 01:58:28 -07:00
const int base = mtx * 4 + col * 32 ;
2013-02-15 22:56:38 +01:00
for ( int i = 0 ; i < length ; i + + )
2013-05-18 01:58:28 -07:00
VI ( base + ( ( row + i ) & 3 ) ) = rdu [ i ] ;
2013-02-15 22:56:38 +01:00
} else {
2013-05-18 01:58:28 -07:00
const int base = mtx * 4 + col ;
2013-02-15 22:56:38 +01:00
for ( int i = 0 ; i < length ; i + + )
2013-05-18 01:58:28 -07:00
VI ( base + ( ( row + i ) & 3 ) * 32 ) = rdu [ i ] ;
2013-02-15 22:56:38 +01:00
}
} else {
2013-02-15 23:09:02 +01:00
for ( int i = 0 ; i < length ; i + + ) {
if ( ! currentMIPS - > VfpuWriteMask ( i ) ) {
2013-02-15 22:56:38 +01:00
int index = mtx * 4 ;
if ( transpose )
index + = ( ( row + i ) & 3 ) + col * 32 ;
else
index + = col + ( ( row + i ) & 3 ) * 32 ;
2013-05-18 01:58:28 -07:00
VI ( index ) = rdu [ i ] ;
2013-02-15 22:56:38 +01:00
}
}
}
2012-11-01 16:19:01 +01:00
}
2013-02-15 23:09:02 +01:00
void ReadMatrix ( float * rd , MatrixSize size , int reg ) {
2012-11-01 16:19:01 +01:00
int mtx = ( reg > > 2 ) & 7 ;
int col = reg & 3 ;
int row = 0 ;
int side = 0 ;
2013-02-15 23:09:02 +01:00
switch ( size ) {
2012-11-01 16:19:01 +01:00
case M_2x2 : row = ( reg > > 5 ) & 2 ; side = 2 ; break ;
case M_3x3 : row = ( reg > > 6 ) & 1 ; side = 3 ; break ;
case M_4x4 : row = ( reg > > 5 ) & 2 ; side = 4 ; break ;
}
2013-05-18 01:58:28 -07:00
int transpose = ( reg > > 5 ) & 1 ;
2012-11-01 16:19:01 +01:00
2013-02-15 23:09:02 +01:00
for ( int i = 0 ; i < side ; i + + ) {
for ( int j = 0 ; j < side ; j + + ) {
2012-11-01 16:19:01 +01:00
int index = mtx * 4 ;
if ( transpose )
index + = ( ( row + i ) & 3 ) + ( ( col + j ) & 3 ) * 32 ;
else
index + = ( ( col + j ) & 3 ) + ( ( row + i ) & 3 ) * 32 ;
rd [ j * 4 + i ] = V ( index ) ;
}
}
}
2013-02-15 23:09:02 +01:00
void WriteMatrix ( const float * rd , MatrixSize size , int reg ) {
2012-11-01 16:19:01 +01:00
int mtx = ( reg > > 2 ) & 7 ;
int col = reg & 3 ;
int row = 0 ;
int side = 0 ;
2013-02-15 23:09:02 +01:00
switch ( size ) {
2012-11-01 16:19:01 +01:00
case M_2x2 : row = ( reg > > 5 ) & 2 ; side = 2 ; break ;
case M_3x3 : row = ( reg > > 6 ) & 1 ; side = 3 ; break ;
case M_4x4 : row = ( reg > > 5 ) & 2 ; side = 4 ; break ;
}
2013-02-18 12:59:41 -08:00
int transpose = ( reg > > 5 ) & 1 ;
if ( currentMIPS - > VfpuWriteMask ( ) ! = 0 ) {
2013-05-18 02:03:16 -07:00
ERROR_LOG_REPORT ( CPU , " Write mask used with vfpu matrix instruction. " ) ;
2013-02-18 12:59:41 -08:00
}
2012-11-01 16:19:01 +01:00
2013-02-15 23:09:02 +01:00
for ( int i = 0 ; i < side ; i + + ) {
for ( int j = 0 ; j < side ; j + + ) {
2013-02-15 22:56:38 +01:00
// Hm, I wonder if this should affect matrices at all.
2013-02-18 12:59:41 -08:00
if ( j ! = side - 1 | | ! currentMIPS - > VfpuWriteMask ( i ) )
2012-11-01 16:19:01 +01:00
{
2013-02-18 12:59:41 -08:00
int index = mtx * 4 ;
2012-11-01 16:19:01 +01:00
if ( transpose )
2013-02-18 12:59:41 -08:00
index + = ( ( row + i ) & 3 ) + ( ( col + j ) & 3 ) * 32 ;
else
index + = ( ( col + j ) & 3 ) + ( ( row + i ) & 3 ) * 32 ;
V ( index ) = rd [ j * 4 + i ] ;
2012-11-01 16:19:01 +01:00
}
}
}
}
int GetNumVectorElements ( VectorSize sz )
{
switch ( sz )
{
case V_Single : return 1 ;
case V_Pair : return 2 ;
case V_Triple : return 3 ;
case V_Quad : return 4 ;
2013-05-18 02:03:16 -07:00
default : return 0 ;
2012-11-01 16:19:01 +01:00
}
}
VectorSize GetHalfVectorSize ( VectorSize sz )
{
switch ( sz )
{
case V_Pair : return V_Single ;
case V_Quad : return V_Pair ;
2013-05-18 02:03:16 -07:00
default :
return V_Single ;
2012-11-01 16:19:01 +01:00
}
}
2013-11-29 09:59:59 -08:00
VectorSize GetDoubleVectorSize ( VectorSize sz )
{
switch ( sz )
{
case V_Single : return V_Pair ;
case V_Pair : return V_Quad ;
default :
return V_Pair ;
}
}
2013-08-24 14:43:49 -07:00
VectorSize GetVecSize ( MIPSOpcode op )
2012-11-01 16:19:01 +01:00
{
int a = ( op > > 7 ) & 1 ;
int b = ( op > > 15 ) & 1 ;
a + = ( b < < 1 ) ;
switch ( a )
{
case 0 : return V_Single ;
case 1 : return V_Pair ;
case 2 : return V_Triple ;
case 3 : return V_Quad ;
default : return V_Quad ;
}
}
2013-08-24 14:43:49 -07:00
MatrixSize GetMtxSize ( MIPSOpcode op )
2012-11-01 16:19:01 +01:00
{
int a = ( op > > 7 ) & 1 ;
int b = ( op > > 15 ) & 1 ;
a + = ( b < < 1 ) ;
switch ( a )
{
2013-12-10 13:06:57 +01:00
case 0 : return M_4x4 ; // This error pretty much only happens in disassembly of junk: // ERROR_LOG_REPORT(CPU, "Unexpected matrix size 1x1."); return M_2x2;
2012-11-01 16:19:01 +01:00
case 1 : return M_2x2 ;
case 2 : return M_3x3 ;
case 3 : return M_4x4 ;
default : return M_4x4 ;
}
}
int GetMatrixSide ( MatrixSize sz )
{
switch ( sz )
{
case M_2x2 : return 2 ;
case M_3x3 : return 3 ;
case M_4x4 : return 4 ;
default : return 0 ;
}
}
const char * GetVectorNotation ( int reg , VectorSize size )
{
static char hej [ 4 ] [ 16 ] ;
static int yo = 0 ; yo + + ; yo & = 3 ;
int mtx = ( reg > > 2 ) & 7 ;
int col = reg & 3 ;
int row = 0 ;
int transpose = ( reg > > 5 ) & 1 ;
char c ;
switch ( size )
{
case V_Single : transpose = 0 ; c = ' S ' ; row = ( reg > > 5 ) & 3 ; break ;
case V_Pair : c = ' C ' ; row = ( reg > > 5 ) & 2 ; break ;
case V_Triple : c = ' C ' ; row = ( reg > > 6 ) & 1 ; break ;
case V_Quad : c = ' C ' ; row = ( reg > > 5 ) & 2 ; break ;
2013-10-26 18:31:14 -07:00
default : c = ' ? ' ; break ;
2012-11-01 16:19:01 +01:00
}
if ( transpose & & c = = ' C ' ) c = ' R ' ;
2013-02-17 15:11:14 -08:00
if ( transpose )
sprintf ( hej [ yo ] , " %c%i%i%i " , c , mtx , row , col ) ;
else
sprintf ( hej [ yo ] , " %c%i%i%i " , c , mtx , col , row ) ;
2012-11-01 16:19:01 +01:00
return hej [ yo ] ;
}
const char * GetMatrixNotation ( int reg , MatrixSize size )
{
static char hej [ 4 ] [ 16 ] ;
static int yo = 0 ; yo + + ; yo & = 3 ;
int mtx = ( reg > > 2 ) & 7 ;
int col = reg & 3 ;
int row = 0 ;
int transpose = ( reg > > 5 ) & 1 ;
char c ;
switch ( size )
{
case M_2x2 : c = ' M ' ; row = ( reg > > 5 ) & 2 ; break ;
case M_3x3 : c = ' M ' ; row = ( reg > > 6 ) & 1 ; break ;
case M_4x4 : c = ' M ' ; row = ( reg > > 5 ) & 2 ; break ;
2013-10-26 18:31:14 -07:00
default : c = ' ? ' ; break ;
2012-11-01 16:19:01 +01:00
}
if ( transpose & & c = = ' M ' ) c = ' E ' ;
sprintf ( hej [ yo ] , " %c%i%i%i " , c , mtx , col , row ) ;
return hej [ yo ] ;
}
float Float16ToFloat32 ( unsigned short l )
{
union float2int {
unsigned int i ;
float f ;
} float2int ;
unsigned short float16 = l ;
unsigned int sign = ( float16 > > VFPU_SH_FLOAT16_SIGN ) & VFPU_MASK_FLOAT16_SIGN ;
int exponent = ( float16 > > VFPU_SH_FLOAT16_EXP ) & VFPU_MASK_FLOAT16_EXP ;
unsigned int fraction = float16 & VFPU_MASK_FLOAT16_FRAC ;
float signf = ( sign = = 1 ) ? - 1.0f : 1.0f ;
float f ;
if ( exponent = = VFPU_FLOAT16_EXP_MAX )
{
if ( fraction = = 0 )
f = std : : numeric_limits < float > : : infinity ( ) ; //(*info->fprintf_func) (info->stream, "%cInf", signchar);
else
f = std : : numeric_limits < float > : : quiet_NaN ( ) ; //(*info->fprintf_func) (info->stream, "%cNaN", signchar);
}
else if ( exponent = = 0 & & fraction = = 0 )
{
f = 0.0f * signf ;
}
else
{
if ( exponent = = 0 )
{
do
{
fraction < < = 1 ;
exponent - - ;
}
while ( ! ( fraction & ( VFPU_MASK_FLOAT16_FRAC + 1 ) ) ) ;
fraction & = VFPU_MASK_FLOAT16_FRAC ;
}
/* Convert to 32-bit single-precision IEEE754. */
float2int . i = sign < < 31 ;
float2int . i | = ( exponent + 112 ) < < 23 ;
float2int . i | = fraction < < 13 ;
f = float2int . f ;
}
return f ;
}