Added error logging to LazyUSF, player now stops on errors.

CQTexperiment
Chris Moeller 2014-02-20 17:07:57 -08:00
parent 486ce41c7f
commit 5c4a4602db
18 changed files with 124 additions and 83 deletions

View File

@ -74,7 +74,7 @@ void CheckTimer (usf_state_t * state) {
state->Timers->CurrentTimerType = count; state->Timers->CurrentTimerType = count;
} }
if (state->Timers->CurrentTimerType == -1) { if (state->Timers->CurrentTimerType == -1) {
DisplayError("No active timers ???\nEmulation Stoped"); DisplayError(state, "No active timers ???\nEmulation Stopped");
StopEmulation(state); StopEmulation(state);
} }
for (count = 0; count < MaxTimers; count++) { for (count = 0; count < MaxTimers; count++) {
@ -363,7 +363,7 @@ void InPermLoop ( usf_state_t * state ) {
return; return;
InterruptsDisabled: InterruptsDisabled:
DisplayError("Stuck in Permanent Loop"); DisplayError(state, "Stuck in Permanent Loop");
StopEmulation(state); StopEmulation(state);
} }

View File

@ -258,7 +258,8 @@ void r4300i_LH (usf_state_t * state) {
if ((Address & 1) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); } if ((Address & 1) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); }
if (!r4300i_LH_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UHW[0])) { if (!r4300i_LH_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UHW[0])) {
//if (ShowTLBMisses) { //if (ShowTLBMisses) {
DisplayError("LH TLB: %X",Address); // Too spammy
//DisplayError(state, "LH TLB: %X",Address);
//} //}
TLB_READ_EXCEPTION(Address); TLB_READ_EXCEPTION(Address);
} else { } else {
@ -306,7 +307,8 @@ void r4300i_LBU (usf_state_t * state) {
uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset;
if (!r4300i_LB_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UB[0])) { if (!r4300i_LB_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UB[0])) {
//if (ShowTLBMisses) { //if (ShowTLBMisses) {
DisplayError("LBU TLB: %X",Address); // Too spammy
//DisplayError(state, "LBU TLB: %X",Address);
//} //}
TLB_READ_EXCEPTION(Address); TLB_READ_EXCEPTION(Address);
} else { } else {
@ -319,7 +321,8 @@ void r4300i_LHU (usf_state_t * state) {
if ((Address & 1) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); } if ((Address & 1) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); }
if (!r4300i_LH_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UHW[0])) { if (!r4300i_LH_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UHW[0])) {
//if (ShowTLBMisses) { //if (ShowTLBMisses) {
DisplayError("LHU TLB: %X",Address); // Too spammy
//DisplayError(state, "LHU TLB: %X",Address);
//} //}
TLB_READ_EXCEPTION(Address); TLB_READ_EXCEPTION(Address);
} else { } else {
@ -351,7 +354,8 @@ void r4300i_LWU (usf_state_t * state) {
if (!r4300i_LW_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UW[0])) { if (!r4300i_LW_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UW[0])) {
//if (ShowTLBMisses) { //if (ShowTLBMisses) {
DisplayError("LWU TLB: %X",Address); // Too spammy
//DisplayError(state, "LWU TLB: %X",Address);
//} //}
TLB_READ_EXCEPTION(Address); TLB_READ_EXCEPTION(Address);
} else { } else {
@ -494,7 +498,8 @@ void r4300i_LL (usf_state_t * state) {
if (!r4300i_LW_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UW[0])) { if (!r4300i_LW_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UW[0])) {
//if (ShowTLBMisses) { //if (ShowTLBMisses) {
DisplayError("LW TLB: %X",Address); // Too spammy
//DisplayError(state, "LW TLB: %X",Address);
//} //}
TLB_READ_EXCEPTION(Address); TLB_READ_EXCEPTION(Address);
} else { } else {
@ -513,7 +518,8 @@ void r4300i_LWC1 (usf_state_t * state) {
if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); } if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); }
if (!r4300i_LW_VAddr(state,Address,&*(uint32_t *)state->FPRFloatLocation[state->Opcode.u.f.ft])) { if (!r4300i_LW_VAddr(state,Address,&*(uint32_t *)state->FPRFloatLocation[state->Opcode.u.f.ft])) {
//if (ShowTLBMisses) { //if (ShowTLBMisses) {
DisplayError("LWC1 TLB: %X",Address); // Too spammy
//DisplayError(state, "LWC1 TLB: %X",Address);
//} //}
TLB_READ_EXCEPTION(Address); TLB_READ_EXCEPTION(Address);
} }
@ -524,7 +530,7 @@ void r4300i_SC (usf_state_t * state) {
if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,0); } if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,0); }
if (state->LLBit == 1) { if (state->LLBit == 1) {
if (!r4300i_SW_VAddr(state,Address,state->GPR[state->Opcode.u.b.rt].UW[0])) { if (!r4300i_SW_VAddr(state,Address,state->GPR[state->Opcode.u.b.rt].UW[0])) {
DisplayError("SW TLB: %X",Address); DisplayError(state, "SW TLB: %X",Address);
} }
} }
state->GPR[state->Opcode.u.b.rt].UW[0] = state->LLBit; state->GPR[state->Opcode.u.b.rt].UW[0] = state->LLBit;
@ -1331,6 +1337,6 @@ void r4300i_COP1_L_CVT_D (usf_state_t * state) {
/************************** Other functions **************************/ /************************** Other functions **************************/
void R4300i_UnknownOpcode (usf_state_t * state) { void R4300i_UnknownOpcode (usf_state_t * state) {
DisplayError("Unknown R4300i Opcode.\tPC:%08x\tOp:%08x\n", state->PROGRAM_COUNTER,state->Opcode.u.Hex); DisplayError(state, "Unknown R4300i Opcode.\tPC:%08x\tOp:%08x\n", state->PROGRAM_COUNTER,state->Opcode.u.Hex);
StopEmulation(state); StopEmulation(state);
} }

View File

@ -18,14 +18,21 @@ void StopEmulation(usf_state_t * state)
state->cpu_running = 0; state->cpu_running = 0;
} }
void DisplayError (char * Message, ...) { void DisplayError (usf_state_t * state, char * Message, ...) {
(void)Message; (void)Message;
//char Msg[1000]; va_list ap;
//va_list ap;
size_t len = strlen( state->error_message );
if ( len )
state->error_message[ len++ ] = '\n';
//va_start( ap, Message ); va_start( ap, Message );
//vsprintf( Msg, Message, ap ); vsprintf( state->error_message + len, Message, ap );
//va_end( ap ); va_end( ap );
state->last_error = state->error_message;
StopEmulation( state );
//printf("Error: %s\n", Msg); //printf("Error: %s\n", Msg);
} }

View File

@ -2,9 +2,5 @@
#include "usf.h" #include "usf.h"
#define CPU_Default -1 void DisplayError (usf_state_t *, char * Message, ...);
#define CPU_Interpreter 0
#define CPU_Recompiler 1
void DisplayError (char * Message, ...);
void StopEmulation(usf_state_t *); void StopEmulation(usf_state_t *);

View File

@ -93,7 +93,7 @@ int32_t Allocate_Memory ( void * state ) {
USF_STATE->N64MEM = USF_STATE->MemChunk + 0x100000 * sizeof(uintptr_t) + 0x10000; USF_STATE->N64MEM = USF_STATE->MemChunk + 0x100000 * sizeof(uintptr_t) + 0x10000;
if(USF_STATE->N64MEM == NULL) { if(USF_STATE->N64MEM == NULL) {
DisplayError("Failed to allocate N64MEM"); DisplayError(USF_STATE, "Failed to allocate N64MEM");
return 0; return 0;
} }
@ -695,7 +695,7 @@ int32_t r4300i_SW_NonMemory ( usf_state_t * state, uint32_t PAddr, uint32_t Valu
PI_DMA_WRITE(state); PI_DMA_WRITE(state);
break; break;
case 0x04600010: case 0x04600010:
//if ((Value & PI_SET_RESET) != 0 ) { DisplayError("reset Controller"); } //if ((Value & PI_SET_RESET) != 0 ) { DisplayError(state, "reset Controller"); }
if ((Value & PI_CLR_INTR) != 0 ) { if ((Value & PI_CLR_INTR) != 0 ) {
MI_INTR_REG &= ~MI_INTR_PI; MI_INTR_REG &= ~MI_INTR_PI;
CheckInterrupts(state); CheckInterrupts(state);

View File

@ -21,6 +21,7 @@
NOINLINE void run_task(usf_state_t * state) NOINLINE void run_task(usf_state_t * state)
{ {
register int PC; register int PC;
int wrap_count = 0;
if (CFG_WAIT_FOR_CPU_HOST != 0) if (CFG_WAIT_FOR_CPU_HOST != 0)
{ {
@ -37,6 +38,11 @@ NOINLINE void run_task(usf_state_t * state)
inst = *(uint32_t *)(state->IMEM + FIT_IMEM(PC)); inst = *(uint32_t *)(state->IMEM + FIT_IMEM(PC));
#ifdef EMULATE_STATIC_PC #ifdef EMULATE_STATIC_PC
PC = (PC + 0x004); PC = (PC + 0x004);
if ( FIT_IMEM(PC) == 0 && ++wrap_count == 32 )
{
message( state, "RSP execution presumably caught in an infinite loop", 3 );
break;
}
EX: EX:
#endif #endif
#ifdef SP_EXECUTE_LOG #ifdef SP_EXECUTE_LOG
@ -445,6 +451,11 @@ EX:
{ {
state->stage = 2*state->stage; /* next IW in branch delay slot? */ state->stage = 2*state->stage; /* next IW in branch delay slot? */
PC = (PC + 0x004) & 0xFFC; 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; SP_PC_REG = 0x04001000 + PC;
} }
continue; continue;
@ -467,7 +478,7 @@ BRANCH:
{} {}
else /* ??? unknown, possibly external intervention from CPU memory map */ else /* ??? unknown, possibly external intervention from CPU memory map */
{ {
message("SP_SET_HALT", 3); message(state, "SP_SET_HALT", 3);
return; return;
} }
SP_STATUS_REG &= ~0x00000001; /* CPU restarts with the correct SIGs. */ SP_STATUS_REG &= ~0x00000001; /* CPU restarts with the correct SIGs. */

View File

@ -21,6 +21,7 @@
#include "../dma.h" #include "../dma.h"
#include "../exception.h" #include "../exception.h"
#include "../main.h"
#include "../memory.h" #include "../memory.h"
#include "../registers.h" #include "../registers.h"
@ -38,7 +39,7 @@ void real_run_rsp(usf_state_t * state, uint32_t cycles)
if (SP_STATUS_REG & 0x00000003) if (SP_STATUS_REG & 0x00000003)
{ {
message("SP_STATUS_HALT", 3); message(state, "SP_STATUS_HALT", 3);
return; return;
} }
run_task(state); run_task(state);

View File

@ -42,10 +42,12 @@ typedef unsigned char byte;
typedef uint32_t RCPREG; typedef uint32_t RCPREG;
#endif #endif
NOINLINE void message(const char* body, int priority) NOINLINE void message(usf_state_t * state, const char* body, int priority)
{ {
(void)body; (void)body;
(void)priority; (void)priority;
if ( priority > 1 )
DisplayError( state, "%s", body );
} }
/* /*

View File

@ -143,7 +143,7 @@ static void MT_DMA_WRITE_LENGTH(usf_state_t * state, int rt)
static void MT_SP_STATUS(usf_state_t * state, int rt) static void MT_SP_STATUS(usf_state_t * state, int rt)
{ {
if (state->SR[rt] & 0xFE000040) if (state->SR[rt] & 0xFE000040)
message("MTC0\nSP_STATUS", 2); message(state, "MTC0\nSP_STATUS", 2);
SP_STATUS_REG &= ~(!!(state->SR[rt] & 0x00000001) << 0); SP_STATUS_REG &= ~(!!(state->SR[rt] & 0x00000001) << 0);
SP_STATUS_REG |= (!!(state->SR[rt] & 0x00000002) << 0); SP_STATUS_REG |= (!!(state->SR[rt] & 0x00000002) << 0);
SP_STATUS_REG &= ~(!!(state->SR[rt] & 0x00000004) << 1); SP_STATUS_REG &= ~(!!(state->SR[rt] & 0x00000004) << 1);
@ -184,21 +184,21 @@ static void MT_CMD_START(usf_state_t * state, int rt)
const uint32_t source = state->SR[rt] & 0xFFFFFFF8; /* Funnelcube demo */ const uint32_t source = state->SR[rt] & 0xFFFFFFF8; /* Funnelcube demo */
if (DPC_BUFBUSY_REG) /* lock hazards not implemented */ if (DPC_BUFBUSY_REG) /* lock hazards not implemented */
message("MTC0\nCMD_START", 0); message(state, "MTC0\nCMD_START", 0);
DPC_END_REG = DPC_CURRENT_REG = DPC_START_REG = source; DPC_END_REG = DPC_CURRENT_REG = DPC_START_REG = source;
return; return;
} }
static void MT_CMD_END(usf_state_t * state, int rt) static void MT_CMD_END(usf_state_t * state, int rt)
{ {
if (DPC_BUFBUSY_REG) if (DPC_BUFBUSY_REG)
message("MTC0\nCMD_END", 0); /* This is just CA-related. */ message(state, "MTC0\nCMD_END", 0); /* This is just CA-related. */
DPC_END_REG = state->SR[rt] & 0xFFFFFFF8; DPC_END_REG = state->SR[rt] & 0xFFFFFFF8;
return; return;
} }
static void MT_CMD_STATUS(usf_state_t * state, int rt) static void MT_CMD_STATUS(usf_state_t * state, int rt)
{ {
if (state->SR[rt] & 0xFFFFFD80) /* unsupported or reserved bits */ if (state->SR[rt] & 0xFFFFFD80) /* unsupported or reserved bits */
message("MTC0\nCMD_STATUS", 2); message(state, "MTC0\nCMD_STATUS", 2);
DPC_STATUS_REG &= ~(!!(state->SR[rt] & 0x00000001) << 0); DPC_STATUS_REG &= ~(!!(state->SR[rt] & 0x00000001) << 0);
DPC_STATUS_REG |= (!!(state->SR[rt] & 0x00000002) << 0); DPC_STATUS_REG |= (!!(state->SR[rt] & 0x00000002) << 0);
DPC_STATUS_REG &= ~(!!(state->SR[rt] & 0x00000004) << 1); DPC_STATUS_REG &= ~(!!(state->SR[rt] & 0x00000004) << 1);
@ -214,7 +214,7 @@ static void MT_CMD_STATUS(usf_state_t * state, int rt)
} }
static void MT_CMD_CLOCK(usf_state_t * state, int rt) static void MT_CMD_CLOCK(usf_state_t * state, int rt)
{ {
message("MTC0\nCMD_CLOCK", 1); /* read-only?? */ message(state, "MTC0\nCMD_CLOCK", 1); /* read-only?? */
DPC_CLOCK_REG = state->SR[rt]; DPC_CLOCK_REG = state->SR[rt];
return; /* Appendix says this is RW; elsewhere it says R. */ return; /* Appendix says this is RW; elsewhere it says R. */
} }
@ -225,7 +225,7 @@ static void MT_READ_ONLY(usf_state_t * state, int rt)
//char text[64]; //char text[64];
//sprintf(text, "MTC0\nInvalid write attempt.\nstate->SR[%i] = 0x%08X", rt, state->SR[rt]); //sprintf(text, "MTC0\nInvalid write attempt.\nstate->SR[%i] = 0x%08X", rt, state->SR[rt]);
//message(text, 2); //message(state, text, 2);
return; return;
} }
@ -419,14 +419,14 @@ INLINE static void LSV(usf_state_t * state, int vt, int element, int offset, int
if (e & 0x1) if (e & 0x1)
{ {
message("LSV\nIllegal element.", 3); message(state, "LSV\nIllegal element.", 3);
return; return;
} }
addr = (state->SR[base] + 2*offset) & 0x00000FFF; addr = (state->SR[base] + 2*offset) & 0x00000FFF;
correction = addr % 0x004; correction = addr % 0x004;
if (correction == 0x003) if (correction == 0x003)
{ {
message("LSV\nWeird addr.", 3); message(state, "LSV\nWeird addr.", 3);
return; return;
} }
VR_S(vt, e) = *(short *)(state->DMEM + addr - HES(0x000)*(correction - 1)); VR_S(vt, e) = *(short *)(state->DMEM + addr - HES(0x000)*(correction - 1));
@ -440,13 +440,13 @@ INLINE static void LLV(usf_state_t * state, int vt, int element, int offset, int
if (e & 0x1) if (e & 0x1)
{ {
message("LLV\nOdd element.", 3); message(state, "LLV\nOdd element.", 3);
return; return;
} /* Illegal (but still even) elements are used by Boss Game Studios. */ } /* Illegal (but still even) elements are used by Boss Game Studios. */
addr = (state->SR[base] + 4*offset) & 0x00000FFF; addr = (state->SR[base] + 4*offset) & 0x00000FFF;
if (addr & 0x00000001) if (addr & 0x00000001)
{ {
message("LLV\nOdd addr.", 3); message(state, "LLV\nOdd addr.", 3);
return; return;
} }
correction = HES(0x000)*(addr%0x004 - 1); correction = HES(0x000)*(addr%0x004 - 1);
@ -462,7 +462,7 @@ INLINE static void LDV(usf_state_t * state, int vt, int element, int offset, int
if (e & 0x1) if (e & 0x1)
{ {
message("LDV\nOdd element.", 3); message(state, "LDV\nOdd element.", 3);
return; return;
} /* Illegal (but still even) elements are used by Boss Game Studios. */ } /* Illegal (but still even) elements are used by Boss Game Studios. */
addr = (state->SR[base] + 8*offset) & 0x00000FFF; addr = (state->SR[base] + 8*offset) & 0x00000FFF;
@ -568,13 +568,13 @@ INLINE static void SLV(usf_state_t * state, int vt, int element, int offset, int
if ((e & 0x1) || e > 0xC) /* must support illegal even elements in F3DEX2 */ if ((e & 0x1) || e > 0xC) /* must support illegal even elements in F3DEX2 */
{ {
message("SLV\nIllegal element.", 3); message(state, "SLV\nIllegal element.", 3);
return; return;
} }
addr = (state->SR[base] + 4*offset) & 0x00000FFF; addr = (state->SR[base] + 4*offset) & 0x00000FFF;
if (addr & 0x00000001) if (addr & 0x00000001)
{ {
message("SLV\nOdd addr.", 3); message(state, "SLV\nOdd addr.", 3);
return; return;
} }
correction = HES(0x000)*(addr%0x004 - 1); correction = HES(0x000)*(addr%0x004 - 1);
@ -680,7 +680,7 @@ INLINE static void LPV(usf_state_t * state, int vt, int element, int offset, int
if (e != 0x0) if (e != 0x0)
{ {
message("LPV\nIllegal element.", 3); message(state, "LPV\nIllegal element.", 3);
return; return;
} }
addr = (state->SR[base] + 8*offset) & 0x00000FFF; addr = (state->SR[base] + 8*offset) & 0x00000FFF;
@ -911,7 +911,7 @@ INLINE static void SPV(usf_state_t * state, int vt, int element, int offset, int
if (e != 0x0) if (e != 0x0)
{ {
message("SPV\nIllegal element.", 3); message(state, "SPV\nIllegal element.", 3);
return; return;
} }
addr = (state->SR[base] + 8*offset) & 0x00000FFF; addr = (state->SR[base] + 8*offset) & 0x00000FFF;
@ -1023,7 +1023,7 @@ INLINE static void SUV(usf_state_t * state, int vt, int element, int offset, int
if (e != 0x0) if (e != 0x0)
{ {
message("SUV\nIllegal element.", 3); message(state, "SUV\nIllegal element.", 3);
return; return;
} }
addr = (state->SR[base] + 8*offset) & 0x00000FFF; addr = (state->SR[base] + 8*offset) & 0x00000FFF;
@ -1054,7 +1054,7 @@ INLINE static void SUV(usf_state_t * state, int vt, int element, int offset, int
state->DMEM[addr + BES(0x003)] = (unsigned char)(state->VR[vt][07] >> 7); state->DMEM[addr + BES(0x003)] = (unsigned char)(state->VR[vt][07] >> 7);
return; return;
default: /* Completely legal, just never seen it be done. */ default: /* Completely legal, just never seen it be done. */
message("SUV\nWeird addr.", 3); message(state, "SUV\nWeird addr.", 3);
return; return;
} }
} }
@ -1070,13 +1070,13 @@ static void LHV(usf_state_t * state, int vt, int element, int offset, int base)
if (e != 0x0) if (e != 0x0)
{ {
message("LHV\nIllegal element.", 3); message(state, "LHV\nIllegal element.", 3);
return; return;
} }
addr = (state->SR[base] + 16*offset) & 0x00000FFF; addr = (state->SR[base] + 16*offset) & 0x00000FFF;
if (addr & 0x0000000E) if (addr & 0x0000000E)
{ {
message("LHV\nIllegal addr.", 3); message(state, "LHV\nIllegal addr.", 3);
return; return;
} }
addr ^= MES(00); addr ^= MES(00);
@ -1102,7 +1102,7 @@ NOINLINE static void LFV(usf_state_t * state, int vt, int element, int offset, i
sprintf(debugger, "%s $v%i[0x%X], 0x%03X($%i)", "LFV", sprintf(debugger, "%s $v%i[0x%X], 0x%03X($%i)", "LFV",
vt, element, offset & 0xFFF, base); vt, element, offset & 0xFFF, base);
message(debugger, 3);*/ message(state, debugger, 3);*/
return; return;
} }
static void SHV(usf_state_t * state, int vt, int element, int offset, int base) static void SHV(usf_state_t * state, int vt, int element, int offset, int base)
@ -1112,13 +1112,13 @@ static void SHV(usf_state_t * state, int vt, int element, int offset, int base)
if (e != 0x0) if (e != 0x0)
{ {
message("SHV\nIllegal element.", 3); message(state, "SHV\nIllegal element.", 3);
return; return;
} }
addr = (state->SR[base] + 16*offset) & 0x00000FFF; addr = (state->SR[base] + 16*offset) & 0x00000FFF;
if (addr & 0x0000000E) if (addr & 0x0000000E)
{ {
message("SHV\nIllegal addr.", 3); message(state, "SHV\nIllegal addr.", 3);
return; return;
} }
addr ^= MES(00); addr ^= MES(00);
@ -1155,7 +1155,7 @@ static void SFV(usf_state_t * state, int vt, int element, int offset, int base)
state->DMEM[addr + 0x00C] = (unsigned char)(state->VR[vt][07] >> 7); state->DMEM[addr + 0x00C] = (unsigned char)(state->VR[vt][07] >> 7);
return; return;
default: default:
message("SFV\nIllegal element.", 3); message(state, "SFV\nIllegal element.", 3);
return; return;
} }
} }
@ -1172,13 +1172,13 @@ INLINE static void LQV(usf_state_t * state, int vt, int element, int offset, int
if (e & 0x1) if (e & 0x1)
{ {
message("LQV\nOdd element.", 3); message(state, "LQV\nOdd element.", 3);
return; return;
} }
addr = (state->SR[base] + 16*offset) & 0x00000FFF; addr = (state->SR[base] + 16*offset) & 0x00000FFF;
if (addr & 0x00000001) if (addr & 0x00000001)
{ {
message("LQV\nOdd addr.", 3); message(state, "LQV\nOdd addr.", 3);
return; return;
} }
b = addr & 0x0000000F; b = addr & 0x0000000F;
@ -1247,13 +1247,13 @@ static void LRV(usf_state_t * state, int vt, int element, int offset, int base)
if (e != 0x0) if (e != 0x0)
{ {
message("LRV\nIllegal element.", 3); message(state, "LRV\nIllegal element.", 3);
return; return;
} }
addr = (state->SR[base] + 16*offset) & 0x00000FFF; addr = (state->SR[base] + 16*offset) & 0x00000FFF;
if (addr & 0x00000001) if (addr & 0x00000001)
{ {
message("LRV\nOdd addr.", 3); message(state, "LRV\nOdd addr.", 3);
return; return;
} }
b = addr & 0x0000000F; b = addr & 0x0000000F;
@ -1360,7 +1360,7 @@ INLINE static void SQV(usf_state_t * state, int vt, int element, int offset, int
*(short *)(state->DMEM + addr + HES(0x00E)) = state->VR[vt][04]; *(short *)(state->DMEM + addr + HES(0x00E)) = state->VR[vt][04];
return; return;
default: default:
message("SQV\nWeird addr.", 3); message(state, "SQV\nWeird addr.", 3);
return; return;
} }
} }
@ -1372,13 +1372,13 @@ static void SRV(usf_state_t * state, int vt, int element, int offset, int base)
if (e != 0x0) if (e != 0x0)
{ {
message("SRV\nIllegal element.", 3); message(state, "SRV\nIllegal element.", 3);
return; return;
} }
addr = (state->SR[base] + 16*offset) & 0x00000FFF; addr = (state->SR[base] + 16*offset) & 0x00000FFF;
if (addr & 0x00000001) if (addr & 0x00000001)
{ {
message("SRV\nOdd addr.", 3); message(state, "SRV\nOdd addr.", 3);
return; return;
} }
b = addr & 0x0000000F; b = addr & 0x0000000F;
@ -1444,18 +1444,18 @@ INLINE static void LTV(usf_state_t * state, int vt, int element, int offset, int
if (e & 1) if (e & 1)
{ {
message("LTV\nIllegal element.", 3); message(state, "LTV\nIllegal element.", 3);
return; return;
} }
if (vt & 07) if (vt & 07)
{ {
message("LTV\nUncertain case!", 3); message(state, "LTV\nUncertain case!", 3);
return; /* For LTV I am not sure; for STV I have an idea. */ return; /* For LTV I am not sure; for STV I have an idea. */
} }
addr = (state->SR[base] + 16*offset) & 0x00000FFF; addr = (state->SR[base] + 16*offset) & 0x00000FFF;
if (addr & 0x0000000F) if (addr & 0x0000000F)
{ {
message("LTV\nIllegal addr.", 3); message(state, "LTV\nIllegal addr.", 3);
return; return;
} }
for (i = 0; i < 8; i++) /* SGI screwed LTV up on N64. See STV instead. */ for (i = 0; i < 8; i++) /* SGI screwed LTV up on N64. See STV instead. */
@ -1474,7 +1474,7 @@ NOINLINE static void SWV(usf_state_t * state, int vt, int element, int offset, i
sprintf(debugger, "%s $v%i[0x%X], 0x%03X($%i)", "SWV", sprintf(debugger, "%s $v%i[0x%X], 0x%03X($%i)", "SWV",
vt, element, offset & 0xFFF, base); vt, element, offset & 0xFFF, base);
message(debugger, 3);*/ message(state, debugger, 3);*/
return; return;
} }
INLINE static void STV(usf_state_t * state, int vt, int element, int offset, int base) INLINE static void STV(usf_state_t * state, int vt, int element, int offset, int base)
@ -1485,18 +1485,18 @@ INLINE static void STV(usf_state_t * state, int vt, int element, int offset, int
if (e & 1) if (e & 1)
{ {
message("STV\nIllegal element.", 3); message(state, "STV\nIllegal element.", 3);
return; return;
} }
if (vt & 07) if (vt & 07)
{ {
message("STV\nUncertain case!", 2); message(state, "STV\nUncertain case!", 2);
return; /* vt &= 030; */ return; /* vt &= 030; */
} }
addr = (state->SR[base] + 16*offset) & 0x00000FFF; addr = (state->SR[base] + 16*offset) & 0x00000FFF;
if (addr & 0x0000000F) if (addr & 0x0000000F)
{ {
message("STV\nIllegal addr.", 3); message(state, "STV\nIllegal addr.", 3);
return; return;
} }
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)

View File

@ -19,6 +19,6 @@ static void VMACQ(usf_state_t * state, int vd, int vs, int vt, int e)
vd &= vs &= vt &= e &= 0; /* unused */ vd &= vs &= vt &= e &= 0; /* unused */
if (vd != vs || vt != e) if (vd != vs || vt != e)
return; return;
message("VMACQ\nUnimplemented.", 3); /* untested, any N64 ROMs use this?? */ message(state, "VMACQ\nUnimplemented.", 3); /* untested, any N64 ROMs use this?? */
return; return;
} }

View File

@ -20,6 +20,6 @@ static void VNOP(usf_state_t * state, int vd, int vs, int vt, int e)
(void)state; (void)state;
if (WB_inhibit) if (WB_inhibit)
return; /* message("VNOP", WB_inhibit); */ return; /* message(state, "VNOP", WB_inhibit); */
return; return;
} }

View File

@ -16,7 +16,7 @@
static void VRSQ(usf_state_t * state, int vd, int de, int vt, int e) static void VRSQ(usf_state_t * state, int vd, int de, int vt, int e)
{ {
message("VRSQ\nUntested.", 1); message(state, "VRSQ\nUntested.", 1);
state->DivIn = (int)state->VR[vt][e & 07]; state->DivIn = (int)state->VR[vt][e & 07];
do_div(state, state->DivIn, SP_DIV_SQRT_YES, SP_DIV_PRECISION_SINGLE); do_div(state, state->DivIn, SP_DIV_SQRT_YES, SP_DIV_PRECISION_SINGLE);
SHUFFLE_VECTOR(VACC_L, state->VR[vt], e); SHUFFLE_VECTOR(VACC_L, state->VR[vt], e);

View File

@ -33,7 +33,7 @@ static void VSAR(int vd, int vs, int vt, int e)
*/ */
if (e > 2) if (e > 2)
{ {
message("VSAR\nInvalid mask.", 2); message(state, "VSAR\nInvalid mask.", 2);
for (i = 0; i < N; i++) for (i = 0; i < N; i++)
VR[vd][i] = 0x0000; /* override behavior (zilmar) */ VR[vd][i] = 0x0000; /* override behavior (zilmar) */
} }
@ -58,7 +58,7 @@ static void VSAW(usf_state_t * state, int vd, int vs, int vt, int e)
if (e > 0x2) if (e > 0x2)
{ /* branch very unlikely...never seen a game do VSAW illegally */ { /* branch very unlikely...never seen a game do VSAW illegally */
message("VSAW\nIllegal mask.", 2); message(state, "VSAW\nIllegal mask.", 2);
for (i = 0; i < N; i++) for (i = 0; i < N; i++)
state->VR[vd][i] = 0x0000; /* override behavior (zilmar) */ state->VR[vd][i] = 0x0000; /* override behavior (zilmar) */
return; return;

View File

@ -53,14 +53,14 @@ static void res_V(usf_state_t * state, int vd, int vs, int vt, int e)
vs = vt = e = 0; vs = vt = e = 0;
if (vs != vt || vt != e) if (vs != vt || vt != e)
return; return;
message("C2\nRESERVED", 2); /* uncertain how to handle reserved, untested */ message(state, "C2\nRESERVED", 2); /* uncertain how to handle reserved, untested */
for (i = 0; i < N; i++) for (i = 0; i < N; i++)
state->VR[vd][i] = 0x0000; /* override behavior (bpoint) */ state->VR[vd][i] = 0x0000; /* override behavior (bpoint) */
return; return;
} }
static void res_M(usf_state_t * state, int vd, int vs, int vt, int e) static void res_M(usf_state_t * state, int vd, int vs, int vt, int e)
{ {
message("VMUL IQ", 2); message(state, "VMUL IQ", 2);
res_V(state, vd, vs, vt, e); res_V(state, vd, vs, vt, e);
return; /* Ultra64 OS did have these, so one could implement this ext. */ return; /* Ultra64 OS did have these, so one could implement this ext. */
} }

View File

@ -14,7 +14,7 @@
#include "usf_internal.h" #include "usf_internal.h"
size_t get_usf_state_size() size_t usf_get_state_size()
{ {
return sizeof(usf_state_t) + 8192; return sizeof(usf_state_t) + 8192;
} }
@ -22,7 +22,7 @@ size_t get_usf_state_size()
void usf_clear(void * state) void usf_clear(void * state)
{ {
size_t offset; size_t offset;
memset(state, 0, get_usf_state_size()); memset(state, 0, usf_get_state_size());
offset = 4096 - (((uintptr_t)state) & 4095); offset = 4096 - (((uintptr_t)state) & 4095);
USF_STATE_HELPER->offset_to_structure = offset; USF_STATE_HELPER->offset_to_structure = offset;
@ -155,7 +155,7 @@ int usf_upload_section(void * state, const uint8_t * data, size_t size)
return 0; return 0;
} }
static void usf_startup(void * state) static int usf_startup(void * state)
{ {
// Detect the Ramsize before the memory allocation // Detect the Ramsize before the memory allocation
@ -168,15 +168,24 @@ static void usf_startup(void * state)
} else if(*(uint32_t*)(USF_STATE->savestatespace + 4) == 0x800000) } else if(*(uint32_t*)(USF_STATE->savestatespace + 4) == 0x800000)
USF_STATE->RdramSize = 0x800000; USF_STATE->RdramSize = 0x800000;
Allocate_Memory(state); if ( !Allocate_Memory(state) )
return -1;
StartEmulationFromSave(USF_STATE, USF_STATE->savestatespace); StartEmulationFromSave(USF_STATE, USF_STATE->savestatespace);
return 0;
} }
void usf_render(void * state, int16_t * buffer, size_t count, int32_t * sample_rate) 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_STATE->MemoryState )
usf_startup( USF_STATE ); {
if ( usf_startup( USF_STATE ) < 0 )
return USF_STATE->last_error;
}
if ( USF_STATE->samples_in_buffer ) if ( USF_STATE->samples_in_buffer )
{ {
@ -195,7 +204,7 @@ void usf_render(void * state, int16_t * buffer, size_t count, int32_t * sample_r
if ( USF_STATE->samples_in_buffer ) 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 ); memmove( USF_STATE->samplebuf, USF_STATE->samplebuf + do_max * 2, sizeof(int16_t) * 2 * USF_STATE->samples_in_buffer );
return; return 0;
} }
if ( buffer ) if ( buffer )
@ -213,6 +222,8 @@ void usf_render(void * state, int16_t * buffer, size_t count, int32_t * sample_r
if ( sample_rate ) if ( sample_rate )
*sample_rate = USF_STATE->SampleRate; *sample_rate = USF_STATE->SampleRate;
return USF_STATE->last_error;
} }
void usf_restart(void * state) void usf_restart(void * state)

View File

@ -42,8 +42,9 @@ int usf_upload_section(void * state, const uint8_t * data, size_t size);
A null pointer is acceptable, in which case samples will be discarded. A null pointer is acceptable, in which case samples will be discarded.
Requesting zero samples with a null pointer is an acceptable way to 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 force at least one block of samples to render and return the current
sample rate in the variable passed in. */ sample rate in the variable passed in.
void usf_render(void * state, int16_t * buffer, size_t count, int32_t * sample_rate); 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);
/* Reloads the ROM and save state, effectively restarting emulation. Also /* Reloads the ROM and save state, effectively restarting emulation. Also
discards any buffered sample data. */ discards any buffered sample data. */

View File

@ -71,6 +71,9 @@ struct usf_state
int16_t samplebuf[16384]; int16_t samplebuf[16384];
size_t samples_in_buffer; size_t samples_in_buffer;
const char * last_error;
char error_message[1024];
// cpu.c // cpu.c
uint32_t NextInstruction, JumpToLocation, AudioIntrReg; uint32_t NextInstruction, JumpToLocation, AudioIntrReg;
CPU_ACTION * CPU_Action; CPU_ACTION * CPU_Action;

View File

@ -1010,7 +1010,7 @@ static int usf_info(void * context, const char * name, const char * value)
struct usf_loader_state state; struct usf_loader_state state;
memset( &state, 0, sizeof(state) ); memset( &state, 0, sizeof(state) );
state.emu_state = malloc( get_usf_state_size() ); state.emu_state = malloc( usf_get_state_size() );
usf_clear( state.emu_state ); usf_clear( state.emu_state );
@ -1022,7 +1022,8 @@ static int usf_info(void * context, const char * name, const char * value)
usf_set_compare( state.emu_state, state.enablecompare ); usf_set_compare( state.emu_state, state.enablecompare );
usf_set_fifo_full( state.emu_state, state.enablefifofull ); usf_set_fifo_full( state.emu_state, state.enablefifofull );
usf_render( state.emu_state, 0, 0, &samplerate ); if ( usf_render( state.emu_state, 0, 0, &samplerate ) != 0 )
return NO;
sampleRate = samplerate; sampleRate = samplerate;
@ -1294,7 +1295,8 @@ static int usf_info(void * context, const char * name, const char * value)
{ {
int32_t samplerate; int32_t samplerate;
usf_render( emulatorCore, (int16_t*) buf, frames, &samplerate ); if ( usf_render( emulatorCore, (int16_t*) buf, frames, &samplerate ) != 0 )
return 0;
sampleRate = samplerate; sampleRate = samplerate;
} }
@ -1523,7 +1525,8 @@ static int usf_info(void * context, const char * name, const char * value)
{ {
ssize_t howmany = frame - framesRead; ssize_t howmany = frame - framesRead;
if (howmany > 1024) howmany = 1024; if (howmany > 1024) howmany = 1024;
usf_render(emulatorCore, temp, howmany, NULL); if ( usf_render(emulatorCore, temp, howmany, NULL) != 0 )
return -1;
framesRead += howmany; framesRead += howmany;
} while (framesRead < frame); } while (framesRead < frame);
} }