Import original LazyUSF into code base, for debugging and comparison.
parent
31d47715d1
commit
b1e67366d0
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 * );
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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
|
@ -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 * );
|
|
@ -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);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "usf.h"
|
||||
|
||||
void DisplayError (usf_state_t *, char * Message, ...);
|
||||
void StopEmulation(usf_state_t *);
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
|
@ -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
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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 * );
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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
|
@ -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
Loading…
Reference in New Issue