Import original LazyUSF into code base, for debugging and comparison.

CQTexperiment
Christopher Snowhill 2018-07-11 19:01:38 -07:00
parent 31d47715d1
commit b1e67366d0
316 changed files with 17615 additions and 915 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,89 @@
#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

@ -0,0 +1,12 @@
#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

@ -0,0 +1,271 @@
#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

@ -0,0 +1,60 @@
#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

@ -0,0 +1,63 @@
/* 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

@ -0,0 +1,604 @@
/*
* 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

@ -0,0 +1,95 @@
/*
* 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

@ -0,0 +1,161 @@
#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

@ -0,0 +1,27 @@
#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

@ -0,0 +1,180 @@
/*
* 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;
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

@ -0,0 +1,34 @@
/*
* 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

@ -0,0 +1,158 @@
/*
* 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

@ -0,0 +1,75 @@
/*
* 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

@ -0,0 +1,799 @@
/*
* 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

@ -0,0 +1,37 @@
/*
* 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

@ -0,0 +1,206 @@
/*
* 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

@ -0,0 +1,37 @@
#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

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

View File

@ -0,0 +1,839 @@
/*
* 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

@ -0,0 +1,64 @@
/*
* 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);

View File

@ -0,0 +1,274 @@
/*
* 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

@ -0,0 +1,285 @@
#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

@ -0,0 +1,89 @@
#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

@ -0,0 +1,99 @@
/*
* 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

@ -0,0 +1,29 @@
/*
* 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,145 @@
/*
* 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.
*
*/
// #ifdef EXT_REGS
#include "usf.h"
#include "main.h"
#include "cpu.h"
#include "types.h"
#include "usf_internal.h"
void SetupRegisters(usf_state_t * state, N64_REGISTERS * n64_Registers) {
state->PROGRAM_COUNTER = n64_Registers->PROGRAM_COUNTER;
state->HI.DW = n64_Registers->HI.DW;
state->LO.DW = n64_Registers->LO.DW;
state->CP0 = n64_Registers->CP0;
state->GPR = n64_Registers->GPR;
state->FPR = n64_Registers->FPR;
state->FPCR = n64_Registers->FPCR;
state->RegRDRAM = n64_Registers->RDRAM;
state->RegSP = n64_Registers->SP;
state->RegDPC = n64_Registers->DPC;
state->RegMI = n64_Registers->MI;
state->RegVI = n64_Registers->VI;
state->RegAI = n64_Registers->AI;
state->RegPI = n64_Registers->PI;
state->RegRI = n64_Registers->RI;
state->RegSI = n64_Registers->SI;
state->PIF_Ram = (uint8_t *) n64_Registers->PIF_Ram;
}
void ChangeMiIntrMask (usf_state_t * state) {
if ( ( state->RegModValue & MI_INTR_MASK_CLR_SP ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_SP; }
if ( ( state->RegModValue & MI_INTR_MASK_SET_SP ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_SP; }
if ( ( state->RegModValue & MI_INTR_MASK_CLR_SI ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_SI; }
if ( ( state->RegModValue & MI_INTR_MASK_SET_SI ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_SI; }
if ( ( state->RegModValue & MI_INTR_MASK_CLR_AI ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_AI; }
if ( ( state->RegModValue & MI_INTR_MASK_SET_AI ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_AI; }
if ( ( state->RegModValue & MI_INTR_MASK_CLR_VI ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_VI; }
if ( ( state->RegModValue & MI_INTR_MASK_SET_VI ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_VI; }
if ( ( state->RegModValue & MI_INTR_MASK_CLR_PI ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_PI; }
if ( ( state->RegModValue & MI_INTR_MASK_SET_PI ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_PI; }
if ( ( state->RegModValue & MI_INTR_MASK_CLR_DP ) != 0 ) { MI_INTR_MASK_REG &= ~MI_INTR_MASK_DP; }
if ( ( state->RegModValue & MI_INTR_MASK_SET_DP ) != 0 ) { MI_INTR_MASK_REG |= MI_INTR_MASK_DP; }
}
void ChangeMiModeReg (usf_state_t * state) {
MI_MODE_REG &= ~0x7F;
MI_MODE_REG |= (state->RegModValue & 0x7F);
if ( ( state->RegModValue & MI_CLR_INIT ) != 0 ) { MI_MODE_REG &= ~MI_MODE_INIT; }
if ( ( state->RegModValue & MI_SET_INIT ) != 0 ) { MI_MODE_REG |= MI_MODE_INIT; }
if ( ( state->RegModValue & MI_CLR_EBUS ) != 0 ) { MI_MODE_REG &= ~MI_MODE_EBUS; }
if ( ( state->RegModValue & MI_SET_EBUS ) != 0 ) { MI_MODE_REG |= MI_MODE_EBUS; }
if ( ( state->RegModValue & MI_CLR_DP_INTR ) != 0 ) { MI_INTR_REG &= ~MI_INTR_DP; }
if ( ( state->RegModValue & MI_CLR_RDRAM ) != 0 ) { MI_MODE_REG &= ~MI_MODE_RDRAM; }
if ( ( state->RegModValue & MI_SET_RDRAM ) != 0 ) { MI_MODE_REG |= MI_MODE_RDRAM; }
}
void ChangeSpStatus (usf_state_t * state) {
if ( ( state->RegModValue & SP_CLR_HALT ) != 0) { SP_STATUS_REG &= ~SP_STATUS_HALT; }
if ( ( state->RegModValue & SP_SET_HALT ) != 0) { SP_STATUS_REG |= SP_STATUS_HALT; }
if ( ( state->RegModValue & SP_CLR_BROKE ) != 0) { SP_STATUS_REG &= ~SP_STATUS_BROKE; }
if ( ( state->RegModValue & SP_CLR_INTR ) != 0) {
MI_INTR_REG &= ~MI_INTR_SP;
CheckInterrupts(state);
}
if ( ( state->RegModValue & SP_CLR_SSTEP ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SSTEP; }
if ( ( state->RegModValue & SP_SET_SSTEP ) != 0) { SP_STATUS_REG |= SP_STATUS_SSTEP; }
if ( ( state->RegModValue & SP_CLR_INTR_BREAK ) != 0) { SP_STATUS_REG &= ~SP_STATUS_INTR_BREAK; }
if ( ( state->RegModValue & SP_SET_INTR_BREAK ) != 0) { SP_STATUS_REG |= SP_STATUS_INTR_BREAK; }
if ( ( state->RegModValue & SP_CLR_SIG0 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG0; }
if ( ( state->RegModValue & SP_SET_SIG0 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG0; }
if ( ( state->RegModValue & SP_CLR_SIG1 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG1; }
if ( ( state->RegModValue & SP_SET_SIG1 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG1; }
if ( ( state->RegModValue & SP_CLR_SIG2 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG2; }
if ( ( state->RegModValue & SP_SET_SIG2 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG2; }
if ( ( state->RegModValue & SP_CLR_SIG3 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG3; }
if ( ( state->RegModValue & SP_SET_SIG3 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG3; }
if ( ( state->RegModValue & SP_CLR_SIG4 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG4; }
if ( ( state->RegModValue & SP_SET_SIG4 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG4; }
if ( ( state->RegModValue & SP_CLR_SIG5 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG5; }
if ( ( state->RegModValue & SP_SET_SIG5 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG5; }
if ( ( state->RegModValue & SP_CLR_SIG6 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG6; }
if ( ( state->RegModValue & SP_SET_SIG6 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG6; }
if ( ( state->RegModValue & SP_CLR_SIG7 ) != 0) { SP_STATUS_REG &= ~SP_STATUS_SIG7; }
if ( ( state->RegModValue & SP_SET_SIG7 ) != 0) { SP_STATUS_REG |= SP_STATUS_SIG7; }
RunRsp(state);
}
void UpdateCurrentHalfLine (usf_state_t * state) {
if (state->Timers->Timer < 0) {
state->HalfLine = 0;
return;
}
state->HalfLine = (state->Timers->Timer / 1500);
state->HalfLine &= ~1;
state->HalfLine += state->ViFieldNumber;
}
void SetFpuLocations (usf_state_t * state) {
int count;
if ((STATUS_REGISTER & STATUS_FR) == 0) {
for (count = 0; count < 32; count ++) {
state->FPRFloatLocation[count] = (void *)(&state->FPR[count >> 1].W[count & 1]);
//state->FPRDoubleLocation[count] = state->FPRFloatLocation[count];
state->FPRDoubleLocation[count] = (void *)(&state->FPR[count >> 1].DW);
}
} else {
for (count = 0; count < 32; count ++) {
state->FPRFloatLocation[count] = (void *)(&state->FPR[count].W[1]);
//state->FPRFloatLocation[count] = (void *)(&state->FPR[count].W[1]);
//state->FPRDoubleLocation[count] = state->FPRFloatLocation[count];
state->FPRDoubleLocation[count] = (void *)(&state->FPR[count].DW);
}
}
}

View File

@ -0,0 +1,378 @@
/*
* 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 REGISTERS_H
#define REGISTERS_H
#include "types.h"
#define INDEX_REGISTER state->CP0[0]
#define RANDOM_REGISTER state->CP0[1]
#define ENTRYLO0_REGISTER state->CP0[2]
#define ENTRYLO1_REGISTER state->CP0[3]
#define CONTEXT_REGISTER state->CP0[4]
#define PAGE_MASK_REGISTER state->CP0[5]
#define WIRED_REGISTER state->CP0[6]
#define BAD_VADDR_REGISTER state->CP0[8]
#define COUNT_REGISTER state->CP0[9]
#define ENTRYHI_REGISTER state->CP0[10]
#define COMPARE_REGISTER state->CP0[11]
#define STATUS_REGISTER state->CP0[12]
#define CAUSE_REGISTER state->CP0[13]
#define EPC_REGISTER state->CP0[14]
#define CONFIG_REGISTER state->CP0[16]
#define TAGLO_REGISTER state->CP0[28]
#define TAGHI_REGISTER state->CP0[29]
#define ERROREPC_REGISTER state->CP0[30]
#define FAKE_CAUSE_REGISTER state->CP0[32]
#define COMPARE_REGISTER_NO 11
#define STATUS_REGISTER_NO 12
#define CAUSE_REGISTER_NO 13
#define REVISION_REGISTER state->FPCR[0]
#define FSTATUS_REGISTER state->FPCR[31]
#define GPR_S0 state->GPR[16]
#define GPR_S1 state->GPR[17]
#define GPR_S2 state->GPR[18]
#define GPR_S3 state->GPR[19]
#define GPR_S4 state->GPR[20]
#define GPR_S5 state->GPR[21]
#define GPR_S6 state->GPR[22]
#define GPR_S7 state->GPR[23]
#define GPR_SP state->GPR[29]
#define GPR_RA state->GPR[31]
#define RDRAM_CONFIG_REG state->RegRDRAM[0]
#define RDRAM_DEVICE_TYPE_REG state->RegRDRAM[0]
#define RDRAM_DEVICE_ID_REG state->RegRDRAM[1]
#define RDRAM_DELAY_REG state->RegRDRAM[2]
#define RDRAM_MODE_REG state->RegRDRAM[3]
#define RDRAM_REF_INTERVAL_REG state->RegRDRAM[4]
#define RDRAM_REF_ROW_REG state->RegRDRAM[5]
#define RDRAM_RAS_INTERVAL_REG state->RegRDRAM[6]
#define RDRAM_MIN_INTERVAL_REG state->RegRDRAM[7]
#define RDRAM_ADDR_SELECT_REG state->RegRDRAM[8]
#define RDRAM_DEVICE_MANUF_REG state->RegRDRAM[9]
#define SP_MEM_ADDR_REG state->RegSP[0]
#define SP_DRAM_ADDR_REG state->RegSP[1]
#define SP_RD_LEN_REG state->RegSP[2]
#define SP_WR_LEN_REG state->RegSP[3]
#define SP_STATUS_REG state->RegSP[4]
#define SP_DMA_FULL_REG state->RegSP[5]
#define SP_DMA_BUSY_REG state->RegSP[6]
#define SP_SEMAPHORE_REG state->RegSP[7]
#define SP_PC_REG state->RegSP[8]
#define SP_IBIST_REG state->RegSP[9]
#define DPC_START_REG state->RegDPC[0]
#define DPC_END_REG state->RegDPC[1]
#define DPC_CURRENT_REG state->RegDPC[2]
#define DPC_STATUS_REG state->RegDPC[3]
#define DPC_CLOCK_REG state->RegDPC[4]
#define DPC_BUFBUSY_REG state->RegDPC[5]
#define DPC_PIPEBUSY_REG state->RegDPC[6]
#define DPC_TMEM_REG state->RegDPC[7]
#define MI_INIT_MODE_REG state->RegMI[0]
#define MI_MODE_REG state->RegMI[0]
#define MI_VERSION_REG state->RegMI[1]
#define MI_NOOP_REG state->RegMI[1]
#define MI_INTR_REG state->RegMI[2]
#define MI_INTR_MASK_REG state->RegMI[3]
#define VI_STATUS_REG state->RegVI[0]
#define VI_CONTROL_REG state->RegVI[0]
#define VI_ORIGIN_REG state->RegVI[1]
#define VI_DRAM_ADDR_REG state->RegVI[1]
#define VI_WIDTH_REG state->RegVI[2]
#define VI_H_WIDTH_REG state->RegVI[2]
#define VI_INTR_REG state->RegVI[3]
#define VI_V_INTR_REG state->RegVI[3]
#define VI_CURRENT_REG state->RegVI[4]
#define VI_V_CURRENT_LINE_REG state->RegVI[4]
#define VI_BURST_REG state->RegVI[5]
#define VI_TIMING_REG state->RegVI[5]
#define VI_V_SYNC_REG state->RegVI[6]
#define VI_H_SYNC_REG state->RegVI[7]
#define VI_LEAP_REG state->RegVI[8]
#define VI_H_SYNC_LEAP_REG state->RegVI[8]
#define VI_H_START_REG state->RegVI[9]
#define VI_H_VIDEO_REG state->RegVI[9]
#define VI_V_START_REG state->RegVI[10]
#define VI_V_VIDEO_REG state->RegVI[10]
#define VI_V_BURST_REG state->RegVI[11]
#define VI_X_SCALE_REG state->RegVI[12]
#define VI_Y_SCALE_REG state->RegVI[13]
#define AI_DRAM_ADDR_REG state->RegAI[0]
#define AI_LEN_REG state->RegAI[1]
#define AI_CONTROL_REG state->RegAI[2]
#define AI_STATUS_REG state->RegAI[3]
#define AI_DACRATE_REG state->RegAI[4]
#define AI_BITRATE_REG state->RegAI[5]
#define PI_DRAM_ADDR_REG state->RegPI[0]
#define PI_CART_ADDR_REG state->RegPI[1]
#define PI_RD_LEN_REG state->RegPI[2]
#define PI_WR_LEN_REG state->RegPI[3]
#define PI_STATUS_REG state->RegPI[4]
#define PI_BSD_DOM1_LAT_REG state->RegPI[5]
#define PI_DOMAIN1_REG state->RegPI[5]
#define PI_BSD_DOM1_PWD_REG state->RegPI[6]
#define PI_BSD_DOM1_PGS_REG state->RegPI[7]
#define PI_BSD_DOM1_RLS_REG state->RegPI[8]
#define PI_BSD_DOM2_LAT_REG state->RegPI[9]
#define PI_DOMAIN2_REG state->RegPI[9]
#define PI_BSD_DOM2_PWD_REG state->RegPI[10]
#define PI_BSD_DOM2_PGS_REG state->RegPI[11]
#define PI_BSD_DOM2_RLS_REG state->RegPI[12]
#define RI_MODE_REG state->RegRI[0]
#define RI_CONFIG_REG state->RegRI[1]
#define RI_CURRENT_LOAD_REG state->RegRI[2]
#define RI_SELECT_REG state->RegRI[3]
#define RI_COUNT_REG state->RegRI[4]
#define RI_REFRESH_REG state->RegRI[4]
#define RI_LATENCY_REG state->RegRI[5]
#define RI_RERROR_REG state->RegRI[6]
#define RI_WERROR_REG state->RegRI[7]
#define SI_DRAM_ADDR_REG state->RegSI[0]
#define SI_PIF_ADDR_RD64B_REG state->RegSI[1]
#define SI_PIF_ADDR_WR64B_REG state->RegSI[2]
#define SI_STATUS_REG state->RegSI[3]
#define STATUS_IE 0x00000001
#define STATUS_EXL 0x00000002
#define STATUS_ERL 0x00000004
#define STATUS_IP0 0x00000100
#define STATUS_IP1 0x00000200
#define STATUS_IP2 0x00000400
#define STATUS_IP3 0x00000800
#define STATUS_IP4 0x00001000
#define STATUS_IP5 0x00002000
#define STATUS_IP6 0x00004000
#define STATUS_IP7 0x00008000
#define STATUS_BEV 0x00400000
#define STATUS_FR 0x04000000
#define STATUS_CU0 0x10000000
#define STATUS_CU1 0x20000000
#define CAUSE_EXC_CODE 0xFF
#define CAUSE_IP0 0x100
#define CAUSE_IP1 0x200
#define CAUSE_IP2 0x400
#define CAUSE_IP3 0x800
#define CAUSE_IP4 0x1000
#define CAUSE_IP5 0x2000
#define CAUSE_IP6 0x4000
#define CAUSE_IP7 0x8000
#define CAUSE_BD 0x80000000
#define SP_CLR_HALT 0x00001 /* Bit 0: clear halt */
#define SP_SET_HALT 0x00002 /* Bit 1: set halt */
#define SP_CLR_BROKE 0x00004 /* Bit 2: clear broke */
#define SP_CLR_INTR 0x00008 /* Bit 3: clear intr */
#define SP_SET_INTR 0x00010 /* Bit 4: set intr */
#define SP_CLR_SSTEP 0x00020 /* Bit 5: clear sstep */
#define SP_SET_SSTEP 0x00040 /* Bit 6: set sstep */
#define SP_CLR_INTR_BREAK 0x00080 /* Bit 7: clear intr on break */
#define SP_SET_INTR_BREAK 0x00100 /* Bit 8: set intr on break */
#define SP_CLR_SIG0 0x00200 /* Bit 9: clear signal 0 */
#define SP_SET_SIG0 0x00400 /* Bit 10: set signal 0 */
#define SP_CLR_SIG1 0x00800 /* Bit 11: clear signal 1 */
#define SP_SET_SIG1 0x01000 /* Bit 12: set signal 1 */
#define SP_CLR_SIG2 0x02000 /* Bit 13: clear signal 2 */
#define SP_SET_SIG2 0x04000 /* Bit 14: set signal 2 */
#define SP_CLR_SIG3 0x08000 /* Bit 15: clear signal 3 */
#define SP_SET_SIG3 0x10000 /* Bit 16: set signal 3 */
#define SP_CLR_SIG4 0x20000 /* Bit 17: clear signal 4 */
#define SP_SET_SIG4 0x40000 /* Bit 18: set signal 4 */
#define SP_CLR_SIG5 0x80000 /* Bit 19: clear signal 5 */
#define SP_SET_SIG5 0x100000 /* Bit 20: set signal 5 */
#define SP_CLR_SIG6 0x200000 /* Bit 21: clear signal 6 */
#define SP_SET_SIG6 0x400000 /* Bit 22: set signal 6 */
#define SP_CLR_SIG7 0x800000 /* Bit 23: clear signal 7 */
#define SP_SET_SIG7 0x1000000 /* Bit 24: set signal 7 */
#define SP_STATUS_HALT 0x001 /* Bit 0: halt */
#define SP_STATUS_BROKE 0x002 /* Bit 1: broke */
#define SP_STATUS_DMA_BUSY 0x004 /* Bit 2: dma busy */
#define SP_STATUS_DMA_FULL 0x008 /* Bit 3: dma full */
#define SP_STATUS_IO_FULL 0x010 /* Bit 4: io full */
#define SP_STATUS_SSTEP 0x020 /* Bit 5: single step */
#define SP_STATUS_INTR_BREAK 0x040 /* Bit 6: interrupt on break */
#define SP_STATUS_SIG0 0x080 /* Bit 7: signal 0 set */
#define SP_STATUS_SIG1 0x100 /* Bit 8: signal 1 set */
#define SP_STATUS_SIG2 0x200 /* Bit 9: signal 2 set */
#define SP_STATUS_SIG3 0x400 /* Bit 10: signal 3 set */
#define SP_STATUS_SIG4 0x800 /* Bit 11: signal 4 set */
#define SP_STATUS_SIG5 0x1000 /* Bit 12: signal 5 set */
#define SP_STATUS_SIG6 0x2000 /* Bit 13: signal 6 set */
#define SP_STATUS_SIG7 0x4000 /* Bit 14: signal 7 set */
#define DPC_CLR_XBUS_DMEM_DMA 0x0001 /* Bit 0: clear xbus_dmem_dma */
#define DPC_SET_XBUS_DMEM_DMA 0x0002 /* Bit 1: set xbus_dmem_dma */
#define DPC_CLR_FREEZE 0x0004 /* Bit 2: clear freeze */
#define DPC_SET_FREEZE 0x0008 /* Bit 3: set freeze */
#define DPC_CLR_FLUSH 0x0010 /* Bit 4: clear flush */
#define DPC_SET_FLUSH 0x0020 /* Bit 5: set flush */
#define DPC_CLR_TMEM_CTR 0x0040 /* Bit 6: clear tmem ctr */
#define DPC_CLR_PIPE_CTR 0x0080 /* Bit 7: clear pipe ctr */
#define DPC_CLR_CMD_CTR 0x0100 /* Bit 8: clear cmd ctr */
#define DPC_CLR_CLOCK_CTR 0x0200 /* Bit 9: clear clock ctr */
#define DPC_STATUS_XBUS_DMEM_DMA 0x001 /* Bit 0: xbus_dmem_dma */
#define DPC_STATUS_FREEZE 0x002 /* Bit 1: freeze */
#define DPC_STATUS_FLUSH 0x004 /* Bit 2: flush */
#define DPC_STATUS_START_GCLK 0x008 /* Bit 3: start gclk */
#define DPC_STATUS_TMEM_BUSY 0x010 /* Bit 4: tmem busy */
#define DPC_STATUS_PIPE_BUSY 0x020 /* Bit 5: pipe busy */
#define DPC_STATUS_CMD_BUSY 0x040 /* Bit 6: cmd busy */
#define DPC_STATUS_CBUF_READY 0x080 /* Bit 7: cbuf ready */
#define DPC_STATUS_DMA_BUSY 0x100 /* Bit 8: dma busy */
#define DPC_STATUS_END_VALID 0x200 /* Bit 9: end valid */
#define DPC_STATUS_START_VALID 0x400 /* Bit 10: start valid */
#define MI_CLR_INIT 0x0080 /* Bit 7: clear init mode */
#define MI_SET_INIT 0x0100 /* Bit 8: set init mode */
#define MI_CLR_EBUS 0x0200 /* Bit 9: clear ebus test */
#define MI_SET_EBUS 0x0400 /* Bit 10: set ebus test mode */
#define MI_CLR_DP_INTR 0x0800 /* Bit 11: clear dp interrupt */
#define MI_CLR_RDRAM 0x1000 /* Bit 12: clear RDRAM reg */
#define MI_SET_RDRAM 0x2000 /* Bit 13: set RDRAM reg mode */
#define MI_MODE_INIT 0x0080 /* Bit 7: init mode */
#define MI_MODE_EBUS 0x0100 /* Bit 8: ebus test mode */
#define MI_MODE_RDRAM 0x0200 /* Bit 9: RDRAM reg mode */
#define MI_INTR_MASK_CLR_SP 0x0001 /* Bit 0: clear SP mask */
#define MI_INTR_MASK_SET_SP 0x0002 /* Bit 1: set SP mask */
#define MI_INTR_MASK_CLR_SI 0x0004 /* Bit 2: clear SI mask */
#define MI_INTR_MASK_SET_SI 0x0008 /* Bit 3: set SI mask */
#define MI_INTR_MASK_CLR_AI 0x0010 /* Bit 4: clear AI mask */
#define MI_INTR_MASK_SET_AI 0x0020 /* Bit 5: set AI mask */
#define MI_INTR_MASK_CLR_VI 0x0040 /* Bit 6: clear VI mask */
#define MI_INTR_MASK_SET_VI 0x0080 /* Bit 7: set VI mask */
#define MI_INTR_MASK_CLR_PI 0x0100 /* Bit 8: clear PI mask */
#define MI_INTR_MASK_SET_PI 0x0200 /* Bit 9: set PI mask */
#define MI_INTR_MASK_CLR_DP 0x0400 /* Bit 10: clear DP mask */
#define MI_INTR_MASK_SET_DP 0x0800 /* Bit 11: set DP mask */
#define MI_INTR_MASK_SP 0x01 /* Bit 0: SP intr mask */
#define MI_INTR_MASK_SI 0x02 /* Bit 1: SI intr mask */
#define MI_INTR_MASK_AI 0x04 /* Bit 2: AI intr mask */
#define MI_INTR_MASK_VI 0x08 /* Bit 3: VI intr mask */
#define MI_INTR_MASK_PI 0x10 /* Bit 4: PI intr mask */
#define MI_INTR_MASK_DP 0x20 /* Bit 5: DP intr mask */
#define MI_INTR_SP 0x01 /* Bit 0: SP intr */
#define MI_INTR_SI 0x02 /* Bit 1: SI intr */
#define MI_INTR_AI 0x04 /* Bit 2: AI intr */
#define MI_INTR_VI 0x08 /* Bit 3: VI intr */
#define MI_INTR_PI 0x10 /* Bit 4: PI intr */
#define MI_INTR_DP 0x20 /* Bit 5: DP intr */
#define PI_STATUS_DMA_BUSY 0x01
#define PI_STATUS_IO_BUSY 0x02
#define PI_STATUS_ERROR 0x04
#define PI_SET_RESET 0x01
#define PI_CLR_INTR 0x02
#define SI_STATUS_DMA_BUSY 0x0001
#define SI_STATUS_RD_BUSY 0x0002
#define SI_STATUS_DMA_ERROR 0x0008
#define SI_STATUS_INTERRUPT 0x1000
#define FPCSR_FS 0x01000000 /* flush denorm to zero */
#define FPCSR_C 0x00800000 /* condition bit */
#define FPCSR_CE 0x00020000 /* cause: unimplemented operation */
#define FPCSR_CV 0x00010000 /* cause: invalid operation */
#define FPCSR_CZ 0x00008000 /* cause: division by zero */
#define FPCSR_CO 0x00004000 /* cause: overflow */
#define FPCSR_CU 0x00002000 /* cause: underflow */
#define FPCSR_CI 0x00001000 /* cause: inexact operation */
#define FPCSR_EV 0x00000800 /* enable: invalid operation */
#define FPCSR_EZ 0x00000400 /* enable: division by zero */
#define FPCSR_EO 0x00000200 /* enable: overflow */
#define FPCSR_EU 0x00000100 /* enable: underflow */
#define FPCSR_EI 0x00000080 /* enable: inexact operation */
#define FPCSR_FV 0x00000040 /* flag: invalid operation */
#define FPCSR_FZ 0x00000020 /* flag: division by zero */
#define FPCSR_FO 0x00000010 /* flag: overflow */
#define FPCSR_FU 0x00000008 /* flag: underflow */
#define FPCSR_FI 0x00000004 /* flag: inexact operation */
#define FPCSR_RM_MASK 0x00000003 /* rounding mode mask */
#define FPCSR_RM_RN 0x00000000 /* round to nearest */
#define FPCSR_RM_RZ 0x00000001 /* round to zero */
#define FPCSR_RM_RP 0x00000002 /* round to positive infinity */
#define FPCSR_RM_RM 0x00000003 /* round to negative infinity */
#define FPR_Type(Reg) (Reg) == R4300i_COP1_S ? "S" : (Reg) == R4300i_COP1_D ? "D" :\
(Reg) == R4300i_COP1_W ? "W" : "L"
typedef struct {
uint32_t PROGRAM_COUNTER;
MIPS_DWORD GPR[32];
MIPS_DWORD FPR[32];
uint32_t CP0[33];
uint32_t FPCR[32];
MIPS_DWORD HI;
MIPS_DWORD LO;
uint32_t RDRAM[10];
uint32_t SP[10];
uint32_t DPC[10];
uint32_t MI[4];
uint32_t VI[14];
uint32_t AI[6];
uint32_t PI[13];
uint32_t RI[8];
uint32_t SI[4];
int8_t PIF_Ram[0x40];
} N64_REGISTERS;
enum FPU_Format {
FPU_Unkown,FPU_Dword, FPU_Qword, FPU_Float, FPU_Double
};
enum FPU_RoundingModel {
RoundUnknown, RoundDefault, RoundTruncate, RoundNearest, RoundDown, RoundUp
};
void ChangeMiIntrMask ( usf_state_t * );
void ChangeMiModeReg ( usf_state_t * );
void ChangeSpStatus ( usf_state_t * );
void InitalizeR4300iRegisters ( usf_state_t * );
void UpdateCurrentHalfLine ( usf_state_t * );
void SetFpuLocations ( usf_state_t * );
void SetupRegisters(usf_state_t *, N64_REGISTERS * n64_Registers);
#endif

View File

@ -0,0 +1,270 @@
#include <stdlib.h>
#include <string.h>
#define _USE_MATH_DEFINES
#include <math.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#include "resampler.h"
#include "rsp_hle/audio.h"
enum { RESAMPLER_SHIFT = 16 };
enum { RESAMPLER_RESOLUTION = 1 << RESAMPLER_SHIFT };
enum { resampler_buffer_size = 64 * 4 };
typedef struct resampler
{
int write_pos, write_filled;
int read_pos, read_filled;
int phase;
int phase_inc;
signed char delay_added;
signed char delay_removed;
short buffer_in[2][resampler_buffer_size * 2];
short buffer_out[resampler_buffer_size * 2];
} resampler;
void * resampler_create(void)
{
resampler * r = ( resampler * ) malloc( sizeof(resampler) );
if ( !r ) return 0;
r->write_pos = 1;
r->write_filled = 0;
r->read_pos = 0;
r->read_filled = 0;
r->phase = 0;
r->phase_inc = 0;
r->delay_added = -1;
r->delay_removed = -1;
memset( r->buffer_in, 0, sizeof(r->buffer_in) );
memset( r->buffer_out, 0, sizeof(r->buffer_out) );
return r;
}
void resampler_delete(void * _r)
{
free( _r );
}
void * resampler_dup(const void * _r)
{
void * r_out = malloc( sizeof(resampler) );
if ( !r_out ) return 0;
resampler_dup_inplace(r_out, _r);
return r_out;
}
void resampler_dup_inplace(void *_d, const void *_s)
{
const resampler * r_in = ( const resampler * ) _s;
resampler * r_out = ( resampler * ) _d;
r_out->write_pos = r_in->write_pos;
r_out->write_filled = r_in->write_filled;
r_out->read_pos = r_in->read_pos;
r_out->read_filled = r_in->read_filled;
r_out->phase = r_in->phase;
r_out->phase_inc = r_in->phase_inc;
r_out->delay_added = r_in->delay_added;
r_out->delay_removed = r_in->delay_removed;
memcpy( r_out->buffer_in, r_in->buffer_in, sizeof(r_in->buffer_in) );
memcpy( r_out->buffer_out, r_in->buffer_out, sizeof(r_in->buffer_out) );
}
int resampler_get_free_count(void *_r)
{
resampler * r = ( resampler * ) _r;
return resampler_buffer_size - r->write_filled;
}
static int resampler_min_filled(resampler *r)
{
return 4;
}
static int resampler_input_delay(resampler *r)
{
return 1;
}
static int resampler_output_delay(resampler *r)
{
return 0;
}
int resampler_ready(void *_r)
{
resampler * r = ( resampler * ) _r;
return r->write_filled > resampler_min_filled(r);
}
void resampler_clear(void *_r)
{
resampler * r = ( resampler * ) _r;
r->write_pos = 1;
r->write_filled = 0;
r->read_pos = 0;
r->read_filled = 0;
r->phase = 0;
r->delay_added = -1;
r->delay_removed = -1;
}
void resampler_set_rate(void *_r, double new_factor)
{
resampler * r = ( resampler * ) _r;
r->phase_inc = new_factor * RESAMPLER_RESOLUTION;
}
void resampler_write_sample(void *_r, short ls, short rs)
{
resampler * r = ( resampler * ) _r;
if ( r->delay_added < 0 )
{
r->delay_added = 0;
r->write_filled = resampler_input_delay( r );
}
if ( r->write_filled < resampler_buffer_size )
{
r->buffer_in[ 0 ][ r->write_pos ] = ls;
r->buffer_in[ 0 ][ r->write_pos + resampler_buffer_size ] = ls;
r->buffer_in[ 1 ][ r->write_pos ] = rs;
r->buffer_in[ 1 ][ r->write_pos + resampler_buffer_size ] = rs;
++r->write_filled;
r->write_pos = ( r->write_pos + 1 ) % resampler_buffer_size;
}
}
static int resampler_run_cubic(resampler * r, short ** out_, short * out_end)
{
int in_size = r->write_filled;
int in_offset = resampler_buffer_size + r->write_pos - r->write_filled;
short const* inl_ = r->buffer_in[0] + in_offset;
short const* inr_ = r->buffer_in[1] + in_offset;
int used = 0;
in_size -= 4;
if ( in_size > 0 )
{
short* out = *out_;
short const* inl = inl_;
short const* inr = inr_;
short const* const in_end = inl + in_size;
int phase = r->phase;
int phase_inc = r->phase_inc;
do
{
int samplel, sampler;
const int16_t* lut;
if ( out >= out_end )
break;
lut = RESAMPLE_LUT + ((phase & 0xfc00) >> 8);
samplel = ((inl[0] * lut[0]) + (inl[1] * lut[1])
+ (inl[2] * lut[2]) + (inl[3] * lut[3])) >> 15;
sampler = ((inr[0] * lut[0]) + (inr[1] * lut[1])
+ (inr[2] * lut[2]) + (inr[3] * lut[3])) >> 15;
if ((samplel + 0x8000) & 0xffff0000) samplel = 0x7fff ^ (samplel >> 31);
if ((sampler + 0x8000) & 0xffff0000) sampler = 0x7fff ^ (sampler >> 31);
*out++ = (short)samplel;
*out++ = (short)sampler;
phase += phase_inc;
inl += (phase >> 16);
inr += (phase >> 16);
phase &= 0xFFFF;
}
while ( inl < in_end );
r->phase = phase;
*out_ = out;
used = (int)(inl - inl_);
r->write_filled -= used;
}
return used;
}
static void resampler_fill(resampler * r)
{
int min_filled = resampler_min_filled(r);
while ( r->write_filled > min_filled &&
r->read_filled < resampler_buffer_size )
{
int write_pos = ( r->read_pos + r->read_filled ) % resampler_buffer_size;
int write_size = resampler_buffer_size - write_pos;
short * out = r->buffer_out + write_pos * 2;
if ( write_size > ( resampler_buffer_size - r->read_filled ) )
write_size = resampler_buffer_size - r->read_filled;
resampler_run_cubic( r, &out, out + write_size * 2 );
r->read_filled += ( out - r->buffer_out - write_pos * 2 ) / 2;
}
}
static void resampler_fill_and_remove_delay(resampler * r)
{
resampler_fill( r );
if ( r->delay_removed < 0 )
{
int delay = resampler_output_delay( r );
r->delay_removed = 0;
while ( delay-- )
resampler_remove_sample( r );
}
}
int resampler_get_sample_count(void *_r)
{
resampler * r = ( resampler * ) _r;
if ( r->read_filled < 1 )
resampler_fill_and_remove_delay( r );
return r->read_filled;
}
void resampler_get_sample(void *_r, short * ls, short * rs)
{
resampler * r = ( resampler * ) _r;
if ( r->read_filled < 1 && r->phase_inc )
resampler_fill_and_remove_delay( r );
if ( r->read_filled < 1 )
{
*ls = 0;
*rs = 0;
}
else
{
*ls = r->buffer_out[ r->read_pos * 2 + 0 ];
*rs = r->buffer_out[ r->read_pos * 2 + 1 ];
}
}
void resampler_remove_sample(void *_r)
{
resampler * r = ( resampler * ) _r;
if ( r->read_filled > 0 )
{
--r->read_filled;
r->read_pos = ( r->read_pos + 1 ) % resampler_buffer_size;
}
}

View File

@ -0,0 +1,40 @@
#ifndef _RESAMPLER_H_
#define _RESAMPLER_H_
#define RESAMPLER_DECORATE USF
#ifdef RESAMPLER_DECORATE
#define PASTE(a,b) a ## b
#define EVALUATE(a,b) PASTE(a,b)
#define resampler_create EVALUATE(RESAMPLER_DECORATE,_resampler_create)
#define resampler_delete EVALUATE(RESAMPLER_DECORATE,_resampler_delete)
#define resampler_dup EVALUATE(RESAMPLER_DECORATE,_resampler_dup)
#define resampler_dup_inplace EVALUATE(RESAMPLER_DECORATE,_resampler_dup_inplace)
#define resampler_set_quality EVALUATE(RESAMPLER_DECORATE,_resampler_set_quality)
#define resampler_get_free_count EVALUATE(RESAMPLER_DECORATE,_resampler_get_free_count)
#define resampler_write_sample EVALUATE(RESAMPLER_DECORATE,_resampler_write_sample)
#define resampler_write_sample_fixed EVALUATE(RESAMPLER_DECORATE,_resampler_write_sample_fixed)
#define resampler_set_rate EVALUATE(RESAMPLER_DECORATE,_resampler_set_rate)
#define resampler_ready EVALUATE(RESAMPLER_DECORATE,_resampler_ready)
#define resampler_clear EVALUATE(RESAMPLER_DECORATE,_resampler_clear)
#define resampler_get_sample_count EVALUATE(RESAMPLER_DECORATE,_resampler_get_sample_count)
#define resampler_get_sample EVALUATE(RESAMPLER_DECORATE,_resampler_get_sample)
#define resampler_get_sample_float EVALUATE(RESAMPLER_DECORATE,_resampler_get_sample_float)
#define resampler_remove_sample EVALUATE(RESAMPLER_DECORATE,_resampler_remove_sample)
#endif
void * resampler_create(void);
void resampler_delete(void *);
void * resampler_dup(const void *);
void resampler_dup_inplace(void *, const void *);
int resampler_get_free_count(void *);
void resampler_write_sample(void *, short sample_l, short sample_r);
void resampler_set_rate( void *, double new_factor );
int resampler_ready(void *);
void resampler_clear(void *);
int resampler_get_sample_count(void *);
void resampler_get_sample(void *, short * sample_l, short * sample_r);
void resampler_remove_sample(void *);
#endif

View File

@ -0,0 +1,11 @@
#ifndef RSP_H
#define RSP_H
#include "usf.h"
#include "usf_internal.h"
void real_run_rsp(usf_state_t *, uint32_t cycles);
int32_t init_rsp(usf_state_t *);
#endif

View File

@ -0,0 +1,495 @@
/******************************************************************************\
* Authors: Iconoclast *
* Release: 2013.12.11 *
* License: CC0 Public Domain Dedication *
* *
* To the extent possible under law, the author(s) have dedicated all copyright *
* and related and neighboring rights to this software to the public domain *
* worldwide. This software is distributed without any warranty. *
* *
* You should have received a copy of the CC0 Public Domain Dedication along *
* with this software. *
* If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. *
\******************************************************************************/
#include "rsp.h"
#include "su.h"
#include "vu/vu.h"
#define FIT_IMEM(PC) (PC & 0xFFF & 0xFFC)
NOINLINE void run_task(usf_state_t * state)
{
register int PC;
int wrap_count = 0;
#ifdef SP_EXECUTE_LOG
int last_PC;
#endif
if (CFG_WAIT_FOR_CPU_HOST != 0)
{
register int i;
for (i = 0; i < 32; i++)
state->MFC0_count[i] = 0;
}
PC = FIT_IMEM(SP_PC_REG);
while ((SP_STATUS_REG & 0x00000001) == 0x00000000)
{
register uint32_t inst;
inst = *(uint32_t *)(state->IMEM + FIT_IMEM(PC));
#ifdef SP_EXECUTE_LOG
last_PC = PC;
#endif
#ifdef EMULATE_STATIC_PC
PC = (PC + 0x004);
if ( FIT_IMEM(PC) == 0 && ++wrap_count == 32 )
{
message( state, "RSP execution presumably caught in an infinite loop", 3 );
break;
}
EX:
#endif
#ifdef SP_EXECUTE_LOG
step_SP_commands(state, last_PC, inst);
#endif
if (inst >> 25 == 0x25) /* is a VU instruction */
{
const int opcode = inst % 64; /* inst.R.func */
const int vd = (inst & 0x000007FF) >> 6; /* inst.R.sa */
const int vs = (unsigned short)(inst) >> 11; /* inst.R.rd */
const int vt = (inst >> 16) & 31; /* inst.R.rt */
const int e = (inst >> 21) & 0xF; /* rs & 0xF */
COP2_C2[opcode](state, vd, vs, vt, e);
}
else
{
const int op = inst >> 26;
const int rs = inst >> 21; /* &= 31 */
const int rt = (inst >> 16) & 31;
const int rd = (unsigned short)(inst) >> 11;
const int element = (inst & 0x000007FF) >> 7;
const int base = (inst >> 21) & 31;
#if (0)
state->SR[0] = 0x00000000; /* already handled on per-instruction basis */
#endif
switch (op)
{
signed int offset;
register uint32_t addr;
case 000: /* SPECIAL */
switch (inst % 64)
{
case 000: /* SLL */
state->SR[rd] = state->SR[rt] << MASK_SA(inst >> 6);
state->SR[0] = 0x00000000;
CONTINUE
case 002: /* SRL */
state->SR[rd] = (unsigned)(state->SR[rt]) >> MASK_SA(inst >> 6);
state->SR[0] = 0x00000000;
CONTINUE
case 003: /* SRA */
state->SR[rd] = (signed)(state->SR[rt]) >> MASK_SA(inst >> 6);
state->SR[0] = 0x00000000;
CONTINUE
case 004: /* SLLV */
state->SR[rd] = state->SR[rt] << MASK_SA(state->SR[rs]);
state->SR[0] = 0x00000000;
CONTINUE
case 006: /* SRLV */
state->SR[rd] = (unsigned)(state->SR[rt]) >> MASK_SA(state->SR[rs]);
state->SR[0] = 0x00000000;
CONTINUE
case 007: /* SRAV */
state->SR[rd] = (signed)(state->SR[rt]) >> MASK_SA(state->SR[rs]);
state->SR[0] = 0x00000000;
CONTINUE
case 011: /* JALR */
state->SR[rd] = (PC + LINK_OFF) & 0x00000FFC;
state->SR[0] = 0x00000000;
case 010: /* JR */
set_PC(state, state->SR[rs]);
JUMP
case 015: /* BREAK */
SP_STATUS_REG |= 0x00000003; /* BROKE | HALT */
if (SP_STATUS_REG & 0x00000040)
{ /* SP_STATUS_INTR_BREAK */
MI_INTR_REG |= 0x00000001;
CheckInterrupts(state);
}
CONTINUE
case 040: /* ADD */
case 041: /* ADDU */
state->SR[rd] = state->SR[rs] + state->SR[rt];
state->SR[0] = 0x00000000; /* needed for Rareware ucodes */
CONTINUE
case 042: /* SUB */
case 043: /* SUBU */
state->SR[rd] = state->SR[rs] - state->SR[rt];
state->SR[0] = 0x00000000;
CONTINUE
case 044: /* AND */
state->SR[rd] = state->SR[rs] & state->SR[rt];
state->SR[0] = 0x00000000; /* needed for Rareware ucodes */
CONTINUE
case 045: /* OR */
state->SR[rd] = state->SR[rs] | state->SR[rt];
state->SR[0] = 0x00000000;
CONTINUE
case 046: /* XOR */
state->SR[rd] = state->SR[rs] ^ state->SR[rt];
state->SR[0] = 0x00000000;
CONTINUE
case 047: /* NOR */
state->SR[rd] = ~(state->SR[rs] | state->SR[rt]);
state->SR[0] = 0x00000000;
CONTINUE
case 052: /* SLT */
state->SR[rd] = ((signed)(state->SR[rs]) < (signed)(state->SR[rt]));
state->SR[0] = 0x00000000;
CONTINUE
case 053: /* SLTU */
state->SR[rd] = ((unsigned)(state->SR[rs]) < (unsigned)(state->SR[rt]));
state->SR[0] = 0x00000000;
CONTINUE
default:
res_S(state);
CONTINUE
}
CONTINUE
case 001: /* REGIMM */
switch (rt)
{
case 020: /* BLTZAL */
state->SR[31] = (PC + LINK_OFF) & 0x00000FFC;
case 000: /* BLTZ */
if (!(state->SR[base] < 0))
CONTINUE
set_PC(state, PC + 4*inst + SLOT_OFF);
JUMP
case 021: /* BGEZAL */
state->SR[31] = (PC + LINK_OFF) & 0x00000FFC;
case 001: /* BGEZ */
if (!(state->SR[base] >= 0))
CONTINUE
set_PC(state, PC + 4*inst + SLOT_OFF);
JUMP
default:
res_S(state);
CONTINUE
}
CONTINUE
case 003: /* JAL */
state->SR[31] = (PC + LINK_OFF) & 0x00000FFC;
case 002: /* J */
set_PC(state, 4*inst);
JUMP
case 004: /* BEQ */
if (!(state->SR[base] == state->SR[rt]))
CONTINUE
set_PC(state, PC + 4*inst + SLOT_OFF);
JUMP
case 005: /* BNE */
if (!(state->SR[base] != state->SR[rt]))
CONTINUE
set_PC(state, PC + 4*inst + SLOT_OFF);
JUMP
case 006: /* BLEZ */
if (!((signed)state->SR[base] <= 0x00000000))
CONTINUE
set_PC(state, PC + 4*inst + SLOT_OFF);
JUMP
case 007: /* BGTZ */
if (!((signed)state->SR[base] > 0x00000000))
CONTINUE
set_PC(state, PC + 4*inst + SLOT_OFF);
JUMP
case 010: /* ADDI */
case 011: /* ADDIU */
state->SR[rt] = state->SR[base] + (signed short)(inst);
state->SR[0] = 0x00000000;
CONTINUE
case 012: /* SLTI */
state->SR[rt] = ((signed)(state->SR[base]) < (signed short)(inst));
state->SR[0] = 0x00000000;
CONTINUE
case 013: /* SLTIU */
state->SR[rt] = ((unsigned)(state->SR[base]) < (unsigned short)(inst));
state->SR[0] = 0x00000000;
CONTINUE
case 014: /* ANDI */
state->SR[rt] = state->SR[base] & (unsigned short)(inst);
state->SR[0] = 0x00000000;
CONTINUE
case 015: /* ORI */
state->SR[rt] = state->SR[base] | (unsigned short)(inst);
state->SR[0] = 0x00000000;
CONTINUE
case 016: /* XORI */
state->SR[rt] = state->SR[base] ^ (unsigned short)(inst);
state->SR[0] = 0x00000000;
CONTINUE
case 017: /* LUI */
state->SR[rt] = inst << 16;
state->SR[0] = 0x00000000;
CONTINUE
case 020: /* COP0 */
switch (base)
{
case 000: /* MFC0 */
MFC0(state, rt, rd & 0xF);
CONTINUE
case 004: /* MTC0 */
MTC0[rd & 0xF](state, rt);
CONTINUE
default:
res_S(state);
CONTINUE
}
CONTINUE
case 022: /* COP2 */
switch (base)
{
case 000: /* MFC2 */
MFC2(state, rt, rd, element);
CONTINUE
case 002: /* CFC2 */
CFC2(state, rt, rd);
CONTINUE
case 004: /* MTC2 */
MTC2(state, rt, rd, element);
CONTINUE
case 006: /* CTC2 */
CTC2(state, rt, rd);
CONTINUE
default:
res_S(state);
CONTINUE
}
CONTINUE
case 040: /* LB */
offset = (signed short)(inst);
addr = (state->SR[base] + offset) & 0x00000FFF;
state->SR[rt] = state->DMEM[BES(addr)];
state->SR[rt] = (signed char)(state->SR[rt]);
state->SR[0] = 0x00000000;
CONTINUE
case 041: /* LH */
offset = (signed short)(inst);
addr = (state->SR[base] + offset) & 0x00000FFF;
if (addr%0x004 == 0x003)
{
SR_B(rt, 2) = state->DMEM[addr - BES(0x000)];
addr = (addr + 0x00000001) & 0x00000FFF;
SR_B(rt, 3) = state->DMEM[addr + BES(0x000)];
state->SR[rt] = (signed short)(state->SR[rt]);
}
else
{
addr -= HES(0x000)*(addr%0x004 - 1);
state->SR[rt] = *(signed short *)(state->DMEM + addr);
}
state->SR[0] = 0x00000000;
CONTINUE
case 043: /* LW */
offset = (signed short)(inst);
addr = (state->SR[base] + offset) & 0x00000FFF;
if (addr%0x004 != 0x000)
ULW(state, rt, addr);
else
state->SR[rt] = *(int32_t *)(state->DMEM + addr);
state->SR[0] = 0x00000000;
CONTINUE
case 044: /* LBU */
offset = (signed short)(inst);
addr = (state->SR[base] + offset) & 0x00000FFF;
state->SR[rt] = state->DMEM[BES(addr)];
state->SR[rt] = (unsigned char)(state->SR[rt]);
state->SR[0] = 0x00000000;
CONTINUE
case 045: /* LHU */
offset = (signed short)(inst);
addr = (state->SR[base] + offset) & 0x00000FFF;
if (addr%0x004 == 0x003)
{
SR_B(rt, 2) = state->DMEM[addr - BES(0x000)];
addr = (addr + 0x00000001) & 0x00000FFF;
SR_B(rt, 3) = state->DMEM[addr + BES(0x000)];
state->SR[rt] = (unsigned short)(state->SR[rt]);
}
else
{
addr -= HES(0x000)*(addr%0x004 - 1);
state->SR[rt] = *(unsigned short *)(state->DMEM + addr);
}
state->SR[0] = 0x00000000;
CONTINUE
case 050: /* SB */
offset = (signed short)(inst);
addr = (state->SR[base] + offset) & 0x00000FFF;
state->DMEM[BES(addr)] = (unsigned char)(state->SR[rt]);
CONTINUE
case 051: /* SH */
offset = (signed short)(inst);
addr = (state->SR[base] + offset) & 0x00000FFF;
if (addr%0x004 == 0x003)
{
state->DMEM[addr - BES(0x000)] = SR_B(rt, 2);
addr = (addr + 0x00000001) & 0x00000FFF;
state->DMEM[addr + BES(0x000)] = SR_B(rt, 3);
CONTINUE
}
addr -= HES(0x000)*(addr%0x004 - 1);
*(short *)(state->DMEM + addr) = (short)(state->SR[rt]);
CONTINUE
case 053: /* SW */
offset = (signed short)(inst);
addr = (state->SR[base] + offset) & 0x00000FFF;
if (addr%0x004 != 0x000)
USW(state, rt, addr);
else
*(int32_t *)(state->DMEM + addr) = state->SR[rt];
CONTINUE
case 062: /* LWC2 */
offset = SE(inst, 6);
switch (rd)
{
case 000: /* LBV */
LBV(state, rt, element, offset, base);
CONTINUE
case 001: /* LSV */
LSV(state, rt, element, offset, base);
CONTINUE
case 002: /* LLV */
LLV(state, rt, element, offset, base);
CONTINUE
case 003: /* LDV */
LDV(state, rt, element, offset, base);
CONTINUE
case 004: /* LQV */
LQV(state, rt, element, offset, base);
CONTINUE
case 005: /* LRV */
LRV(state, rt, element, offset, base);
CONTINUE
case 006: /* LPV */
LPV(state, rt, element, offset, base);
CONTINUE
case 007: /* LUV */
LUV(state, rt, element, offset, base);
CONTINUE
case 010: /* LHV */
LHV(state, rt, element, offset, base);
CONTINUE
case 011: /* LFV */
LFV(state, rt, element, offset, base);
CONTINUE
case 013: /* LTV */
LTV(state, rt, element, offset, base);
CONTINUE
default:
res_S(state);
CONTINUE
}
CONTINUE
case 072: /* SWC2 */
offset = SE(inst, 6);
switch (rd)
{
case 000: /* SBV */
SBV(state, rt, element, offset, base);
CONTINUE
case 001: /* SSV */
SSV(state, rt, element, offset, base);
CONTINUE
case 002: /* SLV */
SLV(state, rt, element, offset, base);
CONTINUE
case 003: /* SDV */
SDV(state, rt, element, offset, base);
CONTINUE
case 004: /* SQV */
SQV(state, rt, element, offset, base);
CONTINUE
case 005: /* SRV */
SRV(state, rt, element, offset, base);
CONTINUE
case 006: /* SPV */
SPV(state, rt, element, offset, base);
CONTINUE
case 007: /* SUV */
SUV(state, rt, element, offset, base);
CONTINUE
case 010: /* SHV */
SHV(state, rt, element, offset, base);
CONTINUE
case 011: /* SFV */
SFV(state, rt, element, offset, base);
CONTINUE
case 012: /* SWV */
SWV(state, rt, element, offset, base);
CONTINUE
case 013: /* STV */
STV(state, rt, element, offset, base);
CONTINUE
default:
res_S(state);
CONTINUE
}
CONTINUE
default:
res_S(state);
CONTINUE
}
}
#ifndef EMULATE_STATIC_PC
if (state->stage == 2) /* branch phase of scheduler */
{
state->stage = 0*stage;
PC = state->temp_PC & 0x00000FFC;
SP_PC_REG = state->temp_PC;
}
else
{
state->stage = 2*state->stage; /* next IW in branch delay slot? */
PC = (PC + 0x004) & 0xFFC;
if ( FIT_IMEM(PC) == 0 && ++wrap_count == 32 )
{
message( state, "RSP execution presumably caught in an infinite loop", 3 );
break;
}
SP_PC_REG = 0x04001000 + PC;
}
continue;
#else
continue;
BRANCH:
inst = *(uint32_t *)(state->IMEM + FIT_IMEM(PC));
#ifdef SP_EXECUTE_LOG
last_PC = PC;
#endif
PC = state->temp_PC & 0x00000FFC;
goto EX;
#endif
}
SP_PC_REG = 0x04001000 | FIT_IMEM(PC);
if (SP_STATUS_REG & 0x00000002) /* normal exit, from executing BREAK */
return;
else if (MI_INTR_REG & 0x00000001) /* interrupt set by MTC0 to break */
CheckInterrupts(state);
else if (CFG_WAIT_FOR_CPU_HOST != 0) /* plugin system hack to re-sync */
{}
else if (SP_SEMAPHORE_REG != 0x00000000) /* semaphore lock fixes */
{}
else /* ??? unknown, possibly external intervention from CPU memory map */
{
message(state, "SP_SET_HALT", 3);
return;
}
SP_STATUS_REG &= ~0x00000001; /* CPU restarts with the correct SIGs. */
return;
}

View File

@ -0,0 +1,109 @@
/******************************************************************************\
* Authors: Iconoclast *
* Release: 2013.12.12 *
* License: CC0 Public Domain Dedication *
* *
* To the extent possible under law, the author(s) have dedicated all copyright *
* and related and neighboring rights to this software to the public domain *
* worldwide. This software is distributed without any warranty. *
* *
* You should have received a copy of the CC0 Public Domain Dedication along *
* with this software. *
* If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. *
\******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "../usf.h"
#include "../dma.h"
#include "../exception.h"
#include "../main.h"
#include "../memory.h"
#include "../registers.h"
#include "../usf_internal.h"
#undef JUMP
#include "config.h"
#include "rsp.h"
#include "../rsp_hle/hle.h"
void real_run_rsp(usf_state_t * state, uint32_t cycles)
{
(void)cycles;
if (SP_STATUS_REG & 0x00000003)
{
message(state, "SP_STATUS_HALT", 3);
return;
}
switch (*(unsigned int *)(state->DMEM + 0xFC0))
{ /* Simulation barrier to redirect processing externally. */
case 0x00000002: /* OSTask.type == M_AUDTASK */
if (state->enable_hle_audio == 0)
break;
hle_execute(&state->hle);
SP_STATUS_REG |= 0x00000203;
if (SP_STATUS_REG & 0x00000040) /* SP_STATUS_INTR_BREAK */
{
MI_INTR_REG |= 0x00000001; /* VR4300 SP interrupt */
CheckInterrupts(state);
}
return;
}
run_task(state);
return;
}
int32_t init_rsp(usf_state_t * state)
{
state->CR[0x0] = &SP_MEM_ADDR_REG;
state->CR[0x1] = &SP_DRAM_ADDR_REG;
state->CR[0x2] = &SP_RD_LEN_REG;
state->CR[0x3] = &SP_WR_LEN_REG;
state->CR[0x4] = &SP_STATUS_REG;
state->CR[0x5] = &SP_DMA_FULL_REG;
state->CR[0x6] = &SP_DMA_BUSY_REG;
state->CR[0x7] = &SP_SEMAPHORE_REG;
state->CR[0x8] = &DPC_START_REG;
state->CR[0x9] = &DPC_END_REG;
state->CR[0xA] = &DPC_CURRENT_REG;
state->CR[0xB] = &DPC_STATUS_REG;
state->CR[0xC] = &DPC_CLOCK_REG;
state->CR[0xD] = &DPC_BUFBUSY_REG;
state->CR[0xE] = &DPC_PIPEBUSY_REG;
state->CR[0xF] = &DPC_TMEM_REG;
hle_init(&state->hle,
state->N64MEM,
state->DMEM,
state->IMEM,
&MI_INTR_REG,
&SP_MEM_ADDR_REG,
&SP_DRAM_ADDR_REG,
&SP_RD_LEN_REG,
&SP_WR_LEN_REG,
&SP_STATUS_REG,
&SP_DMA_FULL_REG,
&SP_DMA_BUSY_REG,
&SP_PC_REG,
&SP_SEMAPHORE_REG,
&DPC_START_REG,
&DPC_END_REG,
&DPC_CURRENT_REG,
&DPC_STATUS_REG,
&DPC_CLOCK_REG,
&DPC_BUFBUSY_REG,
&DPC_PIPEBUSY_REG,
&DPC_TMEM_REG,
state);
return 0;
}

View File

@ -0,0 +1,118 @@
/******************************************************************************\
* Authors: Iconoclast *
* Release: 2013.12.12 *
* License: CC0 Public Domain Dedication *
* *
* To the extent possible under law, the author(s) have dedicated all copyright *
* and related and neighboring rights to this software to the public domain *
* worldwide. This software is distributed without any warranty. *
* *
* You should have received a copy of the CC0 Public Domain Dedication along *
* with this software. *
* If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. *
\******************************************************************************/
#ifndef _RSP_H_
#define _RSP_H_
#ifdef _MSC_VER
#define INLINE __forceinline
#define NOINLINE __declspec(noinline)
#define ALIGNED _declspec(align(16))
#else
#define INLINE inline __attribute__((always_inline))
#define NOINLINE __attribute__((noinline))
#define ALIGNED __attribute__((aligned(16)))
#endif
/*
* Streaming SIMD Extensions version import management
*/
#ifdef ARCH_MIN_SSSE3
#define ARCH_MIN_SSE2
#include <tmmintrin.h>
#endif
#ifdef ARCH_MIN_SSE2
#include <emmintrin.h>
#endif
#ifdef ARCH_MIN_ARM_NEON
#include <arm_neon.h>
#endif
typedef unsigned char byte;
#ifndef RCPREG_DEFINED
#define RCPREG_DEFINED
typedef uint32_t RCPREG;
#endif
NOINLINE static void message(usf_state_t * state, const char* body, int priority)
{
(void)body;
(void)priority;
if ( priority > 1 )
DisplayError( state, "%s", body );
}
/*
* Update RSP configuration memory from local file resource.
*/
#define CHARACTERS_PER_LINE (80)
/* typical standard DOS text file limit per line */
NOINLINE static void update_conf(const char* source)
{
(void)source;
}
#ifdef SP_EXECUTE_LOG
extern void step_SP_commands(usf_state_t * state, int PC, uint32_t inst);
#endif
#include "su.h"
#include "vu/vu.h"
/* Allocate the RSP CPU loop to its own functional space. */
NOINLINE static void run_task(usf_state_t * state);
#include "execute.h"
#ifdef SP_EXECUTE_LOG
#include "matrix.h"
void step_SP_commands(usf_state_t * state, int PC, uint32_t inst)
{
const char digits[16] = {
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
};
char text[256];
char offset[4] = "";
char code[9] = "";
char disasm[24];
unsigned char endian_swap[4];
endian_swap[00] = (unsigned char)(inst >> 24);
endian_swap[01] = (unsigned char)(inst >> 16);
endian_swap[02] = (unsigned char)(inst >> 8);
endian_swap[03] = (unsigned char)inst;
offset[00] = digits[(PC & 0xF00) >> 8];
offset[01] = digits[(PC & 0x0F0) >> 4];
offset[02] = digits[(PC & 0x00F) >> 0];
code[00] = digits[(inst & 0xF0000000) >> 28];
code[01] = digits[(inst & 0x0F000000) >> 24];
code[02] = digits[(inst & 0x00F00000) >> 20];
code[03] = digits[(inst & 0x000F0000) >> 16];
code[04] = digits[(inst & 0x0000F000) >> 12];
code[05] = digits[(inst & 0x00000F00) >> 8];
code[06] = digits[(inst & 0x000000F0) >> 4];
code[07] = digits[(inst & 0x0000000F) >> 0];
strcpy(text, "RSP:\t");
strcat(text, offset);
strcat(text, ":\t");
strcat(text, code);
strcat(text, "\t");
disassemble(disasm, inst);
strcat(text, disasm);
strcat(text, "\n");
fputs(text, stdout);
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,403 @@
/******************************************************************************\
* Authors: Iconoclast *
* Release: 2013.10.07 *
* License: CC0 Public Domain Dedication *
* *
* To the extent possible under law, the author(s) have dedicated all copyright *
* and related and neighboring rights to this software to the public domain *
* worldwide. This software is distributed without any warranty. *
* *
* You should have received a copy of the CC0 Public Domain Dedication along *
* with this software. *
* If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. *
\******************************************************************************/
#ifndef _CLAMP_H
#define _CLAMP_H
/*
* for ANSI compliance (null INLINE attribute if not already set to `inline`)
* Include "rsp.h" for active, non-ANSI inline definition.
*/
#ifndef INLINE
#define INLINE
#endif
/*
* dependency for 48-bit accumulator access
*/
#include "vu.h"
/*
* vector select merge (`VMRG`) formula
*
* This is really just a vectorizer for ternary conditional storage.
* I've named it so because it directly maps to the VMRG op-code.
* -- example --
* for (i = 0; i < N; i++)
* if (c_pass)
* dest = element_a;
* else
* dest = element_b;
*/
static INLINE void merge(short* VD, short* cmp, short* pass, short* fail)
{
register int i;
#ifdef ARCH_MIN_ARM_NEON
int16x8_t p,f,d,c,vd,temp;
p = vld1q_s16((const int16_t*)pass);
f = vld1q_s16((const int16_t*)fail);
c = vld1q_s16((const int16_t*)cmp);
d = vsubq_s16(p,f);
vd = vmlaq_s16(f, c, d); //vd = f + (cmp * d)
vst1q_s16(VD, vd);
return;
#else
#if (0)
/* Do not use this version yet, as it still does not vectorize to SSE2. */
for (i = 0; i < N; i++)
VD[i] = (cmp[i] != 0) ? pass[i] : fail[i];
#else
ALIGNED short diff[N];
for (i = 0; i < N; i++)
diff[i] = pass[i] - fail[i];
for (i = 0; i < N; i++)
VD[i] = fail[i] + cmp[i]*diff[i]; /* actually `(cmp[i] != 0)*diff[i]` */
#endif
return;
#endif
}
#ifdef ARCH_MIN_ARM_NEON
static INLINE void vector_copy(short * VD, short * VS)
{
int16x8_t xmm;
xmm = vld1q_s16((const int16_t*)VS);
vst1q_s16(VD, xmm);
return;
}
static INLINE void SIGNED_CLAMP_ADD(usf_state_t * state, short* VD, short* VS, short* VT)
{
int16x8_t dst, src, vco, max, min;
src = vld1q_s16((const int16_t*)VS);
dst = vld1q_s16((const int16_t*)VT);
vco = vld1q_s16((const int16_t*)state->co);
max = vmaxq_s16(dst, src);
min = vminq_s16(dst, src);
min = vqaddq_s16(min, vco);
max = vqaddq_s16(max, min);
vst1q_s16(VD, max);
return;
}
static INLINE void SIGNED_CLAMP_SUB(usf_state_t * state, short* VD, short* VS, short* VT)
{
int16x8_t dst, src, vco, dif, res, xmm,vd;
src = vld1q_s16((const int16_t*)VS);
vd = vld1q_s16((const int16_t*)VD);
dst = vld1q_s16((const int16_t*)VT);
vco = vld1q_s16((const int16_t*)state->co);
res = vqsubq_s16(src, dst);
dif = vaddq_s16(res, vco);
dif = veorq_s16(dif, res);
dif = vandq_s16(dif, dst);
xmm = vsubq_s16(src, dst);
src = vbicq_s16(dif, src);
xmm = vandq_s16(xmm, src);
xmm = vshrq_n_s16(xmm, 15);
xmm = vbicq_s16(vco, xmm);
res = vqsubq_s16(res, xmm);
vst1q_s16(VD, res);
return;
}
static INLINE void SIGNED_CLAMP_AM(usf_state_t * state, short* VD)
{
int16x8_t pvs, pvd;
int16x8x2_t packed;
int16x8_t result;
int16x4_t low, high;
pvs = vld1q_s16((const int16_t*)VACC_H);
pvd = vld1q_s16((const int16_t*)VACC_M);
packed = vzipq_s16(pvd,pvs);
low = vqmovn_s32((int32x4_t)packed.val[0]);
high = vqmovn_s32((int32x4_t)packed.val[1]);
result = vcombine_s16(low,high);
vst1q_s16(VD,result);
return;
}
#endif
#if !defined ARCH_MIN_SSE2 && !defined ARCH_MIN_ARM_NEON
static INLINE void vector_copy(short* VD, short* VS)
{
#if (0)
memcpy(VD, VS, N*sizeof(short));
#else
register int i;
for (i = 0; i < N; i++)
VD[i] = VS[i];
#endif
return;
}
static INLINE void SIGNED_CLAMP_ADD(usf_state_t * state, short* VD, short* VS, short* VT)
{
ALIGNED int32_t sum[N];
ALIGNED short hi[N], lo[N];
register int i;
for (i = 0; i < N; i++)
sum[i] = VS[i] + VT[i] + state->co[i];
for (i = 0; i < N; i++)
lo[i] = (sum[i] + 0x8000) >> 31;
for (i = 0; i < N; i++)
hi[i] = (0x7FFF - sum[i]) >> 31;
vector_copy(VD, VACC_L);
for (i = 0; i < N; i++)
VD[i] &= ~lo[i];
for (i = 0; i < N; i++)
VD[i] |= hi[i];
for (i = 0; i < N; i++)
VD[i] ^= 0x8000 & (hi[i] | lo[i]);
return;
}
static INLINE void SIGNED_CLAMP_SUB(usf_state_t * state, short* VD, short* VS, short* VT)
{
ALIGNED int32_t dif[N];
ALIGNED short hi[N], lo[N];
register int i;
for (i = 0; i < N; i++)
dif[i] = VS[i] - VT[i] - state->co[i];
for (i = 0; i < N; i++)
lo[i] = (dif[i] + 0x8000) >> 31;
for (i = 0; i < N; i++)
hi[i] = (0x7FFF - dif[i]) >> 31;
vector_copy(VD, VACC_L);
for (i = 0; i < N; i++)
VD[i] &= ~lo[i];
for (i = 0; i < N; i++)
VD[i] |= hi[i];
for (i = 0; i < N; i++)
VD[i] ^= 0x8000 & (hi[i] | lo[i]);
return;
}
static INLINE void SIGNED_CLAMP_AM(usf_state_t * state, short* VD)
{
ALIGNED short hi[N], lo[N];
register int i;
for (i = 0; i < N; i++)
lo[i] = (VACC_H[i] < ~0);
for (i = 0; i < N; i++)
lo[i] |= (VACC_H[i] < 0) & !(VACC_M[i] < 0);
for (i = 0; i < N; i++)
hi[i] = (VACC_H[i] > 0);
for (i = 0; i < N; i++)
hi[i] |= (VACC_H[i] == 0) & (VACC_M[i] < 0);
vector_copy(VD, VACC_M);
for (i = 0; i < N; i++)
VD[i] &= -(lo[i] ^ 1);
for (i = 0; i < N; i++)
VD[i] |= -(hi[i] ^ 0);
for (i = 0; i < N; i++)
VD[i] ^= 0x8000 * (hi[i] | lo[i]);
return;
}
#endif
#ifdef ARCH_MIN_SSE2
/*
* We actually need to write explicit SSE2 code for this because GCC 4.8.1
* (and possibly later versions) has a code generation bug with vectorizing
* the accumulator when it's a signed short (but not when it's unsigned, for
* some stupid and buggy reason).
*
* In addition, as of the more stable GCC 4.7.2 release, while vectorizing
* the accumulator write-backs into SSE2 for me is successfully done, we save
* just one extra scalar x86 instruction for every RSP vector op-code when we
* use SSE2 explicitly for this particular goal instead of letting GCC do it.
*/
static INLINE void vector_copy(short* VD, short* VS)
{
__m128i xmm;
xmm = _mm_load_si128((__m128i *)VS);
_mm_store_si128((__m128i *)VD, xmm);
return;
}
static INLINE void SIGNED_CLAMP_ADD(usf_state_t * state, short* VD, short* VS, short* VT)
{
__m128i dst, src, vco;
__m128i max, min;
src = _mm_load_si128((__m128i *)VS);
dst = _mm_load_si128((__m128i *)VT);
vco = _mm_load_si128((__m128i *)state->co);
/*
* Due to premature clamping in between adds, sometimes we need to add the
* LESSER of two integers, either VS or VT, to the carry-in flag matching the
* current vector register slice, BEFORE finally adding the greater integer.
*/
max = _mm_max_epi16(dst, src);
min = _mm_min_epi16(dst, src);
min = _mm_adds_epi16(min, vco);
max = _mm_adds_epi16(max, min);
_mm_store_si128((__m128i *)VD, max);
return;
}
static INLINE void SIGNED_CLAMP_SUB(usf_state_t * state, short* VD, short* VS, short* VT)
{
__m128i dst, src, vco;
__m128i dif, res, xmm;
src = _mm_load_si128((__m128i *)VS);
dst = _mm_load_si128((__m128i *)VT);
vco = _mm_load_si128((__m128i *)state->co);
res = _mm_subs_epi16(src, dst);
/*
* Due to premature clamps in-between subtracting two of the three operands,
* we must be careful not to offset the result accidentally when subtracting
* the corresponding VCO flag AFTER the saturation from doing (VS - VT).
*/
dif = _mm_add_epi16(res, vco);
dif = _mm_xor_si128(dif, res); /* Adding one suddenly inverts the sign? */
dif = _mm_and_si128(dif, dst); /* Sign change due to subtracting a neg. */
xmm = _mm_sub_epi16(src, dst);
src = _mm_andnot_si128(src, dif); /* VS must be >= 0x0000 for overflow. */
xmm = _mm_and_si128(xmm, src); /* VS + VT != INT16_MIN; VS + VT >= +32768 */
xmm = _mm_srli_epi16(xmm, 15); /* src = (INT16_MAX + 1 === INT16_MIN) ? */
xmm = _mm_andnot_si128(xmm, vco); /* If it's NOT overflow, keep flag. */
res = _mm_subs_epi16(res, xmm);
_mm_store_si128((__m128i *)VD, res);
return;
}
static INLINE void SIGNED_CLAMP_AM(usf_state_t * state, short* VD)
{ /* typical sign-clamp of accumulator-mid (bits 31:16) */
__m128i dst, src;
__m128i pvd, pvs;
pvs = _mm_load_si128((__m128i *)VACC_H);
pvd = _mm_load_si128((__m128i *)VACC_M);
dst = _mm_unpacklo_epi16(pvd, pvs);
src = _mm_unpackhi_epi16(pvd, pvs);
dst = _mm_packs_epi32(dst, src);
_mm_store_si128((__m128i *)VD, dst);
return;
}
#endif
static INLINE void UNSIGNED_CLAMP(usf_state_t * state, short* VD)
{ /* sign-zero hybrid clamp of accumulator-mid (bits 31:16) */
ALIGNED short cond[N];
ALIGNED short temp[N];
register int i;
#ifdef ARCH_MIN_ARM_NEON
uint16x8_t c;
int16x8_t t = vld1q_s16((const int16_t*)temp);
int16x8_t vaccm = vld1q_s16((const int16_t*)VACC_M);
SIGNED_CLAMP_AM(state, temp);
c = vcgtq_s16(t,vaccm);
int16x8_t t_ = vshrq_n_s16(t,15);
int16x8_t vd = vbicq_s16(t,t_);
vd = vorrq_s16(vd,(int16x8_t)c);
vst1q_s16(VD, vd);
return;
#else
SIGNED_CLAMP_AM(state, temp); /* no direct map in SSE, but closely based on this */
for (i = 0; i < N; i++)
cond[i] = -(temp[i] > VACC_M[i]); /* VD |= -(ACC47..16 > +32767) */
for (i = 0; i < N; i++)
VD[i] = temp[i] & ~(temp[i] >> 15); /* Only this clamp is unsigned. */
for (i = 0; i < N; i++)
VD[i] = VD[i] | cond[i];
return;
#endif
}
static INLINE void SIGNED_CLAMP_AL(usf_state_t * state, short* VD)
{ /* sign-clamp accumulator-low (bits 15:0) */
ALIGNED short cond[N];
ALIGNED short temp[N];
register int i;
#ifdef ARCH_MIN_ARM_NEON
SIGNED_CLAMP_AM(state, temp);
uint16x8_t c;
int16x8_t eightk = vdupq_n_s16(0x8000);
uint16x8_t one = vdupq_n_u16(1);
int16x8_t t = vld1q_s16((const int16_t*)temp);
int16x8_t vaccm = vld1q_s16((const int16_t*)VACC_M);
c = vceqq_s16(t,vaccm);
c = vaddq_u16(c, one);
t = veorq_s16(t, eightk);
vst1q_u16(cond,c);
vst1q_s16(temp,t);
merge(VD, cond, temp, VACC_L);
return;
#else
SIGNED_CLAMP_AM(state, temp); /* no direct map in SSE, but closely based on this */
for (i = 0; i < N; i++)
cond[i] = (temp[i] != VACC_M[i]); /* result_clamped != result_raw ? */
for (i = 0; i < N; i++)
temp[i] ^= 0x8000; /* half-assed unsigned saturation mix in the clamp */
merge(VD, cond, temp, VACC_L);
return;
#endif
}
#endif

View File

@ -0,0 +1,90 @@
/******************************************************************************\
* Authors: Iconoclast *
* Release: 2013.11.26 *
* License: CC0 Public Domain Dedication *
* *
* To the extent possible under law, the author(s) have dedicated all copyright *
* and related and neighboring rights to this software to the public domain *
* worldwide. This software is distributed without any warranty. *
* *
* You should have received a copy of the CC0 Public Domain Dedication along *
* with this software. *
* If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. *
\******************************************************************************/
#include "vu.h"
#ifdef VU_EMULATE_SCALAR_ACCUMULATOR_READ
static void VSAR(int vd, int vs, int vt, int e)
{
ALIGNED short oldval[N];
register int i;
for (i = 0; i < N; i++)
oldval[i] = VR[vs][i];
vt = 0;
/* Even though VT is ignored in VSAR, according to official sources as well
* as reversing, lots of games seem to specify it as non-zero, possibly to
* avoid register stalling or other VU hazards. Not really certain why yet.
*/
e ^= 0x8;
/* Or, for exception overrides, should this be `e &= 0x7;` ?
* Currently this code is safer because &= is less likely to catch oddities.
* Either way, documentation shows that the switch range is 0:2, not 8:A.
*/
if (e > 2)
{
message(state, "VSAR\nInvalid mask.", 2);
#if ARCH_MIN_ARM_NEON
int16x8_t zero = vdupq_n_s16(0);
vst1q_s16(VR[vd], zero);
#else
for (i = 0; i < N; i++)
VR[vd][i] = 0x0000; /* override behavior (zilmar) */
#endif
}
else
{
#if ARCH_MIN_ARM_NEON
vector_copy(VR[vd], VACC[e]);
#else
for (i = 0; i < N; i++)
VR[vd][i] = VACC[e][i];
#endif
}
for (i = 0; i < N; i++)
VACC[e][i] = oldval[i]; /* ... = VS */
return;
}
#endif
static void VSAW(usf_state_t * state, int vd, int vs, int vt, int e)
{
register int i;
vs = 0; /* unused--old VSAR algorithm */
vt = 0; /* unused but mysteriously set many times */
if (vs | vt)
return;
e ^= 0x8; /* &= 7 */
if (e > 0x2)
{ /* branch very unlikely...never seen a game do VSAW illegally */
message(state, "VSAW\nIllegal mask.", 2);
#if ARCH_MIN_ARM_NEON
int16x8_t zero = vdupq_n_s16(0);
vst1q_s16(state->VR[vd], zero);
#else
for (i = 0; i < N; i++)
state->VR[vd][i] = 0x0000; /* override behavior (zilmar) */
return;
#endif
}
vector_copy(state->VR[vd], state->VACC[e]);
return;
}

View File

@ -0,0 +1,46 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - stdbool.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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* This header is only intended to be used with msvc compilers */
#pragma once
#if defined(_MSC_VER) && _MSC_VER < 1700
typedef int _Bool;
/**
* The standard states that "an application may undefine and then possibly redefine the macro
* bool, true and false". However, such feature might be withdrawn in a future version.
**/
#define bool _Bool
#define true 1
#define false 0
#define __bool_true_false_are_defined 1
#else
#include <stdbool.h>
#endif

View File

@ -0,0 +1,195 @@
/*
* 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_internal.h"
void SetupTLB_Entry (usf_state_t * state, int32_t Entry);
uint32_t AddressDefined ( usf_state_t * state, uintptr_t VAddr) {
uint32_t i;
if (VAddr >= 0x80000000 && VAddr <= 0xBFFFFFFF) {
return 1;
}
for (i = 0; i < 64; i++) {
if (state->FastTlb[i].ValidEntry == 0) { continue; }
if (VAddr >= state->FastTlb[i].VSTART && VAddr <= state->FastTlb[i].VEND) {
return 1;
}
}
return 0;
}
void InitilizeTLB (usf_state_t * state) {
uint32_t count;
for (count = 0; count < 32; count++) { state->tlb[count].EntryDefined = 0; }
for (count = 0; count < 64; count++) { state->FastTlb[count].ValidEntry = 0; }
SetupTLB(state);
}
void SetupTLB (usf_state_t * state) {
uint32_t count;
memset(state->TLB_Map,0,(0xFFFFF * sizeof(uintptr_t)));
for (count = 0x80000000; count < 0xC0000000; count += 0x1000) {
state->TLB_Map[count >> 12] = ((uintptr_t)state->N64MEM + (count & 0x1FFFFFFF)) - count;
}
for (count = 0; count < 32; count ++) { SetupTLB_Entry(state, count); }
}
/*
test=(BYTE *) VirtualAlloc( 0x10, 0x70000, MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if(test == 0) {
//printf("FAIL!\n");
exit(0);
}
*/
void SetupTLB_Entry (usf_state_t * state, int Entry) {
int32_t FastIndx;
if (!state->tlb[Entry].EntryDefined) { return; }
FastIndx = Entry << 1;
state->FastTlb[FastIndx].VSTART=state->tlb[Entry].EntryHi.b.VPN2 << 13;
state->FastTlb[FastIndx].VEND = state->FastTlb[FastIndx].VSTART + (state->tlb[Entry].PageMask.b.Mask << 12) + 0xFFF;
state->FastTlb[FastIndx].PHYSSTART = state->tlb[Entry].EntryLo0.b.PFN << 12;
state->FastTlb[FastIndx].VALID = state->tlb[Entry].EntryLo0.b.V;
state->FastTlb[FastIndx].DIRTY = state->tlb[Entry].EntryLo0.b.D;
state->FastTlb[FastIndx].GLOBAL = state->tlb[Entry].EntryLo0.b.GLOBAL & state->tlb[Entry].EntryLo1.b.GLOBAL;
state->FastTlb[FastIndx].ValidEntry = 0;
FastIndx = (Entry << 1) + 1;
state->FastTlb[FastIndx].VSTART=(state->tlb[Entry].EntryHi.b.VPN2 << 13) + ((state->tlb[Entry].PageMask.b.Mask << 12) + 0xFFF + 1);
state->FastTlb[FastIndx].VEND = state->FastTlb[FastIndx].VSTART + (state->tlb[Entry].PageMask.b.Mask << 12) + 0xFFF;
state->FastTlb[FastIndx].PHYSSTART = state->tlb[Entry].EntryLo1.b.PFN << 12;
state->FastTlb[FastIndx].VALID = state->tlb[Entry].EntryLo1.b.V;
state->FastTlb[FastIndx].DIRTY = state->tlb[Entry].EntryLo1.b.D;
state->FastTlb[FastIndx].GLOBAL = state->tlb[Entry].EntryLo0.b.GLOBAL & state->tlb[Entry].EntryLo1.b.GLOBAL;
state->FastTlb[FastIndx].ValidEntry = 0;
for ( FastIndx = Entry << 1; FastIndx <= (Entry << 1) + 1; FastIndx++) {
uint32_t count;
if (!state->FastTlb[FastIndx].VALID) {
state->FastTlb[FastIndx].ValidEntry = 1;
continue;
}
if (state->FastTlb[FastIndx].VEND <= state->FastTlb[FastIndx].VSTART) {
continue;
}
if (state->FastTlb[FastIndx].VSTART >= 0x80000000 && state->FastTlb[FastIndx].VEND <= 0xBFFFFFFF) {
continue;
}
if (state->FastTlb[FastIndx].PHYSSTART > 0x1FFFFFFF) {
continue;
}
//test if overlap
state->FastTlb[FastIndx].ValidEntry = 1;
for (count = state->FastTlb[FastIndx].VSTART; count < state->FastTlb[FastIndx].VEND; count += 0x1000) {
state->TLB_Map[count >> 12] = ((uintptr_t)state->N64MEM + (count - state->FastTlb[FastIndx].VSTART + state->FastTlb[FastIndx].PHYSSTART)) - count;
}
}
}
void TLB_Probe (usf_state_t * state) {
uint32_t Counter;
INDEX_REGISTER |= 0x80000000;
for (Counter = 0; Counter < 32; Counter ++) {
uint32_t TlbValue = state->tlb[Counter].EntryHi.Value & (~state->tlb[Counter].PageMask.b.Mask << 13);
uint32_t EntryHi = ENTRYHI_REGISTER & (~state->tlb[Counter].PageMask.b.Mask << 13);
if (TlbValue == EntryHi) {
uint32_t Global = (state->tlb[Counter].EntryHi.Value & 0x100) != 0;
uint32_t SameAsid = ((state->tlb[Counter].EntryHi.Value & 0xFF) == (ENTRYHI_REGISTER & 0xFF));
if (Global || SameAsid) {
INDEX_REGISTER = Counter;
return;
}
}
}
}
void TLB_Read (usf_state_t * state) {
uint32_t index = INDEX_REGISTER & 0x1F;
PAGE_MASK_REGISTER = state->tlb[index].PageMask.Value ;
ENTRYHI_REGISTER = (state->tlb[index].EntryHi.Value & ~state->tlb[index].PageMask.Value) ;
ENTRYLO0_REGISTER = state->tlb[index].EntryLo0.Value;
ENTRYLO1_REGISTER = state->tlb[index].EntryLo1.Value;
}
uint32_t TranslateVaddr ( usf_state_t * state, uintptr_t * Addr) {
if (state->TLB_Map[((*Addr) & 0xffffffff) >> 12] == 0) { return 0; }
*Addr = (uintptr_t)((uint8_t *)(state->TLB_Map[((*Addr) & 0xffffffff) >> 12] + ((*Addr) & 0xffffffff)) - (uintptr_t)state->N64MEM);
return 1;
}
void WriteTLBEntry (usf_state_t * state, int32_t index) {
int32_t FastIndx;
FastIndx = index << 1;
if ((state->PROGRAM_COUNTER >= state->FastTlb[FastIndx].VSTART &&
state->PROGRAM_COUNTER < state->FastTlb[FastIndx].VEND &&
state->FastTlb[FastIndx].ValidEntry && state->FastTlb[FastIndx].VALID)
||
(state->PROGRAM_COUNTER >= state->FastTlb[FastIndx + 1].VSTART &&
state->PROGRAM_COUNTER < state->FastTlb[FastIndx + 1].VEND &&
state->FastTlb[FastIndx + 1].ValidEntry && state->FastTlb[FastIndx + 1].VALID))
{
return;
}
if (state->tlb[index].EntryDefined) {
uint32_t count;
for ( FastIndx = index << 1; FastIndx <= (index << 1) + 1; FastIndx++) {
if (!state->FastTlb[FastIndx].ValidEntry) { continue; }
if (!state->FastTlb[FastIndx].VALID) { continue; }
for (count = state->FastTlb[FastIndx].VSTART; count < state->FastTlb[FastIndx].VEND; count += 0x1000) {
state->TLB_Map[count >> 12] = 0;
}
}
}
state->tlb[index].PageMask.Value = PAGE_MASK_REGISTER;
state->tlb[index].EntryHi.Value = ENTRYHI_REGISTER;
state->tlb[index].EntryLo0.Value = ENTRYLO0_REGISTER;
state->tlb[index].EntryLo1.Value = ENTRYLO1_REGISTER;
state->tlb[index].EntryDefined = 1;
SetupTLB_Entry(state, index);
}

View File

@ -0,0 +1,105 @@
/*
* 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 _TLB_H_
#define _TLB_H_
typedef struct {
uint32_t EntryDefined;
union {
uint32_t Value;
uint8_t A[4];
struct {
unsigned zero : 13;
unsigned Mask : 12;
unsigned zero2 : 7;
} b;
} PageMask;
union {
uint32_t Value;
uint8_t A[4];
struct {
unsigned ASID : 8;
unsigned Zero : 4;
unsigned G : 1;
unsigned VPN2 : 19;
} b;
} EntryHi;
union {
uint32_t Value;
uint8_t A[4];
struct {
unsigned GLOBAL: 1;
unsigned V : 1;
unsigned D : 1;
unsigned C : 3;
unsigned PFN : 20;
unsigned ZERO: 6;
} b;
} EntryLo0;
union {
uint32_t Value;
uint8_t A[4];
struct {
unsigned GLOBAL: 1;
unsigned V : 1;
unsigned D : 1;
unsigned C : 3;
unsigned PFN : 20;
unsigned ZERO: 6;
} b;
} EntryLo1;
} TLB;
typedef struct {
uint32_t VSTART;
uint32_t VEND;
uint32_t PHYSSTART;
uint32_t VALID;
uint32_t DIRTY;
uint32_t GLOBAL;
uint32_t ValidEntry;
} FASTTLB;
uint32_t AddressDefined ( usf_state_t *, uintptr_t VAddr);
void InitilizeTLB ( usf_state_t * );
void SetupTLB ( usf_state_t * );
void TLB_Probe ( usf_state_t * );
void TLB_Read ( usf_state_t * );
uint32_t TranslateVaddr ( usf_state_t *, uintptr_t * Addr);
void WriteTLBEntry ( usf_state_t *, int32_t index );
#endif

View File

@ -0,0 +1,72 @@
/*
* 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 __Types_h
#define __Types_h
#include <stdint.h>
typedef uint64_t QWORD;
typedef union tagVect {
double FD[2];
int64_t DW[2];
uint64_t UDW[2];
int32_t W[4];
float FS[4];
uint32_t UW[4];
int16_t HW[8];
uint16_t UHW[8];
int8_t B[16];
uint8_t UB[16];
} VECTOR;
typedef union tagUWORD {
int32_t W;
uint32_t UW;
int16_t HW[2];
uint16_t UHW[2];
int8_t B[4];
uint8_t UB[4];
float F;
} MIPS_WORD;
typedef union tagUDWORD {
double D;
int64_t DW;
uint64_t UDW;
int32_t W[2];
uint32_t UW[2];
int16_t HW[4];
uint16_t UHW[4];
int8_t B[8];
uint8_t UB[8];
float F[2];
} MIPS_DWORD;
typedef MIPS_WORD MIPSUWORD;
typedef MIPS_DWORD MIPSUDWORD;
#endif

View File

@ -0,0 +1,339 @@
#include <stdint.h>
#include <string.h>
#include "usf.h"
#include "cpu.h"
#include "memory.h"
#include "audio.h"
#include <stdio.h>
#include <stdlib.h>
#include "types.h"
#include "resampler.h"
#include "usf_internal.h"
size_t usf_get_state_size()
{
return sizeof(usf_state_t) + 8192;
}
void usf_clear(void * state)
{
size_t offset;
memset(state, 0, usf_get_state_size());
offset = 4096 - (((uintptr_t)state) & 4095);
USF_STATE_HELPER->offset_to_structure = offset;
//USF_STATE->savestatespace = NULL;
//USF_STATE->cpu_running = 0;
USF_STATE->cpu_stopped = 1;
//USF_STATE->enablecompare = 0;
//USF_STATE->enableFIFOfull = 0;
//USF_STATE->enable_hle_audio = 0;
//USF_STATE->NextInstruction = 0;
//USF_STATE->JumpToLocation = 0;
//USF_STATE->AudioIntrReg = 0;
//USF_STATE->CPU_Action = 0;
//USF_STATE->Timers = 0;
//USF_STATE->CPURunning = 0;
//USF_STATE->SPHack = 0;
//USF_STATE->WaitMode = 0;
//USF_STATE->TLB_Map = 0;
//USF_STATE->MemChunk = 0;
USF_STATE->RdramSize = 0x800000;
USF_STATE->SystemRdramSize = 0x800000;
USF_STATE->RomFileSize = 0x4000000;
//USF_STATE->N64MEM = 0;
//USF_STATE->RDRAM = 0;
//USF_STATE->DMEM = 0;
//USF_STATE->IMEM = 0;
//memset(USF_STATE->ROMPages, 0, sizeof(USF_STATE->ROMPages));
//USF_STATE->savestatespace = 0;
//USF_STATE->NOMEM = 0;
//USF_STATE->WrittenToRom = 0;
//USF_STATE->WroteToRom = 0;
//USF_STATE->TempValue = 0;
//USF_STATE->MemoryState = 0;
//USF_STATE->EmptySpace = 0;
//USF_STATE->Registers = 0;
//USF_STATE->PIF_Ram = 0;
PreAllocate_Memory(USF_STATE);
USF_STATE->resampler = resampler_create();
#ifdef DEBUG_INFO
USF_STATE->debug_log = fopen("/tmp/lazyusf.log", "w");
#endif
}
void usf_set_compare(void * state, int enable)
{
USF_STATE->enablecompare = enable;
}
void usf_set_fifo_full(void * state, int enable)
{
USF_STATE->enableFIFOfull = enable;
}
void usf_set_hle_audio(void * state, int enable)
{
USF_STATE->enable_hle_audio = enable;
}
static uint32_t get_le32( const void * _p )
{
const uint8_t * p = (const uint8_t *) _p;
return p[0] + p[1] * 0x100 + p[2] * 0x10000 + p[3] * 0x1000000;
}
int usf_upload_section(void * state, const uint8_t * data, size_t size)
{
uint32_t temp;
if ( size < 4 ) return -1;
temp = get_le32( data ); data += 4; size -= 4;
if(temp == 0x34365253) { //there is a rom section
uint32_t len, start;
if ( size < 4 ) return -1;
len = get_le32( data ); data += 4; size -= 4;
while(len) {
if ( size < 4 ) return -1;
start = get_le32( data ); data += 4; size -= 4;
while(len) {
uint32_t page = start >> 16;
uint32_t readLen = ( ((start + len) >> 16) > page) ? (((page + 1) << 16) - start) : len;
if( USF_STATE->ROMPages[page] == 0 ) {
USF_STATE->ROMPages[page] = malloc(0x10000);
if ( USF_STATE->ROMPages[page] == 0 )
return -1;
memset(USF_STATE->ROMPages[page], 0, 0x10000);
}
if ( size < readLen )
return -1;
memcpy( USF_STATE->ROMPages[page] + (start & 0xffff), data, readLen );
data += readLen; size -= readLen;
start += readLen;
len -= readLen;
}
if ( size < 4 ) return -1;
len = get_le32( data ); data += 4; size -= 4;
}
}
if ( size < 4 ) return -1;
temp = get_le32( data ); data += 4; size -= 4;
if(temp == 0x34365253) {
uint32_t len, start;
if ( size < 4 ) return -1;
len = get_le32( data ); data += 4; size -= 4;
while(len) {
if ( size < 4 ) return -1;
start = get_le32( data ); data += 4; size -= 4;
if ( size < len ) return -1;
memcpy( USF_STATE->savestatespace + start, data, len );
data += len; size -= len;
if ( size < 4 ) return -1;
len = get_le32( data ); data += 4; size -= 4;
}
}
return 0;
}
static int usf_startup(usf_state_t * state)
{
// Detect the Ramsize before the memory allocation
if(get_le32(state->savestatespace + 4) == 0x400000) {
void * savestate;
state->RdramSize = 0x400000;
savestate = realloc(state->savestatespace, 0x40275c);
if ( savestate )
state->savestatespace = savestate;
} else if(get_le32(USF_STATE->savestatespace + 4) == 0x800000)
state->RdramSize = 0x800000;
if ( !Allocate_Memory(state) )
return -1;
StartEmulationFromSave(state, USF_STATE->savestatespace);
return 0;
}
const char * usf_render(void * state, int16_t * buffer, size_t count, int32_t * sample_rate)
{
USF_STATE->last_error = 0;
USF_STATE->error_message[0] = '\0';
if ( !USF_STATE->MemoryState )
{
if ( usf_startup( USF_STATE ) < 0 )
return USF_STATE->last_error;
}
if ( USF_STATE->samples_in_buffer )
{
size_t do_max = USF_STATE->samples_in_buffer;
if ( do_max > count )
do_max = count;
if ( buffer )
memcpy( buffer, USF_STATE->samplebuf, sizeof(int16_t) * 2 * do_max );
USF_STATE->samples_in_buffer -= do_max;
if ( sample_rate )
*sample_rate = USF_STATE->SampleRate;
if ( USF_STATE->samples_in_buffer )
{
memmove( USF_STATE->samplebuf, USF_STATE->samplebuf + do_max * 2, sizeof(int16_t) * 2 * USF_STATE->samples_in_buffer );
return 0;
}
if ( buffer )
buffer += 2 * do_max;
count -= do_max;
}
USF_STATE->sample_buffer = buffer;
USF_STATE->sample_buffer_count = count;
USF_STATE->cpu_stopped = 0;
USF_STATE->cpu_running = 1;
StartInterpreterCPU(USF_STATE);
if ( sample_rate )
*sample_rate = USF_STATE->SampleRate;
return USF_STATE->last_error;
}
const char * usf_render_resampled(void * state, int16_t * buffer, size_t count, int32_t sample_rate)
{
if ( !buffer )
{
unsigned long samples_buffered = resampler_get_sample_count( USF_STATE->resampler );
resampler_clear(USF_STATE->resampler);
if (samples_buffered)
{
unsigned long samples_to_remove = samples_buffered;
if (samples_to_remove > count)
samples_to_remove = count;
count -= samples_to_remove;
while (samples_to_remove--)
resampler_remove_sample(USF_STATE->resampler);
if (!count)
return 0;
}
count = (size_t)((uint64_t)count * USF_STATE->SampleRate / sample_rate);
if (count > USF_STATE->samples_in_buffer_2)
{
count -= USF_STATE->samples_in_buffer_2;
USF_STATE->samples_in_buffer_2 = 0;
}
else if (count)
{
USF_STATE->samples_in_buffer_2 -= count;
memmove(USF_STATE->samplebuf2, USF_STATE->samplebuf2 + 8192 - USF_STATE->samples_in_buffer_2 * 2, USF_STATE->samples_in_buffer_2 * sizeof(short) * 2);
return 0;
}
return usf_render(state, buffer, count, NULL);
}
while ( count )
{
const char * err;
while ( USF_STATE->samples_in_buffer_2 && resampler_get_free_count(USF_STATE->resampler) )
{
int i = 0, j = resampler_get_free_count(USF_STATE->resampler);
if (j > USF_STATE->samples_in_buffer_2)
j = (int)USF_STATE->samples_in_buffer_2;
for (i = 0; i < j; ++i)
{
resampler_write_sample(USF_STATE->resampler, USF_STATE->samplebuf2[i*2], USF_STATE->samplebuf2[i*2+1]);
}
if (i)
{
memmove(USF_STATE->samplebuf2, USF_STATE->samplebuf2 + i * 2, (USF_STATE->samples_in_buffer_2 - i) * sizeof(short) * 2);
USF_STATE->samples_in_buffer_2 -= i;
}
}
while ( count && resampler_get_sample_count(USF_STATE->resampler) )
{
resampler_get_sample(USF_STATE->resampler, buffer, buffer + 1);
resampler_remove_sample(USF_STATE->resampler);
buffer += 2;
--count;
}
if (!count)
break;
if (USF_STATE->samples_in_buffer_2)
continue;
err = usf_render(state, USF_STATE->samplebuf2, 4096, 0);
if (err)
return err;
USF_STATE->samples_in_buffer_2 = 4096;
resampler_set_rate(USF_STATE->resampler, (float)USF_STATE->SampleRate / (float)sample_rate);
}
return 0;
}
void usf_restart(void * state)
{
if ( USF_STATE->MemoryState )
StartEmulationFromSave(USF_STATE, USF_STATE->savestatespace);
USF_STATE->samples_in_buffer = 0;
USF_STATE->samples_in_buffer_2 = 0;
resampler_clear(USF_STATE->resampler);
}
void usf_shutdown(void * state)
{
Release_Memory(USF_STATE);
resampler_delete(USF_STATE->resampler);
#ifdef DEBUG_INFO
fclose(USF_STATE->debug_log);
#endif
}

View File

@ -0,0 +1,81 @@
/* LazyUSF Public Interface */
#ifndef _USF_H_
#define _USF_H_
#define _CRT_SECURE_NO_WARNINGS
#include <stdint.h>
#include <stdlib.h>
typedef struct usf_state usf_state_t;
typedef struct usf_state_helper usf_state_helper_t;
#ifdef __cplusplus
extern "C" {
#endif
/* Returns the size of the base emulator state. */
size_t usf_get_state_size();
/* Clears and prepares an allocated state.
Do not call this on a state which has already been rendering
without calling usf_shutdown first, or else you will leak memory. */
void usf_clear(void * state);
/* These are both required functions before calling usf_render.
Their values are assumed to be zero, unless the respective
_enablecompare or _enablefifofull tags are present in the file. */
void usf_set_compare(void * state, int enable);
void usf_set_fifo_full(void * state, int enable);
/* This option should speed up decoding significantly, at the expense
of accuracy, and potentially emulation bugs. */
void usf_set_hle_audio(void * state, int enable);
/* This processes and uploads the ROM and/or Project 64 save state data
present in the reserved section of each USF file. They should be
uploaded in the order in which psf_load processes them, or in priority
of deepest and first nested _lib first, top level files, then numbered
_lib# files.
Returns -1 on invalid data error, or 0 on success. */
int usf_upload_section(void * state, const uint8_t * data, size_t size);
/* Renders at least enough sample DMA blocks to fill the count passed in.
A null pointer is acceptable, in which case samples will be discarded.
Requesting zero samples with a null pointer is an acceptable way to
force at least one block of samples to render and return the current
sample rate in the variable passed in.
Requesting a non-zero number of samples with a null buffer pointer will
result in exactly count samples being rendered and discarded.
Emulation runs in whole blocks until there have been exactly enough
Audio Interface DMA transfers to at least fill count samples, at which
point the remainder is buffered in the emulator state until the next
usf_render() call.
Returns 0 on success, or a pointer to the last error message on failure. */
const char * usf_render(void * state, int16_t * buffer, size_t count, int32_t * sample_rate);
/* Renders the same as above, only resampled to the requested sample rate
instead of returning the necessary playback rate. Playback will be a
consistent sample rate, always, as any sample rate changes, if any,
are tracked and accounted for.
Requesting a non-zero number of samples with a null buffer pointer will
result in exactly that count of samples being skipped, in the base time
of the requested sample rate.
Returns 0 on success, or a pointer to the last error message on failure. */
const char * usf_render_resampled(void * state, int16_t * buffer, size_t count, int32_t sample_rate);
/* Reloads the ROM and save state, effectively restarting emulation. Also
discards any buffered sample data. */
void usf_restart(void * state);
/* Frees all allocated memory associated with the emulator state. Necessary
after at least one call to usf_render, or else the memory will be leaked. */
void usf_shutdown(void * state);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,164 @@
#ifndef _USF_INTERNAL_H_
#define _USF_INTERNAL_H_
#include "cpu.h"
#include "rsp_hle/hle.h"
#include "cpu_hle.h"
struct usf_state_helper
{
size_t offset_to_structure;
};
#ifndef RCPREG_DEFINED
#define RCPREG_DEFINED
typedef uint32_t RCPREG;
#endif
#ifdef DEBUG_INFO
#include <stdio.h>
#endif
struct usf_state
{
// RSP vector registers, need to be aligned to 16 bytes
// when SSE2 or SSSE3 is enabled, or for any hope of
// auto vectorization
// usf_clear takes care of aligning the structure within
// the memory block passed into it, treating the pointer
// as usf_state_helper, and storing an offset from the
// pointer to the actual usf_state structure. The size
// which is indicated for allocation accounts for this
// with two pages of padding.
int16_t VR[32][8];
int16_t VACC[3][8];
// RSP virtual registers, also needs alignment
int32_t SR[32];
// rsp/rsp.c, not necessarily in need of alignment
RCPREG* CR[16];
// rsp/vu/cf.h, all need alignment
int16_t ne[8]; /* $vco: high byte "NOTEQUAL" */
int16_t co[8]; /* $vco: low byte "carry/borrow in/out" */
int16_t clip[8]; /* $vcc: high byte (clip tests: VCL, VCH, VCR) */
int16_t comp[8]; /* $vcc: low byte (VEQ, VNE, VLT, VGE, VCL, VCH, VCR) */
int16_t vce[8]; /* $vce: vector compare extension register */
// All further members of the structure need not be aligned
// rsp/vu/divrom.h
int32_t DivIn; /* buffered numerator of division read from vector file */
int32_t DivOut; /* global division result set by VRCP/VRCPL/VRSQ/VRSQH */
#if (0)
int32_t MovIn; /* We do not emulate this register (obsolete, for VMOV). */
#endif
int32_t DPH;
// rsp/rsp.h
int32_t stage; // unused since EMULATE_STATIC_PC is defined by default in rsp/config.h
int32_t temp_PC;
int16_t MFC0_count[32];
// rsp_hle
struct hle_t hle;
uint32_t cpu_running, cpu_stopped;
// options from file tags
uint32_t enablecompare, enableFIFOfull;
// options for decoding
uint32_t enable_hle_audio;
// buffering for rendered sample data
size_t sample_buffer_count;
int16_t * sample_buffer;
// audio.c
// SampleRate is usually guaranteed to stay the same for the duration
// of a given track, and depends on the game.
int32_t SampleRate;
// Audio is rendered in whole Audio Interface DMA transfers, which are
// then copied directly to the caller's buffer. Any left over samples
// from the last DMA transfer that fills the caller's buffer will be
// stored here until the next call to usf_render()
int16_t samplebuf[16384];
size_t samples_in_buffer;
// usf.c
// This takes care of automatically resampling the console audio
// to the user requested sample rate, using the same cubic interpolation
// coefficients as the RSP HLE, which in turn mimics the original RSP
// microcode used in most games.
void * resampler;
int16_t samplebuf2[8192];
size_t samples_in_buffer_2;
// This buffer does not really need to be that large, as it is likely
// to only accumulate a handlful of error messages, at which point
// emulation is immediately halted and the messages are returned to
// the caller.
const char * last_error;
char error_message[1024];
// cpu.c
uint32_t NextInstruction, JumpToLocation, AudioIntrReg;
CPU_ACTION * CPU_Action;
SYSTEM_TIMERS * Timers;
OPCODE Opcode;
uint32_t CPURunning, SPHack;
uint32_t * WaitMode;
// interpreter_ops.c
uint32_t SWL_MASK[4], SWR_MASK[4], LWL_MASK[4], LWR_MASK[4];
int32_t SWL_SHIFT[4], SWR_SHIFT[4], LWL_SHIFT[4], LWR_SHIFT[4];
int32_t RoundingModel;
// memory.c
uintptr_t *TLB_Map;
uint8_t * MemChunk;
uint32_t RdramSize, SystemRdramSize, RomFileSize;
uint8_t * N64MEM, * RDRAM, * DMEM, * IMEM, * ROMPages[0x400], * savestatespace, * NOMEM;
uint32_t WrittenToRom;
uint32_t WroteToRom;
uint32_t TempValue;
uint32_t MemoryState;
uint8_t EmptySpace;
// pif.c
uint8_t *PIF_Ram;
// registers.c
uint32_t PROGRAM_COUNTER, * CP0,*FPCR,*RegRDRAM,*RegSP,*RegDPC,*RegMI,*RegVI,*RegAI,*RegPI,
*RegRI,*RegSI, HalfLine, RegModValue, ViFieldNumber, LLBit, LLAddr;
void * FPRDoubleLocation[32], * FPRFloatLocation[32];
MIPS_DWORD *GPR, *FPR, HI, LO;
int32_t fpuControl;
N64_REGISTERS * Registers;
// tlb.c
FASTTLB FastTlb[64];
TLB tlb[32];
uint32_t OLD_VI_V_SYNC_REG/* = 0*/, VI_INTR_TIME/* = 500000*/;
uint32_t cpu_hle_entry_count;
_HLE_Entry * cpu_hle_entries;
#ifdef DEBUG_INFO
FILE * debug_log;
#endif
};
#define USF_STATE_HELPER ((usf_state_helper_t *)(state))
#define USF_STATE ((usf_state_t *)(((uint8_t *)(state))+((usf_state_helper_t *)(state))->offset_to_structure))
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0940"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "83C8B62118AF57770071B040"
BuildableName = "lazyusf2.framework"
BlueprintName = "lazyusf2"
ReferencedContainer = "container:lazyusf2.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "83C8B62118AF57770071B040"
BuildableName = "lazyusf2.framework"
BlueprintName = "lazyusf2"
ReferencedContainer = "container:lazyusf2.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "83C8B62118AF57770071B040"
BuildableName = "lazyusf2.framework"
BlueprintName = "lazyusf2"
ReferencedContainer = "container:lazyusf2.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

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