2012-11-01 15:19:01 +00: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 22:01:49 +00:00
|
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
2012-11-01 15:19:01 +00: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-07-27 20:14:01 +00:00
|
|
|
#include <cmath>
|
|
|
|
#include <limits>
|
|
|
|
|
|
|
|
#include "math/math_util.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
#include "Common.h"
|
2013-04-26 21:58:20 +00:00
|
|
|
#include "Core/MIPS/MIPS.h"
|
|
|
|
#include "Core/MIPS/MIPSTables.h"
|
|
|
|
#include "Core/MIPS/MIPSDebugInterface.h"
|
|
|
|
#include "Core/MIPS/MIPSVFPUUtils.h"
|
|
|
|
#include "Core/MIPS/JitCommon/JitBlockCache.h"
|
2013-08-12 02:33:52 +00:00
|
|
|
#include "Core/Reporting.h"
|
2013-04-26 21:58:20 +00:00
|
|
|
#include "Core/System.h"
|
|
|
|
#include "Core/HLE/sceDisplay.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2012-11-26 03:25:14 +00:00
|
|
|
#if defined(ARM)
|
2013-01-07 21:33:09 +00:00
|
|
|
#include "ARM/ArmJit.h"
|
2013-08-17 11:42:33 +00:00
|
|
|
#elif defined(PPC)
|
|
|
|
#include "PPC/PpcJit.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
#else
|
|
|
|
#include "x86/Jit.h"
|
|
|
|
#endif
|
2013-04-26 21:58:20 +00:00
|
|
|
#include "Core/MIPS/JitCommon/JitCommon.h"
|
|
|
|
#include "Core/CoreTiming.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
MIPSState mipsr4k;
|
|
|
|
MIPSState *currentMIPS = &mipsr4k;
|
|
|
|
MIPSDebugInterface debugr4k(&mipsr4k);
|
|
|
|
MIPSDebugInterface *currentDebugMIPS = &debugr4k;
|
|
|
|
|
2013-07-27 20:14:01 +00:00
|
|
|
|
|
|
|
#ifndef M_LOG2E
|
|
|
|
#define M_E 2.71828182845904523536f
|
|
|
|
#define M_LOG2E 1.44269504088896340736f
|
|
|
|
#define M_LOG10E 0.434294481903251827651f
|
|
|
|
#define M_LN2 0.693147180559945309417f
|
|
|
|
#define M_LN10 2.30258509299404568402f
|
|
|
|
#undef M_PI
|
|
|
|
#define M_PI 3.14159265358979323846f
|
|
|
|
#define M_PI_2 1.57079632679489661923f
|
|
|
|
#define M_PI_4 0.785398163397448309616f
|
|
|
|
#define M_1_PI 0.318309886183790671538f
|
|
|
|
#define M_2_PI 0.636619772367581343076f
|
|
|
|
#define M_2_SQRTPI 1.12837916709551257390f
|
|
|
|
#define M_SQRT2 1.41421356237309504880f
|
|
|
|
#define M_SQRT1_2 0.707106781186547524401f
|
|
|
|
#endif
|
|
|
|
|
2013-08-25 02:31:12 +00:00
|
|
|
const float cst_constants[32] = {
|
2013-07-27 20:14:01 +00:00
|
|
|
0,
|
|
|
|
std::numeric_limits<float>::max(), // all these are verified on real PSP
|
|
|
|
sqrtf(2.0f),
|
|
|
|
sqrtf(0.5f),
|
|
|
|
2.0f/sqrtf((float)M_PI),
|
|
|
|
2.0f/(float)M_PI,
|
|
|
|
1.0f/(float)M_PI,
|
|
|
|
(float)M_PI/4,
|
|
|
|
(float)M_PI/2,
|
|
|
|
(float)M_PI,
|
|
|
|
(float)M_E,
|
|
|
|
(float)M_LOG2E,
|
|
|
|
(float)M_LOG10E,
|
|
|
|
(float)M_LN2,
|
|
|
|
(float)M_LN10,
|
|
|
|
2*(float)M_PI,
|
|
|
|
(float)M_PI/6,
|
|
|
|
log10f(2.0f),
|
|
|
|
logf(10.0f)/logf(2.0f),
|
|
|
|
sqrtf(3.0f)/2.0f,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
MIPSState::MIPSState()
|
|
|
|
{
|
2012-11-23 11:42:35 +00:00
|
|
|
MIPSComp::jit = 0;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MIPSState::~MIPSState()
|
|
|
|
{
|
2013-02-18 09:14:57 +00:00
|
|
|
if (MIPSComp::jit)
|
|
|
|
{
|
|
|
|
delete MIPSComp::jit;
|
|
|
|
MIPSComp::jit = 0;
|
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MIPSState::Reset()
|
|
|
|
{
|
2012-12-24 07:33:10 +00:00
|
|
|
if (MIPSComp::jit)
|
2012-12-26 11:30:08 +00:00
|
|
|
{
|
2012-12-24 07:33:10 +00:00
|
|
|
delete MIPSComp::jit;
|
2012-12-26 11:30:08 +00:00
|
|
|
MIPSComp::jit = 0;
|
|
|
|
}
|
2013-01-07 21:33:09 +00:00
|
|
|
|
2012-12-24 07:33:10 +00:00
|
|
|
if (PSP_CoreParameter().cpuCore == CPU_JIT)
|
2012-11-01 15:19:01 +00:00
|
|
|
MIPSComp::jit = new MIPSComp::Jit(this);
|
|
|
|
|
|
|
|
memset(r, 0, sizeof(r));
|
|
|
|
memset(f, 0, sizeof(f));
|
|
|
|
memset(v, 0, sizeof(v));
|
|
|
|
memset(vfpuCtrl, 0, sizeof(vfpuCtrl));
|
|
|
|
|
|
|
|
vfpuCtrl[VFPU_CTRL_SPREFIX] = 0xe4; //passthru
|
|
|
|
vfpuCtrl[VFPU_CTRL_TPREFIX] = 0xe4; //passthru
|
|
|
|
vfpuCtrl[VFPU_CTRL_DPREFIX] = 0;
|
|
|
|
vfpuCtrl[VFPU_CTRL_CC] = 0x3f;
|
|
|
|
vfpuCtrl[VFPU_CTRL_INF4] = 0;
|
|
|
|
vfpuCtrl[VFPU_CTRL_RCX0] = 0x3f800001;
|
|
|
|
vfpuCtrl[VFPU_CTRL_RCX1] = 0x3f800002;
|
|
|
|
vfpuCtrl[VFPU_CTRL_RCX2] = 0x3f800004;
|
|
|
|
vfpuCtrl[VFPU_CTRL_RCX3] = 0x3f800008;
|
|
|
|
vfpuCtrl[VFPU_CTRL_RCX4] = 0x3f800000;
|
|
|
|
vfpuCtrl[VFPU_CTRL_RCX5] = 0x3f800000;
|
|
|
|
vfpuCtrl[VFPU_CTRL_RCX6] = 0x3f800000;
|
|
|
|
vfpuCtrl[VFPU_CTRL_RCX7] = 0x3f800000;
|
|
|
|
|
|
|
|
pc = 0;
|
|
|
|
hi = 0;
|
|
|
|
lo = 0;
|
|
|
|
fpcond = 0;
|
|
|
|
fcr31 = 0;
|
|
|
|
debugCount = 0;
|
|
|
|
currentMIPS = this;
|
|
|
|
inDelaySlot = false;
|
2012-11-07 16:34:25 +00:00
|
|
|
llBit = 0;
|
2012-11-01 15:19:01 +00:00
|
|
|
nextPC = 0;
|
2013-01-14 22:03:23 +00:00
|
|
|
downcount = 0;
|
2012-11-01 15:19:01 +00:00
|
|
|
// Initialize the VFPU random number generator with .. something?
|
|
|
|
rng.Init(0x1337);
|
|
|
|
}
|
|
|
|
|
2013-05-19 22:56:37 +00:00
|
|
|
void MIPSState::DoState(PointerWrap &p) {
|
2013-11-14 06:41:25 +00:00
|
|
|
auto s = p.Section("MIPSState", 1, 2);
|
2013-09-15 03:23:03 +00:00
|
|
|
if (!s)
|
|
|
|
return;
|
|
|
|
|
2012-12-28 04:33:10 +00:00
|
|
|
// Reset the jit if we're loading.
|
|
|
|
if (p.mode == p.MODE_READ)
|
|
|
|
Reset();
|
2013-02-18 09:14:57 +00:00
|
|
|
if (MIPSComp::jit)
|
|
|
|
MIPSComp::jit->DoState(p);
|
2013-03-08 16:49:21 +00:00
|
|
|
else
|
|
|
|
MIPSComp::Jit::DoDummyState(p);
|
2012-12-28 04:33:10 +00:00
|
|
|
|
|
|
|
p.DoArray(r, sizeof(r) / sizeof(r[0]));
|
|
|
|
p.DoArray(f, sizeof(f) / sizeof(f[0]));
|
|
|
|
p.DoArray(v, sizeof(v) / sizeof(v[0]));
|
|
|
|
p.DoArray(vfpuCtrl, sizeof(vfpuCtrl) / sizeof(vfpuCtrl[0]));
|
|
|
|
p.Do(pc);
|
|
|
|
p.Do(nextPC);
|
2013-01-11 23:44:18 +00:00
|
|
|
p.Do(downcount);
|
2012-12-28 04:33:10 +00:00
|
|
|
p.Do(hi);
|
|
|
|
p.Do(lo);
|
|
|
|
p.Do(fpcond);
|
2013-11-14 06:41:25 +00:00
|
|
|
if (s <= 1) {
|
|
|
|
u32 fcr0_unusued = 0;
|
|
|
|
p.Do(fcr0_unusued);
|
|
|
|
}
|
2012-12-28 04:33:10 +00:00
|
|
|
p.Do(fcr31);
|
2013-05-19 22:56:37 +00:00
|
|
|
p.Do(rng.m_w);
|
|
|
|
p.Do(rng.m_z);
|
2012-12-28 04:33:10 +00:00
|
|
|
p.Do(inDelaySlot);
|
|
|
|
p.Do(llBit);
|
|
|
|
p.Do(debugCount);
|
|
|
|
}
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
void MIPSState::SingleStep()
|
|
|
|
{
|
|
|
|
int cycles = MIPS_SingleStep();
|
2013-01-11 23:44:18 +00:00
|
|
|
currentMIPS->downcount -= cycles;
|
2012-11-01 15:19:01 +00:00
|
|
|
CoreTiming::Advance();
|
|
|
|
}
|
|
|
|
|
2012-11-19 13:16:37 +00:00
|
|
|
// returns 1 if reached ticks limit
|
|
|
|
int MIPSState::RunLoopUntil(u64 globalTicks)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2012-11-23 11:42:35 +00:00
|
|
|
switch (PSP_CoreParameter().cpuCore)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2012-11-23 11:42:35 +00:00
|
|
|
case CPU_JIT:
|
2012-11-01 15:19:01 +00:00
|
|
|
MIPSComp::jit->RunLoopUntil(globalTicks);
|
2012-11-23 11:42:35 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CPU_INTERPRETER:
|
|
|
|
return MIPSInterpret_RunUntil(globalTicks);
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
2012-11-19 13:16:37 +00:00
|
|
|
return 1;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MIPSState::WriteFCR(int reg, int value)
|
|
|
|
{
|
|
|
|
if (reg == 31)
|
|
|
|
{
|
2013-11-15 07:57:28 +00:00
|
|
|
fcr31 = value & 0x0181FFFF;
|
2012-11-01 15:19:01 +00:00
|
|
|
fpcond = (value >> 23) & 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-08-12 02:33:52 +00:00
|
|
|
WARN_LOG_REPORT(CPU, "WriteFCR: Unexpected reg %d (value %08x)", reg, value);
|
2012-11-01 15:19:01 +00:00
|
|
|
// MessageBox(0, "Invalid FCR","...",0);
|
|
|
|
}
|
|
|
|
DEBUG_LOG(CPU, "FCR%i written to, value %08x", reg, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 MIPSState::ReadFCR(int reg)
|
|
|
|
{
|
|
|
|
DEBUG_LOG(CPU,"FCR%i read",reg);
|
|
|
|
if (reg == 31)
|
|
|
|
{
|
|
|
|
fcr31 = (fcr31 & ~(1<<23)) | ((fpcond & 1)<<23);
|
|
|
|
return fcr31;
|
|
|
|
}
|
|
|
|
else if (reg == 0)
|
|
|
|
{
|
2013-11-14 06:41:25 +00:00
|
|
|
return FCR0_VALUE;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-08-12 02:33:52 +00:00
|
|
|
WARN_LOG_REPORT(CPU, "ReadFCR: Unexpected reg %d", reg);
|
2012-11-01 15:19:01 +00:00
|
|
|
// MessageBox(0, "Invalid FCR","...",0);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-01 07:32:17 +00:00
|
|
|
void MIPSState::InvalidateICache(u32 address, int length)
|
|
|
|
{
|
|
|
|
// Only really applies to jit.
|
|
|
|
if (MIPSComp::jit)
|
|
|
|
MIPSComp::jit->ClearCacheAt(address, length);
|
|
|
|
}
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
// Interrupts should be served directly on the running thread.
|
|
|
|
void MIPSState::Irq()
|
|
|
|
{
|
|
|
|
// if (IRQEnabled())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void MIPSState::SWI()
|
|
|
|
{
|
|
|
|
}
|
2013-07-27 20:14:01 +00:00
|
|
|
|
2013-07-29 20:35:06 +00:00
|
|
|
const char *MIPSState::DisasmAt(u32 compilerPC) {
|
|
|
|
static char temp[256];
|
|
|
|
MIPSDisAsm(Memory::Read_Instruction(compilerPC), 0, temp);
|
|
|
|
return temp;
|
|
|
|
}
|