Kill lots of old outdated comments. Some new comments added. Misc style fixes. No effect on emulation.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@894 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard 2008-10-16 22:06:06 +00:00
parent 3ae2d556ab
commit 21b0d596e4
26 changed files with 558 additions and 634 deletions

View File

@ -15,36 +15,60 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// Simple partial Action Replay code system implementation.
// Will never be able to support some AR codes - specifically those that patch the running
// Action Replay engine itself - yes they do exist!!!
// Action Replay actually is a small virtual machine with a limited number of commands.
// It probably is Turing complete - but what does that matter when AR codes can write
// actual PowerPC code.
#include <string>
#include <vector>
#include "StringUtil.h"
#include "IniFile.h"
#include "HW/Memmap.h"
#include "ActionReplay.h"
u32 cmd_addr;
u8 cmd;
u32 addr;
u32 data;
u8 subtype;
u8 w;
u8 type;
std::vector<AREntry>::const_iterator iter;
std::vector<ARCode> arCodes;
ARCode code;
namespace {
// These should be turned into locals in RunActionReplayCode, and passed as parameters to the others.
static u32 cmd_addr;
static u8 cmd;
static u32 addr;
static u32 data;
static u8 subtype;
static u8 w;
static u8 type;
static std::vector<AREntry>::const_iterator iter;
static std::vector<ARCode> arCodes;
static ARCode code;
} // namespace
void DoARSubtype_RamWriteAndFill();
void DoARSubtype_WriteToPointer();
void DoARSubtype_AddCode();
void DoARSubtype_MasterCodeAndWriteToCCXXXXXX();
void DoARSubtype_Other();
// Parses the Action Replay section of a game ini file.
void LoadActionReplayCodes(IniFile &ini)
{
std::vector<std::string> lines;
ARCode currentCode;
arCodes.clear();
if (!ini.GetLines("ActionReplay", lines)) return;
if (!ini.GetLines("ActionReplay", lines))
return; // no codes found.
for (std::vector<std::string>::const_iterator it = lines.begin(); it != lines.end(); ++it)
{
std::string line = *it;
std::vector<std::string> pieces;
SplitString(line, " ", pieces);
if (pieces.size() == 2 && pieces[0].size() == 8 && pieces[1].size() == 8)
@ -96,6 +120,12 @@ void LoadActionReplayCodes(IniFile &ini)
arCodes.push_back(currentCode);
}
void ActionReplayRunAllActive()
{
for (std::vector<ARCode>::const_iterator iter = arCodes.begin(); iter != arCodes.end(); ++iter)
if (iter->active)
RunActionReplayCode(*iter, false);
}
// The mechanism is slightly different than what the real AR uses, so there may be compatibility problems.
// For example, some authors have created codes that add features to AR. Hacks for popular ones can be added here,
@ -146,25 +176,20 @@ void RunActionReplayCode(const ARCode &arcode, bool nowIsBootup) {
switch (subtype)
{
case 0x0: // Ram write (and fill)
{
DoARSubtype_RamWriteAndFill(); continue;
}
DoARSubtype_RamWriteAndFill();
continue;
case 0x1: // Write to pointer
{
DoARSubtype_WriteToPointer(); continue;
}
DoARSubtype_WriteToPointer();
continue;
case 0x2: // Add code
{
DoARSubtype_AddCode(); continue;
}
DoARSubtype_AddCode();
continue;
case 0x3: // Master Code & Write to CCXXXXXX
{
DoARSubtype_MasterCodeAndWriteToCCXXXXXX(); continue;// TODO: This is not implemented yet
}
DoARSubtype_MasterCodeAndWriteToCCXXXXXX();
continue; // TODO: This is not implemented yet
default: // non-specific z codes (hacks)
{
DoARSubtype_Other(); continue;
}
DoARSubtype_Other();
continue;
}
}
}
@ -194,16 +219,16 @@ void DoARSubtype_RamWriteAndFill()
break;
}
case 0x02: // Dword write
{
Memory::Write_U32(data, new_addr);
break;
}
default: break; // TODO(Omega): maybe add a PanicAlert here?
default:
break; // TODO(Omega): maybe add a PanicAlert here?
}
}
}
void DoARSubtype_WriteToPointer()
{
if (w < 0x8)
@ -230,11 +255,12 @@ void DoARSubtype_WriteToPointer()
}
case 0x02: // Dword write to pointer [44]
{
Memory::Write_U32(data, Memory::Read_U32(new_addr)); break;
}
Memory::Write_U32(data, Memory::Read_U32(new_addr));
break;
default: PanicAlert("AR Method Error (Write To Pointer): w = %08x, addr = %08x",w,addr);
default:
PanicAlert("AR Method Error (Write To Pointer): w = %08x, addr = %08x", w, addr);
break;
}
}
}
@ -247,17 +273,14 @@ void DoARSubtype_AddCode()
switch ((addr >> 25) & 0x03)
{
case 0x0: // Byte add
{
Memory::Write_U8(Memory::Read_U8(new_addr) + (data & 0xFF), new_addr); break;
}
Memory::Write_U8(Memory::Read_U8(new_addr) + (data & 0xFF), new_addr);
break;
case 0x1: // Short add
{
Memory::Write_U16(Memory::Read_U16(new_addr) + (data & 0xFFFF), new_addr); break;
}
Memory::Write_U16(Memory::Read_U16(new_addr) + (data & 0xFFFF), new_addr);
break;
case 0x2: // DWord add
{
Memory::Write_U32(Memory::Read_U32(new_addr) + data, new_addr); break;
}
Memory::Write_U32(Memory::Read_U32(new_addr) + data, new_addr);
break;
case 0x3: // Float add (not working?)
{
union { u32 u; float f;} fu, d;
@ -267,7 +290,8 @@ void DoARSubtype_AddCode()
Memory::Write_U32(fu.u, new_addr);
break;
}
default: break;
default:
break;
}
}
}
@ -293,61 +317,51 @@ void DoARSubtype_Other()
{
switch (cmd & 0xFE)
{
case 0x90: if (Memory::Read_U32(addr) == data) return; // IF 32 bit equal, exit
case 0x90:
// Eh, this must be wrong. Should it really fallthrough?
if (Memory::Read_U32(addr) == data) return; // IF 32 bit equal, exit
case 0x08: // IF 8 bit equal, execute next opcode
case 0x48: // (double)
{
if (Memory::Read_U16(addr) != (data & 0xFFFF)) {
if (++iter == code.ops.end()) return;
if (cmd == 0x48) if (++iter == code.ops.end()) return;
}
break;
}
case 0x0A: // IF 16 bit equal, execute next opcode
case 0x4A: // (double)
{
if (Memory::Read_U16(addr) != (data & 0xFFFF)) {
if (++iter == code.ops.end()) return;
if (cmd == 0x4A) if (++iter == code.ops.end()) return;
}
break;
}
case 0x0C: // IF 32 bit equal, execute next opcode
case 0x4C: // (double)
{
if (Memory::Read_U32(addr) != data) {
if (++iter == code.ops.end()) return;
if (cmd == 0x4C) if (++iter == code.ops.end()) return;
}
break;
}
case 0x10: // IF NOT 8 bit equal, execute next opcode
case 0x50: // (double)
{
if (Memory::Read_U8(addr) == (data & 0xFF)) {
if (++iter == code.ops.end()) return;
if (cmd == 0x50) if (++iter == code.ops.end()) return;
}
break;
}
case 0x12: // IF NOT 16 bit equal, execute next opcode
case 0x52: // (double)
{
if (Memory::Read_U16(addr) == (data & 0xFFFF)) {
if (++iter == code.ops.end()) return;
if (cmd == 0x52) if (++iter == code.ops.end()) return;
}
break;
}
case 0x14: // IF NOT 32 bit equal, execute next opcode
case 0x54: // (double)
{
if (Memory::Read_U32(addr) == data) {
if (++iter == code.ops.end()) return;
if (cmd == 0x54) if (++iter == code.ops.end()) return;
}
break;
}
case 0xC4: // "Master Code" - configure the AR
{
u8 number = data & 0xFF;
@ -361,6 +375,8 @@ void DoARSubtype_Other()
// Blah, we generally ignore master codes.
break;
}
default: PanicAlert("Unknown Action Replay command %02x (%08x %08x)", cmd, iter->cmd_addr, iter->value); break;
default:
PanicAlert("Unknown Action Replay command %02x (%08x %08x)", cmd, iter->cmd_addr, iter->value);
break;
}
}

View File

@ -26,13 +26,7 @@ struct ARCode {
bool active;
};
extern std::vector<ARCode> arCodes;
void ActionReplayRunAllActive();
void RunActionReplayCode(const ARCode &arcode, bool nowIsBootup);
void LoadActionReplayCodes(IniFile &ini);
void DoARSubtype_RamWriteAndFill();
void DoARSubtype_WriteToPointer();
void DoARSubtype_AddCode();
void DoARSubtype_MasterCodeAndWriteToCCXXXXXX();
void DoARSubtype_Other();

View File

@ -14,6 +14,7 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <iostream>
#include <cstring>
@ -22,32 +23,16 @@
#include "HW/Memmap.h"
#include "PowerPC/PPCAnalyst.h"
#include "PowerPC/PPCTables.h"
#include "Console.h"
#include "CoreTiming.h"
#include "Core.h"
#include "PowerPC/Jit64/JitCache.h"
#include "PowerPC/SymbolDB.h"
#include "PowerPCDisasm.h"
#include "Console.h"
#define CASE(x) else if (memcmp(cmd, x, 4*sizeof(TCHAR))==0)
#define CASE1(x) if (memcmp(cmd, x, 2*sizeof(TCHAR))==0)
/*
static Common::Thread *cons_thread;
THREAD_RETURN ConsoleThreadFunc(void *) {
printf("Welcome to the console thread!\n\n");
while (true) {
std::string command;
getline(std::cin, command);
Console_Submit(command.c_str());
}
}
void StartConsoleThread() {
cons_thread = new Common::Thread(ConsoleThreadFunc, 0);
}*/
void Console_Submit(const char *cmd)
{
CASE1("jits")

View File

@ -14,11 +14,14 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// Simple debugging console currently residing in the Logging window. Not used much.
#ifndef _CONSOLE_H
#define _CONSOLE_H
void Console_Submit(const char *cmd);
// void StartConsoleThread();
#endif

View File

@ -14,6 +14,14 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// Core
// The external interface to the emulator core. Plus some extras.
// This is another part of the emu that needs cleaning - Core.cpp really has
// too much random junk inside.
#ifndef _CORE_H
#define _CORE_H
@ -36,10 +44,7 @@ namespace Core
bool Init(const SCoreStartupParameter _CoreParameter);
void Stop();
// Get state
bool SetState(EState _State);
// Get state
EState GetState();
// Save/Load state
@ -64,8 +69,7 @@ namespace Core
int SyncTrace();
void SetBlockStart(u32 addr);
void StopTrace();
} // end of namespace Core
} // namespace
#endif

View File

@ -14,6 +14,7 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _COREPARAMETER_H
#define _COREPARAMETER_H

View File

@ -293,16 +293,13 @@ void Advance()
externalEventSection.Enter();
while (tsFirst)
{
//MessageBox(0,"yay",0,0);
Event *next = tsFirst->next;
AddEventToQueue(tsFirst);
tsFirst = next;
}
externalEventSection.Leave();
// we are out of run, downcount = -3
int cyclesExecuted = slicelength - downcount;
// sliceLength = downac
globalTimer += cyclesExecuted;
@ -312,7 +309,6 @@ void Advance()
{
// LOG(GEKKO, "[Scheduler] %s (%lld, %lld) ",
// first->name ? first->name : "?", (u64)globalTimer, (u64)first->time);
event_types[first->type].callback(first->userdata, (int)(globalTimer - first->time));
Event *next = first->next;
delete first;
@ -326,7 +322,6 @@ void Advance()
if (!first)
{
LOG(GEKKO, "WARNING - no events in queue. Setting downcount to 10000");
// PanicAlert?
downcount += 10000;
}
else
@ -379,4 +374,4 @@ std::string GetScheduledEventsSummary()
return text;
}
}; // end of namespace
} // namespace

View File

@ -24,6 +24,13 @@
// To schedule an event, you first have to register its type. This is where you pass in the
// callback. You then schedule events using the type id you get back.
// See HW/SystemTimers.cpp for the main part of Dolphin's usage of this scheduler.
// The int cyclesLate that the callbacks get is how many cycles late it was.
// So to schedule a new event on a regular basis:
// inside callback:
// ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever")
#include "Common.h"
#include <string>
@ -33,7 +40,6 @@
namespace CoreTiming
{
void Init();
void Shutdown();
@ -43,10 +49,6 @@ u64 GetTicks();
u64 GetIdleTicks();
void DoState(PointerWrap &p);
// The int that the callbacks get is how many cycles late it was.
// So to schedule a new event on a regular basis:
// inside callback:
// ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever")
// Returns the event_type identifier.
int RegisterEvent(const char *name, TimedCallback callback);

View File

@ -17,10 +17,9 @@
// AID / AUDIO_DMA controls pushing audio out to the SRC and then the speakers.
// The audio DMA pushes audio through a small FIFO 32 bytes at a time, as needed.
// Since the SRC behind the fifo eats stereo 16-bit data at a sample rate of 32khz,
// that is, 4 bytes at 32 khz, which is 32 bytes at 4 khz. We should thus schedule an
// event that runs at 4khz, that eats audio from the fifo, and all the rest will follow.
// Then we will have homebrew audio.
// The SRC behind the fifo eats stereo 16-bit data at a sample rate of 32khz,
// that is, 4 bytes at 32 khz, which is 32 bytes at 4 khz. We thereforce schedule an
// event that runs at 4khz, that eats audio from the fifo. Thus, we have homebrew audio.
// The AID interrupt is set when the fifo STARTS a transfer. It latches address and count
// into internal registers and starts copying. This means that the interrupt handler can simply

View File

@ -156,6 +156,16 @@ void InitHWMemFuncs()
hwRead16 [i] = HW_Default_Read<u16&>;
hwRead32 [i] = HW_Default_Read<u32&>;
hwRead64 [i] = HW_Default_Read<u64&>;
// To prevent Dolphin from crashing when running Wii executables in Gc mode.
hwWriteWii8 [i] = HW_Default_Write<u8>;
hwWriteWii16[i] = HW_Default_Write<u16>;
hwWriteWii32[i] = HW_Default_Write<u32>;
hwWriteWii64[i] = HW_Default_Write<u64>;
hwReadWii8 [i] = HW_Default_Read<u8&>;
hwReadWii16 [i] = HW_Default_Read<u16&>;
hwReadWii32 [i] = HW_Default_Read<u32&>;
hwReadWii64 [i] = HW_Default_Read<u64&>;
}
for (int i = 0; i < BLOCKSIZE; i++)

View File

@ -14,6 +14,7 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <stdio.h>
#include "Common.h"

View File

@ -14,6 +14,10 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// Dolphin Logging framework. Needs a good ol' spring cleaning methinks.
#ifndef _LOGMANAGER_H
#define _LOGMANAGER_H

View File

@ -15,7 +15,9 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// TODO: create a OS-neutral version of this file and put it in Common.
// TODO: create a working OS-neutral version of this file and put it in Common.
#ifdef _WIN32

View File

@ -20,52 +20,11 @@
#include "Common.h"
typedef u32 EAddr;
namespace EMM
{
enum WR
{
Read = 1,
Write = 2,
Execute = 4
};
enum WatchType
{
Oneshot,
Continuous
};
enum AccessSize
{
Access8,
Access16,
Access32,
Access64,
Access128
};
typedef int WatchID;
typedef void (*WatchCallback)(EAddr addr, AccessSize size, WR action, WatchID id);
//Useful to emulate low-used I/O, and caching of memory resources that can change any time
WatchID AddWatchRegion(EAddr startAddr, EAddr endAddr, WR watchFor, WatchType type, WatchCallback callback, u64 userData);
void RemoveWatchRegion(WatchID id);
void ClearWatches();
//Call this on your main emulator thread, with your mainloop in codeToRun
typedef u32 EAddr;
void InstallExceptionHandler();
}
u8 ReadHandler8(EAddr address);
u16 ReadHandler16(EAddr address);
u32 ReadHandler32(EAddr address);
u64 ReadHandler64(EAddr address);
void WriteHandler8(EAddr address, u8 value);
void WriteHandler16(EAddr address, u16 value);
void WriteHandler32(EAddr address, u32 value);
void WriteHandler64(EAddr address, u64 value);
#endif

View File

@ -16,15 +16,15 @@
// http://code.google.com/p/dolphin-emu/
// PatchEngine
// Supports simple memory patches, and has a partial Action Replay implementation
// in ActionReplay.cpp/h.
// Zelda item hang fixes:
// [Tue Aug 21 2007] [18:30:40] <Knuckles-> 0x802904b4 in US released
// [Tue Aug 21 2007] [18:30:53] <Knuckles-> 0x80294d54 in EUR Demo version
// [Tue Aug 21 2007] [18:31:10] <Knuckles-> we just patch a blr on it (0x4E800020)
// A little present to our dear hacker friends
// (A partial Action Replay engine)
// And a temporary "solution" to Zelda item glitch...
// [OnLoad]
// 0x80020394=dword,0x4e800020
// #define BLR_OP 0x4e800020
#include <string>
#include <vector>
@ -36,9 +36,14 @@
using namespace Common;
namespace
{
std::vector<Patch> onLoad;
std::vector<Patch> onFrame;
} // namespace
void LoadPatchSection(const char *section, std::vector<Patch> &patches, IniFile &ini)
{
std::vector<std::string> keys;
@ -113,8 +118,5 @@ void PatchEngine_ApplyFramePatches()
void PatchEngine_ApplyARPatches()
{
for (std::vector<ARCode>::const_iterator iter = arCodes.begin(); iter != arCodes.end(); ++iter) {
if (iter->active)
RunActionReplayCode(*iter, false);
}
ActionReplayRunAllActive();
}

View File

@ -39,14 +39,21 @@ using namespace Gen;
using namespace PowerPC;
extern int blocksExecuted;
//X64 Win64 calling convention:
// Parameters in RCX RDX R8 R9
// Volatile RAX R10 R11
// Non volatile (must be saved)
// RBX RSI RDI R12 R13 R14 R15
//Register allocation:
// Dolphin's PowerPC->x86 JIT dynamic recompiler
// All code by ector (hrydgard)
// Features:
// * x86 & x64 support, lots of shared code.
// * Basic block linking
// * Fast dispatcher
// Unfeatures:
// * Does not recompile all instructions. Often falls back to inserting a CALL to the corresponding JIT function.
// Various notes below
// Register allocation
// RAX - Generic quicktemp register
// RBX - point to base of memory map
// RSI RDI R12 R13 R14 R15 - free for allocation
@ -54,114 +61,54 @@ extern int blocksExecuted;
// RSP - stack pointer, do not generally use, very dangerous
// RBP - ?
//RCX RDX R8 R9 are function parameters. We will only call 1 and 2 param functions from compiled code anyway.
//Calling out to the interpreter needs only to flush the volatile regs!
// IMPORTANT:
// Make sure that all generated code and all emulator state sits under the 2GB boundary so that
// RIP addressing can be used easily. Windows will always allocate static code under the 2GB boundary.
// Also make sure to use VirtualAlloc and specify EXECUTE permission.
//Since RIP stores/loads will not be possible to the high memory area, we will have to use
//a statically allocated base pointer in a register, and use displacement addressing off of that.
//A candidate for this is a non vol like R15, since we would not like to have to do a RIP load
//to restore it all the time.
//No wait a minute, why not just keep the unprotected mappings below 2GB?
// Open questions
// * Should there be any statically allocated registers? r3, r4, r5, r8, r0 come to mind.. maybe sp
// * Does it make sense to finish off the remaining non-jitted instructions? Seems we are hitting diminishing returns.
// * Why is the FPU exception handling not working 100%? Several games still get corrupted floating point state.
// This can even be seen in one homebrew Wii demo - RayTracer.elf
//Another question to be addressed is if it is smart to have a static pointer reg to the base
//of the PowerPC reg area.
//Pro: Smaller accesses for GPR (8-bit displacement good enough only for gprs)
//Con: A taken nonvol register (may not be so bad)
//Should there be any statically allocated registers? r3, r4, r5, r8, r0 come to mind.. maybe sp
//When calling external functions, only volatile regs need to be saved.
//This means that they should be allocated last. RAX should probably never
//be allocated, it should just be a temporary to do non-destructive trinary ops.
//However, for the above to work and be a win, we need to store away the non volatiles before
//entering "JIT space". However, once we're there, it will be a win.
//Also, JIT space will need to be surrounded with stack adjusting, since functions will be called.
// Other considerations
//Many instructions have shorter forms for EAX. However, I believe their performance boost
//will be as small to be negligble, so I haven't dirtied up the code with that. AMD recommends it in their
//optimization manuals, though.
//IDEA: FPU exception emulation support by having all fpu blocks writeNTA to a spot in memory that
//is protected if FPU exceptions are enabled. The exception handler would then have to run the
//interpreter until rfi, at which point control can be returned. Of course all regs need to be
//flushed before this happens. This method is branch free but does a memory write or read in the fast case.
// Probably not worthwhile, a test/jz in every fpu block should be enough.
//Block linking is needed. Reserve space at the end of every block for a full 5-byte jmp. Save 16-bit offsets
// We support block linking. Reserve space at the exits of every block for a full 5-byte jmp. Save 16-bit offsets
// from the starts of each block, marking the exits so that they can be nicely patched at any time.
//Blocks do NOT use call/ret, they only jmp to each other and to the dispatcher when necessary.
// * Blocks do NOT use call/ret, they only jmp to each other and to the dispatcher when necessary.
// All blocks that can be precompiled will be precompiled. Code will be memory protected - any write will mark
// the region as non-compilable, and all links to the page will be torn out and replaced with dispatcher jmps.
// Alternatively, icbi instruction SHOULD mark where we can't compile
//IDEA: All major memory altering events (not singular accesses) should call Gfx::Snoop to let it know that memory chagned.
// Seldom-happening events will be handled by adding a decrement of a counter to all blr instructions (which are
// expensive anyway since we need to return to dispatcher, except when they can be predicted).
//TODO:
// TODO: SERIOUS synchronization problem with the video plugin setting tokens and breakpoints!!!
// TODO: SERIOUS synchronization problem with the video plugin setting tokens and breakpoints in dual core mode!!!
// Somewhat fixed by disabling idle skipping when certain interrupts are enabled
// This is no permantent reliable fix
// TODO: Zeldas go whacko when you hang the gfx thread
// Plan: 1. Byteswap Dolphin DONE!
// 2. Fix timing WORKING
// 3. Lay groundwork for x64 JIT WORKING
// 4. Get OneTri up to 60fps, and check compatibility from time to time (yea right) ????
// 5. Add block linking to JIT << NOT SO IMPORTANT
// 6. Optimize GFX plugin to hell << IMPORTANT
// 7. Watch Zelda do 20 fps.
// 8. Watch Zelda TP do 30 fps. DONE :D
// Idea - Accurate exception handling
// Compute register state at a certain instruction by running the JIT in "dry mode", and stopping at the right place.
// Not likely to be done :P
//Optimizations -
// Optimization Ideas -
/*
* Assume SP is in main RAM (in Wii mode too?)
* Assume SP is in main RAM (in Wii mode too?) - partly done
* Assume all floating point loads and double precision loads+stores are to/from main ram
(single precision can be used in write gather)
(this is valid on Wii too when using the VM emulator)
(single precision can be used in write gather pipe, specialized fast check added)
* AMD only - use movaps instead of movapd when loading ps from memory?
* HLE functions like floorf, sin, memcpy, etc - they can be much faster
* Optimal sequence to store floats
* TODO: find optimal sequence to store doubles as floats
cvtpd2ps xmm0, xmm0
movss xmm0, f
movss tempspace, xmm0
mov eax, tempspace
bswap eax
mov [edi], eax
I think pshufb does it faster.
BLOCK EXIT DESIGN
TEST whatever
JZ skip
MOV NPC, exit1
JMP dispatcher
skip:
MOV NPC, exit2
JMP dispatcher
This can be patched into (when both exits are known):
JZ exit2
JMP exit1
The problem is, we still need to fit the downcount somewhere...
Low hanging fruit:
stfd -- guaranteed in memory
@ -186,9 +133,6 @@ cntlzwx
bcctrx
WriteBigEData
detect immediates in stb stw sth
TODO
lha
srawx
@ -196,29 +140,18 @@ addic_rc
addex
subfcx
subfex
000000000A42BD7F mov ecx,0FCBF41BAh
000000000A42BD85 call CInterpreter::fmaddx (5BA3A0h)
000000000A42BD8A mov ecx,0FC8D0132h
000000000A42BD90 call CInterpreter::fmulx (5BA540h)
000000000A42BD95 mov ecx,0FC85202Ah
000000000A42BD9B call CInterpreter::faddx (5BA220h)
000000000A42BDA0 mov ecx,0FC81113Ah
000000000A42BDA6 call CInterpreter::fmaddx (5BA3A0h)
000000000A42C11A call CInterpreter::fnegx (5BA0B0h)
000000000A42C604 call CInterpreter::frspx (5BA170h)
000000000A428FDC call CInterpreter::ps_sum0 (5C9730h)
000000000A428FE1 mov ecx,0FCA02034h
000000000A428FE7 call CInterpreter::frsqrtex (5BA7C0h)
000000000A429062 call CInterpreter::ps_muls0 (5C9820h)
000000000A4290AF call CInterpreter::psq_st (5C9DF0h)
fmaddx
fmulx
faddx
fnegx
frspx
frsqrtex
ps_sum0
*/
// Accurate exception handling
// Compute register state at a certain instruction by running the JIT in "dry mode", and stopping at the right place.
// Not likely to be done :P
// Evil
namespace CPUCompare
{
extern u32 m_BlockStart;
@ -232,7 +165,7 @@ namespace Jit64
void Init()
{
jo.optimizeStack = true;
jo.optimizeStack = false;
jo.enableBlocklink = true; // Speed boost, but not 100% safe
#ifdef _M_X64
jo.enableFastMem = Core::GetStartupParameter().bUseFastMem;
@ -243,6 +176,7 @@ namespace Jit64
jo.fpAccurateFlags = true;
jo.optimizeGatherPipe = true;
jo.interpretFPU = false;
jo.fastInterrupts = false;
}
void WriteCallInterpreter(UGeckoInstruction _inst)
@ -280,6 +214,7 @@ namespace Jit64
static const bool ImHereDebug = false;
static const bool ImHereLog = false;
static std::map<u32, int> been_here;
void ImHere()
{
static FILE *f = 0;
@ -378,9 +313,11 @@ namespace Jit64
const u8 *start = AlignCode4(); //TODO: Test if this or AlignCode16 make a difference from GetCodePtr
b.checkedEntry = start;
b.runCount = 0;
// Downcount flag check. The last block decremented downcounter, and the flag should still be available.
FixupBranch skip = J_CC(CC_NBE);
MOV(32, M(&PC), Imm32(js.blockStart));
JMP(Asm::doTiming, true);
JMP(Asm::doTiming, true); // downcount hit zero - go doTiming.
SetJumpTarget(skip);
const u8 *normalEntry = GetCodePtr();
@ -396,6 +333,17 @@ namespace Jit64
SetJumpTarget(b1);
}
if (false && jo.fastInterrupts)
{
// This does NOT yet work.
TEST(32, M(&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF));
FixupBranch b1 = J_CC(CC_Z);
MOV(32, M(&PC), Imm32(js.blockStart));
JMP(Asm::testExceptions, true);
SetJumpTarget(b1);
}
// Conditionally add profiling code.
if (Profiler::g_ProfileBlocks) {
ADD(32, M(&b.runCount), Imm8(1));
#ifdef _WIN32
@ -439,13 +387,12 @@ namespace Jit64
}
// const GekkoOpInfo *info = GetOpInfo();
// if (js.isLastInstruction)
if (jo.interpretFPU && PPCTables::UsesFPU(ops[i].inst))
Default(ops[i].inst);
else
PPCTables::CompileInstruction(ops[i].inst);
// else
// Default(ops[i].inst);
gpr.SanityCheck();
fpr.SanityCheck();
if (jo.optimizeGatherPipe && js.fifoBytesThisBlock >= 32)

View File

@ -15,9 +15,9 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// Low hanging fruit:
// all used in zelda
// negx
// ========================
// See comments in Jit.cpp.
// ========================
#ifndef _JIT_H
#define _JIT_H
@ -26,14 +26,10 @@
#include "JitCache.h"
#include "x64Emitter.h"
// =======================================================================================
// Enable or disable JIT off options. All the if() checks in the JIT functions may result in a
// speed drop. However it should barely be noticable as the code is recompiled rarely.
// --------------
#define JIT_OFF_OPTIONS
namespace Jit64
{
struct JitStats
@ -80,6 +76,7 @@ namespace Jit64
bool enableFastMem;
bool optimizeGatherPipe;
bool interpretFPU;
bool fastInterrupts;
};
extern JitState js;

View File

@ -30,17 +30,20 @@
// and what functions calls it. That is, we will have an incomplete call graph,
// but only missing indirect branches.
// The results of this analysis are currently not really used for anything, other than
// finding function boundaries so that we can find, fingerprint and detect library functions.
// The results of this analysis is displayed in the code browsing sections at the bottom left
// of the disassembly window (debugger).
// It is also useful for finding function boundaries so that we can find, fingerprint and detect library functions.
// We don't do this much currently. Only for the special case Super Monkey Ball.
namespace PPCAnalyst {
using namespace std;
// VERY ugly. TODO: remove.
PPCAnalyst::CodeOp *codebuffer;
enum {
enum
{
CODEBUFFER_SIZE = 32000,
};

View File

@ -41,8 +41,6 @@ struct GekkoOPTemplate
int runCount;
};
// The eventual goal is to be able to constify as much as possible in this file.
// Currently, the main obstacle is runCount above.
static GekkoOPInfo *m_infoTable[64];
static GekkoOPInfo *m_infoTable4[1024];
static GekkoOPInfo *m_infoTable19[1024];

View File

@ -46,7 +46,6 @@ enum
FL_CHECKEXCEPTIONS = (1<<16),
};
enum
{
OPTYPE_INVALID ,

View File

@ -37,6 +37,7 @@
namespace PowerPC
{
// STATE_TO_SAVE
PowerPCState GC_ALIGNED16(ppcState);
volatile CPUState state = CPU_STEPPING;
@ -292,6 +293,7 @@ namespace PowerPC
CoreTiming::Idle();
}
}
//DualCore OnIdle
void OnIdleDC(void)
{
@ -301,5 +303,5 @@ namespace PowerPC
#endif
CoreTiming::Idle();
}
}
} // namespace

View File

@ -31,6 +31,7 @@ namespace PowerPC
MODE_JIT,
};
// This contains the entire state of the emulated PowerPC "Gekko" CPU.
struct GC_ALIGNED64(PowerPCState)
{
u32 mojs[128]; // Try to isolate the regs from other variables in the cache.
@ -88,7 +89,7 @@ namespace PowerPC
void OnIdleDC(void);
}
// Special registers
// Easy register access macros.
#define HID2 ((UReg_HID2&)PowerPC::ppcState.spr[SPR_HID2])
#define DMAU (*(UReg_DMAU*)&PowerPC::ppcState.spr[SPR_DMAU])
#define DMAL (*(UReg_DMAL*)&PowerPC::ppcState.spr[SPR_DMAL])
@ -115,15 +116,16 @@ namespace PowerPC
#define TL PowerPC::ppcState.spr[SPR_TL]
#define TU PowerPC::ppcState.spr[SPR_TU]
#define rPS0(i) (*(double*)(&PowerPC::ppcState.ps[i][0]))
#define rPS1(i) (*(double*)(&PowerPC::ppcState.ps[i][1]))
#define riPS0(i) (*(u64*)(&PowerPC::ppcState.ps[i][0]))
#define riPS1(i) (*(u64*)(&PowerPC::ppcState.ps[i][1]))
// #define DMAU PowerPC::ppcState.Helper[SPR_DMAU ]
// #define DMAL PowerPC::ppcState.Helper[SPR_DMAL ]
// Wrappers to make it easier to in the future completely replace the storage of CR and Carry bits
// to something more x86-friendly. These are not used 100% consistently yet - and if we do this, we
// need the corresponding stuff on the JIT side too.
inline void SetCRField(int cr_field, int value) {
PowerPC::ppcState.cr = (PowerPC::ppcState.cr & (~(0xF0000000 >> (cr_field * 4)))) | (value << ((7 - cr_field) * 4));
@ -153,6 +155,4 @@ inline int GetCarry() {
return XER.CA;
}
#endif

View File

@ -15,6 +15,8 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// Emulator state saving support.
#ifndef _STATE_H
#define _STATE_H

View File

@ -31,6 +31,7 @@ void SetVolumeName(const std::string& _rFullPath)
{
if (g_pVolume)
{
// This code looks scary. Can the try/catch stuff be removed?
try
{
delete g_pVolume;
@ -91,4 +92,4 @@ bool IsWii()
return false;
}
}
} // namespace

View File

@ -15,6 +15,9 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// Disc volume handler. It's here because Wii discs can consist of multiple volumes.
// GC discs are seen as one big volume.
#ifndef _VOLUMEHANDLER_H
#define _VOLUMEHANDLER_H
@ -22,25 +25,20 @@
#include "CommonTypes.h"
#include "Volume.h"
namespace VolumeHandler
{
void SetVolumeName(const std::string& _rFullPath);
void SetVolumeDirectory(const std::string& _rFullPath, bool _bIsWii);
u32 Read32(u64 _Offset);
bool ReadToPtr(u8* ptr, u64 _dwOffset, u64 _dwLength);
bool IsValid();
bool IsWii();
DiscIO::IVolume *GetVolume();
}
} // namespace
#endif

View File

@ -28,7 +28,7 @@
enum {
XFB_WIDTH = 640,
XFB_HEIGHT = 480, //480,
XFB_HEIGHT = 480, // 528 is max height.
XFB_BUF_HEIGHT = 538, //480,
// TODO: figure out what to do with PAL
};