Switched from lazyusf to lazyusf2

This commit is contained in:
Chris Moeller 2015-03-01 21:28:09 -08:00
parent 24730bdfa2
commit 4d8ec1960f
233 changed files with 61579 additions and 7949 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,240 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - ai_controller.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* 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 "usf/usf.h"
#include "usf/usf_internal.h"
#include "ai_controller.h"
#include "main/rom.h"
#include "memory/memory.h"
#include "r4300/cp0.h"
#include "r4300/r4300_core.h"
#include "r4300/interupt.h"
#include "ri/ri_controller.h"
#include "vi/vi_controller.h"
#include <string.h>
/* Clang complains that 0x80000000 is too large for enumerators, which it says must be 'int' */
static const uint32_t AI_STATUS_BUSY = 0x40000000;
static const uint32_t AI_STATUS_FULL = 0x80000000;
static uint32_t get_remaining_dma_length(struct ai_controller* ai)
{
unsigned int next_ai_event;
unsigned int remaining_dma_duration;
if (ai->fifo[0].duration == 0)
return 0;
update_count(ai->r4300->state);
next_ai_event = get_event(ai->r4300->state, AI_INT);
if (next_ai_event == 0)
return 0;
remaining_dma_duration = next_ai_event - ai->r4300->state->g_cp0_regs[CP0_COUNT_REG];
if (remaining_dma_duration >= 0x80000000)
return 0;
return (uint32_t)((uint64_t)remaining_dma_duration * ai->fifo[0].length / ai->fifo[0].duration);
}
static unsigned int get_dma_duration(struct ai_controller* ai)
{
unsigned int samples_per_sec = ai->r4300->state->ROM_PARAMS.aidacrate / (1 + ai->regs[AI_DACRATE_REG]);
return (uint32_t)(((uint64_t)ai->regs[AI_LEN_REG]*ai->vi->delay*ai->r4300->state->ROM_PARAMS.vilimit)
/ (4 * samples_per_sec));
}
static void do_dma(struct ai_controller* ai, const struct ai_dma* dma)
{
#ifdef DEBUG_INFO
fprintf(ai->r4300->state->debug_log, "Audio DMA push: %d %d\n", dma->address, dma->length);
#endif
/* lazy initialization of sample format */
if (ai->samples_format_changed)
{
unsigned int frequency = (ai->regs[AI_DACRATE_REG] == 0)
? 44100
: ai->r4300->state->ROM_PARAMS.aidacrate / (1 + ai->regs[AI_DACRATE_REG]);
unsigned int bits = (ai->regs[AI_BITRATE_REG] == 0)
? 16
: 1 + ai->regs[AI_BITRATE_REG];
set_audio_format(ai, frequency, bits);
ai->samples_format_changed = 0;
}
/* push audio samples to external sink */
push_audio_samples(ai, &ai->ri->rdram.dram[dma->address/4], dma->length);
/* schedule end of dma event */
update_count(ai->r4300->state);
if (!(ai->regs[AI_STATUS_REG] & AI_STATUS_FULL))
{
remove_event(ai->r4300->state, AI_INT);
add_interupt_event(ai->r4300->state, AI_INT, ai->r4300->state->g_delay_ai ? dma->duration : 0);
}
}
void ai_fifo_queue_int(struct ai_controller* ai)
{
add_interupt_event(ai->r4300->state, AI_INT, ai->r4300->state->g_delay_ai ? get_dma_duration(ai) : 0);
}
static void fifo_push(struct ai_controller* ai)
{
unsigned int duration = get_dma_duration(ai);
if (ai->regs[AI_STATUS_REG] & AI_STATUS_BUSY)
{
ai->fifo[1].address = ai->regs[AI_DRAM_ADDR_REG];
ai->fifo[1].length = ai->regs[AI_LEN_REG];
ai->fifo[1].duration = duration;
if (ai->r4300->state->enableFIFOfull)
ai->regs[AI_STATUS_REG] |= AI_STATUS_FULL;
else
do_dma(ai, &ai->fifo[1]);
}
else
{
ai->fifo[0].address = ai->regs[AI_DRAM_ADDR_REG];
ai->fifo[0].length = ai->regs[AI_LEN_REG];
ai->fifo[0].duration = duration;
ai->regs[AI_STATUS_REG] |= AI_STATUS_BUSY;
do_dma(ai, &ai->fifo[0]);
}
}
static void fifo_pop(struct ai_controller* ai)
{
if (ai->regs[AI_STATUS_REG] & AI_STATUS_FULL)
{
ai->fifo[0].address = ai->fifo[1].address;
ai->fifo[0].length = ai->fifo[1].length;
ai->fifo[0].duration = ai->fifo[1].duration;
ai->regs[AI_STATUS_REG] &= ~AI_STATUS_FULL;
do_dma(ai, &ai->fifo[0]);
}
else
{
ai->regs[AI_STATUS_REG] &= ~AI_STATUS_BUSY;
}
}
void set_audio_format(struct ai_controller* ai, unsigned int frequency, unsigned int bits)
{
ai->set_audio_format(ai->user_data, frequency, bits);
}
void push_audio_samples(struct ai_controller* ai, const void* buffer, size_t size)
{
ai->push_audio_samples(ai->user_data, buffer, size);
}
void connect_ai(struct ai_controller* ai,
struct r4300_core* r4300,
struct ri_controller* ri,
struct vi_controller* vi)
{
ai->r4300 = r4300;
ai->ri = ri;
ai->vi = vi;
}
void init_ai(struct ai_controller* ai)
{
memset(ai->regs, 0, AI_REGS_COUNT*sizeof(uint32_t));
memset(ai->fifo, 0, 2*sizeof(struct ai_dma));
ai->samples_format_changed = 0;
}
int read_ai_regs(void* opaque, uint32_t address, uint32_t* value)
{
struct ai_controller* ai = (struct ai_controller*)opaque;
uint32_t reg = ai_reg(address);
if (reg == AI_LEN_REG)
{
*value = get_remaining_dma_length(ai);
}
else
{
*value = ai->regs[reg];
}
return 0;
}
int write_ai_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask)
{
struct ai_controller* ai = (struct ai_controller*)opaque;
uint32_t reg = ai_reg(address);
switch (reg)
{
case AI_LEN_REG:
masked_write(&ai->regs[AI_LEN_REG], value, mask);
fifo_push(ai);
return 0;
case AI_STATUS_REG:
clear_rcp_interrupt(ai->r4300, MI_INTR_AI);
ai->r4300->mi.AudioIntrReg &= ~MI_INTR_AI;
return 0;
case AI_BITRATE_REG:
case AI_DACRATE_REG:
/* lazy audio format setting */
if ((ai->regs[reg]) != (value & mask))
ai->samples_format_changed = 1;
masked_write(&ai->regs[reg], value, mask);
return 0;
}
masked_write(&ai->regs[reg], value, mask);
return 0;
}
void ai_end_of_dma_event(struct ai_controller* ai)
{
fifo_pop(ai);
ai->r4300->mi.AudioIntrReg |= MI_INTR_AI;
raise_rcp_interrupt(ai->r4300, MI_INTR_AI);
}

View file

@ -0,0 +1,91 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - ai_controller.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_AI_AI_CONTROLLER_H
#define M64P_AI_AI_CONTROLLER_H
#include <stddef.h>
#include <stdint.h>
#include "osal/preproc.h"
struct r4300_core;
struct ri_controller;
struct vi_controller;
enum ai_registers
{
AI_DRAM_ADDR_REG,
AI_LEN_REG,
AI_CONTROL_REG,
AI_STATUS_REG,
AI_DACRATE_REG,
AI_BITRATE_REG,
AI_REGS_COUNT
};
struct ai_dma
{
uint32_t address;
uint32_t length;
unsigned int duration;
};
struct ai_controller
{
uint32_t regs[AI_REGS_COUNT];
struct ai_dma fifo[2];
unsigned int samples_format_changed;
/* external speaker output */
void* user_data;
void (*set_audio_format)(void*,unsigned int, unsigned int);
void (*push_audio_samples)(void*,const void*,size_t);
struct r4300_core* r4300;
struct ri_controller* ri;
struct vi_controller* vi;
};
static osal_inline uint32_t ai_reg(uint32_t address)
{
return (address & 0xffff) >> 2;
}
/* This is for enablefifofull */
void ai_fifo_queue_int(struct ai_controller* ai);
void set_audio_format(struct ai_controller* ai, unsigned int frequency, unsigned int bits);
void push_audio_samples(struct ai_controller* ai, const void* buffer, size_t size);
void connect_ai(struct ai_controller* ai,
struct r4300_core* r4300,
struct ri_controller* ri,
struct vi_controller* vi);
void init_ai(struct ai_controller* ai);
int read_ai_regs(void* opaque, uint32_t address, uint32_t* value);
int write_ai_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask);
void ai_end_of_dma_event(struct ai_controller* ai);
#endif

View file

@ -0,0 +1,70 @@
{ global:
ConfigDeleteSection;
ConfigGetParamBool;
ConfigGetParameter;
ConfigGetParameterHelp;
ConfigGetParameterType;
ConfigGetParamFloat;
ConfigGetParamInt;
ConfigGetParamString;
ConfigGetSharedDataFilepath;
ConfigGetUserCachePath;
ConfigGetUserConfigPath;
ConfigGetUserDataPath;
ConfigHasUnsavedChanges;
ConfigListParameters;
ConfigListSections;
ConfigOpenSection;
ConfigRevertChanges;
ConfigSaveFile;
ConfigSaveSection;
ConfigSetDefaultBool;
ConfigSetDefaultFloat;
ConfigSetDefaultInt;
ConfigSetDefaultString;
ConfigSetParameter;
ConfigSetParameterHelp;
CoreAddCheat;
CoreAttachPlugin;
CoreCheatEnabled;
CoreDetachPlugin;
CoreDoCommand;
CoreErrorMessage;
CoreGetAPIVersions;
CoreGetRomSettings;
CoreOverrideVidExt;
CoreShutdown;
CoreStartup;
DebugBreakpointCommand;
DebugBreakpointLookup;
DebugDecodeOp;
DebugGetCPUDataPtr;
DebugGetState;
DebugMemGetMemInfo;
DebugMemGetPointer;
DebugMemGetRecompInfo;
DebugMemRead16;
DebugMemRead32;
DebugMemRead64;
DebugMemRead8;
DebugMemWrite16;
DebugMemWrite32;
DebugMemWrite64;
DebugMemWrite8;
DebugSetCallbacks;
DebugSetCoreCompare;
DebugSetRunState;
DebugStep;
PluginGetVersion;
VidExt_GL_GetProcAddress;
VidExt_GL_SetAttribute;
VidExt_GL_GetAttribute;
VidExt_GL_SwapBuffers;
VidExt_Init;
VidExt_ListFullscreenModes;
VidExt_Quit;
VidExt_SetCaption;
VidExt_SetVideoMode;
VidExt_ToggleFullScreen;
VidExt_ResizeWindow;
local: *; };

View file

@ -0,0 +1,77 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-core - api/callbacks.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2009 Richard Goedeken *
* *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* This file contains the Core functions for handling callbacks to the
* front-end application
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "usf/usf.h"
#include "usf/usf_internal.h"
#include "m64p_types.h"
#include "callbacks.h"
void DebugMessage(usf_state_t * state, int level, const char *message, ...)
{
va_list args;
size_t len;
if (
#ifdef DEBUG_INFO
1 ||
#endif
level > 1 )
{
#ifdef DEBUG_INFO
char buffer[1024];
va_start(args, message);
vsprintf(buffer, message, args);
va_end(args);
fprintf(state->debug_log, "%s\n", buffer);
if ( level > 1 )
#endif
return;
}
len = strlen( state->error_message );
if ( len )
state->error_message[ len++ ] = '\n';
va_start(args, message);
#if _MSC_VER >= 1300
vsprintf_s(state->error_message + len, 16384 - len, message, args);
#else
vsprintf(state->error_message + len, message, args);
#endif
va_end(args);
state->last_error = state->error_message;
state->stop = 1;
}

View file

@ -0,0 +1,41 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-core - api/callbacks.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2009 Richard Goedeken *
* *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* This file contains the definitions for callback functions which will be
* called from the other Core modules
*/
#if !defined(API_CALLBACKS_H)
#define API_CALLBACKS_H
#include "usf/usf.h"
#include "m64p_types.h"
#include "m64p_frontend.h"
/* Functions for use by the Core, to send information back to the front-end app */
extern m64p_error SetDebugCallback(usf_state_t *, ptr_DebugCallback pFunc, void *Context);
extern m64p_error SetStateCallback(usf_state_t *, ptr_StateCallback pFunc, void *Context);
extern void DebugMessage(usf_state_t *, int level, const char *message, ...);
extern void StateChanged(usf_state_t *, m64p_core_param param_type, int new_value);
#endif /* API_CALLBACKS_H */

View file

@ -0,0 +1,90 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-core - m64p_common.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2009 Richard Goedeken *
* *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* This header file defines typedefs for function pointers to common Core
* and plugin functions, for use by the front-end and plugin modules to attach
* to the dynamic libraries.
*/
#if !defined(M64P_COMMON_H)
#define M64P_COMMON_H
#include "m64p_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/* PluginGetVersion()
*
* This function retrieves version information from a library. This
* function is the same for the core library and the plugins.
*/
typedef m64p_error (*ptr_PluginGetVersion)(m64p_plugin_type *, int *, int *, const char **, int *);
#if defined(M64P_PLUGIN_PROTOTYPES) || defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *, int *, int *, const char **, int *);
#endif
/* CoreGetAPIVersions()
*
* This function retrieves API version information from the core.
*/
typedef m64p_error (*ptr_CoreGetAPIVersions)(int *, int *, int *, int *);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL CoreGetAPIVersions(int *, int *, int *, int *);
#endif
/* CoreErrorMessage()
*
* This function returns a pointer to a NULL-terminated string giving a
* human-readable description of the error.
*/
typedef const char * (*ptr_CoreErrorMessage)(m64p_error);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT const char * CALL CoreErrorMessage(m64p_error);
#endif
/* PluginStartup()
*
* This function initializes a plugin for use by allocating memory, creating
* data structures, and loading the configuration data.
*/
typedef m64p_error (*ptr_PluginStartup)(m64p_dynlib_handle, void *, void (*)(void *, int, const char *));
#if defined(M64P_PLUGIN_PROTOTYPES) || defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle, void *, void (*)(void *, int, const char *));
#endif
/* PluginShutdown()
*
* This function destroys data structures and releases memory allocated by
* the plugin library.
*/
typedef m64p_error (*ptr_PluginShutdown)(void);
#if defined(M64P_PLUGIN_PROTOTYPES) || defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL PluginShutdown(void);
#endif
#ifdef __cplusplus
}
#endif
#endif /* #define M64P_COMMON_H */

View file

@ -0,0 +1,252 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-core - m64p_config.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2009 Richard Goedeken *
* *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* This header file defines typedefs for function pointers to the Core's
* configuration handling functions.
*/
#if !defined(M64P_CONFIG_H)
#define M64P_CONFIG_H
#include "m64p_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/* ConfigListSections()
*
* This function is called to enumerate the list of Sections in the Mupen64Plus
* configuration file. It is expected that there will be a section named "Core"
* for core-specific configuration data, "Graphics" for common graphics options,
* and one or more sections for each plugin library.
*/
typedef m64p_error (*ptr_ConfigListSections)(void *, void (*)(void *, const char *));
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL ConfigListSections(void *, void (*)(void *, const char *));
#endif
/* ConfigOpenSection()
*
* This function is used to give a configuration section handle to the front-end
* which may be used to read or write configuration parameter values in a given
* section of the configuration file.
*/
typedef m64p_error (*ptr_ConfigOpenSection)(const char *, m64p_handle *);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL ConfigOpenSection(const char *, m64p_handle *);
#endif
/* ConfigListParameters()
*
* This function is called to enumerate the list of Parameters in a given
* Section of the Mupen64Plus configuration file.
*/
typedef m64p_error (*ptr_ConfigListParameters)(m64p_handle, void *, void (*)(void *, const char *, m64p_type));
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL ConfigListParameters(m64p_handle, void *, void (*)(void *, const char *, m64p_type));
#endif
/* ConfigSaveFile()
*
* This function saves the entire current Mupen64Plus configuration to disk.
*/
typedef m64p_error (*ptr_ConfigSaveFile)(void);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL ConfigSaveFile(void);
#endif
/* ConfigSaveSection()
*
* This function saves one section of the current Mupen64Plus configuration to disk.
*/
typedef m64p_error (*ptr_ConfigSaveSection)(const char *);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL ConfigSaveSection(const char *);
#endif
/* ConfigHasUnsavedChanges()
*
* This function determines if a given Section (or all sections) of the Mupen64Plus Core configuration file has been modified since it was last saved or loaded.
*/
typedef int (*ptr_ConfigHasUnsavedChanges)(const char *);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT int CALL ConfigHasUnsavedChanges(const char *);
#endif
/* ConfigDeleteSection()
*
* This function deletes a section from the Mupen64Plus configuration data.
*/
typedef m64p_error (*ptr_ConfigDeleteSection)(const char *SectionName);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL ConfigDeleteSection(const char *SectionName);
#endif
/* ConfigRevertChanges()
*
* This function reverts changes previously made to one section of the configuration file, so that it will match with the configuration at the last time that it was loaded from or saved to disk.
*/
typedef m64p_error (*ptr_ConfigRevertChanges)(const char *SectionName);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL ConfigRevertChanges(const char *SectionName);
#endif
/* ConfigSetParameter()
*
* This function sets the value of one of the emulator's configuration
* parameters.
*/
typedef m64p_error (*ptr_ConfigSetParameter)(m64p_handle, const char *, m64p_type, const void *);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL ConfigSetParameter(m64p_handle, const char *, m64p_type, const void *);
#endif
/* ConfigSetParameterHelp()
*
* This function sets the help string of one of the emulator's configuration
* parameters.
*/
typedef m64p_error (*ptr_ConfigSetParameterHelp)(m64p_handle, const char *, const char *);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL ConfigSetParameterHelp(m64p_handle, const char *, const char *);
#endif
/* ConfigGetParameter()
*
* This function retrieves the value of one of the emulator's parameters.
*/
typedef m64p_error (*ptr_ConfigGetParameter)(m64p_handle, const char *, m64p_type, void *, int);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL ConfigGetParameter(m64p_handle, const char *, m64p_type, void *, int);
#endif
/* ConfigGetParameterType()
*
* This function retrieves the type of one of the emulator's parameters.
*/
typedef m64p_error (*ptr_ConfigGetParameterType)(m64p_handle, const char *, m64p_type *);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL ConfigGetParameterType(m64p_handle, const char *, m64p_type *);
#endif
/* ConfigGetParameterHelp()
*
* This function retrieves the help information about one of the emulator's
* parameters.
*/
typedef const char * (*ptr_ConfigGetParameterHelp)(m64p_handle, const char *);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT const char * CALL ConfigGetParameterHelp(m64p_handle, const char *);
#endif
/* ConfigSetDefault***()
*
* These functions are used to set the value of a configuration parameter if it
* is not already present in the configuration file. This may happen if a new
* user runs the emulator, or an upgraded module uses a new parameter, or the
* user deletes his or her configuration file. If the parameter is already
* present in the given section of the configuration file, then no action will
* be taken and this function will return successfully.
*/
typedef m64p_error (*ptr_ConfigSetDefaultInt)(m64p_handle, const char *, int, const char *);
typedef m64p_error (*ptr_ConfigSetDefaultFloat)(m64p_handle, const char *, float, const char *);
typedef m64p_error (*ptr_ConfigSetDefaultBool)(m64p_handle, const char *, int, const char *);
typedef m64p_error (*ptr_ConfigSetDefaultString)(m64p_handle, const char *, const char *, const char *);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL ConfigSetDefaultInt(m64p_handle, const char *, int, const char *);
EXPORT m64p_error CALL ConfigSetDefaultFloat(m64p_handle, const char *, float, const char *);
EXPORT m64p_error CALL ConfigSetDefaultBool(m64p_handle, const char *, int, const char *);
EXPORT m64p_error CALL ConfigSetDefaultString(m64p_handle, const char *, const char *, const char *);
#endif
/* ConfigGetParam***()
*
* These functions retrieve the value of one of the emulator's parameters in
* the given section, and return the value directly to the calling function. If
* an errors occurs (such as an invalid Section handle, or invalid
* configuration parameter name), then an error will be sent to the front-end
* via the DebugCallback() function, and either a 0 (zero) or an empty string
* will be returned.
*/
typedef int (*ptr_ConfigGetParamInt)(m64p_handle, const char *);
typedef float (*ptr_ConfigGetParamFloat)(m64p_handle, const char *);
typedef int (*ptr_ConfigGetParamBool)(m64p_handle, const char *);
typedef const char * (*ptr_ConfigGetParamString)(m64p_handle, const char *);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT int CALL ConfigGetParamInt(m64p_handle, const char *);
EXPORT float CALL ConfigGetParamFloat(m64p_handle, const char *);
EXPORT int CALL ConfigGetParamBool(m64p_handle, const char *);
EXPORT const char * CALL ConfigGetParamString(m64p_handle, const char *);
#endif
/* ConfigGetSharedDataFilepath()
*
* This function is provided to allow a plugin to retrieve a full pathname to a
* given shared data file. This type of file is intended to be shared among
* multiple users on a system, so it is likely to be read-only.
*/
typedef const char * (*ptr_ConfigGetSharedDataFilepath)(const char *);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT const char * CALL ConfigGetSharedDataFilepath(const char *);
#endif
/* ConfigGetUserConfigPath()
*
* This function may be used by the plugins or front-end to get a path to the
* directory for storing user-specific configuration files. This will be the
* directory where "mupen64plus.cfg" is located.
*/
typedef const char * (*ptr_ConfigGetUserConfigPath)(void);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT const char * CALL ConfigGetUserConfigPath(void);
#endif
/* ConfigGetUserDataPath()
*
* This function may be used by the plugins or front-end to get a path to the
* directory for storing user-specific data files. This may be used to store
* files such as screenshots, saved game states, or hi-res textures.
*/
typedef const char * (*ptr_ConfigGetUserDataPath)(void);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT const char * CALL ConfigGetUserDataPath(void);
#endif
/* ConfigGetUserCachePath()
*
* This function may be used by the plugins or front-end to get a path to the
* directory for storing cached user-specific data files. Files in this
* directory may be deleted by the user to save space, so critical information
* should not be stored here. This directory may be used to store files such
* as the ROM browser cache.
*/
typedef const char * (*ptr_ConfigGetUserCachePath)(void);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT const char * CALL ConfigGetUserCachePath(void);
#endif
#ifdef __cplusplus
}
#endif
#endif /* #define M64P_CONFIG_H */

View file

@ -0,0 +1,202 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-core - m64p_debugger.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2009 Richard Goedeken *
* *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* This header file defines typedefs for function pointers to Core Debugger
* functions.
*/
#if !defined(M64P_DEBUGGER_H)
#define M64P_DEBUGGER_H
#include "m64p_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/* DebugSetCallbacks()
*
* This function is called by the front-end to supply debugger callback
* function pointers. If debugger is enabled and then later disabled within the
* UI, this function may be called with NULL pointers in order to disable the
* callbacks.
*/
typedef m64p_error (*ptr_DebugSetCallbacks)(void (*)(void), void (*)(unsigned int), void (*)(void));
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL DebugSetCallbacks(void (*)(void), void (*)(unsigned int), void (*)(void));
#endif
/* DebugSetCoreCompare()
*
* This function is called by the front-end to supply callback function pointers
* for the Core Comparison feature.
*/
typedef m64p_error (*ptr_DebugSetCoreCompare)(void (*)(unsigned int), void (*)(int, void *));
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL DebugSetCoreCompare(void (*)(unsigned int), void (*)(int, void *));
#endif
/* DebugSetRunState()
*
* This function sets the run state of the R4300 CPU emulator.
*/
typedef m64p_error (*ptr_DebugSetRunState)(m64p_dbg_runstate);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL DebugSetRunState(m64p_dbg_runstate);
#endif
/* DebugGetState()
*
* This function reads and returns a debugger state variable, which are
* enumerated in m64p_types.h.
*/
typedef int (*ptr_DebugGetState)(m64p_dbg_state);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT int CALL DebugGetState(m64p_dbg_state);
#endif
/* DebugStep()
*
* This function signals the debugger to advance one instruction when in the
* stepping mode.
*/
typedef m64p_error (*ptr_DebugStep)(void);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL DebugStep(void);
#endif
/* DebugDecodeOp()
*
* This is a helper function for the debugger front-end. This instruction takes
* a PC value and an R4300 instruction opcode and writes the disassembled
* instruction mnemonic and arguments into character buffers. This is intended
* to be used to display disassembled code.
*/
typedef void (*ptr_DebugDecodeOp)(unsigned int, char *, char *, int);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT void CALL DebugDecodeOp(unsigned int, char *, char *, int);
#endif
/* DebugMemGetRecompInfo()
*
* This function is used by the front-end to retrieve disassembly information
* about recompiled code. For example, the dynamic recompiler may take a single
* R4300 instruction and compile it into 10 x86 instructions. This function may
* then be used to retrieve the disassembled code of the 10 x86 instructions.
*/
typedef void * (*ptr_DebugMemGetRecompInfo)(m64p_dbg_mem_info, unsigned int, int);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT void * CALL DebugMemGetRecompInfo(m64p_dbg_mem_info, unsigned int, int);
#endif
/* DebugMemGetMemInfo()
*
* This function returns an integer value regarding the memory location address,
* corresponding to the information requested by mem_info_type, which is a type
* enumerated in m64p_types.h.
*/
typedef int (*ptr_DebugMemGetMemInfo)(m64p_dbg_mem_info, unsigned int);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT int CALL DebugMemGetMemInfo(m64p_dbg_mem_info, unsigned int);
#endif
/* DebugMemGetPointer()
*
* This function returns a memory pointer (in x86 memory space) to a block of
* emulated N64 memory. This may be used to retrieve a pointer to a special N64
* block (such as the serial, video, or audio registers) or the RDRAM.
*/
typedef void * (*ptr_DebugMemGetPointer)(m64p_dbg_memptr_type);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT void * CALL DebugMemGetPointer(m64p_dbg_memptr_type);
#endif
/* DebugMemRead**()
*
* These functions retrieve a value from the emulated N64 memory. The returned
* value will be correctly byte-swapped for the host architecture.
*/
typedef unsigned long long (*ptr_DebugMemRead64)(unsigned int);
typedef unsigned int (*ptr_DebugMemRead32)(unsigned int);
typedef unsigned short (*ptr_DebugMemRead16)(unsigned int);
typedef unsigned char (*ptr_DebugMemRead8)(unsigned int);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT unsigned long long CALL DebugMemRead64(unsigned int);
EXPORT unsigned int CALL DebugMemRead32(unsigned int);
EXPORT unsigned short CALL DebugMemRead16(unsigned int);
EXPORT unsigned char CALL DebugMemRead8(unsigned int);
#endif
/* DebugMemWrite**()
*
* These functions write a value into the emulated N64 memory. The given value
* will be correctly byte-swapped before storage.
*/
typedef void (*ptr_DebugMemWrite64)(unsigned int, unsigned long long);
typedef void (*ptr_DebugMemWrite32)(unsigned int, unsigned int);
typedef void (*ptr_DebugMemWrite16)(unsigned int, unsigned short);
typedef void (*ptr_DebugMemWrite8)(unsigned int, unsigned char);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT void CALL DebugMemWrite64(unsigned int, unsigned long long);
EXPORT void CALL DebugMemWrite32(unsigned int, unsigned int);
EXPORT void CALL DebugMemWrite16(unsigned int, unsigned short);
EXPORT void CALL DebugMemWrite8(unsigned int, unsigned char);
#endif
/* DebugGetCPUDataPtr()
*
* This function returns a memory pointer (in x86 memory space) to a specific
* register in the emulated R4300 CPU.
*/
typedef void * (*ptr_DebugGetCPUDataPtr)(m64p_dbg_cpu_data);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT void * CALL DebugGetCPUDataPtr(m64p_dbg_cpu_data);
#endif
/* DebugBreakpointLookup()
*
* This function searches through all current breakpoints in the debugger to
* find one that matches the given input parameters. If a matching breakpoint
* is found, the index number is returned. If no breakpoints are found, -1 is
* returned.
*/
typedef int (*ptr_DebugBreakpointLookup)(unsigned int, unsigned int, unsigned int);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT int CALL DebugBreakpointLookup(unsigned int, unsigned int, unsigned int);
#endif
/* DebugBreakpointCommand()
*
* This function is used to process common breakpoint commands, such as adding,
* removing, or searching the breakpoints. The meanings of the index and ptr
* input parameters vary by command.
*/
typedef int (*ptr_DebugBreakpointCommand)(m64p_dbg_bkp_command, unsigned int, m64p_breakpoint *);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT int CALL DebugBreakpointCommand(m64p_dbg_bkp_command, unsigned int, m64p_breakpoint *);
#endif
#ifdef __cplusplus
}
#endif
#endif /* #define M64P_DEBUGGER_H */

View file

@ -0,0 +1,141 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-core - m64p_frontend.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2009 Richard Goedeken *
* *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* This header file defines typedefs for function pointers to Core functions
* designed for use by the front-end user interface.
*/
#if !defined(M64P_FRONTEND_H)
#define M64P_FRONTEND_H
#include "m64p_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/* pointer types to the callback functions in the front-end application */
typedef void (*ptr_DebugCallback)(void *Context, int level, const char *message);
typedef void (*ptr_StateCallback)(void *Context, m64p_core_param param_type, int new_value);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT void CALL DebugCallback(void *Context, int level, const char *message);
EXPORT void CALL StateCallback(void *Context, m64p_core_param param_type, int new_value);
#endif
/* CoreStartup()
*
* This function initializes libmupen64plus for use by allocating memory,
* creating data structures, and loading the configuration file.
*/
typedef m64p_error (*ptr_CoreStartup)(int, const char *, const char *, void *, ptr_DebugCallback, void *, ptr_StateCallback);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL CoreStartup(int, const char *, const char *, void *, ptr_DebugCallback, void *, ptr_StateCallback);
#endif
/* CoreShutdown()
*
* This function saves the configuration file, then destroys data structures
* and releases memory allocated by the core library.
*/
typedef m64p_error (*ptr_CoreShutdown)(void);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL CoreShutdown(void);
#endif
/* CoreAttachPlugin()
*
* This function attaches the given plugin to the emulator core. There can only
* be one plugin of each type attached to the core at any given time.
*/
typedef m64p_error (*ptr_CoreAttachPlugin)(m64p_plugin_type, m64p_dynlib_handle);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL CoreAttachPlugin(m64p_plugin_type, m64p_dynlib_handle);
#endif
/* CoreDetachPlugin()
*
* This function detaches the given plugin from the emulator core, and re-attaches
* the 'dummy' plugin functions.
*/
typedef m64p_error (*ptr_CoreDetachPlugin)(m64p_plugin_type);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL CoreDetachPlugin(m64p_plugin_type);
#endif
/* CoreDoCommand()
*
* This function sends a command to the emulator core.
*/
typedef m64p_error (*ptr_CoreDoCommand)(m64p_command, int, void *);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL CoreDoCommand(m64p_command, int, void *);
#endif
/* CoreOverrideVidExt()
*
* This function overrides the core's internal SDL-based OpenGL functions. This
* override functionality allows a front-end to define its own video extension
* functions to be used instead of the SDL functions. If any of the function
* pointers in the structure are NULL, the override function will be disabled
* and the core's internal SDL functions will be used.
*/
typedef m64p_error (*ptr_CoreOverrideVidExt)(m64p_video_extension_functions *);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL CoreOverrideVidExt(m64p_video_extension_functions *);
#endif
/* CoreAddCheat()
*
* This function will add a Cheat Function to a list of currently active cheats
* which are applied to the open ROM.
*/
typedef m64p_error (*ptr_CoreAddCheat)(const char *, m64p_cheat_code *, int);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL CoreAddCheat(const char *, m64p_cheat_code *, int);
#endif
/* CoreCheatEnabled()
*
* This function will enable or disable a Cheat Function which is in the list of
* currently active cheats.
*/
typedef m64p_error (*ptr_CoreCheatEnabled)(const char *, int);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL CoreCheatEnabled(const char *, int);
#endif
/* CoreGetRomSettings()
*
* This function will retrieve the ROM settings from the mupen64plus INI file for
* the ROM image corresponding to the given CRC values.
*/
typedef m64p_error (*ptr_CoreGetRomSettings)(m64p_rom_settings *, int, int, int);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL CoreGetRomSettings(m64p_rom_settings *, int, int, int);
#endif
#ifdef __cplusplus
}
#endif
#endif /* #define M64P_FRONTEND_H */

View file

@ -0,0 +1,273 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-core - m64p_plugin.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2002 Hacktarux *
* Copyright (C) 2009 Richard Goedeken *
* *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#if !defined(M64P_PLUGIN_H)
#define M64P_PLUGIN_H
#include "m64p_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/*** Controller plugin's ****/
#define PLUGIN_NONE 1
#define PLUGIN_MEMPAK 2
#define PLUGIN_RUMBLE_PAK 3 /* not implemented for non raw data */
#define PLUGIN_TRANSFER_PAK 4 /* not implemented for non raw data */
#define PLUGIN_RAW 5 /* the controller plugin is passed in raw data */
/***** Structures *****/
typedef struct {
unsigned char * RDRAM;
unsigned char * DMEM;
unsigned char * IMEM;
unsigned int * MI_INTR_REG;
unsigned int * SP_MEM_ADDR_REG;
unsigned int * SP_DRAM_ADDR_REG;
unsigned int * SP_RD_LEN_REG;
unsigned int * SP_WR_LEN_REG;
unsigned int * SP_STATUS_REG;
unsigned int * SP_DMA_FULL_REG;
unsigned int * SP_DMA_BUSY_REG;
unsigned int * SP_PC_REG;
unsigned int * SP_SEMAPHORE_REG;
unsigned int * DPC_START_REG;
unsigned int * DPC_END_REG;
unsigned int * DPC_CURRENT_REG;
unsigned int * DPC_STATUS_REG;
unsigned int * DPC_CLOCK_REG;
unsigned int * DPC_BUFBUSY_REG;
unsigned int * DPC_PIPEBUSY_REG;
unsigned int * DPC_TMEM_REG;
void (*CheckInterrupts)(void);
void (*ProcessDlistList)(void);
void (*ProcessAlistList)(void);
void (*ProcessRdpList)(void);
void (*ShowCFB)(void);
} RSP_INFO;
typedef struct {
unsigned char * HEADER; /* This is the rom header (first 40h bytes of the rom) */
unsigned char * RDRAM;
unsigned char * DMEM;
unsigned char * IMEM;
unsigned int * MI_INTR_REG;
unsigned int * DPC_START_REG;
unsigned int * DPC_END_REG;
unsigned int * DPC_CURRENT_REG;
unsigned int * DPC_STATUS_REG;
unsigned int * DPC_CLOCK_REG;
unsigned int * DPC_BUFBUSY_REG;
unsigned int * DPC_PIPEBUSY_REG;
unsigned int * DPC_TMEM_REG;
unsigned int * VI_STATUS_REG;
unsigned int * VI_ORIGIN_REG;
unsigned int * VI_WIDTH_REG;
unsigned int * VI_INTR_REG;
unsigned int * VI_V_CURRENT_LINE_REG;
unsigned int * VI_TIMING_REG;
unsigned int * VI_V_SYNC_REG;
unsigned int * VI_H_SYNC_REG;
unsigned int * VI_LEAP_REG;
unsigned int * VI_H_START_REG;
unsigned int * VI_V_START_REG;
unsigned int * VI_V_BURST_REG;
unsigned int * VI_X_SCALE_REG;
unsigned int * VI_Y_SCALE_REG;
void (*CheckInterrupts)(void);
} GFX_INFO;
typedef struct {
unsigned char * RDRAM;
unsigned char * DMEM;
unsigned char * IMEM;
unsigned int * MI_INTR_REG;
unsigned int * AI_DRAM_ADDR_REG;
unsigned int * AI_LEN_REG;
unsigned int * AI_CONTROL_REG;
unsigned int * AI_STATUS_REG;
unsigned int * AI_DACRATE_REG;
unsigned int * AI_BITRATE_REG;
void (*CheckInterrupts)(void);
} AUDIO_INFO;
typedef struct {
int Present;
int RawData;
int Plugin;
} CONTROL;
typedef union {
unsigned int Value;
struct {
unsigned R_DPAD : 1;
unsigned L_DPAD : 1;
unsigned D_DPAD : 1;
unsigned U_DPAD : 1;
unsigned START_BUTTON : 1;
unsigned Z_TRIG : 1;
unsigned B_BUTTON : 1;
unsigned A_BUTTON : 1;
unsigned R_CBUTTON : 1;
unsigned L_CBUTTON : 1;
unsigned D_CBUTTON : 1;
unsigned U_CBUTTON : 1;
unsigned R_TRIG : 1;
unsigned L_TRIG : 1;
unsigned Reserved1 : 1;
unsigned Reserved2 : 1;
signed X_AXIS : 8;
signed Y_AXIS : 8;
};
} BUTTONS;
typedef struct {
CONTROL *Controls; /* A pointer to an array of 4 controllers .. eg:
CONTROL Controls[4]; */
} CONTROL_INFO;
/* common plugin function pointer types */
typedef void (*ptr_RomClosed)(void);
typedef int (*ptr_RomOpen)(void);
#if defined(M64P_PLUGIN_PROTOTYPES)
EXPORT int CALL RomOpen(void);
EXPORT void CALL RomClosed(void);
#endif
/* video plugin function pointer types */
typedef void (*ptr_ChangeWindow)(void);
typedef int (*ptr_InitiateGFX)(GFX_INFO Gfx_Info);
typedef void (*ptr_MoveScreen)(int x, int y);
typedef void (*ptr_ProcessDList)(void);
typedef void (*ptr_ProcessRDPList)(void);
typedef void (*ptr_ShowCFB)(void);
typedef void (*ptr_UpdateScreen)(void);
typedef void (*ptr_ViStatusChanged)(void);
typedef void (*ptr_ViWidthChanged)(void);
typedef void (*ptr_ReadScreen2)(void *dest, int *width, int *height, int front);
typedef void (*ptr_SetRenderingCallback)(void (*callback)(int));
typedef void (*ptr_ResizeVideoOutput)(int width, int height);
#if defined(M64P_PLUGIN_PROTOTYPES)
EXPORT void CALL ChangeWindow(void);
EXPORT int CALL InitiateGFX(GFX_INFO Gfx_Info);
EXPORT void CALL MoveScreen(int x, int y);
EXPORT void CALL ProcessDList(void);
EXPORT void CALL ProcessRDPList(void);
EXPORT void CALL ShowCFB(void);
EXPORT void CALL UpdateScreen(void);
EXPORT void CALL ViStatusChanged(void);
EXPORT void CALL ViWidthChanged(void);
EXPORT void CALL ReadScreen2(void *dest, int *width, int *height, int front);
EXPORT void CALL SetRenderingCallback(void (*callback)(int));
EXPORT void CALL ResizeVideoOutput(int width, int height);
#endif
/* frame buffer plugin spec extension */
typedef struct
{
unsigned int addr;
unsigned int size;
unsigned int width;
unsigned int height;
} FrameBufferInfo;
typedef void (*ptr_FBRead)(unsigned int addr);
typedef void (*ptr_FBWrite)(unsigned int addr, unsigned int size);
typedef void (*ptr_FBGetFrameBufferInfo)(void *p);
#if defined(M64P_PLUGIN_PROTOTYPES)
EXPORT void CALL FBRead(unsigned int addr);
EXPORT void CALL FBWrite(unsigned int addr, unsigned int size);
EXPORT void CALL FBGetFrameBufferInfo(void *p);
#endif
/* audio plugin function pointers */
typedef void (*ptr_AiDacrateChanged)(int SystemType);
typedef void (*ptr_AiLenChanged)(void);
typedef int (*ptr_InitiateAudio)(AUDIO_INFO Audio_Info);
typedef void (*ptr_ProcessAList)(void);
typedef void (*ptr_SetSpeedFactor)(int percent);
typedef void (*ptr_VolumeUp)(void);
typedef void (*ptr_VolumeDown)(void);
typedef int (*ptr_VolumeGetLevel)(void);
typedef void (*ptr_VolumeSetLevel)(int level);
typedef void (*ptr_VolumeMute)(void);
typedef const char * (*ptr_VolumeGetString)(void);
#if defined(M64P_PLUGIN_PROTOTYPES)
EXPORT void CALL AiDacrateChanged(int SystemType);
EXPORT void CALL AiLenChanged(void);
EXPORT int CALL InitiateAudio(AUDIO_INFO Audio_Info);
EXPORT void CALL ProcessAList(void);
EXPORT void CALL SetSpeedFactor(int percent);
EXPORT void CALL VolumeUp(void);
EXPORT void CALL VolumeDown(void);
EXPORT int CALL VolumeGetLevel(void);
EXPORT void CALL VolumeSetLevel(int level);
EXPORT void CALL VolumeMute(void);
EXPORT const char * CALL VolumeGetString(void);
#endif
/* input plugin function pointers */
typedef void (*ptr_ControllerCommand)(int Control, unsigned char *Command);
typedef void (*ptr_GetKeys)(int Control, BUTTONS *Keys);
typedef void (*ptr_InitiateControllers)(CONTROL_INFO ControlInfo);
typedef void (*ptr_ReadController)(int Control, unsigned char *Command);
typedef void (*ptr_SDL_KeyDown)(int keymod, int keysym);
typedef void (*ptr_SDL_KeyUp)(int keymod, int keysym);
typedef void (*ptr_RenderCallback)(void);
#if defined(M64P_PLUGIN_PROTOTYPES)
EXPORT void CALL ControllerCommand(int Control, unsigned char *Command);
EXPORT void CALL GetKeys(int Control, BUTTONS *Keys);
EXPORT void CALL InitiateControllers(CONTROL_INFO ControlInfo);
EXPORT void CALL ReadController(int Control, unsigned char *Command);
EXPORT void CALL SDL_KeyDown(int keymod, int keysym);
EXPORT void CALL SDL_KeyUp(int keymod, int keysym);
EXPORT void CALL RenderCallback(void);
#endif
/* RSP plugin function pointers */
typedef unsigned int (*ptr_DoRspCycles)(unsigned int Cycles);
typedef void (*ptr_InitiateRSP)(RSP_INFO Rsp_Info, unsigned int *CycleCount);
#if defined(M64P_PLUGIN_PROTOTYPES)
EXPORT unsigned int CALL DoRspCycles(unsigned int Cycles);
EXPORT void CALL InitiateRSP(RSP_INFO Rsp_Info, unsigned int *CycleCount);
#endif
#ifdef __cplusplus
}
#endif
#endif /* M64P_PLUGIN_H */

View file

@ -0,0 +1,365 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-core - m64p_types.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2012 CasualJames *
* Copyright (C) 2009 Richard Goedeken *
* *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#if !defined(M64P_TYPES_H)
#define M64P_TYPES_H
/* ----------------------------------------- */
/* Platform-specific stuff */
/* ----------------------------------------- */
/* necessary headers */
#if defined(WIN32)
#include <windows.h>
#endif
/* DLL handles and function declaration specifiers */
#if defined(WIN32)
#define IMPORT extern "C" __declspec(dllimport)
#define EXPORT __declspec(dllexport)
#define CALL __cdecl
typedef HMODULE m64p_dynlib_handle;
#else
#define IMPORT extern "C"
#define EXPORT __attribute__((visibility("default")))
#define CALL
typedef void * m64p_dynlib_handle;
#endif
/* ----------------------------------------- */
/* Structures and Types for Core library API */
/* ----------------------------------------- */
typedef void * m64p_handle;
typedef void (*m64p_frame_callback)(unsigned int FrameIndex);
typedef void (*m64p_input_callback)(void);
typedef void (*m64p_audio_callback)(void);
typedef void (*m64p_vi_callback)(void);
typedef enum {
M64TYPE_INT = 1,
M64TYPE_FLOAT,
M64TYPE_BOOL,
M64TYPE_STRING
} m64p_type;
typedef enum {
M64MSG_ERROR = 1,
M64MSG_WARNING,
M64MSG_INFO,
M64MSG_STATUS,
M64MSG_VERBOSE
} m64p_msg_level;
typedef enum {
M64ERR_SUCCESS = 0,
M64ERR_NOT_INIT, /* Function is disallowed before InitMupen64Plus() is called */
M64ERR_ALREADY_INIT, /* InitMupen64Plus() was called twice */
M64ERR_INCOMPATIBLE, /* API versions between components are incompatible */
M64ERR_INPUT_ASSERT, /* Invalid parameters for function call, such as ParamValue=NULL for GetCoreParameter() */
M64ERR_INPUT_INVALID, /* Invalid input data, such as ParamValue="maybe" for SetCoreParameter() to set a BOOL-type value */
M64ERR_INPUT_NOT_FOUND, /* The input parameter(s) specified a particular item which was not found */
M64ERR_NO_MEMORY, /* Memory allocation failed */
M64ERR_FILES, /* Error opening, creating, reading, or writing to a file */
M64ERR_INTERNAL, /* Internal error (bug) */
M64ERR_INVALID_STATE, /* Current program state does not allow operation */
M64ERR_PLUGIN_FAIL, /* A plugin function returned a fatal error */
M64ERR_SYSTEM_FAIL, /* A system function call, such as an SDL or file operation, failed */
M64ERR_UNSUPPORTED, /* Function call is not supported (ie, core not built with debugger) */
M64ERR_WRONG_TYPE /* A given input type parameter cannot be used for desired operation */
} m64p_error;
typedef enum {
M64CAPS_DYNAREC = 1,
M64CAPS_DEBUGGER = 2,
M64CAPS_CORE_COMPARE = 4
} m64p_core_caps;
typedef enum {
M64PLUGIN_NULL = 0,
M64PLUGIN_RSP = 1,
M64PLUGIN_GFX,
M64PLUGIN_AUDIO,
M64PLUGIN_INPUT,
M64PLUGIN_CORE
} m64p_plugin_type;
typedef enum {
M64EMU_STOPPED = 1,
M64EMU_RUNNING,
M64EMU_PAUSED
} m64p_emu_state;
typedef enum {
M64VIDEO_NONE = 1,
M64VIDEO_WINDOWED,
M64VIDEO_FULLSCREEN
} m64p_video_mode;
typedef enum {
M64VIDEOFLAG_SUPPORT_RESIZING = 1
} m64p_video_flags;
typedef enum {
M64CORE_EMU_STATE = 1,
M64CORE_VIDEO_MODE,
M64CORE_SAVESTATE_SLOT,
M64CORE_SPEED_FACTOR,
M64CORE_SPEED_LIMITER,
M64CORE_VIDEO_SIZE,
M64CORE_AUDIO_VOLUME,
M64CORE_AUDIO_MUTE,
M64CORE_INPUT_GAMESHARK,
M64CORE_STATE_LOADCOMPLETE,
M64CORE_STATE_SAVECOMPLETE
} m64p_core_param;
typedef enum {
M64CMD_NOP = 0,
M64CMD_ROM_OPEN,
M64CMD_ROM_CLOSE,
M64CMD_ROM_GET_HEADER,
M64CMD_ROM_GET_SETTINGS,
M64CMD_EXECUTE,
M64CMD_STOP,
M64CMD_PAUSE,
M64CMD_RESUME,
M64CMD_CORE_STATE_QUERY,
M64CMD_STATE_LOAD,
M64CMD_STATE_SAVE,
M64CMD_STATE_SET_SLOT,
M64CMD_SEND_SDL_KEYDOWN,
M64CMD_SEND_SDL_KEYUP,
M64CMD_SET_FRAME_CALLBACK,
M64CMD_TAKE_NEXT_SCREENSHOT,
M64CMD_CORE_STATE_SET,
M64CMD_READ_SCREEN,
M64CMD_RESET,
M64CMD_ADVANCE_FRAME
} m64p_command;
typedef struct {
unsigned int address;
int value;
} m64p_cheat_code;
/* ----------------------------------------- */
/* Structures to hold ROM image information */
/* ----------------------------------------- */
typedef enum
{
SYSTEM_NTSC = 0,
SYSTEM_PAL,
SYSTEM_MPAL
} m64p_system_type;
typedef struct
{
unsigned char init_PI_BSB_DOM1_LAT_REG; /* 0x00 */
unsigned char init_PI_BSB_DOM1_PGS_REG; /* 0x01 */
unsigned char init_PI_BSB_DOM1_PWD_REG; /* 0x02 */
unsigned char init_PI_BSB_DOM1_PGS_REG2; /* 0x03 */
unsigned int ClockRate; /* 0x04 */
unsigned int PC; /* 0x08 */
unsigned int Release; /* 0x0C */
unsigned int CRC1; /* 0x10 */
unsigned int CRC2; /* 0x14 */
unsigned int Unknown[2]; /* 0x18 */
unsigned char Name[20]; /* 0x20 */
unsigned int unknown; /* 0x34 */
unsigned int Manufacturer_ID; /* 0x38 */
unsigned short Cartridge_ID; /* 0x3C - Game serial number */
unsigned short Country_code; /* 0x3E */
} m64p_rom_header;
typedef struct
{
char goodname[256];
char MD5[33];
unsigned char savetype;
unsigned char status; /* Rom status on a scale from 0-5. */
unsigned char players; /* Local players 0-4, 2/3/4 way Netplay indicated by 5/6/7. */
unsigned char rumble; /* 0 - No, 1 - Yes boolean for rumble support. */
} m64p_rom_settings;
/* ----------------------------------------- */
/* Structures and Types for the Debugger */
/* ----------------------------------------- */
typedef enum {
M64P_DBG_RUN_STATE = 1,
M64P_DBG_PREVIOUS_PC,
M64P_DBG_NUM_BREAKPOINTS,
M64P_DBG_CPU_DYNACORE,
M64P_DBG_CPU_NEXT_INTERRUPT
} m64p_dbg_state;
typedef enum {
M64P_DBG_RUNSTATE_PAUSED = 0,
M64P_DBG_RUNSTATE_STEPPING,
M64P_DBG_RUNSTATE_RUNNING
} m64p_dbg_runstate;
typedef enum {
M64P_DBG_MEM_TYPE = 1,
M64P_DBG_MEM_FLAGS,
M64P_DBG_MEM_HAS_RECOMPILED,
M64P_DBG_MEM_NUM_RECOMPILED,
M64P_DBG_RECOMP_OPCODE = 16,
M64P_DBG_RECOMP_ARGS,
M64P_DBG_RECOMP_ADDR
} m64p_dbg_mem_info;
typedef enum {
M64P_MEM_NOMEM = 0,
M64P_MEM_NOTHING,
M64P_MEM_RDRAM,
M64P_MEM_RDRAMREG,
M64P_MEM_RSPMEM,
M64P_MEM_RSPREG,
M64P_MEM_RSP,
M64P_MEM_DP,
M64P_MEM_DPS,
M64P_MEM_VI,
M64P_MEM_AI,
M64P_MEM_PI,
M64P_MEM_RI,
M64P_MEM_SI,
M64P_MEM_FLASHRAMSTAT,
M64P_MEM_ROM,
M64P_MEM_PIF,
M64P_MEM_MI,
M64P_MEM_BREAKPOINT
} m64p_dbg_mem_type;
typedef enum {
M64P_MEM_FLAG_READABLE = 0x01,
M64P_MEM_FLAG_WRITABLE = 0x02,
M64P_MEM_FLAG_READABLE_EMUONLY = 0x04, /* the EMUONLY flags signify that emulated code can read/write here, but debugger cannot */
M64P_MEM_FLAG_WRITABLE_EMUONLY = 0x08
} m64p_dbg_mem_flags;
typedef enum {
M64P_DBG_PTR_RDRAM = 1,
M64P_DBG_PTR_PI_REG,
M64P_DBG_PTR_SI_REG,
M64P_DBG_PTR_VI_REG,
M64P_DBG_PTR_RI_REG,
M64P_DBG_PTR_AI_REG
} m64p_dbg_memptr_type;
typedef enum {
M64P_CPU_PC = 1,
M64P_CPU_REG_REG,
M64P_CPU_REG_HI,
M64P_CPU_REG_LO,
M64P_CPU_REG_COP0,
M64P_CPU_REG_COP1_DOUBLE_PTR,
M64P_CPU_REG_COP1_SIMPLE_PTR,
M64P_CPU_REG_COP1_FGR_64,
M64P_CPU_TLB
} m64p_dbg_cpu_data;
typedef enum {
M64P_BKP_CMD_ADD_ADDR = 1,
M64P_BKP_CMD_ADD_STRUCT,
M64P_BKP_CMD_REPLACE,
M64P_BKP_CMD_REMOVE_ADDR,
M64P_BKP_CMD_REMOVE_IDX,
M64P_BKP_CMD_ENABLE,
M64P_BKP_CMD_DISABLE,
M64P_BKP_CMD_CHECK
} m64p_dbg_bkp_command;
#define M64P_MEM_INVALID 0xFFFFFFFF /* invalid memory read will return this */
#define BREAKPOINTS_MAX_NUMBER 128
typedef enum {
M64P_BKP_FLAG_ENABLED = 0x01,
M64P_BKP_FLAG_READ = 0x02,
M64P_BKP_FLAG_WRITE = 0x04,
M64P_BKP_FLAG_EXEC = 0x08,
M64P_BKP_FLAG_LOG = 0x10 /* Log to the console when this breakpoint hits */
} m64p_dbg_bkp_flags;
#define BPT_CHECK_FLAG(a, b) ((a.flags & b) == b)
#define BPT_SET_FLAG(a, b) a.flags = (a.flags | b);
#define BPT_CLEAR_FLAG(a, b) a.flags = (a.flags & (~b));
#define BPT_TOGGLE_FLAG(a, b) a.flags = (a.flags ^ b);
typedef struct {
unsigned int address;
unsigned int endaddr;
unsigned int flags;
} m64p_breakpoint;
/* ------------------------------------------------- */
/* Structures and Types for Core Video Extension API */
/* ------------------------------------------------- */
typedef struct {
unsigned int uiWidth;
unsigned int uiHeight;
} m64p_2d_size;
typedef enum {
M64P_GL_DOUBLEBUFFER = 1,
M64P_GL_BUFFER_SIZE,
M64P_GL_DEPTH_SIZE,
M64P_GL_RED_SIZE,
M64P_GL_GREEN_SIZE,
M64P_GL_BLUE_SIZE,
M64P_GL_ALPHA_SIZE,
M64P_GL_SWAP_CONTROL,
M64P_GL_MULTISAMPLEBUFFERS,
M64P_GL_MULTISAMPLESAMPLES,
M64P_GL_CONTEXT_MAJOR_VERSION,
M64P_GL_CONTEXT_MINOR_VERSION,
M64P_GL_CONTEXT_PROFILE_MASK
} m64p_GLattr;
typedef enum {
M64P_GL_CONTEXT_PROFILE_CORE,
M64P_GL_CONTEXT_PROFILE_COMPATIBILITY,
M64P_GL_CONTEXT_PROFILE_ES
} m64p_GLContextType;
typedef struct {
unsigned int Functions;
m64p_error (*VidExtFuncInit)(void);
m64p_error (*VidExtFuncQuit)(void);
m64p_error (*VidExtFuncListModes)(m64p_2d_size *, int *);
m64p_error (*VidExtFuncSetMode)(int, int, int, int, int);
void * (*VidExtFuncGLGetProc)(const char*);
m64p_error (*VidExtFuncGLSetAttr)(m64p_GLattr, int);
m64p_error (*VidExtFuncGLGetAttr)(m64p_GLattr, int *);
m64p_error (*VidExtFuncGLSwapBuf)(void);
m64p_error (*VidExtFuncSetCaption)(const char *);
m64p_error (*VidExtFuncToggleFS)(void);
m64p_error (*VidExtFuncResizeWindow)(int, int);
} m64p_video_extension_functions;
#endif /* define M64P_TYPES_H */

View file

@ -0,0 +1,154 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-core - m64p_vidext.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2009 Richard Goedeken *
* *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* This header file defines typedefs for function pointers to the core's
* video extension functions.
*/
#if !defined(M64P_VIDEXT_H)
#define M64P_VIDEXT_H
#include "m64p_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/* VidExt_Init()
*
* This function should be called from within the InitiateGFX() video plugin
* function call. The default SDL implementation of this function simply calls
* SDL_InitSubSystem(SDL_INIT_VIDEO). It does not open a rendering window or
* switch video modes.
*/
typedef m64p_error (*ptr_VidExt_Init)(void);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL VidExt_Init(void);
#endif
/* VidExt_Quit()
*
* This function closes any open rendering window and shuts down the video
* system. The default SDL implementation of this function calls
* SDL_QuitSubSystem(SDL_INIT_VIDEO). This function should be called from
* within the RomClose() video plugin function.
*/
typedef m64p_error (*ptr_VidExt_Quit)(void);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL VidExt_Quit(void);
#endif
/* VidExt_ListFullscreenModes()
*
* This function is used to enumerate the available resolutions for fullscreen
* video modes. A pointer to an array is passed into the function, which is
* then filled with resolution sizes.
*/
typedef m64p_error (*ptr_VidExt_ListFullscreenModes)(m64p_2d_size *, int *);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL VidExt_ListFullscreenModes(m64p_2d_size *, int *);
#endif
/* VidExt_SetVideoMode()
*
* This function creates a rendering window or switches into a fullscreen
* video mode. Any desired OpenGL attributes should be set before calling
* this function.
*/
typedef m64p_error (*ptr_VidExt_SetVideoMode)(int, int, int, m64p_video_mode, m64p_video_flags);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL VidExt_SetVideoMode(int, int, int, m64p_video_mode, m64p_video_flags);
#endif
/* VidExt_ResizeWindow()
*
* This function resizes the opengl rendering window to match the given size.
*/
typedef m64p_error (*ptr_VidExt_ResizeWindow)(int, int);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL VidExt_ResizeWindow(int, int);
#endif
/* VidExt_SetCaption()
*
* This function sets the caption text of the emulator rendering window.
*/
typedef m64p_error (*ptr_VidExt_SetCaption)(const char *);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL VidExt_SetCaption(const char *);
#endif
/* VidExt_ToggleFullScreen()
*
* This function toggles between fullscreen and windowed rendering modes.
*/
typedef m64p_error (*ptr_VidExt_ToggleFullScreen)(void);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL VidExt_ToggleFullScreen(void);
#endif
/* VidExt_GL_GetProcAddress()
*
* This function is used to get a pointer to an OpenGL extension function. This
* is only necessary on the Windows platform, because the OpenGL implementation
* shipped with Windows only supports OpenGL version 1.1.
*/
typedef void * (*ptr_VidExt_GL_GetProcAddress)(const char *);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT void * CALL VidExt_GL_GetProcAddress(const char *);
#endif
/* VidExt_GL_SetAttribute()
*
* This function is used to set certain OpenGL attributes which must be
* specified before creating the rendering window with VidExt_SetVideoMode.
*/
typedef m64p_error (*ptr_VidExt_GL_SetAttribute)(m64p_GLattr, int);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL VidExt_GL_SetAttribute(m64p_GLattr, int);
#endif
/* VidExt_GL_GetAttribute()
*
* This function is used to get the value of OpenGL attributes. These values may
* be changed when calling VidExt_SetVideoMode.
*/
typedef m64p_error (*ptr_VidExt_GL_GetAttribute)(m64p_GLattr, int *);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL VidExt_GL_GetAttribute(m64p_GLattr, int *);
#endif
/* VidExt_GL_SwapBuffers()
*
* This function is used to swap the front/back buffers after rendering an
* output video frame.
*/
typedef m64p_error (*ptr_VidExt_GL_SwapBuffers)(void);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL VidExt_GL_SwapBuffers(void);
#endif
#ifdef __cplusplus
}
#endif
#endif /* #define M64P_VIDEXT_H */

View file

@ -1,89 +0,0 @@
#include "usf.h"
#include "memory.h"
#include "audio.h"
#include <stdlib.h>
#include <stdio.h>
#include "usf_internal.h"
void AddBuffer(usf_state_t *state, unsigned char *buf, unsigned int length) {
unsigned int i, do_max;
int16_t * sample_buffer = state->sample_buffer;
if(!state->cpu_running)
return;
do_max = length >> 2;
if ( do_max > state->sample_buffer_count )
do_max = (unsigned int) state->sample_buffer_count;
if ( sample_buffer )
for (i = 0; i < do_max; ++i)
{
*sample_buffer++ = ((int16_t*)buf)[1];
*sample_buffer++ = ((int16_t*)buf)[0];
buf += 4;
}
else
buf += 4 * do_max;
state->sample_buffer_count -= do_max;
state->sample_buffer = sample_buffer;
length -= do_max << 2;
if ( length )
{
sample_buffer = state->samplebuf;
do_max = length >> 2;
for (i = 0; i < do_max; ++i)
{
*sample_buffer++ = ((int16_t*)buf)[1];
*sample_buffer++ = ((int16_t*)buf)[0];
buf += 4;
}
state->samples_in_buffer = do_max;
state->cpu_running = 0;
}
}
void AiLenChanged(usf_state_t * state) {
int32_t length = 0;
uint32_t address = (AI_DRAM_ADDR_REG & 0x00FFFFF8);
length = AI_LEN_REG & 0x3FFF8;
#ifdef DEBUG_INFO
fprintf(state->debug_log, "Audio DMA push: %d %d\n", AI_DRAM_ADDR_REG, length);
#endif
AddBuffer(state, state->RDRAM+address, length);
if(length && !(AI_STATUS_REG&0x80000000)) {
const float VSyncTiming = 789000.0f;
double BytesPerSecond = 48681812.0 / (AI_DACRATE_REG + 1) * 4;
double CountsPerSecond = (double)((((double)VSyncTiming) * (double)60.0)) * 2.0;
double CountsPerByte = (double)CountsPerSecond / (double)BytesPerSecond;
unsigned int IntScheduled = (unsigned int)((double)AI_LEN_REG * CountsPerByte);
ChangeTimer(state,AiTimer,IntScheduled);
}
if(state->enableFIFOfull) {
if(AI_STATUS_REG&0x40000000)
AI_STATUS_REG|=0x80000000;
}
AI_STATUS_REG|=0x40000000;
}
unsigned int AiReadLength(usf_state_t * state) {
AI_LEN_REG = 0;
return AI_LEN_REG;
}
void AiDacrateChanged(usf_state_t * state, unsigned int value) {
AI_DACRATE_REG = value;
state->SampleRate = 48681812 / (AI_DACRATE_REG + 1);
}

View file

@ -1,12 +0,0 @@
#ifndef _AUDIO_H_
#define _AUDIO_H_
#include "usf.h"
#include "cpu.h"
#include "memory.h"
uint32_t AiReadLength(usf_state_t *);
void AiLenChanged(usf_state_t *);
void AiDacrateChanged(usf_state_t *, uint32_t value);
#endif

View file

@ -1,271 +0,0 @@
#include "usf.h"
#include "usf_internal.h"
#include "cpu_hle.h"
#include "audiolib.h"
#include "os.h"
#include "main.h"
#include "memory.h"
#define N64WORD(x) (*(uint32_t*)PageVRAM((x)))
#define N64HALF(x) (*(uint16_t*)PageVRAM((x)))
#define N64BYTE(x) (*(uint8_t*)PageVRAM((x)))
int alCopy(usf_state_t * state, int paddr) {
uint32_t source = (state->GPR[4].UW[0]);
uint32_t dest = (state->GPR[5].UW[0]);
uint32_t len = (state->GPR[6].UW[0]);
if(len&3)
DisplayError(state, "OMG!!!! - alCopy length & 3\n");
memcpyn642n64(state, dest, source, len);
return 1;
}
int alLink(usf_state_t * state, int paddr) {
ALLink *element = (ALLink*)PageVRAM(state->GPR[4].UW[0]);
ALLink *after = (ALLink*)PageVRAM(state->GPR[5].UW[0]);
ALLink *afterNext;
element->next = after->next;
element->prev = state->GPR[5].UW[0];
if (after->next) {
afterNext = (ALLink*)PageVRAM(after->next);
afterNext->prev = state->GPR[4].UW[0];
}
after->next = state->GPR[4].UW[0];
return 1;
}
int alUnLink(usf_state_t * state, int paddr) {
ALLink *element = (ALLink*)PageVRAM(state->GPR[4].UW[0]);
ALLink *elementNext = (ALLink*)PageVRAM(element->next);
ALLink *elementPrev = (ALLink*)PageVRAM(element->prev);
// _asm int 3
if (element->next)
elementNext->prev = element->prev;
if (element->prev)
elementPrev->next = element->next;
return 1;
}
int alEvtqPostEvent(usf_state_t * state, int paddr) {
ALEventQueue *evtq;
ALEvent *events;
uint32_t A0 = state->GPR[4].UW[0];
uint32_t A1 = state->GPR[5].UW[0];
uint32_t DeltaTime = state->GPR[6].UW[0];
uint32_t nodeNext = 0;
uint32_t nextItem = 0;
uint32_t node = 0;
uint32_t nextDelta = 0;
uint32_t item = 0;
uint32_t postWhere = 0;
uint32_t NEXT = 0;
uint32_t nextItemDelta = 0;
evtq = (ALEventQueue *)PageVRAM(A0);
events = (ALEvent *)PageVRAM(A1);
//_asm int 3
NEXT = evtq->freeList.next;
if(NEXT == 0)
return 1;
//DisplayError("%08x", N64WORD(0x800533E4));
//cprintf("%08x\t%08x\n", N64WORD(0x800533D4), N64WORD(0x800533D8));
item = NEXT;
state->GPR[4].UW[0] = NEXT;
alUnLink(state, 0);
state->GPR[4].UW[0] = A1; state->GPR[5].UW[0] = NEXT + 0xC; state->GPR[6].UW[0] = 0x10;
alCopy(state, 0);
postWhere = (DeltaTime==0x7FFFFFFF)?1:0;
nodeNext = A0;
node = nodeNext + 8;
while(nodeNext !=0 ) {
nodeNext = *(uint32_t*)PageVRAM(node);
if(nodeNext != 0) {
nextDelta = *(uint32_t*)PageVRAM(nodeNext + 8);
nextItem = nodeNext;
if(DeltaTime < nextDelta) {
*(uint32_t*)PageVRAM(item + 8) = DeltaTime;
nextItemDelta = *(uint32_t*)PageVRAM(nextItem + 8);
*(uint32_t*)PageVRAM(nextItem + 8) = nextItemDelta - DeltaTime;
state->GPR[4].UW[0] = item; state->GPR[5].UW[0] = node;
alLink(state, 0);
return 1;
} else {
node = nodeNext;
DeltaTime -= nextDelta;
if(node == 0)
return 1;
}
}
}
if(postWhere == 0)
*(uint32_t*)PageVRAM(item + 8) = DeltaTime;
else
*(uint32_t*)PageVRAM(item + 8) = 0;
state->GPR[4].UW[0] = item; state->GPR[5].UW[0] = node;
alLink(state, 0);
return 1;
}
int alEvtqPostEvent_Alt(usf_state_t * state, int paddr) {
return 0;
}
#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
uint32_t __nextSampleTime(usf_state_t * state, uint32_t driver, uint32_t *client) {
uint32_t c = 0;
int32_t deltaTime = 0x7FFFFFFF;
*client = 0;
for(c = N64WORD(driver); c != 0; c = N64WORD(c)) {
int samplesLeft = N64WORD(c + 0x10);
int curSamples = N64WORD(driver + 0x20);
if((samplesLeft - curSamples) < deltaTime) {
*client = c;
deltaTime = samplesLeft - curSamples;
}
}
return N64WORD((*client)+0x10);
}
int32_t _timeToSamplesNoRound(usf_state_t * state, long synth, long micros)
{
uint32_t outputRate = N64WORD(synth+0x44);
float tmp = ((float)micros) * outputRate / 1000000.0 + 0.5;
//DisplayError("Smaple rate is %d", outputRate);
return (int32_t)tmp;
}
uint32_t byteswap(char b[4] ) {
uint32_t out = 0;
out += b[3];
out += b[2] << 8;
out += b[1] << 16;
out += b[0] << 24;
return out;
}
int alAudioFrame(usf_state_t * state, int paddr) {
uint32_t alGlobals = 0;
uint32_t driver = 0, *paramSamples, *curSamples, client = 0, dl = 0;
uint32_t A0 = state->GPR[4].UW[0];
uint32_t A1 = state->GPR[5].UW[0];
uint32_t A2 = state->GPR[6].UW[0];
uint32_t outLen = state->GPR[7].UW[0];
uint32_t cmdlEnd = A0;
uint32_t lOutBuf = A2;
alGlobals = ((*(uint16_t*)PageRAM2(paddr + 0x8)) & 0xFFFF) << 16; //alGlobals->drvr
alGlobals += *(int16_t*)PageRAM2(paddr + 0xc);
//alGlobals = 0x80750C74;
driver = N64WORD(alGlobals);
paramSamples = (uint32_t*) PageVRAM(driver + 0x1c);
curSamples = (uint32_t*) PageVRAM(driver + 0x20);
if(N64WORD(driver) == 0) { // if(drvr->head == 0)
N64WORD(A1) = 0;
state->GPR[2].UW[0] = A0;
return 1;
}
for(*paramSamples = __nextSampleTime(state, driver, &client); (*paramSamples - *curSamples) < outLen; *paramSamples = __nextSampleTime(state, driver, &client)) {
int32_t *cSamplesLeft;
cSamplesLeft = (int32_t *) PageVRAM(client + 0x10);
*paramSamples &= ~0xf;
//run handler (not-HLE'd)
state->GPR[4].UW[0] = client;
RunFunction(state, N64WORD(client+0x8));
*cSamplesLeft += _timeToSamplesNoRound(state, driver, state->GPR[2].UW[0]);
}
*paramSamples &= ~0xf;
//give us some stack
state->GPR[0x1d].UW[0] -= 0x20;
N64WORD(state->GPR[0x1d].UW[0]+0x4) = 0; //tmp
while (outLen > 0) {
uint32_t maxOutSamples = 0, nOut = 0, cmdPtr = 0, output = 0, setParam = 0, handler = 0;
maxOutSamples = N64WORD(driver + 0x48);
nOut = MIN(maxOutSamples, outLen);
cmdPtr = cmdlEnd;//+8;
output = N64WORD(driver + 0x38);
setParam = N64WORD(output+8); // alSaveParam
state->GPR[4].DW = output;
state->GPR[5].DW = 0x6; // AL_FILTER_SET_DRAM
state->GPR[6].DW = lOutBuf;
RunFunction(state, setParam);
handler = N64WORD(output+4); // alSavePull
state->GPR[4].DW = output;
state->GPR[5].DW = state->GPR[0x1d].UW[0]+0x12; //&tmp
state->GPR[6].DW = nOut;
state->GPR[7].DW = *curSamples;
N64WORD(state->GPR[0x1d].UW[0]+0x10) = cmdPtr;
RunFunction(state, handler);
curSamples = (uint32_t *) PageVRAM(driver + 0x20);
cmdlEnd = state->GPR[2].UW[0];
outLen -= nOut;
lOutBuf += (nOut<<2);
*curSamples += nOut;
}
state->GPR[0x1d].UW[0] += 0x20;
N64WORD(A1) = (int32_t) ((cmdlEnd - A0) >> 3);
state->GPR[4].UW[0] = driver;
while( (dl = N64WORD(driver+0x14)) ) {
state->GPR[4].UW[0] = dl;
alUnLink(state, 0);
state->GPR[4].UW[0] = dl;
state->GPR[5].UW[0] = driver + 4;
alLink(state, 0);
}
state->GPR[2].UW[0] = cmdlEnd;
return 1;
}

View file

@ -1,60 +0,0 @@
#ifndef _CPU_HLE_AUDIOLIB_
#define _CPU_HLE_AUDIOLIB_
#include "cpu_hle.h"
#include "os.h"
// a few of these structures/type were sequestered from SGI\Nindendo's code
typedef struct ALLink_s {
uint32_t next;
uint32_t prev;
} ALLink;
typedef struct {
ALLink freeList;
ALLink allocList;
int32_t eventCount;
} ALEventQueue;
typedef struct {
uint16_t type;
uint8_t msg[12];
} ALEvent;
typedef struct {
ALLink node;
int32_t delta; //microtime
ALEvent event;
} ALEventListItem;
int alCopy(usf_state_t *, int paddr);
int alLink(usf_state_t *, int paddr);
int alUnLink(usf_state_t *, int paddr);
int alEvtqPostEvent(usf_state_t *, int paddr) ;
int alEvtqPostEvent_Alt(usf_state_t *, int paddr);
int alAudioFrame(usf_state_t *, int paddr);
// need to remove these
typedef struct {
uint8_t *base;
uint8_t *cur;
int32_t len;
int32_t count;
} ALHeap;
typedef struct ALPlayer_s {
struct ALPlayer_s *next;
void *clientData;
void *handler;
int32_t callTime;
int32_t samplesLeft;
} ALPlayer;
#endif

View file

@ -1,63 +0,0 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.in by autoheader. */
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#define LT_OBJDIR ".libs/"
/* Name of package */
#define PACKAGE "lazyusf"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""
/* Define to the full name of this package. */
#define PACKAGE_NAME "lazyusf"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "lazyusf 1.0.0"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "lazyusf"
/* Define to the version of this package. */
#define PACKAGE_VERSION "1.0.0"
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Version number of package */
#define VERSION "1.0.0"
/* Define to 1 if the X Window System is missing or not being used. */
/* #undef X_DISPLAY_MISSING */

View file

@ -1,604 +0,0 @@
/*
* Project 64 - A Nintendo 64 emulator.
*
* (c) Copyright 2001 zilmar (zilmar@emulation64.com) and
* Jabo (jabo@emulation64.com).
*
* pj64 homepage: www.pj64.net
*
* Permission to use, copy, modify and distribute Project64 in both binary and
* source form, for non-commercial purposes, is hereby granted without fee,
* providing that this license information and copyright notice appear with
* all copies and any derived work.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event shall the authors be held liable for any damages
* arising from the use of this software.
*
* Project64 is freeware for PERSONAL USE only. Commercial users should
* seek permission of the copyright holders first. Commercial use includes
* charging money for Project64 or software derived from Project64.
*
* The copyright holders request that bug fixes and improvements to the code
* should be forwarded to them so if they want them.
*
*/
#include <stdint.h>
#include <string.h>
#include "main.h"
#include "cpu.h"
#include "usf.h"
#include "audio.h"
#include "registers.h"
#include "rsp.h"
#include "cpu_hle.h"
#include "usf_internal.h"
#include <stdlib.h>
void ChangeCompareTimer(usf_state_t * state) {
uint32_t NextCompare = COMPARE_REGISTER - COUNT_REGISTER;
if ((NextCompare & 0x80000000) != 0) { NextCompare = 0x7FFFFFFF; }
if (NextCompare == 0) { NextCompare = 0x1; }
ChangeTimer(state,CompareTimer,NextCompare);
}
void ChangeTimer(usf_state_t * state, int32_t Type, int32_t Value) {
if (Value == 0) {
state->Timers->NextTimer[Type] = 0;
state->Timers->Active[Type] = 0;
return;
}
state->Timers->NextTimer[Type] = Value - state->Timers->Timer;
state->Timers->Active[Type] = 1;
CheckTimer(state);
}
void CheckTimer (usf_state_t * state) {
int32_t count;
for (count = 0; count < MaxTimers; count++) {
if (!state->Timers->Active[count]) { continue; }
if (!(count == CompareTimer && state->Timers->NextTimer[count] == 0x7FFFFFFF)) {
state->Timers->NextTimer[count] += state->Timers->Timer;
}
}
state->Timers->CurrentTimerType = -1;
state->Timers->Timer = 0x7FFFFFFF;
for (count = 0; count < MaxTimers; count++) {
if (!state->Timers->Active[count]) { continue; }
if (state->Timers->NextTimer[count] >= state->Timers->Timer) { continue; }
state->Timers->Timer = state->Timers->NextTimer[count];
state->Timers->CurrentTimerType = count;
}
if (state->Timers->CurrentTimerType == -1) {
DisplayError(state, "No active timers ???\nEmulation Stopped");
StopEmulation(state);
}
for (count = 0; count < MaxTimers; count++) {
if (!state->Timers->Active[count]) { continue; }
if (!(count == CompareTimer && state->Timers->NextTimer[count] == 0x7FFFFFFF)) {
state->Timers->NextTimer[count] -= state->Timers->Timer;
}
}
if (state->Timers->NextTimer[CompareTimer] == 0x7FFFFFFF) {
uint32_t NextCompare = COMPARE_REGISTER - COUNT_REGISTER;
if ((NextCompare & 0x80000000) == 0 && NextCompare != 0x7FFFFFFF) {
ChangeCompareTimer(state);
}
}
}
void CloseCpu (usf_state_t * state) {
uint32_t count = 0;
if(!state->MemChunk) return;
if (!state->cpu_running) { return; }
state->cpu_running = 0;
for (count = 0; count < 3; count ++ ) {
state->CPU_Action->CloseCPU = 1;
state->CPU_Action->DoSomething = 1;
}
state->CPURunning = 0;
}
int32_t DelaySlotEffectsCompare (usf_state_t * state, uint32_t PC, uint32_t Reg1, uint32_t Reg2) {
OPCODE Command;
if (!r4300i_LW_VAddr(state, PC + 4, (uint32_t*)&Command.u.Hex)) {
return 1;
}
switch (Command.u.b.op) {
case R4300i_SPECIAL:
switch (Command.u.e.funct) {
case R4300i_SPECIAL_SLL:
case R4300i_SPECIAL_SRL:
case R4300i_SPECIAL_SRA:
case R4300i_SPECIAL_SLLV:
case R4300i_SPECIAL_SRLV:
case R4300i_SPECIAL_SRAV:
case R4300i_SPECIAL_MFHI:
case R4300i_SPECIAL_MTHI:
case R4300i_SPECIAL_MFLO:
case R4300i_SPECIAL_MTLO:
case R4300i_SPECIAL_DSLLV:
case R4300i_SPECIAL_DSRLV:
case R4300i_SPECIAL_DSRAV:
case R4300i_SPECIAL_ADD:
case R4300i_SPECIAL_ADDU:
case R4300i_SPECIAL_SUB:
case R4300i_SPECIAL_SUBU:
case R4300i_SPECIAL_AND:
case R4300i_SPECIAL_OR:
case R4300i_SPECIAL_XOR:
case R4300i_SPECIAL_NOR:
case R4300i_SPECIAL_SLT:
case R4300i_SPECIAL_SLTU:
case R4300i_SPECIAL_DADD:
case R4300i_SPECIAL_DADDU:
case R4300i_SPECIAL_DSUB:
case R4300i_SPECIAL_DSUBU:
case R4300i_SPECIAL_DSLL:
case R4300i_SPECIAL_DSRL:
case R4300i_SPECIAL_DSRA:
case R4300i_SPECIAL_DSLL32:
case R4300i_SPECIAL_DSRL32:
case R4300i_SPECIAL_DSRA32:
if (Command.u.e.rd == 0) { return 0; }
if (Command.u.e.rd == Reg1) { return 1; }
if (Command.u.e.rd == Reg2) { return 1; }
break;
case R4300i_SPECIAL_MULT:
case R4300i_SPECIAL_MULTU:
case R4300i_SPECIAL_DIV:
case R4300i_SPECIAL_DIVU:
case R4300i_SPECIAL_DMULT:
case R4300i_SPECIAL_DMULTU:
case R4300i_SPECIAL_DDIV:
case R4300i_SPECIAL_DDIVU:
break;
default:
return 1;
}
break;
case R4300i_CP0:
switch (Command.u.b.rs) {
case R4300i_COP0_MT: break;
case R4300i_COP0_MF:
if (Command.u.b.rt == 0) { return 0; }
if (Command.u.b.rt == Reg1) { return 1; }
if (Command.u.b.rt == Reg2) { return 1; }
break;
default:
if ( (Command.u.b.rs & 0x10 ) != 0 ) {
switch( state->Opcode.u.e.funct ) {
case R4300i_COP0_CO_TLBR: break;
case R4300i_COP0_CO_TLBWI: break;
case R4300i_COP0_CO_TLBWR: break;
case R4300i_COP0_CO_TLBP: break;
default:
return 1;
}
return 1;
}
}
break;
case R4300i_CP1:
switch (Command.u.f.fmt) {
case R4300i_COP1_MF:
if (Command.u.b.rt == 0) { return 0; }
if (Command.u.b.rt == Reg1) { return 1; }
if (Command.u.b.rt == Reg2) { return 1; }
break;
case R4300i_COP1_CF: break;
case R4300i_COP1_MT: break;
case R4300i_COP1_CT: break;
case R4300i_COP1_S: break;
case R4300i_COP1_D: break;
case R4300i_COP1_W: break;
case R4300i_COP1_L: break;
return 1;
}
break;
case R4300i_ANDI:
case R4300i_ORI:
case R4300i_XORI:
case R4300i_LUI:
case R4300i_ADDI:
case R4300i_ADDIU:
case R4300i_SLTI:
case R4300i_SLTIU:
case R4300i_DADDI:
case R4300i_DADDIU:
case R4300i_LB:
case R4300i_LH:
case R4300i_LW:
case R4300i_LWL:
case R4300i_LWR:
case R4300i_LDL:
case R4300i_LDR:
case R4300i_LBU:
case R4300i_LHU:
case R4300i_LD:
case R4300i_LWC1:
case R4300i_LDC1:
if (Command.u.b.rt == 0) { return 0; }
if (Command.u.b.rt == Reg1) { return 1; }
if (Command.u.b.rt == Reg2) { return 1; }
break;
case R4300i_CACHE: break;
case R4300i_SB: break;
case R4300i_SH: break;
case R4300i_SW: break;
case R4300i_SWR: break;
case R4300i_SWL: break;
case R4300i_SWC1: break;
case R4300i_SDC1: break;
case R4300i_SD: break;
default:
return 1;
}
return 0;
}
int32_t DelaySlotEffectsJump (usf_state_t * state, uint32_t JumpPC) {
OPCODE Command;
if (!r4300i_LW_VAddr(state, JumpPC, &Command.u.Hex)) { return 1; }
switch (Command.u.b.op) {
case R4300i_SPECIAL:
switch (Command.u.e.funct) {
case R4300i_SPECIAL_JR: return DelaySlotEffectsCompare(state,JumpPC,Command.u.b.rs,0);
case R4300i_SPECIAL_JALR: return DelaySlotEffectsCompare(state,JumpPC,Command.u.b.rs,31);
}
break;
case R4300i_REGIMM:
switch (Command.u.b.rt) {
case R4300i_REGIMM_BLTZ:
case R4300i_REGIMM_BGEZ:
case R4300i_REGIMM_BLTZL:
case R4300i_REGIMM_BGEZL:
case R4300i_REGIMM_BLTZAL:
case R4300i_REGIMM_BGEZAL:
return DelaySlotEffectsCompare(state,JumpPC,Command.u.b.rs,0);
}
break;
case R4300i_JAL:
case R4300i_SPECIAL_JALR: return DelaySlotEffectsCompare(state,JumpPC,31,0); break;
case R4300i_J: return 0;
case R4300i_BEQ:
case R4300i_BNE:
case R4300i_BLEZ:
case R4300i_BGTZ:
return DelaySlotEffectsCompare(state,JumpPC,Command.u.b.rs,Command.u.b.rt);
case R4300i_CP1:
switch (Command.u.f.fmt) {
case R4300i_COP1_BC:
switch (Command.u.f.ft) {
case R4300i_COP1_BC_BCF:
case R4300i_COP1_BC_BCT:
case R4300i_COP1_BC_BCFL:
case R4300i_COP1_BC_BCTL:
{
int32_t EffectDelaySlot;
OPCODE NewCommand;
if (!r4300i_LW_VAddr(state, JumpPC + 4, &NewCommand.u.Hex)) { return 1; }
EffectDelaySlot = 0;
if (NewCommand.u.b.op == R4300i_CP1) {
if (NewCommand.u.f.fmt == R4300i_COP1_S && (NewCommand.u.e.funct & 0x30) == 0x30 ) {
EffectDelaySlot = 1;
}
if (NewCommand.u.f.fmt == R4300i_COP1_D && (NewCommand.u.e.funct & 0x30) == 0x30 ) {
EffectDelaySlot = 1;
}
}
return EffectDelaySlot;
}
break;
}
break;
}
break;
case R4300i_BEQL:
case R4300i_BNEL:
case R4300i_BLEZL:
case R4300i_BGTZL:
return DelaySlotEffectsCompare(state,JumpPC,Command.u.b.rs,Command.u.b.rt);
}
return 1;
}
void DoSomething ( usf_state_t * state ) {
if (state->CPU_Action->CloseCPU) {
//StopEmulation();
state->cpu_running = 0;
//printf("Stopping?\n");
}
if (state->CPU_Action->CheckInterrupts) {
state->CPU_Action->CheckInterrupts = 0;
CheckInterrupts(state);
}
if (state->CPU_Action->DoInterrupt) {
state->CPU_Action->DoInterrupt = 0;
DoIntrException(state, 0);
}
state->CPU_Action->DoSomething = 0;
if (state->CPU_Action->DoInterrupt) { state->CPU_Action->DoSomething = 1; }
}
void InPermLoop ( usf_state_t * state ) {
// *** Changed ***/
if (state->CPU_Action->DoInterrupt) { return; }
/* Interrupts enabled */
if (( STATUS_REGISTER & STATUS_IE ) == 0 ) { goto InterruptsDisabled; }
if (( STATUS_REGISTER & STATUS_EXL ) != 0 ) { goto InterruptsDisabled; }
if (( STATUS_REGISTER & STATUS_ERL ) != 0 ) { goto InterruptsDisabled; }
if (( STATUS_REGISTER & 0xFF00) == 0) { goto InterruptsDisabled; }
/* check sound playing */
/* check RSP running */
/* check RDP running */
if (state->Timers->Timer >= 0) {
COUNT_REGISTER += state->Timers->Timer + 1;
state->Timers->Timer = -1;
}
return;
InterruptsDisabled:
DisplayError(state, "Stuck in Permanent Loop");
StopEmulation(state);
}
void ReadFromMem(const void * source, void * target, uint32_t length, uint32_t *offset) {
memcpy((uint8_t*)target,((uint8_t*)source)+*offset,length);
*offset+=length;
}
uint32_t Machine_LoadStateFromRAM(usf_state_t * state, void * savestatespace) {
uint8_t LoadHeader[0x40];
uint32_t Value, count, SaveRDRAMSize, offset=0;
ReadFromMem( savestatespace,&Value,sizeof(Value),&offset);
if (Value != 0x23D8A6C8) { return 0; }
ReadFromMem( savestatespace,&SaveRDRAMSize,sizeof(SaveRDRAMSize),&offset);
ReadFromMem( savestatespace,&LoadHeader,0x40,&offset);
state->Timers->CurrentTimerType = -1;
state->Timers->Timer = 0;
for (count = 0; count < MaxTimers; count ++) { state->Timers->Active[count] = 0; }
//fix rdram size
if (SaveRDRAMSize != state->RdramSize) {
// dothis :)
}
state->RdramSize = SaveRDRAMSize;
ReadFromMem( savestatespace,&Value,sizeof(Value),&offset);
ChangeTimer(state,ViTimer,Value);
ReadFromMem( savestatespace,&state->PROGRAM_COUNTER,sizeof(state->PROGRAM_COUNTER),&offset);
ReadFromMem( savestatespace,state->GPR,sizeof(int64_t)*32,&offset);
ReadFromMem( savestatespace,state->FPR,sizeof(int64_t)*32,&offset);
ReadFromMem( savestatespace,state->CP0,sizeof(uint32_t)*32,&offset);
ReadFromMem( savestatespace,state->FPCR,sizeof(uint32_t)*32,&offset);
ReadFromMem( savestatespace,&state->HI,sizeof(int64_t),&offset);
ReadFromMem( savestatespace,&state->LO,sizeof(int64_t),&offset);
ReadFromMem( savestatespace,state->RegRDRAM,sizeof(uint32_t)*10,&offset);
ReadFromMem( savestatespace,state->RegSP,sizeof(uint32_t)*10,&offset);
ReadFromMem( savestatespace,state->RegDPC,sizeof(uint32_t)*10,&offset);
ReadFromMem( savestatespace,state->RegMI,sizeof(uint32_t)*4,&offset);
ReadFromMem( savestatespace,state->RegVI,sizeof(uint32_t)*14,&offset);
ReadFromMem( savestatespace,state->RegAI,sizeof(uint32_t)*6,&offset);
ReadFromMem( savestatespace,state->RegPI,sizeof(uint32_t)*13,&offset);
ReadFromMem( savestatespace,state->RegRI,sizeof(uint32_t)*8,&offset);
ReadFromMem( savestatespace,state->RegSI,sizeof(uint32_t)*4,&offset);
ReadFromMem( savestatespace,state->tlb,sizeof(TLB)*32,&offset);
ReadFromMem( savestatespace,(uint8_t*)state->PIF_Ram,0x40,&offset);
ReadFromMem( savestatespace,state->RDRAM,SaveRDRAMSize,&offset);
ReadFromMem( savestatespace,state->DMEM,0x1000,&offset);
ReadFromMem( savestatespace,state->IMEM,0x1000,&offset);
state->CP0[32] = 0;
SetupTLB(state);
ChangeCompareTimer(state);
AI_STATUS_REG = 0;
AiDacrateChanged(state, AI_DACRATE_REG);
// StartAiInterrupt(state);
SetFpuLocations(state); // important if FR=1
return 1;
}
void StartEmulationFromSave ( usf_state_t * state, void * savestate ) {
uint32_t count = 0;
//printf("Starting generic Cpu\n");
//CloseCpu();
memset(state->N64MEM, 0, state->RdramSize);
memset(state->DMEM, 0, 0x1000);
memset(state->IMEM, 0, 0x1000);
memset(state->TLB_Map, 0, 0x100000 * sizeof(uintptr_t) + 0x10000);
memset(state->CPU_Action,0,sizeof(*state->CPU_Action));
state->WrittenToRom = 0;
InitilizeTLB(state);
SetupRegisters(state, state->Registers);
BuildInterpreter(state);
state->Timers->CurrentTimerType = -1;
state->Timers->Timer = 0;
for (count = 0; count < MaxTimers; count ++) { state->Timers->Active[count] = 0; }
ChangeTimer(state,ViTimer,5000);
ChangeCompareTimer(state);
state->ViFieldNumber = 0;
state->CPURunning = 1;
*state->WaitMode = 0;
init_rsp(state);
Machine_LoadStateFromRAM(state, savestate);
state->SampleRate = 48681812 / (AI_DACRATE_REG + 1);
if(state->enableFIFOfull) {
const float VSyncTiming = 789000.0f;
double BytesPerSecond = 48681812.0 / (AI_DACRATE_REG + 1) * 4;
double CountsPerSecond = (double)(((double)VSyncTiming) * (double)60.0);
double CountsPerByte = (double)CountsPerSecond / (double)BytesPerSecond;
uint32_t IntScheduled = (uint32_t)((double)AI_LEN_REG * CountsPerByte);
ChangeTimer(state,AiTimer,IntScheduled);
AI_STATUS_REG|=0x40000000;
}
state->OLD_VI_V_SYNC_REG = ~VI_V_SYNC_REG;
CPUHLE_Scan(state);
}
void RefreshScreen (usf_state_t * state){
if (state->OLD_VI_V_SYNC_REG != VI_V_SYNC_REG)
{
state->OLD_VI_V_SYNC_REG = VI_V_SYNC_REG;
if (VI_V_SYNC_REG == 0)
{
state->VI_INTR_TIME = 500000;
}
else
{
state->VI_INTR_TIME = (VI_V_SYNC_REG + 1) * 1500;
if ((VI_V_SYNC_REG & 1) != 0)
{
state->VI_INTR_TIME -= 38;
}
}
}
ChangeTimer(state,ViTimer,state->Timers->Timer + state->Timers->NextTimer[ViTimer] + state->VI_INTR_TIME);
if ((VI_STATUS_REG & 0x10) != 0)
{
if (state->ViFieldNumber == 0)
{
state->ViFieldNumber = 1;
}
else
{
state->ViFieldNumber = 0;
}
}
else
{
state->ViFieldNumber = 0;
}
}
void RunRsp (usf_state_t * state) {
#ifdef DEBUG_INFO
fprintf(state->debug_log, "RSP Task:");
#endif
if ( ( SP_STATUS_REG & SP_STATUS_HALT ) == 0) {
if ( ( SP_STATUS_REG & SP_STATUS_BROKE ) == 0 ) {
uint32_t Task = *( uint32_t *)(state->DMEM + 0xFC0);
switch (Task) {
case 1: {
MI_INTR_REG |= 0x20;
SP_STATUS_REG |= (0x0203 );
if ((SP_STATUS_REG & SP_STATUS_INTR_BREAK) != 0 )
MI_INTR_REG |= 1;
#ifdef DEBUG_INFO
fprintf(state->debug_log, " DList - interrupts %d\n", MI_INTR_REG);
#endif
CheckInterrupts(state);
DPC_STATUS_REG &= ~0x0002;
return;
}
break;
case 2: {
#ifdef DEBUG_INFO
fprintf(state->debug_log, " AList");
#endif
break;
}
break;
default:
break;
}
real_run_rsp(state, 100);
SP_STATUS_REG |= (0x0203 );
if ((SP_STATUS_REG & SP_STATUS_INTR_BREAK) != 0 ) {
#ifdef DEBUG_INFO
fprintf(state->debug_log, " - interrupt");
#endif
MI_INTR_REG |= 1;
CheckInterrupts(state);
}
}
}
#ifdef DEBUG_INFO
fprintf(state->debug_log, "\n");
#endif
}
void TimerDone (usf_state_t * state) {
switch (state->Timers->CurrentTimerType) {
case CompareTimer:
if(state->enablecompare)
FAKE_CAUSE_REGISTER |= CAUSE_IP7;
CheckInterrupts(state);
ChangeCompareTimer(state);
break;
case ViTimer:
RefreshScreen(state);
MI_INTR_REG |= MI_INTR_VI;
CheckInterrupts(state);
*state->WaitMode=0;
break;
case AiTimer:
ChangeTimer(state,AiTimer,0);
AI_STATUS_REG=0;
state->AudioIntrReg|=4;
//CheckInterrupts(state);
break;
}
CheckTimer(state);
}

View file

@ -1,95 +0,0 @@
/*
* Project 64 - A Nintendo 64 emulator.
*
* (c) Copyright 2001 zilmar (zilmar@emulation64.com) and
* Jabo (jabo@emulation64.com).
*
* pj64 homepage: www.pj64.net
*
* Permission to use, copy, modify and distribute Project64 in both binary and
* source form, for non-commercial purposes, is hereby granted without fee,
* providing that this license information and copyright notice appear with
* all copies and any derived work.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event shall the authors be held liable for any damages
* arising from the use of this software.
*
* Project64 is freeware for PERSONAL USE only. Commercial users should
* seek permission of the copyright holders first. Commercial use includes
* charging money for Project64 or software derived from Project64.
*
* The copyright holders request that bug fixes and improvements to the code
* should be forwarded to them so if they want them.
*
*/
#ifndef _CPU_H_
#define _CPU_H_
#include "interpreter_cpu.h"
#include "interpreter_ops.h"
#include "registers.h"
#include "tlb.h"
#include "memory.h"
#include "dma.h"
#include "exception.h"
#include "pif.h"
#include "opcode.h"
#include "usf.h"
typedef struct {
int32_t DoSomething;
int32_t CloseCPU;
int32_t CheckInterrupts;
int32_t DoInterrupt;
} CPU_ACTION;
#define MaxTimers 3
#define CompareTimer 0
#define ViTimer 1
#define AiTimer 2
typedef struct {
int32_t NextTimer[MaxTimers];
int32_t Active[MaxTimers];
int32_t CurrentTimerType;
int32_t Timer;
} SYSTEM_TIMERS;
void ChangeCompareTimer ( usf_state_t * );
void ChangeTimer ( usf_state_t *, int32_t Type, int32_t Value );
void CheckTimer ( usf_state_t * );
void CloseCpu ( usf_state_t * );
int32_t DelaySlotEffectsCompare ( usf_state_t *, uint32_t PC, uint32_t Reg1, uint32_t Reg2 );
int32_t DelaySlotEffectsJump ( usf_state_t *, uint32_t JumpPC);
void DoSomething ( usf_state_t * );
void InPermLoop ( usf_state_t * );
void InitiliazeCPUFlags ( usf_state_t * );
void RefreshScreen ( usf_state_t * );
void RunRsp ( usf_state_t * );
void StartEmulation ( usf_state_t * );
void TimerDone ( usf_state_t * );
void RecompileTimerDone ( usf_state_t * );
#define NORMAL 0
#define DO_DELAY_SLOT 1
#define DO_END_DELAY_SLOT 2
#define DELAY_SLOT 3
#define END_DELAY_SLOT 4
#define LIKELY_DELAY_SLOT 5
#define JUMP 6
#define DELAY_SLOT_DONE 7
#define LIKELY_DELAY_SLOT_DONE 8
#define END_BLOCK 9
enum SaveType {
Auto,
Eeprom_4K,
Eeprom_16K,
Sram,
FlashRam
};
void StartEmulationFromSave ( usf_state_t * state, void * savestate );
#endif

View file

@ -1,161 +0,0 @@
#include <string.h>
#include "usf.h"
#include "usf_internal.h"
#include "cpu_hle.h"
#include "os.h"
#include "audiolib.h"
// Nintendo 64 Standard (and non standard) library functions, for HLE
int numEntries = 0;
_HLE_Entry entrys[] = {
{"__osEnqueueThread",0,20,{0x8C,0x98,0,0,0x8C,0xAF,0,4,0,0x80,0xC8,0x25,0x8F,0xE,0,4,1,0xCF,8,0x2A},0,0,__osEnqueueThread},
{"__osRestoreInt",0,28,{0x40,8,0x60,0 ,1,4,0x40,0x25,0x40,0x88,0x60,0,0,0,0,0,0,0,0,0,3,0xE0,0,8,0,0,0,0},0,0,__osRestoreInt},
{"__osDisableInt",0,32,{0x40,8,0x60,0,0x24,1,0xFF,0xFE,1,1,0x48,0x24,0x40,0x89,0x60,0,0x31,2,0,1,0,0,0,0,3,0xE0,0,8,0,0,0,0},0,0,__osDisableInt},
// {"osStartThread",0,32,{0x27,0xBD,0xFF,0xD8,0xAF,0xBF,0,0x1C,0xAF,0xA4,0,0x28,0xAF,0xB1,0,0x18,0xC,-1,-1,-1,0xAF,0xB0,0,0x14,0x8F,0xAE,0,0x28,0x24,1,0,1,0,0x40,0x80,0x25},0,0,osStartThread},
//{"osPiStartDma",0,52,{0x27,0xBD,0xFF,0xD8,0x3C,0xE,-1,-1,0x8D,0xCE,-1,-1,0xAF,0xBF,0,0x1C,0xAF,0xA4,0,0x28,0xAF,0xA5,0,0x2C,0xAF,0xA6,0,0x30,0xAF,0xA7,0,0x34,0xAF,0xB1,0,0x18,0x15,0xC0,0,3,0xAF,0xB0,0,0x14,0x10,0,0,0x32,0x24,2,0xFF,0xFF},0,0,osPiStartDma}
//{"osRecvMesg",0,60,{0x27,0xBD,0xFF,0xD8,0xAF,0xBF,0,0x1C,0xAF,0xA4,0,0x28,0xAF,0xA5,0,0x2C,0xAF,0xA6,0,0x30,0xAF,0xB1,0,0x18,0xC,-1,-1,-1,0xAF,0xB0,0,0x14,0x8F,0xAE,0,0x28,0,0x40,0x80,0x25,0x8D,0xCF,0,8,0x15,0xE0,0,0x12,0,0,0,0,0x8f,0xb8,0,0x30,0x17,0,0,5},0,0,osRecvMesg},
{"saveThreadContext",0,32,{0x3C,5,-1,-1,0x8C,0xA5,-1,-1,0x40,8,0x60,0,0x8C,0xBB,0,0x18,0x35,8,0,2,0xAC,0xA8,1,0x18,0xFC,0xB0,0,0x98,0xFC,0xB1,0,0xA0},0,0,saveThreadContext},
{"loadThreadContext",0,40,{0x3C,4,-1,-1,0xC,-1,-1,-1,0x24,0x84,-1,-1,0x3C,1,-1,-1,0xAC,0x22,-1,-1,0x24,8,0,4,0xA4,0x48,0,0x10,0,0x40,0xD0,0x25,0x3C,8,-1,-1,0x8F,0x5B,1,0x18},0,0,loadThreadContext},
{"osSetIntMask",0,44,{0x40,0xC,0x60,0,0x31,0x82,0xFF,1,0x3C,8,-1,-1,0x25,8,-1,-1,0x8D,0xB,0,0,0x24,1,0xFF,0xFF,1,0x61,0x40,0x26,0x31,8,0xFF,0,0,0x48,0x10,0x25,0x3C,0xA,0xA4,0x30,0x8D,0x4A,0,0xC},0,0,osSetIntMask},
{"osVirtualToPhysical",0,36,{0x27,0xBD,0xFF,0xE8,0xAF,0xA4,0,0x18,0x8F,0xAE,0,0x18,0x3C,1,0x80,0,0xAF,0xBF,0,0x14,1,0xC1,8,0x2B,0x14,0x20,0,7,0x3C,1,0xA0,0,1,0xC1,8,0x2B},0,0,osVirtualToPhysical},
{"alCopy",0,32,{0,0x80,0x10,0x25,0,0xA0,0x18,0x25,0x18,0xC0,0,0x18,0,0,0x38,0x25,0x30,0xC5,0,3,0x10,0xA0,0,9,0,0xA0,0x20,0x25,0x90,0x4E,0,0},0,0,alCopy},
{"alLink",0,28,{0x8C,0xAE,0,0,0xAC,0x85,0,4,0xAC,0x8E,0,0,0x8C,0xA2,0,0,0x10,0x40,0,2,0,0,0,0,0xAC,0x44,0,4},0,0,alLink},
{"alUnlink",0,28,{0x8C,0x82,0,0,0x50,0x40,0,4,0x8C,0x82,0,4,0x8C,0x8E,0,4,0xAC,0x4E,0,4,0x8C,0x82,0,4,0x10,0x40,0,3},0,0,alUnLink},
{"osAiSetNextBuffer",0,32,{0x27,0xBD,0xFF,0xE0,0x3C,0xF,-1,-1,0x91,0xEF,-1,-1,0xAF,0xA4,0,0x20,0x8F,0xAE,0,0x20,0xAF,0xBF,0,0x14,0xAF,0xA5,0,0x24,0x11,0xE0,0,3},0,0,osAiSetNextBuffer},
{"alLink (DK64)",0,20,{0x8C,0xAE,0,0,0xAC,0x8E,0,0,0xAC,0x85,0,4,0x8C,0xAF,0,0,0x11,0xE0,0,3},0,0,alLink},
{"alUnLink (DK64)",0,28,{0x8C,0x8E,0,0,0x11,0xC0,0,4,0,0,0,0,0x8C,0x8F,0,4,0x8C,0x98,0,0,0xAF,0xF,0,4,0x8C,0x99,0,4},0,0,alUnLink},
{"alEvtqPostEvent",0,64,{0x27,0xBD,0xFF,0xD0,0xAF,0xBF,0,0x14,0xAF,0xA4,0,0x30,0xAF,0xA5,0,0x34,0xAF,0xA0,0,0x20,0x24,4,0,1,0xC,-1,-1,-1,0xAF,0xA6,0,0x38,0x8F,0xAE,0,0x30,0x8F,0xA7,0,0x38,0,0x40,0x28,0x25,0x8D,0xC8,0,0,0x15,0,0,5,1,0,0x20,0x25,0xC,-1,-1,-1,0,0x40,0x20,0x25},0,0,alEvtqPostEvent},
{"alEvtqPostEvent (DK64)",0,64,{0x27,0xBD,0xFF,0xD0,0xAF,0xBF,0,0x14,0xAF,0xA4,0,0x30,0xAF,0xA5,0,0x34,0xAF,0xA6,0,0x38,0xAF,0xA0,0,0x20,0xC,-1,-1,-1,0x24,4,0,1,0xAF,0xA2,0,0x1C,0x8F,0xAE,0,0x30,0x8D,0xCF,0,0,0xAF,0xAF,0,0x2C,0x8F,0xB8,0,0x2C,0x17,0,0,5,0,0,0,0,0xC,-1,-1,-1,0x8F,0xA4,0,0x1C},0,0,alEvtqPostEvent},
{"alEvtqPostEvent (CBFD)",0,56,{0x27,0xBD,0xFF,0xC0,0xAF,0xBF,0,0x14,0xAF,0xA4,0,0x40,0xAF,0xA5,0,0x44,0xAF,0xA6,0,0x48,0xAF,0xA7,0,0x4C,0xAF,0xA0,0,0x30,0x8F,0xAE,0,0x4C,0x31,0xCF,0,2,0x11,0xE0,0,4,0,0,0,0,0xC,-1,-1,-1,0x24,4,0,1,0xAF,0xA2,0,0x2C},0,0,alEvtqPostEvent},
{"alEvtqPostEvent (BT)",0,60,{0x27,0xBD,0xFF,0xD0,0xAF,0xBF,0,0x14,0xAF,0xA4,0,0x30,0xAF,0xA5,0,0x34,0xAF,0xA6,0,0x38,0xAF,0xA7,0,0x3C,0xAF,0xA0,0,0x20,0xC,-1,-1,-1,0x24,4,0,1,0xAF,0xA2,0,0x1C,0x8F,0xAE,0,0x30,0x8D,0xCF,0,0,0xAF,0xAF,0,0x2C,0x8F,0xB8,0,0x2C,0x17,0,0,5},0,0,alEvtqPostEvent},
{"alAudioFrame",0,52,{0x27,0xBD,0xFF,0x48,0xAF,0xB1,0,0x30,0x3C,0x11,-1,-1,0x8E,0x31,0-1,-1,0xAF,0xBF,0,0x4C,0xAF,0xB7,0,0x48,0xAF,0xB6,0,0x44,0xAF,0xB5,0,0x40,0xAF,0xB4,0,0x3C,0xAF,0xB3,0,0x38,0xAF,0xB2,0,0x34,0xAF,0xB0,0,0x2C,0xF7,0xB6,0,0x20},0,0,alAudioFrame},
//{"alAudioFrame (DK64)",0,64,{0x27,0xBD,0xFF,0xC0,0xAF,0xBF,0,0x1C,0xAF,0xA4,0,0x40,0xAF,0xA5,0,0x44,0xAF,0xA6,0,0x48,0xAF,0xA7,0,0x4C,0xAF,0xB1,0,0x18,0xAF,0xB0,0,0x14,0xA7,0xA0,0,0x3A,0x8F,0xAE,0,0x40,0xAF,0xAE,0,0x34,0x8F,0xAF,0,0x48,0xAF,0xAF,0,0x28,0x3C,0x18,0x80,0x75,0x8F,0x18,0xC,0x74,0x8F,0x19,0,0},0,0,alAudioFrame},
};
//int 0xA4,0xA6,0,0x38
//char foundlist[2048];
int sort_entrys(void * a, void * b)
{
_HLE_Entry * _a = (_HLE_Entry *)a;
_HLE_Entry * _b = (_HLE_Entry *)b;
return _b->used - _a->used;
}
int CPUHLE_Scan(usf_state_t * state)
{
int i = 0, j = 0;
unsigned char c = 0;
long d = 0;
int entrySize = 0;
int entry = 0;
void * address = 0;
int good = 1; //, needcomma = 0;
_HLE_Entry * entries;
unsigned entries_used = 0;
numEntries = sizeof(entrys) / sizeof(_HLE_Entry);
entries = state->cpu_hle_entries = realloc( state->cpu_hle_entries, sizeof(entrys) );
memcpy( entries, entrys, sizeof(entrys) );
//for(i=0; i < numEntries; i++)
// entries[i].used = 0;
//memset(foundlist,0,2048);
for(i=0; i < (state->RdramSize - 64); i+=4) {
for(entry = 0; entry < numEntries; entry++) {
if(entries[entry].used)
continue;
good = 1;
entrySize = entries[entry].length;
for(j=0; j < entrySize; j++) {
address = state->N64MEM + i + j;
//address = i;
c = *(unsigned char *)(address);
d = entries[entry].bytes[j^3];
if((c != d) && (d!=-1)) {
good = 0;
break;
}
}
if(good == 1 && i< (state->RdramSize-64)) {
//char buf[256];
//if(needcomma) {
// sprintf(buf,", %s", entries[entry].name);
//} else {
// sprintf(buf,"%s", entries[entry].name);
//}
//needcomma = 1;
//strcat(foundlist,buf);
entries[entry].used = 1;
entries[entry].phys = i;
++entries_used;
break;
}
}
}
qsort(entries, numEntries, sizeof(*entries), sort_entrys);
state->cpu_hle_entry_count = entries_used;
//printf("<--------------HLE Functions Found--------------->\n%s<------------------------------------------------>\n", foundlist);
//printf("HLE Functions found: %s\n", foundlist);
return 0;
}
int DoCPUHLE(usf_state_t * state, unsigned long loc)
{
int i = 0;
uintptr_t real_addr = PageVRAM2(loc);
_HLE_Entry * entries = state->cpu_hle_entries;
unsigned numEntries = state->cpu_hle_entry_count;
for(i = 0; i < numEntries; i++) {
if(entries[i].phys == real_addr) {
//printf("CPU HLEing using %d at %08x (phys: %08x) \"%s\"\n", entries[i].name, loc, entries[i].phys, entries[i].name);
if(entries[i].location(state, entries[i].phys)) {
// printf("done\n");
return 1;
}
else
return 0;
}
}
return 0;
}

View file

@ -1,27 +0,0 @@
#ifndef _CPU_HLE_
#define _CPU_HLE_
#include "usf.h"
#include "cpu.h"
#include "interpreter_ops.h"
#include "memory.h"
typedef struct {
char *name;
int num;
int length;
long bytes[80];
int used;
int phys;
int (*location)(usf_state_t *, int);
} _HLE_Entry;
int CPUHLE_Scan(usf_state_t *);
int DoCPUHLE(usf_state_t *, unsigned long loc);
////////////////////////////////////////////////////////////////////
// OS Thread Stuff
// found this stuff in daedalus
#endif

View file

@ -1,183 +0,0 @@
/*
* Project 64 - A Nintendo 64 emulator.
*
* (c) Copyright 2001 zilmar (zilmar@emulation64.com) and
* Jabo (jabo@emulation64.com).
*
* pj64 homepage: www.pj64.net
*
* Permission to use, copy, modify and distribute Project64 in both binary and
* source form, for non-commercial purposes, is hereby granted without fee,
* providing that this license information and copyright notice appear with
* all copies and any derived work.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event shall the authors be held liable for any damages
* arising from the use of this software.
*
* Project64 is freeware for PERSONAL USE only. Commercial users should
* seek permission of the copyright holders first. Commercial use includes
* charging money for Project64 or software derived from Project64.
*
* The copyright holders request that bug fixes and improvements to the code
* should be forwarded to them so if they want them.
*
*/
#include <string.h>
#include "main.h"
#include "cpu.h"
#include "usf.h"
#include "usf_internal.h"
void PI_DMA_READ (usf_state_t * state) {
PI_STATUS_REG &= ~PI_STATUS_DMA_BUSY;
MI_INTR_REG |= MI_INTR_PI;
CheckInterrupts(state);
return;
}
void PI_DMA_WRITE (usf_state_t * state) {
uint32_t i;
#ifdef DEBUG_INFO
fprintf(state->debug_log, "PI DMA WRITE: %08x to %08x for %08x bytes\n", PI_CART_ADDR_REG, PI_DRAM_ADDR_REG, PI_WR_LEN_REG + 1);
#endif
PI_STATUS_REG |= PI_STATUS_DMA_BUSY;
if ( PI_DRAM_ADDR_REG + PI_WR_LEN_REG + 1 > state->RdramSize) {
PI_STATUS_REG &= ~PI_STATUS_DMA_BUSY;
MI_INTR_REG |= MI_INTR_PI;
CheckInterrupts(state);
return;
}
if ( PI_CART_ADDR_REG >= 0x08000000 && PI_CART_ADDR_REG <= 0x08010000) {
return;
}
if ( PI_CART_ADDR_REG >= 0x10000000 && PI_CART_ADDR_REG <= 0x1FBFFFFF) {
PI_CART_ADDR_REG -= 0x10000000;
for (i = 0; i < PI_WR_LEN_REG + 1; i ++) {
*(state->N64MEM+((PI_DRAM_ADDR_REG + i) ^ 3)) = *PageROM(state, (PI_CART_ADDR_REG + i) ^ 3);
}
PI_CART_ADDR_REG += 0x10000000;
PI_STATUS_REG &= ~PI_STATUS_DMA_BUSY;
MI_INTR_REG |= MI_INTR_PI;
CheckInterrupts(state);
CheckTimer(state);
return;
}
PI_STATUS_REG &= ~PI_STATUS_DMA_BUSY;
MI_INTR_REG |= MI_INTR_PI;
CheckInterrupts(state);
}
void SI_DMA_READ (usf_state_t * state) {
if ((int32_t)SI_DRAM_ADDR_REG > (int32_t)state->RdramSize) {
return;
}
PifRamRead(state);
SI_DRAM_ADDR_REG &= 0xFFFFFFF8;
if ((int32_t)SI_DRAM_ADDR_REG < 0) {
int32_t count, RdramPos;
RdramPos = (int32_t)SI_DRAM_ADDR_REG;
for (count = 0; count < 0x40; count++, RdramPos++) {
if (RdramPos < 0) { continue; }
state->N64MEM[RdramPos ^3] = state->PIF_Ram[count];
}
} else {
int32_t count, RdramPos;
RdramPos = (uint32_t)SI_DRAM_ADDR_REG;
for (count = 0; count < 0x40; count++, RdramPos++) {
if (RdramPos < 0) { continue; }
state->N64MEM[RdramPos ^3] = state->PIF_Ram[count];
}
}
MI_INTR_REG |= MI_INTR_SI;
SI_STATUS_REG |= SI_STATUS_INTERRUPT;
CheckInterrupts(state);
}
void SI_DMA_WRITE (usf_state_t * state) {
if ((int32_t)SI_DRAM_ADDR_REG > (int32_t)state->RdramSize) {
return;
}
SI_DRAM_ADDR_REG &= 0xFFFFFFF8;
if ((int32_t)SI_DRAM_ADDR_REG < 0) {
int32_t count, RdramPos;
RdramPos = (int32_t)SI_DRAM_ADDR_REG;
for (count = 0; count < 0x40; count++, RdramPos++) {
if (RdramPos < 0) { state->PIF_Ram[count] = 0; continue; }
state->PIF_Ram[count] = state->N64MEM[RdramPos ^3];
}
} else {
int32_t count, RdramPos;
RdramPos = (int32_t)SI_DRAM_ADDR_REG;
for (count = 0; count < 0x40; count++, RdramPos++) {
if (RdramPos < 0) { state->PIF_Ram[count] = 0; continue; }
state->PIF_Ram[count] = state->N64MEM[RdramPos ^3];
}
}
PifRamWrite(state);
MI_INTR_REG |= MI_INTR_SI;
SI_STATUS_REG |= SI_STATUS_INTERRUPT;
CheckInterrupts(state);
}
void SP_DMA_READ (usf_state_t * state) {
SP_DRAM_ADDR_REG &= 0x1FFFFFFF;
if (SP_DRAM_ADDR_REG > state->RdramSize) {
SP_DMA_BUSY_REG = 0;
SP_STATUS_REG &= ~SP_STATUS_DMA_BUSY;
return;
}
if (SP_RD_LEN_REG + 1 + (SP_MEM_ADDR_REG & 0xFFF) > 0x1000) {
return;
}
memcpy( state->DMEM + (SP_MEM_ADDR_REG & 0x1FFF), state->N64MEM + SP_DRAM_ADDR_REG,
SP_RD_LEN_REG + 1 );
SP_DMA_BUSY_REG = 0;
SP_STATUS_REG &= ~SP_STATUS_DMA_BUSY;
MI_INTR_REG &= ~MI_INTR_SP;
CheckInterrupts(state);
CheckTimer(state);
}
void SP_DMA_WRITE (usf_state_t * state) {
if (SP_DRAM_ADDR_REG > state->RdramSize) {
return;
}
if (SP_WR_LEN_REG + 1 + (SP_MEM_ADDR_REG & 0xFFF) > 0x1000) {
return;
}
memcpy( state->N64MEM + SP_DRAM_ADDR_REG, state->DMEM + (SP_MEM_ADDR_REG & 0x1FFF),
SP_WR_LEN_REG + 1);
SP_DMA_BUSY_REG = 0;
SP_STATUS_REG &= ~SP_STATUS_DMA_BUSY;
}

View file

@ -1,34 +0,0 @@
/*
* Project 64 - A Nintendo 64 emulator.
*
* (c) Copyright 2001 zilmar (zilmar@emulation64.com) and
* Jabo (jabo@emulation64.com).
*
* pj64 homepage: www.pj64.net
*
* Permission to use, copy, modify and distribute Project64 in both binary and
* source form, for non-commercial purposes, is hereby granted without fee,
* providing that this license information and copyright notice appear with
* all copies and any derived work.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event shall the authors be held liable for any damages
* arising from the use of this software.
*
* Project64 is freeware for PERSONAL USE only. Commercial users should
* seek permission of the copyright holders first. Commercial use includes
* charging money for Project64 or software derived from Project64.
*
* The copyright holders request that bug fixes and improvements to the code
* should be forwarded to them so if they want them.
*
*/
void PI_DMA_READ ( usf_state_t * );
void PI_DMA_WRITE ( usf_state_t * );
void SI_DMA_READ ( usf_state_t * );
void SI_DMA_WRITE ( usf_state_t * );
void SP_DMA_READ ( usf_state_t * );
void SP_DMA_WRITE ( usf_state_t * );

View file

@ -1,158 +0,0 @@
/*
* Project 64 - A Nintendo 64 emulator.
*
* (c) Copyright 2001 zilmar (zilmar@emulation64.com) and
* Jabo (jabo@emulation64.com).
*
* pj64 homepage: www.pj64.net
*
* Permission to use, copy, modify and distribute Project64 in both binary and
* source form, for non-commercial purposes, is hereby granted without fee,
* providing that this license information and copyright notice appear with
* all copies and any derived work.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event shall the authors be held liable for any damages
* arising from the use of this software.
*
* Project64 is freeware for PERSONAL USE only. Commercial users should
* seek permission of the copyright holders first. Commercial use includes
* charging money for Project64 or software derived from Project64.
*
* The copyright holders request that bug fixes and improvements to the code
* should be forwarded to them so if they want them.
*
*/
#include "main.h"
#include "cpu.h"
#include "usf_internal.h"
void CheckInterrupts ( usf_state_t * state ) {
MI_INTR_REG &= ~MI_INTR_AI;
MI_INTR_REG |= (state->AudioIntrReg & MI_INTR_AI);
#ifdef DEBUG_INFO
if (MI_INTR_REG)
fprintf(state->debug_log, "Interrupt %d - ", MI_INTR_REG);
#endif
if ((MI_INTR_MASK_REG & MI_INTR_REG) != 0) {
#ifdef DEBUG_INFO
fprintf(state->debug_log, "triggered\n");
#endif
FAKE_CAUSE_REGISTER |= CAUSE_IP2;
} else {
#ifdef DEBUG_INFO
if (MI_INTR_REG)
fprintf(state->debug_log, "masked\n");
#endif
FAKE_CAUSE_REGISTER &= ~CAUSE_IP2;
}
if (( STATUS_REGISTER & STATUS_IE ) == 0 ) { return; }
if (( STATUS_REGISTER & STATUS_EXL ) != 0 ) { return; }
if (( STATUS_REGISTER & STATUS_ERL ) != 0 ) { return; }
if (( STATUS_REGISTER & FAKE_CAUSE_REGISTER & 0xFF00) != 0) {
if (!state->CPU_Action->DoInterrupt) {
state->CPU_Action->DoSomething = 1;
state->CPU_Action->DoInterrupt = 1;
}
}
}
void DoAddressError ( usf_state_t * state, uint32_t DelaySlot, uint32_t BadVaddr, uint32_t FromRead) {
if (FromRead) {
CAUSE_REGISTER = EXC_RADE;
} else {
CAUSE_REGISTER = EXC_WADE;
}
BAD_VADDR_REGISTER = BadVaddr;
if (DelaySlot) {
CAUSE_REGISTER |= CAUSE_BD;
EPC_REGISTER = state->PROGRAM_COUNTER - 4;
} else {
EPC_REGISTER = state->PROGRAM_COUNTER;
}
STATUS_REGISTER |= STATUS_EXL;
state->PROGRAM_COUNTER = 0x80000180;
}
void DoBreakException ( usf_state_t * state, uint32_t DelaySlot) {
CAUSE_REGISTER = EXC_BREAK;
if (DelaySlot) {
CAUSE_REGISTER |= CAUSE_BD;
EPC_REGISTER = state->PROGRAM_COUNTER - 4;
} else {
EPC_REGISTER = state->PROGRAM_COUNTER;
}
STATUS_REGISTER |= STATUS_EXL;
state->PROGRAM_COUNTER = 0x80000180;
}
void DoCopUnusableException ( usf_state_t * state, uint32_t DelaySlot, uint32_t Coprocessor ) {
CAUSE_REGISTER = EXC_CPU;
if (Coprocessor == 1) { CAUSE_REGISTER |= 0x10000000; }
if (DelaySlot) {
CAUSE_REGISTER |= CAUSE_BD;
EPC_REGISTER = state->PROGRAM_COUNTER - 4;
} else {
EPC_REGISTER = state->PROGRAM_COUNTER;
}
STATUS_REGISTER |= STATUS_EXL;
state->PROGRAM_COUNTER = 0x80000180;
}
void DoIntrException ( usf_state_t * state, uint32_t DelaySlot ) {
if (( STATUS_REGISTER & STATUS_IE ) == 0 ) { return; }
if (( STATUS_REGISTER & STATUS_EXL ) != 0 ) { return; }
if (( STATUS_REGISTER & STATUS_ERL ) != 0 ) { return; }
CAUSE_REGISTER = FAKE_CAUSE_REGISTER;
CAUSE_REGISTER |= EXC_INT;
EPC_REGISTER = state->PROGRAM_COUNTER;
if (DelaySlot) {
CAUSE_REGISTER |= CAUSE_BD;
EPC_REGISTER -= 4;
}
STATUS_REGISTER |= STATUS_EXL;
state->PROGRAM_COUNTER = 0x80000180;
}
void DoTLBMiss ( usf_state_t * state, uint32_t DelaySlot, uint32_t BadVaddr ) {
CAUSE_REGISTER = EXC_RMISS;
BAD_VADDR_REGISTER = BadVaddr;
CONTEXT_REGISTER &= 0xFF80000F;
CONTEXT_REGISTER |= (BadVaddr >> 9) & 0x007FFFF0;
ENTRYHI_REGISTER = (BadVaddr & 0xFFFFE000);
if ((STATUS_REGISTER & STATUS_EXL) == 0) {
if (DelaySlot) {
CAUSE_REGISTER |= CAUSE_BD;
EPC_REGISTER = state->PROGRAM_COUNTER - 4;
} else {
EPC_REGISTER = state->PROGRAM_COUNTER;
}
if (AddressDefined(state, BadVaddr)) {
state->PROGRAM_COUNTER = 0x80000180;
} else {
state->PROGRAM_COUNTER = 0x80000000;
}
STATUS_REGISTER |= STATUS_EXL;
} else {
state->PROGRAM_COUNTER = 0x80000180;
}
}
void DoSysCallException ( usf_state_t * state, uint32_t DelaySlot) {
CAUSE_REGISTER = EXC_SYSCALL;
if (DelaySlot) {
CAUSE_REGISTER |= CAUSE_BD;
EPC_REGISTER = state->PROGRAM_COUNTER - 4;
} else {
EPC_REGISTER = state->PROGRAM_COUNTER;
}
STATUS_REGISTER |= STATUS_EXL;
state->PROGRAM_COUNTER = 0x80000180;
}

View file

@ -1,75 +0,0 @@
/*
* Project 64 - A Nintendo 64 emulator.
*
* (c) Copyright 2001 zilmar (zilmar@emulation64.com) and
* Jabo (jabo@emulation64.com).
*
* pj64 homepage: www.pj64.net
*
* Permission to use, copy, modify and distribute Project64 in both binary and
* source form, for non-commercial purposes, is hereby granted without fee,
* providing that this license information and copyright notice appear with
* all copies and any derived work.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event shall the authors be held liable for any damages
* arising from the use of this software.
*
* Project64 is freeware for PERSONAL USE only. Commercial users should
* seek permission of the copyright holders first. Commercial use includes
* charging money for Project64 or software derived from Project64.
*
* The copyright holders request that bug fixes and improvements to the code
* should be forwarded to them so if they want them.
*
*/
#define EXC_CODE(x) ((x)<<2)
#define EXC_INT EXC_CODE(0) /* interrupt */
#define EXC_MOD EXC_CODE(1) /* TLB mod */
#define EXC_RMISS EXC_CODE(2) /* Read TLB Miss */
#define EXC_WMISS EXC_CODE(3) /* Write TLB Miss */
#define EXC_RADE EXC_CODE(4) /* Read Address Error */
#define EXC_WADE EXC_CODE(5) /* Write Address Error */
#define EXC_IBE EXC_CODE(6) /* Instruction Bus Error */
#define EXC_DBE EXC_CODE(7) /* Data Bus Error */
#define EXC_SYSCALL EXC_CODE(8) /* SYSCALL */
#define EXC_BREAK EXC_CODE(9) /* BREAKpoint */
#define EXC_II EXC_CODE(10)/* Illegal Instruction */
#define EXC_CPU EXC_CODE(11)/* CoProcessor Unusable */
#define EXC_OV EXC_CODE(12)/* OVerflow */
#define EXC_TRAP EXC_CODE(13)/* Trap exception */
#define EXC_VCEI EXC_CODE(14)/* Virt. Coherency on Inst. fetch */
#define EXC_FPE EXC_CODE(15)/* Floating Point Exception */
#define EXC_WATCH EXC_CODE(23)/* Watchpoint reference */
#define EXC_VCED EXC_CODE(31)/* Virt. Coherency on data read */
#define Exception_Name(Except)\
(Except) == EXC_INT ? "interrupt" :\
(Except) == EXC_MOD ? "TLB mod" :\
(Except) == EXC_RMISS ? "Read TLB Miss" :\
(Except) == EXC_WMISS ? "Write TLB Miss" :\
(Except) == EXC_RADE ? "Read Address Error" :\
(Except) == EXC_WADE ? "Write Address Error" :\
(Except) == EXC_IBE ? "Instruction Bus Error" :\
(Except) == EXC_DBE ? "Data Bus Error" :\
(Except) == EXC_SYSCALL ? "SYSCALL" :\
(Except) == EXC_BREAK ? "Break" :\
(Except) == EXC_II ? "Illegal Instruction" :\
(Except) == EXC_CPU ? "CoProcessor Unusable" :\
(Except) == EXC_OV ? "OVerflow" :\
(Except) == EXC_TRAP ? "Trap exception" :\
(Except) == EXC_VCEI ? "Virt. Coherency on Inst. fetch" :\
(Except) == EXC_FPE ? "Floating Point Exception" :\
(Except) == EXC_WATCH ? "Watchpoint reference" :\
(Except) == EXC_VCED ? "Virt. Coherency on data read" :\
"Unkown"
void AiCheckInterrupts ( usf_state_t * );
void CheckInterrupts ( usf_state_t * );
void DoAddressError ( usf_state_t *, uint32_t DelaySlot, uint32_t BadVaddr, uint32_t FromRead );
void DoBreakException ( usf_state_t *, uint32_t DelaySlot );
void DoCopUnusableException ( usf_state_t *, uint32_t DelaySlot, uint32_t Coprocessor );
void DoIntrException ( usf_state_t *, uint32_t DelaySlot );
void DoTLBMiss ( usf_state_t *, uint32_t DelaySlot, uint32_t BadVaddr );
void DoSysCallException ( usf_state_t *, uint32_t DelaySlot);

View file

@ -1,799 +0,0 @@
/*
* Project 64 - A Nintendo 64 emulator.
*
* (c) Copyright 2001 zilmar (zilmar@emulation64.com) and
* Jabo (jabo@emulation64.com).
*
* pj64 homepage: www.pj64.net
*
* Permission to use, copy, modify and distribute Project64 in both binary and
* source form, for non-commercial purposes, is hereby granted without fee,
* providing that this license information and copyright notice appear with
* all copies and any derived work.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event shall the authors be held liable for any damages
* arising from the use of this software.
*
* Project64 is freeware for PERSONAL USE only. Commercial users should
* seek permission of the copyright holders first. Commercial use includes
* charging money for Project64 or software derived from Project64.
*
* The copyright holders request that bug fixes and improvements to the code
* should be forwarded to them so if they want them.
*
*/
#include <float.h>
#include "main.h"
#include "cpu.h"
#include "usf.h"
#include "memory.h"
#include "cpu_hle.h"
#include "usf_internal.h"
#include <stdio.h>
void (* R4300i_Opcode[64])(usf_state_t *);
void (* R4300i_Special[64])(usf_state_t *);
void (* R4300i_Regimm[32])(usf_state_t *);
void (* R4300i_CoP0[32])(usf_state_t *);
void (* R4300i_CoP0_Function[64])(usf_state_t *);
void (* R4300i_CoP1[32])(usf_state_t *);
void (* R4300i_CoP1_BC[32])(usf_state_t *);
void (* R4300i_CoP1_S[64])(usf_state_t *);
void (* R4300i_CoP1_D[64])(usf_state_t *);
void (* R4300i_CoP1_W[64])(usf_state_t *);
void (* R4300i_CoP1_L[64])(usf_state_t *);
void R4300i_opcode_SPECIAL (usf_state_t * state) {
R4300i_Special[ state->Opcode.u.e.funct ](state);
}
void R4300i_opcode_REGIMM (usf_state_t * state) {
R4300i_Regimm[ state->Opcode.u.b.rt ](state);
}
void R4300i_opcode_COP0 (usf_state_t * state) {
R4300i_CoP0[ state->Opcode.u.b.rs ](state);
}
void R4300i_opcode_COP0_CO (usf_state_t * state) {
R4300i_CoP0_Function[ state->Opcode.u.e.funct ](state);
}
void R4300i_opcode_COP1 (usf_state_t * state) {
R4300i_CoP1[ state->Opcode.u.f.fmt ](state);
}
void R4300i_opcode_COP1_BC (usf_state_t * state) {
R4300i_CoP1_BC[ state->Opcode.u.f.ft ](state);
}
void R4300i_opcode_COP1_S (usf_state_t * state) {
// controlfp(RoundingModel);
R4300i_CoP1_S[ state->Opcode.u.e.funct ](state);
}
void R4300i_opcode_COP1_D (usf_state_t * state) {
// controlfp(RoundingModel);
R4300i_CoP1_D[ state->Opcode.u.e.funct ](state);
}
void R4300i_opcode_COP1_W (usf_state_t * state) {
R4300i_CoP1_W[ state->Opcode.u.e.funct ](state);
}
void R4300i_opcode_COP1_L (usf_state_t * state) {
R4300i_CoP1_L[ state->Opcode.u.e.funct ](state);
}
void BuildInterpreter (usf_state_t * state) {
(void)state;
R4300i_Opcode[ 0] = R4300i_opcode_SPECIAL;
R4300i_Opcode[ 1] = R4300i_opcode_REGIMM;
R4300i_Opcode[ 2] = r4300i_J;
R4300i_Opcode[ 3] = r4300i_JAL;
R4300i_Opcode[ 4] = r4300i_BEQ;
R4300i_Opcode[ 5] = r4300i_BNE;
R4300i_Opcode[ 6] = r4300i_BLEZ;
R4300i_Opcode[ 7] = r4300i_BGTZ;
R4300i_Opcode[ 8] = r4300i_ADDI;
R4300i_Opcode[ 9] = r4300i_ADDIU;
R4300i_Opcode[10] = r4300i_SLTI;
R4300i_Opcode[11] = r4300i_SLTIU;
R4300i_Opcode[12] = r4300i_ANDI;
R4300i_Opcode[13] = r4300i_ORI;
R4300i_Opcode[14] = r4300i_XORI;
R4300i_Opcode[15] = r4300i_LUI;
R4300i_Opcode[16] = R4300i_opcode_COP0;
R4300i_Opcode[17] = R4300i_opcode_COP1;
R4300i_Opcode[18] = R4300i_UnknownOpcode;
R4300i_Opcode[19] = R4300i_UnknownOpcode;
R4300i_Opcode[20] = r4300i_BEQL;
R4300i_Opcode[21] = r4300i_BNEL;
R4300i_Opcode[22] = r4300i_BLEZL;
R4300i_Opcode[23] = r4300i_BGTZL;
R4300i_Opcode[24] = R4300i_UnknownOpcode;
R4300i_Opcode[25] = r4300i_DADDIU;
R4300i_Opcode[26] = r4300i_LDL;
R4300i_Opcode[27] = r4300i_LDR;
R4300i_Opcode[28] = R4300i_UnknownOpcode;
R4300i_Opcode[29] = R4300i_UnknownOpcode;
R4300i_Opcode[30] = R4300i_UnknownOpcode;
R4300i_Opcode[31] = R4300i_UnknownOpcode;
R4300i_Opcode[32] = r4300i_LB;
R4300i_Opcode[33] = r4300i_LH;
R4300i_Opcode[34] = r4300i_LWL;
R4300i_Opcode[35] = r4300i_LW;
R4300i_Opcode[36] = r4300i_LBU;
R4300i_Opcode[37] = r4300i_LHU;
R4300i_Opcode[38] = r4300i_LWR;
R4300i_Opcode[39] = r4300i_LWU;
R4300i_Opcode[40] = r4300i_SB;
R4300i_Opcode[41] = r4300i_SH;
R4300i_Opcode[42] = r4300i_SWL;
R4300i_Opcode[43] = r4300i_SW;
R4300i_Opcode[44] = r4300i_SDL;
R4300i_Opcode[45] = r4300i_SDR;
R4300i_Opcode[46] = r4300i_SWR;
R4300i_Opcode[47] = r4300i_CACHE;
R4300i_Opcode[48] = r4300i_LL;
R4300i_Opcode[49] = r4300i_LWC1;
R4300i_Opcode[50] = R4300i_UnknownOpcode;
R4300i_Opcode[51] = R4300i_UnknownOpcode;
R4300i_Opcode[52] = R4300i_UnknownOpcode;
R4300i_Opcode[53] = r4300i_LDC1;
R4300i_Opcode[54] = R4300i_UnknownOpcode;
R4300i_Opcode[55] = r4300i_LD;
R4300i_Opcode[56] = r4300i_SC;
R4300i_Opcode[57] = r4300i_SWC1;
R4300i_Opcode[58] = R4300i_UnknownOpcode;
R4300i_Opcode[59] = R4300i_UnknownOpcode;
R4300i_Opcode[60] = R4300i_UnknownOpcode;
R4300i_Opcode[61] = r4300i_SDC1;
R4300i_Opcode[62] = R4300i_UnknownOpcode;
R4300i_Opcode[63] = r4300i_SD;
R4300i_Special[ 0] = r4300i_SPECIAL_SLL;
R4300i_Special[ 1] = R4300i_UnknownOpcode;
R4300i_Special[ 2] = r4300i_SPECIAL_SRL;
R4300i_Special[ 3] = r4300i_SPECIAL_SRA;
R4300i_Special[ 4] = r4300i_SPECIAL_SLLV;
R4300i_Special[ 5] = R4300i_UnknownOpcode;
R4300i_Special[ 6] = r4300i_SPECIAL_SRLV;
R4300i_Special[ 7] = r4300i_SPECIAL_SRAV;
R4300i_Special[ 8] = r4300i_SPECIAL_JR;
R4300i_Special[ 9] = r4300i_SPECIAL_JALR;
R4300i_Special[10] = R4300i_UnknownOpcode;
R4300i_Special[11] = R4300i_UnknownOpcode;
R4300i_Special[12] = r4300i_SPECIAL_SYSCALL;
R4300i_Special[13] = r4300i_SPECIAL_BREAK;
R4300i_Special[14] = R4300i_UnknownOpcode;
R4300i_Special[15] = r4300i_SPECIAL_SYNC;
R4300i_Special[16] = r4300i_SPECIAL_MFHI;
R4300i_Special[17] = r4300i_SPECIAL_MTHI;
R4300i_Special[18] = r4300i_SPECIAL_MFLO;
R4300i_Special[19] = r4300i_SPECIAL_MTLO;
R4300i_Special[20] = r4300i_SPECIAL_DSLLV;
R4300i_Special[21] = R4300i_UnknownOpcode;
R4300i_Special[22] = r4300i_SPECIAL_DSRLV;
R4300i_Special[23] = r4300i_SPECIAL_DSRAV;
R4300i_Special[24] = r4300i_SPECIAL_MULT;
R4300i_Special[25] = r4300i_SPECIAL_MULTU;
R4300i_Special[26] = r4300i_SPECIAL_DIV;
R4300i_Special[27] = r4300i_SPECIAL_DIVU;
R4300i_Special[28] = r4300i_SPECIAL_DMULT;
R4300i_Special[29] = r4300i_SPECIAL_DMULTU;
R4300i_Special[30] = r4300i_SPECIAL_DDIV;
R4300i_Special[31] = r4300i_SPECIAL_DDIVU;
R4300i_Special[32] = r4300i_SPECIAL_ADD;
R4300i_Special[33] = r4300i_SPECIAL_ADDU;
R4300i_Special[34] = r4300i_SPECIAL_SUB;
R4300i_Special[35] = r4300i_SPECIAL_SUBU;
R4300i_Special[36] = r4300i_SPECIAL_AND;
R4300i_Special[37] = r4300i_SPECIAL_OR;
R4300i_Special[38] = r4300i_SPECIAL_XOR;
R4300i_Special[39] = r4300i_SPECIAL_NOR;
R4300i_Special[40] = R4300i_UnknownOpcode;
R4300i_Special[41] = R4300i_UnknownOpcode;
R4300i_Special[42] = r4300i_SPECIAL_SLT;
R4300i_Special[43] = r4300i_SPECIAL_SLTU;
R4300i_Special[44] = r4300i_SPECIAL_DADD;
R4300i_Special[45] = r4300i_SPECIAL_DADDU;
R4300i_Special[46] = r4300i_SPECIAL_DSUB;
R4300i_Special[47] = r4300i_SPECIAL_DSUBU;
R4300i_Special[48] = R4300i_UnknownOpcode;
R4300i_Special[49] = R4300i_UnknownOpcode;
R4300i_Special[50] = R4300i_UnknownOpcode;
R4300i_Special[51] = R4300i_UnknownOpcode;
R4300i_Special[52] = r4300i_SPECIAL_TEQ;
R4300i_Special[53] = R4300i_UnknownOpcode;
R4300i_Special[54] = R4300i_UnknownOpcode;
R4300i_Special[55] = R4300i_UnknownOpcode;
R4300i_Special[56] = r4300i_SPECIAL_DSLL;
R4300i_Special[57] = R4300i_UnknownOpcode;
R4300i_Special[58] = r4300i_SPECIAL_DSRL;
R4300i_Special[59] = r4300i_SPECIAL_DSRA;
R4300i_Special[60] = r4300i_SPECIAL_DSLL32;
R4300i_Special[61] = R4300i_UnknownOpcode;
R4300i_Special[62] = r4300i_SPECIAL_DSRL32;
R4300i_Special[63] = r4300i_SPECIAL_DSRA32;
R4300i_Regimm[ 0] = r4300i_REGIMM_BLTZ;
R4300i_Regimm[ 1] = r4300i_REGIMM_BGEZ;
R4300i_Regimm[ 2] = r4300i_REGIMM_BLTZL;
R4300i_Regimm[ 3] = r4300i_REGIMM_BGEZL;
R4300i_Regimm[ 4] = R4300i_UnknownOpcode;
R4300i_Regimm[ 5] = R4300i_UnknownOpcode;
R4300i_Regimm[ 6] = R4300i_UnknownOpcode;
R4300i_Regimm[ 7] = R4300i_UnknownOpcode;
R4300i_Regimm[ 8] = R4300i_UnknownOpcode;
R4300i_Regimm[ 9] = R4300i_UnknownOpcode;
R4300i_Regimm[10] = R4300i_UnknownOpcode;
R4300i_Regimm[11] = R4300i_UnknownOpcode;
R4300i_Regimm[12] = R4300i_UnknownOpcode;
R4300i_Regimm[13] = R4300i_UnknownOpcode;
R4300i_Regimm[14] = R4300i_UnknownOpcode;
R4300i_Regimm[15] = R4300i_UnknownOpcode;
R4300i_Regimm[16] = r4300i_REGIMM_BLTZAL;
R4300i_Regimm[17] = r4300i_REGIMM_BGEZAL;
R4300i_Regimm[18] = R4300i_UnknownOpcode;
R4300i_Regimm[19] = R4300i_UnknownOpcode;
R4300i_Regimm[20] = R4300i_UnknownOpcode;
R4300i_Regimm[21] = R4300i_UnknownOpcode;
R4300i_Regimm[22] = R4300i_UnknownOpcode;
R4300i_Regimm[23] = R4300i_UnknownOpcode;
R4300i_Regimm[24] = R4300i_UnknownOpcode;
R4300i_Regimm[25] = R4300i_UnknownOpcode;
R4300i_Regimm[26] = R4300i_UnknownOpcode;
R4300i_Regimm[27] = R4300i_UnknownOpcode;
R4300i_Regimm[28] = R4300i_UnknownOpcode;
R4300i_Regimm[29] = R4300i_UnknownOpcode;
R4300i_Regimm[30] = R4300i_UnknownOpcode;
R4300i_Regimm[31] = R4300i_UnknownOpcode;
R4300i_CoP0[ 0] = r4300i_COP0_MF;
R4300i_CoP0[ 1] = R4300i_UnknownOpcode;
R4300i_CoP0[ 2] = R4300i_UnknownOpcode;
R4300i_CoP0[ 3] = R4300i_UnknownOpcode;
R4300i_CoP0[ 4] = r4300i_COP0_MT;
R4300i_CoP0[ 5] = R4300i_UnknownOpcode;
R4300i_CoP0[ 6] = R4300i_UnknownOpcode;
R4300i_CoP0[ 7] = R4300i_UnknownOpcode;
R4300i_CoP0[ 8] = R4300i_UnknownOpcode;
R4300i_CoP0[ 9] = R4300i_UnknownOpcode;
R4300i_CoP0[10] = R4300i_UnknownOpcode;
R4300i_CoP0[11] = R4300i_UnknownOpcode;
R4300i_CoP0[12] = R4300i_UnknownOpcode;
R4300i_CoP0[13] = R4300i_UnknownOpcode;
R4300i_CoP0[14] = R4300i_UnknownOpcode;
R4300i_CoP0[15] = R4300i_UnknownOpcode;
R4300i_CoP0[16] = R4300i_opcode_COP0_CO;
R4300i_CoP0[17] = R4300i_opcode_COP0_CO;
R4300i_CoP0[18] = R4300i_opcode_COP0_CO;
R4300i_CoP0[19] = R4300i_opcode_COP0_CO;
R4300i_CoP0[20] = R4300i_opcode_COP0_CO;
R4300i_CoP0[21] = R4300i_opcode_COP0_CO;
R4300i_CoP0[22] = R4300i_opcode_COP0_CO;
R4300i_CoP0[23] = R4300i_opcode_COP0_CO;
R4300i_CoP0[24] = R4300i_opcode_COP0_CO;
R4300i_CoP0[25] = R4300i_opcode_COP0_CO;
R4300i_CoP0[26] = R4300i_opcode_COP0_CO;
R4300i_CoP0[27] = R4300i_opcode_COP0_CO;
R4300i_CoP0[28] = R4300i_opcode_COP0_CO;
R4300i_CoP0[29] = R4300i_opcode_COP0_CO;
R4300i_CoP0[30] = R4300i_opcode_COP0_CO;
R4300i_CoP0[31] = R4300i_opcode_COP0_CO;
R4300i_CoP0_Function[ 0] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[ 1] = r4300i_COP0_CO_TLBR;
R4300i_CoP0_Function[ 2] = r4300i_COP0_CO_TLBWI;
R4300i_CoP0_Function[ 3] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[ 4] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[ 5] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[ 6] = r4300i_COP0_CO_TLBWR;
R4300i_CoP0_Function[ 7] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[ 8] = r4300i_COP0_CO_TLBP;
R4300i_CoP0_Function[ 9] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[10] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[11] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[12] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[13] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[14] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[15] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[16] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[17] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[18] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[19] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[20] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[21] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[22] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[23] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[24] = r4300i_COP0_CO_ERET;
R4300i_CoP0_Function[25] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[26] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[27] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[28] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[29] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[30] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[31] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[32] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[33] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[34] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[35] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[36] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[37] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[38] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[39] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[40] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[41] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[42] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[43] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[44] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[45] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[46] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[47] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[48] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[49] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[50] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[51] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[52] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[53] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[54] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[55] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[56] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[57] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[58] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[59] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[60] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[61] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[62] = R4300i_UnknownOpcode;
R4300i_CoP0_Function[63] = R4300i_UnknownOpcode;
R4300i_CoP1[ 0] = r4300i_COP1_MF;
R4300i_CoP1[ 1] = r4300i_COP1_DMF;
R4300i_CoP1[ 2] = r4300i_COP1_CF;
R4300i_CoP1[ 3] = R4300i_UnknownOpcode;
R4300i_CoP1[ 4] = r4300i_COP1_MT;
R4300i_CoP1[ 5] = r4300i_COP1_DMT;
R4300i_CoP1[ 6] = r4300i_COP1_CT;
R4300i_CoP1[ 7] = R4300i_UnknownOpcode;
R4300i_CoP1[ 8] = R4300i_opcode_COP1_BC;
R4300i_CoP1[ 9] = R4300i_UnknownOpcode;
R4300i_CoP1[10] = R4300i_UnknownOpcode;
R4300i_CoP1[11] = R4300i_UnknownOpcode;
R4300i_CoP1[12] = R4300i_UnknownOpcode;
R4300i_CoP1[13] = R4300i_UnknownOpcode;
R4300i_CoP1[14] = R4300i_UnknownOpcode;
R4300i_CoP1[15] = R4300i_UnknownOpcode;
R4300i_CoP1[16] = R4300i_opcode_COP1_S;
R4300i_CoP1[17] = R4300i_opcode_COP1_D;
R4300i_CoP1[18] = R4300i_UnknownOpcode;
R4300i_CoP1[19] = R4300i_UnknownOpcode;
R4300i_CoP1[20] = R4300i_opcode_COP1_W;
R4300i_CoP1[21] = R4300i_opcode_COP1_L;
R4300i_CoP1[22] = R4300i_UnknownOpcode;
R4300i_CoP1[23] = R4300i_UnknownOpcode;
R4300i_CoP1[24] = R4300i_UnknownOpcode;
R4300i_CoP1[25] = R4300i_UnknownOpcode;
R4300i_CoP1[26] = R4300i_UnknownOpcode;
R4300i_CoP1[27] = R4300i_UnknownOpcode;
R4300i_CoP1[28] = R4300i_UnknownOpcode;
R4300i_CoP1[29] = R4300i_UnknownOpcode;
R4300i_CoP1[30] = R4300i_UnknownOpcode;
R4300i_CoP1[31] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[ 0] = r4300i_COP1_BCF;
R4300i_CoP1_BC[ 1] = r4300i_COP1_BCT;
R4300i_CoP1_BC[ 2] = r4300i_COP1_BCFL;
R4300i_CoP1_BC[ 3] = r4300i_COP1_BCTL;
R4300i_CoP1_BC[ 4] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[ 5] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[ 6] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[ 7] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[ 8] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[ 9] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[10] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[11] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[12] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[13] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[14] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[15] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[16] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[17] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[18] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[19] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[20] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[21] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[22] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[23] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[24] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[25] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[26] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[27] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[28] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[29] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[30] = R4300i_UnknownOpcode;
R4300i_CoP1_BC[31] = R4300i_UnknownOpcode;
R4300i_CoP1_S[ 0] = r4300i_COP1_S_ADD;
R4300i_CoP1_S[ 1] = r4300i_COP1_S_SUB;
R4300i_CoP1_S[ 2] = r4300i_COP1_S_MUL;
R4300i_CoP1_S[ 3] = r4300i_COP1_S_DIV;
R4300i_CoP1_S[ 4] = r4300i_COP1_S_SQRT;
R4300i_CoP1_S[ 5] = r4300i_COP1_S_ABS;
R4300i_CoP1_S[ 6] = r4300i_COP1_S_MOV;
R4300i_CoP1_S[ 7] = r4300i_COP1_S_NEG;
R4300i_CoP1_S[ 8] = R4300i_UnknownOpcode;
R4300i_CoP1_S[ 9] = r4300i_COP1_S_TRUNC_L;
R4300i_CoP1_S[10] = r4300i_COP1_S_CEIL_L; //added by Witten
R4300i_CoP1_S[11] = r4300i_COP1_S_FLOOR_L; //added by Witten
R4300i_CoP1_S[12] = r4300i_COP1_S_ROUND_W;
R4300i_CoP1_S[13] = r4300i_COP1_S_TRUNC_W;
R4300i_CoP1_S[14] = r4300i_COP1_S_CEIL_W; //added by Witten
R4300i_CoP1_S[15] = r4300i_COP1_S_FLOOR_W;
R4300i_CoP1_S[16] = R4300i_UnknownOpcode;
R4300i_CoP1_S[17] = R4300i_UnknownOpcode;
R4300i_CoP1_S[18] = R4300i_UnknownOpcode;
R4300i_CoP1_S[19] = R4300i_UnknownOpcode;
R4300i_CoP1_S[20] = R4300i_UnknownOpcode;
R4300i_CoP1_S[21] = R4300i_UnknownOpcode;
R4300i_CoP1_S[22] = R4300i_UnknownOpcode;
R4300i_CoP1_S[23] = R4300i_UnknownOpcode;
R4300i_CoP1_S[24] = R4300i_UnknownOpcode;
R4300i_CoP1_S[25] = R4300i_UnknownOpcode;
R4300i_CoP1_S[26] = R4300i_UnknownOpcode;
R4300i_CoP1_S[27] = R4300i_UnknownOpcode;
R4300i_CoP1_S[28] = R4300i_UnknownOpcode;
R4300i_CoP1_S[29] = R4300i_UnknownOpcode;
R4300i_CoP1_S[30] = R4300i_UnknownOpcode;
R4300i_CoP1_S[31] = R4300i_UnknownOpcode;
R4300i_CoP1_S[32] = R4300i_UnknownOpcode;
R4300i_CoP1_S[33] = r4300i_COP1_S_CVT_D;
R4300i_CoP1_S[34] = R4300i_UnknownOpcode;
R4300i_CoP1_S[35] = R4300i_UnknownOpcode;
R4300i_CoP1_S[36] = r4300i_COP1_S_CVT_W;
R4300i_CoP1_S[37] = r4300i_COP1_S_CVT_L;
R4300i_CoP1_S[38] = R4300i_UnknownOpcode;
R4300i_CoP1_S[39] = R4300i_UnknownOpcode;
R4300i_CoP1_S[40] = R4300i_UnknownOpcode;
R4300i_CoP1_S[41] = R4300i_UnknownOpcode;
R4300i_CoP1_S[42] = R4300i_UnknownOpcode;
R4300i_CoP1_S[43] = R4300i_UnknownOpcode;
R4300i_CoP1_S[44] = R4300i_UnknownOpcode;
R4300i_CoP1_S[45] = R4300i_UnknownOpcode;
R4300i_CoP1_S[46] = R4300i_UnknownOpcode;
R4300i_CoP1_S[47] = R4300i_UnknownOpcode;
R4300i_CoP1_S[48] = r4300i_COP1_S_CMP;
R4300i_CoP1_S[49] = r4300i_COP1_S_CMP;
R4300i_CoP1_S[50] = r4300i_COP1_S_CMP;
R4300i_CoP1_S[51] = r4300i_COP1_S_CMP;
R4300i_CoP1_S[52] = r4300i_COP1_S_CMP;
R4300i_CoP1_S[53] = r4300i_COP1_S_CMP;
R4300i_CoP1_S[54] = r4300i_COP1_S_CMP;
R4300i_CoP1_S[55] = r4300i_COP1_S_CMP;
R4300i_CoP1_S[56] = r4300i_COP1_S_CMP;
R4300i_CoP1_S[57] = r4300i_COP1_S_CMP;
R4300i_CoP1_S[58] = r4300i_COP1_S_CMP;
R4300i_CoP1_S[59] = r4300i_COP1_S_CMP;
R4300i_CoP1_S[60] = r4300i_COP1_S_CMP;
R4300i_CoP1_S[61] = r4300i_COP1_S_CMP;
R4300i_CoP1_S[62] = r4300i_COP1_S_CMP;
R4300i_CoP1_S[63] = r4300i_COP1_S_CMP;
R4300i_CoP1_D[ 0] = r4300i_COP1_D_ADD;
R4300i_CoP1_D[ 1] = r4300i_COP1_D_SUB;
R4300i_CoP1_D[ 2] = r4300i_COP1_D_MUL;
R4300i_CoP1_D[ 3] = r4300i_COP1_D_DIV;
R4300i_CoP1_D[ 4] = r4300i_COP1_D_SQRT;
R4300i_CoP1_D[ 5] = r4300i_COP1_D_ABS;
R4300i_CoP1_D[ 6] = r4300i_COP1_D_MOV;
R4300i_CoP1_D[ 7] = r4300i_COP1_D_NEG;
R4300i_CoP1_D[ 8] = R4300i_UnknownOpcode;
R4300i_CoP1_D[ 9] = r4300i_COP1_D_TRUNC_L; //added by Witten
R4300i_CoP1_D[10] = r4300i_COP1_D_CEIL_L; //added by Witten
R4300i_CoP1_D[11] = r4300i_COP1_D_FLOOR_L; //added by Witten
R4300i_CoP1_D[12] = r4300i_COP1_D_ROUND_W;
R4300i_CoP1_D[13] = r4300i_COP1_D_TRUNC_W;
R4300i_CoP1_D[14] = r4300i_COP1_D_CEIL_W; //added by Witten
R4300i_CoP1_D[15] = r4300i_COP1_D_FLOOR_W; //added by Witten
R4300i_CoP1_D[16] = R4300i_UnknownOpcode;
R4300i_CoP1_D[17] = R4300i_UnknownOpcode;
R4300i_CoP1_D[18] = R4300i_UnknownOpcode;
R4300i_CoP1_D[19] = R4300i_UnknownOpcode;
R4300i_CoP1_D[20] = R4300i_UnknownOpcode;
R4300i_CoP1_D[21] = R4300i_UnknownOpcode;
R4300i_CoP1_D[22] = R4300i_UnknownOpcode;
R4300i_CoP1_D[23] = R4300i_UnknownOpcode;
R4300i_CoP1_D[24] = R4300i_UnknownOpcode;
R4300i_CoP1_D[25] = R4300i_UnknownOpcode;
R4300i_CoP1_D[26] = R4300i_UnknownOpcode;
R4300i_CoP1_D[27] = R4300i_UnknownOpcode;
R4300i_CoP1_D[28] = R4300i_UnknownOpcode;
R4300i_CoP1_D[29] = R4300i_UnknownOpcode;
R4300i_CoP1_D[30] = R4300i_UnknownOpcode;
R4300i_CoP1_D[31] = R4300i_UnknownOpcode;
R4300i_CoP1_D[32] = r4300i_COP1_D_CVT_S;
R4300i_CoP1_D[33] = R4300i_UnknownOpcode;
R4300i_CoP1_D[34] = R4300i_UnknownOpcode;
R4300i_CoP1_D[35] = R4300i_UnknownOpcode;
R4300i_CoP1_D[36] = r4300i_COP1_D_CVT_W;
R4300i_CoP1_D[37] = r4300i_COP1_D_CVT_L;
R4300i_CoP1_D[38] = R4300i_UnknownOpcode;
R4300i_CoP1_D[39] = R4300i_UnknownOpcode;
R4300i_CoP1_D[40] = R4300i_UnknownOpcode;
R4300i_CoP1_D[41] = R4300i_UnknownOpcode;
R4300i_CoP1_D[42] = R4300i_UnknownOpcode;
R4300i_CoP1_D[43] = R4300i_UnknownOpcode;
R4300i_CoP1_D[44] = R4300i_UnknownOpcode;
R4300i_CoP1_D[45] = R4300i_UnknownOpcode;
R4300i_CoP1_D[46] = R4300i_UnknownOpcode;
R4300i_CoP1_D[47] = R4300i_UnknownOpcode;
R4300i_CoP1_D[48] = r4300i_COP1_D_CMP;
R4300i_CoP1_D[49] = r4300i_COP1_D_CMP;
R4300i_CoP1_D[50] = r4300i_COP1_D_CMP;
R4300i_CoP1_D[51] = r4300i_COP1_D_CMP;
R4300i_CoP1_D[52] = r4300i_COP1_D_CMP;
R4300i_CoP1_D[53] = r4300i_COP1_D_CMP;
R4300i_CoP1_D[54] = r4300i_COP1_D_CMP;
R4300i_CoP1_D[55] = r4300i_COP1_D_CMP;
R4300i_CoP1_D[56] = r4300i_COP1_D_CMP;
R4300i_CoP1_D[57] = r4300i_COP1_D_CMP;
R4300i_CoP1_D[58] = r4300i_COP1_D_CMP;
R4300i_CoP1_D[59] = r4300i_COP1_D_CMP;
R4300i_CoP1_D[60] = r4300i_COP1_D_CMP;
R4300i_CoP1_D[61] = r4300i_COP1_D_CMP;
R4300i_CoP1_D[62] = r4300i_COP1_D_CMP;
R4300i_CoP1_D[63] = r4300i_COP1_D_CMP;
R4300i_CoP1_W[ 0] = R4300i_UnknownOpcode;
R4300i_CoP1_W[ 1] = R4300i_UnknownOpcode;
R4300i_CoP1_W[ 2] = R4300i_UnknownOpcode;
R4300i_CoP1_W[ 3] = R4300i_UnknownOpcode;
R4300i_CoP1_W[ 4] = R4300i_UnknownOpcode;
R4300i_CoP1_W[ 5] = R4300i_UnknownOpcode;
R4300i_CoP1_W[ 6] = R4300i_UnknownOpcode;
R4300i_CoP1_W[ 7] = R4300i_UnknownOpcode;
R4300i_CoP1_W[ 8] = R4300i_UnknownOpcode;
R4300i_CoP1_W[ 9] = R4300i_UnknownOpcode;
R4300i_CoP1_W[10] = R4300i_UnknownOpcode;
R4300i_CoP1_W[11] = R4300i_UnknownOpcode;
R4300i_CoP1_W[12] = R4300i_UnknownOpcode;
R4300i_CoP1_W[13] = R4300i_UnknownOpcode;
R4300i_CoP1_W[14] = R4300i_UnknownOpcode;
R4300i_CoP1_W[15] = R4300i_UnknownOpcode;
R4300i_CoP1_W[16] = R4300i_UnknownOpcode;
R4300i_CoP1_W[17] = R4300i_UnknownOpcode;
R4300i_CoP1_W[18] = R4300i_UnknownOpcode;
R4300i_CoP1_W[19] = R4300i_UnknownOpcode;
R4300i_CoP1_W[20] = R4300i_UnknownOpcode;
R4300i_CoP1_W[21] = R4300i_UnknownOpcode;
R4300i_CoP1_W[22] = R4300i_UnknownOpcode;
R4300i_CoP1_W[23] = R4300i_UnknownOpcode;
R4300i_CoP1_W[24] = R4300i_UnknownOpcode;
R4300i_CoP1_W[25] = R4300i_UnknownOpcode;
R4300i_CoP1_W[26] = R4300i_UnknownOpcode;
R4300i_CoP1_W[27] = R4300i_UnknownOpcode;
R4300i_CoP1_W[28] = R4300i_UnknownOpcode;
R4300i_CoP1_W[29] = R4300i_UnknownOpcode;
R4300i_CoP1_W[30] = R4300i_UnknownOpcode;
R4300i_CoP1_W[31] = R4300i_UnknownOpcode;
R4300i_CoP1_W[32] = r4300i_COP1_W_CVT_S;
R4300i_CoP1_W[33] = r4300i_COP1_W_CVT_D;
R4300i_CoP1_W[34] = R4300i_UnknownOpcode;
R4300i_CoP1_W[35] = R4300i_UnknownOpcode;
R4300i_CoP1_W[36] = R4300i_UnknownOpcode;
R4300i_CoP1_W[37] = R4300i_UnknownOpcode;
R4300i_CoP1_W[38] = R4300i_UnknownOpcode;
R4300i_CoP1_W[39] = R4300i_UnknownOpcode;
R4300i_CoP1_W[40] = R4300i_UnknownOpcode;
R4300i_CoP1_W[41] = R4300i_UnknownOpcode;
R4300i_CoP1_W[42] = R4300i_UnknownOpcode;
R4300i_CoP1_W[43] = R4300i_UnknownOpcode;
R4300i_CoP1_W[44] = R4300i_UnknownOpcode;
R4300i_CoP1_W[45] = R4300i_UnknownOpcode;
R4300i_CoP1_W[46] = R4300i_UnknownOpcode;
R4300i_CoP1_W[47] = R4300i_UnknownOpcode;
R4300i_CoP1_W[48] = R4300i_UnknownOpcode;
R4300i_CoP1_W[49] = R4300i_UnknownOpcode;
R4300i_CoP1_W[50] = R4300i_UnknownOpcode;
R4300i_CoP1_W[51] = R4300i_UnknownOpcode;
R4300i_CoP1_W[52] = R4300i_UnknownOpcode;
R4300i_CoP1_W[53] = R4300i_UnknownOpcode;
R4300i_CoP1_W[54] = R4300i_UnknownOpcode;
R4300i_CoP1_W[55] = R4300i_UnknownOpcode;
R4300i_CoP1_W[56] = R4300i_UnknownOpcode;
R4300i_CoP1_W[57] = R4300i_UnknownOpcode;
R4300i_CoP1_W[58] = R4300i_UnknownOpcode;
R4300i_CoP1_W[59] = R4300i_UnknownOpcode;
R4300i_CoP1_W[60] = R4300i_UnknownOpcode;
R4300i_CoP1_W[61] = R4300i_UnknownOpcode;
R4300i_CoP1_W[62] = R4300i_UnknownOpcode;
R4300i_CoP1_W[63] = R4300i_UnknownOpcode;
R4300i_CoP1_L[ 0] = R4300i_UnknownOpcode;
R4300i_CoP1_L[ 1] = R4300i_UnknownOpcode;
R4300i_CoP1_L[ 2] = R4300i_UnknownOpcode;
R4300i_CoP1_L[ 3] = R4300i_UnknownOpcode;
R4300i_CoP1_L[ 4] = R4300i_UnknownOpcode;
R4300i_CoP1_L[ 5] = R4300i_UnknownOpcode;
R4300i_CoP1_L[ 6] = R4300i_UnknownOpcode;
R4300i_CoP1_L[ 7] = R4300i_UnknownOpcode;
R4300i_CoP1_L[ 8] = R4300i_UnknownOpcode;
R4300i_CoP1_L[ 9] = R4300i_UnknownOpcode;
R4300i_CoP1_L[10] = R4300i_UnknownOpcode;
R4300i_CoP1_L[11] = R4300i_UnknownOpcode;
R4300i_CoP1_L[12] = R4300i_UnknownOpcode;
R4300i_CoP1_L[13] = R4300i_UnknownOpcode;
R4300i_CoP1_L[14] = R4300i_UnknownOpcode;
R4300i_CoP1_L[15] = R4300i_UnknownOpcode;
R4300i_CoP1_L[16] = R4300i_UnknownOpcode;
R4300i_CoP1_L[17] = R4300i_UnknownOpcode;
R4300i_CoP1_L[18] = R4300i_UnknownOpcode;
R4300i_CoP1_L[19] = R4300i_UnknownOpcode;
R4300i_CoP1_L[20] = R4300i_UnknownOpcode;
R4300i_CoP1_L[21] = R4300i_UnknownOpcode;
R4300i_CoP1_L[22] = R4300i_UnknownOpcode;
R4300i_CoP1_L[23] = R4300i_UnknownOpcode;
R4300i_CoP1_L[24] = R4300i_UnknownOpcode;
R4300i_CoP1_L[25] = R4300i_UnknownOpcode;
R4300i_CoP1_L[26] = R4300i_UnknownOpcode;
R4300i_CoP1_L[27] = R4300i_UnknownOpcode;
R4300i_CoP1_L[28] = R4300i_UnknownOpcode;
R4300i_CoP1_L[29] = R4300i_UnknownOpcode;
R4300i_CoP1_L[30] = R4300i_UnknownOpcode;
R4300i_CoP1_L[31] = R4300i_UnknownOpcode;
R4300i_CoP1_L[32] = r4300i_COP1_L_CVT_S;
R4300i_CoP1_L[33] = r4300i_COP1_L_CVT_D;
R4300i_CoP1_L[34] = R4300i_UnknownOpcode;
R4300i_CoP1_L[35] = R4300i_UnknownOpcode;
R4300i_CoP1_L[36] = R4300i_UnknownOpcode;
R4300i_CoP1_L[37] = R4300i_UnknownOpcode;
R4300i_CoP1_L[38] = R4300i_UnknownOpcode;
R4300i_CoP1_L[39] = R4300i_UnknownOpcode;
R4300i_CoP1_L[40] = R4300i_UnknownOpcode;
R4300i_CoP1_L[41] = R4300i_UnknownOpcode;
R4300i_CoP1_L[42] = R4300i_UnknownOpcode;
R4300i_CoP1_L[43] = R4300i_UnknownOpcode;
R4300i_CoP1_L[44] = R4300i_UnknownOpcode;
R4300i_CoP1_L[45] = R4300i_UnknownOpcode;
R4300i_CoP1_L[46] = R4300i_UnknownOpcode;
R4300i_CoP1_L[47] = R4300i_UnknownOpcode;
R4300i_CoP1_L[48] = R4300i_UnknownOpcode;
R4300i_CoP1_L[49] = R4300i_UnknownOpcode;
R4300i_CoP1_L[50] = R4300i_UnknownOpcode;
R4300i_CoP1_L[51] = R4300i_UnknownOpcode;
R4300i_CoP1_L[52] = R4300i_UnknownOpcode;
R4300i_CoP1_L[53] = R4300i_UnknownOpcode;
R4300i_CoP1_L[54] = R4300i_UnknownOpcode;
R4300i_CoP1_L[55] = R4300i_UnknownOpcode;
R4300i_CoP1_L[56] = R4300i_UnknownOpcode;
R4300i_CoP1_L[57] = R4300i_UnknownOpcode;
R4300i_CoP1_L[58] = R4300i_UnknownOpcode;
R4300i_CoP1_L[59] = R4300i_UnknownOpcode;
R4300i_CoP1_L[60] = R4300i_UnknownOpcode;
R4300i_CoP1_L[61] = R4300i_UnknownOpcode;
R4300i_CoP1_L[62] = R4300i_UnknownOpcode;
R4300i_CoP1_L[63] = R4300i_UnknownOpcode;
}
void RunFunction(usf_state_t * state, uint32_t address) {
uint32_t oldPC = state->PROGRAM_COUNTER, oldRA = state->GPR[31].UW[0], la = state->NextInstruction;
int callStack = 0;
state->NextInstruction = NORMAL;
state->PROGRAM_COUNTER = address;
while( (state->PROGRAM_COUNTER != oldRA) || callStack) {
if(state->PROGRAM_COUNTER == address)
callStack++;
ExecuteInterpreterOpCode(state);
if(state->PROGRAM_COUNTER == oldRA)
callStack--;
}
state->PROGRAM_COUNTER = oldPC;
state->GPR[31].UW[0] = oldRA;
state->NextInstruction = la;
}
#ifdef DEBUG_INFO
#include "debugger/dbg_decoder.h"
#endif
void ExecuteInterpreterOpCode (usf_state_t * state) {
if (*state->WaitMode) state->Timers->Timer = -1;
if (!r4300i_LW_VAddr(state, state->PROGRAM_COUNTER, &state->Opcode.u.Hex)) {
DoTLBMiss(state, state->NextInstruction == JUMP,state->PROGRAM_COUNTER);
state->NextInstruction = NORMAL;
return;
}
#ifdef DEBUG_INFO
{
char opcode[256];
char arguments[256];
r4300_decode_op(state->Opcode.u.Hex, opcode, arguments, state->PROGRAM_COUNTER);
fprintf(state->debug_log, "%08x: %-16s %s\n", state->PROGRAM_COUNTER, opcode, arguments);
}
#endif
COUNT_REGISTER += 2;
state->Timers->Timer -= 2;
RANDOM_REGISTER -= 1;
if ((int32_t)RANDOM_REGISTER < (int32_t)WIRED_REGISTER) {
RANDOM_REGISTER = 31;
}
R4300i_Opcode[ state->Opcode.u.b.op ](state);
if (state->GPR[0].DW != 0) {
state->GPR[0].DW = 0;
}
switch (state->NextInstruction) {
case NORMAL:
state->PROGRAM_COUNTER += 4;
break;
case DELAY_SLOT:
state->NextInstruction = JUMP;
state->PROGRAM_COUNTER += 4;
break;
case JUMP:
if (
#ifdef DEBUG_INFO
0 &&
#endif
state->cpu_hle_entry_count &&
DoCPUHLE(state, state->JumpToLocation)) {
state->PROGRAM_COUNTER = state->GPR[31].UW[0];
state->NextInstruction = NORMAL;
}
else {
state->PROGRAM_COUNTER = state->JumpToLocation;
state->NextInstruction = NORMAL;
}
if ((int32_t)state->Timers->Timer < 0) { TimerDone(state); }
if (state->CPU_Action->DoSomething) { DoSomething(state); }
}
}
void StartInterpreterCPU (usf_state_t * state) {
const int safety_count_max = 20000000;
int safety_count = safety_count_max;
size_t last_sample_buffer_count = state->sample_buffer_count;
state->NextInstruction = NORMAL;
while(state->cpu_running) {
ExecuteInterpreterOpCode(state);
if (!--safety_count) {
if (last_sample_buffer_count == state->sample_buffer_count) {
DisplayError( state, "Emulator core is not generating any samples after 20 million instructions" );
break;
} else {
safety_count = safety_count_max;
last_sample_buffer_count = state->sample_buffer_count;
}
}
}
state->cpu_stopped = 1;
}
void TestInterpreterJump (usf_state_t * state, uint32_t PC, uint32_t TargetPC, int32_t Reg1, int32_t Reg2) {
if (PC != TargetPC) { return; }
if (DelaySlotEffectsCompare(state,PC,Reg1,Reg2)) { return; }
InPermLoop(state);
}

View file

@ -1,37 +0,0 @@
/*
* Project 64 - A Nintendo 64 emulator.
*
* (c) Copyright 2001 zilmar (zilmar@emulation64.com) and
* Jabo (jabo@emulation64.com).
*
* pj64 homepage: www.pj64.net
*
* Permission to use, copy, modify and distribute Project64 in both binary and
* source form, for non-commercial purposes, is hereby granted without fee,
* providing that this license information and copyright notice appear with
* all copies and any derived work.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event shall the authors be held liable for any damages
* arising from the use of this software.
*
* Project64 is freeware for PERSONAL USE only. Commercial users should
* seek permission of the copyright holders first. Commercial use includes
* charging money for Project64 or software derived from Project64.
*
* The copyright holders request that bug fixes and improvements to the code
* should be forwarded to them so if they want them.
*
*/
#include <stdint.h>
void BuildInterpreter ( usf_state_t * );
void ExecuteInterpreterOpCode ( usf_state_t * );
void StartInterpreterCPU ( usf_state_t * );
void TestInterpreterJump ( usf_state_t *, uint32_t PC, uint32_t TargetPC, int32_t Reg1, int32_t Reg2 );
void RunFunction( usf_state_t *, uint32_t address );
extern void (* R4300i_Opcode[64])(usf_state_t *);

File diff suppressed because it is too large Load diff

View file

@ -1,206 +0,0 @@
/*
* Project 64 - A Nintendo 64 emulator.
*
* (c) Copyright 2001 zilmar (zilmar@emulation64.com) and
* Jabo (jabo@emulation64.com).
*
* pj64 homepage: www.pj64.net
*
* Permission to use, copy, modify and distribute Project64 in both binary and
* source form, for non-commercial purposes, is hereby granted without fee,
* providing that this license information and copyright notice appear with
* all copies and any derived work.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event shall the authors be held liable for any damages
* arising from the use of this software.
*
* Project64 is freeware for PERSONAL USE only. Commercial users should
* seek permission of the copyright holders first. Commercial use includes
* charging money for Project64 or software derived from Project64.
*
* The copyright holders request that bug fixes and improvements to the code
* should be forwarded to them so if they want them.
*
*/
/************************* OpCode functions *************************/
void r4300i_J ( usf_state_t * );
void r4300i_JAL ( usf_state_t * );
void r4300i_BNE ( usf_state_t * );
void r4300i_BEQ ( usf_state_t * );
void r4300i_BLEZ ( usf_state_t * );
void r4300i_BGTZ ( usf_state_t * );
void r4300i_ADDI ( usf_state_t * );
void r4300i_ADDIU ( usf_state_t * );
void r4300i_SLTI ( usf_state_t * );
void r4300i_SLTIU ( usf_state_t * );
void r4300i_ANDI ( usf_state_t * );
void r4300i_ORI ( usf_state_t * );
void r4300i_XORI ( usf_state_t * );
void r4300i_LUI ( usf_state_t * );
void r4300i_BEQL ( usf_state_t * );
void r4300i_BNEL ( usf_state_t * );
void r4300i_BLEZL ( usf_state_t * );
void r4300i_BGTZL ( usf_state_t * );
void r4300i_DADDIU ( usf_state_t * );
void r4300i_LDL ( usf_state_t * );
void r4300i_LDR ( usf_state_t * );
void r4300i_LB ( usf_state_t * );
void r4300i_LH ( usf_state_t * );
void r4300i_LWL ( usf_state_t * );
void r4300i_LW ( usf_state_t * );
void r4300i_LBU ( usf_state_t * );
void r4300i_LHU ( usf_state_t * );
void r4300i_LWR ( usf_state_t * );
void r4300i_LWU ( usf_state_t * );
void r4300i_SB ( usf_state_t * );
void r4300i_SH ( usf_state_t * );
void r4300i_SWL ( usf_state_t * );
void r4300i_SW ( usf_state_t * );
void r4300i_SDL ( usf_state_t * );
void r4300i_SDR ( usf_state_t * );
void r4300i_SWR ( usf_state_t * );
void r4300i_CACHE ( usf_state_t * );
void r4300i_LL ( usf_state_t * );
void r4300i_LWC1 ( usf_state_t * );
void r4300i_LDC1 ( usf_state_t * );
void r4300i_LD ( usf_state_t * );
void r4300i_SC ( usf_state_t * );
void r4300i_SWC1 ( usf_state_t * );
void r4300i_SDC1 ( usf_state_t * );
void r4300i_SD ( usf_state_t * );
/********************** R4300i OpCodes: Special **********************/
void r4300i_SPECIAL_SLL ( usf_state_t * );
void r4300i_SPECIAL_SRL ( usf_state_t * );
void r4300i_SPECIAL_SRA ( usf_state_t * );
void r4300i_SPECIAL_SLLV ( usf_state_t * );
void r4300i_SPECIAL_SRLV ( usf_state_t * );
void r4300i_SPECIAL_SRAV ( usf_state_t * );
void r4300i_SPECIAL_JR ( usf_state_t * );
void r4300i_SPECIAL_JALR ( usf_state_t * );
void r4300i_SPECIAL_SYSCALL ( usf_state_t * );
void r4300i_SPECIAL_BREAK ( usf_state_t * );
void r4300i_SPECIAL_SYNC ( usf_state_t * );
void r4300i_SPECIAL_MFHI ( usf_state_t * );
void r4300i_SPECIAL_MTHI ( usf_state_t * );
void r4300i_SPECIAL_MFLO ( usf_state_t * );
void r4300i_SPECIAL_MTLO ( usf_state_t * );
void r4300i_SPECIAL_DSLLV ( usf_state_t * );
void r4300i_SPECIAL_DSRLV ( usf_state_t * );
void r4300i_SPECIAL_DSRAV ( usf_state_t * );
void r4300i_SPECIAL_MULT ( usf_state_t * );
void r4300i_SPECIAL_MULTU ( usf_state_t * );
void r4300i_SPECIAL_DIV ( usf_state_t * );
void r4300i_SPECIAL_DIVU ( usf_state_t * );
void r4300i_SPECIAL_DMULT ( usf_state_t * );
void r4300i_SPECIAL_DMULTU ( usf_state_t * );
void r4300i_SPECIAL_DDIV ( usf_state_t * );
void r4300i_SPECIAL_DDIVU ( usf_state_t * );
void r4300i_SPECIAL_ADD ( usf_state_t * );
void r4300i_SPECIAL_ADDU ( usf_state_t * );
void r4300i_SPECIAL_SUB ( usf_state_t * );
void r4300i_SPECIAL_SUBU ( usf_state_t * );
void r4300i_SPECIAL_AND ( usf_state_t * );
void r4300i_SPECIAL_OR ( usf_state_t * );
void r4300i_SPECIAL_XOR ( usf_state_t * );
void r4300i_SPECIAL_NOR ( usf_state_t * );
void r4300i_SPECIAL_SLT ( usf_state_t * );
void r4300i_SPECIAL_SLTU ( usf_state_t * );
void r4300i_SPECIAL_DADD ( usf_state_t * );
void r4300i_SPECIAL_DADDU ( usf_state_t * );
void r4300i_SPECIAL_DSUB ( usf_state_t * );
void r4300i_SPECIAL_DSUBU ( usf_state_t * );
void r4300i_SPECIAL_TEQ ( usf_state_t * );
void r4300i_SPECIAL_DSLL ( usf_state_t * );
void r4300i_SPECIAL_DSRL ( usf_state_t * );
void r4300i_SPECIAL_DSRA ( usf_state_t * );
void r4300i_SPECIAL_DSLL32 ( usf_state_t * );
void r4300i_SPECIAL_DSRL32 ( usf_state_t * );
void r4300i_SPECIAL_DSRA32 ( usf_state_t * );
/********************** R4300i OpCodes: RegImm **********************/
void r4300i_REGIMM_BLTZ ( usf_state_t * );
void r4300i_REGIMM_BGEZ ( usf_state_t * );
void r4300i_REGIMM_BLTZL ( usf_state_t * );
void r4300i_REGIMM_BGEZL ( usf_state_t * );
void r4300i_REGIMM_BLTZAL ( usf_state_t * );
void r4300i_REGIMM_BGEZAL ( usf_state_t * );
/************************** COP0 functions **************************/
void r4300i_COP0_MF ( usf_state_t * );
void r4300i_COP0_MT ( usf_state_t * );
/************************** COP0 CO functions ***********************/
void r4300i_COP0_CO_TLBR ( usf_state_t * );
void r4300i_COP0_CO_TLBWI ( usf_state_t * );
void r4300i_COP0_CO_TLBWR ( usf_state_t * );
void r4300i_COP0_CO_TLBP ( usf_state_t * );
void r4300i_COP0_CO_ERET ( usf_state_t * );
/************************** COP1 functions **************************/
void r4300i_COP1_MF ( usf_state_t * );
void r4300i_COP1_DMF ( usf_state_t * );
void r4300i_COP1_CF ( usf_state_t * );
void r4300i_COP1_MT ( usf_state_t * );
void r4300i_COP1_DMT ( usf_state_t * );
void r4300i_COP1_CT ( usf_state_t * );
/************************* COP1: BC1 functions ***********************/
void r4300i_COP1_BCF ( usf_state_t * );
void r4300i_COP1_BCT ( usf_state_t * );
void r4300i_COP1_BCFL ( usf_state_t * );
void r4300i_COP1_BCTL ( usf_state_t * );
/************************** COP1: S functions ************************/
void r4300i_COP1_S_ADD ( usf_state_t * );
void r4300i_COP1_S_SUB ( usf_state_t * );
void r4300i_COP1_S_MUL ( usf_state_t * );
void r4300i_COP1_S_DIV ( usf_state_t * );
void r4300i_COP1_S_SQRT ( usf_state_t * );
void r4300i_COP1_S_ABS ( usf_state_t * );
void r4300i_COP1_S_MOV ( usf_state_t * );
void r4300i_COP1_S_NEG ( usf_state_t * );
void r4300i_COP1_S_TRUNC_L ( usf_state_t * );
void r4300i_COP1_S_CEIL_L ( usf_state_t * ); //added by Witten
void r4300i_COP1_S_FLOOR_L ( usf_state_t * ); //added by Witten
void r4300i_COP1_S_ROUND_W ( usf_state_t * );
void r4300i_COP1_S_TRUNC_W ( usf_state_t * );
void r4300i_COP1_S_CEIL_W ( usf_state_t * ); //added by Witten
void r4300i_COP1_S_FLOOR_W ( usf_state_t * );
void r4300i_COP1_S_CVT_D ( usf_state_t * );
void r4300i_COP1_S_CVT_W ( usf_state_t * );
void r4300i_COP1_S_CVT_L ( usf_state_t * );
void r4300i_COP1_S_CMP ( usf_state_t * );
/************************** COP1: D functions ************************/
void r4300i_COP1_D_ADD ( usf_state_t * );
void r4300i_COP1_D_SUB ( usf_state_t * );
void r4300i_COP1_D_MUL ( usf_state_t * );
void r4300i_COP1_D_DIV ( usf_state_t * );
void r4300i_COP1_D_SQRT ( usf_state_t * );
void r4300i_COP1_D_ABS ( usf_state_t * );
void r4300i_COP1_D_MOV ( usf_state_t * );
void r4300i_COP1_D_NEG ( usf_state_t * );
void r4300i_COP1_D_TRUNC_L ( usf_state_t * ); //added by Witten
void r4300i_COP1_D_CEIL_L ( usf_state_t * ); //added by Witten
void r4300i_COP1_D_FLOOR_L ( usf_state_t * ); //added by Witten
void r4300i_COP1_D_ROUND_W ( usf_state_t * );
void r4300i_COP1_D_TRUNC_W ( usf_state_t * );
void r4300i_COP1_D_CEIL_W ( usf_state_t * ); //added by Witten
void r4300i_COP1_D_FLOOR_W ( usf_state_t * ); //added by Witten
void r4300i_COP1_D_CVT_S ( usf_state_t * );
void r4300i_COP1_D_CVT_W ( usf_state_t * );
void r4300i_COP1_D_CVT_L ( usf_state_t * );
void r4300i_COP1_D_CMP ( usf_state_t * );
/************************** COP1: W functions ************************/
void r4300i_COP1_W_CVT_S ( usf_state_t * );
void r4300i_COP1_W_CVT_D ( usf_state_t * );
/************************** COP1: L functions ************************/
void r4300i_COP1_L_CVT_S ( usf_state_t * );
void r4300i_COP1_L_CVT_D ( usf_state_t * );
/************************** Other functions **************************/
void R4300i_UnknownOpcode ( usf_state_t * );

View file

@ -1,37 +0,0 @@
#include <stdint.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "usf.h"
#include "cpu.h"
#include "memory.h"
#include "usf_internal.h"
void StopEmulation(usf_state_t * state)
{
//asm("int $3");
//printf("Arrivederci!\n\n");
//Release_Memory();
//exit(0);
state->cpu_running = 0;
}
void DisplayError (usf_state_t * state, char * Message, ...) {
va_list ap;
size_t len = strlen( state->error_message );
if ( len )
state->error_message[ len++ ] = '\n';
va_start( ap, Message );
vsprintf( state->error_message + len, Message, ap );
va_end( ap );
state->last_error = state->error_message;
StopEmulation( state );
//printf("Error: %s\n", Msg);
}

View file

@ -1,6 +0,0 @@
#include <stdint.h>
#include "usf.h"
void DisplayError (usf_state_t *, char * Message, ...);
void StopEmulation(usf_state_t *);

View file

@ -0,0 +1,127 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - util.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2012 Mupen64plus development 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., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef __LIST_H__
#define __LIST_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include "osal/preproc.h"
struct list_head {
struct list_head *prev;
struct list_head *next;
};
#define LIST_HEAD(list) \
struct list_head list = { &(list), &(list) }
static osal_inline void INIT_LIST_HEAD(struct list_head *head)
{
head->next = head;
head->prev = head;
}
static osal_inline void list_add(struct list_head *new_item, struct list_head *head)
{
struct list_head *next = head->next;
next->prev = new_item;
new_item->next = next;
new_item->prev = head;
head->next = new_item;
}
static osal_inline void list_add_tail(struct list_head *new_item, struct list_head *head)
{
struct list_head *prev = head->prev;
prev->next = new_item;
new_item->next = head;
new_item->prev = prev;
head->prev = new_item;
}
static osal_inline void list_del(struct list_head *entry)
{
struct list_head *next = entry->next;
struct list_head *prev = entry->prev;
next->prev = prev;
prev->next = next;
}
static osal_inline void list_del_init(struct list_head *entry)
{
list_del(entry);
INIT_LIST_HEAD(entry);
}
static osal_inline int list_empty(const struct list_head *head)
{
return (head->next == head);
}
#ifdef __GNUC__
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#else
#define container_of(ptr, type, member) \
((type *)((char *)(ptr) - offsetof(type, member)))
#endif
#define list_entry(ptr, type, member) container_of(ptr, type, member)
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#define list_for_each_entry_t(pos, head, type, member) \
for (pos = list_entry((head)->next, type, member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, type, member))
#define list_for_each_safe(pos, safe, head) \
for (pos = (head)->next, safe = pos->next; pos != (head); \
pos = safe, safe = pos->next)
#define list_for_each_entry_safe_t(pos, safe, head, type, member) \
for (pos = list_entry((head)->next, type, member), \
safe = list_entry(pos->member.next, type, member); \
&pos->member != (head); \
pos = safe, \
safe = list_entry(safe->member.next, type, member))
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,185 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - main.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2012 CasualJames *
* Copyright (C) 2008-2009 Richard Goedeken *
* Copyright (C) 2008 Ebenblues Nmn Okaygo Tillin9 *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* This is MUPEN64's main entry point. It contains code that is common
* to both the gui and non-gui versions of mupen64. See
* gui subdirectories for the gui-specific code.
* if you want to implement an interface, you should look here
*/
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include "usf/usf.h"
#include "usf/usf_internal.h"
#define M64P_CORE_PROTOTYPES 1
#include "api/m64p_types.h"
#include "api/callbacks.h"
#include "main.h"
#include "rom.h"
#include "savestates.h"
#include "util.h"
#include "ai/ai_controller.h"
#include "memory/memory.h"
#include "pi/pi_controller.h"
#include "r4300/r4300.h"
#include "r4300/r4300_core.h"
#include "r4300/interupt.h"
#include "r4300/reset.h"
#include "rdp/rdp_core.h"
#include "ri/ri_controller.h"
#include "rsp/rsp_core.h"
#include "si/si_controller.h"
#include "vi/vi_controller.h"
/* version number for Core config section */
#define CONFIG_PARAM_VERSION 1.01
/*********************************************************************************************************
* helper functions
*/
void main_message(usf_state_t * state, m64p_msg_level level, unsigned int corner, const char *format, ...)
{
va_list ap;
char buffer[2049];
va_start(ap, format);
vsnprintf(buffer, 2047, format, ap);
buffer[2048]='\0';
va_end(ap);
/* send message to front-end */
DebugMessage(state, level, "%s", buffer);
}
/*********************************************************************************************************
* global functions, for adjusting the core emulator behavior
*/
m64p_error main_reset(usf_state_t * state, int do_hard_reset)
{
if (do_hard_reset)
state->reset_hard_job |= 1;
else
reset_soft(state);
return M64ERR_SUCCESS;
}
/*********************************************************************************************************
* global functions, callbacks from the r4300 core or from other plugins
*/
/* called on vertical interrupt.
* Allow the core to perform various things */
static void connect_all(
usf_state_t* state,
struct r4300_core* r4300,
struct rdp_core* dp,
struct rsp_core* sp,
struct ai_controller* ai,
struct pi_controller* pi,
struct ri_controller* ri,
struct si_controller* si,
struct vi_controller* vi,
uint32_t* dram,
size_t dram_size,
uint8_t* rom,
size_t rom_size)
{
connect_r4300(r4300, state);
connect_rdp(dp, r4300, sp, ri);
connect_rsp(sp, r4300, dp, ri);
connect_ai(ai, r4300, ri, vi);
connect_pi(pi, r4300, ri, rom, rom_size);
connect_ri(ri, dram, dram_size);
connect_si(si, r4300, ri);
connect_vi(vi, r4300);
}
/*********************************************************************************************************
* emulation thread - runs the core
*/
m64p_error main_start(usf_state_t * state)
{
unsigned int RDRAMSize;
unsigned int disable_extra_mem;
memcpy(&RDRAMSize, state->save_state + 4, 4);
to_little_endian_buffer(&RDRAMSize, 4, 1);
/* take the r4300 emulator mode from the config file at this point and cache it in a global variable */
#ifdef DEBUG_INFO
state->r4300emu = 0;
#else
state->r4300emu = state->enable_trimming_mode ? 1 : 2;
#endif
/* set some other core parameters based on the config file values */
state->no_compiled_jump = 0;
//state->g_delay_si = 1;
state->g_delay_sp = 1;
disable_extra_mem = RDRAMSize == 0x400000;
state->count_per_op = COUNT_PER_OP_DEFAULT;
if (state->count_per_op <= 0)
state->count_per_op = state->ROM_PARAMS.countperop;
connect_all(state, &state->g_r4300, &state->g_dp, &state->g_sp,
&state->g_ai, &state->g_pi, &state->g_ri, &state->g_si, &state->g_vi,
state->g_rdram, (disable_extra_mem == 0) ? 0x800000 : 0x400000,
state->g_rom, state->g_rom_size);
init_memory(state, (disable_extra_mem == 0) ? 0x800000 : 0x400000);
/* connect external audio sink to AI component */
state->g_ai.user_data = state;
state->g_ai.set_audio_format = usf_set_audio_format;
state->g_ai.push_audio_samples = usf_push_audio_samples;
/* call r4300 CPU core and run the game */
r4300_reset_hard(state);
r4300_reset_soft(state);
r4300_begin(state);
if (!savestates_load(state, state->save_state, state->save_state_size, 0))
return M64ERR_INVALID_STATE;
if (state->enableFIFOfull)
{
state->g_delay_ai = 1;
ai_fifo_queue_int(&state->g_ai);
state->g_ai.regs[AI_STATUS_REG] |= 0x40000000;
}
return M64ERR_SUCCESS;
}
void main_run(usf_state_t * state)
{
r4300_execute(state);
}

View file

@ -0,0 +1,48 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - main.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2012 CasualJames *
* Copyright (C) 2002 Blight *
* *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef __MAIN_H__
#define __MAIN_H__
#include "api/m64p_types.h"
#include <stdint.h>
struct r4300_core;
struct rdp_core;
struct rsp_core;
struct ai_controller;
struct pi_controller;
struct ri_controller;
struct si_controller;
struct vi_controller;
enum { RDRAM_MAX_SIZE = 0x800000 };
/* globals */
void main_message(usf_state_t *, m64p_msg_level level, unsigned int osd_corner, const char *format, ...);
m64p_error main_start(usf_state_t *);
void main_run(usf_state_t *);
#endif /* __MAIN_H__ */

View file

@ -0,0 +1,133 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - rom.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2008 Tillin9 *
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stddef.h>
#include "usf/usf.h"
#include "usf/usf_internal.h"
#define M64P_CORE_PROTOTYPES 1
#include "api/m64p_types.h"
#include "api/callbacks.h"
#include "rom.h"
#include "main.h"
#include "util.h"
#include "memory/memory.h"
#include "r4300/r4300.h"
#define DEFAULT 16
#define CHUNKSIZE 1024*128 /* Read files 128KB at a time. */
static m64p_system_type rom_country_code_to_system_type(unsigned short country_code);
static int rom_system_type_to_ai_dac_rate(m64p_system_type system_type);
static int rom_system_type_to_vi_limit(m64p_system_type system_type);
m64p_error open_rom(usf_state_t * state)
{
if (state->g_rom_size >= sizeof(m64p_rom_header))
memcpy(&state->ROM_HEADER, state->g_rom, sizeof(m64p_rom_header));
/* add some useful properties to ROM_PARAMS */
state->ROM_PARAMS.systemtype = SYSTEM_NTSC /*rom_country_code_to_system_type(ROM_HEADER.Country_code)*/;
state->ROM_PARAMS.vilimit = rom_system_type_to_vi_limit(state->ROM_PARAMS.systemtype);
state->ROM_PARAMS.aidacrate = rom_system_type_to_ai_dac_rate(state->ROM_PARAMS.systemtype);
state->ROM_PARAMS.countperop = COUNT_PER_OP_DEFAULT;
return M64ERR_SUCCESS;
}
m64p_error close_rom(usf_state_t * state)
{
free(state->g_rom);
state->g_rom = NULL;
DebugMessage(state, M64MSG_STATUS, "Rom closed.");
return M64ERR_SUCCESS;
}
/********************************************************************************************/
/* ROM utility functions */
// Get the system type associated to a ROM country code.
static m64p_system_type rom_country_code_to_system_type(unsigned short country_code)
{
switch (country_code & 0xFF)
{
// PAL codes
case 0x44:
case 0x46:
case 0x49:
case 0x50:
case 0x53:
case 0x55:
case 0x58:
case 0x59:
return SYSTEM_PAL;
// NTSC codes
case 0x37:
case 0x41:
case 0x45:
case 0x4a:
default: // Fallback for unknown codes
return SYSTEM_NTSC;
}
}
// Get the VI (vertical interrupt) limit associated to a ROM system type.
static int rom_system_type_to_vi_limit(m64p_system_type system_type)
{
switch (system_type)
{
case SYSTEM_PAL:
case SYSTEM_MPAL:
return 50;
case SYSTEM_NTSC:
default:
return 60;
}
}
static int rom_system_type_to_ai_dac_rate(m64p_system_type system_type)
{
switch (system_type)
{
case SYSTEM_PAL:
return 49656530;
case SYSTEM_MPAL:
return 48628316;
case SYSTEM_NTSC:
default:
return 48681812;
}
}

View file

@ -0,0 +1,92 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - rom.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2008 Tillin9 *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef __ROM_H__
#define __ROM_H__
#include "api/m64p_types.h"
#include <stdint.h>
#define BIT(bitnr) (1ULL << (bitnr))
#ifdef __GNUC__
#define isset_bitmask(x, bitmask) ({ typeof(bitmask) _bitmask = (bitmask); \
(_bitmask & (x)) == _bitmask; })
#else
#define isset_bitmask(x, bitmask) ((bitmask & (x)) == bitmask)
#endif
/* ROM Loading and Saving functions */
m64p_error open_rom(usf_state_t *);
m64p_error close_rom(usf_state_t *);
typedef struct _rom_params
{
m64p_system_type systemtype;
int vilimit;
int aidacrate;
char headername[21]; /* ROM Name as in the header, removing trailing whitespace */
unsigned char countperop;
} rom_params;
/* Supported rom compressiontypes. */
enum
{
UNCOMPRESSED,
ZIP_COMPRESSION,
GZIP_COMPRESSION,
BZIP2_COMPRESSION,
LZMA_COMPRESSION,
SZIP_COMPRESSION
};
/* Supported rom image types. */
enum
{
Z64IMAGE,
V64IMAGE,
N64IMAGE
};
/* Supported CIC chips. */
enum
{
CIC_NUS_6101,
CIC_NUS_6102,
CIC_NUS_6103,
CIC_NUS_6105,
CIC_NUS_6106
};
/* Supported save types. */
enum
{
EEPROM_4KB,
EEPROM_16KB,
SRAM,
FLASH_RAM,
CONTROLLER_PACK,
NONE
};
#endif /* __ROM_H__ */

View file

@ -0,0 +1,639 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - savestates.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2012 CasualJames *
* Copyright (C) 2009 Olejl Tillin9 *
* Copyright (C) 2008 Richard42 Tillin9 *
* 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 <stdlib.h>
#include <string.h>
#include "usf/usf.h"
#include "usf/usf_internal.h"
#define M64P_CORE_PROTOTYPES 1
#include "api/m64p_types.h"
#include "api/callbacks.h"
#include "savestates.h"
#include "main.h"
#include "rom.h"
#include "util.h"
#include "ai/ai_controller.h"
#include "memory/memory.h"
#include "r4300/tlb.h"
#include "r4300/cp0.h"
#include "r4300/cp1.h"
#include "r4300/r4300.h"
#include "r4300/r4300_core.h"
#include "r4300/cached_interp.h"
#include "r4300/interupt.h"
#include "pi/pi_controller.h"
#ifdef NEW_DYNAREC
#include "r4300/new_dynarec/new_dynarec.h"
#endif
#include "rdp/rdp_core.h"
#include "ri/ri_controller.h"
#include "rsp/rsp_core.h"
#include "si/si_controller.h"
#include "vi/vi_controller.h"
static const char* savestate_magic = "M64+SAVE";
static const int savestate_latest_version = 0x00010000; /* 1.0 */
static const unsigned char pj64_magic[4] = { 0xC8, 0xA6, 0xD8, 0x23 };
#define GETARRAY(buff, type, count) \
(to_little_endian_buffer(buff, sizeof(type),count), \
buff += count*sizeof(type), \
(type *)(buff-count*sizeof(type)))
#define COPYARRAY(dst, buff, type, count) \
memcpy(dst, GETARRAY(buff, type, count), sizeof(type)*count)
#define GETDATA(buff, type) *GETARRAY(buff, type, 1)
#define PUTARRAY(src, buff, type, count) \
memcpy(buff, src, sizeof(type)*count); \
to_little_endian_buffer(buff, sizeof(type), count); \
buff += count*sizeof(type);
#define PUTDATA(buff, type, value) \
do { type x = value; PUTARRAY(&x, buff, type, 1); } while(0)
#define read_bytes(ptr, size) \
{ \
if ((size) > state_size) \
{ \
if (savestateData) free(savestateData); \
return 0; \
} \
memcpy((ptr), state_ptr, (size)); \
state_ptr += (size); \
state_size -= (size); \
}
static int savestates_load_m64p(usf_state_t * state, unsigned char * ptr, unsigned int size)
{
unsigned char header[44];
int version;
int i;
unsigned char * state_ptr = ptr;
unsigned int state_size = size;
size_t savestateSize;
unsigned char *savestateData = 0, *curr;
char queue[1024];
/* Read and check Mupen64Plus magic number. */
read_bytes(header, 44);
curr = header;
if(strncmp((char *)curr, savestate_magic, 8)!=0)
return 0;
curr += 8;
version = *curr++;
version = (version << 8) | *curr++;
version = (version << 8) | *curr++;
version = (version << 8) | *curr++;
if(version != 0x00010000)
return 0;
/* skip MD5 */
curr += 32;
/* Read the rest of the savestate */
savestateSize = 16788244;
if (state_size < savestateSize + sizeof(queue))
return 0;
savestateData = curr = malloc(savestateSize);
if (!savestateData)
return 0;
read_bytes(savestateData, savestateSize);
read_bytes(queue, sizeof(queue));
// Parse savestate
state->g_ri.rdram.regs[RDRAM_CONFIG_REG] = GETDATA(curr, uint32_t);
state->g_ri.rdram.regs[RDRAM_DEVICE_ID_REG] = GETDATA(curr, uint32_t);
state->g_ri.rdram.regs[RDRAM_DELAY_REG] = GETDATA(curr, uint32_t);
state->g_ri.rdram.regs[RDRAM_MODE_REG] = GETDATA(curr, uint32_t);
state->g_ri.rdram.regs[RDRAM_REF_INTERVAL_REG] = GETDATA(curr, uint32_t);
state->g_ri.rdram.regs[RDRAM_REF_ROW_REG] = GETDATA(curr, uint32_t);
state->g_ri.rdram.regs[RDRAM_RAS_INTERVAL_REG] = GETDATA(curr, uint32_t);
state->g_ri.rdram.regs[RDRAM_MIN_INTERVAL_REG] = GETDATA(curr, uint32_t);
state->g_ri.rdram.regs[RDRAM_ADDR_SELECT_REG] = GETDATA(curr, uint32_t);
state->g_ri.rdram.regs[RDRAM_DEVICE_MANUF_REG] = GETDATA(curr, uint32_t);
curr += 4; /* Padding from old implementation */
state->g_r4300.mi.regs[MI_INIT_MODE_REG] = GETDATA(curr, uint32_t);
curr += 4; // Duplicate MI init mode flags from old implementation
state->g_r4300.mi.regs[MI_VERSION_REG] = GETDATA(curr, uint32_t);
state->g_r4300.mi.regs[MI_INTR_REG] = GETDATA(curr, uint32_t);
state->g_r4300.mi.regs[MI_INTR_MASK_REG] = GETDATA(curr, uint32_t);
curr += 4; /* Padding from old implementation */
curr += 8; // Duplicated MI intr flags and padding from old implementation
state->g_pi.regs[PI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_CART_ADDR_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_RD_LEN_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_WR_LEN_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_STATUS_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_BSD_DOM1_LAT_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_BSD_DOM1_PWD_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_BSD_DOM1_PGS_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_BSD_DOM1_RLS_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_BSD_DOM2_LAT_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_BSD_DOM2_PWD_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_BSD_DOM2_PGS_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_BSD_DOM2_RLS_REG] = GETDATA(curr, uint32_t);
state->g_sp.regs[SP_MEM_ADDR_REG] = GETDATA(curr, uint32_t);
state->g_sp.regs[SP_DRAM_ADDR_REG] = GETDATA(curr, uint32_t);
state->g_sp.regs[SP_RD_LEN_REG] = GETDATA(curr, uint32_t);
state->g_sp.regs[SP_WR_LEN_REG] = GETDATA(curr, uint32_t);
curr += 4; /* Padding from old implementation */
state->g_sp.regs[SP_STATUS_REG] = GETDATA(curr, uint32_t);
curr += 16; // Duplicated SP flags and padding from old implementation
state->g_sp.regs[SP_DMA_FULL_REG] = GETDATA(curr, uint32_t);
state->g_sp.regs[SP_DMA_BUSY_REG] = GETDATA(curr, uint32_t);
state->g_sp.regs[SP_SEMAPHORE_REG] = GETDATA(curr, uint32_t);
state->g_sp.regs2[SP_PC_REG] = GETDATA(curr, uint32_t);
state->g_sp.regs2[SP_IBIST_REG] = GETDATA(curr, uint32_t);
state->g_si.regs[SI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t);
state->g_si.regs[SI_PIF_ADDR_RD64B_REG] = GETDATA(curr, uint32_t);
state->g_si.regs[SI_PIF_ADDR_WR64B_REG] = GETDATA(curr, uint32_t);
state->g_si.regs[SI_STATUS_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_STATUS_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_ORIGIN_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_WIDTH_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_V_INTR_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_CURRENT_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_BURST_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_V_SYNC_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_H_SYNC_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_LEAP_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_H_START_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_V_START_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_V_BURST_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_X_SCALE_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_Y_SCALE_REG] = GETDATA(curr, uint32_t);
state->g_vi.delay = GETDATA(curr, unsigned int);
state->g_ri.regs[RI_MODE_REG] = GETDATA(curr, uint32_t);
state->g_ri.regs[RI_CONFIG_REG] = GETDATA(curr, uint32_t);
state->g_ri.regs[RI_CURRENT_LOAD_REG] = GETDATA(curr, uint32_t);
state->g_ri.regs[RI_SELECT_REG] = GETDATA(curr, uint32_t);
state->g_ri.regs[RI_REFRESH_REG] = GETDATA(curr, uint32_t);
state->g_ri.regs[RI_LATENCY_REG] = GETDATA(curr, uint32_t);
state->g_ri.regs[RI_ERROR_REG] = GETDATA(curr, uint32_t);
state->g_ri.regs[RI_WERROR_REG] = GETDATA(curr, uint32_t);
state->g_ai.regs[AI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t);
state->g_ai.regs[AI_LEN_REG] = GETDATA(curr, uint32_t);
state->g_ai.regs[AI_CONTROL_REG] = GETDATA(curr, uint32_t);
state->g_ai.regs[AI_STATUS_REG] = GETDATA(curr, uint32_t);
state->g_ai.regs[AI_DACRATE_REG] = GETDATA(curr, uint32_t);
state->g_ai.regs[AI_BITRATE_REG] = GETDATA(curr, uint32_t);
state->g_ai.fifo[1].duration = GETDATA(curr, unsigned int);
state->g_ai.fifo[1].length = GETDATA(curr, uint32_t);
state->g_ai.fifo[0].duration = GETDATA(curr, unsigned int);
state->g_ai.fifo[0].length = GETDATA(curr, uint32_t);
/* best effort initialization of fifo addresses...
* You might get a small sound "pop" because address might be wrong.
* Proper initialization requires changes to savestate format
*/
state->g_ai.fifo[0].address = state->g_ai.regs[AI_DRAM_ADDR_REG];
state->g_ai.fifo[1].address = state->g_ai.regs[AI_DRAM_ADDR_REG];
state->g_ai.samples_format_changed = 1;
state->g_dp.dpc_regs[DPC_START_REG] = GETDATA(curr, uint32_t);
state->g_dp.dpc_regs[DPC_END_REG] = GETDATA(curr, uint32_t);
state->g_dp.dpc_regs[DPC_CURRENT_REG] = GETDATA(curr, uint32_t);
curr += 4; // Padding from old implementation
state->g_dp.dpc_regs[DPC_STATUS_REG] = GETDATA(curr, uint32_t);
curr += 12; // Duplicated DPC flags and padding from old implementation
state->g_dp.dpc_regs[DPC_CLOCK_REG] = GETDATA(curr, uint32_t);
state->g_dp.dpc_regs[DPC_BUFBUSY_REG] = GETDATA(curr, uint32_t);
state->g_dp.dpc_regs[DPC_PIPEBUSY_REG] = GETDATA(curr, uint32_t);
state->g_dp.dpc_regs[DPC_TMEM_REG] = GETDATA(curr, uint32_t);
state->g_dp.dps_regs[DPS_TBIST_REG] = GETDATA(curr, uint32_t);
state->g_dp.dps_regs[DPS_TEST_MODE_REG] = GETDATA(curr, uint32_t);
state->g_dp.dps_regs[DPS_BUFTEST_ADDR_REG] = GETDATA(curr, uint32_t);
state->g_dp.dps_regs[DPS_BUFTEST_DATA_REG] = GETDATA(curr, uint32_t);
COPYARRAY(state->g_rdram, curr, uint32_t, RDRAM_MAX_SIZE/4);
COPYARRAY(state->g_sp.mem, curr, uint32_t, SP_MEM_SIZE/4);
COPYARRAY(state->g_si.pif.ram, curr, uint8_t, PIF_RAM_SIZE);
/*state->g_pi.use_flashram =*/ (void)GETDATA(curr, int);
/*state->g_pi.flashram.mode =*/ (void)GETDATA(curr, int);
/*state->g_pi.flashram.status =*/ (void)GETDATA(curr, unsigned long long);
/*state->g_pi.flashram.erase_offset =*/ (void)GETDATA(curr, unsigned int);
/*state->g_pi.flashram.write_pointer =*/ (void)GETDATA(curr, unsigned int);
COPYARRAY(state->tlb_LUT_r, curr, unsigned int, 0x100000);
COPYARRAY(state->tlb_LUT_w, curr, unsigned int, 0x100000);
state->llbit = GETDATA(curr, unsigned int);
COPYARRAY(state->reg, curr, long long int, 32);
COPYARRAY(state->g_cp0_regs, curr, unsigned int, CP0_REGS_COUNT);
set_fpr_pointers(state, state->g_cp0_regs[CP0_STATUS_REG]);
state->lo = GETDATA(curr, long long int);
state->hi = GETDATA(curr, long long int);
COPYARRAY(state->reg_cop1_fgr_64, curr, long long int, 32);
if ((state->g_cp0_regs[CP0_STATUS_REG] & 0x04000000) == 0) // 32-bit FPR mode requires data shuffling because 64-bit layout is always stored in savestate file
shuffle_fpr_data(state, 0x04000000, 0);
state->FCR0 = GETDATA(curr, int);
state->FCR31 = GETDATA(curr, int);
for (i = 0; i < 32; i++)
{
state->tlb_e[i].mask = GETDATA(curr, short);
curr += 2;
state->tlb_e[i].vpn2 = GETDATA(curr, int);
state->tlb_e[i].g = GETDATA(curr, char);
state->tlb_e[i].asid = GETDATA(curr, unsigned char);
curr += 2;
state->tlb_e[i].pfn_even = GETDATA(curr, int);
state->tlb_e[i].c_even = GETDATA(curr, char);
state->tlb_e[i].d_even = GETDATA(curr, char);
state->tlb_e[i].v_even = GETDATA(curr, char);
curr++;
state->tlb_e[i].pfn_odd = GETDATA(curr, int);
state->tlb_e[i].c_odd = GETDATA(curr, char);
state->tlb_e[i].d_odd = GETDATA(curr, char);
state->tlb_e[i].v_odd = GETDATA(curr, char);
state->tlb_e[i].r = GETDATA(curr, char);
state->tlb_e[i].start_even = GETDATA(curr, unsigned int);
state->tlb_e[i].end_even = GETDATA(curr, unsigned int);
state->tlb_e[i].phys_even = GETDATA(curr, unsigned int);
state->tlb_e[i].start_odd = GETDATA(curr, unsigned int);
state->tlb_e[i].end_odd = GETDATA(curr, unsigned int);
state->tlb_e[i].phys_odd = GETDATA(curr, unsigned int);
}
#ifdef NEW_DYNAREC
if (state->r4300emu == CORE_DYNAREC) {
state->pcaddr = GETDATA(curr, unsigned int);
state->pending_exception = 1;
invalidate_all_pages(state);
} else {
if(state->r4300emu != CORE_PURE_INTERPRETER)
{
for (i = 0; i < 0x100000; i++)
state->invalid_code[i] = 1;
}
generic_jump_to(state, GETDATA(curr, unsigned int)); // PC
}
#else
if(state->r4300emu != CORE_PURE_INTERPRETER)
{
for (i = 0; i < 0x100000; i++)
state->invalid_code[i] = 1;
}
generic_jump_to(state, GETDATA(curr, unsigned int)); // PC
#endif
state->next_interupt = GETDATA(curr, unsigned int);
state->g_vi.next_vi = GETDATA(curr, unsigned int);
state->g_vi.field = GETDATA(curr, unsigned int);
free(savestateData);
// assert(savestateData+savestateSize == curr)
to_little_endian_buffer(queue, 4, 256);
load_eventqueue_infos(state, queue);
#ifdef NEW_DYNAREC
if (state->r4300emu == CORE_DYNAREC)
state->last_addr = state->pcaddr;
else
state->last_addr = state->PC->addr;
#else
state->last_addr = state->PC->addr;
#endif
return 1;
}
static int savestates_load_pj64(usf_state_t * state, unsigned char * ptr, unsigned int size)
{
char buffer[1024];
unsigned int vi_timer, SaveRDRAMSize;
int i;
#ifdef DYNAREC
unsigned long long dummy;
#endif
unsigned char header[8];
unsigned char * state_ptr = ptr;
unsigned int state_size = size;
size_t savestateSize;
unsigned char *savestateData = 0, *curr;
/* Read and check Project64 magic number. */
read_bytes(header, 8);
curr = header;
if (memcmp(curr, pj64_magic, 4) != 0)
{
return 0;
}
curr += 4;
SaveRDRAMSize = GETDATA(curr, unsigned int);
/* Read the rest of the savestate into memory. */
savestateSize = SaveRDRAMSize + 0x2754;
savestateData = curr = malloc(savestateSize);
if (!savestateData)
return 0;
if (state_size < savestateSize)
{
free(savestateData);
return 0;
}
read_bytes(savestateData, savestateSize);
// skip ROM header
curr += 0x40;
// vi_timer
vi_timer = GETDATA(curr, unsigned int);
// Program Counter
state->last_addr = GETDATA(curr, unsigned int);
// GPR
COPYARRAY(state->reg, curr, long long int, 32);
// FPR
COPYARRAY(state->reg_cop1_fgr_64, curr, long long int, 32);
// CP0
COPYARRAY(state->g_cp0_regs, curr, unsigned int, CP0_REGS_COUNT);
set_fpr_pointers(state, state->g_cp0_regs[CP0_STATUS_REG]);
if ((state->g_cp0_regs[CP0_STATUS_REG] & 0x04000000) == 0) // TODO not sure how pj64 handles this
shuffle_fpr_data(state, 0x04000000, 0);
// Initialze the interupts
vi_timer += state->g_cp0_regs[CP0_COUNT_REG];
state->next_interupt = (state->g_cp0_regs[CP0_COMPARE_REG] < vi_timer)
? state->g_cp0_regs[CP0_COMPARE_REG]
: vi_timer;
state->g_vi.next_vi = vi_timer;
state->g_vi.field = 0;
*((unsigned int*)&buffer[0]) = VI_INT;
*((unsigned int*)&buffer[4]) = vi_timer;
*((unsigned int*)&buffer[8]) = COMPARE_INT;
*((unsigned int*)&buffer[12]) = state->g_cp0_regs[CP0_COMPARE_REG];
*((unsigned int*)&buffer[16]) = 0xFFFFFFFF;
load_eventqueue_infos(state, buffer);
// FPCR
state->FCR0 = GETDATA(curr, int);
curr += 30 * 4; // FCR1...FCR30 not supported
state->FCR31 = GETDATA(curr, int);
// hi / lo
state->hi = GETDATA(curr, long long int);
state->lo = GETDATA(curr, long long int);
// rdram register
state->g_ri.rdram.regs[RDRAM_CONFIG_REG] = GETDATA(curr, uint32_t);
state->g_ri.rdram.regs[RDRAM_DEVICE_ID_REG] = GETDATA(curr, uint32_t);
state->g_ri.rdram.regs[RDRAM_DELAY_REG] = GETDATA(curr, uint32_t);
state->g_ri.rdram.regs[RDRAM_MODE_REG] = GETDATA(curr, uint32_t);
state->g_ri.rdram.regs[RDRAM_REF_INTERVAL_REG] = GETDATA(curr, uint32_t);
state->g_ri.rdram.regs[RDRAM_REF_ROW_REG] = GETDATA(curr, uint32_t);
state->g_ri.rdram.regs[RDRAM_RAS_INTERVAL_REG] = GETDATA(curr, uint32_t);
state->g_ri.rdram.regs[RDRAM_MIN_INTERVAL_REG] = GETDATA(curr, uint32_t);
state->g_ri.rdram.regs[RDRAM_ADDR_SELECT_REG] = GETDATA(curr, uint32_t);
state->g_ri.rdram.regs[RDRAM_DEVICE_MANUF_REG] = GETDATA(curr, uint32_t);
// sp_register
state->g_sp.regs[SP_MEM_ADDR_REG] = GETDATA(curr, uint32_t);
state->g_sp.regs[SP_DRAM_ADDR_REG] = GETDATA(curr, uint32_t);
state->g_sp.regs[SP_RD_LEN_REG] = GETDATA(curr, uint32_t);
state->g_sp.regs[SP_WR_LEN_REG] = GETDATA(curr, uint32_t);
state->g_sp.regs[SP_STATUS_REG] = GETDATA(curr, uint32_t);
state->g_sp.regs[SP_DMA_FULL_REG] = GETDATA(curr, uint32_t);
state->g_sp.regs[SP_DMA_BUSY_REG] = GETDATA(curr, uint32_t);
state->g_sp.regs[SP_SEMAPHORE_REG] = GETDATA(curr, uint32_t);
state->g_sp.regs2[SP_PC_REG] = GETDATA(curr, uint32_t);
state->g_sp.regs2[SP_IBIST_REG] = GETDATA(curr, uint32_t);
// dpc_register
state->g_dp.dpc_regs[DPC_START_REG] = GETDATA(curr, uint32_t);
state->g_dp.dpc_regs[DPC_END_REG] = GETDATA(curr, uint32_t);
state->g_dp.dpc_regs[DPC_CURRENT_REG] = GETDATA(curr, uint32_t);
state->g_dp.dpc_regs[DPC_STATUS_REG] = GETDATA(curr, uint32_t);
state->g_dp.dpc_regs[DPC_CLOCK_REG] = GETDATA(curr, uint32_t);
state->g_dp.dpc_regs[DPC_BUFBUSY_REG] = GETDATA(curr, uint32_t);
state->g_dp.dpc_regs[DPC_PIPEBUSY_REG] = GETDATA(curr, uint32_t);
state->g_dp.dpc_regs[DPC_TMEM_REG] = GETDATA(curr, uint32_t);
(void)GETDATA(curr, unsigned int); // Dummy read
(void)GETDATA(curr, unsigned int); // Dummy read
// mi_register
state->g_r4300.mi.regs[MI_INIT_MODE_REG] = GETDATA(curr, uint32_t);
state->g_r4300.mi.regs[MI_VERSION_REG] = GETDATA(curr, uint32_t);
state->g_r4300.mi.regs[MI_INTR_REG] = GETDATA(curr, uint32_t);
state->g_r4300.mi.regs[MI_INTR_MASK_REG] = GETDATA(curr, uint32_t);
// vi_register
state->g_vi.regs[VI_STATUS_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_ORIGIN_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_WIDTH_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_V_INTR_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_CURRENT_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_BURST_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_V_SYNC_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_H_SYNC_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_LEAP_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_H_START_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_V_START_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_V_BURST_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_X_SCALE_REG] = GETDATA(curr, uint32_t);
state->g_vi.regs[VI_Y_SCALE_REG] = GETDATA(curr, uint32_t);
state->g_vi.delay = (state->g_vi.regs[VI_V_SYNC_REG] == 0)
? 500000
: (state->g_vi.regs[VI_V_SYNC_REG] + 1)*1500;
// ai_register
state->g_ai.regs[AI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t);
state->g_ai.regs[AI_LEN_REG] = GETDATA(curr, uint32_t);
state->g_ai.regs[AI_CONTROL_REG] = GETDATA(curr, uint32_t);
state->g_ai.regs[AI_STATUS_REG] = GETDATA(curr, uint32_t);
state->g_ai.regs[AI_DACRATE_REG] = GETDATA(curr, uint32_t);
state->g_ai.regs[AI_BITRATE_REG] = GETDATA(curr, uint32_t);
state->g_ai.samples_format_changed = 1;
// XXX USF
state->g_ai.regs[AI_STATUS_REG] = 0;
// pi_register
state->g_pi.regs[PI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_CART_ADDR_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_RD_LEN_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_WR_LEN_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_STATUS_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_BSD_DOM1_LAT_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_BSD_DOM1_PWD_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_BSD_DOM1_PGS_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_BSD_DOM1_RLS_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_BSD_DOM2_LAT_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_BSD_DOM2_PWD_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_BSD_DOM2_PGS_REG] = GETDATA(curr, uint32_t);
state->g_pi.regs[PI_BSD_DOM2_RLS_REG] = GETDATA(curr, uint32_t);
// ri_register
state->g_ri.regs[RI_MODE_REG] = GETDATA(curr, uint32_t);
state->g_ri.regs[RI_CONFIG_REG] = GETDATA(curr, uint32_t);
state->g_ri.regs[RI_CURRENT_LOAD_REG] = GETDATA(curr, uint32_t);
state->g_ri.regs[RI_SELECT_REG] = GETDATA(curr, uint32_t);
state->g_ri.regs[RI_REFRESH_REG] = GETDATA(curr, uint32_t);
state->g_ri.regs[RI_LATENCY_REG] = GETDATA(curr, uint32_t);
state->g_ri.regs[RI_ERROR_REG] = GETDATA(curr, uint32_t);
state->g_ri.regs[RI_WERROR_REG] = GETDATA(curr, uint32_t);
// si_register
state->g_si.regs[SI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t);
state->g_si.regs[SI_PIF_ADDR_RD64B_REG] = GETDATA(curr, uint32_t);
state->g_si.regs[SI_PIF_ADDR_WR64B_REG] = GETDATA(curr, uint32_t);
state->g_si.regs[SI_STATUS_REG] = GETDATA(curr, uint32_t);
// tlb
memset(state->tlb_LUT_r, 0, 0x400000);
memset(state->tlb_LUT_w, 0, 0x400000);
for (i=0; i < 32; i++)
{
unsigned int MyPageMask, MyEntryHi, MyEntryLo0, MyEntryLo1;
(void)GETDATA(curr, unsigned int); // Dummy read - EntryDefined
MyPageMask = GETDATA(curr, unsigned int);
MyEntryHi = GETDATA(curr, unsigned int);
MyEntryLo0 = GETDATA(curr, unsigned int);
MyEntryLo1 = GETDATA(curr, unsigned int);
// This is copied from TLBWI instruction
state->tlb_e[i].g = (MyEntryLo0 & MyEntryLo1 & 1);
state->tlb_e[i].pfn_even = (MyEntryLo0 & 0x3FFFFFC0) >> 6;
state->tlb_e[i].pfn_odd = (MyEntryLo1 & 0x3FFFFFC0) >> 6;
state->tlb_e[i].c_even = (MyEntryLo0 & 0x38) >> 3;
state->tlb_e[i].c_odd = (MyEntryLo1 & 0x38) >> 3;
state->tlb_e[i].d_even = (MyEntryLo0 & 0x4) >> 2;
state->tlb_e[i].d_odd = (MyEntryLo1 & 0x4) >> 2;
state->tlb_e[i].v_even = (MyEntryLo0 & 0x2) >> 1;
state->tlb_e[i].v_odd = (MyEntryLo1 & 0x2) >> 1;
state->tlb_e[i].asid = (MyEntryHi & 0xFF);
state->tlb_e[i].vpn2 = (MyEntryHi & 0xFFFFE000) >> 13;
//state->tlb_e[i].r = (MyEntryHi & 0xC000000000000000LL) >> 62;
state->tlb_e[i].mask = (MyPageMask & 0x1FFE000) >> 13;
state->tlb_e[i].start_even = state->tlb_e[i].vpn2 << 13;
state->tlb_e[i].end_even = state->tlb_e[i].start_even+
(state->tlb_e[i].mask << 12) + 0xFFF;
state->tlb_e[i].phys_even = state->tlb_e[i].pfn_even << 12;
state->tlb_e[i].start_odd = state->tlb_e[i].end_even+1;
state->tlb_e[i].end_odd = state->tlb_e[i].start_odd+
(state->tlb_e[i].mask << 12) + 0xFFF;
state->tlb_e[i].phys_odd = state->tlb_e[i].pfn_odd << 12;
tlb_map(state, &state->tlb_e[i]);
}
// pif ram
COPYARRAY(state->g_si.pif.ram, curr, uint8_t, PIF_RAM_SIZE);
// RDRAM
memset(state->g_rdram, 0, RDRAM_MAX_SIZE);
COPYARRAY(state->g_rdram, curr, uint32_t, SaveRDRAMSize/4);
// DMEM + IMEM
COPYARRAY(state->g_sp.mem, curr, uint32_t, SP_MEM_SIZE/4);
// The following values should not matter because we don't have any AI interrupt
// g_ai.fifo[1].delay = 0; g_ai.fifo[1].length = 0;
// g_ai.fifo[0].delay = 0; g_ai.fifo[0].length = 0;
// The following is not available in PJ64 savestate. Keep the values as is.
// g_dp.dps_regs[DPS_TBIST_REG] = 0; g_dp.dps_regs[DPS_TEST_MODE_REG] = 0;
// g_dp.dps_regs[DPS_BUFTEST_ADDR_REG] = 0; g_dp.dps_regs[DPS_BUFTEST_DATA_REG] = 0; llbit = 0;
// No flashram info in pj64 savestate.
//init_flashram(&state->g_pi.flashram);
#ifdef NEW_DYNAREC
if (state->r4300emu == CORE_DYNAREC) {
state->pcaddr = state->last_addr;
state->pending_exception = 1;
invalidate_all_pages(state);
} else {
if(state->r4300emu != CORE_PURE_INTERPRETER)
{
for (i = 0; i < 0x100000; i++)
state->invalid_code[i] = 1;
}
generic_jump_to(state, state->last_addr);
}
#else
if(state->r4300emu != CORE_PURE_INTERPRETER)
{
for (i = 0; i < 0x100000; i++)
state->invalid_code[i] = 1;
}
#ifdef DYNAREC
*(void **)&state->return_address = (void *)&dummy;
#endif
generic_jump_to(state, state->last_addr);
#ifdef DYNAREC
*(void **)&state->return_address = (void *)0;
#endif
#endif
// assert(savestateData+savestateSize == curr)
free(savestateData);
return 1;
}
int savestates_load(usf_state_t * state, unsigned char * ptr, unsigned int size, unsigned int is_m64p)
{
if (is_m64p)
return savestates_load_m64p(state, ptr, size);
else
return savestates_load_pj64(state, ptr, size);
}

View file

@ -0,0 +1,31 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - savestates.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2012 CasualJames *
* Copyright (C) 2009 Olejl Tillin9 *
* Copyright (C) 2008 Richard42 Tillin9 *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef __SAVESTAVES_H__
#define __SAVESTAVES_H__
int savestates_load(usf_state_t *, unsigned char * ptr, unsigned int size, unsigned int is_m64p);
#endif /* __SAVESTAVES_H__ */

View file

@ -0,0 +1,186 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - util.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2012 CasualJames *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* Provides common utilities to the rest of the code:
* -String functions
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <limits.h>
#include "usf/usf.h"
#include "rom.h"
#include "util.h"
#include "osal/preproc.h"
/**********************
Byte swap utilities
**********************/
void swap_buffer(void *buffer, size_t length, size_t count)
{
size_t i;
if (length == 2)
{
unsigned short *pun = (unsigned short *)buffer;
for (i = 0; i < count; i++)
pun[i] = m64p_swap16(pun[i]);
}
else if (length == 4)
{
unsigned int *pun = (unsigned int *)buffer;
for (i = 0; i < count; i++)
pun[i] = m64p_swap32(pun[i]);
}
else if (length == 8)
{
unsigned long long *pun = (unsigned long long *)buffer;
for (i = 0; i < count; i++)
pun[i] = m64p_swap64(pun[i]);
}
}
void to_little_endian_buffer(void *buffer, size_t length, size_t count)
{
#ifdef M64P_BIG_ENDIAN
swap_buffer(buffer, length, count);
#endif
}
void to_big_endian_buffer(void *buffer, size_t length, size_t count)
{
#ifndef M64P_BIG_ENDIAN
swap_buffer(buffer, length, count);
#endif
}
/**********************
String utilities
**********************/
char *trim(char *str)
{
char *start = str, *end = str + strlen(str);
while (start < end && isspace(*start))
start++;
while (end > start && isspace(*(end-1)))
end--;
memmove(str, start, end - start);
str[end - start] = '\0';
return str;
}
int string_to_int(const char *str, int *result)
{
char *endptr;
long int n;
if (*str == '\0' || isspace(*str))
return 0;
errno = 0;
n = strtol(str, &endptr, 10);
if (*endptr != '\0' || errno != 0 || n < INT_MIN || n > INT_MAX)
return 0;
*result = (int)n;
return 1;
}
static unsigned char char2hex(char c)
{
c = tolower(c);
if(c >= '0' && c <= '9')
return c - '0';
else if(c >= 'a' && c <= 'f')
return c - 'a' + 10;
else
return 0xFF;
}
int parse_hex(const char *str, unsigned char *output, size_t output_size)
{
size_t i, j;
for (i = 0; i < output_size; i++)
{
output[i] = 0;
for (j = 0; j < 2; j++)
{
unsigned char h = char2hex(*str++);
if (h == 0xFF)
return 0;
output[i] = (output[i] << 4) | h;
}
}
if (*str != '\0')
return 0;
return 1;
}
char *formatstr(const char *fmt, ...)
{
int size = 128, ret;
char *str = (char *)malloc(size), *newstr;
va_list args;
/* There are two implementations of vsnprintf we have to deal with:
* C99 version: Returns the number of characters which would have been written
* if the buffer had been large enough, and -1 on failure.
* Windows version: Returns the number of characters actually written,
* and -1 on failure or truncation.
* NOTE: An implementation equivalent to the Windows one appears in glibc <2.1.
*/
while (str != NULL)
{
va_start(args, fmt);
ret = vsnprintf(str, size, fmt, args);
va_end(args);
// Successful result?
if (ret >= 0 && ret < size)
return str;
// Increment the capacity of the buffer
if (ret >= size)
size = ret + 1; // C99 version: We got the needed buffer size
else
size *= 2; // Windows version: Keep guessing
newstr = (char *)realloc(str, size);
if (newstr == NULL)
free(str);
str = newstr;
}
return NULL;
}

View file

@ -0,0 +1,213 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - util.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2012 CasualJames *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef __UTIL_H__
#define __UTIL_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <string.h>
#include "osal/preproc.h"
/**********************
File utilities
**********************/
typedef enum _file_status
{
file_ok,
file_open_error,
file_read_error,
file_write_error
} file_status_t;
/** read_from_file
* opens a file and reads the specified number of bytes.
* returns zero on success, nonzero on failure
*/
file_status_t read_from_file(const char *filename, void *data, size_t size);
/** write_to_file
* opens a file and writes the specified number of bytes.
* returns zero on sucess, nonzero on failure
*/
file_status_t write_to_file(const char *filename, const void *data, size_t size);
/**********************
Byte swap utilities
**********************/
#ifdef _MSC_VER
#include <stdlib.h>
#endif
/* GCC has also byte swap intrinsics (__builtin_bswap32, etc.), but they were
* added in relatively recent versions. In addition, GCC can detect the byte
* swap code and optimize it with a high enough optimization level. */
static osal_inline unsigned short m64p_swap16(unsigned short x)
{
#ifdef _MSC_VER
return _byteswap_ushort(x);
#else
return ((x & 0x00FF) << 8) |
((x & 0xFF00) >> 8);
#endif
}
static osal_inline unsigned int m64p_swap32(unsigned int x)
{
#ifdef _MSC_VER
return _byteswap_ulong(x); // long is always 32-bit in Windows
#else
return ((x & 0x000000FF) << 24) |
((x & 0x0000FF00) << 8) |
((x & 0x00FF0000) >> 8) |
((x & 0xFF000000) >> 24);
#endif
}
static osal_inline unsigned long long int m64p_swap64(unsigned long long int x)
{
#ifdef _MSC_VER
return _byteswap_uint64(x);
#else
return ((x & 0x00000000000000FFULL) << 56) |
((x & 0x000000000000FF00ULL) << 40) |
((x & 0x0000000000FF0000ULL) << 24) |
((x & 0x00000000FF000000ULL) << 8) |
((x & 0x000000FF00000000ULL) >> 8) |
((x & 0x0000FF0000000000ULL) >> 24) |
((x & 0x00FF000000000000ULL) >> 40) |
((x & 0xFF00000000000000ULL) >> 56);
#endif
}
#ifdef M64P_BIG_ENDIAN
#define big16(x) (x)
#define big32(x) (x)
#define big64(x) (x)
#define little16(x) m64p_swap16(x)
#define little32(x) m64p_swap32(x)
#define little64(x) m64p_swap64(x)
#else
#define big16(x) m64p_swap16(x)
#define big32(x) m64p_swap32(x)
#define big64(x) m64p_swap64(x)
#define little16(x) (x)
#define little32(x) (x)
#define little64(x) (x)
#endif
/* Byte swaps, converts to little endian or converts to big endian a buffer,
* containing 'count' elements, each of size 'length'. */
void swap_buffer(void *buffer, size_t length, size_t count);
void to_little_endian_buffer(void *buffer, size_t length, size_t count);
void to_big_endian_buffer(void *buffer, size_t length, size_t count);
/**********************
GUI utilities
**********************/
void countrycodestring(unsigned short countrycode, char *string);
void imagestring(unsigned char imagetype, char *string);
/**********************
Path utilities
**********************/
/* Extracts the full file name (with extension) from a path string.
* Returns the same string, advanced until the file name. */
const char* namefrompath(const char* path);
/* Creates a path string by joining two path strings.
* The given path strings may or may not start or end with a path separator.
* Returns a malloc'd string with the resulting path. */
char* combinepath(const char* first, const char *second);
/**********************
String utilities
**********************/
/** trim
* Removes leading and trailing whitespace from str. Function modifies str
* and also returns modified string.
*/
char *trim(char *str);
/* Converts an string to an integer.
* Returns 1 on success, 0 on failure. 'result' is undefined on failure.
*
* The following conditions cause this function to fail:
* - Empty string
* - Leading characters (including whitespace)
* - Trailing characters (including whitespace)
* - Overflow or underflow.
*/
int string_to_int(const char *str, int *result);
/* Converts an string of hexadecimal characters to a byte array.
* 'output_size' is the number of bytes (hex digraphs) to convert.
* Returns 1 on success, 0 on failure. 'output' is undefined on failure. */
int parse_hex(const char *str, unsigned char *output, size_t output_size);
/* Formats an string, using the same syntax as printf.
* Returns the result in a malloc'd string. */
char* formatstr(const char* fmt, ...);
typedef enum _ini_line_type
{
INI_BLANK,
INI_COMMENT,
INI_SECTION,
INI_PROPERTY,
INI_TRASH
} ini_line_type;
typedef struct _ini_line
{
ini_line_type type;
char *name;
char *value;
} ini_line;
/* Parses the INI file line pointer by 'lineptr'.
* The first line pointed by 'lineptr' may be modifed.
* 'lineptr' will point to the next line after this function runs.
*
* Returns a ini_line structure with information about the line.
* For INI_COMMENT, the value field contains the comment.
* For INI_SECTION, the name field contains the section name.
* For INI_PROPERTY, the name and value fields contain the property parameters.
* The line type is INI_BLANK if the line is blank or invalid.
*
* The name and value fields (if any) of ini_line point to 'lineptr'
* (so their lifetime is associated to that of 'lineptr').
*/
ini_line ini_parse_line(char **lineptr);
#ifdef __cplusplus
}
#endif
#endif // __UTIL_H__

View file

@ -0,0 +1,39 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - version.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2008-2012 Richard42 DarkJeztr Tillin9 *
* *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Version macros automatically replaced by Makefiles. */
#ifndef __VERSION_H__
#define __VERSION_H__
#define MUPEN_CORE_NAME "Mupen64Plus Core"
#define MUPEN_CORE_VERSION 0x020000
#define FRONTEND_API_VERSION 0x020101
#define CONFIG_API_VERSION 0x020300
#define DEBUG_API_VERSION 0x020000
#define VIDEXT_API_VERSION 0x030000
#define VERSION_PRINTF_SPLIT(x) (((x) >> 16) & 0xffff), (((x) >> 8) & 0xff), ((x) & 0xff)
#endif /* __VERSION_H__ */

View file

@ -1,839 +0,0 @@
/*
* Project 64 - A Nintendo 64 emulator.
*
* (c) Copyright 2001 zilmar (zilmar@emulation64.com) and
* Jabo (jabo@emulation64.com).
*
* pj64 homepage: www.pj64.net
*
* Permission to use, copy, modify and distribute Project64 in both binary and
* source form, for non-commercial purposes, is hereby granted without fee,
* providing that this license information and copyright notice appear with
* all copies and any derived work.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event shall the authors be held liable for any damages
* arising from the use of this software.
*
* Project64 is freeware for PERSONAL USE only. Commercial users should
* seek permission of the copyright holders first. Commercial use includes
* charging money for Project64 or software derived from Project64.
*
* The copyright holders request that bug fixes and improvements to the code
* should be forwarded to them so if they want them.
*
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "usf.h"
#include "main.h"
#include "cpu.h"
#include "audio.h"
#include "rsp.h"
#include "usf_internal.h"
uint8_t * PageROM(usf_state_t * state, uint32_t addr) {
return (state->ROMPages[addr/0x10000])?state->ROMPages[addr/0x10000]+(addr%0x10000):&state->EmptySpace;
}
void * large_alloc(size_t);
void large_free(void *, size_t);
#ifdef _WIN32
#include <Windows.h>
void * large_alloc(size_t size)
{
return VirtualAlloc( NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
}
void large_free(void * p, size_t size)
{
VirtualFree( p, size, MEM_RELEASE );
}
#else
#include <sys/mman.h>
#ifdef __APPLE__
#define MAP_ANONYMOUS MAP_ANON
#endif
void * large_alloc(size_t size)
{
return mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
}
void large_free(void * p, size_t size)
{
munmap( p, size );
}
#endif
int32_t Allocate_Memory ( void * state ) {
//uint32_t i = 0;
//RdramSize = 0x800000;
// Allocate the N64MEM and TLB_Map so that they are in each others 4GB range
// Also put the registers there :)
// the mmap technique works craptacular when the regions don't overlay
USF_STATE->MemChunk = (uint8_t *) large_alloc( 0x100000 * sizeof(uintptr_t) + 0x1D000 + USF_STATE->RdramSize );
USF_STATE->TLB_Map = (uintptr_t*)USF_STATE->MemChunk;
if (USF_STATE->TLB_Map == NULL) {
return 0;
}
memset(USF_STATE->TLB_Map, 0, 0x100000 * sizeof(uintptr_t) + 0x10000);
USF_STATE->N64MEM = USF_STATE->MemChunk + 0x100000 * sizeof(uintptr_t) + 0x10000;
if(USF_STATE->N64MEM == NULL) {
DisplayError(USF_STATE, "Failed to allocate N64MEM");
return 0;
}
//memset(state->N64MEM, 0, USF_STATE->RdramSize);
USF_STATE->NOMEM = USF_STATE->N64MEM + USF_STATE->RdramSize;
//if(USF_STATE->RdramSize == 0x400000)
//{
// munmap(N64MEM + 0x400000, 0x400000);
//}
USF_STATE->Registers = (N64_REGISTERS *)((uintptr_t)USF_STATE->MemChunk + 0x100000 * sizeof(uintptr_t));
//USF_STATE->TLBLoadAddress = (uint32_t *)((uintptr_t)USF_STATE->Registers + 0x500);
//USF_STATE->Timers = (SYSTEM_TIMERS*)(USF_STATE->TLBLoadAddress + 4);
USF_STATE->Timers = (SYSTEM_TIMERS*)((uintptr_t)USF_STATE->Registers + 0x500);
USF_STATE->WaitMode = (uint32_t *)(USF_STATE->Timers + sizeof(SYSTEM_TIMERS));
USF_STATE->CPU_Action = (CPU_ACTION *)(USF_STATE->WaitMode + 4);
//USF_STATE->RSP_GPR = (struct RSP_GPR_TYPE *)(USF_STATE->CPU_Action + sizeof(CPU_ACTION));
//USF_STATE->DMEM = (uint8_t *)(USF_STATE->RSP_GPR + (32 * 16));
USF_STATE->DMEM = (uint8_t *)(USF_STATE->CPU_Action + sizeof(CPU_ACTION));
//state->RSP_ACCUM = (struct RSP_ACCUM_TYPE *)(USF_STATE->DMEM + 0x2000);
USF_STATE->RDRAM = (uint8_t *)(USF_STATE->N64MEM);
USF_STATE->IMEM = USF_STATE->DMEM + 0x1000;
USF_STATE->MemoryState = 1;
return 1;
}
int PreAllocate_Memory(usf_state_t * state) {
int i = 0;
// Moved the savestate allocation here :) (for better management later)
state->savestatespace = (uint8_t *) malloc(0x80275C);
if(state->savestatespace == 0)
return 0;
memset(state->savestatespace, 0, 0x80275C);
for (i = 0; i < 0x400; i++) {
state->ROMPages[i] = 0;
}
return 1;
}
void Release_Memory ( usf_state_t * state ) {
uint32_t i;
for (i = 0; i < 0x400; i++) {
if (state->ROMPages[i]) {
free(state->ROMPages[i]); state->ROMPages[i] = 0;
}
}
//printf("Freeing memory\n");
state->MemoryState = 0;
if (state->MemChunk != 0) { large_free( state->MemChunk, 0x100000 * sizeof(uintptr_t) + 0x1D000 + state->RdramSize ); state->MemChunk=0; }
if(state->cpu_hle_entries)
free(state->cpu_hle_entries);
state->cpu_hle_entries = NULL;
if(state->savestatespace)
free(state->savestatespace);
state->savestatespace = NULL;
}
int32_t r4300i_LB_NonMemory ( usf_state_t * state, uint32_t PAddr, uint32_t * Value, uint32_t SignExtend ) {
if (PAddr >= 0x10000000 && PAddr < 0x16000000) {
if (state->WrittenToRom) { return 0; }
if ((PAddr & 2) == 0) { PAddr = (PAddr + 4) ^ 2; }
if ((PAddr - 0x10000000) < state->RomFileSize) {
if (SignExtend) {
*Value = (char)*PageROM(state, (PAddr - 0x10000000)^3);
} else {
*Value = *PageROM(state, (PAddr - 0x10000000)^3);
}
return 1;
} else {
*Value = 0;
return 0;
}
}
switch (PAddr & 0xFFF00000) {
default:
* Value = 0;
return 0;
break;
}
return 1;
}
uint32_t r4300i_LB_VAddr ( usf_state_t * state, uint32_t VAddr, uint8_t * Value ) {
uintptr_t address;
address = state->TLB_Map[VAddr >> 12];
if (address == 0) { return 0; }
*Value = *(uint8_t *)(address + (VAddr ^ 3));
return 1;
}
uint32_t r4300i_LD_VAddr ( usf_state_t * state, uint32_t VAddr, uint64_t * Value ) {
uintptr_t address;
address = state->TLB_Map[VAddr >> 12];
if (address == 0) { return 0; }
if (address + VAddr + 7 - (uintptr_t)state->N64MEM >= state->RdramSize)
{
*((uint32_t *)(Value) + 1) = 0;
*((uint32_t *)(Value)) = 0;
return 1;
}
*((uint32_t *)(Value) + 1) = *(uint32_t *)(address + VAddr);
*((uint32_t *)(Value)) = *(uint32_t *)(address + VAddr + 4);
return 1;
}
int32_t r4300i_LH_NonMemory ( usf_state_t * state, uint32_t PAddr, uint32_t * Value, int32_t SignExtend ) {
(void)state;
(void)SignExtend;
switch (PAddr & 0xFFF00000) {
default:
* Value = 0;
return 0;
break;
}
return 1;
}
uint32_t r4300i_LH_VAddr ( usf_state_t * state, uint32_t VAddr, uint16_t * Value ) {
uintptr_t address;
address = state->TLB_Map[VAddr >> 12];
if (address == 0)
return 0;
if (address + (VAddr ^ 2) + 1 - (uintptr_t)state->N64MEM >= state->RdramSize)
{
*Value = 0;
return 1;
}
*Value = *(uint16_t *)(address + (VAddr ^ 2));
return 1;
}
int32_t r4300i_LW_NonMemory ( usf_state_t * state, uint32_t PAddr, uint32_t * Value ) {
if (PAddr >= 0x10000000 && PAddr < 0x16000000) {
if (state->WrittenToRom) {
*Value = state->WroteToRom;
//LogMessage("%X: Read crap from Rom %X from %X",PROGRAM_COUNTER,*Value,PAddr);
state->WrittenToRom = 0;
return 1;
}
if ((PAddr - 0x10000000) < state->RomFileSize) {
*Value = *(uint32_t *)PageROM(state, (PAddr - 0x10000000));
return 1;
} else {
*Value = PAddr & 0xFFFF;
*Value = (*Value << 16) | *Value;
return 0;
}
}
switch (PAddr & 0xFFF00000) {
case 0x03F00000:
switch (PAddr) {
case 0x03F00000: * Value = RDRAM_CONFIG_REG; break;
case 0x03F00004: * Value = RDRAM_DEVICE_ID_REG; break;
case 0x03F00008: * Value = RDRAM_DELAY_REG; break;
case 0x03F0000C: * Value = RDRAM_MODE_REG; break;
case 0x03F00010: * Value = RDRAM_REF_INTERVAL_REG; break;
case 0x03F00014: * Value = RDRAM_REF_ROW_REG; break;
case 0x03F00018: * Value = RDRAM_RAS_INTERVAL_REG; break;
case 0x03F0001C: * Value = RDRAM_MIN_INTERVAL_REG; break;
case 0x03F00020: * Value = RDRAM_ADDR_SELECT_REG; break;
case 0x03F00024: * Value = RDRAM_DEVICE_MANUF_REG; break;
default:
* Value = 0;
return 0;
}
break;
case 0x04000000:
switch (PAddr) {
case 0x04040010: *Value = SP_STATUS_REG; break;
case 0x04040014: *Value = SP_DMA_FULL_REG; break;
case 0x04040018: *Value = SP_DMA_BUSY_REG; break;
case 0x04080000: *Value = SP_PC_REG; break;
default:
* Value = 0;
return 0;
}
break;
case 0x04100000:
switch (PAddr) {
case 0x0410000C: *Value = DPC_STATUS_REG; break;
case 0x04100010: *Value = DPC_CLOCK_REG; break;
case 0x04100014: *Value = DPC_BUFBUSY_REG; break;
case 0x04100018: *Value = DPC_PIPEBUSY_REG; break;
case 0x0410001C: *Value = DPC_TMEM_REG; break;
default:
* Value = 0;
return 0;
}
break;
case 0x04300000:
switch (PAddr) {
case 0x04300000: * Value = MI_MODE_REG; break;
case 0x04300004: * Value = MI_VERSION_REG; break;
case 0x04300008: * Value = MI_INTR_REG; break;
case 0x0430000C: * Value = MI_INTR_MASK_REG; break;
default:
* Value = 0;
return 0;
}
break;
case 0x04400000:
switch (PAddr) {
case 0x04400000: *Value = VI_STATUS_REG; break;
case 0x04400004: *Value = VI_ORIGIN_REG; break;
case 0x04400008: *Value = VI_WIDTH_REG; break;
case 0x0440000C: *Value = VI_INTR_REG; break;
case 0x04400010:
*Value = 0;
break;
case 0x04400014: *Value = VI_BURST_REG; break;
case 0x04400018: *Value = VI_V_SYNC_REG; break;
case 0x0440001C: *Value = VI_H_SYNC_REG; break;
case 0x04400020: *Value = VI_LEAP_REG; break;
case 0x04400024: *Value = VI_H_START_REG; break;
case 0x04400028: *Value = VI_V_START_REG ; break;
case 0x0440002C: *Value = VI_V_BURST_REG; break;
case 0x04400030: *Value = VI_X_SCALE_REG; break;
case 0x04400034: *Value = VI_Y_SCALE_REG; break;
default:
* Value = 0;
return 0;
}
break;
case 0x04500000:
switch (PAddr) {
case 0x04500004: *Value = AiReadLength(state); break;
case 0x0450000C: *Value = AI_STATUS_REG; break;
default:
* Value = 0;
return 0;
}
break;
case 0x04600000:
switch (PAddr) {
case 0x04600010: *Value = PI_STATUS_REG; break;
case 0x04600014: *Value = PI_DOMAIN1_REG; break;
case 0x04600018: *Value = PI_BSD_DOM1_PWD_REG; break;
case 0x0460001C: *Value = PI_BSD_DOM1_PGS_REG; break;
case 0x04600020: *Value = PI_BSD_DOM1_RLS_REG; break;
case 0x04600024: *Value = PI_DOMAIN2_REG; break;
case 0x04600028: *Value = PI_BSD_DOM2_PWD_REG; break;
case 0x0460002C: *Value = PI_BSD_DOM2_PGS_REG; break;
case 0x04600030: *Value = PI_BSD_DOM2_RLS_REG; break;
default:
* Value = 0;
return 0;
}
break;
case 0x04700000:
switch (PAddr) {
case 0x04700000: * Value = RI_MODE_REG; break;
case 0x04700004: * Value = RI_CONFIG_REG; break;
case 0x04700008: * Value = RI_CURRENT_LOAD_REG; break;
case 0x0470000C: * Value = RI_SELECT_REG; break;
case 0x04700010: * Value = RI_REFRESH_REG; break;
case 0x04700014: * Value = RI_LATENCY_REG; break;
case 0x04700018: * Value = RI_RERROR_REG; break;
case 0x0470001C: * Value = RI_WERROR_REG; break;
default:
* Value = 0;
return 0;
}
break;
case 0x04800000:
switch (PAddr) {
case 0x04800018: *Value = SI_STATUS_REG; break;
default:
*Value = 0;
return 0;
}
break;
case 0x05000000:
*Value = PAddr & 0xFFFF;
*Value = (*Value << 16) | *Value;
return 0;
case 0x08000000:
*Value = 0;
break;
default:
*Value = PAddr & 0xFFFF;
*Value = (*Value << 16) | *Value;
return 0;
break;
}
return 1;
}
void r4300i_LW_PAddr ( usf_state_t * state, uint32_t PAddr, uint32_t * Value ) {
*Value = *(uint32_t *)(state->N64MEM+PAddr);
}
uint32_t r4300i_LW_VAddr ( usf_state_t * state, uint32_t VAddr, uint32_t * Value ) {
uintptr_t address = state->TLB_Map[VAddr >> 12];
if (address == 0)
return 0;
address += VAddr;
if((address - (uintptr_t)state->RDRAM) > state->RdramSize) {
address = address - (uintptr_t)state->RDRAM;
return r4300i_LW_NonMemory(state, (uint32_t) address, Value);
}
*Value = *(uint32_t *)address;
return 1;
}
int32_t r4300i_SB_NonMemory ( usf_state_t * state, uint32_t PAddr, uint8_t Value ) {
switch (PAddr & 0xFFF00000) {
case 0x00000000:
case 0x00100000:
case 0x00200000:
case 0x00300000:
case 0x00400000:
case 0x00500000:
case 0x00600000:
case 0x00700000:
if (PAddr < state->RdramSize) {
*(uint8_t *)(state->N64MEM+PAddr) = Value;
}
break;
default:
return 0;
break;
}
return 1;
}
uint32_t r4300i_SB_VAddr ( usf_state_t * state, uint32_t VAddr, uint8_t Value ) {
uintptr_t address;
address = state->TLB_Map[VAddr >> 12];
if (address == 0) { return 0; }
if (address + (VAddr ^ 3) - (uintptr_t)state->N64MEM < state->RdramSize)
*(uint8_t *)(address + (VAddr ^ 3)) = Value;
return 1;
}
int32_t r4300i_SH_NonMemory ( usf_state_t * state, uint32_t PAddr, uint16_t Value ) {
switch (PAddr & 0xFFF00000) {
case 0x00000000:
case 0x00100000:
case 0x00200000:
case 0x00300000:
case 0x00400000:
case 0x00500000:
case 0x00600000:
case 0x00700000:
if (PAddr < state->RdramSize) {
*(uint16_t *)(state->N64MEM+PAddr) = Value;
}
break;
default:
return 0;
break;
}
return 1;
}
uint32_t r4300i_SD_VAddr ( usf_state_t * state, uint32_t VAddr, uint64_t Value ) {
uintptr_t address;
address = state->TLB_Map[VAddr >> 12];
if (address == 0) { return 0; }
if (address + VAddr + 7 - (uintptr_t)state->N64MEM < state->RdramSize)
{
*(uint32_t *)(address + VAddr) = *((uint32_t *)(&Value) + 1);
*(uint32_t *)(address + VAddr + 4) = *((uint32_t *)(&Value));
}
return 1;
}
uint32_t r4300i_SH_VAddr ( usf_state_t * state, uint32_t VAddr, uint16_t Value ) {
uintptr_t address;
address = state->TLB_Map[VAddr >> 12];
if (address == 0) { return 0; }
if (address + 1 + (VAddr ^ 2) - (uintptr_t)state->N64MEM < state->RdramSize)
*(uint16_t *)(address + (VAddr ^ 2)) = Value;
return 1;
}
int32_t r4300i_SW_NonMemory ( usf_state_t * state, uint32_t PAddr, uint32_t Value ) {
if (PAddr >= 0x10000000 && PAddr < 0x16000000) {
if ((PAddr - 0x10000000) < state->RomFileSize) {
state->WrittenToRom = 1;
state->WroteToRom = Value;
} else {
return 0;
}
}
switch (PAddr & 0xFFF00000) {
case 0x00000000:
case 0x00100000:
case 0x00200000:
case 0x00300000:
case 0x00400000:
case 0x00500000:
case 0x00600000:
case 0x00700000:
if (PAddr < state->RdramSize) {
*(uint32_t *)(state->N64MEM+PAddr) = Value;
}
break;
case 0x03F00000:
switch (PAddr) {
case 0x03F00000: RDRAM_CONFIG_REG = Value; break;
case 0x03F00004: RDRAM_DEVICE_ID_REG = Value; break;
case 0x03F00008: RDRAM_DELAY_REG = Value; break;
case 0x03F0000C: RDRAM_MODE_REG = Value; break;
case 0x03F00010: RDRAM_REF_INTERVAL_REG = Value; break;
case 0x03F00014: RDRAM_REF_ROW_REG = Value; break;
case 0x03F00018: RDRAM_RAS_INTERVAL_REG = Value; break;
case 0x03F0001C: RDRAM_MIN_INTERVAL_REG = Value; break;
case 0x03F00020: RDRAM_ADDR_SELECT_REG = Value; break;
case 0x03F00024: RDRAM_DEVICE_MANUF_REG = Value; break;
case 0x03F04004: break;
case 0x03F08004: break;
case 0x03F80004: break;
case 0x03F80008: break;
case 0x03F8000C: break;
case 0x03F80014: break;
default:
return 0;
}
break;
case 0x04000000:
if (PAddr < 0x04002000) {
*(uint32_t *)(state->N64MEM+PAddr) = Value;
return 1;
}
switch (PAddr) {
case 0x04040000: SP_MEM_ADDR_REG = Value; break;
case 0x04040004: SP_DRAM_ADDR_REG = Value; break;
case 0x04040008:
SP_RD_LEN_REG = Value;
SP_DMA_READ(state);
break;
case 0x0404000C:
SP_WR_LEN_REG = Value;
SP_DMA_WRITE(state);
break;
case 0x04040010:
if ( ( Value & SP_CLR_HALT ) != 0) { SP_STATUS_REG &= ~SP_STATUS_HALT; }
if ( ( Value & SP_SET_HALT ) != 0) { SP_STATUS_REG |= SP_STATUS_HALT; }
if ( ( Value & SP_CLR_BROKE ) != 0) { SP_STATUS_REG &= ~SP_STATUS_BROKE; }
if ( ( Value & SP_CLR_INTR ) != 0) {
MI_INTR_REG &= ~MI_INTR_SP;
CheckInterrupts(state);
}
if ( ( Value & SP_CLR_SSTEP ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SSTEP; }
if ( ( Value & SP_SET_SSTEP ) != 0) { SP_STATUS_REG |= SP_STATUS_SSTEP; }
if ( ( Value & SP_CLR_INTR_BREAK ) != 0) { SP_STATUS_REG &= ~SP_STATUS_INTR_BREAK; }
if ( ( Value & SP_SET_INTR_BREAK ) != 0) { SP_STATUS_REG |= SP_STATUS_INTR_BREAK; }
if ( ( Value & SP_CLR_SIG0 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG0; }
if ( ( Value & SP_SET_SIG0 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG0; }
if ( ( Value & SP_CLR_SIG1 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG1; }
if ( ( Value & SP_SET_SIG1 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG1; }
if ( ( Value & SP_CLR_SIG2 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG2; }
if ( ( Value & SP_SET_SIG2 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG2; }
if ( ( Value & SP_CLR_SIG3 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG3; }
if ( ( Value & SP_SET_SIG3 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG3; }
if ( ( Value & SP_CLR_SIG4 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG4; }
if ( ( Value & SP_SET_SIG4 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG4; }
if ( ( Value & SP_CLR_SIG5 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG5; }
if ( ( Value & SP_SET_SIG5 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG5; }
if ( ( Value & SP_CLR_SIG6 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG6; }
if ( ( Value & SP_SET_SIG6 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG6; }
if ( ( Value & SP_CLR_SIG7 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG7; }
if ( ( Value & SP_SET_SIG7 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG7; }
RunRsp(state);
break;
case 0x0404001C: SP_SEMAPHORE_REG = 0; break;
case 0x04080000: SP_PC_REG = Value & 0xFFC; break;
default:
return 0;
}
break;
case 0x04100000:
switch (PAddr) {
case 0x04100000:
DPC_START_REG = Value;
DPC_CURRENT_REG = Value;
break;
case 0x04100004:
DPC_END_REG = Value;
break;
case 0x04100008: DPC_CURRENT_REG = Value; break;
case 0x0410000C:
if ( ( Value & DPC_CLR_XBUS_DMEM_DMA ) != 0) { DPC_STATUS_REG &= ~DPC_STATUS_XBUS_DMEM_DMA; }
if ( ( Value & DPC_SET_XBUS_DMEM_DMA ) != 0) { DPC_STATUS_REG |= DPC_STATUS_XBUS_DMEM_DMA; }
if ( ( Value & DPC_CLR_FREEZE ) != 0) { DPC_STATUS_REG &= ~DPC_STATUS_FREEZE; }
if ( ( Value & DPC_SET_FREEZE ) != 0) { DPC_STATUS_REG |= DPC_STATUS_FREEZE; }
if ( ( Value & DPC_CLR_FLUSH ) != 0) { DPC_STATUS_REG &= ~DPC_STATUS_FLUSH; }
if ( ( Value & DPC_SET_FLUSH ) != 0) { DPC_STATUS_REG |= DPC_STATUS_FLUSH; }
if ( ( Value & DPC_CLR_FREEZE ) != 0)
{
if ( ( SP_STATUS_REG & SP_STATUS_HALT ) == 0)
{
if ( ( SP_STATUS_REG & SP_STATUS_BROKE ) == 0 )
{
RunRsp(state);
}
}
}
break;
default:
return 0;
}
break;
case 0x04300000:
switch (PAddr) {
case 0x04300000:
MI_MODE_REG &= ~0x7F;
MI_MODE_REG |= (Value & 0x7F);
if ( ( Value & MI_CLR_INIT ) != 0 ) { MI_MODE_REG &= ~MI_MODE_INIT; }
if ( ( Value & MI_SET_INIT ) != 0 ) { MI_MODE_REG |= MI_MODE_INIT; }
if ( ( Value & MI_CLR_EBUS ) != 0 ) { MI_MODE_REG &= ~MI_MODE_EBUS; }
if ( ( Value & MI_SET_EBUS ) != 0 ) { MI_MODE_REG |= MI_MODE_EBUS; }
if ( ( Value & MI_CLR_DP_INTR ) != 0 ) {
MI_INTR_REG &= ~MI_INTR_DP;
CheckInterrupts(state);
}
if ( ( Value & MI_CLR_RDRAM ) != 0 ) { MI_MODE_REG &= ~MI_MODE_RDRAM; }
if ( ( Value & MI_SET_RDRAM ) != 0 ) { MI_MODE_REG |= MI_MODE_RDRAM; }
break;
case 0x0430000C:
if ( ( Value & MI_INTR_MASK_CLR_SP ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_SP; }
if ( ( Value & MI_INTR_MASK_SET_SP ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_SP; }
if ( ( Value & MI_INTR_MASK_CLR_SI ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_SI; }
if ( ( Value & MI_INTR_MASK_SET_SI ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_SI; }
if ( ( Value & MI_INTR_MASK_CLR_AI ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_AI; }
if ( ( Value & MI_INTR_MASK_SET_AI ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_AI; }
if ( ( Value & MI_INTR_MASK_CLR_VI ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_VI; }
if ( ( Value & MI_INTR_MASK_SET_VI ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_VI; }
if ( ( Value & MI_INTR_MASK_CLR_PI ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_PI; }
if ( ( Value & MI_INTR_MASK_SET_PI ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_PI; }
if ( ( Value & MI_INTR_MASK_CLR_DP ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_DP; }
if ( ( Value & MI_INTR_MASK_SET_DP ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_DP; }
break;
default:
return 0;
}
break;
case 0x04400000:
switch (PAddr) {
case 0x04400000:
//if (VI_STATUS_REG != Value) {
VI_STATUS_REG = Value;
// if (ViStatusChanged != NULL ) { ViStatusChanged(); }
//}
break;
case 0x04400004:
VI_ORIGIN_REG = (Value & 0xFFFFFF);
//if (UpdateScreen != NULL ) { UpdateScreen(); }
break;
case 0x04400008:
//if (VI_WIDTH_REG != Value) {
VI_WIDTH_REG = Value;
// if (ViWidthChanged != NULL ) { ViWidthChanged(); }
//}
break;
case 0x0440000C: VI_INTR_REG = Value; break;
case 0x04400010:
MI_INTR_REG &= ~MI_INTR_VI;
CheckInterrupts(state);
break;
case 0x04400014: VI_BURST_REG = Value; break;
case 0x04400018: VI_V_SYNC_REG = Value; break;
case 0x0440001C: VI_H_SYNC_REG = Value; break;
case 0x04400020: VI_LEAP_REG = Value; break;
case 0x04400024: VI_H_START_REG = Value; break;
case 0x04400028: VI_V_START_REG = Value; break;
case 0x0440002C: VI_V_BURST_REG = Value; break;
case 0x04400030: VI_X_SCALE_REG = Value; break;
case 0x04400034: VI_Y_SCALE_REG = Value; break;
default:
return 0;
}
break;
case 0x04500000:
switch (PAddr) {
case 0x04500000: AI_DRAM_ADDR_REG = Value; break;
case 0x04500004:
AI_LEN_REG = Value;
AiLenChanged(state);
break;
case 0x04500008: AI_CONTROL_REG = (Value & 0x1); break;
case 0x0450000C:
/* Clear Interrupt */;
MI_INTR_REG &= ~MI_INTR_AI;
state->AudioIntrReg &= ~MI_INTR_AI;
CheckInterrupts(state);
break;
case 0x04500010:
AI_DACRATE_REG = Value;
//if (AiDacrateChanged != NULL) { AiDacrateChanged(SYSTEM_NTSC); }
break;
case 0x04500014: AI_BITRATE_REG = Value; break;
default:
return 0;
}
break;
case 0x04600000:
switch (PAddr) {
case 0x04600000: PI_DRAM_ADDR_REG = Value; break;
case 0x04600004: PI_CART_ADDR_REG = Value; break;
case 0x04600008:
PI_RD_LEN_REG = Value;
PI_DMA_READ(state);
break;
case 0x0460000C:
PI_WR_LEN_REG = Value;
PI_DMA_WRITE(state);
break;
case 0x04600010:
//if ((Value & PI_SET_RESET) != 0 ) { DisplayError(state, "reset Controller"); }
if ((Value & PI_CLR_INTR) != 0 ) {
MI_INTR_REG &= ~MI_INTR_PI;
CheckInterrupts(state);
}
break;
case 0x04600014: PI_DOMAIN1_REG = (Value & 0xFF); break;
case 0x04600018: PI_BSD_DOM1_PWD_REG = (Value & 0xFF); break;
case 0x0460001C: PI_BSD_DOM1_PGS_REG = (Value & 0xFF); break;
case 0x04600020: PI_BSD_DOM1_RLS_REG = (Value & 0xFF); break;
default:
return 0;
}
break;
case 0x04700000:
switch (PAddr) {
case 0x04700000: RI_MODE_REG = Value; break;
case 0x04700004: RI_CONFIG_REG = Value; break;
case 0x04700008: RI_CURRENT_LOAD_REG = Value; break;
case 0x0470000C: RI_SELECT_REG = Value; break;
case 0x04700010: RI_REFRESH_REG = Value; break;
case 0x04700014: RI_LATENCY_REG = Value; break;
case 0x04700018: RI_RERROR_REG = Value; break;
case 0x0470001C: RI_WERROR_REG = Value; break;
default:
return 0;
}
break;
case 0x04800000:
switch (PAddr) {
case 0x04800000: SI_DRAM_ADDR_REG = Value; break;
case 0x04800004:
SI_PIF_ADDR_RD64B_REG = Value;
SI_DMA_READ (state);
break;
case 0x04800010:
SI_PIF_ADDR_WR64B_REG = Value;
SI_DMA_WRITE(state);
break;
case 0x04800018:
MI_INTR_REG &= ~MI_INTR_SI;
SI_STATUS_REG &= ~SI_STATUS_INTERRUPT;
CheckInterrupts(state);
break;
default:
return 0;
}
break;
case 0x08000000:
if (PAddr != 0x08010000) { return 0; }
break;
case 0x1FC00000:
if (PAddr < 0x1FC007C0) {
return 0;
} else if (PAddr < 0x1FC00800) {
if (PAddr == 0x1FC007FC) {
PifRamWrite(state);
}
return 1;
}
return 0;
break;
default:
return 0;
break;
}
return 1;
}
uint32_t r4300i_SW_VAddr ( usf_state_t * state, uint32_t VAddr, uint32_t Value ) {
uintptr_t address;
address = state->TLB_Map[VAddr >> 12];
if (address == 0) { return 0; }
address = (address + VAddr);
if((address - (uintptr_t)state->RDRAM) > state->RdramSize) {
address = address - (uintptr_t)state->RDRAM;
return r4300i_SW_NonMemory(state, (uint32_t) address, Value);
}
*(uint32_t *)address = Value;
return 1;
}
void memcpyn642n64(usf_state_t * state, uint32_t dest, uint32_t src, uint32_t len)
{
uint32_t i;
uint32_t temp;
for (i = 0; i < len; i += 4)
{
uintptr_t dstAddr = state->TLB_Map[(dest + i) >> 12];
uintptr_t srcAddr = state->TLB_Map[(src + i) >> 12];
if (srcAddr)
temp = *(uint32_t*)(srcAddr + src + i);
else
temp = 0;
if (dstAddr)
*(uint32_t*)(dstAddr + dest + i) = temp;
}
}

View file

@ -1,64 +0,0 @@
/*
* Project 64 - A Nintendo 64 emulator.
*
* (c) Copyright 2001 zilmar (zilmar@emulation64.com) and
* Jabo (jabo@emulation64.com).
*
* pj64 homepage: www.pj64.net
*
* Permission to use, copy, modify and distribute Project64 in both binary and
* source form, for non-commercial purposes, is hereby granted without fee,
* providing that this license information and copyright notice appear with
* all copies and any derived work.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event shall the authors be held liable for any damages
* arising from the use of this software.
*
* Project64 is freeware for PERSONAL USE only. Commercial users should
* seek permission of the copyright holders first. Commercial use includes
* charging money for Project64 or software derived from Project64.
*
* The copyright holders request that bug fixes and improvements to the code
* should be forwarded to them so if they want them.
*
*/
#define LargeCompileBufferSize 0x03200000
#define NormalCompileBufferSize 0x01500000
#define RSP_RECOMPMEM_SIZE 0x400000
#define RSP_SECRECOMPMEM_SIZE 0x200000
#define ROM_IN_MAPSPACE
#define PageRAM2(x) (state->N64MEM+(uint32_t)(x))
#define PageVRAM(x) (state->TLB_Map[((uint32_t)(x))>>12]+(uint32_t)(x))
#define PageVRAM2(x) (uint32_t)(PageVRAM(x)-(uintptr_t)state->N64MEM)
/* Memory Control */
int Allocate_Memory ( void * );
void Release_Memory ( usf_state_t * );
int PreAllocate_Memory( usf_state_t * );
/* CPU memory functions */
//int r4300i_Command_MemoryFilter ( uint32_t dwExptCode, LPEXCEPTION_POINTERS lpEP );
//int r4300i_CPU_MemoryFilter ( uint32_t dwExptCode, LPEXCEPTION_POINTERS lpEP );
int32_t r4300i_LB_NonMemory ( usf_state_t *, uint32_t PAddr, uint32_t * Value, uint32_t SignExtend );
uint32_t r4300i_LB_VAddr ( usf_state_t *, uint32_t VAddr, uint8_t * Value );
uint32_t r4300i_LD_VAddr ( usf_state_t *, uint32_t VAddr, uint64_t * Value );
int32_t r4300i_LH_NonMemory ( usf_state_t *, uint32_t PAddr, uint32_t * Value, int32_t SignExtend );
uint32_t r4300i_LH_VAddr ( usf_state_t *, uint32_t VAddr, uint16_t * Value );
int32_t r4300i_LW_NonMemory ( usf_state_t *, uint32_t PAddr, uint32_t * Value );
void r4300i_LW_PAddr ( usf_state_t *, uint32_t PAddr, uint32_t * Value );
uint32_t r4300i_LW_VAddr ( usf_state_t *, uint32_t VAddr, uint32_t * Value );
int32_t r4300i_SB_NonMemory ( usf_state_t *, uint32_t PAddr, uint8_t Value );
uint32_t r4300i_SB_VAddr ( usf_state_t *, uint32_t VAddr, uint8_t Value );
uint32_t r4300i_SD_VAddr ( usf_state_t *, uint32_t VAddr, uint64_t Value );
int32_t r4300i_SH_NonMemory ( usf_state_t *, uint32_t PAddr, uint16_t Value );
uint32_t r4300i_SH_VAddr ( usf_state_t *, uint32_t VAddr, uint16_t Value );
int32_t r4300i_SW_NonMemory ( usf_state_t *, uint32_t PAddr, uint32_t Value );
uint32_t r4300i_SW_VAddr ( usf_state_t *, uint32_t VAddr, uint32_t Value );
uint8_t * PageROM(usf_state_t *, uint32_t addr);
void memcpyn642n64(usf_state_t *, uint32_t dest, uint32_t src, uint32_t len);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,106 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - memory.h *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_MEMORY_MEMORY_H
#define M64P_MEMORY_MEMORY_H
#include <stdint.h>
#define read_word_in_memory() state->readmem[state->address>>16](state)
#define read_byte_in_memory() state->readmemb[state->address>>16](state)
#define read_hword_in_memory() state->readmemh[state->address>>16](state)
#define read_dword_in_memory() state->readmemd[state->address>>16](state)
#define write_word_in_memory() state->writemem[state->address>>16](state)
#define write_byte_in_memory() state->writememb[state->address >>16](state)
#define write_hword_in_memory() state->writememh[state->address >>16](state)
#define write_dword_in_memory() state->writememd[state->address >>16](state)
#ifndef M64P_BIG_ENDIAN
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
#define sl(x) __builtin_bswap32(x)
#else
#define sl(mot) \
( \
((mot & 0x000000FF) << 24) | \
((mot & 0x0000FF00) << 8) | \
((mot & 0x00FF0000) >> 8) | \
((mot & 0xFF000000) >> 24) \
)
#endif
#define S8 3
#define S16 2
#define Sh16 1
#else
#define sl(mot) mot
#define S8 0
#define S16 0
#define Sh16 0
#endif
#include "osal/preproc.h"
static osal_inline void masked_write(uint32_t* dst, uint32_t value, uint32_t mask)
{
*dst = (*dst & ~mask) | (value & mask);
}
int init_memory(usf_state_t *, uint32_t rdram_size);
void map_region(usf_state_t *,
uint16_t region,
int type,
void (osal_fastcall *read8)(usf_state_t *),
void (osal_fastcall *read16)(usf_state_t *),
void (osal_fastcall *read32)(usf_state_t *),
void (osal_fastcall *read64)(usf_state_t *),
void (osal_fastcall *write8)(usf_state_t *),
void (osal_fastcall *write16)(usf_state_t *),
void (osal_fastcall *write32)(usf_state_t *),
void (osal_fastcall *write64)(usf_state_t *));
/* XXX: cannot make them static because of dynarec + rdp fb */
void osal_fastcall read_rdram(usf_state_t *);
void osal_fastcall read_rdramb(usf_state_t *);
void osal_fastcall read_rdramh(usf_state_t *);
void osal_fastcall read_rdramd(usf_state_t *);
void osal_fastcall write_rdram(usf_state_t *);
void osal_fastcall write_rdramb(usf_state_t *);
void osal_fastcall write_rdramh(usf_state_t *);
void osal_fastcall write_rdramd(usf_state_t *);
void osal_fastcall read_rdramFB(usf_state_t *);
void osal_fastcall read_rdramFBb(usf_state_t *);
void osal_fastcall read_rdramFBh(usf_state_t *);
void osal_fastcall read_rdramFBd(usf_state_t *);
void osal_fastcall write_rdramFB(usf_state_t *);
void osal_fastcall write_rdramFBb(usf_state_t *);
void osal_fastcall write_rdramFBh(usf_state_t *);
void osal_fastcall write_rdramFBd(usf_state_t *);
/* Returns a pointer to a block of contiguous memory
* Can access RDRAM, SP_DMEM, SP_IMEM and ROM, using TLB if necessary
* Useful for getting fast access to a zone with executable code. */
unsigned int * osal_fastcall fast_mem_access(usf_state_t *, unsigned int address);
#endif

View file

@ -1,274 +0,0 @@
/*
* Project 64 - A Nintendo 64 emulator.
*
* (c) Copyright 2001 zilmar (zilmar@emulation64.com) and
* Jabo (jabo@emulation64.com).
*
* pj64 homepage: www.pj64.net
*
* Permission to use, copy, modify and distribute Project64 in both binary and
* source form, for non-commercial purposes, is hereby granted without fee,
* providing that this license information and copyright notice appear with
* all copies and any derived work.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event shall the authors be held liable for any damages
* arising from the use of this software.
*
* Project64 is freeware for PERSONAL USE only. Commercial users should
* seek permission of the copyright holders first. Commercial use includes
* charging money for Project64 or software derived from Project64.
*
* The copyright holders request that bug fixes and improvements to the code
* should be forwarded to them so if they want them.
*
*/
#ifndef __OpCode
#define __OpCode
#include "types.h"
typedef struct {
union {
uint32_t Hex;
uint8_t Ascii[4];
struct {
unsigned offset : 16;
unsigned rt : 5;
unsigned rs : 5;
unsigned op : 6;
} b;
struct {
unsigned immediate : 16;
unsigned : 5;
unsigned base : 5;
unsigned : 6;
} c;
struct {
unsigned target : 26;
unsigned : 6;
} d;
struct {
unsigned funct : 6;
unsigned sa : 5;
unsigned rd : 5;
unsigned : 5;
unsigned : 5;
unsigned : 6;
} e;
struct {
unsigned : 6;
unsigned fd : 5;
unsigned fs : 5;
unsigned ft : 5;
unsigned fmt : 5;
unsigned : 6;
} f;
} u;
} OPCODE;
//R4300i OpCodes
#define R4300i_SPECIAL 0
#define R4300i_REGIMM 1
#define R4300i_J 2
#define R4300i_JAL 3
#define R4300i_BEQ 4
#define R4300i_BNE 5
#define R4300i_BLEZ 6
#define R4300i_BGTZ 7
#define R4300i_ADDI 8
#define R4300i_ADDIU 9
#define R4300i_SLTI 10
#define R4300i_SLTIU 11
#define R4300i_ANDI 12
#define R4300i_ORI 13
#define R4300i_XORI 14
#define R4300i_LUI 15
#define R4300i_CP0 16
#define R4300i_CP1 17
#define R4300i_BEQL 20
#define R4300i_BNEL 21
#define R4300i_BLEZL 22
#define R4300i_BGTZL 23
#define R4300i_DADDI 24
#define R4300i_DADDIU 25
#define R4300i_LDL 26
#define R4300i_LDR 27
#define R4300i_LB 32
#define R4300i_LH 33
#define R4300i_LWL 34
#define R4300i_LW 35
#define R4300i_LBU 36
#define R4300i_LHU 37
#define R4300i_LWR 38
#define R4300i_LWU 39
#define R4300i_SB 40
#define R4300i_SH 41
#define R4300i_SWL 42
#define R4300i_SW 43
#define R4300i_SDL 44
#define R4300i_SDR 45
#define R4300i_SWR 46
#define R4300i_CACHE 47
#define R4300i_LL 48
#define R4300i_LWC1 49
#define R4300i_LWC2 0x32
#define R4300i_LLD 0x34
#define R4300i_LDC1 53
#define R4300i_LDC2 0x36
#define R4300i_LD 55
#define R4300i_SC 0x38
#define R4300i_SWC1 57
#define R4300i_SWC2 0x3A
#define R4300i_SCD 0x3C
#define R4300i_SDC1 61
#define R4300i_SDC2 62
#define R4300i_SD 63
/* R4300i Special opcodes */
#define R4300i_SPECIAL_SLL 0
#define R4300i_SPECIAL_SRL 2
#define R4300i_SPECIAL_SRA 3
#define R4300i_SPECIAL_SLLV 4
#define R4300i_SPECIAL_SRLV 6
#define R4300i_SPECIAL_SRAV 7
#define R4300i_SPECIAL_JR 8
#define R4300i_SPECIAL_JALR 9
#define R4300i_SPECIAL_SYSCALL 12
#define R4300i_SPECIAL_BREAK 13
#define R4300i_SPECIAL_SYNC 15
#define R4300i_SPECIAL_MFHI 16
#define R4300i_SPECIAL_MTHI 17
#define R4300i_SPECIAL_MFLO 18
#define R4300i_SPECIAL_MTLO 19
#define R4300i_SPECIAL_DSLLV 20
#define R4300i_SPECIAL_DSRLV 22
#define R4300i_SPECIAL_DSRAV 23
#define R4300i_SPECIAL_MULT 24
#define R4300i_SPECIAL_MULTU 25
#define R4300i_SPECIAL_DIV 26
#define R4300i_SPECIAL_DIVU 27
#define R4300i_SPECIAL_DMULT 28
#define R4300i_SPECIAL_DMULTU 29
#define R4300i_SPECIAL_DDIV 30
#define R4300i_SPECIAL_DDIVU 31
#define R4300i_SPECIAL_ADD 32
#define R4300i_SPECIAL_ADDU 33
#define R4300i_SPECIAL_SUB 34
#define R4300i_SPECIAL_SUBU 35
#define R4300i_SPECIAL_AND 36
#define R4300i_SPECIAL_OR 37
#define R4300i_SPECIAL_XOR 38
#define R4300i_SPECIAL_NOR 39
#define R4300i_SPECIAL_SLT 42
#define R4300i_SPECIAL_SLTU 43
#define R4300i_SPECIAL_DADD 44
#define R4300i_SPECIAL_DADDU 45
#define R4300i_SPECIAL_DSUB 46
#define R4300i_SPECIAL_DSUBU 47
#define R4300i_SPECIAL_TGE 48
#define R4300i_SPECIAL_TGEU 49
#define R4300i_SPECIAL_TLT 50
#define R4300i_SPECIAL_TLTU 51
#define R4300i_SPECIAL_TEQ 52
#define R4300i_SPECIAL_TNE 54
#define R4300i_SPECIAL_DSLL 56
#define R4300i_SPECIAL_DSRL 58
#define R4300i_SPECIAL_DSRA 59
#define R4300i_SPECIAL_DSLL32 60
#define R4300i_SPECIAL_DSRL32 62
#define R4300i_SPECIAL_DSRA32 63
/* R4300i RegImm opcodes */
#define R4300i_REGIMM_BLTZ 0
#define R4300i_REGIMM_BGEZ 1
#define R4300i_REGIMM_BLTZL 2
#define R4300i_REGIMM_BGEZL 3
#define R4300i_REGIMM_TGEI 0x08
#define R4300i_REGIMM_TGEIU 0x09
#define R4300i_REGIMM_TLTI 0x0A
#define R4300i_REGIMM_TLTIU 0x0B
#define R4300i_REGIMM_TEQI 0x0C
#define R4300i_REGIMM_TNEI 0x0E
#define R4300i_REGIMM_BLTZAL 0x10
#define R4300i_REGIMM_BGEZAL 17
#define R4300i_REGIMM_BLTZALL 0x12
#define R4300i_REGIMM_BGEZALL 0x13
/* R4300i COP0 opcodes */
#define R4300i_COP0_MF 0
#define R4300i_COP0_MT 4
/* R4300i COP0 CO opcodes */
#define R4300i_COP0_CO_TLBR 1
#define R4300i_COP0_CO_TLBWI 2
#define R4300i_COP0_CO_TLBWR 6
#define R4300i_COP0_CO_TLBP 8
#define R4300i_COP0_CO_ERET 24
/* R4300i COP1 opcodes */
#define R4300i_COP1_MF 0
#define R4300i_COP1_DMF 1
#define R4300i_COP1_CF 2
#define R4300i_COP1_MT 4
#define R4300i_COP1_DMT 5
#define R4300i_COP1_CT 6
#define R4300i_COP1_BC 8
#define R4300i_COP1_S 16
#define R4300i_COP1_D 17
#define R4300i_COP1_W 20
#define R4300i_COP1_L 21
/* R4300i COP1 BC opcodes */
#define R4300i_COP1_BC_BCF 0
#define R4300i_COP1_BC_BCT 1
#define R4300i_COP1_BC_BCFL 2
#define R4300i_COP1_BC_BCTL 3
#define R4300i_COP1_FUNCT_ADD 0
#define R4300i_COP1_FUNCT_SUB 1
#define R4300i_COP1_FUNCT_MUL 2
#define R4300i_COP1_FUNCT_DIV 3
#define R4300i_COP1_FUNCT_SQRT 4
#define R4300i_COP1_FUNCT_ABS 5
#define R4300i_COP1_FUNCT_MOV 6
#define R4300i_COP1_FUNCT_NEG 7
#define R4300i_COP1_FUNCT_ROUND_L 8
#define R4300i_COP1_FUNCT_TRUNC_L 9
#define R4300i_COP1_FUNCT_CEIL_L 10
#define R4300i_COP1_FUNCT_FLOOR_L 11
#define R4300i_COP1_FUNCT_ROUND_W 12
#define R4300i_COP1_FUNCT_TRUNC_W 13
#define R4300i_COP1_FUNCT_CEIL_W 14
#define R4300i_COP1_FUNCT_FLOOR_W 15
#define R4300i_COP1_FUNCT_CVT_S 32
#define R4300i_COP1_FUNCT_CVT_D 33
#define R4300i_COP1_FUNCT_CVT_W 36
#define R4300i_COP1_FUNCT_CVT_L 37
#define R4300i_COP1_FUNCT_C_F 48
#define R4300i_COP1_FUNCT_C_UN 49
#define R4300i_COP1_FUNCT_C_EQ 50
#define R4300i_COP1_FUNCT_C_UEQ 51
#define R4300i_COP1_FUNCT_C_OLT 52
#define R4300i_COP1_FUNCT_C_ULT 53
#define R4300i_COP1_FUNCT_C_OLE 54
#define R4300i_COP1_FUNCT_C_ULE 55
#define R4300i_COP1_FUNCT_C_SF 56
#define R4300i_COP1_FUNCT_C_NGLE 57
#define R4300i_COP1_FUNCT_C_SEQ 58
#define R4300i_COP1_FUNCT_C_NGL 59
#define R4300i_COP1_FUNCT_C_LT 60
#define R4300i_COP1_FUNCT_C_NGE 61
#define R4300i_COP1_FUNCT_C_LE 62
#define R4300i_COP1_FUNCT_C_NGT 63
#endif

View file

@ -1,285 +0,0 @@
#include <string.h>
#include "usf.h"
#include "usf_internal.h"
#include "os.h"
#include "cpu_hle.h"
#include "audio.h"
#include "interpreter_cpu.h"
#include "main.h"
#include "memory.h"
#define N64WORD(x) (*(uint32_t*)PageVRAM((x)))
#define N64HALF(x) (*(uint16_t*)PageVRAM((x)))
#define N64BYTE(x) (*(uint8_t*)PageVRAM((x^3)))
#define N64DWORD(addr) (((long long)N64WORD((addr))) << 32) + N64WORD((addr)+4);
int __osRestoreInt(usf_state_t * state, int n)
{
STATUS_REGISTER |= state->GPR[0x4].UW[0];
return 1;
}
int __osDisableInt(usf_state_t * state, int n)
{
state->GPR[0x2].UW[0] = STATUS_REGISTER & 1;
STATUS_REGISTER &= 0xFFFFFFFE;
return 1;
}
void osEnqueueThread(usf_state_t * state, uint32_t osThreadQueueAddr, uint32_t threadVAddr)
{
OSThread *thread = (OSThread*) PageVRAM(threadVAddr);
OSThread *oldThread = (OSThread*) PageVRAM(osThreadQueueAddr);
OSThread *curThread = (OSThread*) PageVRAM(oldThread->next);
while((int32_t)curThread->priority >= (int32_t)thread->priority) {
oldThread = curThread;
curThread = (OSThread*) PageVRAM(curThread->next);
}
thread->next = oldThread->next;
oldThread->next = threadVAddr;
thread->queue = osThreadQueueAddr;
}
int __osEnqueueThread(usf_state_t * state, int n) {
osEnqueueThread(state, state->GPR[4].UW[0],state->GPR[5].UW[0]);
return 1;
}
int osStartThread(usf_state_t * state, int n)
{
OSMesgQueue *osThreadQueue = NULL;
uint32_t osThreadQueueAddr = 0;
uint32_t oldStatus = STATUS_REGISTER & 1;
uint32_t osActiveThreadAddr = 0;
uint32_t osActiveThread = 0;
OSThread *thread = (OSThread*)PageVRAM(state->GPR[4].UW[0]);
STATUS_REGISTER &= 0xFFFFFFFE;
osThreadQueueAddr = ((*(uint32_t*)PageRAM2(n + 0x40)) & 0xFFFF) << 16;
osThreadQueueAddr += *(int16_t*)PageRAM2(n + 0x50);
osThreadQueue = (OSMesgQueue*) PageVRAM(osThreadQueueAddr);
if(thread->state != 8 ) {
DisplayError(state, "OMG, thread state is not OS_STATE_WAITING!\n");
return 0;
}
thread->state = OS_STATE_RUNNABLE;
osEnqueueThread(state,osThreadQueueAddr,state->GPR[4].UW[0]);
osActiveThreadAddr = ((*(uint32_t*)PageRAM2(n + 0xDC)) & 0xFFFF) << 16;
osActiveThreadAddr += *(int16_t*)PageRAM2(n + 0xE0);
osActiveThread = *(uint32_t*)PageVRAM(osActiveThreadAddr);
if(osActiveThread==0) {
DisplayError(state,"OMG, active thread is NULL!\n");
return 0;
}
STATUS_REGISTER |= oldStatus;
// CheckInterrupts();
return 1;
}
int osRecvMesg(usf_state_t * state, int n)
{
//unsigned long devAddr = state->GPR[7].UW[0];
//unsigned long vAddr = state->GPR[0x11].UW[0];
//unsigned long nbytes = state->GPR[0x10].UW[0];
//unsigned long oldStatus = STATUS_REGISTER & 1;
RunFunction(state, n | (state->PROGRAM_COUNTER & 0xF0000000));
//DisplayError("%08x\n%08x\n%08x",devAddr, vAddr, nbytes);
return 1;
}
// doesnt even use?
int osSetIntMask(usf_state_t * state, int paddr) {
#if 0
uint32_t globalIntMask = 0;
uint32_t mask = STATUS_REGISTER & 0xFF01;
uint32_t interrupts = 0;
uint32_t intAddress = 0, newMask = 0, workMask = 0;
uint32_t baseAddress = 0;
globalIntMask = ((*(uint16_t*)PageRAM2(paddr + 0x8)) & 0xFFFF) << 16;
globalIntMask += *(uint16_t*)PageRAM2(paddr + 0xc);
globalIntMask = *(uint32_t*)PageVRAM(globalIntMask);
interrupts = (globalIntMask ^ 0xffffffff) & 0xff00;
mask |= interrupts;
newMask = MI_INTR_MASK_REG;
if(!newMask)
newMask = ((globalIntMask >> 16) ^ 0xFFFFFFFF) & 0x3F;
mask |= (newMask << 16);
baseAddress = ((*(uint16_t*)PageRAM2(paddr + 0x5C)) & 0xFFFF) << 16;
baseAddress += *(int16_t*)PageRAM2(paddr + 0x64);
baseAddress += ((state->GPR[4].UW[0] & 0x3F0000) & globalIntMask) >> 15;;
MI_INTR_MASK_REG = *(uint16_t*)PageVRAM(baseAddress);
state->STATUS_REGISTER = ((state->GPR[4].UW[0] & 0xff01) & (globalIntMask & 0xff00)) | (STATUS_REGISTER & 0xFFFF00FF);
#endif
return 1;
}
int osVirtualToPhysical(usf_state_t * state, int paddr) {
uintptr_t address = 0;
uintptr_t vaddr = state->GPR[4].UW[0];
address = (state->TLB_Map[vaddr >> 12] + vaddr) - (uintptr_t)state->N64MEM;
if(address < 0x800000) {
state->GPR[2].UW[0] = (uint32_t)address;
} else
state->GPR[2].UW[0] = 0xFFFFFFFF;
return 1;
}
int osAiSetNextBuffer(usf_state_t * state, int paddr) {
uint32_t var = 0, var2 = 0;
var = ((*(int16_t*)PageRAM2(paddr + 0x4)) & 0xFFFF) << 16;
var += *(int16_t*)PageRAM2(paddr + 0x8);
var2 = N64WORD(var);
if(AI_CONTROL_REG & 0x80000000)
state->GPR[2].UW[0] = -1;
AI_DRAM_ADDR_REG = state->GPR[4].UW[0];
AI_LEN_REG = state->GPR[5].UW[0]&0x3FFF;
AiLenChanged(state);
state->GPR[2].UW[0] = 0;
return 1;
}
int saveThreadContext(usf_state_t * state, int paddr) {
#if 0
uint32_t OSThreadContextAddr = 0;
OSThreadContextAddr = ((*(int16_t*)PageRAM2(paddr)) & 0xFFFF) << 16;
OSThreadContextAddr += *(int16_t*)PageRAM2(paddr + 0x4);
OSThreadContextAddr = N64WORD(OSThreadContextAddr);
if((PageVRAM2(OSThreadContextAddr) & 0xffff) > 0xFF00) {
DisplayError(state,"OMG! Too high!");
return 0;
}
#endif
return 0;
}
int loadThreadContext(usf_state_t * state, int paddr) {
#if 0
uint32_t i = 0, OSThreadContextAddr = 0, T9 = 0, osOSThread = 0, Addr2 = 0, GlobalBitMask = 0, Tmp = 0;
uint32_t K0 = 0, K1 = 0, T0 = 0, R1 = 0, RCP = 0, intrList = 0;
OSThread t;
OSThreadContextAddr = ((*(int16_t*)PageRAM2(paddr)) & 0xFFFF) << 16;
OSThreadContextAddr += *(int16_t*)PageRAM2(paddr + 0x8);
Addr2 = ((*(int16_t*)PageRAM2(paddr + 0xC)) & 0xFFFF) << 16;
Addr2 += *(int16_t*)PageRAM2(paddr + 0x10);
GlobalBitMask = ((*(int16_t*)PageRAM2(paddr + 0x20)) & 0xFFFF) << 16;
GlobalBitMask += *(int16_t*)PageRAM2(paddr + 0x28);
GlobalBitMask = N64WORD(GlobalBitMask);
intrList = ((*(int16_t*)PageRAM2(paddr + 0x14C + 0x0)) & 0xFFFF) << 16;
intrList += *(int16_t*)PageRAM2(paddr + 0x150 + 0x0);
return 0;
if((PageVRAM2(OSThreadContextAddr) & 0xffff) > 0xFE80) {
DisplayError(state, "OMG this number is too high!!!!\n");
}
osOSThread = N64WORD(OSThreadContextAddr);
T9 = N64WORD(osOSThread);
N64WORD(OSThreadContextAddr) = T9;
N64WORD(Addr2) = osOSThread;
N64WORD(osOSThread + 0x10) = OS_STATE_RUNNING; //T0 is globalbitmask
K1 = N64WORD(osOSThread + 0x118); //osOSThread.context.k0
STATUS_REGISTER = (K1 & 0xFFFF00FF) | (GlobalBitMask & 0xFF00);
for(i = 1; i <= 0x19; i++) {
state->GPR[i].DW = N64DWORD(osOSThread + 0x18 + (i * 8));
}
for(i = 0x1C; i <= 0x1F; i++) {
state->GPR[i].DW = N64DWORD(osOSThread + 0x8 + (i * 8));
}
state->LO.DW = N64DWORD(osOSThread + 0x108);
state->HI.DW = N64DWORD(osOSThread + 0x110);
EPC_REGISTER = (uint32_t) N64WORD(osOSThread + 0x11C);
state->FPCR[31] = (uint32_t) N64WORD(osOSThread + 0x12C);
if(N64WORD(osOSThread + 0x18)) {
for(i = 0; i <= 30; i+=2) {
(*(uint64_t *)state->FPRDoubleLocation[i]) = N64DWORD(osOSThread + 0x130 + (i * 4));
}
} else {
}
state->GPR[0x1A].UW[0] = (uint32_t) osOSThread;
RCP = N64WORD(osOSThread + 0x128);
K0 = (intrList + ((RCP & (GlobalBitMask >> 16)) << 1));
K1 = 0;
r4300i_LH_VAddr(state, K0, &K1);
// cheap hack?
//K1 = 0xAAA;
SW_Register(0x0430000C, K1);
NextInstruction = JUMP;
if ((STATUS_REGISTER & STATUS_ERL) != 0) {
JumpToLocation = ERROREPC_REGISTER;
STATUS_REGISTER &= ~STATUS_ERL;
} else {
JumpToLocation = EPC_REGISTER;
STATUS_REGISTER &= ~STATUS_EXL;
}
LLBit = 0;
CheckInterrupts();
#endif
return 0;
}

View file

@ -1,89 +0,0 @@
#ifndef _CPU_HLE_OS_
#define _CPU_HLE_OS_
#include "cpu_hle.h"
#pragma pack(1)
#define OS_STATE_STOPPED 1
#define OS_STATE_RUNNABLE 2
#define OS_STATE_RUNNING 4
#define OS_STATE_WAITING 8
typedef uint32_t OSPri;
typedef uint32_t OSId;
typedef
union
{
struct
{
float f_odd;
float f_even;
} f;
double d;
}
__OSfp;
typedef struct {
uint64_t at, v0, v1, a0, a1, a2, a3;
uint64_t t0, t1, t2, t3, t4, t5, t6, t7;
uint64_t s0, s1, s2, s3, s4, s5, s6, s7;
uint64_t t8, t9, gp, sp, s8, ra;
uint64_t lo, hi;
uint32_t sr, pc, cause, badvaddr, rcp;
uint32_t fpcsr;
__OSfp fp0, fp2, fp4, fp6, fp8, fp10, fp12, fp14;
__OSfp fp16, fp18, fp20, fp22, fp24, fp26, fp28, fp30;
} __OSThreadContext;
typedef struct OSThread_s
{
uint32_t next; // run/mesg queue link
OSPri priority; // run/mesg queue priority
uint32_t queue; // queue thread is on
uint32_t tlnext; // all threads queue link
#if 0
uint16_t state; // OS_STATE_*
uint16_t flags; // flags for rmon
#endif
//swap these because of byteswapping
uint16_t flags; // flags for rmon
uint16_t state; // OS_STATE_*
OSId id; // id for debugging
int fp; // thread has used fp unit
__OSThreadContext context; // register/interrupt mask
} OSThread;
typedef void * OSMesg;
//
// Structure for message queue
//
typedef struct OSMesgQueue_s
{
OSThread *mtqueue; // Queue to store threads blocked
// on empty mailboxes (receive)
OSThread *fullqueue; // Queue to store threads blocked
// on full mailboxes (send)
int32_t validCount; // Contains number of valid message
int32_t first; // Points to first valid message
int32_t msgCount; // Contains total # of messages
OSMesg *msg; // Points to message buffer array
} OSMesgQueue;
int __osRestoreInt(usf_state_t *, int n);
int __osDisableInt(usf_state_t *, int n);
int __osEnqueueThread(usf_state_t *, int n) ;
int osStartThread(usf_state_t *, int n);
int osRecvMesg(usf_state_t *, int n);
int osSetIntMask(usf_state_t *, int paddr) ;
int osVirtualToPhysical(usf_state_t *, int paddr);
int osAiSetNextBuffer(usf_state_t *, int paddr);
int saveThreadContext(usf_state_t *, int paddr);
int loadThreadContext(usf_state_t *, int paddr);
#endif

View file

@ -30,6 +30,7 @@
#define OSAL_BREAKPOINT_INTERRUPT __asm{ int 3 };
#define ALIGN(BYTES,DATA) __declspec(align(BYTES)) DATA
#define osal_inline __inline
#define osal_fastcall __fastcall
/* string functions */
#define osal_insensitive_strcmp(x, y) _stricmp(x, y)
@ -46,6 +47,11 @@
#define OSAL_BREAKPOINT_INTERRUPT __asm__(" int $3; ");
#define ALIGN(BYTES,DATA) DATA __attribute__((aligned(BYTES)))
#define osal_inline inline
#ifdef __i386__
#define osal_fastcall __attribute__((fastcall))
#else
#define osal_fastcall
#endif
/* string functions */
#define osal_insensitive_strcmp(x, y) strcasecmp(x, y)

View file

@ -0,0 +1,91 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - cart_rom.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* 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 "usf/usf.h"
#include "usf/usf_internal.h"
#include "usf/barray.h"
#include "cart_rom.h"
#include "pi_controller.h"
void connect_cart_rom(struct cart_rom* cart_rom,
uint8_t* rom, size_t rom_size)
{
cart_rom->rom = rom;
cart_rom->rom_size = rom_size;
}
void init_cart_rom(struct cart_rom* cart_rom)
{
cart_rom->last_write = 0;
}
int read_cart_rom(void* opaque, uint32_t address, uint32_t* value)
{
struct pi_controller* pi = (struct pi_controller*)opaque;
uint32_t addr = rom_address(address);
if (pi->cart_rom.last_write != 0)
{
*value = pi->cart_rom.last_write;
pi->cart_rom.last_write = 0;
}
else
{
*value = *(uint32_t*)(pi->cart_rom.rom + addr);
}
return 0;
}
int write_cart_rom(void* opaque, uint32_t address, uint32_t value, uint32_t mask)
{
struct pi_controller* pi = (struct pi_controller*)opaque;
pi->cart_rom.last_write = value & mask;
return 0;
}
int read_cart_rom_tracked(void* opaque, uint32_t address, uint32_t* value)
{
usf_state_t* state = (usf_state_t*)opaque;
struct pi_controller* pi = &state->g_pi;
uint32_t addr = rom_address(address);
if (pi->cart_rom.last_write != 0)
{
*value = pi->cart_rom.last_write;
pi->cart_rom.last_write = 0;
}
else
{
bit_array_set(state->barray_rom, addr / 4);
*value = *(uint32_t*)(pi->cart_rom.rom + addr);
}
return 0;
}

View file

@ -0,0 +1,53 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - cart_rom.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_PI_CART_ROM_H
#define M64P_PI_CART_ROM_H
#include <stddef.h>
#include <stdint.h>
#include "osal/preproc.h"
struct cart_rom
{
uint8_t* rom;
size_t rom_size;
uint32_t last_write;
};
static osal_inline uint32_t rom_address(uint32_t address)
{
return (address & 0x03fffffc);
}
void connect_cart_rom(struct cart_rom* cart_rom,
uint8_t* rom, size_t rom_size);
void init_cart_rom(struct cart_rom* cart_rom);
int read_cart_rom(void* opaque, uint32_t address, uint32_t* value);
int write_cart_rom(void* opaque, uint32_t address, uint32_t value, uint32_t mask);
int read_cart_rom_tracked(void* opaque, uint32_t address, uint32_t* value);
#endif

View file

@ -0,0 +1,249 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - pi_controller.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* 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 "usf/usf.h"
#include "usf/usf_internal.h"
#include "usf/barray.h"
#include "pi_controller.h"
#define M64P_CORE_PROTOTYPES 1
#include "api/m64p_types.h"
#include "api/callbacks.h"
#include "main/rom.h"
#include "memory/memory.h"
#include "r4300/cached_interp.h"
#include "r4300/cp0.h"
#include "r4300/interupt.h"
#include "r4300/new_dynarec/new_dynarec.h"
#include "r4300/ops.h"
#include "r4300/r4300.h"
#include "r4300/r4300_core.h"
#include "ri/rdram_detection_hack.h"
#include "ri/ri_controller.h"
#include <string.h>
static void dma_pi_read(usf_state_t * state, struct pi_controller* pi)
{
if (pi->regs[PI_CART_ADDR_REG] >= 0x08000000 && pi->regs[PI_CART_ADDR_REG] < 0x08010000)
{
}
else
{
DebugMessage(state, M64MSG_WARNING, "Unknown dma read in dma_pi_read()");
}
pi->regs[PI_STATUS_REG] |= 1;
update_count(state);
add_interupt_event(state, PI_INT, state->g_delay_pi ? 0x1000/*pi->regs[PI_RD_LEN_REG]*/ : 0);
}
static void dma_pi_write(usf_state_t * state, struct pi_controller* pi)
{
unsigned int longueur;
int i;
#ifdef DEBUG_INFO
fprintf(state->debug_log, "PI DMA WRITE: %08x to %08x for %08x bytes\n", pi->regs[PI_CART_ADDR_REG], pi->regs[PI_DRAM_ADDR_REG], pi->regs[PI_WR_LEN_REG] + 1);
#endif
if (pi->regs[PI_CART_ADDR_REG] < 0x10000000)
{
if (pi->regs[PI_CART_ADDR_REG] >= 0x08000000 && pi->regs[PI_CART_ADDR_REG] < 0x08010000)
{
}
else if (pi->regs[PI_CART_ADDR_REG] >= 0x06000000 && pi->regs[PI_CART_ADDR_REG] < 0x08000000)
{
}
else
{
DebugMessage(state, M64MSG_WARNING, "Unknown dma write 0x%x in dma_pi_write()", (int)pi->regs[PI_CART_ADDR_REG]);
}
pi->regs[PI_STATUS_REG] |= 1;
update_count(state);
add_interupt_event(state, PI_INT, state->g_delay_pi ? /*pi->regs[PI_WR_LEN_REG]*/0x1000 : 0);
return;
}
if (pi->regs[PI_CART_ADDR_REG] >= 0x1fc00000) // for paper mario
{
pi->regs[PI_STATUS_REG] |= 1;
update_count(state);
add_interupt_event(state, PI_INT, state->g_delay_pi ? 0x1000 : 0);
return;
}
longueur = (pi->regs[PI_WR_LEN_REG] & 0xFFFFFF)+1;
i = (pi->regs[PI_CART_ADDR_REG]-0x10000000)&0x3FFFFFF;
longueur = (i + (int) longueur) > pi->cart_rom.rom_size ?
(pi->cart_rom.rom_size - i) : longueur;
longueur = (pi->regs[PI_DRAM_ADDR_REG] + longueur) > 0x7FFFFF ?
(0x7FFFFF - pi->regs[PI_DRAM_ADDR_REG]) : longueur;
if (i > pi->cart_rom.rom_size || pi->regs[PI_DRAM_ADDR_REG] > 0x7FFFFF)
{
pi->regs[PI_STATUS_REG] |= 3;
update_count(state);
add_interupt_event(state, PI_INT, state->g_delay_pi ? longueur/8 : 0);
return;
}
if (state->r4300emu != CORE_PURE_INTERPRETER)
{
for (i=0; i<(int)longueur; i++)
{
unsigned long rdram_address1 = pi->regs[PI_DRAM_ADDR_REG]+i+0x80000000;
unsigned long rdram_address2 = pi->regs[PI_DRAM_ADDR_REG]+i+0xa0000000;
unsigned long rom_address = (((pi->regs[PI_CART_ADDR_REG]-0x10000000)&0x3FFFFFF)+i);
if (state->enable_trimming_mode)
bit_array_set(state->barray_rom, rom_address / 4);
((unsigned char*)pi->ri->rdram.dram)[(pi->regs[PI_DRAM_ADDR_REG]+i)^S8]=
pi->cart_rom.rom[rom_address^S8];
if (!state->invalid_code[rdram_address1>>12])
{
if (!state->blocks[rdram_address1>>12] ||
state->blocks[rdram_address1>>12]->block[(rdram_address1&0xFFF)/4].ops !=
state->current_instruction_table.NOTCOMPILED)
{
state->invalid_code[rdram_address1>>12] = 1;
}
#ifdef NEW_DYNAREC
invalidate_block(state, rdram_address1>>12);
#endif
}
if (!state->invalid_code[rdram_address2>>12])
{
if (!state->blocks[rdram_address1>>12] ||
state->blocks[rdram_address2>>12]->block[(rdram_address2&0xFFF)/4].ops !=
state->current_instruction_table.NOTCOMPILED)
{
state->invalid_code[rdram_address2>>12] = 1;
}
}
}
}
else
{
for (i=0; i<(int)longueur; i++)
{
unsigned long rom_address = (((pi->regs[PI_CART_ADDR_REG]-0x10000000)&0x3FFFFFF)+i);
if (state->enable_trimming_mode)
bit_array_set(state->barray_rom, rom_address / 4);
((unsigned char*)pi->ri->rdram.dram)[(pi->regs[PI_DRAM_ADDR_REG]+i)^S8]=
pi->cart_rom.rom[rom_address^S8];
}
}
/* HACK: monitor PI DMA to trigger RDRAM size detection
* hack just before initial cart ROM loading. */
if (pi->regs[PI_CART_ADDR_REG] == 0x10001000)
{
force_detected_rdram_size_hack(state);
}
pi->regs[PI_STATUS_REG] |= 3;
update_count(state);
add_interupt_event(state, PI_INT, state->g_delay_pi ? longueur/8 : 0);
return;
}
void connect_pi(struct pi_controller* pi,
struct r4300_core* r4300,
struct ri_controller* ri,
uint8_t* rom, size_t rom_size)
{
connect_cart_rom(&pi->cart_rom, rom, rom_size);
pi->r4300 = r4300;
pi->ri = ri;
}
void init_pi(struct pi_controller* pi)
{
memset(pi->regs, 0, PI_REGS_COUNT*sizeof(uint32_t));
}
int read_pi_regs(void* opaque, uint32_t address, uint32_t* value)
{
struct pi_controller* pi = (struct pi_controller*)opaque;
uint32_t reg = pi_reg(address);
*value = pi->regs[reg];
return 0;
}
int write_pi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask)
{
struct pi_controller* pi = (struct pi_controller*)opaque;
uint32_t reg = pi_reg(address);
switch (reg)
{
case PI_RD_LEN_REG:
masked_write(&pi->regs[PI_RD_LEN_REG], value, mask);
dma_pi_read(pi->r4300->state, pi);
return 0;
case PI_WR_LEN_REG:
masked_write(&pi->regs[PI_WR_LEN_REG], value, mask);
dma_pi_write(pi->r4300->state, pi);
return 0;
case PI_STATUS_REG:
if (value & mask & 2)
clear_rcp_interrupt(pi->r4300, MI_INTR_PI);
return 0;
case PI_BSD_DOM1_LAT_REG:
case PI_BSD_DOM1_PWD_REG:
case PI_BSD_DOM1_PGS_REG:
case PI_BSD_DOM1_RLS_REG:
case PI_BSD_DOM2_LAT_REG:
case PI_BSD_DOM2_PWD_REG:
case PI_BSD_DOM2_PGS_REG:
case PI_BSD_DOM2_RLS_REG:
masked_write(&pi->regs[reg], value & 0xff, mask);
return 0;
}
masked_write(&pi->regs[reg], value, mask);
return 0;
}
void pi_end_of_dma_event(struct pi_controller* pi)
{
pi->regs[PI_STATUS_REG] &= ~3;
raise_rcp_interrupt(pi->r4300, MI_INTR_PI);
}

View file

@ -0,0 +1,81 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - pi_controller.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_PI_PI_CONTROLLER_H
#define M64P_PI_PI_CONTROLLER_H
#include <stddef.h>
#include <stdint.h>
#include "cart_rom.h"
struct r4300_core;
struct ri_controller;
enum pi_registers
{
PI_DRAM_ADDR_REG,
PI_CART_ADDR_REG,
PI_RD_LEN_REG,
PI_WR_LEN_REG,
PI_STATUS_REG,
PI_BSD_DOM1_LAT_REG,
PI_BSD_DOM1_PWD_REG,
PI_BSD_DOM1_PGS_REG,
PI_BSD_DOM1_RLS_REG,
PI_BSD_DOM2_LAT_REG,
PI_BSD_DOM2_PWD_REG,
PI_BSD_DOM2_PGS_REG,
PI_BSD_DOM2_RLS_REG,
PI_REGS_COUNT
};
struct pi_controller
{
uint32_t regs[PI_REGS_COUNT];
struct cart_rom cart_rom;
struct r4300_core* r4300;
struct ri_controller* ri;
};
#include "osal/preproc.h"
static osal_inline uint32_t pi_reg(uint32_t address)
{
return (address & 0xffff) >> 2;
}
void connect_pi(struct pi_controller* pi,
struct r4300_core* r4300,
struct ri_controller* ri,
uint8_t* rom, size_t rom_size);
void init_pi(struct pi_controller* pi);
int read_pi_regs(void* opaque, uint32_t address, uint32_t* value);
int write_pi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask);
void pi_end_of_dma_event(struct pi_controller* pi);
#endif

View file

@ -1,99 +0,0 @@
/*
* Project 64 - A Nintendo 64 emulator.
*
* (c) Copyright 2001 zilmar (zilmar@emulation64.com) and
* Jabo (jabo@emulation64.com).
*
* pj64 homepage: www.pj64.net
*
* Permission to use, copy, modify and distribute Project64 in both binary and
* source form, for non-commercial purposes, is hereby granted without fee,
* providing that this license information and copyright notice appear with
* all copies and any derived work.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event shall the authors be held liable for any damages
* arising from the use of this software.
*
* Project64 is freeware for PERSONAL USE only. Commercial users should
* seek permission of the copyright holders first. Commercial use includes
* charging money for Project64 or software derived from Project64.
*
* The copyright holders request that bug fixes and improvements to the code
* should be forwarded to them so if they want them.
*
*/
#include "usf.h"
#include "main.h"
#include "cpu.h"
#include "usf_internal.h"
// Skeletal support so USFs that read the controller won't fail (bad practice, though)
void ProcessControllerCommand ( usf_state_t * state, int32_t Control, uint8_t * Command);
void PifRamRead (usf_state_t * state) {
int32_t Channel, CurPos;
Channel = 0;
CurPos = 0;
do {
switch(state->PIF_Ram[CurPos]) {
case 0x00:
Channel += 1;
if (Channel > 6) { CurPos = 0x40; }
break;
case 0xFE: CurPos = 0x40; break;
case 0xFF: break;
case 0xB4: case 0x56: case 0xB8: break; /* ??? */
default:
if ((state->PIF_Ram[CurPos] & 0xC0) == 0) {
CurPos += state->PIF_Ram[CurPos] + (state->PIF_Ram[CurPos + 1] & 0x3F) + 1;
Channel += 1;
} else {
CurPos = 0x40;
}
break;
}
CurPos += 1;
} while( CurPos < 0x40 );
}
void PifRamWrite (usf_state_t * state) {
int Channel, CurPos;
Channel = 0;
for (CurPos = 0; CurPos < 0x40; CurPos++){
switch(state->PIF_Ram[CurPos]) {
case 0x00:
Channel += 1;
if (Channel > 6) { CurPos = 0x40; }
break;
case 0xFE: CurPos = 0x40; break;
case 0xFF: break;
case 0xB4: case 0x56: case 0xB8: break; /* ??? */
default:
if ((state->PIF_Ram[CurPos] & 0xC0) == 0) {
if (Channel < 4) {
ProcessControllerCommand(state,Channel,&state->PIF_Ram[CurPos]);
}
CurPos += state->PIF_Ram[CurPos] + (state->PIF_Ram[CurPos + 1] & 0x3F) + 1;
Channel += 1;
} else
CurPos = 0x40;
break;
}
}
state->PIF_Ram[0x3F] = 0;
}
// always return failure
void ProcessControllerCommand ( usf_state_t * state, int32_t Control, uint8_t * Command) {
(void)state;
(void)Control;
Command[1] |= 0x80;
}

View file

@ -1,29 +0,0 @@
/*
* Project 64 - A Nintendo 64 emulator.
*
* (c) Copyright 2001 zilmar (zilmar@emulation64.com) and
* Jabo (jabo@emulation64.com).
*
* pj64 homepage: www.pj64.net
*
* Permission to use, copy, modify and distribute Project64 in both binary and
* source form, for non-commercial purposes, is hereby granted without fee,
* providing that this license information and copyright notice appear with
* all copies and any derived work.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event shall the authors be held liable for any damages
* arising from the use of this software.
*
* Project64 is freeware for PERSONAL USE only. Commercial users should
* seek permission of the copyright holders first. Commercial use includes
* charging money for Project64 or software derived from Project64.
*
* The copyright holders request that bug fixes and improvements to the code
* should be forwarded to them so if they want them.
*
*/
extern uint8_t *PIF_Ram;
void PifRamWrite ( usf_state_t * );
void PifRamRead ( usf_state_t * );

View file

@ -0,0 +1,567 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - cached_interp.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 "cached_interp.h"
#include "api/m64p_types.h"
#include "api/callbacks.h"
#include "main/main.h"
#include "memory/memory.h"
#include "r4300.h"
#include "cp0.h"
#include "cp1.h"
#include "ops.h"
#include "exception.h"
#include "interupt.h"
#include "macros.h"
#include "recomp.h"
#include "tlb.h"
// -----------------------------------------------------------
// Cached interpreter functions (and fallback for dynarec).
// -----------------------------------------------------------
#define UPDATE_DEBUGGER() do { } while(0)
#define PCADDR state->PC->addr
#define ADD_TO_PC(x) state->PC += x;
#define DECLARE_INSTRUCTION(name) static void osal_fastcall name(usf_state_t * state)
#define DECLARE_JUMP(name, destination, condition, link, likely, cop1) \
static void osal_fastcall name(usf_state_t * state) \
{ \
const int take_jump = (condition); \
const unsigned int jump_target = (destination); \
long long int *link_register = (link); \
if (cop1 && check_cop1_unusable(state)) return; \
if (link_register != &state->reg[0]) \
{ \
*link_register=state->PC->addr + 8; \
sign_extended(*link_register); \
} \
if (!likely || take_jump) \
{ \
state->PC++; \
state->delay_slot=1; \
UPDATE_DEBUGGER(); \
state->PC->ops(state); \
update_count(state); \
state->delay_slot=0; \
if (take_jump && !state->skip_jump) \
{ \
state->PC=state->actual->block+((jump_target-state->actual->start)>>2); \
} \
} \
else \
{ \
state->PC += 2; \
update_count(state); \
} \
state->last_addr = state->PC->addr; \
if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state); \
} \
static void osal_fastcall name##_OUT(usf_state_t * state) \
{ \
const int take_jump = (condition); \
const unsigned int jump_target = (destination); \
long long int *link_register = (link); \
if (cop1 && check_cop1_unusable(state)) return; \
if (link_register != &state->reg[0]) \
{ \
*link_register=state->PC->addr + 8; \
sign_extended(*link_register); \
} \
if (!likely || take_jump) \
{ \
state->PC++; \
state->delay_slot=1; \
UPDATE_DEBUGGER(); \
state->PC->ops(state); \
update_count(state); \
state->delay_slot=0; \
if (take_jump && !state->skip_jump) \
{ \
jump_to(jump_target); \
} \
} \
else \
{ \
state->PC += 2; \
update_count(state); \
} \
state->last_addr = state->PC->addr; \
if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state); \
} \
static void osal_fastcall name##_IDLE(usf_state_t * state) \
{ \
const int take_jump = (condition); \
int skip; \
if (cop1 && check_cop1_unusable(state)) return; \
if (take_jump) \
{ \
update_count(state); \
skip = state->next_interupt - state->g_cp0_regs[CP0_COUNT_REG]; \
if (skip > 3) state->g_cp0_regs[CP0_COUNT_REG] += (skip & 0xFFFFFFFC); \
else name(state); \
} \
else name(state); \
}
#define CHECK_MEMORY() \
if (!state->invalid_code[state->address>>12]) \
if (state->blocks[state->address>>12]->block[(state->address&0xFFF)/4].ops != \
state->current_instruction_table.NOTCOMPILED) \
state->invalid_code[state->address>>12] = 1;
// two functions are defined from the macros above but never used
// these prototype declarations will prevent a warning
#if defined(__GNUC__)
static void osal_fastcall JR_IDLE(usf_state_t *) __attribute__((used));
static void osal_fastcall JALR_IDLE(usf_state_t *) __attribute__((used));
#endif
#include "interpreter.def"
// -----------------------------------------------------------
// Flow control 'fake' instructions
// -----------------------------------------------------------
static void osal_fastcall FIN_BLOCK(usf_state_t * state)
{
if (!state->delay_slot)
{
jump_to((state->PC-1)->addr+4);
/*#ifdef DBG
if (g_DebuggerActive) update_debugger(PC->addr);
#endif
Used by dynarec only, check should be unnecessary
*/
state->PC->ops(state);
if (state->r4300emu == CORE_DYNAREC) dyna_jump(state);
}
else
{
precomp_block *blk = state->actual;
precomp_instr *inst = state->PC;
jump_to((state->PC-1)->addr+4);
/*#ifdef DBG
if (g_DebuggerActive) update_debugger(PC->addr);
#endif
Used by dynarec only, check should be unnecessary
*/
if (!state->skip_jump)
{
state->PC->ops(state);
state->actual = blk;
state->PC = inst+1;
}
else
state->PC->ops(state);
if (state->r4300emu == CORE_DYNAREC) dyna_jump(state);
}
}
static void osal_fastcall NOTCOMPILED(usf_state_t * state)
{
unsigned int *mem = fast_mem_access(state, state->blocks[state->PC->addr>>12]->start);
if (mem != NULL)
recompile_block(state, (int *)mem, state->blocks[state->PC->addr >> 12], state->PC->addr);
else
DebugMessage(state, M64MSG_ERROR, "not compiled exception");
/*#ifdef DBG
if (g_DebuggerActive) update_debugger(PC->addr);
#endif
The preceeding update_debugger SHOULD be unnecessary since it should have been
called before NOTCOMPILED would have been executed
*/
state->PC->ops(state);
if (state->r4300emu == CORE_DYNAREC)
dyna_jump(state);
}
static void osal_fastcall NOTCOMPILED2(usf_state_t * state)
{
NOTCOMPILED(state);
}
// -----------------------------------------------------------
// Cached interpreter instruction table
// -----------------------------------------------------------
const cpu_instruction_table cached_interpreter_table = {
LB,
LBU,
LH,
LHU,
LW,
LWL,
LWR,
SB,
SH,
SW,
SWL,
SWR,
LD,
LDL,
LDR,
LL,
LWU,
SC,
SD,
SDL,
SDR,
SYNC,
ADDI,
ADDIU,
SLTI,
SLTIU,
ANDI,
ORI,
XORI,
LUI,
DADDI,
DADDIU,
ADD,
ADDU,
SUB,
SUBU,
SLT,
SLTU,
AND,
OR,
XOR,
NOR,
DADD,
DADDU,
DSUB,
DSUBU,
MULT,
MULTU,
DIV,
DIVU,
MFHI,
MTHI,
MFLO,
MTLO,
DMULT,
DMULTU,
DDIV,
DDIVU,
J,
J_OUT,
J_IDLE,
JAL,
JAL_OUT,
JAL_IDLE,
// Use the _OUT versions of JR and JALR, since we don't know
// until runtime if they're going to jump inside or outside the block
JR_OUT,
JALR_OUT,
BEQ,
BEQ_OUT,
BEQ_IDLE,
BNE,
BNE_OUT,
BNE_IDLE,
BLEZ,
BLEZ_OUT,
BLEZ_IDLE,
BGTZ,
BGTZ_OUT,
BGTZ_IDLE,
BLTZ,
BLTZ_OUT,
BLTZ_IDLE,
BGEZ,
BGEZ_OUT,
BGEZ_IDLE,
BLTZAL,
BLTZAL_OUT,
BLTZAL_IDLE,
BGEZAL,
BGEZAL_OUT,
BGEZAL_IDLE,
BEQL,
BEQL_OUT,
BEQL_IDLE,
BNEL,
BNEL_OUT,
BNEL_IDLE,
BLEZL,
BLEZL_OUT,
BLEZL_IDLE,
BGTZL,
BGTZL_OUT,
BGTZL_IDLE,
BLTZL,
BLTZL_OUT,
BLTZL_IDLE,
BGEZL,
BGEZL_OUT,
BGEZL_IDLE,
BLTZALL,
BLTZALL_OUT,
BLTZALL_IDLE,
BGEZALL,
BGEZALL_OUT,
BGEZALL_IDLE,
BC1TL,
BC1TL_OUT,
BC1TL_IDLE,
BC1FL,
BC1FL_OUT,
BC1FL_IDLE,
SLL,
SRL,
SRA,
SLLV,
SRLV,
SRAV,
DSLL,
DSRL,
DSRA,
DSLLV,
DSRLV,
DSRAV,
DSLL32,
DSRL32,
DSRA32,
MTC0,
MFC0,
TLBR,
TLBWI,
TLBWR,
TLBP,
CACHE,
ERET,
LWC1,
SWC1,
MTC1,
MFC1,
CTC1,
CFC1,
BC1T,
BC1T_OUT,
BC1T_IDLE,
BC1F,
BC1F_OUT,
BC1F_IDLE,
DMFC1,
DMTC1,
LDC1,
SDC1,
CVT_S_D,
CVT_S_W,
CVT_S_L,
CVT_D_S,
CVT_D_W,
CVT_D_L,
CVT_W_S,
CVT_W_D,
CVT_L_S,
CVT_L_D,
ROUND_W_S,
ROUND_W_D,
ROUND_L_S,
ROUND_L_D,
TRUNC_W_S,
TRUNC_W_D,
TRUNC_L_S,
TRUNC_L_D,
CEIL_W_S,
CEIL_W_D,
CEIL_L_S,
CEIL_L_D,
FLOOR_W_S,
FLOOR_W_D,
FLOOR_L_S,
FLOOR_L_D,
ADD_S,
ADD_D,
SUB_S,
SUB_D,
MUL_S,
MUL_D,
DIV_S,
DIV_D,
ABS_S,
ABS_D,
MOV_S,
MOV_D,
NEG_S,
NEG_D,
SQRT_S,
SQRT_D,
C_F_S,
C_F_D,
C_UN_S,
C_UN_D,
C_EQ_S,
C_EQ_D,
C_UEQ_S,
C_UEQ_D,
C_OLT_S,
C_OLT_D,
C_ULT_S,
C_ULT_D,
C_OLE_S,
C_OLE_D,
C_ULE_S,
C_ULE_D,
C_SF_S,
C_SF_D,
C_NGLE_S,
C_NGLE_D,
C_SEQ_S,
C_SEQ_D,
C_NGL_S,
C_NGL_D,
C_LT_S,
C_LT_D,
C_NGE_S,
C_NGE_D,
C_LE_S,
C_LE_D,
C_NGT_S,
C_NGT_D,
SYSCALL,
BREAK,
TEQ,
NOP,
RESERVED,
NI,
FIN_BLOCK,
NOTCOMPILED,
NOTCOMPILED2
};
static unsigned int osal_fastcall update_invalid_addr(usf_state_t * state, unsigned int addr)
{
if (addr >= 0x80000000 && addr < 0xc0000000)
{
if (state->invalid_code[addr>>12]) state->invalid_code[(addr^0x20000000)>>12] = 1;
if (state->invalid_code[(addr^0x20000000)>>12]) state->invalid_code[addr>>12] = 1;
return addr;
}
else
{
unsigned int paddr = virtual_to_physical_address(state, addr, 2);
if (paddr)
{
unsigned int beg_paddr = paddr - (addr - (addr&~0xFFF));
update_invalid_addr(state, paddr);
if (state->invalid_code[(beg_paddr+0x000)>>12]) state->invalid_code[addr>>12] = 1;
if (state->invalid_code[(beg_paddr+0xFFC)>>12]) state->invalid_code[addr>>12] = 1;
if (state->invalid_code[addr>>12]) state->invalid_code[(beg_paddr+0x000)>>12] = 1;
if (state->invalid_code[addr>>12]) state->invalid_code[(beg_paddr+0xFFC)>>12] = 1;
}
return paddr;
}
}
#define addr state->jump_to_address
void osal_fastcall jump_to_func(usf_state_t * state)
{
unsigned int paddr;
if (state->skip_jump) return;
paddr = update_invalid_addr(state, addr);
if (!paddr) return;
state->actual = state->blocks[addr>>12];
if (state->invalid_code[addr>>12])
{
if (!state->blocks[addr>>12])
{
state->blocks[addr>>12] = (precomp_block *) malloc(sizeof(precomp_block));
state->actual = state->blocks[addr>>12];
state->blocks[addr>>12]->code = NULL;
state->blocks[addr>>12]->block = NULL;
state->blocks[addr>>12]->jumps_table = NULL;
state->blocks[addr>>12]->riprel_table = NULL;
}
state->blocks[addr>>12]->start = addr & ~0xFFF;
state->blocks[addr>>12]->end = (addr & ~0xFFF) + 0x1000;
init_block(state, state->blocks[addr>>12]);
}
state->PC=state->actual->block+((addr-state->actual->start)>>2);
if (state->r4300emu == CORE_DYNAREC) dyna_jump(state);
}
#undef addr
void osal_fastcall init_blocks(usf_state_t * state)
{
int i;
for (i=0; i<0x100000; i++)
{
state->invalid_code[i] = 1;
state->blocks[i] = NULL;
}
}
void osal_fastcall free_blocks(usf_state_t * state)
{
int i;
for (i=0; i<0x100000; i++)
{
if (state->blocks[i])
{
free_block(state, state->blocks[i]);
free(state->blocks[i]);
state->blocks[i] = NULL;
}
}
}

View file

@ -0,0 +1,44 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - cached_interp.h *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_R4300_CACHED_INTERP_H
#define M64P_R4300_CACHED_INTERP_H
#include "usf/usf.h"
#include "osal/preproc.h"
#include "ops.h"
/* FIXME: use forward declaration for precomp_block */
#include "recomp.h"
#include "osal/preproc.h"
extern const cpu_instruction_table cached_interpreter_table;
void osal_fastcall init_blocks(usf_state_t *);
void osal_fastcall free_blocks(usf_state_t *);
void osal_fastcall jump_to_func(usf_state_t *);
/* Jumps to the given address. This is for the cached interpreter / dynarec. */
#define jump_to(a) { state->jump_to_address = a; jump_to_func(state); }
#endif /* M64P_R4300_CACHED_INTERP_H */

View file

@ -0,0 +1,70 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - cp0.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 "usf/usf.h"
#include "usf/usf_internal.h"
#include "r4300.h"
#include "cp0.h"
#include "exception.h"
#include "new_dynarec/new_dynarec.h"
#ifdef COMPARE_CORE
#include "api/debugger.h"
#endif
#ifdef DBG
#include "debugger/dbg_types.h"
#include "debugger/debugger.h"
#endif
/* global functions */
int osal_fastcall check_cop1_unusable(usf_state_t * state)
{
if (!(state->g_cp0_regs[CP0_STATUS_REG] & 0x20000000))
{
state->g_cp0_regs[CP0_CAUSE_REG] = (11 << 2) | 0x10000000;
exception_general(state);
return 1;
}
return 0;
}
void update_count(usf_state_t * state)
{
#ifdef NEW_DYNAREC
if (r4300emu != CORE_DYNAREC)
{
#endif
state->g_cp0_regs[CP0_COUNT_REG] += ((state->PC->addr - state->last_addr) >> 2) * state->count_per_op;
state->last_addr = state->PC->addr;
#ifdef NEW_DYNAREC
}
#endif
/*#ifdef DBG
if (g_DebuggerActive && !delay_slot) update_debugger(PC->addr);
#endif
*/
}

View file

@ -0,0 +1,61 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - cp0.h *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_R4300_CP0_H
#define M64P_R4300_CP0_H
#include "usf/usf.h"
enum {
CP0_INDEX_REG,
CP0_RANDOM_REG,
CP0_ENTRYLO0_REG,
CP0_ENTRYLO1_REG,
CP0_CONTEXT_REG,
CP0_PAGEMASK_REG,
CP0_WIRED_REG,
/* 7 is unused */
CP0_BADVADDR_REG = 8,
CP0_COUNT_REG,
CP0_ENTRYHI_REG,
CP0_COMPARE_REG,
CP0_STATUS_REG,
CP0_CAUSE_REG,
CP0_EPC_REG,
CP0_PREVID_REG,
CP0_CONFIG_REG,
CP0_LLADDR_REG,
CP0_WATCHLO_REG,
CP0_WATCHHI_REG,
CP0_XCONTEXT_REG,
/* 21 - 27 are unused */
CP0_TAGLO_REG = 28,
CP0_TAGHI_REG,
CP0_ERROREPC_REG,
/* 31 is unused */
CP0_REGS_COUNT = 32
};
int osal_fastcall check_cop1_unusable(usf_state_t *);
void update_count(usf_state_t *);
#endif /* M64P_R4300_CP0_H */

View file

@ -0,0 +1,110 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - cp1.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 "usf/usf.h"
#include "new_dynarec/new_dynarec.h"
#include "usf/usf_internal.h"
/* Refer to Figure 6-2 on page 155 and explanation on page B-11
of MIPS R4000 Microprocessor User's Manual (Second Edition)
by Joe Heinrich.
*/
void shuffle_fpr_data(usf_state_t * state, int oldStatus, int newStatus)
{
#if defined(M64P_BIG_ENDIAN)
const int isBigEndian = 1;
#else
const int isBigEndian = 0;
#endif
if ((newStatus & 0x04000000) != (oldStatus & 0x04000000))
{
int i;
int temp_fgr_32[32];
// pack or unpack the FGR register data
if (newStatus & 0x04000000)
{ // switching into 64-bit mode
// retrieve 32 FPR values from packed 32-bit FGR registers
for (i = 0; i < 32; i++)
{
temp_fgr_32[i] = *((int *) &state->reg_cop1_fgr_64[i>>1] + ((i & 1) ^ isBigEndian));
}
// unpack them into 32 64-bit registers, taking the high 32-bits from their temporary place in the upper 16 FGRs
for (i = 0; i < 32; i++)
{
int high32 = *((int *) &state->reg_cop1_fgr_64[(i>>1)+16] + (i & 1));
*((int *) &state->reg_cop1_fgr_64[i] + isBigEndian) = temp_fgr_32[i];
*((int *) &state->reg_cop1_fgr_64[i] + (isBigEndian^1)) = high32;
}
}
else
{ // switching into 32-bit mode
// retrieve the high 32 bits from each 64-bit FGR register and store in temp array
for (i = 0; i < 32; i++)
{
temp_fgr_32[i] = *((int *) &state->reg_cop1_fgr_64[i] + (isBigEndian^1));
}
// take the low 32 bits from each register and pack them together into 64-bit pairs
for (i = 0; i < 16; i++)
{
unsigned int least32 = *((unsigned int *) &state->reg_cop1_fgr_64[i*2] + isBigEndian);
unsigned int most32 = *((unsigned int *) &state->reg_cop1_fgr_64[i*2+1] + isBigEndian);
state->reg_cop1_fgr_64[i] = ((unsigned long long) most32 << 32) | (unsigned long long) least32;
}
// store the high bits in the upper 16 FGRs, which wont be accessible in 32-bit mode
for (i = 0; i < 32; i++)
{
*((int *) &state->reg_cop1_fgr_64[(i>>1)+16] + (i & 1)) = temp_fgr_32[i];
}
}
}
}
void set_fpr_pointers(usf_state_t * state, int newStatus)
{
int i;
#if defined(M64P_BIG_ENDIAN)
const int isBigEndian = 1;
#else
const int isBigEndian = 0;
#endif
// update the FPR register pointers
if (newStatus & 0x04000000)
{
for (i = 0; i < 32; i++)
{
state->reg_cop1_double[i] = (double*) &state->reg_cop1_fgr_64[i];
state->reg_cop1_simple[i] = ((float*) &state->reg_cop1_fgr_64[i]) + isBigEndian;
}
}
else
{
for (i = 0; i < 32; i++)
{
state->reg_cop1_double[i] = (double*) &state->reg_cop1_fgr_64[i>>1];
state->reg_cop1_simple[i] = ((float*) &state->reg_cop1_fgr_64[i>>1]) + ((i & 1) ^ isBigEndian);
}
}
}

View file

@ -0,0 +1,31 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - cp1.h *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_R4300_CP1_H
#define M64P_R4300_CP1_H
#include "usf/usf.h"
void shuffle_fpr_data(usf_state_t *, int oldStatus, int newStatus);
void set_fpr_pointers(usf_state_t *, int newStatus);
#endif /* M64P_R4300_CP1_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,149 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - exception.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 "usf/usf.h"
#include "usf/usf_internal.h"
#include "api/m64p_types.h"
#include "api/callbacks.h"
#include "memory/memory.h"
#include "exception.h"
#include "r4300.h"
#include "cp0.h"
#include "recomph.h"
#include "tlb.h"
void TLB_refill_exception(usf_state_t * state, unsigned int address, int w)
{
int usual_handler = 0, i;
if (state->r4300emu != CORE_DYNAREC && w != 2) update_count(state);
if (w == 1) state->g_cp0_regs[CP0_CAUSE_REG] = (3 << 2);
else state->g_cp0_regs[CP0_CAUSE_REG] = (2 << 2);
state->g_cp0_regs[CP0_BADVADDR_REG] = address;
state->g_cp0_regs[CP0_CONTEXT_REG] = (state->g_cp0_regs[CP0_CONTEXT_REG] & 0xFF80000F) | ((address >> 9) & 0x007FFFF0);
state->g_cp0_regs[CP0_ENTRYHI_REG] = address & 0xFFFFE000;
if (state->g_cp0_regs[CP0_STATUS_REG] & 0x2) // Test de EXL
{
generic_jump_to(state, 0x80000180);
if(state->delay_slot==1 || state->delay_slot==3) state->g_cp0_regs[CP0_CAUSE_REG] |= 0x80000000;
else state->g_cp0_regs[CP0_CAUSE_REG] &= 0x7FFFFFFF;
}
else
{
if (state->r4300emu != CORE_PURE_INTERPRETER)
{
if (w!=2)
state->g_cp0_regs[CP0_EPC_REG] = state->PC->addr;
else
state->g_cp0_regs[CP0_EPC_REG] = address;
}
else state->g_cp0_regs[CP0_EPC_REG] = state->PC->addr;
state->g_cp0_regs[CP0_CAUSE_REG] &= ~0x80000000;
state->g_cp0_regs[CP0_STATUS_REG] |= 0x2; //EXL=1
if (address >= 0x80000000 && address < 0xc0000000)
usual_handler = 1;
for (i=0; i<32; i++)
{
if (/*state->tlb_e[i].v_even &&*/ address >= state->tlb_e[i].start_even &&
address <= state->tlb_e[i].end_even)
usual_handler = 1;
if (/*state->tlb_e[i].v_odd &&*/ address >= state->tlb_e[i].start_odd &&
address <= state->tlb_e[i].end_odd)
usual_handler = 1;
}
if (usual_handler)
{
generic_jump_to(state, 0x80000180);
}
else
{
generic_jump_to(state, 0x80000000);
}
}
if(state->delay_slot==1 || state->delay_slot==3)
{
state->g_cp0_regs[CP0_CAUSE_REG] |= 0x80000000;
state->g_cp0_regs[CP0_EPC_REG]-=4;
}
else
{
state->g_cp0_regs[CP0_CAUSE_REG] &= 0x7FFFFFFF;
}
if(w != 2) state->g_cp0_regs[CP0_EPC_REG]-=4;
state->last_addr = state->PC->addr;
if (state->r4300emu == CORE_DYNAREC)
{
dyna_jump(state);
if (!state->dyna_interp) state->delay_slot = 0;
}
if (state->r4300emu != CORE_DYNAREC || state->dyna_interp)
{
state->dyna_interp = 0;
if (state->delay_slot)
{
state->skip_jump = state->PC->addr;
state->next_interupt = 0;
}
}
}
void osal_fastcall exception_general(usf_state_t * state)
{
update_count(state);
state->g_cp0_regs[CP0_STATUS_REG] |= 2;
state->g_cp0_regs[CP0_EPC_REG] = state->PC->addr;
if(state->delay_slot==1 || state->delay_slot==3)
{
state->g_cp0_regs[CP0_CAUSE_REG] |= 0x80000000;
state->g_cp0_regs[CP0_EPC_REG]-=4;
}
else
{
state->g_cp0_regs[CP0_CAUSE_REG] &= 0x7FFFFFFF;
}
generic_jump_to(state, 0x80000180);
state->last_addr = state->PC->addr;
if (state->r4300emu == CORE_DYNAREC)
{
dyna_jump(state);
if (!state->dyna_interp) state->delay_slot = 0;
}
if (state->r4300emu != CORE_DYNAREC || state->dyna_interp)
{
state->dyna_interp = 0;
if (state->delay_slot)
{
state->skip_jump = state->PC->addr;
state->next_interupt = 0;
}
}
}

View file

@ -0,0 +1,31 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - exception.h *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_R4300_EXCEPTION_H
#define M64P_R4300_EXCEPTION_H
#include "usf/usf.h"
void TLB_refill_exception(usf_state_t *, unsigned int addresse, int w);
void osal_fastcall exception_general(usf_state_t *);
#endif /* M64P_R4300_EXCEPTION_H */

View file

@ -0,0 +1,465 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - fpu.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2010 Ari64 *
* *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_R4300_FPU_H
#define M64P_R4300_FPU_H
#include <math.h>
#include "usf/usf.h"
#include "usf/usf_internal.h"
#include "r4300.h"
#ifdef _MSC_VER
#define M64P_FPU_INLINE static __inline
#include <float.h>
typedef enum { FE_TONEAREST = 0, FE_TOWARDZERO, FE_UPWARD, FE_DOWNWARD } eRoundType;
static void fesetround(eRoundType RoundType)
{
static const unsigned int msRound[4] = { _RC_NEAR, _RC_CHOP, _RC_UP, _RC_DOWN };
unsigned int oldX87, oldSSE2;
__control87_2(msRound[RoundType], _MCW_RC, &oldX87, &oldSSE2);
}
static __inline double round(double x) { return floor(x + 0.5); }
static __inline float roundf(float x) { return (float) floor(x + 0.5); }
static __inline double trunc(double x) { return (double) (int) x; }
static __inline float truncf(float x) { return (float) (int) x; }
#define isnan _isnan
#else
#define M64P_FPU_INLINE static inline
#include <fenv.h>
#endif
M64P_FPU_INLINE void set_rounding(usf_state_t * state)
{
switch(state->rounding_mode) {
case 0x33F:
fesetround(FE_TONEAREST);
break;
case 0xF3F:
fesetround(FE_TOWARDZERO);
break;
case 0xB3F:
fesetround(FE_UPWARD);
break;
case 0x73F:
fesetround(FE_DOWNWARD);
break;
}
}
M64P_FPU_INLINE void cvt_s_w(usf_state_t * state, int *source,float *dest)
{
set_rounding(state);
*dest = (float) *source;
}
M64P_FPU_INLINE void cvt_d_w(usf_state_t * state, int *source,double *dest)
{
(void)state;
*dest = (double) *source;
}
M64P_FPU_INLINE void cvt_s_l(usf_state_t * state, long long *source,float *dest)
{
set_rounding(state);
*dest = (float) *source;
}
M64P_FPU_INLINE void cvt_d_l(usf_state_t * state, long long *source,double *dest)
{
set_rounding(state);
*dest = (double) *source;
}
M64P_FPU_INLINE void cvt_d_s(usf_state_t * state, float *source,double *dest)
{
(void)state;
*dest = (double) *source;
}
M64P_FPU_INLINE void cvt_s_d(usf_state_t * state, double *source,float *dest)
{
set_rounding(state);
*dest = (float) *source;
}
M64P_FPU_INLINE void round_l_s(float *source,long long *dest)
{
*dest = (long long) roundf(*source);
}
M64P_FPU_INLINE void round_w_s(float *source,int *dest)
{
*dest = (int) roundf(*source);
}
M64P_FPU_INLINE void trunc_l_s(float *source,long long *dest)
{
*dest = (long long) truncf(*source);
}
M64P_FPU_INLINE void trunc_w_s(float *source,int *dest)
{
*dest = (int) truncf(*source);
}
M64P_FPU_INLINE void ceil_l_s(float *source,long long *dest)
{
*dest = (long long) ceilf(*source);
}
M64P_FPU_INLINE void ceil_w_s(float *source,int *dest)
{
*dest = (int) ceilf(*source);
}
M64P_FPU_INLINE void floor_l_s(float *source,long long *dest)
{
*dest = (long long) floorf(*source);
}
M64P_FPU_INLINE void floor_w_s(float *source,int *dest)
{
*dest = (int) floorf(*source);
}
M64P_FPU_INLINE void round_l_d(double *source,long long *dest)
{
*dest = (long long) round(*source);
}
M64P_FPU_INLINE void round_w_d(double *source,int *dest)
{
*dest = (int) round(*source);
}
M64P_FPU_INLINE void trunc_l_d(double *source,long long *dest)
{
*dest = (long long) trunc(*source);
}
M64P_FPU_INLINE void trunc_w_d(double *source,int *dest)
{
*dest = (int) trunc(*source);
}
M64P_FPU_INLINE void ceil_l_d(double *source,long long *dest)
{
*dest = (long long) ceil(*source);
}
M64P_FPU_INLINE void ceil_w_d(double *source,int *dest)
{
*dest = (int) ceil(*source);
}
M64P_FPU_INLINE void floor_l_d(double *source,long long *dest)
{
*dest = (long long) floor(*source);
}
M64P_FPU_INLINE void floor_w_d(double *source,int *dest)
{
*dest = (int) floor(*source);
}
M64P_FPU_INLINE void cvt_w_s(usf_state_t * state, float *source,int *dest)
{
switch(state->FCR31&3)
{
case 0: round_w_s(source,dest);return;
case 1: trunc_w_s(source,dest);return;
case 2: ceil_w_s(source,dest);return;
case 3: floor_w_s(source,dest);return;
}
}
M64P_FPU_INLINE void cvt_w_d(usf_state_t * state, double *source,int *dest)
{
switch(state->FCR31&3)
{
case 0: round_w_d(source,dest);return;
case 1: trunc_w_d(source,dest);return;
case 2: ceil_w_d(source,dest);return;
case 3: floor_w_d(source,dest);return;
}
}
M64P_FPU_INLINE void cvt_l_s(usf_state_t * state, float *source,long long *dest)
{
switch(state->FCR31&3)
{
case 0: round_l_s(source,dest);return;
case 1: trunc_l_s(source,dest);return;
case 2: ceil_l_s(source,dest);return;
case 3: floor_l_s(source,dest);return;
}
}
M64P_FPU_INLINE void cvt_l_d(usf_state_t * state, double *source,long long *dest)
{
switch(state->FCR31&3)
{
case 0: round_l_d(source,dest);return;
case 1: trunc_l_d(source,dest);return;
case 2: ceil_l_d(source,dest);return;
case 3: floor_l_d(source,dest);return;
}
}
M64P_FPU_INLINE void c_f_s(usf_state_t * state)
{
state->FCR31 &= ~0x800000;
}
M64P_FPU_INLINE void c_un_s(usf_state_t * state, float *source,float *target)
{
state->FCR31=(isnan(*source) || isnan(*target)) ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_eq_s(usf_state_t * state, float *source,float *target)
{
if (isnan(*source) || isnan(*target)) {state->FCR31&=~0x800000;return;}
state->FCR31 = *source==*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_ueq_s(usf_state_t * state, float *source,float *target)
{
if (isnan(*source) || isnan(*target)) {state->FCR31|=0x800000;return;}
state->FCR31 = *source==*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_olt_s(usf_state_t * state, float *source,float *target)
{
if (isnan(*source) || isnan(*target)) {state->FCR31&=~0x800000;return;}
state->FCR31 = *source<*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_ult_s(usf_state_t * state, float *source,float *target)
{
if (isnan(*source) || isnan(*target)) {state->FCR31|=0x800000;return;}
state->FCR31 = *source<*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_ole_s(usf_state_t * state, float *source,float *target)
{
if (isnan(*source) || isnan(*target)) {state->FCR31&=~0x800000;return;}
state->FCR31 = *source<=*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_ule_s(usf_state_t * state, float *source,float *target)
{
if (isnan(*source) || isnan(*target)) {state->FCR31|=0x800000;return;}
state->FCR31 = *source<=*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_sf_s(usf_state_t * state, float *source,float *target)
{
//if (isnan(*source) || isnan(*target)) // FIXME - exception
state->FCR31&=~0x800000;
}
M64P_FPU_INLINE void c_ngle_s(usf_state_t * state, float *source,float *target)
{
//if (isnan(*source) || isnan(*target)) // FIXME - exception
state->FCR31&=~0x800000;
}
M64P_FPU_INLINE void c_seq_s(usf_state_t * state, float *source,float *target)
{
//if (isnan(*source) || isnan(*target)) // FIXME - exception
state->FCR31 = *source==*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_ngl_s(usf_state_t * state, float *source,float *target)
{
//if (isnan(*source) || isnan(*target)) // FIXME - exception
state->FCR31 = *source==*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_lt_s(usf_state_t * state, float *source,float *target)
{
//if (isnan(*source) || isnan(*target)) // FIXME - exception
state->FCR31 = *source<*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_nge_s(usf_state_t * state, float *source,float *target)
{
//if (isnan(*source) || isnan(*target)) // FIXME - exception
state->FCR31 = *source<*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_le_s(usf_state_t * state, float *source,float *target)
{
//if (isnan(*source) || isnan(*target)) // FIXME - exception
state->FCR31 = *source<=*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_ngt_s(usf_state_t * state, float *source,float *target)
{
//if (isnan(*source) || isnan(*target)) // FIXME - exception
state->FCR31 = *source<=*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_f_d(usf_state_t * state)
{
state->FCR31 &= ~0x800000;
}
M64P_FPU_INLINE void c_un_d(usf_state_t * state, double *source,double *target)
{
state->FCR31=(isnan(*source) || isnan(*target)) ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_eq_d(usf_state_t * state, double *source,double *target)
{
if (isnan(*source) || isnan(*target)) {state->FCR31&=~0x800000;return;}
state->FCR31 = *source==*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_ueq_d(usf_state_t * state, double *source,double *target)
{
if (isnan(*source) || isnan(*target)) {state->FCR31|=0x800000;return;}
state->FCR31 = *source==*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_olt_d(usf_state_t * state, double *source,double *target)
{
if (isnan(*source) || isnan(*target)) {state->FCR31&=~0x800000;return;}
state->FCR31 = *source<*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_ult_d(usf_state_t * state, double *source,double *target)
{
if (isnan(*source) || isnan(*target)) {state->FCR31|=0x800000;return;}
state->FCR31 = *source<*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_ole_d(usf_state_t * state, double *source,double *target)
{
if (isnan(*source) || isnan(*target)) {state->FCR31&=~0x800000;return;}
state->FCR31 = *source<=*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_ule_d(usf_state_t * state, double *source,double *target)
{
if (isnan(*source) || isnan(*target)) {state->FCR31|=0x800000;return;}
state->FCR31 = *source<=*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_sf_d(usf_state_t * state, double *source,double *target)
{
(void)source; (void)target;
//if (isnan(*source) || isnan(*target)) // FIXME - exception
state->FCR31&=~0x800000;
}
M64P_FPU_INLINE void c_ngle_d(usf_state_t * state, double *source,double *target)
{
//if (isnan(*source) || isnan(*target)) // FIXME - exception
state->FCR31&=~0x800000;
}
M64P_FPU_INLINE void c_seq_d(usf_state_t * state, double *source,double *target)
{
//if (isnan(*source) || isnan(*target)) // FIXME - exception
state->FCR31 = *source==*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_ngl_d(usf_state_t * state, double *source,double *target)
{
//if (isnan(*source) || isnan(*target)) // FIXME - exception
state->FCR31 = *source==*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_lt_d(usf_state_t * state, double *source,double *target)
{
//if (isnan(*source) || isnan(*target)) // FIXME - exception
state->FCR31 = *source<*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_nge_d(usf_state_t * state, double *source,double *target)
{
//if (isnan(*source) || isnan(*target)) // FIXME - exception
state->FCR31 = *source<*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_le_d(usf_state_t * state, double *source,double *target)
{
//if (isnan(*source) || isnan(*target)) // FIXME - exception
state->FCR31 = *source<=*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void c_ngt_d(usf_state_t * state, double *source,double *target)
{
//if (isnan(*source) || isnan(*target)) // FIXME - exception
state->FCR31 = *source<=*target ? state->FCR31|0x800000 : state->FCR31&~0x800000;
}
M64P_FPU_INLINE void add_s(usf_state_t * state, float *source1,float *source2,float *target)
{
set_rounding(state);
*target=(*source1)+(*source2);
}
M64P_FPU_INLINE void sub_s(usf_state_t * state, float *source1,float *source2,float *target)
{
set_rounding(state);
*target=(*source1)-(*source2);
}
M64P_FPU_INLINE void mul_s(usf_state_t * state, float *source1,float *source2,float *target)
{
set_rounding(state);
*target=(*source1)*(*source2);
}
M64P_FPU_INLINE void div_s(usf_state_t * state, float *source1,float *source2,float *target)
{
set_rounding(state);
*target=(*source1)/(*source2);
}
M64P_FPU_INLINE void sqrt_s(usf_state_t * state, float *source,float *target)
{
set_rounding(state);
*target=sqrtf(*source);
}
M64P_FPU_INLINE void abs_s(usf_state_t * state, float *source,float *target)
{
(void)state;
*target=fabsf(*source);
}
M64P_FPU_INLINE void mov_s(usf_state_t * state, float *source,float *target)
{
(void)state;
*target=*source;
}
M64P_FPU_INLINE void neg_s(usf_state_t * state, float *source,float *target)
{
(void)state;
*target=-(*source);
}
M64P_FPU_INLINE void add_d(usf_state_t * state, double *source1,double *source2,double *target)
{
set_rounding(state);
*target=(*source1)+(*source2);
}
M64P_FPU_INLINE void sub_d(usf_state_t * state, double *source1,double *source2,double *target)
{
set_rounding(state);
*target=(*source1)-(*source2);
}
M64P_FPU_INLINE void mul_d(usf_state_t * state, double *source1,double *source2,double *target)
{
set_rounding(state);
*target=(*source1)*(*source2);
}
M64P_FPU_INLINE void div_d(usf_state_t * state, double *source1,double *source2,double *target)
{
set_rounding(state);
*target=(*source1)/(*source2);
}
M64P_FPU_INLINE void sqrt_d(usf_state_t * state, double *source,double *target)
{
set_rounding(state);
*target=sqrt(*source);
}
M64P_FPU_INLINE void abs_d(usf_state_t * state, double *source,double *target)
{
(void)state;
*target=fabs(*source);
}
M64P_FPU_INLINE void mov_d(usf_state_t * state, double *source,double *target)
{
(void)state;
*target=*source;
}
M64P_FPU_INLINE void neg_d(usf_state_t * state, double *source,double *target)
{
(void)state;
*target=-(*source);
}
#endif /* M64P_R4300_FPU_H */

View file

@ -0,0 +1,105 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - instr_counters.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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#if defined(COUNT_INSTR)
#include <stdio.h>
#include <string.h>
#include "usf/usf.h"
#include "usf/usf_internal.h"
#include "api/m64p_types.h"
#include "api/callbacks.h"
/* various constants */
static char instr_name[][10] =
{
"reserved", "NI", "J", "JAL", "BEQ", "BNE", "BLEZ", "BGTZ",
"ADDI", "ADDIU", "SLTI", "SLTIU", "ANDI", "ORI", "XORI", "LUI",
"BEQL", "BNEL", "BLEZL", "BGTZL", "DADDI", "DADDIU", "LDL", "LDR",
"LB", "LH", "LW", "LWL", "LBU", "LHU", "LWU", "LWR",
"SB", "SH", "SW", "SWL", "SWR", "SDL", "SDR", "LWC1",
"LDC1", "LD", "LL", "SWC1", "SDC1", "SD", "SC", "BLTZ",
"BGEZ", "BLTZL", "BGEZL", "BLTZAL", "BGEZAL", "BLTZALL", "BGEZALL", "SLL",
"SRL", "SRA", "SLLV", "SRLV", "SRAV", "JR", "JALR", "SYSCALL",
"MFHI", "MTHI", "MFLO", "MTLO", "DSLLV", "DSRLV", "DSRAV", "MULT",
"MULTU", "DIV", "DIVU", "DMULT", "DMULTU", "DDIV", "DDIVU", "ADD",
"ADDU", "SUB", "SUBU", "AND", "OR", "XOR", "NOR", "SLT",
"SLTU", "DADD", "DADDU", "DSUB", "DSUBU", "DSLL", "DSRL", "DSRA",
"TEQ", "DSLL32", "DSRL32", "DSRA32", "BC1F", "BC1T", "BC1FL", "BC1TL",
"TLBWI", "TLBP", "TLBR", "TLBWR", "ERET", "MFC0", "MTC0", "MFC1",
"DMFC1", "CFC1", "MTC1", "DMTC1", "CTC1", "f.CVT", "f.CMP", "f.ADD",
"f.SUB", "f.MUL", "f.DIV", "f.SQRT", "f.ABS", "f.MOV", "f.NEG", "f.ROUND",
"f.TRUNC", "f.CEIL", "f.FLOOR"
};
static unsigned int instr_type[131] =
{
9, 10, 6, 6, 7, 7, 7, 7, 3, 3, 4, 4, 3, 4, 4, 0,
7, 7, 7, 7, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 7,
7, 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 6, 6, 10,
2, 2, 2, 2, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3,
3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
8, 4, 4, 4, 7, 7, 7, 7, 10, 10, 10, 10, 8, 2, 2, 2,
2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 2, 5, 5,
5, 5, 5
};
static char instr_typename[][20] =
{
"Load", "Store", "Data move/convert",
"32-bit math", "64-bit math", "Float Math",
"Jump", "Branch", "Exceptions",
"Reserved", "Other"
};
/* global function */
void instr_counters_print(usf_state_t * state)
{
size_t i;
unsigned int iTypeCount[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
unsigned int iTotal = 0;
char line[128], param[24];
DebugMessage(state, M64MSG_INFO, "Instruction counters:");
line[0] = 0;
for (i = 0; i < 131; i++)
{
sprintf(param, "%8s: %08i ", instr_name[i], state->instr_count[i]);
strcat(line, param);
if (i % 5 == 4)
{
DebugMessage(state, M64MSG_INFO, "%s", line);
line[0] = 0;
}
iTypeCount[instr_type[i]] += state->instr_count[i];
iTotal += state->instr_count[i];
}
DebugMessage(state, M64MSG_INFO, "Instruction type summary (total instructions = %i)", iTotal);
for (i = 0; i < 11; i++)
{
DebugMessage(state, M64MSG_INFO, "%20s: %04.1f%% (%i)", instr_typename[i], (float) iTypeCount[i] * 100.0 / iTotal, iTypeCount[i]);
}
}
#endif /* COUNT_INSTR */

View file

@ -0,0 +1,29 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - instr_counters.h *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_R4300_INSTR_COUNTERS_H
#define M64P_R4300_INSTR_COUNTERS_H
#if defined(COUNT_INSTR)
void instr_counters_print(usf_state_t * state);
#endif /* COUNT_INSTR */
#endif /* M64P_R4300_INSTR_COUNTERS_H */

View file

@ -0,0 +1,79 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - interpreter.def *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Before #including this file, the following macros should be defined:
*
* PCADDR: Program counter (memory address of the current instruction).
*
* ADD_TO_PC(x): Increment the program counter in 'x' instructions.
* This is only used for small changes to PC, so the new program counter
* is guaranteed to fall in the current cached interpreter or dynarec block.
*
* DECLARE_INSTRUCTION(name)
* Declares an instruction function which is not a jump.
* Followed by a block of code.
*
* DECLARE_JUMP(name, destination, condition, link, likely, cop1)
* name is the name of the jump or branch instruction.
* destination is the destination memory address of the jump.
* If condition is nonzero, the jump is taken.
* link is a pointer to a variable where (PC+8) is written unconditionally.
* To avoid linking, pass &reg[0]
* If likely is nonzero, the delay slot is only executed if the jump is taken.
* If cop1 is nonzero, a COP1 unusable check will be done.
*
* CHECK_MEMORY(): A snippet to be run after a store instruction,
* to check if the store affected executable blocks.
* The memory address of the store is in the 'address' global.
*/
DECLARE_INSTRUCTION(NI)
{
DebugMessage(state, M64MSG_ERROR, "NI() @ 0x%x", PCADDR);
DebugMessage(state, M64MSG_ERROR, "opcode not implemented: %x:%x", PCADDR, *fast_mem_access(state, PCADDR));
state->stop=1;
}
DECLARE_INSTRUCTION(RESERVED)
{
DebugMessage(state, M64MSG_ERROR, "reserved opcode: %x:%x", PCADDR, *fast_mem_access(state, PCADDR));
state->stop=1;
}
// R4300
#include "interpreter_r4300.def"
// COP0
#include "interpreter_cop0.def"
// COP1
#include "interpreter_cop1.def"
// regimm
#include "interpreter_regimm.def"
// special
#include "interpreter_special.def"
// TLB
#include "interpreter_tlb.def"

View file

@ -0,0 +1,137 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - interpreter_cop0.def *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
DECLARE_INSTRUCTION(MFC0)
{
switch(rfs)
{
case CP0_RANDOM_REG:
DebugMessage(state, M64MSG_ERROR, "MFC0 instruction reading un-implemented Random register");
state->stop=1;
case CP0_COUNT_REG:
update_count(state);
default:
rrt32 = state->g_cp0_regs[rfs];
sign_extended(rrt);
}
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(MTC0)
{
switch(rfs)
{
case CP0_INDEX_REG:
state->g_cp0_regs[CP0_INDEX_REG] = (unsigned int) rrt & 0x8000003F;
if ((state->g_cp0_regs[CP0_INDEX_REG] & 0x3F) > 31)
{
DebugMessage(state, M64MSG_ERROR, "MTC0 instruction writing Index register with TLB index > 31");
state->stop=1;
}
break;
case CP0_RANDOM_REG:
break;
case CP0_ENTRYLO0_REG:
state->g_cp0_regs[CP0_ENTRYLO0_REG] = (unsigned int) rrt & 0x3FFFFFFF;
break;
case CP0_ENTRYLO1_REG:
state->g_cp0_regs[CP0_ENTRYLO1_REG] = (unsigned int) rrt & 0x3FFFFFFF;
break;
case CP0_CONTEXT_REG:
state->g_cp0_regs[CP0_CONTEXT_REG] = ((unsigned int) rrt & 0xFF800000)
| (state->g_cp0_regs[CP0_CONTEXT_REG] & 0x007FFFF0);
break;
case CP0_PAGEMASK_REG:
state->g_cp0_regs[CP0_PAGEMASK_REG] = (unsigned int) rrt & 0x01FFE000;
break;
case CP0_WIRED_REG:
state->g_cp0_regs[CP0_WIRED_REG] = (unsigned int) rrt;
state->g_cp0_regs[CP0_RANDOM_REG] = 31;
break;
case CP0_BADVADDR_REG:
break;
case CP0_COUNT_REG:
update_count(state);
state->interupt_unsafe_state = 1;
if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state);
state->interupt_unsafe_state = 0;
translate_event_queue(state, (unsigned int) rrt & 0xFFFFFFFF);
state->g_cp0_regs[CP0_COUNT_REG] = (unsigned int) rrt & 0xFFFFFFFF;
break;
case CP0_ENTRYHI_REG:
state->g_cp0_regs[CP0_ENTRYHI_REG] = (unsigned int) rrt & 0xFFFFE0FF;
break;
case CP0_COMPARE_REG:
update_count(state);
remove_event(state, COMPARE_INT);
add_interupt_event_count(state, COMPARE_INT, (unsigned int)rrt);
state->g_cp0_regs[CP0_COMPARE_REG] = (unsigned int) rrt;
state->g_cp0_regs[CP0_CAUSE_REG] &= 0xFFFF7FFF; //Timer interupt is clear
break;
case CP0_STATUS_REG:
if((rrt & 0x04000000) != (state->g_cp0_regs[CP0_STATUS_REG] & 0x04000000))
{
shuffle_fpr_data(state, state->g_cp0_regs[CP0_STATUS_REG], (unsigned int) rrt);
set_fpr_pointers(state, (unsigned int) rrt);
}
state->g_cp0_regs[CP0_STATUS_REG] = (unsigned int) rrt;
update_count(state);
ADD_TO_PC(1);
check_interupt(state);
state->interupt_unsafe_state = 1;
if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state);
state->interupt_unsafe_state = 0;
ADD_TO_PC(-1);
break;
case CP0_CAUSE_REG:
if (rrt!=0)
{
DebugMessage(state, M64MSG_ERROR, "MTC0 instruction trying to write Cause register with non-0 value");
state->stop = 1;
}
else state->g_cp0_regs[CP0_CAUSE_REG] = (unsigned int) rrt;
break;
case CP0_EPC_REG:
state->g_cp0_regs[CP0_EPC_REG] = (unsigned int) rrt;
break;
case CP0_PREVID_REG:
break;
case CP0_CONFIG_REG:
state->g_cp0_regs[CP0_CONFIG_REG] = (unsigned int) rrt;
break;
case CP0_WATCHLO_REG:
state->g_cp0_regs[CP0_WATCHLO_REG] = (unsigned int) rrt & 0xFFFFFFFF;
break;
case CP0_WATCHHI_REG:
state->g_cp0_regs[CP0_WATCHHI_REG] = (unsigned int) rrt & 0xFFFFFFFF;
break;
case CP0_TAGLO_REG:
state->g_cp0_regs[CP0_TAGLO_REG] = (unsigned int) rrt & 0x0FFFFFC0;
break;
case CP0_TAGHI_REG:
state->g_cp0_regs[CP0_TAGHI_REG] =0;
break;
default:
DebugMessage(state, M64MSG_ERROR, "Unknown MTC0 write: %d", rfs);
state->stop=1;
}
ADD_TO_PC(1);
}

View file

@ -0,0 +1,708 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - interpreter_cop1.def *
* 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 "fpu.h"
DECLARE_JUMP(BC1F, PCADDR + (iimmediate+1)*4, (state->FCR31 & 0x800000)==0, &state->reg[0], 0, 1)
DECLARE_JUMP(BC1T, PCADDR + (iimmediate+1)*4, (state->FCR31 & 0x800000)!=0, &state->reg[0], 0, 1)
DECLARE_JUMP(BC1FL, PCADDR + (iimmediate+1)*4, (state->FCR31 & 0x800000)==0, &state->reg[0], 1, 1)
DECLARE_JUMP(BC1TL, PCADDR + (iimmediate+1)*4, (state->FCR31 & 0x800000)!=0, &state->reg[0], 1, 1)
DECLARE_INSTRUCTION(MFC1)
{
if (check_cop1_unusable(state)) return;
rrt32 = *((int*)state->reg_cop1_simple[rfs]);
sign_extended(rrt);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DMFC1)
{
if (check_cop1_unusable(state)) return;
rrt = *((long long*)state->reg_cop1_double[rfs]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(CFC1)
{
if (check_cop1_unusable(state)) return;
if (rfs==31)
{
rrt32 = state->FCR31;
sign_extended(rrt);
}
if (rfs==0)
{
rrt32 = state->FCR0;
sign_extended(rrt);
}
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(MTC1)
{
if (check_cop1_unusable(state)) return;
*((int*)state->reg_cop1_simple[rfs]) = rrt32;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DMTC1)
{
if (check_cop1_unusable(state)) return;
*((long long*)state->reg_cop1_double[rfs]) = rrt;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(CTC1)
{
if (check_cop1_unusable(state)) return;
if (rfs==31)
state->FCR31 = rrt32;
switch((state->FCR31 & 3))
{
case 0:
state->rounding_mode = 0x33F; // Round to nearest, or to even if equidistant
break;
case 1:
state->rounding_mode = 0xF3F; // Truncate (toward 0)
break;
case 2:
state->rounding_mode = 0xB3F; // Round up (toward +infinity)
break;
case 3:
state->rounding_mode = 0x73F; // Round down (toward -infinity)
break;
}
//if ((state->FCR31 >> 7) & 0x1F) printf("FPU Exception enabled : %x\n",
// (int)((state->FCR31 >> 7) & 0x1F));
ADD_TO_PC(1);
}
// COP1_D
DECLARE_INSTRUCTION(ADD_D)
{
if (check_cop1_unusable(state)) return;
add_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft], state->reg_cop1_double[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(SUB_D)
{
if (check_cop1_unusable(state)) return;
sub_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft], state->reg_cop1_double[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(MUL_D)
{
if (check_cop1_unusable(state)) return;
mul_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft], state->reg_cop1_double[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DIV_D)
{
if (check_cop1_unusable(state)) return;
if((state->FCR31 & 0x400) && *state->reg_cop1_double[cfft] == 0)
{
//state->FCR31 |= 0x8020;
/*state->FCR31 |= 0x8000;
state->Cause = 15 << 2;
exception_general(state);*/
DebugMessage(state, M64MSG_ERROR, "DIV_D by 0");
//return;
}
div_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft], state->reg_cop1_double[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(SQRT_D)
{
if (check_cop1_unusable(state)) return;
sqrt_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(ABS_D)
{
if (check_cop1_unusable(state)) return;
abs_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(MOV_D)
{
if (check_cop1_unusable(state)) return;
mov_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(NEG_D)
{
if (check_cop1_unusable(state)) return;
neg_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(ROUND_L_D)
{
if (check_cop1_unusable(state)) return;
round_l_d(state->reg_cop1_double[cffs], (long long*)(state->reg_cop1_double[cffd]));
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(TRUNC_L_D)
{
if (check_cop1_unusable(state)) return;
trunc_l_d(state->reg_cop1_double[cffs], (long long*)(state->reg_cop1_double[cffd]));
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(CEIL_L_D)
{
if (check_cop1_unusable(state)) return;
ceil_l_d(state->reg_cop1_double[cffs], (long long*)(state->reg_cop1_double[cffd]));
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(FLOOR_L_D)
{
if (check_cop1_unusable(state)) return;
floor_l_d(state->reg_cop1_double[cffs], (long long*)(state->reg_cop1_double[cffd]));
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(ROUND_W_D)
{
if (check_cop1_unusable(state)) return;
round_w_d(state->reg_cop1_double[cffs], (int*)state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(TRUNC_W_D)
{
if (check_cop1_unusable(state)) return;
trunc_w_d(state->reg_cop1_double[cffs], (int*)state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(CEIL_W_D)
{
if (check_cop1_unusable(state)) return;
ceil_w_d(state->reg_cop1_double[cffs], (int*)state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(FLOOR_W_D)
{
if (check_cop1_unusable(state)) return;
floor_w_d(state->reg_cop1_double[cffs], (int*)state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(CVT_S_D)
{
if (check_cop1_unusable(state)) return;
cvt_s_d(state, state->reg_cop1_double[cffs], state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(CVT_W_D)
{
if (check_cop1_unusable(state)) return;
cvt_w_d(state, state->reg_cop1_double[cffs], (int*)state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(CVT_L_D)
{
if (check_cop1_unusable(state)) return;
cvt_l_d(state, state->reg_cop1_double[cffs], (long long*)(state->reg_cop1_double[cffd]));
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_F_D)
{
if (check_cop1_unusable(state)) return;
c_f_d(state);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_UN_D)
{
if (check_cop1_unusable(state)) return;
c_un_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_EQ_D)
{
if (check_cop1_unusable(state)) return;
c_eq_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_UEQ_D)
{
if (check_cop1_unusable(state)) return;
c_ueq_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_OLT_D)
{
if (check_cop1_unusable(state)) return;
c_olt_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_ULT_D)
{
if (check_cop1_unusable(state)) return;
c_ult_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_OLE_D)
{
if (check_cop1_unusable(state)) return;
c_ole_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_ULE_D)
{
if (check_cop1_unusable(state)) return;
c_ule_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_SF_D)
{
if (isnan(*state->reg_cop1_double[cffs]) || isnan(*state->reg_cop1_double[cfft]))
{
DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode");
state->stop=1;
}
c_sf_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_NGLE_D)
{
if (isnan(*state->reg_cop1_double[cffs]) || isnan(*state->reg_cop1_double[cfft]))
{
DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode");
state->stop=1;
}
c_ngle_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_SEQ_D)
{
if (isnan(*state->reg_cop1_double[cffs]) || isnan(*state->reg_cop1_double[cfft]))
{
DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode");
state->stop=1;
}
c_seq_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_NGL_D)
{
if (isnan(*state->reg_cop1_double[cffs]) || isnan(*state->reg_cop1_double[cfft]))
{
DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode");
state->stop=1;
}
c_ngl_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_LT_D)
{
if (check_cop1_unusable(state)) return;
if (isnan(*state->reg_cop1_double[cffs]) || isnan(*state->reg_cop1_double[cfft]))
{
DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode");
state->stop=1;
}
c_lt_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_NGE_D)
{
if (check_cop1_unusable(state)) return;
if (isnan(*state->reg_cop1_double[cffs]) || isnan(*state->reg_cop1_double[cfft]))
{
DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode");
state->stop=1;
}
c_nge_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_LE_D)
{
if (check_cop1_unusable(state)) return;
if (isnan(*state->reg_cop1_double[cffs]) || isnan(*state->reg_cop1_double[cfft]))
{
DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode");
state->stop=1;
}
c_le_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_NGT_D)
{
if (check_cop1_unusable(state)) return;
if (isnan(*state->reg_cop1_double[cffs]) || isnan(*state->reg_cop1_double[cfft]))
{
DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode");
state->stop=1;
}
c_ngt_d(state, state->reg_cop1_double[cffs], state->reg_cop1_double[cfft]);
ADD_TO_PC(1);
}
// COP1_L
DECLARE_INSTRUCTION(CVT_S_L)
{
if (check_cop1_unusable(state)) return;
cvt_s_l(state, (long long*)(state->reg_cop1_double[cffs]), state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(CVT_D_L)
{
if (check_cop1_unusable(state)) return;
cvt_d_l(state, (long long*)(state->reg_cop1_double[cffs]), state->reg_cop1_double[cffd]);
ADD_TO_PC(1);
}
// COP1_S
DECLARE_INSTRUCTION(ADD_S)
{
if (check_cop1_unusable(state)) return;
add_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft], state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(SUB_S)
{
if (check_cop1_unusable(state)) return;
sub_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft], state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(MUL_S)
{
if (check_cop1_unusable(state)) return;
mul_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft], state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DIV_S)
{
if (check_cop1_unusable(state)) return;
if((state->FCR31 & 0x400) && *state->reg_cop1_simple[cfft] == 0)
{
DebugMessage(state, M64MSG_ERROR, "DIV_S by 0");
}
div_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft], state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(SQRT_S)
{
if (check_cop1_unusable(state)) return;
sqrt_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(ABS_S)
{
if (check_cop1_unusable(state)) return;
abs_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(MOV_S)
{
if (check_cop1_unusable(state)) return;
mov_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(NEG_S)
{
if (check_cop1_unusable(state)) return;
neg_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(ROUND_L_S)
{
if (check_cop1_unusable(state)) return;
round_l_s(state->reg_cop1_simple[cffs], (long long*)(state->reg_cop1_double[cffd]));
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(TRUNC_L_S)
{
if (check_cop1_unusable(state)) return;
trunc_l_s(state->reg_cop1_simple[cffs], (long long*)(state->reg_cop1_double[cffd]));
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(CEIL_L_S)
{
if (check_cop1_unusable(state)) return;
ceil_l_s(state->reg_cop1_simple[cffs], (long long*)(state->reg_cop1_double[cffd]));
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(FLOOR_L_S)
{
if (check_cop1_unusable(state)) return;
floor_l_s(state->reg_cop1_simple[cffs], (long long*)(state->reg_cop1_double[cffd]));
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(ROUND_W_S)
{
if (check_cop1_unusable(state)) return;
round_w_s(state->reg_cop1_simple[cffs], (int*)state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(TRUNC_W_S)
{
if (check_cop1_unusable(state)) return;
trunc_w_s(state->reg_cop1_simple[cffs], (int*)state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(CEIL_W_S)
{
if (check_cop1_unusable(state)) return;
ceil_w_s(state->reg_cop1_simple[cffs], (int*)state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(FLOOR_W_S)
{
if (check_cop1_unusable(state)) return;
floor_w_s(state->reg_cop1_simple[cffs], (int*)state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(CVT_D_S)
{
if (check_cop1_unusable(state)) return;
cvt_d_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_double[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(CVT_W_S)
{
if (check_cop1_unusable(state)) return;
cvt_w_s(state, state->reg_cop1_simple[cffs], (int*)state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(CVT_L_S)
{
if (check_cop1_unusable(state)) return;
cvt_l_s(state, state->reg_cop1_simple[cffs], (long long*)(state->reg_cop1_double[cffd]));
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_F_S)
{
if (check_cop1_unusable(state)) return;
c_f_s(state);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_UN_S)
{
if (check_cop1_unusable(state)) return;
c_un_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_EQ_S)
{
if (check_cop1_unusable(state)) return;
c_eq_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_UEQ_S)
{
if (check_cop1_unusable(state)) return;
c_ueq_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_OLT_S)
{
if (check_cop1_unusable(state)) return;
c_olt_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_ULT_S)
{
if (check_cop1_unusable(state)) return;
c_ult_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_OLE_S)
{
if (check_cop1_unusable(state)) return;
c_ole_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_ULE_S)
{
if (check_cop1_unusable(state)) return;
c_ule_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_SF_S)
{
if (check_cop1_unusable(state)) return;
if (isnan(*state->reg_cop1_simple[cffs]) || isnan(*state->reg_cop1_simple[cfft]))
{
DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode");
state->stop=1;
}
c_sf_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_NGLE_S)
{
if (check_cop1_unusable(state)) return;
if (isnan(*state->reg_cop1_simple[cffs]) || isnan(*state->reg_cop1_simple[cfft]))
{
DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode");
state->stop=1;
}
c_ngle_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_SEQ_S)
{
if (check_cop1_unusable(state)) return;
if (isnan(*state->reg_cop1_simple[cffs]) || isnan(*state->reg_cop1_simple[cfft]))
{
DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode");
state->stop=1;
}
c_seq_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_NGL_S)
{
if (check_cop1_unusable(state)) return;
if (isnan(*state->reg_cop1_simple[cffs]) || isnan(*state->reg_cop1_simple[cfft]))
{
DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode");
state->stop=1;
}
c_ngl_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_LT_S)
{
if (check_cop1_unusable(state)) return;
if (isnan(*state->reg_cop1_simple[cffs]) || isnan(*state->reg_cop1_simple[cfft]))
{
DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode");
state->stop=1;
}
c_lt_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_NGE_S)
{
if (check_cop1_unusable(state)) return;
if (isnan(*state->reg_cop1_simple[cffs]) || isnan(*state->reg_cop1_simple[cfft]))
{
DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode");
state->stop=1;
}
c_nge_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_LE_S)
{
if (check_cop1_unusable(state)) return;
if (isnan(*state->reg_cop1_simple[cffs]) || isnan(*state->reg_cop1_simple[cfft]))
{
DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode");
state->stop=1;
}
c_le_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(C_NGT_S)
{
if (check_cop1_unusable(state)) return;
if (isnan(*state->reg_cop1_simple[cffs]) || isnan(*state->reg_cop1_simple[cfft]))
{
DebugMessage(state, M64MSG_ERROR, "Invalid operation exception in C opcode");
state->stop=1;
}
c_ngt_s(state, state->reg_cop1_simple[cffs], state->reg_cop1_simple[cfft]);
ADD_TO_PC(1);
}
// COP1_W
DECLARE_INSTRUCTION(CVT_S_W)
{
if (check_cop1_unusable(state)) return;
cvt_s_w(state, (int*)state->reg_cop1_simple[cffs], state->reg_cop1_simple[cffd]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(CVT_D_W)
{
if (check_cop1_unusable(state)) return;
cvt_d_w(state, (int*)state->reg_cop1_simple[cffs], state->reg_cop1_double[cffd]);
ADD_TO_PC(1);
}

View file

@ -0,0 +1,800 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - interpreter_r4300.def *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
DECLARE_JUMP(J, (jinst_index<<2) | ((PCADDR+4) & 0xF0000000), 1, &state->reg[0], 0, 0)
DECLARE_JUMP(JAL, (jinst_index<<2) | ((PCADDR+4) & 0xF0000000), 1, &state->reg[31], 0, 0)
DECLARE_JUMP(BEQ, PCADDR + (iimmediate+1)*4, irs == irt, &state->reg[0], 0, 0)
DECLARE_JUMP(BNE, PCADDR + (iimmediate+1)*4, irs != irt, &state->reg[0], 0, 0)
DECLARE_JUMP(BLEZ, PCADDR + (iimmediate+1)*4, irs <= 0, &state->reg[0], 0, 0)
DECLARE_JUMP(BGTZ, PCADDR + (iimmediate+1)*4, irs > 0, &state->reg[0], 0, 0)
DECLARE_INSTRUCTION(ADDI)
{
irt32 = irs32 + iimmediate;
sign_extended(irt);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(ADDIU)
{
irt32 = irs32 + iimmediate;
sign_extended(irt);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(SLTI)
{
if (irs < iimmediate) irt = 1;
else irt = 0;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(SLTIU)
{
if ((unsigned long long)irs < (unsigned long long)((long long)iimmediate))
irt = 1;
else irt = 0;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(ANDI)
{
irt = irs & (unsigned short)iimmediate;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(ORI)
{
irt = irs | (unsigned short)iimmediate;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(XORI)
{
irt = irs ^ (unsigned short)iimmediate;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(LUI)
{
irt32 = iimmediate << 16;
sign_extended(irt);
ADD_TO_PC(1);
}
DECLARE_JUMP(BEQL, PCADDR + (iimmediate+1)*4, irs == irt, &state->reg[0], 1, 0)
DECLARE_JUMP(BNEL, PCADDR + (iimmediate+1)*4, irs != irt, &state->reg[0], 1, 0)
DECLARE_JUMP(BLEZL, PCADDR + (iimmediate+1)*4, irs <= 0, &state->reg[0], 1, 0)
DECLARE_JUMP(BGTZL, PCADDR + (iimmediate+1)*4, irs > 0, &state->reg[0], 1, 0)
DECLARE_INSTRUCTION(DADDI)
{
irt = irs + iimmediate;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DADDIU)
{
irt = irs + iimmediate;
ADD_TO_PC(1);
}
// TODOXXX refactor the following functions to remove the
// lsaddr and lsrpt locals. this may lead to a small speedup too
DECLARE_INSTRUCTION(LDL)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
unsigned long long int word = 0;
ADD_TO_PC(1);
switch ((lsaddr) & 7)
{
case 0:
state->address = (unsigned int) lsaddr;
state->rdword = (unsigned long long *) lsrtp;
read_dword_in_memory();
break;
case 1:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &word;
read_dword_in_memory();
if(state->address)
*lsrtp = (*lsrtp & 0xFF) | (word << 8);
break;
case 2:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &word;
read_dword_in_memory();
if(state->address)
*lsrtp = (*lsrtp & 0xFFFF) | (word << 16);
break;
case 3:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &word;
read_dword_in_memory();
if(state->address)
*lsrtp = (*lsrtp & 0xFFFFFF) | (word << 24);
break;
case 4:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &word;
read_dword_in_memory();
if(state->address)
*lsrtp = (*lsrtp & 0xFFFFFFFF) | (word << 32);
break;
case 5:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &word;
read_dword_in_memory();
if(state->address)
*lsrtp = (*lsrtp & 0xFFFFFFFFFFLL) | (word << 40);
break;
case 6:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &word;
read_dword_in_memory();
if(state->address)
*lsrtp = (*lsrtp & 0xFFFFFFFFFFFFLL) | (word << 48);
break;
case 7:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &word;
read_dword_in_memory();
if(state->address)
*lsrtp = (*lsrtp & 0xFFFFFFFFFFFFFFLL) | (word << 56);
break;
}
}
DECLARE_INSTRUCTION(LDR)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
unsigned long long int word = 0;
ADD_TO_PC(1);
switch ((lsaddr) & 7)
{
case 0:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &word;
read_dword_in_memory();
if(state->address)
*lsrtp = (*lsrtp & 0xFFFFFFFFFFFFFF00LL) | (word >> 56);
break;
case 1:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &word;
read_dword_in_memory();
if(state->address)
*lsrtp = (*lsrtp & 0xFFFFFFFFFFFF0000LL) | (word >> 48);
break;
case 2:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &word;
read_dword_in_memory();
if(state->address)
*lsrtp = (*lsrtp & 0xFFFFFFFFFF000000LL) | (word >> 40);
break;
case 3:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &word;
read_dword_in_memory();
if(state->address)
*lsrtp = (*lsrtp & 0xFFFFFFFF00000000LL) | (word >> 32);
break;
case 4:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &word;
read_dword_in_memory();
if(state->address)
*lsrtp = (*lsrtp & 0xFFFFFF0000000000LL) | (word >> 24);
break;
case 5:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &word;
read_dword_in_memory();
if(state->address)
*lsrtp = (*lsrtp & 0xFFFF000000000000LL) | (word >> 16);
break;
case 6:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &word;
read_dword_in_memory();
if(state->address)
*lsrtp = (*lsrtp & 0xFF00000000000000LL) | (word >> 8);
break;
case 7:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = (unsigned long long *) lsrtp;
read_dword_in_memory();
break;
}
}
DECLARE_INSTRUCTION(LB)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
ADD_TO_PC(1);
state->address = (unsigned int) lsaddr;
state->rdword = (unsigned long long *) lsrtp;
read_byte_in_memory();
if (state->address)
sign_extendedb(*lsrtp);
}
DECLARE_INSTRUCTION(LH)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
ADD_TO_PC(1);
state->address = (unsigned int) lsaddr;
state->rdword = (unsigned long long *) lsrtp;
read_hword_in_memory();
if (state->address)
sign_extendedh(*lsrtp);
}
DECLARE_INSTRUCTION(LWL)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
unsigned long long int word = 0;
ADD_TO_PC(1);
switch ((lsaddr) & 3)
{
case 0:
state->address = (unsigned int) lsaddr;
state->rdword = (unsigned long long *) lsrtp;
read_word_in_memory();
break;
case 1:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC;
state->rdword = &word;
read_word_in_memory();
if(state->address)
*lsrtp = (*lsrtp & 0xFF) | (word << 8);
break;
case 2:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC;
state->rdword = &word;
read_word_in_memory();
if(state->address)
*lsrtp = (*lsrtp & 0xFFFF) | (word << 16);
break;
case 3:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC;
state->rdword = &word;
read_word_in_memory();
if(state->address)
*lsrtp = (*lsrtp & 0xFFFFFF) | (word << 24);
break;
}
if(state->address)
sign_extended(*lsrtp);
}
DECLARE_INSTRUCTION(LW)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
ADD_TO_PC(1);
state->address = (unsigned int) lsaddr;
state->rdword = (unsigned long long *) lsrtp;
read_word_in_memory();
if (state->address)
sign_extended(*lsrtp);
}
DECLARE_INSTRUCTION(LBU)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
ADD_TO_PC(1);
state->address = (unsigned int) lsaddr;
state->rdword = (unsigned long long *) lsrtp;
read_byte_in_memory();
}
DECLARE_INSTRUCTION(LHU)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
ADD_TO_PC(1);
state->address = (unsigned int) lsaddr;
state->rdword = (unsigned long long *) lsrtp;
read_hword_in_memory();
}
DECLARE_INSTRUCTION(LWR)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
unsigned long long int word = 0;
ADD_TO_PC(1);
switch ((lsaddr) & 3)
{
case 0:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC;
state->rdword = &word;
read_word_in_memory();
if(state->address)
*lsrtp = (*lsrtp & 0xFFFFFFFFFFFFFF00LL) | ((word >> 24) & 0xFF);
break;
case 1:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC;
state->rdword = &word;
read_word_in_memory();
if(state->address)
*lsrtp = (*lsrtp & 0xFFFFFFFFFFFF0000LL) | ((word >> 16) & 0xFFFF);
break;
case 2:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC;
state->rdword = &word;
read_word_in_memory();
if(state->address)
*lsrtp = (*lsrtp & 0xFFFFFFFFFF000000LL) | ((word >> 8) & 0XFFFFFF);
break;
case 3:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC;
state->rdword = (unsigned long long *) lsrtp;
read_word_in_memory();
if(state->address)
sign_extended(*lsrtp);
}
}
DECLARE_INSTRUCTION(LWU)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
ADD_TO_PC(1);
state->address = (unsigned int) lsaddr;
state->rdword = (unsigned long long *) lsrtp;
read_word_in_memory();
}
DECLARE_INSTRUCTION(SB)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
ADD_TO_PC(1);
state->address = (unsigned int) lsaddr;
state->cpu_byte = (unsigned char)(*lsrtp & 0xFF);
write_byte_in_memory();
CHECK_MEMORY();
}
DECLARE_INSTRUCTION(SH)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
ADD_TO_PC(1);
state->address = (unsigned int) lsaddr;
state->cpu_hword = (unsigned short)(*lsrtp & 0xFFFF);
write_hword_in_memory();
CHECK_MEMORY();
}
DECLARE_INSTRUCTION(SWL)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
unsigned long long int old_word = 0;
ADD_TO_PC(1);
switch ((lsaddr) & 3)
{
case 0:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC;
state->cpu_word = (unsigned int)*lsrtp;
write_word_in_memory();
CHECK_MEMORY();
break;
case 1:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC;
state->rdword = &old_word;
read_word_in_memory();
if(state->address)
{
state->cpu_word = ((unsigned int)*lsrtp >> 8) | ((unsigned int) old_word & 0xFF000000);
write_word_in_memory();
CHECK_MEMORY();
}
break;
case 2:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC;
state->rdword = &old_word;
read_word_in_memory();
if(state->address)
{
state->cpu_word = ((unsigned int)*lsrtp >> 16) | ((unsigned int) old_word & 0xFFFF0000);
write_word_in_memory();
CHECK_MEMORY();
}
break;
case 3:
state->address = (unsigned int) lsaddr;
state->cpu_byte = (unsigned char)(*lsrtp >> 24);
write_byte_in_memory();
CHECK_MEMORY();
break;
}
}
DECLARE_INSTRUCTION(SW)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
ADD_TO_PC(1);
state->address = (unsigned int) lsaddr;
state->cpu_word = (unsigned int)(*lsrtp & 0xFFFFFFFF);
write_word_in_memory();
CHECK_MEMORY();
}
DECLARE_INSTRUCTION(SDL)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
unsigned long long int old_word = 0;
ADD_TO_PC(1);
switch ((lsaddr) & 7)
{
case 0:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->cpu_dword = *lsrtp;
write_dword_in_memory();
CHECK_MEMORY();
break;
case 1:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &old_word;
read_dword_in_memory();
if(state->address)
{
state->cpu_dword = ((unsigned long long)*lsrtp >> 8)|(old_word & 0xFF00000000000000LL);
write_dword_in_memory();
CHECK_MEMORY();
}
break;
case 2:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &old_word;
read_dword_in_memory();
if(state->address)
{
state->cpu_dword = ((unsigned long long)*lsrtp >> 16)|(old_word & 0xFFFF000000000000LL);
write_dword_in_memory();
CHECK_MEMORY();
}
break;
case 3:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &old_word;
read_dword_in_memory();
if(state->address)
{
state->cpu_dword = ((unsigned long long)*lsrtp >> 24)|(old_word & 0xFFFFFF0000000000LL);
write_dword_in_memory();
CHECK_MEMORY();
}
break;
case 4:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &old_word;
read_dword_in_memory();
if(state->address)
{
state->cpu_dword = ((unsigned long long)*lsrtp >> 32)|(old_word & 0xFFFFFFFF00000000LL);
write_dword_in_memory();
CHECK_MEMORY();
}
break;
case 5:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &old_word;
read_dword_in_memory();
if(state->address)
{
state->cpu_dword = ((unsigned long long)*lsrtp >> 40)|(old_word & 0xFFFFFFFFFF000000LL);
write_dword_in_memory();
CHECK_MEMORY();
}
break;
case 6:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &old_word;
read_dword_in_memory();
if(state->address)
{
state->cpu_dword = ((unsigned long long)*lsrtp >> 48)|(old_word & 0xFFFFFFFFFFFF0000LL);
write_dword_in_memory();
CHECK_MEMORY();
}
break;
case 7:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &old_word;
read_dword_in_memory();
if(state->address)
{
state->cpu_dword = ((unsigned long long)*lsrtp >> 56)|(old_word & 0xFFFFFFFFFFFFFF00LL);
write_dword_in_memory();
CHECK_MEMORY();
}
break;
}
}
DECLARE_INSTRUCTION(SDR)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
unsigned long long int old_word = 0;
ADD_TO_PC(1);
switch ((lsaddr) & 7)
{
case 0:
state->address = (unsigned int) lsaddr;
state->rdword = &old_word;
read_dword_in_memory();
if(state->address)
{
state->cpu_dword = (*lsrtp << 56) | (old_word & 0x00FFFFFFFFFFFFFFLL);
write_dword_in_memory();
CHECK_MEMORY();
}
break;
case 1:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &old_word;
read_dword_in_memory();
if(state->address)
{
state->cpu_dword = (*lsrtp << 48) | (old_word & 0x0000FFFFFFFFFFFFLL);
write_dword_in_memory();
CHECK_MEMORY();
}
break;
case 2:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &old_word;
read_dword_in_memory();
if(state->address)
{
state->cpu_dword = (*lsrtp << 40) | (old_word & 0x000000FFFFFFFFFFLL);
write_dword_in_memory();
CHECK_MEMORY();
}
break;
case 3:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &old_word;
read_dword_in_memory();
if(state->address)
{
state->cpu_dword = (*lsrtp << 32) | (old_word & 0x00000000FFFFFFFFLL);
write_dword_in_memory();
CHECK_MEMORY();
}
break;
case 4:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &old_word;
read_dword_in_memory();
if(state->address)
{
state->cpu_dword = (*lsrtp << 24) | (old_word & 0x0000000000FFFFFFLL);
write_dword_in_memory();
CHECK_MEMORY();
}
break;
case 5:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &old_word;
read_dword_in_memory();
if(state->address)
{
state->cpu_dword = (*lsrtp << 16) | (old_word & 0x000000000000FFFFLL);
write_dword_in_memory();
CHECK_MEMORY();
}
break;
case 6:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->rdword = &old_word;
read_dword_in_memory();
if(state->address)
{
state->cpu_dword = (*lsrtp << 8) | (old_word & 0x00000000000000FFLL);
write_dword_in_memory();
CHECK_MEMORY();
}
break;
case 7:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFF8;
state->cpu_dword = *lsrtp;
write_dword_in_memory();
CHECK_MEMORY();
break;
}
}
DECLARE_INSTRUCTION(SWR)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
unsigned long long int old_word = 0;
ADD_TO_PC(1);
switch ((lsaddr) & 3)
{
case 0:
state->address = (unsigned int) lsaddr;
state->rdword = &old_word;
read_word_in_memory();
if(state->address)
{
state->cpu_word = ((unsigned int)*lsrtp << 24) | ((unsigned int) old_word & 0x00FFFFFF);
write_word_in_memory();
CHECK_MEMORY();
}
break;
case 1:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC;
state->rdword = &old_word;
read_word_in_memory();
if(state->address)
{
state->cpu_word = ((unsigned int)*lsrtp << 16) | ((unsigned int) old_word & 0x0000FFFF);
write_word_in_memory();
CHECK_MEMORY();
}
break;
case 2:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC;
state->rdword = &old_word;
read_word_in_memory();
if(state->address)
{
state->cpu_word = ((unsigned int)*lsrtp << 8) | ((unsigned int) old_word & 0x000000FF);
write_word_in_memory();
CHECK_MEMORY();
}
break;
case 3:
state->address = ((unsigned int) lsaddr) & 0xFFFFFFFC;
state->cpu_word = (unsigned int)*lsrtp;
write_word_in_memory();
CHECK_MEMORY();
break;
}
}
DECLARE_INSTRUCTION(CACHE)
{
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(LL)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
ADD_TO_PC(1);
state->address = (unsigned int) lsaddr;
state->rdword = (unsigned long long *) lsrtp;
read_word_in_memory();
if (state->address)
{
sign_extended(*lsrtp);
state->llbit = 1;
}
}
DECLARE_INSTRUCTION(LWC1)
{
const unsigned char lslfft = lfft;
const unsigned int lslfaddr = (unsigned int)(lfoffset + state->reg[lfbase]);
unsigned long long int temp;
if (check_cop1_unusable(state)) return;
ADD_TO_PC(1);
state->address = (unsigned int) lslfaddr;
state->rdword = &temp;
read_word_in_memory();
if (state->address)
*((int*)state->reg_cop1_simple[lslfft]) = (int) *state->rdword;
}
DECLARE_INSTRUCTION(LDC1)
{
const unsigned char lslfft = lfft;
const unsigned int lslfaddr = (unsigned int)(lfoffset + state->reg[lfbase]);
if (check_cop1_unusable(state)) return;
ADD_TO_PC(1);
state->address = (unsigned int) lslfaddr;
state->rdword = (unsigned long long *)state->reg_cop1_double[lslfft];
read_dword_in_memory();
}
DECLARE_INSTRUCTION(LD)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
ADD_TO_PC(1);
state->address = (unsigned int) lsaddr;
state->rdword = (unsigned long long *) lsrtp;
read_dword_in_memory();
}
DECLARE_INSTRUCTION(SC)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
ADD_TO_PC(1);
if(state->llbit)
{
state->address = (unsigned int) lsaddr;
state->cpu_word = (unsigned int)(*lsrtp & 0xFFFFFFFF);
write_word_in_memory();
CHECK_MEMORY();
state->llbit = 0;
*lsrtp = 1;
}
else
{
*lsrtp = 0;
}
}
DECLARE_INSTRUCTION(SWC1)
{
const unsigned char lslfft = lfft;
const unsigned int lslfaddr = (unsigned int)(lfoffset + state->reg[lfbase]);
if (check_cop1_unusable(state)) return;
ADD_TO_PC(1);
state->address = (unsigned int) lslfaddr;
state->cpu_word = *((int*)state->reg_cop1_simple[lslfft]);
write_word_in_memory();
CHECK_MEMORY();
}
DECLARE_INSTRUCTION(SDC1)
{
const unsigned char lslfft = lfft;
const unsigned int lslfaddr = (unsigned int)(lfoffset + state->reg[lfbase]);
if (check_cop1_unusable(state)) return;
ADD_TO_PC(1);
state->address = (unsigned int) lslfaddr;
state->cpu_dword = *((unsigned long long*)state->reg_cop1_double[lslfft]);
write_dword_in_memory();
CHECK_MEMORY();
}
DECLARE_INSTRUCTION(SD)
{
const unsigned int lsaddr = (unsigned int)(iimmediate + irs32);
long long int *lsrtp = &irt;
ADD_TO_PC(1);
state->address = (unsigned int) lsaddr;
state->cpu_dword = *lsrtp;
write_dword_in_memory();
CHECK_MEMORY();
}

View file

@ -0,0 +1,29 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - interpreter_regimm.def *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
DECLARE_JUMP(BLTZ, PCADDR + (iimmediate+1)*4, irs < 0, &state->reg[0], 0, 0)
DECLARE_JUMP(BGEZ, PCADDR + (iimmediate+1)*4, irs >= 0, &state->reg[0], 0, 0)
DECLARE_JUMP(BLTZL, PCADDR + (iimmediate+1)*4, irs < 0, &state->reg[0], 1, 0)
DECLARE_JUMP(BGEZL, PCADDR + (iimmediate+1)*4, irs >= 0, &state->reg[0], 1, 0)
DECLARE_JUMP(BLTZAL, PCADDR + (iimmediate+1)*4, irs < 0, &state->reg[31], 0, 0)
DECLARE_JUMP(BGEZAL, PCADDR + (iimmediate+1)*4, irs >= 0, &state->reg[31], 0, 0)
DECLARE_JUMP(BLTZALL, PCADDR + (iimmediate+1)*4, irs < 0, &state->reg[31], 1, 0)
DECLARE_JUMP(BGEZALL, PCADDR + (iimmediate+1)*4, irs >= 0, &state->reg[31], 1, 0)

View file

@ -0,0 +1,408 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - interpreter_special.def *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
DECLARE_INSTRUCTION(NOP)
{
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(SLL)
{
rrd32 = (unsigned int)(rrt32) << rsa;
sign_extended(rrd);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(SRL)
{
rrd32 = (unsigned int)rrt32 >> rsa;
sign_extended(rrd);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(SRA)
{
rrd32 = (signed int)rrt32 >> rsa;
sign_extended(rrd);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(SLLV)
{
rrd32 = (unsigned int)(rrt32) << (rrs32&0x1F);
sign_extended(rrd);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(SRLV)
{
rrd32 = (unsigned int)rrt32 >> (rrs32 & 0x1F);
sign_extended(rrd);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(SRAV)
{
rrd32 = (signed int)rrt32 >> (rrs32 & 0x1F);
sign_extended(rrd);
ADD_TO_PC(1);
}
DECLARE_JUMP(JR, irs32, 1, &state->reg[0], 0, 0)
DECLARE_JUMP(JALR, irs32, 1, &rrd, 0, 0)
DECLARE_INSTRUCTION(SYSCALL)
{
state->g_cp0_regs[CP0_CAUSE_REG] = 8 << 2;
exception_general(state);
}
DECLARE_INSTRUCTION(SYNC)
{
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(MFHI)
{
rrd = state->hi;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(MTHI)
{
state->hi = rrs;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(MFLO)
{
rrd = state->lo;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(MTLO)
{
state->lo = rrs;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DSLLV)
{
rrd = rrt << (rrs32&0x3F);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DSRLV)
{
rrd = (unsigned long long)rrt >> (rrs32 & 0x3F);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DSRAV)
{
rrd = (long long)rrt >> (rrs32 & 0x3F);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(MULT)
{
long long int temp;
temp = rrs * rrt;
state->hi = temp >> 32;
state->lo = temp;
sign_extended(state->lo);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(MULTU)
{
unsigned long long int temp;
temp = (unsigned int)rrs * (unsigned long long)((unsigned int)rrt);
state->hi = (long long)temp >> 32;
state->lo = temp;
sign_extended(state->lo);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DIV)
{
if (rrt32)
{
state->lo = rrs32 / rrt32;
state->hi = rrs32 % rrt32;
sign_extended(state->lo);
sign_extended(state->hi);
}
else DebugMessage(state, M64MSG_ERROR, "DIV: divide by 0");
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DIVU)
{
if (rrt32)
{
state->lo = (unsigned int)rrs32 / (unsigned int)rrt32;
state->hi = (unsigned int)rrs32 % (unsigned int)rrt32;
sign_extended(state->lo);
sign_extended(state->hi);
}
else DebugMessage(state, M64MSG_ERROR, "DIVU: divide by 0");
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DMULT)
{
unsigned long long int op1, op2, op3, op4;
unsigned long long int result1, result2, result3, result4;
unsigned long long int temp1, temp2, temp3, temp4;
int sign = 0;
if (rrs < 0)
{
op2 = -rrs;
sign = 1 - sign;
}
else op2 = rrs;
if (rrt < 0)
{
op4 = -rrt;
sign = 1 - sign;
}
else op4 = rrt;
op1 = op2 & 0xFFFFFFFF;
op2 = (op2 >> 32) & 0xFFFFFFFF;
op3 = op4 & 0xFFFFFFFF;
op4 = (op4 >> 32) & 0xFFFFFFFF;
temp1 = op1 * op3;
temp2 = (temp1 >> 32) + op1 * op4;
temp3 = op2 * op3;
temp4 = (temp3 >> 32) + op2 * op4;
result1 = temp1 & 0xFFFFFFFF;
result2 = temp2 + (temp3 & 0xFFFFFFFF);
result3 = (result2 >> 32) + temp4;
result4 = (result3 >> 32);
state->lo = result1 | (result2 << 32);
state->hi = (result3 & 0xFFFFFFFF) | (result4 << 32);
if (sign)
{
state->hi = ~state->hi;
if (!state->lo) state->hi++;
else state->lo = ~state->lo + 1;
}
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DMULTU)
{
unsigned long long int op1, op2, op3, op4;
unsigned long long int result1, result2, result3, result4;
unsigned long long int temp1, temp2, temp3, temp4;
op1 = rrs & 0xFFFFFFFF;
op2 = (rrs >> 32) & 0xFFFFFFFF;
op3 = rrt & 0xFFFFFFFF;
op4 = (rrt >> 32) & 0xFFFFFFFF;
temp1 = op1 * op3;
temp2 = (temp1 >> 32) + op1 * op4;
temp3 = op2 * op3;
temp4 = (temp3 >> 32) + op2 * op4;
result1 = temp1 & 0xFFFFFFFF;
result2 = temp2 + (temp3 & 0xFFFFFFFF);
result3 = (result2 >> 32) + temp4;
result4 = (result3 >> 32);
state->lo = result1 | (result2 << 32);
state->hi = (result3 & 0xFFFFFFFF) | (result4 << 32);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DDIV)
{
if (rrt)
{
state->lo = (long long int)rrs / (long long int)rrt;
state->hi = (long long int)rrs % (long long int)rrt;
}
else DebugMessage(state, M64MSG_ERROR, "DDIV: divide by 0");
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DDIVU)
{
if (rrt)
{
state->lo = (unsigned long long int)rrs / (unsigned long long int)rrt;
state->hi = (unsigned long long int)rrs % (unsigned long long int)rrt;
}
else DebugMessage(state, M64MSG_ERROR, "DDIVU: divide by 0");
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(ADD)
{
rrd32 = rrs32 + rrt32;
sign_extended(rrd);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(ADDU)
{
rrd32 = rrs32 + rrt32;
sign_extended(rrd);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(SUB)
{
rrd32 = rrs32 - rrt32;
sign_extended(rrd);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(SUBU)
{
rrd32 = rrs32 - rrt32;
sign_extended(rrd);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(AND)
{
rrd = rrs & rrt;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(OR)
{
rrd = rrs | rrt;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(XOR)
{
rrd = rrs ^ rrt;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(NOR)
{
rrd = ~(rrs | rrt);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(SLT)
{
if (rrs < rrt) rrd = 1;
else rrd = 0;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(SLTU)
{
if ((unsigned long long)rrs < (unsigned long long)rrt)
rrd = 1;
else rrd = 0;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DADD)
{
rrd = rrs + rrt;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DADDU)
{
rrd = rrs + rrt;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DSUB)
{
rrd = rrs - rrt;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DSUBU)
{
rrd = rrs - rrt;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(TEQ)
{
if (rrs == rrt)
{
DebugMessage(state, M64MSG_ERROR, "trap exception in TEQ");
state->stop=1;
}
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DSLL)
{
rrd = rrt << rsa;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DSRL)
{
rrd = (unsigned long long)rrt >> rsa;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DSRA)
{
rrd = rrt >> rsa;
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DSLL32)
{
rrd = rrt << (32+rsa);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DSRL32)
{
rrd = (unsigned long long int)rrt >> (32+rsa);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(DSRA32)
{
rrd = (signed long long int)rrt >> (32+rsa);
ADD_TO_PC(1);
}
/* Idle loop hack from 64th Note */
DECLARE_INSTRUCTION(BREAK)
{
state->g_cp0_regs[CP0_COUNT_REG] = state->next_interupt;
ADD_TO_PC(1);
}

View file

@ -0,0 +1,250 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - interpreter_tlb.def *
* 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 <zlib.h> // For adler32()
DECLARE_INSTRUCTION(TLBR)
{
int index;
index = state->g_cp0_regs[CP0_INDEX_REG] & 0x1F;
state->g_cp0_regs[CP0_PAGEMASK_REG] = state->tlb_e[index].mask << 13;
state->g_cp0_regs[CP0_ENTRYHI_REG] = ((state->tlb_e[index].vpn2 << 13) | state->tlb_e[index].asid);
state->g_cp0_regs[CP0_ENTRYLO0_REG] = (state->tlb_e[index].pfn_even << 6) | (state->tlb_e[index].c_even << 3)
| (state->tlb_e[index].d_even << 2) | (state->tlb_e[index].v_even << 1)
| state->tlb_e[index].g;
state->g_cp0_regs[CP0_ENTRYLO1_REG] = (state->tlb_e[index].pfn_odd << 6) | (state->tlb_e[index].c_odd << 3)
| (state->tlb_e[index].d_odd << 2) | (state->tlb_e[index].v_odd << 1)
| state->tlb_e[index].g;
ADD_TO_PC(1);
}
static void TLBWrite(usf_state_t * state, unsigned int idx)
{
if (state->r4300emu != CORE_PURE_INTERPRETER)
{
unsigned int i;
if (state->tlb_e[idx].v_even)
{
for (i=state->tlb_e[idx].start_even>>12; i<=state->tlb_e[idx].end_even>>12; i++)
{
if(!state->invalid_code[i] &&(state->invalid_code[state->tlb_LUT_r[i]>>12] ||
state->invalid_code[(state->tlb_LUT_r[i]>>12)+0x20000]))
state->invalid_code[i] = 1;
if (!state->invalid_code[i])
{
/*int j;
md5_state_t state;
md5_byte_t digest[16];
md5_init(&state);
md5_append(&state,
(const md5_byte_t*)&state->g_rdram[(state->tlb_LUT_r[i]&0x7FF000)/4],
0x1000);
md5_finish(&state, digest);
for (j=0; j<16; j++) state->blocks[i]->md5[j] = digest[j];*/
state->blocks[i]->adler32 = adler32(0, (const unsigned char *)&state->g_rdram[(state->tlb_LUT_r[i]&0x7FF000)/4], 0x1000);
state->invalid_code[i] = 1;
}
else if (state->blocks[i])
{
/*int j;
for (j=0; j<16; j++) state->blocks[i]->md5[j] = 0;*/
state->blocks[i]->adler32 = 0;
}
}
}
if (state->tlb_e[idx].v_odd)
{
for (i=state->tlb_e[idx].start_odd>>12; i<=state->tlb_e[idx].end_odd>>12; i++)
{
if(!state->invalid_code[i] &&(state->invalid_code[state->tlb_LUT_r[i]>>12] ||
state->invalid_code[(state->tlb_LUT_r[i]>>12)+0x20000]))
state->invalid_code[i] = 1;
if (!state->invalid_code[i])
{
/*int j;
md5_state_t state;
md5_byte_t digest[16];
md5_init(&state);
md5_append(&state,
(const md5_byte_t*)&state->g_rdram[(state->tlb_LUT_r[i]&0x7FF000)/4],
0x1000);
md5_finish(&state, digest);
for (j=0; j<16; j++) state->blocks[i]->md5[j] = digest[j];*/
state->blocks[i]->adler32 = adler32(0, (const unsigned char *)&state->g_rdram[(state->tlb_LUT_r[i]&0x7FF000)/4], 0x1000);
state->invalid_code[i] = 1;
}
else if (state->blocks[i])
{
/*int j;
for (j=0; j<16; j++) state->blocks[i]->md5[j] = 0;*/
state->blocks[i]->adler32 = 0;
}
}
}
}
tlb_unmap(state, &state->tlb_e[idx]);
state->tlb_e[idx].g = (state->g_cp0_regs[CP0_ENTRYLO0_REG] & state->g_cp0_regs[CP0_ENTRYLO1_REG] & 1);
state->tlb_e[idx].pfn_even = (state->g_cp0_regs[CP0_ENTRYLO0_REG] & 0x3FFFFFC0) >> 6;
state->tlb_e[idx].pfn_odd = (state->g_cp0_regs[CP0_ENTRYLO1_REG] & 0x3FFFFFC0) >> 6;
state->tlb_e[idx].c_even = (state->g_cp0_regs[CP0_ENTRYLO0_REG] & 0x38) >> 3;
state->tlb_e[idx].c_odd = (state->g_cp0_regs[CP0_ENTRYLO1_REG] & 0x38) >> 3;
state->tlb_e[idx].d_even = (state->g_cp0_regs[CP0_ENTRYLO0_REG] & 0x4) >> 2;
state->tlb_e[idx].d_odd = (state->g_cp0_regs[CP0_ENTRYLO1_REG] & 0x4) >> 2;
state->tlb_e[idx].v_even = (state->g_cp0_regs[CP0_ENTRYLO0_REG] & 0x2) >> 1;
state->tlb_e[idx].v_odd = (state->g_cp0_regs[CP0_ENTRYLO1_REG] & 0x2) >> 1;
state->tlb_e[idx].asid = (state->g_cp0_regs[CP0_ENTRYHI_REG] & 0xFF);
state->tlb_e[idx].vpn2 = (state->g_cp0_regs[CP0_ENTRYHI_REG] & 0xFFFFE000) >> 13;
//state->tlb_e[idx].r = (state->g_cp0_regs[CP0_ENTRYHI_REG] & 0xC000000000000000LL) >> 62;
state->tlb_e[idx].mask = (state->g_cp0_regs[CP0_PAGEMASK_REG] & 0x1FFE000) >> 13;
state->tlb_e[idx].start_even = state->tlb_e[idx].vpn2 << 13;
state->tlb_e[idx].end_even = state->tlb_e[idx].start_even+
(state->tlb_e[idx].mask << 12) + 0xFFF;
state->tlb_e[idx].phys_even = state->tlb_e[idx].pfn_even << 12;
state->tlb_e[idx].start_odd = state->tlb_e[idx].end_even+1;
state->tlb_e[idx].end_odd = state->tlb_e[idx].start_odd+
(state->tlb_e[idx].mask << 12) + 0xFFF;
state->tlb_e[idx].phys_odd = state->tlb_e[idx].pfn_odd << 12;
tlb_map(state, &state->tlb_e[idx]);
if (state->r4300emu != CORE_PURE_INTERPRETER)
{
unsigned int i;
if (state->tlb_e[idx].v_even)
{
for (i=state->tlb_e[idx].start_even>>12; i<=state->tlb_e[idx].end_even>>12; i++)
{
/*if (state->blocks[i] && (state->blocks[i]->md5[0] || state->blocks[i]->md5[1] ||
state->blocks[i]->md5[2] || state->blocks[i]->md5[3]))
{
int j;
int equal = 1;
md5_state_t state;
md5_byte_t digest[16];
md5_init(&state);
md5_append(&state,
(const md5_byte_t*)&state->g_rdram[(state->tlb_LUT_r[i]&0x7FF000)/4],
0x1000);
md5_finish(&state, digest);
for (j=0; j<16; j++)
if (digest[j] != state->blocks[i]->md5[j])
equal = 0;
if (equal) state->invalid_code[i] = 0;
}*/
if(state->blocks[i] && state->blocks[i]->adler32)
{
if(state->blocks[i]->adler32 == adler32(0,(const unsigned char *)&state->g_rdram[(state->tlb_LUT_r[i]&0x7FF000)/4],0x1000))
state->invalid_code[i] = 0;
}
}
}
if (state->tlb_e[idx].v_odd)
{
for (i=state->tlb_e[idx].start_odd>>12; i<=state->tlb_e[idx].end_odd>>12; i++)
{
/*if (state->blocks[i] && (state->blocks[i]->md5[0] || state->blocks[i]->md5[1] ||
state->blocks[i]->md5[2] || state->blocks[i]->md5[3]))
{
int j;
int equal = 1;
md5_state_t state;
md5_byte_t digest[16];
md5_init(&state);
md5_append(&state,
(const md5_byte_t*)&state->g_rdram[(state->tlb_LUT_r[i]&0x7FF000)/4],
0x1000);
md5_finish(&state, digest);
for (j=0; j<16; j++)
if (digest[j] != state->blocks[i]->md5[j])
equal = 0;
if (equal) state->invalid_code[i] = 0;
}*/
if(state->blocks[i] && state->blocks[i]->adler32)
{
if(state->blocks[i]->adler32 == adler32(0,(const unsigned char *)&state->g_rdram[(state->tlb_LUT_r[i]&0x7FF000)/4],0x1000))
state->invalid_code[i] = 0;
}
}
}
}
}
DECLARE_INSTRUCTION(TLBWI)
{
TLBWrite(state, state->g_cp0_regs[CP0_INDEX_REG]&0x3F);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(TLBWR)
{
update_count(state);
state->g_cp0_regs[CP0_RANDOM_REG] = (state->g_cp0_regs[CP0_COUNT_REG]/2 % (32 - state->g_cp0_regs[CP0_WIRED_REG]))
+ state->g_cp0_regs[CP0_WIRED_REG];
TLBWrite(state, state->g_cp0_regs[CP0_RANDOM_REG]);
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(TLBP)
{
int i;
state->g_cp0_regs[CP0_INDEX_REG] |= 0x80000000;
for (i=0; i<32; i++)
{
if (((state->tlb_e[i].vpn2 & (~state->tlb_e[i].mask)) ==
(((state->g_cp0_regs[CP0_ENTRYHI_REG] & 0xFFFFE000) >> 13) & (~state->tlb_e[i].mask))) &&
((state->tlb_e[i].g) ||
(state->tlb_e[i].asid == (state->g_cp0_regs[CP0_ENTRYHI_REG] & 0xFF))))
{
state->g_cp0_regs[CP0_INDEX_REG] = i;
break;
}
}
ADD_TO_PC(1);
}
DECLARE_INSTRUCTION(ERET)
{
update_count(state);
if (state->g_cp0_regs[CP0_STATUS_REG] & 0x4)
{
DebugMessage(state, M64MSG_ERROR, "error in ERET");
state->stop=1;
}
else
{
state->g_cp0_regs[CP0_STATUS_REG] &= ~0x2;
generic_jump_to(state, state->g_cp0_regs[CP0_EPC_REG]);
}
state->llbit = 0;
check_interupt(state);
state->last_addr = PCADDR;
if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state);
}

View file

@ -0,0 +1,601 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - interupt.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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#define M64P_CORE_PROTOTYPES 1
#include "usf/usf.h"
#include "usf/usf_internal.h"
#include "interupt.h"
#include "cached_interp.h"
#include "cp0.h"
#include "exception.h"
#include "new_dynarec/new_dynarec.h"
#include "r4300.h"
#include "r4300_core.h"
#include "reset.h"
#include "ai/ai_controller.h"
#include "api/m64p_types.h"
#include "api/callbacks.h"
#include "main/main.h"
#include "main/savestates.h"
#include "pi/pi_controller.h"
#include "rdp/rdp_core.h"
#include "rsp/rsp_core.h"
#include "si/si_controller.h"
#include "vi/vi_controller.h"
#include <string.h>
/***************************************************************************
* Pool of Single Linked List Nodes
**************************************************************************/
#ifndef INTERUPT_STRUCTS
#define INTERUPT_STRUCTS
#define POOL_CAPACITY 16
struct interrupt_event
{
int type;
unsigned int count;
};
struct node
{
struct interrupt_event data;
struct node *next;
};
struct pool
{
struct node nodes[POOL_CAPACITY];
struct node* stack[POOL_CAPACITY];
size_t index;
};
struct interrupt_queue
{
struct pool pool;
struct node* first;
};
#endif
static struct node* alloc_node(struct pool* p);
static void free_node(struct pool* p, struct node* node);
static void clear_pool(struct pool* p);
/* node allocation/deallocation on a given pool */
static struct node* alloc_node(struct pool* p)
{
/* return NULL if pool is too small */
if (p->index >= POOL_CAPACITY)
return NULL;
return p->stack[p->index++];
}
static void free_node(struct pool* p, struct node* node)
{
if (p->index == 0 || node == NULL)
return;
p->stack[--p->index] = node;
}
/* release all nodes */
static void clear_pool(struct pool* p)
{
size_t i;
for(i = 0; i < POOL_CAPACITY; ++i)
p->stack[i] = &p->nodes[i];
p->index = 0;
}
/***************************************************************************
* Interrupt Queue
**************************************************************************/
static void clear_queue(usf_state_t * state)
{
state->q.first = NULL;
clear_pool(&state->q.pool);
}
static int before_event(usf_state_t * state, unsigned int evt1, unsigned int evt2, int type2)
{
if(evt1 - state->g_cp0_regs[CP0_COUNT_REG] < 0x80000000)
{
if(evt2 - state->g_cp0_regs[CP0_COUNT_REG] < 0x80000000)
{
if((evt1 - state->g_cp0_regs[CP0_COUNT_REG]) < (evt2 - state->g_cp0_regs[CP0_COUNT_REG])) return 1;
else return 0;
}
else
{
if((state->g_cp0_regs[CP0_COUNT_REG] - evt2) < 0x10000000)
{
switch(type2)
{
case SPECIAL_INT:
if(state->SPECIAL_done) return 1;
else return 0;
break;
default:
return 0;
}
}
else return 1;
}
}
else return 0;
}
void add_interupt_event(usf_state_t * state, int type, unsigned int delay)
{
add_interupt_event_count(state, type, state->g_cp0_regs[CP0_COUNT_REG] + delay);
}
void add_interupt_event_count(usf_state_t * state, int type, unsigned int count)
{
struct node* event;
struct node* e;
int special;
special = (type == SPECIAL_INT);
if(state->g_cp0_regs[CP0_COUNT_REG] > 0x80000000) state->SPECIAL_done = 0;
if (get_event(state, type)) {
DebugMessage(state, M64MSG_WARNING, "two events of type 0x%x in interrupt queue", type);
/* FIXME: hack-fix for freezing in Perfect Dark
* http://code.google.com/p/mupen64plus/issues/detail?id=553
* https://github.com/mupen64plus-ae/mupen64plus-ae/commit/802d8f81d46705d64694d7a34010dc5f35787c7d
*/
return;
}
event = alloc_node(&state->q.pool);
if (event == NULL)
{
DebugMessage(state, M64MSG_ERROR, "Failed to allocate node for new interrupt event");
return;
}
event->data.count = count;
event->data.type = type;
if (state->q.first == NULL)
{
state->q.first = event;
event->next = NULL;
state->next_interupt = state->q.first->data.count;
}
else if (before_event(state, count, state->q.first->data.count, state->q.first->data.type) && !special)
{
event->next = state->q.first;
state->q.first = event;
state->next_interupt = state->q.first->data.count;
}
else
{
for(e = state->q.first;
e->next != NULL &&
(!before_event(state, count, e->next->data.count, e->next->data.type) || special);
e = e->next);
if (e->next == NULL)
{
e->next = event;
event->next = NULL;
}
else
{
if (!special)
for(; e->next != NULL && e->next->data.count == count; e = e->next);
event->next = e->next;
e->next = event;
}
}
}
static void remove_interupt_event(usf_state_t * state)
{
struct node* e;
e = state->q.first;
state->q.first = e->next;
free_node(&state->q.pool, e);
state->next_interupt = (state->q.first != NULL
&& (state->q.first->data.count > state->g_cp0_regs[CP0_COUNT_REG]
|| (state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count) < 0x80000000))
? state->q.first->data.count
: 0;
}
unsigned int get_event(usf_state_t * state, int type)
{
struct node* e = state->q.first;
if (e == NULL)
return 0;
if (e->data.type == type)
return e->data.count;
for(; e->next != NULL && e->next->data.type != type; e = e->next);
return (e->next != NULL)
? e->next->data.count
: 0;
}
int get_next_event_type(usf_state_t * state)
{
return (state->q.first == NULL)
? 0
: state->q.first->data.type;
}
void remove_event(usf_state_t * state, int type)
{
struct node* to_del;
struct node* e = state->q.first;
if (e == NULL)
return;
if (e->data.type == type)
{
state->q.first = e->next;
free_node(&state->q.pool, e);
}
else
{
for(; e->next != NULL && e->next->data.type != type; e = e->next);
if (e->next != NULL)
{
to_del = e->next;
e->next = to_del->next;
free_node(&state->q.pool, to_del);
}
}
}
void translate_event_queue(usf_state_t * state, unsigned int base)
{
struct node* e;
remove_event(state, COMPARE_INT);
remove_event(state, SPECIAL_INT);
for(e = state->q.first; e != NULL; e = e->next)
{
e->data.count = (e->data.count - state->g_cp0_regs[CP0_COUNT_REG]) + base;
}
add_interupt_event_count(state, COMPARE_INT, state->g_cp0_regs[CP0_COMPARE_REG]);
add_interupt_event_count(state, SPECIAL_INT, 0);
r4300_reset_checkpoint(state, base);
}
int save_eventqueue_infos(usf_state_t * state, char *buf)
{
int len;
struct node* e;
len = 0;
for(e = state->q.first; e != NULL; e = e->next)
{
memcpy(buf + len , &e->data.type , 4);
memcpy(buf + len + 4, &e->data.count, 4);
len += 8;
}
*((unsigned int*)&buf[len]) = 0xFFFFFFFF;
return len+4;
}
void load_eventqueue_infos(usf_state_t * state, char *buf)
{
int len = 0;
clear_queue(state);
while (*((unsigned int*)&buf[len]) != 0xFFFFFFFF)
{
int type = *((unsigned int*)&buf[len]);
unsigned int count = *((unsigned int*)&buf[len+4]);
add_interupt_event_count(state, type, count);
len += 8;
}
}
void init_interupt(usf_state_t * state)
{
state->SPECIAL_done = 1;
state->g_vi.delay = state->g_vi.next_vi = 5000;
clear_queue(state);
add_interupt_event_count(state, VI_INT, state->g_vi.next_vi);
add_interupt_event_count(state, SPECIAL_INT, 0);
}
void check_interupt(usf_state_t * state)
{
struct node* event;
state->g_r4300.mi.regs[MI_INTR_REG] &= ~MI_INTR_AI;
state->g_r4300.mi.regs[MI_INTR_REG] |= state->g_r4300.mi.AudioIntrReg & MI_INTR_AI;
#ifdef DEBUG_INFO
if (state->g_r4300.mi.regs[MI_INTR_REG])
fprintf(state->debug_log, "Interrupt %d - ", state->g_r4300.mi.regs[MI_INTR_REG]);
#endif
if (state->g_r4300.mi.regs[MI_INTR_REG] & state->g_r4300.mi.regs[MI_INTR_MASK_REG])
{
#ifdef DEBUG_INFO
fprintf(state->debug_log, "triggered\n");
#endif
state->g_cp0_regs[CP0_CAUSE_REG] = (state->g_cp0_regs[CP0_CAUSE_REG] | 0x400) & 0xFFFFFF83;
}
else
{
#ifdef DEBUG_INFO
if (state->g_r4300.mi.regs[MI_INTR_REG])
fprintf(state->debug_log, "masked\n");
#endif
state->g_cp0_regs[CP0_CAUSE_REG] &= ~0x400;
}
if ((state->g_cp0_regs[CP0_STATUS_REG] & 7) != 1) return;
if (state->g_cp0_regs[CP0_STATUS_REG] & state->g_cp0_regs[CP0_CAUSE_REG] & 0xFF00)
{
event = alloc_node(&state->q.pool);
if (event == NULL)
{
DebugMessage(state, M64MSG_ERROR, "Failed to allocate node for new interrupt event");
return;
}
event->data.count = state->next_interupt = state->g_cp0_regs[CP0_COUNT_REG];
event->data.type = CHECK_INT;
if (state->q.first == NULL)
{
state->q.first = event;
event->next = NULL;
}
else
{
event->next = state->q.first;
state->q.first = event;
}
}
}
static void wrapped_exception_general(usf_state_t * state)
{
#ifdef NEW_DYNAREC
if (r4300emu == CORE_DYNAREC) {
state->g_cp0_regs[CP0_EPC_REG] = pcaddr;
state->pcaddr = 0x80000180;
state->g_cp0_regs[CP0_STATUS_REG] |= 2;
state->g_cp0_regs[CP0_CAUSE_REG] &= 0x7FFFFFFF;
state->pending_exception=1;
} else {
exception_general(state);
}
#else
exception_general(state);
#endif
}
void raise_maskable_interrupt(usf_state_t * state, uint32_t cause)
{
state->g_cp0_regs[CP0_CAUSE_REG] = (state->g_cp0_regs[CP0_CAUSE_REG] | cause) & 0xffffff83;
if (!(state->g_cp0_regs[CP0_STATUS_REG] & state->g_cp0_regs[CP0_CAUSE_REG] & 0xff00))
return;
if ((state->g_cp0_regs[CP0_STATUS_REG] & 7) != 1)
return;
wrapped_exception_general(state);
}
static void special_int_handler(usf_state_t * state)
{
if (state->g_cp0_regs[CP0_COUNT_REG] > 0x10000000)
return;
state->SPECIAL_done = 1;
remove_interupt_event(state);
add_interupt_event_count(state, SPECIAL_INT, 0);
}
static void compare_int_handler(usf_state_t * state)
{
remove_interupt_event(state);
state->g_cp0_regs[CP0_COUNT_REG]+=state->count_per_op;
add_interupt_event_count(state, COMPARE_INT, state->g_cp0_regs[CP0_COMPARE_REG]);
state->g_cp0_regs[CP0_COUNT_REG]-=state->count_per_op;
if (state->enablecompare)
raise_maskable_interrupt(state, 0x8000);
}
static void hw2_int_handler(usf_state_t * state)
{
// Hardware Interrupt 2 -- remove interrupt event from queue
remove_interupt_event(state);
state->g_cp0_regs[CP0_STATUS_REG] = (state->g_cp0_regs[CP0_STATUS_REG] & ~0x00380000) | 0x1000;
state->g_cp0_regs[CP0_CAUSE_REG] = (state->g_cp0_regs[CP0_CAUSE_REG] | 0x1000) & 0xffffff83;
wrapped_exception_general(state);
}
static void nmi_int_handler(usf_state_t * state)
{
// Non Maskable Interrupt -- remove interrupt event from queue
remove_interupt_event(state);
// setup r4300 Status flags: reset TS and SR, set BEV, ERL, and SR
state->g_cp0_regs[CP0_STATUS_REG] = (state->g_cp0_regs[CP0_STATUS_REG] & ~0x00380000) | 0x00500004;
state->g_cp0_regs[CP0_CAUSE_REG] = 0x00000000;
// simulate the soft reset code which would run from the PIF ROM
r4300_reset_soft(state);
// clear all interrupts, reset interrupt counters back to 0
state->g_cp0_regs[CP0_COUNT_REG] = 0;
state->g_gs_vi_counter = 0;
init_interupt(state);
// clear the audio status register so that subsequent write_ai() calls will work properly
state->g_ai.regs[AI_STATUS_REG] = 0;
// set ErrorEPC with the last instruction address
state->g_cp0_regs[CP0_ERROREPC_REG] = state->PC->addr;
// reset the r4300 internal state
if (state->r4300emu != CORE_PURE_INTERPRETER)
{
// clear all the compiled instruction blocks and re-initialize
free_blocks(state);
init_blocks(state);
}
// adjust ErrorEPC if we were in a delay slot, and clear the delay_slot and dyna_interp flags
if(state->delay_slot==1 || state->delay_slot==3)
{
state->g_cp0_regs[CP0_ERROREPC_REG]-=4;
}
state->delay_slot = 0;
state->dyna_interp = 0;
// set next instruction address to reset vector
state->last_addr = 0xa4000040;
generic_jump_to(state, 0xa4000040);
}
void osal_fastcall gen_interupt(usf_state_t * state)
{
r4300_checkpoint(state);
if (state->stop == 1)
{
state->g_gs_vi_counter = 0; // debug
dyna_stop(state);
}
if (!state->interupt_unsafe_state)
{
if (state->reset_hard_job)
{
reset_hard(state);
state->reset_hard_job = 0;
return;
}
}
if (state->skip_jump)
{
unsigned int dest = state->skip_jump;
state->skip_jump = 0;
state->next_interupt = (state->q.first->data.count > state->g_cp0_regs[CP0_COUNT_REG]
|| (state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count) < 0x80000000)
? state->q.first->data.count
: 0;
state->last_addr = dest;
generic_jump_to(state, dest);
return;
}
switch(state->q.first->data.type)
{
case SPECIAL_INT:
special_int_handler(state);
break;
case VI_INT:
remove_interupt_event(state);
vi_vertical_interrupt_event(&state->g_vi);
break;
case COMPARE_INT:
compare_int_handler(state);
break;
case CHECK_INT:
remove_interupt_event(state);
wrapped_exception_general(state);
break;
case SI_INT:
remove_interupt_event(state);
si_end_of_dma_event(&state->g_si);
break;
case PI_INT:
remove_interupt_event(state);
pi_end_of_dma_event(&state->g_pi);
break;
case AI_INT:
remove_interupt_event(state);
ai_end_of_dma_event(&state->g_ai);
break;
case SP_INT:
remove_interupt_event(state);
rsp_interrupt_event(&state->g_sp);
break;
case DP_INT:
remove_interupt_event(state);
rdp_interrupt_event(&state->g_dp);
break;
case HW2_INT:
hw2_int_handler(state);
break;
case NMI_INT:
nmi_int_handler(state);
break;
default:
DebugMessage(state, M64MSG_ERROR, "Unknown interrupt queue event type %.8X.", state->q.first->data.type);
remove_interupt_event(state);
wrapped_exception_general(state);
break;
}
}

View file

@ -0,0 +1,60 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - interupt.h *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_R4300_INTERUPT_H
#define M64P_R4300_INTERUPT_H
#include <stdint.h>
#include "usf/usf.h"
void init_interupt(usf_state_t *);
// set to avoid savestates/reset if state may be inconsistent
// (e.g. in the middle of an instruction)
void raise_maskable_interrupt(usf_state_t *, uint32_t cause);
void osal_fastcall gen_interupt(usf_state_t *);
void check_interupt(usf_state_t *);
void translate_event_queue(usf_state_t *, unsigned int base);
void remove_event(usf_state_t *, int type);
void add_interupt_event_count(usf_state_t *, int type, unsigned int count);
void add_interupt_event(usf_state_t *, int type, unsigned int delay);
unsigned int get_event(usf_state_t *, int type);
int get_next_event_type(usf_state_t *);
int save_eventqueue_infos(usf_state_t *, char *buf);
void load_eventqueue_infos(usf_state_t *, char *buf);
#define VI_INT 0x001
#define COMPARE_INT 0x002
#define CHECK_INT 0x004
#define SI_INT 0x008
#define PI_INT 0x010
#define SPECIAL_INT 0x020
#define AI_INT 0x040
#define SP_INT 0x080
#define DP_INT 0x100
#define HW2_INT 0x200
#define NMI_INT 0x400
#endif /* M64P_R4300_INTERUPT_H */

View file

@ -0,0 +1,63 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - macros.h *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_R4300_MACROS_H
#define M64P_R4300_MACROS_H
#define sign_extended(a) a = (long long)((int)a)
#define sign_extendedb(a) a = (long long)((signed char)a)
#define sign_extendedh(a) a = (long long)((short)a)
#define rrt *state->PC->f.r.rt
#define rrd *state->PC->f.r.rd
#define rfs state->PC->f.r.nrd
#define rrs *state->PC->f.r.rs
#define rsa state->PC->f.r.sa
#define irt *state->PC->f.i.rt
#define ioffset state->PC->f.i.immediate
#define iimmediate state->PC->f.i.immediate
#define irs *state->PC->f.i.rs
#define ibase *state->PC->f.i.rs
#define jinst_index state->PC->f.j.inst_index
#define lfbase state->PC->f.lf.base
#define lfft state->PC->f.lf.ft
#define lfoffset state->PC->f.lf.offset
#define cfft state->PC->f.cf.ft
#define cffs state->PC->f.cf.fs
#define cffd state->PC->f.cf.fd
// 32 bits macros
#ifndef M64P_BIG_ENDIAN
#define rrt32 *((int*)state->PC->f.r.rt)
#define rrd32 *((int*)state->PC->f.r.rd)
#define rrs32 *((int*)state->PC->f.r.rs)
#define irs32 *((int*)state->PC->f.i.rs)
#define irt32 *((int*)state->PC->f.i.rt)
#else
#define rrt32 *((int*)state->PC->f.r.rt+1)
#define rrd32 *((int*)state->PC->f.r.rd+1)
#define rrs32 *((int*)state->PC->f.r.rs+1)
#define irs32 *((int*)state->PC->f.i.rs+1)
#define irt32 *((int*)state->PC->f.i.rt+1)
#endif
#endif /* M64P_R4300_MACROS_H */

View file

@ -0,0 +1,136 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - mi_controller.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* 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 "usf/usf.h"
#include "usf/usf_internal.h"
#include "mi_controller.h"
#include "r4300.h"
#include "r4300_core.h"
#include "cp0.h"
#include "interupt.h"
#include <string.h>
static int update_mi_init_mode(uint32_t* mi_init_mode, uint32_t w)
{
int clear_dp = 0;
/* set init_length */
*mi_init_mode &= ~0x7f;
*mi_init_mode |= w & 0x7f;
/* clear / set init_mode */
if (w & 0x80) *mi_init_mode &= ~0x80;
if (w & 0x100) *mi_init_mode |= 0x80;
/* clear / set ebus test_mode */
if (w & 0x200) *mi_init_mode &= ~0x100;
if (w & 0x400) *mi_init_mode |= 0x100;
/* clear DP interrupt */
if (w & 0x800) clear_dp = 1;
/* clear / set RDRAM reg_mode */
if (w & 0x1000) *mi_init_mode &= ~0x200;
if (w & 0x2000) *mi_init_mode |= 0x200;
return clear_dp;
}
static void update_mi_intr_mask(uint32_t* mi_intr_mask, uint32_t w)
{
if (w & 0x1) *mi_intr_mask &= ~0x1; // clear SP mask
if (w & 0x2) *mi_intr_mask |= 0x1; // set SP mask
if (w & 0x4) *mi_intr_mask &= ~0x2; // clear SI mask
if (w & 0x8) *mi_intr_mask |= 0x2; // set SI mask
if (w & 0x10) *mi_intr_mask &= ~0x4; // clear AI mask
if (w & 0x20) *mi_intr_mask |= 0x4; // set AI mask
if (w & 0x40) *mi_intr_mask &= ~0x8; // clear VI mask
if (w & 0x80) *mi_intr_mask |= 0x8; // set VI mask
if (w & 0x100) *mi_intr_mask &= ~0x10; // clear PI mask
if (w & 0x200) *mi_intr_mask |= 0x10; // set PI mask
if (w & 0x400) *mi_intr_mask &= ~0x20; // clear DP mask
if (w & 0x800) *mi_intr_mask |= 0x20; // set DP mask
}
void init_mi(struct mi_controller* mi)
{
memset(mi->regs, 0, MI_REGS_COUNT*sizeof(uint32_t));
mi->regs[MI_VERSION_REG] = 0x02020102;
mi->AudioIntrReg = 0;
}
int read_mi_regs(void* opaque, uint32_t address, uint32_t* value)
{
struct r4300_core* r4300 = (struct r4300_core*)opaque;
uint32_t reg = mi_reg(address);
*value = r4300->mi.regs[reg];
return 0;
}
int write_mi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask)
{
struct r4300_core* r4300 = (struct r4300_core*)opaque;
uint32_t reg = mi_reg(address);
switch(reg)
{
case MI_INIT_MODE_REG:
if (update_mi_init_mode(&r4300->mi.regs[MI_INIT_MODE_REG], value & mask) != 0)
{
clear_rcp_interrupt(r4300, MI_INTR_DP);
}
break;
case MI_INTR_MASK_REG:
update_mi_intr_mask(&r4300->mi.regs[MI_INTR_MASK_REG], value & mask);
check_interupt(r4300->state);
update_count(r4300->state);
if (r4300->state->next_interupt <= r4300->state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(r4300->state);
break;
}
return 0;
}
/* interrupt execution is immediate (if not masked) */
void raise_rcp_interrupt(struct r4300_core* r4300, uint32_t mi_intr)
{
r4300->mi.regs[MI_INTR_REG] |= mi_intr;
if (r4300->mi.regs[MI_INTR_REG] & r4300->mi.regs[MI_INTR_MASK_REG])
raise_maskable_interrupt(r4300->state, 0x400);
}
/* interrupt execution is scheduled (if not masked) */
void signal_rcp_interrupt(struct r4300_core* r4300, uint32_t mi_intr)
{
r4300->mi.regs[MI_INTR_REG] |= mi_intr;
check_interupt(r4300->state);
}
void clear_rcp_interrupt(struct r4300_core* r4300, uint32_t mi_intr)
{
r4300->mi.regs[MI_INTR_REG] &= ~mi_intr;
check_interupt(r4300->state);
}

View file

@ -0,0 +1,71 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - mi_controller.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_R4300_MI_CONTROLLER_H
#define M64P_R4300_MI_CONTROLLER_H
#include <stdint.h>
struct r4300_core;
enum mi_registers
{
MI_INIT_MODE_REG,
MI_VERSION_REG,
MI_INTR_REG,
MI_INTR_MASK_REG,
MI_REGS_COUNT
};
enum mi_intr
{
MI_INTR_SP = 0x01,
MI_INTR_SI = 0x02,
MI_INTR_AI = 0x04,
MI_INTR_VI = 0x08,
MI_INTR_PI = 0x10,
MI_INTR_DP = 0x20
};
struct mi_controller
{
uint32_t regs[MI_REGS_COUNT];
uint32_t AudioIntrReg;
};
#include "osal/preproc.h"
static osal_inline uint32_t mi_reg(uint32_t address)
{
return (address & 0xffff) >> 2;
}
void init_mi(struct mi_controller* mi);
int read_mi_regs(void* opaque, uint32_t address, uint32_t* value);
int write_mi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask);
void raise_rcp_interrupt(struct r4300_core* r4300, uint32_t mi_intr);
void signal_rcp_interrupt(struct r4300_core* r4300, uint32_t mi_intr);
void clear_rcp_interrupt(struct r4300_core* r4300, uint32_t mi_intr);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,48 @@
#ifndef M64P_R4300_ASSEM_ARM_H
#define M64P_R4300_ASSEM_ARM_H
#define HOST_REGS 13
#define HOST_CCREG 10
#define HOST_BTREG 8
#define EXCLUDE_REG 11
#define HOST_IMM8 1
#define HAVE_CMOV_IMM 1
#define CORTEX_A8_BRANCH_PREDICTION_HACK 1
#define USE_MINI_HT 1
//#define REG_PREFETCH 1
#define HAVE_CONDITIONAL_CALL 1
#define RAM_OFFSET 1
/* ARM calling convention:
r0-r3, r12: caller-save
r4-r11: callee-save */
#define ARG1_REG 0
#define ARG2_REG 1
#define ARG3_REG 2
#define ARG4_REG 3
/* GCC register naming convention:
r10 = sl (base)
r11 = fp (frame pointer)
r12 = ip (scratch)
r13 = sp (stack pointer)
r14 = lr (link register)
r15 = pc (program counter) */
#define FP 11
#define LR 14
#define HOST_TEMPREG 14
// Note: FP is set to &dynarec_local when executing generated code.
// Thus the local variables are actually global and not on the stack.
extern char *invc_ptr;
extern char extra_memory[33554432];
#define BASE_ADDR ((int)(&extra_memory))
//#define TARGET_SIZE_2 24 // 2^24 = 16 megabytes
#define TARGET_SIZE_2 25 // 2^25 = 32 megabytes
#endif /* M64P_R4300_ASSEM_ARM_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,32 @@
#ifndef M64P_R4300_ASSEM_X86_H
#define M64P_R4300_ASSEM_X86_H
#define HOST_REGS 8
#define HOST_CCREG 6
#define HOST_BTREG 5
#define EXCLUDE_REG 4
//#define IMM_PREFETCH 1
#define HOST_IMM_ADDR32 1
#define INVERTED_CARRY 1
#define DESTRUCTIVE_WRITEBACK 1
#define DESTRUCTIVE_SHIFT 1
#define USE_MINI_HT 1
#ifdef __cplusplus
extern "C" {
#endif
extern void *base_addr; // Code generator target address
#ifdef __cplusplus
}
#endif
#define TARGET_SIZE_2 25 // 2^25 = 32 megabytes
#define JUMP_TABLE_SIZE 0 // Not needed for 32-bit x86
/* x86 calling convention:
caller-save: %eax %ecx %edx
callee-save: %ebp %ebx %esi %edi */
#endif /* M64P_R4300_ASSEM_X86_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,929 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - linkage_x86.s *
* Copyright (C) 2009-2011 Ari64 *
* *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
.file "linkage_x86.s"
.bss
.align 4
.section .rodata
.text
.globl dyna_linker
.hidden dyna_linker
.type dyna_linker, @function
dyna_linker:
/* eax = virtual target address */
/* ebx = instruction to patch */
mov %eax, %edi
mov %eax, %ecx
shr $12, %edi
cmp $0xC0000000, %eax
cmovge tlb_LUT_r(,%edi,4), %ecx
test %ecx, %ecx
cmovz %eax, %ecx
xor $0x80000000, %ecx
mov $2047, %edx
shr $12, %ecx
and %ecx, %edx
or $2048, %edx
cmp %edx, %ecx
cmova %edx, %ecx
/* jump_in lookup */
mov jump_in(,%ecx,4), %edx
.A1:
test %edx, %edx
je .A3
mov (%edx), %edi
xor %eax, %edi
or 4(%edx), %edi
je .A2
movl 12(%edx), %edx
jmp .A1
.A2:
mov (%ebx), %edi
mov %esi, %ebp
lea 4(%ebx,%edi,1), %esi
mov %eax, %edi
pusha
call add_link
popa
mov 8(%edx), %edi
mov %ebp, %esi
lea -4(%edi), %edx
subl %ebx, %edx
movl %edx, (%ebx)
jmp *%edi
.A3:
/* hash_table lookup */
mov %eax, %edi
mov %eax, %edx
shr $16, %edi
shr $12, %edx
xor %eax, %edi
and $2047, %edx
movzwl %di, %edi
shl $4, %edi
cmp $2048, %ecx
cmovc %edx, %ecx
cmp hash_table(%edi), %eax
jne .A5
.A4:
mov hash_table+4(%edi), %edx
jmp *%edx
.A5:
cmp hash_table+8(%edi), %eax
lea 8(%edi), %edi
je .A4
/* jump_dirty lookup */
mov jump_dirty(,%ecx,4), %edx
.A6:
testl %edx, %edx
je .A8
mov (%edx), %ecx
xor %eax, %ecx
or 4(%edx), %ecx
je .A7
movl 12(%edx), %edx
jmp .A6
.A7:
mov 8(%edx), %edx
/* hash_table insert */
mov hash_table-8(%edi), %ebx
mov hash_table-4(%edi), %ecx
mov %eax, hash_table-8(%edi)
mov %edx, hash_table-4(%edi)
mov %ebx, hash_table(%edi)
mov %ecx, hash_table+4(%edi)
jmp *%edx
.A8:
mov %eax, %edi
pusha
call new_recompile_block
test %eax, %eax
popa
je dyna_linker
/* pagefault */
mov %eax, %ebx
mov $0x08, %ecx
.size dyna_linker, .-dyna_linker
.type exec_pagefault, @function
exec_pagefault:
/* eax = instruction pointer */
/* ebx = fault address */
/* ecx = cause */
mov g_cp0_regs+48, %edx
add $-12, %esp
mov g_cp0_regs+16, %edi
or $2, %edx
mov %ebx, g_cp0_regs+32 /* BadVAddr */
and $0xFF80000F, %edi
mov %edx, g_cp0_regs+48 /* Status */
mov %ecx, g_cp0_regs+52 /* Cause */
mov %eax, g_cp0_regs+56 /* EPC */
mov %ebx, %ecx
shr $9, %ebx
and $0xFFFFE000, %ecx
and $0x007FFFF0, %ebx
mov %ecx, g_cp0_regs+40 /* EntryHI */
or %ebx, %edi
mov %edi, g_cp0_regs+16 /* Context */
push $0x80000000
call get_addr_ht
add $16, %esp
jmp *%eax
.size exec_pagefault, .-exec_pagefault
/* Special dynamic linker for the case where a page fault
may occur in a branch delay slot */
.globl dyna_linker_ds
.hidden dyna_linker_ds
.type dyna_linker_ds, @function
dyna_linker_ds:
mov %eax, %edi
mov %eax, %ecx
shr $12, %edi
cmp $0xC0000000, %eax
cmovge tlb_LUT_r(,%edi,4), %ecx
test %ecx, %ecx
cmovz %eax, %ecx
xor $0x80000000, %ecx
mov $2047, %edx
shr $12, %ecx
and %ecx, %edx
or $2048, %edx
cmp %edx, %ecx
cmova %edx, %ecx
/* jump_in lookup */
mov jump_in(,%ecx,4), %edx
.B1:
test %edx, %edx
je .B3
mov (%edx), %edi
xor %eax, %edi
or 4(%edx), %edi
je .B2
movl 12(%edx), %edx
jmp .B1
.B2:
mov (%ebx), %edi
mov %esi, %ecx
lea 4(%ebx,%edi,1), %esi
mov %eax, %edi
pusha
call add_link
popa
mov 8(%edx), %edi
mov %ecx, %esi
lea -4(%edi), %edx
subl %ebx, %edx
movl %edx, (%ebx)
jmp *%edi
.B3:
/* hash_table lookup */
mov %eax, %edi
mov %eax, %edx
shr $16, %edi
shr $12, %edx
xor %eax, %edi
and $2047, %edx
movzwl %di, %edi
shl $4, %edi
cmp $2048, %ecx
cmovc %edx, %ecx
cmp hash_table(%edi), %eax
jne .B5
.B4:
mov hash_table+4(%edi), %edx
jmp *%edx
.B5:
cmp hash_table+8(%edi), %eax
lea 8(%edi), %edi
je .B4
/* jump_dirty lookup */
mov jump_dirty(,%ecx,4), %edx
.B6:
testl %edx, %edx
je .B8
mov (%edx), %ecx
xor %eax, %ecx
or 4(%edx), %ecx
je .B7
movl 12(%edx), %edx
jmp .B6
.B7:
mov 8(%edx), %edx
/* hash_table insert */
mov hash_table-8(%edi), %ebx
mov hash_table-4(%edi), %ecx
mov %eax, hash_table-8(%edi)
mov %edx, hash_table-4(%edi)
mov %ebx, hash_table(%edi)
mov %ecx, hash_table+4(%edi)
jmp *%edx
.B8:
mov %eax, %edi
and $0xFFFFFFF8, %edi
inc %edi
pusha
call new_recompile_block
test %eax, %eax
popa
je dyna_linker_ds
/* pagefault */
and $0xFFFFFFF8, %eax
mov $0x80000008, %ecx /* High bit set indicates pagefault in delay slot */
mov %eax, %ebx
sub $4, %eax
jmp exec_pagefault
.size dyna_linker_ds, .-dyna_linker_ds
.globl jump_vaddr_eax
.hidden jump_vaddr_eax
.type jump_vaddr_eax, @function
jump_vaddr_eax:
mov %eax, %edi
jmp jump_vaddr_edi
.size jump_vaddr_eax, .-jump_vaddr_eax
.globl jump_vaddr_ecx
.hidden jump_vaddr_ecx
.type jump_vaddr_ecx, @function
jump_vaddr_ecx:
mov %ecx, %edi
jmp jump_vaddr_edi
.size jump_vaddr_ecx, .-jump_vaddr_ecx
.globl jump_vaddr_edx
.hidden jump_vaddr_edx
.type jump_vaddr_edx, @function
jump_vaddr_edx:
mov %edx, %edi
jmp jump_vaddr_edi
.size jump_vaddr_edx, .-jump_vaddr_edx
.globl jump_vaddr_ebx
.hidden jump_vaddr_ebx
.type jump_vaddr_ebx, @function
jump_vaddr_ebx:
mov %ebx, %edi
jmp jump_vaddr_edi
.size jump_vaddr_ebx, .-jump_vaddr_ebx
.globl jump_vaddr_ebp
.hidden jump_vaddr_ebp
.type jump_vaddr_ebp, @function
jump_vaddr_ebp:
mov %ebp, %edi
.size jump_vaddr_ebp, .-jump_vaddr_ebp
.globl jump_vaddr_edi
.hidden jump_vaddr_edi
.type jump_vaddr_edi, @function
jump_vaddr_edi:
mov %edi, %eax
.size jump_vaddr_edi, .-jump_vaddr_edi
.type jump_vaddr, @function
jump_vaddr:
/* Check hash table */
shr $16, %eax
xor %edi, %eax
movzwl %ax, %eax
shl $4, %eax
cmp hash_table(%eax), %edi
jne .C2
.C1:
mov hash_table+4(%eax), %edi
jmp *%edi
.C2:
cmp hash_table+8(%eax), %edi
lea 8(%eax), %eax
je .C1
/* No hit on hash table, call compiler */
add $-12, %esp
push %edi
mov %esi, cycle_count /* CCREG */
call get_addr
mov cycle_count, %esi
add $16, %esp
jmp *%eax
.size jump_vaddr, .-jump_vaddr
.globl verify_code_ds
.hidden verify_code_ds
.type verify_code_ds, @function
verify_code_ds:
mov %ebp, branch_target
.size verify_code_ds, .-verify_code_ds
.globl verify_code_vm
.hidden verify_code_vm
.type verify_code_vm, @function
verify_code_vm:
/* eax = source (virtual address) */
/* ebx = target */
/* ecx = length */
cmp $0xC0000000, %eax
jl verify_code
mov %eax, %edx
lea -1(%eax,%ecx,1), %ebp
shr $12, %edx
shr $12, %ebp
mov memory_map(,%edx,4), %edi
test %edi, %edi
js .D5
lea (%eax,%edi,4), %eax
.D1:
xor memory_map(,%edx,4), %edi
shl $2, %edi
jne .D5
mov memory_map(,%edx,4), %edi
inc %edx
cmp %ebp, %edx
jbe .D1
.size verify_code_vm, .-verify_code_vm
.globl verify_code
.hidden verify_code
.type verify_code, @function
verify_code:
/* eax = source */
/* ebx = target */
/* ecx = length */
mov -4(%eax,%ecx,1), %edi
xor -4(%ebx,%ecx,1), %edi
jne .D5
mov %ecx, %edx
add $-4, %ecx
je .D3
test $4, %edx
cmove %edx, %ecx
mov %esi, cycle_count
.D2:
mov -4(%eax,%ecx,1), %edx
mov -4(%ebx,%ecx,1), %ebp
mov -8(%eax,%ecx,1), %esi
xor %edx, %ebp
mov -8(%ebx,%ecx,1), %edi
jne .D4
xor %esi, %edi
jne .D4
add $-8, %ecx
jne .D2
mov cycle_count, %esi
mov branch_target, %ebp
.D3:
ret
.D4:
mov cycle_count, %esi
.D5:
mov branch_target, %ebp
push %esi /* for stack alignment, unused */
push 8(%esp)
call get_addr
add $16, %esp /* pop stack */
jmp *%eax
.size verify_code, .-verify_code
.globl cc_interrupt
.hidden cc_interrupt
.type cc_interrupt, @function
cc_interrupt:
add last_count, %esi
add $-28, %esp /* Align stack */
mov %esi, g_cp0_regs+36 /* Count */
shr $19, %esi
movl $0, pending_exception
and $0x7f, %esi
cmpl $0, restore_candidate(,%esi,4)
jne .E4
.E1:
call gen_interupt
mov g_cp0_regs+36, %esi
mov next_interupt, %eax
mov pending_exception, %ebx
mov stop, %ecx
add $28, %esp
mov %eax, last_count
sub %eax, %esi
test %ecx, %ecx
jne .E3
test %ebx, %ebx
jne .E2
ret
.E2:
add $-8, %esp
mov pcaddr, %edi
mov %esi, cycle_count /* CCREG */
push %edi
call get_addr_ht
mov cycle_count, %esi
add $16, %esp
jmp *%eax
.E3:
add $16, %esp /* pop stack */
pop %edi /* restore edi */
pop %esi /* restore esi */
pop %ebx /* restore ebx */
pop %ebp /* restore ebp */
ret /* exit dynarec */
.E4:
/* Move 'dirty' blocks to the 'clean' list */
mov restore_candidate(,%esi,4), %ebx
mov %esi, %ebp
movl $0, restore_candidate(,%esi,4)
shl $5, %ebp
.E5:
shr $1, %ebx
jnc .E6
mov %ebp, (%esp)
call clean_blocks
.E6:
inc %ebp
test $31, %ebp
jne .E5
jmp .E1
.size cc_interrupt, .-cc_interrupt
.globl do_interrupt
.hidden do_interrupt
.type do_interrupt, @function
do_interrupt:
mov pcaddr, %edi
add $-12, %esp
push %edi
call get_addr_ht
add $16, %esp
mov g_cp0_regs+36, %esi
mov next_interupt, %ebx
mov %ebx, last_count
sub %ebx, %esi
add $2, %esi
jmp *%eax
.size do_interrupt, .-do_interrupt
.globl fp_exception
.hidden fp_exception
.type fp_exception, @function
fp_exception:
mov $0x1000002c, %edx
.E7:
mov g_cp0_regs+48, %ebx
add $-12, %esp
or $2, %ebx
mov %ebx, g_cp0_regs+48 /* Status */
mov %edx, g_cp0_regs+52 /* Cause */
mov %eax, g_cp0_regs+56 /* EPC */
push $0x80000180
call get_addr_ht
add $16, %esp
jmp *%eax
.size fp_exception, .-fp_exception
.globl fp_exception_ds
.hidden fp_exception_ds
.type fp_exception_ds, @function
fp_exception_ds:
mov $0x9000002c, %edx /* Set high bit if delay slot */
jmp .E7
.size fp_exception_ds, .-fp_exception_ds
.globl jump_syscall
.hidden jump_syscall
.type jump_syscall, @function
jump_syscall:
mov $0x20, %edx
mov g_cp0_regs+48, %ebx
add $-12, %esp
or $2, %ebx
mov %ebx, g_cp0_regs+48 /* Status */
mov %edx, g_cp0_regs+52 /* Cause */
mov %eax, g_cp0_regs+56 /* EPC */
push $0x80000180
call get_addr_ht
add $16, %esp
jmp *%eax
.size jump_syscall, .-jump_syscall
.globl jump_eret
.hidden jump_eret
.type jump_eret, @function
jump_eret:
mov g_cp0_regs+48, %ebx /* Status */
add last_count, %esi
and $0xFFFFFFFD, %ebx
mov %esi, g_cp0_regs+36 /* Count */
mov %ebx, g_cp0_regs+48 /* Status */
call check_interupt
mov next_interupt, %eax
mov g_cp0_regs+36, %esi
mov %eax, last_count
sub %eax, %esi
mov g_cp0_regs+56, %eax /* EPC */
jns .E11
.E8:
mov $248, %ebx
xor %edi, %edi
.E9:
mov reg(%ebx), %ecx
mov reg+4(%ebx), %edx
sar $31, %ecx
xor %ecx, %edx
neg %edx
adc %edi, %edi
sub $8, %ebx
jne .E9
mov hi(%ebx), %ecx
mov hi+4(%ebx), %edx
sar $31, %ecx
xor %ecx, %edx
jne .E10
mov lo(%ebx), %ecx
mov lo+4(%ebx), %edx
sar $31, %ecx
xor %ecx, %edx
.E10:
neg %edx
adc %edi, %edi
add $-8, %esp
push %edi
push %eax
mov %esi, cycle_count
call get_addr_32
mov cycle_count, %esi
add $16, %esp
jmp *%eax
.E11:
mov %eax, pcaddr
call cc_interrupt
mov pcaddr, %eax
jmp .E8
.size jump_eret, .-jump_eret
.globl new_dyna_start
.hidden new_dyna_start
.type new_dyna_start, @function
new_dyna_start:
push %ebp
push %ebx
push %esi
push %edi
add $-8, %esp /* align stack */
push $0xa4000040
call new_recompile_block
movl next_interupt, %edi
movl g_cp0_regs+36, %esi
movl %edi, last_count
subl %edi, %esi
jmp *base_addr
.size new_dyna_start, .-new_dyna_start
/* Note: Assumes %ebx, %ebp, %esi, %edi are callee-saved */
.globl invalidate_block_eax
.hidden invalidate_block_eax
.type invalidate_block_eax, @function
invalidate_block_eax:
push %eax
push %ecx
push %edx
push %eax
jmp invalidate_block_call
.size invalidate_block_eax, .-invalidate_block_eax
.globl invalidate_block_ecx
.hidden invalidate_block_ecx
.type invalidate_block_ecx, @function
invalidate_block_ecx:
push %eax
push %ecx
push %edx
push %ecx
jmp invalidate_block_call
.size invalidate_block_ecx, .-invalidate_block_ecx
.globl invalidate_block_edx
.hidden invalidate_block_edx
.type invalidate_block_edx, @function
invalidate_block_edx:
push %eax
push %ecx
push %edx
push %edx
jmp invalidate_block_call
.size invalidate_block_edx, .-invalidate_block_edx
.globl invalidate_block_ebx
.hidden invalidate_block_ebx
.type invalidate_block_ebx, @function
invalidate_block_ebx:
push %eax
push %ecx
push %edx
push %ebx
jmp invalidate_block_call
.size invalidate_block_ebx, .-invalidate_block_ebx
.globl invalidate_block_ebp
.hidden invalidate_block_ebp
.type invalidate_block_ebp, @function
invalidate_block_ebp:
push %eax
push %ecx
push %edx
push %ebp
jmp invalidate_block_call
.size invalidate_block_ebp, .-invalidate_block_ebp
.globl invalidate_block_esi
.hidden invalidate_block_esi
.type invalidate_block_esi, @function
invalidate_block_esi:
push %eax
push %ecx
push %edx
push %esi
jmp invalidate_block_call
.size invalidate_block_esi, .-invalidate_block_esi
.globl invalidate_block_edi
.hidden invalidate_block_edi
.type invalidate_block_edi, @function
invalidate_block_edi:
push %eax
push %ecx
push %edx
push %edi
.size invalidate_block_edi, .-invalidate_block_edi
.type invalidate_block_call, @function
invalidate_block_call:
call invalidate_block
pop %eax /* Throw away */
pop %edx
pop %ecx
pop %eax
ret
.size invalidate_block_call, .-invalidate_block_call
.globl write_rdram_new
.hidden write_rdram_new
.type write_rdram_new, @function
write_rdram_new:
mov address, %edi
mov cpu_word, %ecx
mov %ecx, g_rdram-0x80000000(%edi)
jmp .E12
.size write_rdram_new, .-write_rdram_new
.globl write_rdramb_new
.hidden write_rdramb_new
.type write_rdramb_new, @function
write_rdramb_new:
mov address, %edi
xor $3, %edi
movb cpu_byte, %cl
movb %cl, g_rdram-0x80000000(%edi)
jmp .E12
.size write_rdramb_new, .-write_rdramb_new
.globl write_rdramh_new
.hidden write_rdramh_new
.type write_rdramh_new, @function
write_rdramh_new:
mov address, %edi
xor $2, %edi
movw cpu_hword, %cx
movw %cx, g_rdram-0x80000000(%edi)
jmp .E12
.size write_rdramh_new, .-write_rdramh_new
.globl write_rdramd_new
.hidden write_rdramd_new
.type write_rdramd_new, @function
write_rdramd_new:
mov address, %edi
mov cpu_dword+4, %ecx
mov cpu_dword, %edx
mov %ecx, g_rdram-0x80000000(%edi)
mov %edx, g_rdram-0x80000000+4(%edi)
jmp .E12
.size write_rdramd_new, .-write_rdramd_new
.type do_invalidate, @function
do_invalidate:
mov address, %edi
mov %edi, %ebx /* Return ebx to caller */
.E12:
shr $12, %edi
cmpb $1, invalid_code(%edi)
je .E13
push %edi
call invalidate_block
pop %edi
.E13:
ret
.size do_invalidate, .-do_invalidate
.globl read_nomem_new
.hidden read_nomem_new
.type read_nomem_new, @function
read_nomem_new:
mov address, %edi
mov %edi, %ebx
shr $12, %edi
mov memory_map(,%edi,4),%edi
mov $0x8, %eax
test %edi, %edi
js tlb_exception
mov (%ebx,%edi,4), %ecx
mov %ecx, readmem_dword
ret
.size read_nomem_new, .-read_nomem_new
.globl read_nomemb_new
.hidden read_nomemb_new
.type read_nomemb_new, @function
read_nomemb_new:
mov address, %edi
mov %edi, %ebx
shr $12, %edi
mov memory_map(,%edi,4),%edi
mov $0x8, %eax
test %edi, %edi
js tlb_exception
xor $3, %ebx
movzbl (%ebx,%edi,4), %ecx
mov %ecx, readmem_dword
ret
.size read_nomemb_new, .-read_nomemb_new
.globl read_nomemh_new
.hidden read_nomemh_new
.type read_nomemh_new, @function
read_nomemh_new:
mov address, %edi
mov %edi, %ebx
shr $12, %edi
mov memory_map(,%edi,4),%edi
mov $0x8, %eax
test %edi, %edi
js tlb_exception
xor $2, %ebx
movzwl (%ebx,%edi,4), %ecx
mov %ecx, readmem_dword
ret
.size read_nomemh_new, .-read_nomemh_new
.globl read_nomemd_new
.hidden read_nomemd_new
.type read_nomemd_new, @function
read_nomemd_new:
mov address, %edi
mov %edi, %ebx
shr $12, %edi
mov memory_map(,%edi,4),%edi
mov $0x8, %eax
test %edi, %edi
js tlb_exception
mov 4(%ebx,%edi,4), %ecx
mov (%ebx,%edi,4), %edx
mov %ecx, readmem_dword
mov %edx, readmem_dword+4
ret
.size read_nomemd_new, .-read_nomemd_new
.globl write_nomem_new
.hidden write_nomem_new
.type write_nomem_new, @function
write_nomem_new:
call do_invalidate
mov memory_map(,%edi,4),%edi
mov cpu_word, %ecx
mov $0xc, %eax
shl $2, %edi
jc tlb_exception
mov %ecx, (%ebx,%edi)
ret
.size write_nomem_new, .-write_nomem_new
.globl write_nomemb_new
.hidden write_nomemb_new
.type write_nomemb_new, @function
write_nomemb_new:
call do_invalidate
mov memory_map(,%edi,4),%edi
movb cpu_byte, %cl
mov $0xc, %eax
shl $2, %edi
jc tlb_exception
xor $3, %ebx
movb %cl, (%ebx,%edi)
ret
.size write_nomemb_new, .-write_nomemb_new
.globl write_nomemh_new
.hidden write_nomemh_new
.type write_nomemh_new, @function
write_nomemh_new:
call do_invalidate
mov memory_map(,%edi,4),%edi
movw cpu_hword, %cx
mov $0xc, %eax
shl $2, %edi
jc tlb_exception
xor $2, %ebx
movw %cx, (%ebx,%edi)
ret
.size write_nomemh_new, .-write_nomemh_new
.globl write_nomemd_new
.hidden write_nomemd_new
.type write_nomemd_new, @function
write_nomemd_new:
call do_invalidate
mov memory_map(,%edi,4),%edi
mov cpu_dword+4, %edx
mov cpu_dword, %ecx
mov $0xc, %eax
shl $2, %edi
jc tlb_exception
mov %edx, (%ebx,%edi)
mov %ecx, 4(%ebx,%edi)
ret
.size write_nomemd_new, .-write_nomemd_new
.type tlb_exception, @function
tlb_exception:
/* eax = cause */
/* ebx = address */
/* ebp = instr addr + flags */
mov 0x24(%esp), %ebp
/* Debug:
push %ebp
push %ebx
push %eax
call tlb_debug
pop %eax
pop %ebx
pop %ebp
/* end debug */
mov g_cp0_regs+48, %esi
mov %ebp, %ecx
mov %ebp, %edx
mov %ebp, %edi
shl $31, %ebp
shr $12, %ecx
or %ebp, %eax
sar $29, %ebp
and $0xFFFFFFFC, %edx
mov memory_map(,%ecx,4), %ecx
or $2, %esi
mov (%edx, %ecx, 4), %ecx
add %ebp, %edx
mov %esi, g_cp0_regs+48 /* Status */
mov %eax, g_cp0_regs+52 /* Cause */
mov %edx, g_cp0_regs+56 /* EPC */
add $0x24, %esp
mov $0x6000022, %edx
mov %ecx, %ebp
movswl %cx, %eax
shr $26, %ecx
shr $21, %ebp
sub %eax, %ebx
and $0x1f, %ebp
ror %cl, %edx
mov g_cp0_regs+16, %esi
cmovc reg(,%ebp,8), %ebx
and $0xFF80000F, %esi
mov %ebx, reg(,%ebp,8)
add %ebx, %eax
sar $31, %ebx
mov %eax, g_cp0_regs+32 /* BadVAddr */
shr $9, %eax
test $2, %edi
cmove reg+4(,%ebp,8), %ebx
add $-12, %esp
and $0x007FFFF0, %eax
mov %ebx, reg+4(,%ebp,8)
push $0x80000180
or %eax, %esi
mov %esi, g_cp0_regs+16 /* Context */
call get_addr_ht
add $16, %esp
movl next_interupt, %edi
movl g_cp0_regs+36, %esi /* Count */
movl %edi, last_count
subl %edi, %esi
jmp *%eax
.size tlb_exception, .-tlb_exception
.globl breakpoint
.hidden breakpoint
.type breakpoint, @function
breakpoint:
.size breakpoint, .-breakpoint

View file

@ -0,0 +1,873 @@
;Mupen64plus - linkage_x86.asm
;Copyright (C) 2009-2011 Ari64
;
;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.
%ifdef ELF_TYPE
%macro cglobal 1
global %1
%endmacro
%macro cextern 1
extern %1
%endmacro
%else
%macro cglobal 1
global _%1
%define %1 _%1
%endmacro
%macro cextern 1
extern _%1
%define %1 _%1
%endmacro
%endif
cglobal dyna_linker
cglobal dyna_linker_ds
cglobal jump_vaddr_eax
cglobal jump_vaddr_ecx
cglobal jump_vaddr_edx
cglobal jump_vaddr_ebx
cglobal jump_vaddr_ebp
cglobal jump_vaddr_edi
cglobal verify_code_ds
cglobal verify_code_vm
cglobal verify_code
cglobal cc_interrupt
cglobal do_interrupt
cglobal fp_exception
cglobal fp_exception_ds
cglobal jump_syscall
cglobal jump_eret
cglobal new_dyna_start
cglobal invalidate_block_eax
cglobal invalidate_block_ecx
cglobal invalidate_block_edx
cglobal invalidate_block_ebx
cglobal invalidate_block_ebp
cglobal invalidate_block_esi
cglobal invalidate_block_edi
cglobal write_rdram_new
cglobal write_rdramb_new
cglobal write_rdramh_new
cglobal write_rdramd_new
cglobal read_nomem_new
cglobal read_nomemb_new
cglobal read_nomemh_new
cglobal read_nomemd_new
cglobal write_nomem_new
cglobal write_nomemb_new
cglobal write_nomemh_new
cglobal write_nomemd_new
cglobal breakpoint
cextern base_addr
cextern tlb_LUT_r
cextern jump_in
cextern add_link
cextern hash_table
cextern jump_dirty
cextern new_recompile_block
cextern g_cp0_regs
cextern get_addr_ht
cextern cycle_count
cextern get_addr
cextern branch_target
cextern memory_map
cextern pending_exception
cextern restore_candidate
cextern gen_interupt
cextern next_interupt
cextern stop
cextern last_count
cextern pcaddr
cextern clean_blocks
cextern reg
cextern hi
cextern lo
cextern invalidate_block
cextern address
cextern g_rdram
cextern cpu_byte
cextern cpu_hword
cextern cpu_word
cextern cpu_dword
cextern invalid_code
cextern readmem_dword
cextern check_interupt
cextern get_addr_32
section .bss
align 4
section .rodata
section .text
dyna_linker:
;eax = virtual target address
;ebx = instruction to patch
mov edi, eax
mov ecx, eax
shr edi, 12
cmp eax, 0C0000000h
cmovge ecx, [tlb_LUT_r+edi*4]
test ecx, ecx
cmovz ecx, eax
xor ecx, 080000000h
mov edx, 2047
shr ecx, 12
and edx, ecx
or edx, 2048
cmp ecx, edx
cmova ecx, edx
;jump_in lookup
mov edx, [jump_in+ecx*4]
_A1:
test edx, edx
je _A3
mov edi, [edx]
xor edi, eax
or edi, [4+edx]
je _A2
mov edx, DWORD [12+edx]
jmp _A1
_A2:
mov edi, [ebx]
mov ebp, esi
lea esi, [4+ebx+edi*1]
mov edi, eax
pusha
call add_link
popa
mov edi, [8+edx]
mov esi, ebp
lea edx, [-4+edi]
sub edx, ebx
mov DWORD [ebx], edx
jmp edi
_A3:
;hash_table lookup
mov edi, eax
mov edx, eax
shr edi, 16
shr edx, 12
xor edi, eax
and edx, 2047
movzx edi, di
shl edi, 4
cmp ecx, 2048
cmovc ecx, edx
cmp eax, [hash_table+edi]
jne _A5
_A4:
mov edx, [hash_table+4+edi]
jmp edx
_A5:
cmp eax, [hash_table+8+edi]
lea edi, [8+edi]
je _A4
;jump_dirty lookup
mov edx, [jump_dirty+ecx*4]
_A6:
test edx, edx
je _A8
mov ecx, [edx]
xor ecx, eax
or ecx, [4+edx]
je _A7
mov edx, DWORD [12+edx]
jmp _A6
_A7:
mov edx, [8+edx]
;hash_table insert
mov ebx, [hash_table-8+edi]
mov ecx, [hash_table-4+edi]
mov [hash_table-8+edi], eax
mov [hash_table-4+edi], edx
mov [hash_table+edi], ebx
mov [hash_table+4+edi], ecx
jmp edx
_A8:
mov edi, eax
pusha
call new_recompile_block
test eax, eax
popa
je dyna_linker
;pagefault
mov ebx, eax
mov ecx, 008h
exec_pagefault:
;eax = instruction pointer
;ebx = fault address
;ecx = cause
mov edx, [g_cp0_regs+48]
add esp, -12
mov edi, [g_cp0_regs+16]
or edx, 2
mov [g_cp0_regs+32], ebx ;BadVAddr
and edi, 0FF80000Fh
mov [g_cp0_regs+48], edx ;Status
mov [g_cp0_regs+52], ecx ;Cause
mov [g_cp0_regs+56], eax ;EPC
mov ecx, ebx
shr ebx, 9
and ecx, 0FFFFE000h
and ebx, 0007FFFF0h
mov [g_cp0_regs+40], ecx ;EntryHI
or edi, ebx
mov [g_cp0_regs+16], edi ;Context
push 080000000h
call get_addr_ht
add esp, 16
jmp eax
;Special dynamic linker for the case where a page fault
;may occur in a branch delay slot
dyna_linker_ds:
mov edi, eax
mov ecx, eax
shr edi, 12
cmp eax, 0C0000000h
cmovge ecx, [tlb_LUT_r+edi*4]
test ecx, ecx
cmovz ecx, eax
xor ecx, 080000000h
mov edx, 2047
shr ecx, 12
and edx, ecx
or edx, 2048
cmp ecx, edx
cmova ecx, edx
;jump_in lookup
mov edx, [jump_in+ecx*4]
_B1:
test edx, edx
je _B3
mov edi, [edx]
xor edi, eax
or edi, [4+edx]
je _B2
mov edx, DWORD [12+edx]
jmp _B1
_B2:
mov edi, [ebx]
mov ecx, esi
lea esi, [4+ebx+edi*1]
mov edi, eax
pusha
call add_link
popa
mov edi, [8+edx]
mov esi, ecx
lea edx, [-4+edi]
sub edx, ebx
mov DWORD [ebx], edx
jmp edi
_B3:
;hash_table lookup
mov edi, eax
mov edx, eax
shr edi, 16
shr edx, 12
xor edi, eax
and edx, 2047
movzx edi, di
shl edi, 4
cmp ecx, 2048
cmovc ecx, edx
cmp eax, [hash_table+edi]
jne _B5
_B4:
mov edx, [hash_table+4+edi]
jmp edx
_B5:
cmp eax, [hash_table+8+edi]
lea edi, [8+edi]
je _B4
;jump_dirty lookup
mov edx, [jump_dirty+ecx*4]
_B6:
test edx, edx
je _B8
mov ecx, [edx]
xor ecx, eax
or ecx, [4+edx]
je _B7
mov edx, DWORD [12+edx]
jmp _B6
_B7:
mov edx, [8+edx]
;hash_table insert
mov ebx, [hash_table-8+edi]
mov ecx, [hash_table-4+edi]
mov [hash_table-8+edi], eax
mov [hash_table-4+edi], edx
mov [hash_table+edi], ebx
mov [hash_table+4+edi], ecx
jmp edx
_B8:
mov edi, eax
and edi, 0FFFFFFF8h
inc edi
pusha
call new_recompile_block
test eax, eax
popa
je dyna_linker_ds
;pagefault
and eax, 0FFFFFFF8h
mov ecx, 080000008h ;High bit set indicates pagefault in delay slot
mov ebx, eax
sub eax, 4
jmp exec_pagefault
jump_vaddr_eax:
mov edi, eax
jmp jump_vaddr_edi
jump_vaddr_ecx:
mov edi, ecx
jmp jump_vaddr_edi
jump_vaddr_edx:
mov edi, edx
jmp jump_vaddr_edi
jump_vaddr_ebx:
mov edi, ebx
jmp jump_vaddr_edi
jump_vaddr_ebp:
mov edi, ebp
jump_vaddr_edi:
mov eax, edi
jump_vaddr:
;Check hash table
shr eax, 16
xor eax, edi
movzx eax, ax
shl eax, 4
cmp edi, [hash_table+eax]
jne _C2
_C1:
mov edi, [hash_table+4+eax]
jmp edi
_C2:
cmp edi, [hash_table+8+eax]
lea eax, [8+eax]
je _C1
;No hit on hash table, call compiler
add esp, -12
push edi
mov [cycle_count], esi ;CCREG
call get_addr
mov esi, [cycle_count]
add esp, 16
jmp eax
verify_code_ds:
mov [branch_target], ebp
verify_code_vm:
;eax = source (virtual address)
;ebx = target
;ecx = length
cmp eax, 0C0000000h
jl verify_code
mov edx, eax
lea ebp, [-1+eax+ecx*1]
shr edx, 12
shr ebp, 12
mov edi, [memory_map+edx*4]
test edi, edi
js _D5
lea eax, [eax+edi*4]
_D1:
xor edi, [memory_map+edx*4]
shl edi, 2
jne _D5
mov edi, [memory_map+edx*4]
inc edx
cmp edx, ebp
jbe _D1
verify_code:
;eax = source
;ebx = target
;ecx = length
mov edi, [-4+eax+ecx*1]
xor edi, [-4+ebx+ecx*1]
jne _D5
mov edx, ecx
add ecx, -4
je _D3
test edx, 4
cmove ecx, edx
mov [cycle_count], esi
_D2:
mov edx, [-4+eax+ecx*1]
mov ebp, [-4+ebx+ecx*1]
mov esi, [-8+eax+ecx*1]
xor ebp, edx
mov edi, [-8+ebx+ecx*1]
jne _D4
xor edi, esi
jne _D4
add ecx, -8
jne _D2
mov esi, [cycle_count]
mov ebp, [branch_target]
_D3:
ret
_D4:
mov esi, [cycle_count]
_D5:
mov ebp, [branch_target]
push esi ;for stack alignment, unused
push DWORD [8+esp]
call get_addr
add esp, 16 ;pop stack
jmp eax
cc_interrupt:
add esi, [last_count]
add esp, -28 ;Align stack
mov [g_cp0_regs+36], esi ;Count
shr esi, 19
mov DWORD [pending_exception], 0
and esi, 07fh
cmp DWORD [restore_candidate+esi*4], 0
jne _E4
_E1:
call gen_interupt
mov esi, [g_cp0_regs+36]
mov eax, [next_interupt]
mov ebx, [pending_exception]
mov ecx, [stop]
add esp, 28
mov [last_count], eax
sub esi, eax
test ecx, ecx
jne _E3
test ebx, ebx
jne _E2
ret
_E2:
add esp, -8
mov edi, [pcaddr]
mov [cycle_count], esi ;CCREG
push edi
call get_addr_ht
mov esi, [cycle_count]
add esp, 16
jmp eax
_E3:
add esp, 16 ;pop stack
pop edi ;restore edi
pop esi ;restore esi
pop ebx ;restore ebx
pop ebp ;restore ebp
ret ;exit dynarec
_E4:
;Move 'dirty' blocks to the 'clean' list
mov ebx, [restore_candidate+esi*4]
mov ebp, esi
mov DWORD [restore_candidate+esi*4], 0
shl ebp, 5
_E5:
shr ebx, 1
jnc _E6
mov [esp], ebp
call clean_blocks
_E6:
inc ebp
test ebp, 31
jne _E5
jmp _E1
do_interrupt:
mov edi, [pcaddr]
add esp, -12
push edi
call get_addr_ht
add esp, 16
mov esi, [g_cp0_regs+36]
mov ebx, [next_interupt]
mov [last_count], ebx
sub esi, ebx
add esi, 2
jmp eax
fp_exception:
mov edx, 01000002ch
_E7:
mov ebx, [g_cp0_regs+48]
add esp, -12
or ebx, 2
mov [g_cp0_regs+48], ebx ;Status
mov [g_cp0_regs+52], edx ;Cause
mov [g_cp0_regs+56], eax ;EPC
push 080000180h
call get_addr_ht
add esp, 16
jmp eax
fp_exception_ds:
mov edx, 09000002ch ;Set high bit if delay slot
jmp _E7
jump_syscall:
mov edx, 020h
mov ebx, [g_cp0_regs+48]
add esp, -12
or ebx, 2
mov [g_cp0_regs+48], ebx ;Status
mov [g_cp0_regs+52], edx ;Cause
mov [g_cp0_regs+56], eax ;EPC
push 080000180h
call get_addr_ht
add esp, 16
jmp eax
jump_eret:
mov ebx, [g_cp0_regs+48] ;Status
add esi, [last_count]
and ebx, 0FFFFFFFDh
mov [g_cp0_regs+36], esi ;Count
mov [g_cp0_regs+48], ebx ;Status
call check_interupt
mov eax, [next_interupt]
mov esi, [g_cp0_regs+36]
mov [last_count], eax
sub esi, eax
mov eax, [g_cp0_regs+56] ;EPC
jns _E11
_E8:
mov ebx, 248
xor edi, edi
_E9:
mov ecx, [reg+ebx]
mov edx, [reg+4+ebx]
sar ecx, 31
xor edx, ecx
neg edx
adc edi, edi
sub ebx, 8
jne _E9
mov ecx, [hi+ebx]
mov edx, [hi+4+ebx]
sar ecx, 31
xor edx, ecx
jne _E10
mov ecx, [lo+ebx]
mov edx, [lo+4+ebx]
sar ecx, 31
xor edx, ecx
_E10:
neg edx
adc edi, edi
add esp, -8
push edi
push eax
mov [cycle_count], esi
call get_addr_32
mov esi, [cycle_count]
add esp, 16
jmp eax
_E11:
mov [pcaddr], eax
call cc_interrupt
mov eax, [pcaddr]
jmp _E8
new_dyna_start:
push ebp
push ebx
push esi
push edi
add esp, -8 ;align stack
push 0a4000040h
call new_recompile_block
mov edi, DWORD [next_interupt]
mov esi, DWORD [g_cp0_regs+36]
mov DWORD [last_count], edi
sub esi, edi
jmp DWORD [base_addr]
invalidate_block_eax:
push eax
push ecx
push edx
push eax
jmp invalidate_block_call
invalidate_block_ecx:
push eax
push ecx
push edx
push ecx
jmp invalidate_block_call
invalidate_block_edx:
push eax
push ecx
push edx
push edx
jmp invalidate_block_call
invalidate_block_ebx:
push eax
push ecx
push edx
push ebx
jmp invalidate_block_call
invalidate_block_ebp:
push eax
push ecx
push edx
push ebp
jmp invalidate_block_call
invalidate_block_esi:
push eax
push ecx
push edx
push esi
jmp invalidate_block_call
invalidate_block_edi:
push eax
push ecx
push edx
push edi
invalidate_block_call:
call invalidate_block
pop eax ;Throw away
pop edx
pop ecx
pop eax
ret
write_rdram_new:
mov edi, [address]
mov ecx, [cpu_word]
mov [g_rdram-0x80000000+edi], ecx
jmp _E12
write_rdramb_new:
mov edi, [address]
xor edi, 3
mov cl, BYTE [cpu_byte]
mov BYTE [g_rdram-0x80000000+edi], cl
jmp _E12
write_rdramh_new:
mov edi, [address]
xor edi, 2
mov cx, WORD [cpu_hword]
mov WORD [g_rdram-0x80000000+edi], cx
jmp _E12
write_rdramd_new:
mov edi, [address]
mov ecx, [cpu_dword+4]
mov edx, [cpu_dword+0]
mov [g_rdram-0x80000000+edi], ecx
mov [g_rdram-0x80000000+4+edi], edx
jmp _E12
do_invalidate:
mov edi, [address]
mov ebx, edi ;Return ebx to caller
_E12:
shr edi, 12
cmp BYTE [invalid_code+edi], 1
je _E13
push edi
call invalidate_block
pop edi
_E13:
ret
read_nomem_new:
mov edi, [address]
mov ebx, edi
shr edi, 12
mov edi, [memory_map+edi*4]
mov eax, 08h
test edi, edi
js tlb_exception
mov ecx, [ebx+edi*4]
mov [readmem_dword], ecx
ret
read_nomemb_new:
mov edi, [address]
mov ebx, edi
shr edi, 12
mov edi, [memory_map+edi*4]
mov eax, 08h
test edi, edi
js tlb_exception
xor ebx, 3
movzx ecx, BYTE [ebx+edi*4]
mov [readmem_dword], ecx
ret
read_nomemh_new:
mov edi, [address]
mov ebx, edi
shr edi, 12
mov edi, [memory_map+edi*4]
mov eax, 08h
test edi, edi
js tlb_exception
xor ebx, 2
movzx ecx, WORD [ebx+edi*4]
mov [readmem_dword], ecx
ret
read_nomemd_new:
mov edi, [address]
mov ebx, edi
shr edi, 12
mov edi, [memory_map+edi*4]
mov eax, 08h
test edi, edi
js tlb_exception
mov ecx, [4+ebx+edi*4]
mov edx, [ebx+edi*4]
mov [readmem_dword], ecx
mov [readmem_dword+4], edx
ret
write_nomem_new:
call do_invalidate
mov edi, [memory_map+edi*4]
mov ecx, [cpu_word]
mov eax, 0ch
shl edi, 2
jc tlb_exception
mov [ebx+edi], ecx
ret
write_nomemb_new:
call do_invalidate
mov edi, [memory_map+edi*4]
mov cl, BYTE [cpu_byte]
mov eax, 0ch
shl edi, 2
jc tlb_exception
xor ebx, 3
mov BYTE [ebx+edi], cl
ret
write_nomemh_new:
call do_invalidate
mov edi, [memory_map+edi*4]
mov cx, WORD [cpu_hword]
mov eax, 0ch
shl edi, 2
jc tlb_exception
xor ebx, 2
mov WORD [ebx+edi], cx
ret
write_nomemd_new:
call do_invalidate
mov edi, [memory_map+edi*4]
mov edx, [cpu_dword+4]
mov ecx, [cpu_dword+0]
mov eax, 0ch
shl edi, 2
jc tlb_exception
mov [ebx+edi], edx
mov [4+ebx+edi], ecx
ret
tlb_exception:
;eax = cause
;ebx = address
;ebp = instr addr + flags
mov ebp, [024h+esp]
;Debug:
;push ebp
;push ebx
;push eax
;call tlb_debug
;pop eax
;pop ebx
;pop ebp
;end debug
mov esi, [g_cp0_regs+48]
mov ecx, ebp
mov edx, ebp
mov edi, ebp
shl ebp, 31
shr ecx, 12
or eax, ebp
sar ebp, 29
and edx, 0FFFFFFFCh
mov ecx, [memory_map+ecx*4]
or esi, 2
mov ecx, [edx+ecx*4]
add edx, ebp
mov [g_cp0_regs+48], esi ;Status
mov [g_cp0_regs+52], eax ;Cause
mov [g_cp0_regs+56], edx ;EPC
add esp, 024h
mov edx, 06000022h
mov ebp, ecx
movsx eax, cx
shr ecx, 26
shr ebp, 21
sub ebx, eax
and ebp, 01fh
ror edx, cl
mov esi, [g_cp0_regs+16]
cmovc ebx, [reg+ebp*8]
and esi, 0FF80000Fh
mov [reg+ebp*8], ebx
add eax, ebx
sar ebx, 31
mov [g_cp0_regs+32], eax ;BadVAddr
shr eax, 9
test edi, 2
cmove ebx, [reg+4+ebp*8]
add esp, -12
and eax, 0007FFFF0h
mov [reg+4+ebp*8], ebx
push 080000180h
or esi, eax
mov [g_cp0_regs+16], esi ;Context
call get_addr_ht
add esp, 16
mov edi, DWORD [next_interupt]
mov esi, DWORD [g_cp0_regs+36] ;Count
mov DWORD [last_count], edi
sub esi, edi
jmp eax
breakpoint:

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,44 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - new_dynarec.h *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_R4300_NEW_DYNAREC_H
#define M64P_R4300_NEW_DYNAREC_H
#define NEW_DYNAREC_X86 1
#define NEW_DYNAREC_AMD64 2
#define NEW_DYNAREC_ARM 3
#ifdef __cplusplus
extern "C" {
#endif
extern int pcaddr;
extern int pending_exception;
#ifdef __cplusplus
}
#endif
void invalidate_all_pages(void);
void invalidate_block(unsigned int block);
void new_dynarec_init(void);
void new_dyna_start(void);
void new_dynarec_cleanup(void);
#endif /* M64P_R4300_NEW_DYNAREC_H */

View file

@ -0,0 +1,327 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - ops.h *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_R4300_OPS_H
#define M64P_R4300_OPS_H
#include "osal/preproc.h"
typedef struct _cpu_instruction_table
{
/* All jump/branch instructions (except JR and JALR) have three versions:
* - JUMPNAME() which for jumps inside the current block.
* - JUMPNAME_OUT() which jumps outside the current block.
* - JUMPNAME_IDLE() which does busy wait optimization.
*
* Busy wait optimization is used when a jump jumps to itself,
* and the instruction on the delay slot is a NOP.
* The program is waiting for the next interrupt, so we can just
* increase Count until the point where the next interrupt happens. */
// Load and store instructions
void (osal_fastcall *LB)(usf_state_t *);
void (osal_fastcall *LBU)(usf_state_t *);
void (osal_fastcall *LH)(usf_state_t *);
void (osal_fastcall *LHU)(usf_state_t *);
void (osal_fastcall *LW)(usf_state_t *);
void (osal_fastcall *LWL)(usf_state_t *);
void (osal_fastcall *LWR)(usf_state_t *);
void (osal_fastcall *SB)(usf_state_t *);
void (osal_fastcall *SH)(usf_state_t *);
void (osal_fastcall *SW)(usf_state_t *);
void (osal_fastcall *SWL)(usf_state_t *);
void (osal_fastcall *SWR)(usf_state_t *);
void (osal_fastcall *LD)(usf_state_t *);
void (osal_fastcall *LDL)(usf_state_t *);
void (osal_fastcall *LDR)(usf_state_t *);
void (osal_fastcall *LL)(usf_state_t *);
void (osal_fastcall *LWU)(usf_state_t *);
void (osal_fastcall *SC)(usf_state_t *);
void (osal_fastcall *SD)(usf_state_t *);
void (osal_fastcall *SDL)(usf_state_t *);
void (osal_fastcall *SDR)(usf_state_t *);
void (osal_fastcall *SYNC)(usf_state_t *);
// Arithmetic instructions (ALU immediate)
void (osal_fastcall *ADDI)(usf_state_t *);
void (osal_fastcall *ADDIU)(usf_state_t *);
void (osal_fastcall *SLTI)(usf_state_t *);
void (osal_fastcall *SLTIU)(usf_state_t *);
void (osal_fastcall *ANDI)(usf_state_t *);
void (osal_fastcall *ORI)(usf_state_t *);
void (osal_fastcall *XORI)(usf_state_t *);
void (osal_fastcall *LUI)(usf_state_t *);
void (osal_fastcall *DADDI)(usf_state_t *);
void (osal_fastcall *DADDIU)(usf_state_t *);
// Arithmetic instructions (3-operand)
void (osal_fastcall *ADD)(usf_state_t *);
void (osal_fastcall *ADDU)(usf_state_t *);
void (osal_fastcall *SUB)(usf_state_t *);
void (osal_fastcall *SUBU)(usf_state_t *);
void (osal_fastcall *SLT)(usf_state_t *);
void (osal_fastcall *SLTU)(usf_state_t *);
void (osal_fastcall *AND)(usf_state_t *);
void (osal_fastcall *OR)(usf_state_t *);
void (osal_fastcall *XOR)(usf_state_t *);
void (osal_fastcall *NOR)(usf_state_t *);
void (osal_fastcall *DADD)(usf_state_t *);
void (osal_fastcall *DADDU)(usf_state_t *);
void (osal_fastcall *DSUB)(usf_state_t *);
void (osal_fastcall *DSUBU)(usf_state_t *);
// Multiply and divide instructions
void (osal_fastcall *MULT)(usf_state_t *);
void (osal_fastcall *MULTU)(usf_state_t *);
void (osal_fastcall *DIV)(usf_state_t *);
void (osal_fastcall *DIVU)(usf_state_t *);
void (osal_fastcall *MFHI)(usf_state_t *);
void (osal_fastcall *MTHI)(usf_state_t *);
void (osal_fastcall *MFLO)(usf_state_t *);
void (osal_fastcall *MTLO)(usf_state_t *);
void (osal_fastcall *DMULT)(usf_state_t *);
void (osal_fastcall *DMULTU)(usf_state_t *);
void (osal_fastcall *DDIV)(usf_state_t *);
void (osal_fastcall *DDIVU)(usf_state_t *);
// Jump and branch instructions
void (osal_fastcall *J)(usf_state_t *);
void (osal_fastcall *J_OUT)(usf_state_t *);
void (osal_fastcall *J_IDLE)(usf_state_t *);
void (osal_fastcall *JAL)(usf_state_t *);
void (osal_fastcall *JAL_OUT)(usf_state_t *);
void (osal_fastcall *JAL_IDLE)(usf_state_t *);
void (osal_fastcall *JR)(usf_state_t *);
void (osal_fastcall *JALR)(usf_state_t *);
void (osal_fastcall *BEQ)(usf_state_t *);
void (osal_fastcall *BEQ_OUT)(usf_state_t *);
void (osal_fastcall *BEQ_IDLE)(usf_state_t *);
void (osal_fastcall *BNE)(usf_state_t *);
void (osal_fastcall *BNE_OUT)(usf_state_t *);
void (osal_fastcall *BNE_IDLE)(usf_state_t *);
void (osal_fastcall *BLEZ)(usf_state_t *);
void (osal_fastcall *BLEZ_OUT)(usf_state_t *);
void (osal_fastcall *BLEZ_IDLE)(usf_state_t *);
void (osal_fastcall *BGTZ)(usf_state_t *);
void (osal_fastcall *BGTZ_OUT)(usf_state_t *);
void (osal_fastcall *BGTZ_IDLE)(usf_state_t *);
void (osal_fastcall *BLTZ)(usf_state_t *);
void (osal_fastcall *BLTZ_OUT)(usf_state_t *);
void (osal_fastcall *BLTZ_IDLE)(usf_state_t *);
void (osal_fastcall *BGEZ)(usf_state_t *);
void (osal_fastcall *BGEZ_OUT)(usf_state_t *);
void (osal_fastcall *BGEZ_IDLE)(usf_state_t *);
void (osal_fastcall *BLTZAL)(usf_state_t *);
void (osal_fastcall *BLTZAL_OUT)(usf_state_t *);
void (osal_fastcall *BLTZAL_IDLE)(usf_state_t *);
void (osal_fastcall *BGEZAL)(usf_state_t *);
void (osal_fastcall *BGEZAL_OUT)(usf_state_t *);
void (osal_fastcall *BGEZAL_IDLE)(usf_state_t *);
void (osal_fastcall *BEQL)(usf_state_t *);
void (osal_fastcall *BEQL_OUT)(usf_state_t *);
void (osal_fastcall *BEQL_IDLE)(usf_state_t *);
void (osal_fastcall *BNEL)(usf_state_t *);
void (osal_fastcall *BNEL_OUT)(usf_state_t *);
void (osal_fastcall *BNEL_IDLE)(usf_state_t *);
void (osal_fastcall *BLEZL)(usf_state_t *);
void (osal_fastcall *BLEZL_OUT)(usf_state_t *);
void (osal_fastcall *BLEZL_IDLE)(usf_state_t *);
void (osal_fastcall *BGTZL)(usf_state_t *);
void (osal_fastcall *BGTZL_OUT)(usf_state_t *);
void (osal_fastcall *BGTZL_IDLE)(usf_state_t *);
void (osal_fastcall *BLTZL)(usf_state_t *);
void (osal_fastcall *BLTZL_OUT)(usf_state_t *);
void (osal_fastcall *BLTZL_IDLE)(usf_state_t *);
void (osal_fastcall *BGEZL)(usf_state_t *);
void (osal_fastcall *BGEZL_OUT)(usf_state_t *);
void (osal_fastcall *BGEZL_IDLE)(usf_state_t *);
void (osal_fastcall *BLTZALL)(usf_state_t *);
void (osal_fastcall *BLTZALL_OUT)(usf_state_t *);
void (osal_fastcall *BLTZALL_IDLE)(usf_state_t *);
void (osal_fastcall *BGEZALL)(usf_state_t *);
void (osal_fastcall *BGEZALL_OUT)(usf_state_t *);
void (osal_fastcall *BGEZALL_IDLE)(usf_state_t *);
void (osal_fastcall *BC1TL)(usf_state_t *);
void (osal_fastcall *BC1TL_OUT)(usf_state_t *);
void (osal_fastcall *BC1TL_IDLE)(usf_state_t *);
void (osal_fastcall *BC1FL)(usf_state_t *);
void (osal_fastcall *BC1FL_OUT)(usf_state_t *);
void (osal_fastcall *BC1FL_IDLE)(usf_state_t *);
// Shift instructions
void (osal_fastcall *SLL)(usf_state_t *);
void (osal_fastcall *SRL)(usf_state_t *);
void (osal_fastcall *SRA)(usf_state_t *);
void (osal_fastcall *SLLV)(usf_state_t *);
void (osal_fastcall *SRLV)(usf_state_t *);
void (osal_fastcall *SRAV)(usf_state_t *);
void (osal_fastcall *DSLL)(usf_state_t *);
void (osal_fastcall *DSRL)(usf_state_t *);
void (osal_fastcall *DSRA)(usf_state_t *);
void (osal_fastcall *DSLLV)(usf_state_t *);
void (osal_fastcall *DSRLV)(usf_state_t *);
void (osal_fastcall *DSRAV)(usf_state_t *);
void (osal_fastcall *DSLL32)(usf_state_t *);
void (osal_fastcall *DSRL32)(usf_state_t *);
void (osal_fastcall *DSRA32)(usf_state_t *);
// COP0 instructions
void (osal_fastcall *MTC0)(usf_state_t *);
void (osal_fastcall *MFC0)(usf_state_t *);
void (osal_fastcall *TLBR)(usf_state_t *);
void (osal_fastcall *TLBWI)(usf_state_t *);
void (osal_fastcall *TLBWR)(usf_state_t *);
void (osal_fastcall *TLBP)(usf_state_t *);
void (osal_fastcall *CACHE)(usf_state_t *);
void (osal_fastcall *ERET)(usf_state_t *);
// COP1 instructions
void (osal_fastcall *LWC1)(usf_state_t *);
void (osal_fastcall *SWC1)(usf_state_t *);
void (osal_fastcall *MTC1)(usf_state_t *);
void (osal_fastcall *MFC1)(usf_state_t *);
void (osal_fastcall *CTC1)(usf_state_t *);
void (osal_fastcall *CFC1)(usf_state_t *);
void (osal_fastcall *BC1T)(usf_state_t *);
void (osal_fastcall *BC1T_OUT)(usf_state_t *);
void (osal_fastcall *BC1T_IDLE)(usf_state_t *);
void (osal_fastcall *BC1F)(usf_state_t *);
void (osal_fastcall *BC1F_OUT)(usf_state_t *);
void (osal_fastcall *BC1F_IDLE)(usf_state_t *);
void (osal_fastcall *DMFC1)(usf_state_t *);
void (osal_fastcall *DMTC1)(usf_state_t *);
void (osal_fastcall *LDC1)(usf_state_t *);
void (osal_fastcall *SDC1)(usf_state_t *);
void (osal_fastcall *CVT_S_D)(usf_state_t *);
void (osal_fastcall *CVT_S_W)(usf_state_t *);
void (osal_fastcall *CVT_S_L)(usf_state_t *);
void (osal_fastcall *CVT_D_S)(usf_state_t *);
void (osal_fastcall *CVT_D_W)(usf_state_t *);
void (osal_fastcall *CVT_D_L)(usf_state_t *);
void (osal_fastcall *CVT_W_S)(usf_state_t *);
void (osal_fastcall *CVT_W_D)(usf_state_t *);
void (osal_fastcall *CVT_L_S)(usf_state_t *);
void (osal_fastcall *CVT_L_D)(usf_state_t *);
void (osal_fastcall *ROUND_W_S)(usf_state_t *);
void (osal_fastcall *ROUND_W_D)(usf_state_t *);
void (osal_fastcall *ROUND_L_S)(usf_state_t *);
void (osal_fastcall *ROUND_L_D)(usf_state_t *);
void (osal_fastcall *TRUNC_W_S)(usf_state_t *);
void (osal_fastcall *TRUNC_W_D)(usf_state_t *);
void (osal_fastcall *TRUNC_L_S)(usf_state_t *);
void (osal_fastcall *TRUNC_L_D)(usf_state_t *);
void (osal_fastcall *CEIL_W_S)(usf_state_t *);
void (osal_fastcall *CEIL_W_D)(usf_state_t *);
void (osal_fastcall *CEIL_L_S)(usf_state_t *);
void (osal_fastcall *CEIL_L_D)(usf_state_t *);
void (osal_fastcall *FLOOR_W_S)(usf_state_t *);
void (osal_fastcall *FLOOR_W_D)(usf_state_t *);
void (osal_fastcall *FLOOR_L_S)(usf_state_t *);
void (osal_fastcall *FLOOR_L_D)(usf_state_t *);
void (osal_fastcall *ADD_S)(usf_state_t *);
void (osal_fastcall *ADD_D)(usf_state_t *);
void (osal_fastcall *SUB_S)(usf_state_t *);
void (osal_fastcall *SUB_D)(usf_state_t *);
void (osal_fastcall *MUL_S)(usf_state_t *);
void (osal_fastcall *MUL_D)(usf_state_t *);
void (osal_fastcall *DIV_S)(usf_state_t *);
void (osal_fastcall *DIV_D)(usf_state_t *);
void (osal_fastcall *ABS_S)(usf_state_t *);
void (osal_fastcall *ABS_D)(usf_state_t *);
void (osal_fastcall *MOV_S)(usf_state_t *);
void (osal_fastcall *MOV_D)(usf_state_t *);
void (osal_fastcall *NEG_S)(usf_state_t *);
void (osal_fastcall *NEG_D)(usf_state_t *);
void (osal_fastcall *SQRT_S)(usf_state_t *);
void (osal_fastcall *SQRT_D)(usf_state_t *);
void (osal_fastcall *C_F_S)(usf_state_t *);
void (osal_fastcall *C_F_D)(usf_state_t *);
void (osal_fastcall *C_UN_S)(usf_state_t *);
void (osal_fastcall *C_UN_D)(usf_state_t *);
void (osal_fastcall *C_EQ_S)(usf_state_t *);
void (osal_fastcall *C_EQ_D)(usf_state_t *);
void (osal_fastcall *C_UEQ_S)(usf_state_t *);
void (osal_fastcall *C_UEQ_D)(usf_state_t *);
void (osal_fastcall *C_OLT_S)(usf_state_t *);
void (osal_fastcall *C_OLT_D)(usf_state_t *);
void (osal_fastcall *C_ULT_S)(usf_state_t *);
void (osal_fastcall *C_ULT_D)(usf_state_t *);
void (osal_fastcall *C_OLE_S)(usf_state_t *);
void (osal_fastcall *C_OLE_D)(usf_state_t *);
void (osal_fastcall *C_ULE_S)(usf_state_t *);
void (osal_fastcall *C_ULE_D)(usf_state_t *);
void (osal_fastcall *C_SF_S)(usf_state_t *);
void (osal_fastcall *C_SF_D)(usf_state_t *);
void (osal_fastcall *C_NGLE_S)(usf_state_t *);
void (osal_fastcall *C_NGLE_D)(usf_state_t *);
void (osal_fastcall *C_SEQ_S)(usf_state_t *);
void (osal_fastcall *C_SEQ_D)(usf_state_t *);
void (osal_fastcall *C_NGL_S)(usf_state_t *);
void (osal_fastcall *C_NGL_D)(usf_state_t *);
void (osal_fastcall *C_LT_S)(usf_state_t *);
void (osal_fastcall *C_LT_D)(usf_state_t *);
void (osal_fastcall *C_NGE_S)(usf_state_t *);
void (osal_fastcall *C_NGE_D)(usf_state_t *);
void (osal_fastcall *C_LE_S)(usf_state_t *);
void (osal_fastcall *C_LE_D)(usf_state_t *);
void (osal_fastcall *C_NGT_S)(usf_state_t *);
void (osal_fastcall *C_NGT_D)(usf_state_t *);
// Special instructions
void (osal_fastcall *SYSCALL)(usf_state_t *);
void (osal_fastcall *BREAK)(usf_state_t *);
// Exception instructions
void (osal_fastcall *TEQ)(usf_state_t *);
// Emulator helper functions
void (osal_fastcall *NOP)(usf_state_t *); // No operation (used to nullify R0 writes)
void (osal_fastcall *RESERVED)(usf_state_t *); // Reserved instruction handler
void (osal_fastcall *NI)(usf_state_t *); // Not implemented instruction handler
void (osal_fastcall *FIN_BLOCK)(usf_state_t *); // Handler for the end of a block
void (osal_fastcall *NOTCOMPILED)(usf_state_t *); // Handler for not yet compiled code
void (osal_fastcall *NOTCOMPILED2)(usf_state_t *); // TODOXXX
} cpu_instruction_table;
#endif /* M64P_R4300_OPS_H_*/

View file

@ -0,0 +1,746 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - pure_interp.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2015 Nebuleon <nebuleon.fumika@gmail.com> *
* *
* 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 <stdint.h>
#include "usf/usf.h"
#include "api/m64p_types.h"
#include "api/callbacks.h"
#include "memory/memory.h"
#include "main/main.h"
#include "osal/preproc.h"
/* TLBWrite requires invalid_code and blocks from cached_interp.h, but only if
* (at run time) the active core is not the Pure Interpreter. */
#include "cached_interp.h"
#include "r4300.h"
#include "cp0.h"
#include "cp1.h"
#include "exception.h"
#include "interupt.h"
#include "tlb.h"
#include "usf/usf_internal.h"
static void InterpretOpcode(usf_state_t * state);
#define PCADDR state->interp_PC.addr
#define ADD_TO_PC(x) state->interp_PC.addr += x*4;
#define DECLARE_INSTRUCTION(name) static void name(usf_state_t * state, uint32_t op)
#define DECLARE_JUMP(name, destination, condition, link, likely, cop1) \
static void name(usf_state_t * state, uint32_t op) \
{ \
const int take_jump = (condition); \
const unsigned int jump_target = (destination); \
long long int *link_register = (link); \
if (cop1 && check_cop1_unusable(state)) return; \
if (link_register != &state->reg[0]) \
{ \
*link_register=state->interp_PC.addr + 8; \
sign_extended(*link_register); \
} \
if (!likely || take_jump) \
{ \
state->interp_PC.addr += 4; \
state->delay_slot=1; \
InterpretOpcode(state); \
update_count(state); \
state->delay_slot=0; \
if (take_jump && !state->skip_jump) \
{ \
state->interp_PC.addr = jump_target; \
} \
} \
else \
{ \
state->interp_PC.addr += 8; \
update_count(state); \
} \
state->last_addr = state->interp_PC.addr; \
if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state); \
} \
static void name##_IDLE(usf_state_t * state, uint32_t op) \
{ \
const int take_jump = (condition); \
int skip; \
if (cop1 && check_cop1_unusable(state)) return; \
if (take_jump) \
{ \
update_count(state); \
skip = state->next_interupt - state->g_cp0_regs[CP0_COUNT_REG]; \
if (skip > 3) state->g_cp0_regs[CP0_COUNT_REG] += (skip & 0xFFFFFFFC); \
else name(state, op); \
} \
else name(state, op); \
}
#define CHECK_MEMORY()
#define RD_OF(op) (((op) >> 11) & 0x1F)
#define RS_OF(op) (((op) >> 21) & 0x1F)
#define RT_OF(op) (((op) >> 16) & 0x1F)
#define SA_OF(op) (((op) >> 6) & 0x1F)
#define IMM16S_OF(op) ((int16_t) (op))
#define IMM16U_OF(op) ((uint16_t) (op))
#define FD_OF(op) (((op) >> 6) & 0x1F)
#define FS_OF(op) (((op) >> 11) & 0x1F)
#define FT_OF(op) (((op) >> 16) & 0x1F)
#define JUMP_OF(op) ((op) & UINT32_C(0x3FFFFFF))
/* Determines whether a relative jump in a 16-bit immediate goes back to the
* same instruction without doing any work in its delay slot. The jump is
* relative to the instruction in the delay slot, so 1 instruction backwards
* (-1) goes back to the jump. */
#define IS_RELATIVE_IDLE_LOOP(op, addr) \
(IMM16S_OF(op) == -1 && *fast_mem_access(state, (addr) + 4) == 0)
/* Determines whether an absolute jump in a 26-bit immediate goes back to the
* same instruction without doing any work in its delay slot. The jump is
* in the same 256 MiB segment as the delay slot, so if the jump instruction
* is at the last address in its segment, it does not jump back to itself. */
#define IS_ABSOLUTE_IDLE_LOOP(op, addr) \
(JUMP_OF(op) == ((addr) & UINT32_C(0x0FFFFFFF)) >> 2 \
&& ((addr) & UINT32_C(0x0FFFFFFF)) != UINT32_C(0x0FFFFFFC) \
&& *fast_mem_access(state, (addr) + 4) == 0)
#define sign_extended(a) a = (int64_t) ((int32_t) (a))
#define sign_extendedb(a) a = (int64_t) ((int8_t) (a))
#define sign_extendedh(a) a = (int64_t) ((int16_t) (a))
/* These macros are like those in macros.h, but they parse opcode fields. */
#define rrt state->reg[RT_OF(op)]
#define rrd state->reg[RD_OF(op)]
#define rfs FS_OF(op)
#define rrs state->reg[RS_OF(op)]
#define rsa SA_OF(op)
#define irt state->reg[RT_OF(op)]
#define ioffset IMM16S_OF(op)
#define iimmediate IMM16S_OF(op)
#define irs state->reg[RS_OF(op)]
#define ibase state->reg[RS_OF(op)]
#define jinst_index JUMP_OF(op)
#define lfbase RS_OF(op)
#define lfft FT_OF(op)
#define lfoffset IMM16S_OF(op)
#define cfft FT_OF(op)
#define cffs FS_OF(op)
#define cffd FD_OF(op)
// 32 bits macros
#ifndef M64P_BIG_ENDIAN
#define rrt32 *((int32_t*) &state->reg[RT_OF(op)])
#define rrd32 *((int32_t*) &state->reg[RD_OF(op)])
#define rrs32 *((int32_t*) &state->reg[RS_OF(op)])
#define irs32 *((int32_t*) &state->reg[RS_OF(op)])
#define irt32 *((int32_t*) &state->reg[RT_OF(op)])
#else
#define rrt32 *((int32_t*) &state->reg[RT_OF(op)] + 1)
#define rrd32 *((int32_t*) &state->reg[RD_OF(op)] + 1)
#define rrs32 *((int32_t*) &state->reg[RS_OF(op)] + 1)
#define irs32 *((int32_t*) &state->reg[RS_OF(op)] + 1)
#define irt32 *((int32_t*) &state->reg[RT_OF(op)] + 1)
#endif
// two functions are defined from the macros above but never used
// these prototype declarations will prevent a warning
#if defined(__GNUC__)
static void JR_IDLE(usf_state_t *, uint32_t) __attribute__((used));
static void JALR_IDLE(usf_state_t *, uint32_t) __attribute__((used));
#endif
#include "interpreter.def"
#include <stdio.h>
#include <inttypes.h>
#ifdef DEBUG_INFO
#include "debugger/dbg_decoder.h"
#include <string.h>
#endif
void InterpretOpcode(usf_state_t * state)
{
uint32_t op = *fast_mem_access(state, state->PC->addr);
#ifdef DEBUG_INFO
if (0)
{
char instr[256];
char arguments[256];
r4300_decode_op(op, instr, arguments, state->PC->addr);
fprintf(state->debug_log, "%08x: %-16s %s\n", state->PC->addr, instr, arguments);
}
#endif
switch ((op >> 26) & 0x3F) {
case 0: /* SPECIAL prefix */
switch (op & 0x3F) {
case 0: /* SPECIAL opcode 0: SLL */
if (RD_OF(op) != 0) SLL(state, op);
else NOP(state, 0);
break;
case 2: /* SPECIAL opcode 2: SRL */
if (RD_OF(op) != 0) SRL(state, op);
else NOP(state, 0);
break;
case 3: /* SPECIAL opcode 3: SRA */
if (RD_OF(op) != 0) SRA(state, op);
else NOP(state, 0);
break;
case 4: /* SPECIAL opcode 4: SLLV */
if (RD_OF(op) != 0) SLLV(state, op);
else NOP(state, 0);
break;
case 6: /* SPECIAL opcode 6: SRLV */
if (RD_OF(op) != 0) SRLV(state, op);
else NOP(state, 0);
break;
case 7: /* SPECIAL opcode 7: SRAV */
if (RD_OF(op) != 0) SRAV(state, op);
else NOP(state, 0);
break;
case 8: JR(state, op); break;
case 9: /* SPECIAL opcode 9: JALR */
/* Note: This can omit the check for Rd == 0 because the JALR
* function checks for link_register != &reg[0]. If you're
* using this as a reference for a JIT, do check Rd == 0 in it. */
JALR(state, op);
break;
case 12: SYSCALL(state, op); break;
case 13: /* SPECIAL opcode 13: BREAK */
BREAK(state, op);
break;
case 15: SYNC(state, op); break;
case 16: /* SPECIAL opcode 16: MFHI */
if (RD_OF(op) != 0) MFHI(state, op);
else NOP(state, 0);
break;
case 17: MTHI(state, op); break;
case 18: /* SPECIAL opcode 18: MFLO */
if (RD_OF(op) != 0) MFLO(state, op);
else NOP(state, 0);
break;
case 19: MTLO(state, op); break;
case 20: /* SPECIAL opcode 20: DSLLV */
if (RD_OF(op) != 0) DSLLV(state, op);
else NOP(state, 0);
break;
case 22: /* SPECIAL opcode 22: DSRLV */
if (RD_OF(op) != 0) DSRLV(state, op);
else NOP(state, 0);
break;
case 23: /* SPECIAL opcode 23: DSRAV */
if (RD_OF(op) != 0) DSRAV(state, op);
else NOP(state, 0);
break;
case 24: MULT(state, op); break;
case 25: MULTU(state, op); break;
case 26: DIV(state, op); break;
case 27: DIVU(state, op); break;
case 28: DMULT(state, op); break;
case 29: DMULTU(state, op); break;
case 30: DDIV(state, op); break;
case 31: DDIVU(state, op); break;
case 32: /* SPECIAL opcode 32: ADD */
if (RD_OF(op) != 0) ADD(state, op);
else NOP(state, 0);
break;
case 33: /* SPECIAL opcode 33: ADDU */
if (RD_OF(op) != 0) ADDU(state, op);
else NOP(state, 0);
break;
case 34: /* SPECIAL opcode 34: SUB */
if (RD_OF(op) != 0) SUB(state, op);
else NOP(state, 0);
break;
case 35: /* SPECIAL opcode 35: SUBU */
if (RD_OF(op) != 0) SUBU(state, op);
else NOP(state, 0);
break;
case 36: /* SPECIAL opcode 36: AND */
if (RD_OF(op) != 0) AND(state, op);
else NOP(state, 0);
break;
case 37: /* SPECIAL opcode 37: OR */
if (RD_OF(op) != 0) OR(state, op);
else NOP(state, 0);
break;
case 38: /* SPECIAL opcode 38: XOR */
if (RD_OF(op) != 0) XOR(state, op);
else NOP(state, 0);
break;
case 39: /* SPECIAL opcode 39: NOR */
if (RD_OF(op) != 0) NOR(state, op);
else NOP(state, 0);
break;
case 42: /* SPECIAL opcode 42: SLT */
if (RD_OF(op) != 0) SLT(state, op);
else NOP(state, 0);
break;
case 43: /* SPECIAL opcode 43: SLTU */
if (RD_OF(op) != 0) SLTU(state, op);
else NOP(state, 0);
break;
case 44: /* SPECIAL opcode 44: DADD */
if (RD_OF(op) != 0) DADD(state, op);
else NOP(state, 0);
break;
case 45: /* SPECIAL opcode 45: DADDU */
if (RD_OF(op) != 0) DADDU(state, op);
else NOP(state, 0);
break;
case 46: /* SPECIAL opcode 46: DSUB */
if (RD_OF(op) != 0) DSUB(state, op);
else NOP(state, 0);
break;
case 47: /* SPECIAL opcode 47: DSUBU */
if (RD_OF(op) != 0) DSUBU(state, op);
else NOP(state, 0);
break;
case 48: /* SPECIAL opcode 48: TGE (Not implemented) */
case 49: /* SPECIAL opcode 49: TGEU (Not implemented) */
case 50: /* SPECIAL opcode 50: TLT (Not implemented) */
case 51: /* SPECIAL opcode 51: TLTU (Not implemented) */
NI(state, op);
break;
case 52: TEQ(state, op); break;
case 54: /* SPECIAL opcode 54: TNE (Not implemented) */
NI(state, op);
break;
case 56: /* SPECIAL opcode 56: DSLL */
if (RD_OF(op) != 0) DSLL(state, op);
else NOP(state, 0);
break;
case 58: /* SPECIAL opcode 58: DSRL */
if (RD_OF(op) != 0) DSRL(state, op);
else NOP(state, 0);
break;
case 59: /* SPECIAL opcode 59: DSRA */
if (RD_OF(op) != 0) DSRA(state, op);
else NOP(state, 0);
break;
case 60: /* SPECIAL opcode 60: DSLL32 */
if (RD_OF(op) != 0) DSLL32(state, op);
else NOP(state, 0);
break;
case 62: /* SPECIAL opcode 62: DSRL32 */
if (RD_OF(op) != 0) DSRL32(state, op);
else NOP(state, 0);
break;
case 63: /* SPECIAL opcode 63: DSRA32 */
if (RD_OF(op) != 0) DSRA32(state, op);
else NOP(state, 0);
break;
default: /* SPECIAL opcodes 1, 5, 10, 11, 14, 21, 40, 41, 53, 55, 57,
61: Reserved Instructions */
RESERVED(state, op);
break;
} /* switch (op & 0x3F) for the SPECIAL prefix */
break;
case 1: /* REGIMM prefix */
switch ((op >> 16) & 0x1F) {
case 0: /* REGIMM opcode 0: BLTZ */
if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BLTZ_IDLE(state, op);
else BLTZ(state, op);
break;
case 1: /* REGIMM opcode 1: BGEZ */
if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BGEZ_IDLE(state, op);
else BGEZ(state, op);
break;
case 2: /* REGIMM opcode 2: BLTZL */
if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BLTZL_IDLE(state, op);
else BLTZL(state, op);
break;
case 3: /* REGIMM opcode 3: BGEZL */
if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BGEZL_IDLE(state, op);
else BGEZL(state, op);
break;
case 8: /* REGIMM opcode 8: TGEI (Not implemented) */
case 9: /* REGIMM opcode 9: TGEIU (Not implemented) */
case 10: /* REGIMM opcode 10: TLTI (Not implemented) */
case 11: /* REGIMM opcode 11: TLTIU (Not implemented) */
case 12: /* REGIMM opcode 12: TEQI (Not implemented) */
case 14: /* REGIMM opcode 14: TNEI (Not implemented) */
NI(state, op);
break;
case 16: /* REGIMM opcode 16: BLTZAL */
if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BLTZAL_IDLE(state, op);
else BLTZAL(state, op);
break;
case 17: /* REGIMM opcode 17: BGEZAL */
if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BGEZAL_IDLE(state, op);
else BGEZAL(state, op);
break;
case 18: /* REGIMM opcode 18: BLTZALL */
if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BLTZALL_IDLE(state, op);
else BLTZALL(state, op);
break;
case 19: /* REGIMM opcode 19: BGEZALL */
if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BGEZALL_IDLE(state, op);
else BGEZALL(state, op);
break;
default: /* REGIMM opcodes 4..7, 13, 15, 20..31:
Reserved Instructions */
RESERVED(state, op);
break;
} /* switch ((op >> 16) & 0x1F) for the REGIMM prefix */
break;
case 2: /* Major opcode 2: J */
if (IS_ABSOLUTE_IDLE_LOOP(op, state->PC->addr)) J_IDLE(state, op);
else J(state, op);
break;
case 3: /* Major opcode 3: JAL */
if (IS_ABSOLUTE_IDLE_LOOP(op, state->PC->addr)) JAL_IDLE(state, op);
else JAL(state, op);
break;
case 4: /* Major opcode 4: BEQ */
if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BEQ_IDLE(state, op);
else BEQ(state, op);
break;
case 5: /* Major opcode 5: BNE */
if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BNE_IDLE(state, op);
else BNE(state, op);
break;
case 6: /* Major opcode 6: BLEZ */
if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BLEZ_IDLE(state, op);
else BLEZ(state, op);
break;
case 7: /* Major opcode 7: BGTZ */
if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BGTZ_IDLE(state, op);
else BGTZ(state, op);
break;
case 8: /* Major opcode 8: ADDI */
if (RT_OF(op) != 0) ADDI(state, op);
else NOP(state, 0);
break;
case 9: /* Major opcode 9: ADDIU */
if (RT_OF(op) != 0) ADDIU(state, op);
else NOP(state, 0);
break;
case 10: /* Major opcode 10: SLTI */
if (RT_OF(op) != 0) SLTI(state, op);
else NOP(state, 0);
break;
case 11: /* Major opcode 11: SLTIU */
if (RT_OF(op) != 0) SLTIU(state, op);
else NOP(state, 0);
break;
case 12: /* Major opcode 12: ANDI */
if (RT_OF(op) != 0) ANDI(state, op);
else NOP(state, 0);
break;
case 13: /* Major opcode 13: ORI */
if (RT_OF(op) != 0) ORI(state, op);
else NOP(state, 0);
break;
case 14: /* Major opcode 14: XORI */
if (RT_OF(op) != 0) XORI(state, op);
else NOP(state, 0);
break;
case 15: /* Major opcode 15: LUI */
if (RT_OF(op) != 0) LUI(state, op);
else NOP(state, 0);
break;
case 16: /* Coprocessor 0 prefix */
switch ((op >> 21) & 0x1F) {
case 0: /* Coprocessor 0 opcode 0: MFC0 */
if (RT_OF(op) != 0) MFC0(state, op);
else NOP(state, 0);
break;
case 4: MTC0(state, op); break;
case 16: /* Coprocessor 0 opcode 16: TLB */
switch (op & 0x3F) {
case 1: TLBR(state, op); break;
case 2: TLBWI(state, op); break;
case 6: TLBWR(state, op); break;
case 8: TLBP(state, op); break;
case 24: ERET(state, op); break;
default: /* TLB sub-opcodes 0, 3..5, 7, 9..23, 25..63:
Reserved Instructions */
RESERVED(state, op);
break;
} /* switch (op & 0x3F) for Coprocessor 0 TLB opcodes */
break;
default: /* Coprocessor 0 opcodes 1..3, 4..15, 17..31:
Reserved Instructions */
RESERVED(state, op);
break;
} /* switch ((op >> 21) & 0x1F) for the Coprocessor 0 prefix */
break;
case 17: /* Coprocessor 1 prefix */
switch ((op >> 21) & 0x1F) {
case 0: /* Coprocessor 1 opcode 0: MFC1 */
if (RT_OF(op) != 0) MFC1(state, op);
else NOP(state, 0);
break;
case 1: /* Coprocessor 1 opcode 1: DMFC1 */
if (RT_OF(op) != 0) DMFC1(state, op);
else NOP(state, 0);
break;
case 2: /* Coprocessor 1 opcode 2: CFC1 */
if (RT_OF(op) != 0) CFC1(state, op);
else NOP(state, 0);
break;
case 4: MTC1(state, op); break;
case 5: DMTC1(state, op); break;
case 6: CTC1(state, op); break;
case 8: /* Coprocessor 1 opcode 8: Branch on C1 condition... */
switch ((op >> 16) & 0x3) {
case 0: /* opcode 0: BC1F */
if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BC1F_IDLE(state, op);
else BC1F(state, op);
break;
case 1: /* opcode 1: BC1T */
if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BC1T_IDLE(state, op);
else BC1T(state, op);
break;
case 2: /* opcode 2: BC1FL */
if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BC1FL_IDLE(state, op);
else BC1FL(state, op);
break;
case 3: /* opcode 3: BC1TL */
if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BC1TL_IDLE(state, op);
else BC1TL(state, op);
break;
} /* switch ((op >> 16) & 0x3) for branches on C1 condition */
break;
case 16: /* Coprocessor 1 S-format opcodes */
switch (op & 0x3F) {
case 0: ADD_S(state, op); break;
case 1: SUB_S(state, op); break;
case 2: MUL_S(state, op); break;
case 3: DIV_S(state, op); break;
case 4: SQRT_S(state, op); break;
case 5: ABS_S(state, op); break;
case 6: MOV_S(state, op); break;
case 7: NEG_S(state, op); break;
case 8: ROUND_L_S(state, op); break;
case 9: TRUNC_L_S(state, op); break;
case 10: CEIL_L_S(state, op); break;
case 11: FLOOR_L_S(state, op); break;
case 12: ROUND_W_S(state, op); break;
case 13: TRUNC_W_S(state, op); break;
case 14: CEIL_W_S(state, op); break;
case 15: FLOOR_W_S(state, op); break;
case 33: CVT_D_S(state, op); break;
case 36: CVT_W_S(state, op); break;
case 37: CVT_L_S(state, op); break;
case 48: C_F_S(state, op); break;
case 49: C_UN_S(state, op); break;
case 50: C_EQ_S(state, op); break;
case 51: C_UEQ_S(state, op); break;
case 52: C_OLT_S(state, op); break;
case 53: C_ULT_S(state, op); break;
case 54: C_OLE_S(state, op); break;
case 55: C_ULE_S(state, op); break;
case 56: C_SF_S(state, op); break;
case 57: C_NGLE_S(state, op); break;
case 58: C_SEQ_S(state, op); break;
case 59: C_NGL_S(state, op); break;
case 60: C_LT_S(state, op); break;
case 61: C_NGE_S(state, op); break;
case 62: C_LE_S(state, op); break;
case 63: C_NGT_S(state, op); break;
default: /* Coprocessor 1 S-format opcodes 16..32, 34..35, 38..47:
Reserved Instructions */
RESERVED(state, op);
break;
} /* switch (op & 0x3F) for Coprocessor 1 S-format opcodes */
break;
case 17: /* Coprocessor 1 D-format opcodes */
switch (op & 0x3F) {
case 0: ADD_D(state, op); break;
case 1: SUB_D(state, op); break;
case 2: MUL_D(state, op); break;
case 3: DIV_D(state, op); break;
case 4: SQRT_D(state, op); break;
case 5: ABS_D(state, op); break;
case 6: MOV_D(state, op); break;
case 7: NEG_D(state, op); break;
case 8: ROUND_L_D(state, op); break;
case 9: TRUNC_L_D(state, op); break;
case 10: CEIL_L_D(state, op); break;
case 11: FLOOR_L_D(state, op); break;
case 12: ROUND_W_D(state, op); break;
case 13: TRUNC_W_D(state, op); break;
case 14: CEIL_W_D(state, op); break;
case 15: FLOOR_W_D(state, op); break;
case 32: CVT_S_D(state, op); break;
case 36: CVT_W_D(state, op); break;
case 37: CVT_L_D(state, op); break;
case 48: C_F_D(state, op); break;
case 49: C_UN_D(state, op); break;
case 50: C_EQ_D(state, op); break;
case 51: C_UEQ_D(state, op); break;
case 52: C_OLT_D(state, op); break;
case 53: C_ULT_D(state, op); break;
case 54: C_OLE_D(state, op); break;
case 55: C_ULE_D(state, op); break;
case 56: C_SF_D(state, op); break;
case 57: C_NGLE_D(state, op); break;
case 58: C_SEQ_D(state, op); break;
case 59: C_NGL_D(state, op); break;
case 60: C_LT_D(state, op); break;
case 61: C_NGE_D(state, op); break;
case 62: C_LE_D(state, op); break;
case 63: C_NGT_D(state, op); break;
default: /* Coprocessor 1 D-format opcodes 16..31, 33..35, 38..47:
Reserved Instructions */
RESERVED(state, op);
break;
} /* switch (op & 0x3F) for Coprocessor 1 D-format opcodes */
break;
case 20: /* Coprocessor 1 W-format opcodes */
switch (op & 0x3F) {
case 32: CVT_S_W(state, op); break;
case 33: CVT_D_W(state, op); break;
default: /* Coprocessor 1 W-format opcodes 0..31, 34..63:
Reserved Instructions */
RESERVED(state, op);
break;
}
break;
case 21: /* Coprocessor 1 L-format opcodes */
switch (op & 0x3F) {
case 32: CVT_S_L(state, op); break;
case 33: CVT_D_L(state, op); break;
default: /* Coprocessor 1 L-format opcodes 0..31, 34..63:
Reserved Instructions */
RESERVED(state, op);
break;
}
break;
default: /* Coprocessor 1 opcodes 3, 7, 9..15, 18..19, 22..31:
Reserved Instructions */
RESERVED(state, op);
break;
} /* switch ((op >> 21) & 0x1F) for the Coprocessor 1 prefix */
break;
case 20: /* Major opcode 20: BEQL */
if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BEQL_IDLE(state, op);
else BEQL(state, op);
break;
case 21: /* Major opcode 21: BNEL */
if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BNEL_IDLE(state, op);
else BNEL(state, op);
break;
case 22: /* Major opcode 22: BLEZL */
if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BLEZL_IDLE(state, op);
else BLEZL(state, op);
break;
case 23: /* Major opcode 23: BGTZL */
if (IS_RELATIVE_IDLE_LOOP(op, state->PC->addr)) BGTZL_IDLE(state, op);
else BGTZL(state, op);
break;
case 24: /* Major opcode 24: DADDI */
if (RT_OF(op) != 0) DADDI(state, op);
else NOP(state, 0);
break;
case 25: /* Major opcode 25: DADDIU */
if (RT_OF(op) != 0) DADDIU(state, op);
else NOP(state, 0);
break;
case 26: /* Major opcode 26: LDL */
if (RT_OF(op) != 0) LDL(state, op);
else NOP(state, 0);
break;
case 27: /* Major opcode 27: LDR */
if (RT_OF(op) != 0) LDR(state, op);
else NOP(state, 0);
break;
case 32: /* Major opcode 32: LB */
if (RT_OF(op) != 0) LB(state, op);
else NOP(state, 0);
break;
case 33: /* Major opcode 33: LH */
if (RT_OF(op) != 0) LH(state, op);
else NOP(state, 0);
break;
case 34: /* Major opcode 34: LWL */
if (RT_OF(op) != 0) LWL(state, op);
else NOP(state, 0);
break;
case 35: /* Major opcode 35: LW */
if (RT_OF(op) != 0) LW(state, op);
else NOP(state, 0);
break;
case 36: /* Major opcode 36: LBU */
if (RT_OF(op) != 0) LBU(state, op);
else NOP(state, 0);
break;
case 37: /* Major opcode 37: LHU */
if (RT_OF(op) != 0) LHU(state, op);
else NOP(state, 0);
break;
case 38: /* Major opcode 38: LWR */
if (RT_OF(op) != 0) LWR(state, op);
else NOP(state, 0);
break;
case 39: /* Major opcode 39: LWU */
if (RT_OF(op) != 0) LWU(state, op);
else NOP(state, 0);
break;
case 40: SB(state, op); break;
case 41: SH(state, op); break;
case 42: SWL(state, op); break;
case 43: SW(state, op); break;
case 44: SDL(state, op); break;
case 45: SDR(state, op); break;
case 46: SWR(state, op); break;
case 47: CACHE(state, op); break;
case 48: /* Major opcode 48: LL */
if (RT_OF(op) != 0) LL(state, op);
else NOP(state, 0);
break;
case 49: LWC1(state, op); break;
case 52: /* Major opcode 52: LLD (Not implemented) */
NI(state, op);
break;
case 53: LDC1(state, op); break;
case 55: /* Major opcode 55: LD */
if (RT_OF(op) != 0) LD(state, op);
else NOP(state, 0);
break;
case 56: /* Major opcode 56: SC */
if (RT_OF(op) != 0) SC(state, op);
else NOP(state, 0);
break;
case 57: SWC1(state, op); break;
case 60: /* Major opcode 60: SCD (Not implemented) */
NI(state, op);
break;
case 61: SDC1(state, op); break;
case 63: SD(state, op); break;
default: /* Major opcodes 18..19, 28..31, 50..51, 54, 58..59, 62:
Reserved Instructions */
RESERVED(state, op);
break;
} /* switch ((op >> 26) & 0x3F) */
}
void pure_interpreter(usf_state_t * state)
{
state->stop = 0;
state->PC = &state->interp_PC;
while (!state->stop)
{
r4300_checkpoint(state);
InterpretOpcode(state);
}
}

View file

@ -0,0 +1,27 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - pure_interp.h *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_R4300_PURE_INTERP_H
#define M64P_R4300_PURE_INTERP_H
void pure_interpreter(usf_state_t *);
#endif /* M64P_R4300_PURE_INTERP_H */

View file

@ -0,0 +1,349 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - r4300.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 <stdlib.h>
#include <string.h>
#include "usf/usf.h"
#include "usf/usf_internal.h"
#include "ai/ai_controller.h"
#include "api/m64p_types.h"
#include "api/callbacks.h"
#include "memory/memory.h"
#include "main/main.h"
#include "main/rom.h"
#include "pi/pi_controller.h"
#include "rsp/rsp_core.h"
#include "si/si_controller.h"
#include "vi/vi_controller.h"
#include "r4300.h"
#include "r4300_core.h"
#include "cached_interp.h"
#include "cp0.h"
#include "cp1.h"
#include "ops.h"
#include "interupt.h"
#include "pure_interp.h"
#include "recomp.h"
#include "recomph.h"
#include "tlb.h"
#include "new_dynarec/new_dynarec.h"
#ifdef DBG
#include "debugger/dbg_types.h"
#include "debugger/debugger.h"
#endif
#if defined(COUNT_INSTR)
#include "instr_counters.h"
#endif
void generic_jump_to(usf_state_t * state, unsigned int address)
{
if (state->r4300emu == CORE_PURE_INTERPRETER)
state->interp_PC.addr = address;
else {
#ifdef NEW_DYNAREC
if (state->r4300emu == CORE_DYNAREC)
state->last_addr = pcaddr;
else
jump_to(address);
#else
jump_to(address);
#endif
}
}
/* this hard reset function simulates the boot-up state of the R4300 CPU */
void r4300_reset_hard(usf_state_t * state)
{
unsigned int i;
// clear r4300 registers and TLB entries
for (i = 0; i < 32; i++)
{
state->reg[i]=0;
state->g_cp0_regs[i]=0;
state->reg_cop1_fgr_64[i]=0;
// --------------tlb------------------------
state->tlb_e[i].mask=0;
state->tlb_e[i].vpn2=0;
state->tlb_e[i].g=0;
state->tlb_e[i].asid=0;
state->tlb_e[i].pfn_even=0;
state->tlb_e[i].c_even=0;
state->tlb_e[i].d_even=0;
state->tlb_e[i].v_even=0;
state->tlb_e[i].pfn_odd=0;
state->tlb_e[i].c_odd=0;
state->tlb_e[i].d_odd=0;
state->tlb_e[i].v_odd=0;
state->tlb_e[i].r=0;
//tlb_e[i].check_parity_mask=0x1000;
state->tlb_e[i].start_even=0;
state->tlb_e[i].end_even=0;
state->tlb_e[i].phys_even=0;
state->tlb_e[i].start_odd=0;
state->tlb_e[i].end_odd=0;
state->tlb_e[i].phys_odd=0;
}
for (i=0; i<0x100000; i++)
{
state->tlb_LUT_r[i] = 0;
state->tlb_LUT_w[i] = 0;
}
state->llbit=0;
state->hi=0;
state->lo=0;
state->FCR0=0x511;
state->FCR31=0;
// set COP0 registers
state->g_cp0_regs[CP0_RANDOM_REG] = 31;
state->g_cp0_regs[CP0_STATUS_REG]= 0x34000000;
set_fpr_pointers(state, state->g_cp0_regs[CP0_STATUS_REG]);
state->g_cp0_regs[CP0_CONFIG_REG]= 0x6e463;
state->g_cp0_regs[CP0_PREVID_REG] = 0xb00;
state->g_cp0_regs[CP0_COUNT_REG] = 0x5000;
state->g_cp0_regs[CP0_CAUSE_REG] = 0x5C;
state->g_cp0_regs[CP0_CONTEXT_REG] = 0x7FFFF0;
state->g_cp0_regs[CP0_EPC_REG] = 0xFFFFFFFF;
state->g_cp0_regs[CP0_BADVADDR_REG] = 0xFFFFFFFF;
state->g_cp0_regs[CP0_ERROREPC_REG] = 0xFFFFFFFF;
state->rounding_mode = 0x33F;
}
static unsigned int get_tv_type(usf_state_t * state)
{
switch(state->ROM_PARAMS.systemtype)
{
default:
case SYSTEM_NTSC: return 1;
case SYSTEM_PAL: return 0;
case SYSTEM_MPAL: return 2;
}
}
/* Simulates end result of PIFBootROM execution */
void r4300_reset_soft(usf_state_t * state)
{
unsigned int rom_type = 0; /* 0:Cart, 1:DD */
unsigned int reset_type = 0; /* 0:ColdReset, 1:NMI */
unsigned int s7 = 0; /* ??? */
unsigned int tv_type = get_tv_type(state); /* 0:PAL, 1:NTSC, 2:MPAL */
uint32_t bsd_dom1_config = (state->g_rom && state->g_rom_size >= 4) ? *(uint32_t*)state->g_rom : 0;
state->g_cp0_regs[CP0_STATUS_REG] = 0x34000000;
state->g_cp0_regs[CP0_CONFIG_REG] = 0x0006e463;
state->g_sp.regs[SP_STATUS_REG] = 1;
state->g_sp.regs2[SP_PC_REG] = 0;
state->g_pi.regs[PI_BSD_DOM1_LAT_REG] = (bsd_dom1_config ) & 0xff;
state->g_pi.regs[PI_BSD_DOM1_PWD_REG] = (bsd_dom1_config >> 8) & 0xff;
state->g_pi.regs[PI_BSD_DOM1_PGS_REG] = (bsd_dom1_config >> 16) & 0x0f;
state->g_pi.regs[PI_BSD_DOM1_RLS_REG] = (bsd_dom1_config >> 20) & 0x03;
state->g_pi.regs[PI_STATUS_REG] = 0;
state->g_ai.regs[AI_DRAM_ADDR_REG] = 0;
state->g_ai.regs[AI_LEN_REG] = 0;
state->g_vi.regs[VI_V_INTR_REG] = 1023;
state->g_vi.regs[VI_CURRENT_REG] = 0;
state->g_vi.regs[VI_H_START_REG] = 0;
state->g_r4300.mi.regs[MI_INTR_REG] &= ~(MI_INTR_PI | MI_INTR_VI | MI_INTR_AI | MI_INTR_SP);
if (state->g_rom && state->g_rom_size >= 0xfc0)
memcpy((unsigned char*)state->g_sp.mem+0x40, state->g_rom+0x40, 0xfc0);
state->reg[19] = rom_type; /* s3 */
state->reg[20] = tv_type; /* s4 */
state->reg[21] = reset_type; /* s5 */
state->reg[22] = state->g_si.pif.cic.seed;/* s6 */
state->reg[23] = s7; /* s7 */
/* required by CIC x105 */
state->g_sp.mem[0x1000/4] = 0x3c0dbfc0;
state->g_sp.mem[0x1004/4] = 0x8da807fc;
state->g_sp.mem[0x1008/4] = 0x25ad07c0;
state->g_sp.mem[0x100c/4] = 0x31080080;
state->g_sp.mem[0x1010/4] = 0x5500fffc;
state->g_sp.mem[0x1014/4] = 0x3c0dbfc0;
state->g_sp.mem[0x1018/4] = 0x8da80024;
state->g_sp.mem[0x101c/4] = 0x3c0bb000;
/* required by CIC x105 */
state->reg[11] = 0xffffffffa4000040ULL; /* t3 */
state->reg[29] = 0xffffffffa4001ff0ULL; /* sp */
state->reg[31] = 0xffffffffa4001550ULL; /* ra */
/* ready to execute IPL3 */
}
#if !defined(NO_ASM)
static void dynarec_setup_code()
{
usf_state_t * state;
#ifdef _MSC_VER
_asm
{
mov state, esi
}
#else
asm volatile
#ifdef __x86_64__
(" mov %%r15, (%[state]) \n"
#else
(" mov %%esi, (%[state]) \n"
#endif
:
: [state]"r"(&state)
: "memory"
);
#endif
// The dynarec jumps here after we call dyna_start and it prepares
// Here we need to prepare the initial code block and jump to it
jump_to(state->last_addr);
// Prevent segfault on failed jump_to
if (!state->actual || !state->actual->block || !state->actual->code)
dyna_stop(state);
}
#endif
void r4300_begin(usf_state_t * state)
{
state->current_instruction_table = cached_interpreter_table;
state->delay_slot=0;
state->stop = 0;
state->rompause = 0;
state->next_interupt = 624999;
init_interupt(state);
if (state->r4300emu == CORE_PURE_INTERPRETER)
{
DebugMessage(state, M64MSG_INFO, "Starting R4300 emulator: Pure Interpreter");
state->r4300emu = CORE_PURE_INTERPRETER;
}
#if defined(DYNAREC)
else if (state->r4300emu >= 2)
{
DebugMessage(state, M64MSG_INFO, "Starting R4300 emulator: Dynamic Recompiler");
state->r4300emu = CORE_DYNAREC;
init_blocks(state);
#ifdef NEW_DYNAREC
new_dynarec_init(state);
#endif
}
#endif
else /* if (r4300emu == CORE_INTERPRETER) */
{
DebugMessage(state, M64MSG_INFO, "Starting R4300 emulator: Cached Interpreter");
state->r4300emu = CORE_INTERPRETER;
init_blocks(state);
}
}
void r4300_reset_checkpoint(usf_state_t * state, unsigned int new_cp0_count)
{
unsigned int diff = state->g_cp0_regs[CP0_COUNT_REG] - state->g_timer_checkpoint;
state->g_timer_checkpoint = new_cp0_count - diff;
}
void r4300_checkpoint(usf_state_t * state)
{
if (state->g_cp0_regs[CP0_COUNT_REG] - state->g_timer_checkpoint >= state->count_per_op * 20000000)
{
if (state->last_sample_buffer_count == state->sample_buffer_count)
{
DebugMessage(state, 1, "Emulator appears to be stuck!");
return;
}
state->last_sample_buffer_count = state->sample_buffer_count;
state->g_timer_checkpoint = state->g_cp0_regs[CP0_COUNT_REG];
}
}
void r4300_execute(usf_state_t * state)
{
state->g_timer_checkpoint = state->g_cp0_regs[CP0_COUNT_REG];
state->last_sample_buffer_count = state->sample_buffer_count;
if (state->r4300emu == CORE_PURE_INTERPRETER)
{
pure_interpreter(state);
}
#if defined(DYNAREC)
else if (state->r4300emu == CORE_DYNAREC)
{
#ifdef NEW_DYNAREC
new_dyna_start(state);
#else
dyna_start(state, (void*)dynarec_setup_code);
state->PC++;
#endif
}
#endif
else /* if (r4300emu == CORE_INTERPRETER) */
{
/* Prevent segfault on failed jump_to */
if (!state->actual->block)
return;
while (!state->stop)
{
r4300_checkpoint(state);
state->PC->ops(state);
}
}
}
void r4300_end(usf_state_t * state)
{
if (state->r4300emu == CORE_PURE_INTERPRETER)
{
}
#if defined(DYNAREC)
else if (state->r4300emu == CORE_DYNAREC)
{
#ifdef NEW_DYNAREC
new_dynarec_cleanup(state);
#endif
free_blocks(state);
}
#endif
else /* if (r4300emu == CORE_INTERPRETER) */
{
free_blocks(state);
}
DebugMessage(state, M64MSG_INFO, "R4300 emulator finished.");
}

View file

@ -0,0 +1,52 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - r4300.h *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_R4300_R4300_H
#define M64P_R4300_R4300_H
#include "usf/usf.h"
#include "ops.h"
#include "recomp.h"
#define COUNT_PER_OP_DEFAULT 2
void r4300_reset_hard(usf_state_t *);
void r4300_reset_soft(usf_state_t *);
void r4300_begin(usf_state_t *);
void r4300_execute(usf_state_t *);
void r4300_end(usf_state_t *);
void r4300_reset_checkpoint(usf_state_t *, unsigned int new_cp0_count);
void r4300_checkpoint(usf_state_t *);
/* Jump to the given address. This works for all r4300 emulator, but is slower.
* Use this for common code which can be executed from any r4300 emulator. */
void generic_jump_to(usf_state_t *, unsigned int address);
// r4300 emulators
#define CORE_PURE_INTERPRETER 0
#define CORE_INTERPRETER 1
#define CORE_DYNAREC 2
#endif /* M64P_R4300_R4300_H */

View file

@ -0,0 +1,35 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - r4300_core.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* 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 "usf/usf.h"
#include "r4300_core.h"
void init_r4300(struct r4300_core* r4300)
{
init_mi(&r4300->mi);
}
void connect_r4300(struct r4300_core* r4300,
usf_state_t* state)
{
r4300->state = state;
}

View file

@ -0,0 +1,39 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - r4300_core.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_R4300_R4300_CORE_H
#define M64P_R4300_R4300_CORE_H
#include "mi_controller.h"
struct r4300_core
{
struct mi_controller mi;
usf_state_t* state;
};
void init_r4300(struct r4300_core* r4300);
void connect_r4300(struct r4300_core* r4300,
usf_state_t* state);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,114 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - recomp.h *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_R4300_RECOMP_H
#define M64P_R4300_RECOMP_H
#include <stddef.h>
#include "osal/preproc.h"
#ifndef PRECOMP_STRUCTS
#define PRECOMP_STRUCTS
#if defined(__x86_64__)
#include "x86_64/assemble_struct.h"
#else
#include "x86/assemble_struct.h"
#endif
typedef struct _precomp_instr
{
void (osal_fastcall *ops)(usf_state_t * state);
union
{
struct
{
long long int *rs;
long long int *rt;
short immediate;
} i;
struct
{
unsigned int inst_index;
} j;
struct
{
long long int *rs;
long long int *rt;
long long int *rd;
unsigned char sa;
unsigned char nrd;
} r;
struct
{
unsigned char base;
unsigned char ft;
short offset;
} lf;
struct
{
unsigned char ft;
unsigned char fs;
unsigned char fd;
} cf;
} f;
unsigned int addr; /* word-aligned instruction address in r4300 address space */
unsigned int local_addr; /* byte offset to start of corresponding x86_64 instructions, from start of code block */
reg_cache_struct reg_cache_infos;
} precomp_instr;
typedef struct _precomp_block
{
precomp_instr *block;
unsigned int start;
unsigned int end;
unsigned char *code;
unsigned int code_length;
unsigned int max_code_length;
void *jumps_table;
int jumps_number;
void *riprel_table;
int riprel_number;
//unsigned char md5[16];
unsigned int adler32;
} precomp_block;
#endif
void recompile_block(usf_state_t *, int *source, precomp_block *block, unsigned int func);
void init_block(usf_state_t *, precomp_block *block);
void free_block(usf_state_t *, precomp_block *block);
void recompile_opcode(usf_state_t *);
void dyna_jump(usf_state_t *);
void dyna_start(usf_state_t *, void *code);
void dyna_stop(usf_state_t *);
void *realloc_exec(usf_state_t *, void *ptr, size_t oldsize, size_t newsize);
#if defined(__x86_64__)
#include "x86_64/assemble.h"
#include "x86_64/regcache.h"
#else
#include "x86/assemble.h"
#include "x86/regcache.h"
#endif
#endif /* M64P_R4300_RECOMP_H */

View file

@ -0,0 +1,294 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - recomph.h *
* 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_R4300_RECOMPH_H
#define M64P_R4300_RECOMPH_H
#include "usf/usf.h"
#include "usf/usf_internal.h"
#include "recomp.h"
void passe2(usf_state_t *, precomp_instr *dest, int start, int end, precomp_block* block);
void init_assembler(usf_state_t *, void *block_jumps_table, int block_jumps_number, void *block_riprel_table, int block_riprel_number);
void free_assembler(usf_state_t *, void **block_jumps_table, int *block_jumps_number, void **block_riprel_table, int *block_riprel_number);
#if defined(__x86_64__)
void gencallinterp(usf_state_t *, unsigned long long addr, int jump);
#else
void gencallinterp(usf_state_t *, unsigned long addr, int jump);
#endif
void genupdate_system(usf_state_t *, int type);
void genbnel(usf_state_t *);
void genblezl(usf_state_t *);
void genlw(usf_state_t *);
void genlbu(usf_state_t *);
void genlhu(usf_state_t *);
void gensb(usf_state_t *);
void gensh(usf_state_t *);
void gensw(usf_state_t *);
void gencache(usf_state_t *);
void genlwc1(usf_state_t *);
void genld(usf_state_t *);
void gensd(usf_state_t *);
void genbeq(usf_state_t *);
void genbne(usf_state_t *);
void genblez(usf_state_t *);
void genaddi(usf_state_t *);
void genaddiu(usf_state_t *);
void genslti(usf_state_t *);
void gensltiu(usf_state_t *);
void genandi(usf_state_t *);
void genori(usf_state_t *);
void genxori(usf_state_t *);
void genlui(usf_state_t *);
void genbeql(usf_state_t *);
void genmul_s(usf_state_t *);
void gendiv_s(usf_state_t *);
void gencvt_d_s(usf_state_t *);
void genadd_d(usf_state_t *);
void gentrunc_w_d(usf_state_t *);
void gencvt_s_w(usf_state_t *);
void genmfc1(usf_state_t *);
void gencfc1(usf_state_t *);
void genmtc1(usf_state_t *);
void genctc1(usf_state_t *);
void genj(usf_state_t *);
void genjal(usf_state_t *);
void genslt(usf_state_t *);
void gensltu(usf_state_t *);
void gendsll32(usf_state_t *);
void gendsra32(usf_state_t *);
void genbgez(usf_state_t *);
void genbgezl(usf_state_t *);
void genbgezal(usf_state_t *);
void gentlbwi(usf_state_t *);
void generet(usf_state_t *);
void genmfc0(usf_state_t *);
void genadd_s(usf_state_t *);
void genmult(usf_state_t *);
void genmultu(usf_state_t *);
void genmflo(usf_state_t *);
void genmtlo(usf_state_t *);
void gendiv(usf_state_t *);
void gendmultu(usf_state_t *);
void genddivu(usf_state_t *);
void genadd(usf_state_t *);
void genaddu(usf_state_t *);
void gensubu(usf_state_t *);
void genand(usf_state_t *);
void genor(usf_state_t *);
void genxor(usf_state_t *);
void genreserved(usf_state_t *);
void gennop(usf_state_t *);
void gensll(usf_state_t *);
void gensrl(usf_state_t *);
void gensra(usf_state_t *);
void gensllv(usf_state_t *);
void gensrlv(usf_state_t *);
void genjr(usf_state_t *);
void genni(usf_state_t *);
void genmfhi(usf_state_t *);
void genmthi(usf_state_t *);
void genmtc0(usf_state_t *);
void genbltz(usf_state_t *);
void genlwl(usf_state_t *);
void genswl(usf_state_t *);
void gentlbp(usf_state_t *);
void gentlbr(usf_state_t *);
void genswr(usf_state_t *);
void genlwr(usf_state_t *);
void gensrav(usf_state_t *);
void genbgtz(usf_state_t *);
void genlb(usf_state_t *);
void genswc1(usf_state_t *);
void genldc1(usf_state_t *);
void gencvt_d_w(usf_state_t *);
void genmul_d(usf_state_t *);
void gensub_d(usf_state_t *);
void gendiv_d(usf_state_t *);
void gencvt_s_d(usf_state_t *);
void genmov_s(usf_state_t *);
void genc_le_s(usf_state_t *);
void genbc1t(usf_state_t *);
void gentrunc_w_s(usf_state_t *);
void genbc1tl(usf_state_t *);
void genc_lt_s(usf_state_t *);
void genbc1fl(usf_state_t *);
void genneg_s(usf_state_t *);
void genc_le_d(usf_state_t *);
void genbgezal_idle(usf_state_t *);
void genj_idle(usf_state_t *);
void genbeq_idle(usf_state_t *);
void genlh(usf_state_t *);
void genmov_d(usf_state_t *);
void genc_lt_d(usf_state_t *);
void genbc1f(usf_state_t *);
void gennor(usf_state_t *);
void genneg_d(usf_state_t *);
void gensub(usf_state_t *);
void genblez_idle(usf_state_t *);
void gendivu(usf_state_t *);
void gencvt_w_s(usf_state_t *);
void genbltzl(usf_state_t *);
void gensdc1(usf_state_t *);
void genc_eq_s(usf_state_t *);
void genjalr(usf_state_t *);
void gensub_s(usf_state_t *);
void gensqrt_s(usf_state_t *);
void genc_eq_d(usf_state_t *);
void gencvt_w_d(usf_state_t *);
void genfin_block(usf_state_t *);
void genddiv(usf_state_t *);
void gendaddiu(usf_state_t *);
void genbgtzl(usf_state_t *);
void gendsrav(usf_state_t *);
void gendsllv(usf_state_t *);
void gencvt_s_l(usf_state_t *);
void gendmtc1(usf_state_t *);
void gendsrlv(usf_state_t *);
void gendsra(usf_state_t *);
void gendmult(usf_state_t *);
void gendsll(usf_state_t *);
void genabs_s(usf_state_t *);
void gensc(usf_state_t *);
void gennotcompiled(usf_state_t *);
void genjal_idle(usf_state_t *);
void genjal_out(usf_state_t *);
void genbeq_out(usf_state_t *);
void gensyscall(usf_state_t *);
void gensync(usf_state_t *);
void gendadd(usf_state_t *);
void gendaddu(usf_state_t *);
void gendsub(usf_state_t *);
void gendsubu(usf_state_t *);
void genteq(usf_state_t *);
void gendsrl(usf_state_t *);
void gendsrl32(usf_state_t *);
void genbltz_idle(usf_state_t *);
void genbltz_out(usf_state_t *);
void genbgez_idle(usf_state_t *);
void genbgez_out(usf_state_t *);
void genbltzl_idle(usf_state_t *);
void genbltzl_out(usf_state_t *);
void genbgezl_idle(usf_state_t *);
void genbgezl_out(usf_state_t *);
void genbltzal_idle(usf_state_t *);
void genbltzal_out(usf_state_t *);
void genbltzal(usf_state_t *);
void genbgezal_out(usf_state_t *);
void genbltzall_idle(usf_state_t *);
void genbltzall_out(usf_state_t *);
void genbltzall(usf_state_t *);
void genbgezall_idle(usf_state_t *);
void genbgezall_out(usf_state_t *);
void genbgezall(usf_state_t *);
void gentlbwr(usf_state_t *);
void genbc1f_idle(usf_state_t *);
void genbc1f_out(usf_state_t *);
void genbc1t_idle(usf_state_t *);
void genbc1t_out(usf_state_t *);
void genbc1fl_idle(usf_state_t *);
void genbc1fl_out(usf_state_t *);
void genbc1tl_idle(usf_state_t *);
void genbc1tl_out(usf_state_t *);
void genround_l_s(usf_state_t *);
void gentrunc_l_s(usf_state_t *);
void genceil_l_s(usf_state_t *);
void genfloor_l_s(usf_state_t *);
void genround_w_s(usf_state_t *);
void genceil_w_s(usf_state_t *);
void genfloor_w_s(usf_state_t *);
void gencvt_l_s(usf_state_t *);
void genc_f_s(usf_state_t *);
void genc_un_s(usf_state_t *);
void genc_ueq_s(usf_state_t *);
void genc_olt_s(usf_state_t *);
void genc_ult_s(usf_state_t *);
void genc_ole_s(usf_state_t *);
void genc_ule_s(usf_state_t *);
void genc_sf_s(usf_state_t *);
void genc_ngle_s(usf_state_t *);
void genc_seq_s(usf_state_t *);
void genc_ngl_s(usf_state_t *);
void genc_nge_s(usf_state_t *);
void genc_ngt_s(usf_state_t *);
void gensqrt_d(usf_state_t *);
void genabs_d(usf_state_t *);
void genround_l_d(usf_state_t *);
void gentrunc_l_d(usf_state_t *);
void genceil_l_d(usf_state_t *);
void genfloor_l_d(usf_state_t *);
void genround_w_d(usf_state_t *);
void genceil_w_d(usf_state_t *);
void genfloor_w_d(usf_state_t *);
void gencvt_l_d(usf_state_t *);
void genc_f_d(usf_state_t *);
void genc_un_d(usf_state_t *);
void genc_ueq_d(usf_state_t *);
void genc_olt_d(usf_state_t *);
void genc_ult_d(usf_state_t *);
void genc_ole_d(usf_state_t *);
void genc_ule_d(usf_state_t *);
void genc_sf_d(usf_state_t *);
void genc_ngle_d(usf_state_t *);
void genc_seq_d(usf_state_t *);
void genc_ngl_d(usf_state_t *);
void genc_nge_d(usf_state_t *);
void genc_ngt_d(usf_state_t *);
void gencvt_d_l(usf_state_t *);
void gendmfc1(usf_state_t *);
void genj_out(usf_state_t *);
void genbne_idle(usf_state_t *);
void genbne_out(usf_state_t *);
void genblez_out(usf_state_t *);
void genbgtz_idle(usf_state_t *);
void genbgtz_out(usf_state_t *);
void genbeql_idle(usf_state_t *);
void genbeql_out(usf_state_t *);
void genbnel_idle(usf_state_t *);
void genbnel_out(usf_state_t *);
void genblezl_idle(usf_state_t *);
void genblezl_out(usf_state_t *);
void genbgtzl_idle(usf_state_t *);
void genbgtzl_out(usf_state_t *);
void gendaddi(usf_state_t *);
void genldl(usf_state_t *);
void genldr(usf_state_t *);
void genlwu(usf_state_t *);
void gensdl(usf_state_t *);
void gensdr(usf_state_t *);
void genlink_subblock(usf_state_t *);
void gendelayslot(usf_state_t *);
void gencheck_interupt_reg(usf_state_t *);
void gentest(usf_state_t *);
void gentest_out(usf_state_t *);
void gentest_idle(usf_state_t *);
void gentestl(usf_state_t *);
void gentestl_out(usf_state_t *);
void gencheck_cop1_unusable(usf_state_t *);
void genll(usf_state_t *);
void genbreak(usf_state_t *);
#endif /* M64P_R4300_RECOMPH_H */

View file

@ -0,0 +1,55 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - reset.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2011 CasualJames *
* Copyright (C) 2008-2009 Richard Goedeken *
* Copyright (C) 2008 Ebenblues Nmn Okaygo Tillin9 *
* Hard reset based on code by 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 "usf/usf.h"
#include "usf/usf_internal.h"
#include "r4300/reset.h"
#include "r4300/r4300.h"
#include "r4300/interupt.h"
#include "memory/memory.h"
#include "r4300/cached_interp.h"
void reset_hard(usf_state_t * state)
{
init_memory(state, 0x800000);
r4300_reset_hard(state);
r4300_reset_soft(state);
state->last_addr = 0xa4000040;
state->next_interupt = 624999;
init_interupt(state);
if(state->r4300emu != CORE_PURE_INTERPRETER)
{
free_blocks(state);
init_blocks(state);
}
generic_jump_to(state, state->last_addr);
}
void reset_soft(usf_state_t * state)
{
add_interupt_event(state, HW2_INT, 0); /* Hardware 2 Interrupt immediately */
add_interupt_event(state, NMI_INT, 50000000); /* Non maskable Interrupt after 1/2 second */
}

Some files were not shown because too many files have changed in this diff Show more