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;
}
if (state->Timers->CurrentTimerType == -1) {
DisplayError("No active timers ???\nEmulation Stoped");
DisplayError(state, "No active timers ???\nEmulation Stopped");
StopEmulation(state);
}
for (count = 0; count < MaxTimers; count++) {
@ -363,7 +363,7 @@ void InPermLoop ( usf_state_t * state ) {
return;
InterruptsDisabled:
DisplayError("Stuck in Permanent Loop");
DisplayError(state, "Stuck in Permanent Loop");
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 (!r4300i_LH_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UHW[0])) {
//if (ShowTLBMisses) {
DisplayError("LH TLB: %X",Address);
// Too spammy
//DisplayError(state, "LH TLB: %X",Address);
//}
TLB_READ_EXCEPTION(Address);
} 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;
if (!r4300i_LB_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UB[0])) {
//if (ShowTLBMisses) {
DisplayError("LBU TLB: %X",Address);
// Too spammy
//DisplayError(state, "LBU TLB: %X",Address);
//}
TLB_READ_EXCEPTION(Address);
} else {
@ -319,7 +321,8 @@ void r4300i_LHU (usf_state_t * state) {
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 (ShowTLBMisses) {
DisplayError("LHU TLB: %X",Address);
// Too spammy
//DisplayError(state, "LHU TLB: %X",Address);
//}
TLB_READ_EXCEPTION(Address);
} 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 (ShowTLBMisses) {
DisplayError("LWU TLB: %X",Address);
// Too spammy
//DisplayError(state, "LWU TLB: %X",Address);
//}
TLB_READ_EXCEPTION(Address);
} 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 (ShowTLBMisses) {
DisplayError("LW TLB: %X",Address);
// Too spammy
//DisplayError(state, "LW TLB: %X",Address);
//}
TLB_READ_EXCEPTION(Address);
} else {
@ -513,7 +518,8 @@ void r4300i_LWC1 (usf_state_t * state) {
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 (ShowTLBMisses) {
DisplayError("LWC1 TLB: %X",Address);
// Too spammy
//DisplayError(state, "LWC1 TLB: %X",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 (state->LLBit == 1) {
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;
@ -1331,6 +1337,6 @@ void r4300i_COP1_L_CVT_D (usf_state_t * state) {
/************************** Other functions **************************/
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);
}

View File

@ -18,14 +18,21 @@ void StopEmulation(usf_state_t * state)
state->cpu_running = 0;
}
void DisplayError (char * Message, ...) {
void DisplayError (usf_state_t * state, char * 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 );
//vsprintf( Msg, Message, ap );
//va_end( ap );
va_start( ap, Message );
vsprintf( state->error_message + len, Message, ap );
va_end( ap );
state->last_error = state->error_message;
StopEmulation( state );
//printf("Error: %s\n", Msg);
}

View File

@ -2,9 +2,5 @@
#include "usf.h"
#define CPU_Default -1
#define CPU_Interpreter 0
#define CPU_Recompiler 1
void DisplayError (char * Message, ...);
void DisplayError (usf_state_t *, char * Message, ...);
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;
if(USF_STATE->N64MEM == NULL) {
DisplayError("Failed to allocate N64MEM");
DisplayError(USF_STATE, "Failed to allocate N64MEM");
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);
break;
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 ) {
MI_INTR_REG &= ~MI_INTR_PI;
CheckInterrupts(state);

View File

@ -21,6 +21,7 @@
NOINLINE void run_task(usf_state_t * state)
{
register int PC;
int wrap_count = 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));
#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
@ -445,6 +451,11 @@ EX:
{
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;
@ -467,7 +478,7 @@ BRANCH:
{}
else /* ??? unknown, possibly external intervention from CPU memory map */
{
message("SP_SET_HALT", 3);
message(state, "SP_SET_HALT", 3);
return;
}
SP_STATUS_REG &= ~0x00000001; /* CPU restarts with the correct SIGs. */

View File

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

View File

@ -42,10 +42,12 @@ typedef unsigned char byte;
typedef uint32_t RCPREG;
#endif
NOINLINE void message(const char* body, int priority)
NOINLINE void message(usf_state_t * state, const char* body, int priority)
{
(void)body;
(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)
{
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] & 0x00000002) << 0);
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 */
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;
return;
}
static void MT_CMD_END(usf_state_t * state, int rt)
{
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;
return;
}
static void MT_CMD_STATUS(usf_state_t * state, int rt)
{
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] & 0x00000002) << 0);
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)
{
message("MTC0\nCMD_CLOCK", 1); /* read-only?? */
message(state, "MTC0\nCMD_CLOCK", 1); /* read-only?? */
DPC_CLOCK_REG = state->SR[rt];
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];
//sprintf(text, "MTC0\nInvalid write attempt.\nstate->SR[%i] = 0x%08X", rt, state->SR[rt]);
//message(text, 2);
//message(state, text, 2);
return;
}
@ -419,14 +419,14 @@ INLINE static void LSV(usf_state_t * state, int vt, int element, int offset, int
if (e & 0x1)
{
message("LSV\nIllegal element.", 3);
message(state, "LSV\nIllegal element.", 3);
return;
}
addr = (state->SR[base] + 2*offset) & 0x00000FFF;
correction = addr % 0x004;
if (correction == 0x003)
{
message("LSV\nWeird addr.", 3);
message(state, "LSV\nWeird addr.", 3);
return;
}
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)
{
message("LLV\nOdd element.", 3);
message(state, "LLV\nOdd element.", 3);
return;
} /* Illegal (but still even) elements are used by Boss Game Studios. */
addr = (state->SR[base] + 4*offset) & 0x00000FFF;
if (addr & 0x00000001)
{
message("LLV\nOdd addr.", 3);
message(state, "LLV\nOdd addr.", 3);
return;
}
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)
{
message("LDV\nOdd element.", 3);
message(state, "LDV\nOdd element.", 3);
return;
} /* Illegal (but still even) elements are used by Boss Game Studios. */
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 */
{
message("SLV\nIllegal element.", 3);
message(state, "SLV\nIllegal element.", 3);
return;
}
addr = (state->SR[base] + 4*offset) & 0x00000FFF;
if (addr & 0x00000001)
{
message("SLV\nOdd addr.", 3);
message(state, "SLV\nOdd addr.", 3);
return;
}
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)
{
message("LPV\nIllegal element.", 3);
message(state, "LPV\nIllegal element.", 3);
return;
}
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)
{
message("SPV\nIllegal element.", 3);
message(state, "SPV\nIllegal element.", 3);
return;
}
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)
{
message("SUV\nIllegal element.", 3);
message(state, "SUV\nIllegal element.", 3);
return;
}
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);
return;
default: /* Completely legal, just never seen it be done. */
message("SUV\nWeird addr.", 3);
message(state, "SUV\nWeird addr.", 3);
return;
}
}
@ -1070,13 +1070,13 @@ static void LHV(usf_state_t * state, int vt, int element, int offset, int base)
if (e != 0x0)
{
message("LHV\nIllegal element.", 3);
message(state, "LHV\nIllegal element.", 3);
return;
}
addr = (state->SR[base] + 16*offset) & 0x00000FFF;
if (addr & 0x0000000E)
{
message("LHV\nIllegal addr.", 3);
message(state, "LHV\nIllegal addr.", 3);
return;
}
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",
vt, element, offset & 0xFFF, base);
message(debugger, 3);*/
message(state, debugger, 3);*/
return;
}
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)
{
message("SHV\nIllegal element.", 3);
message(state, "SHV\nIllegal element.", 3);
return;
}
addr = (state->SR[base] + 16*offset) & 0x00000FFF;
if (addr & 0x0000000E)
{
message("SHV\nIllegal addr.", 3);
message(state, "SHV\nIllegal addr.", 3);
return;
}
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);
return;
default:
message("SFV\nIllegal element.", 3);
message(state, "SFV\nIllegal element.", 3);
return;
}
}
@ -1172,13 +1172,13 @@ INLINE static void LQV(usf_state_t * state, int vt, int element, int offset, int
if (e & 0x1)
{
message("LQV\nOdd element.", 3);
message(state, "LQV\nOdd element.", 3);
return;
}
addr = (state->SR[base] + 16*offset) & 0x00000FFF;
if (addr & 0x00000001)
{
message("LQV\nOdd addr.", 3);
message(state, "LQV\nOdd addr.", 3);
return;
}
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)
{
message("LRV\nIllegal element.", 3);
message(state, "LRV\nIllegal element.", 3);
return;
}
addr = (state->SR[base] + 16*offset) & 0x00000FFF;
if (addr & 0x00000001)
{
message("LRV\nOdd addr.", 3);
message(state, "LRV\nOdd addr.", 3);
return;
}
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];
return;
default:
message("SQV\nWeird addr.", 3);
message(state, "SQV\nWeird addr.", 3);
return;
}
}
@ -1372,13 +1372,13 @@ static void SRV(usf_state_t * state, int vt, int element, int offset, int base)
if (e != 0x0)
{
message("SRV\nIllegal element.", 3);
message(state, "SRV\nIllegal element.", 3);
return;
}
addr = (state->SR[base] + 16*offset) & 0x00000FFF;
if (addr & 0x00000001)
{
message("SRV\nOdd addr.", 3);
message(state, "SRV\nOdd addr.", 3);
return;
}
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)
{
message("LTV\nIllegal element.", 3);
message(state, "LTV\nIllegal element.", 3);
return;
}
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. */
}
addr = (state->SR[base] + 16*offset) & 0x00000FFF;
if (addr & 0x0000000F)
{
message("LTV\nIllegal addr.", 3);
message(state, "LTV\nIllegal addr.", 3);
return;
}
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",
vt, element, offset & 0xFFF, base);
message(debugger, 3);*/
message(state, debugger, 3);*/
return;
}
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)
{
message("STV\nIllegal element.", 3);
message(state, "STV\nIllegal element.", 3);
return;
}
if (vt & 07)
{
message("STV\nUncertain case!", 2);
message(state, "STV\nUncertain case!", 2);
return; /* vt &= 030; */
}
addr = (state->SR[base] + 16*offset) & 0x00000FFF;
if (addr & 0x0000000F)
{
message("STV\nIllegal addr.", 3);
message(state, "STV\nIllegal addr.", 3);
return;
}
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 */
if (vd != vs || vt != e)
return;
message("VMACQ\nUnimplemented.", 3); /* untested, any N64 ROMs use this?? */
message(state, "VMACQ\nUnimplemented.", 3); /* untested, any N64 ROMs use this?? */
return;
}

View File

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

View File

@ -16,7 +16,7 @@
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];
do_div(state, state->DivIn, SP_DIV_SQRT_YES, SP_DIV_PRECISION_SINGLE);
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)
{
message("VSAR\nInvalid mask.", 2);
message(state, "VSAR\nInvalid mask.", 2);
for (i = 0; i < N; i++)
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)
{ /* 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++)
state->VR[vd][i] = 0x0000; /* override behavior (zilmar) */
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;
if (vs != vt || vt != e)
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++)
state->VR[vd][i] = 0x0000; /* override behavior (bpoint) */
return;
}
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);
return; /* Ultra64 OS did have these, so one could implement this ext. */
}

View File

@ -14,7 +14,7 @@
#include "usf_internal.h"
size_t get_usf_state_size()
size_t usf_get_state_size()
{
return sizeof(usf_state_t) + 8192;
}
@ -22,7 +22,7 @@ size_t get_usf_state_size()
void usf_clear(void * state)
{
size_t offset;
memset(state, 0, get_usf_state_size());
memset(state, 0, usf_get_state_size());
offset = 4096 - (((uintptr_t)state) & 4095);
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;
}
static void usf_startup(void * state)
static int usf_startup(void * state)
{
// 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)
USF_STATE->RdramSize = 0x800000;
Allocate_Memory(state);
if ( !Allocate_Memory(state) )
return -1;
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 )
usf_startup( USF_STATE );
{
if ( usf_startup( USF_STATE ) < 0 )
return USF_STATE->last_error;
}
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 )
{
memmove( USF_STATE->samplebuf, USF_STATE->samplebuf + do_max * 2, sizeof(int16_t) * 2 * USF_STATE->samples_in_buffer );
return;
return 0;
}
if ( buffer )
@ -213,6 +222,8 @@ void usf_render(void * state, int16_t * buffer, size_t count, int32_t * sample_r
if ( sample_rate )
*sample_rate = USF_STATE->SampleRate;
return USF_STATE->last_error;
}
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.
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. */
void usf_render(void * state, int16_t * buffer, size_t count, int32_t * sample_rate);
sample rate in the variable passed in.
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
discards any buffered sample data. */

View File

@ -71,6 +71,9 @@ struct usf_state
int16_t samplebuf[16384];
size_t samples_in_buffer;
const char * last_error;
char error_message[1024];
// cpu.c
uint32_t NextInstruction, JumpToLocation, AudioIntrReg;
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;
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 );
@ -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_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;
@ -1294,7 +1295,8 @@ static int usf_info(void * context, const char * name, const char * value)
{
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;
}
@ -1523,7 +1525,8 @@ static int usf_info(void * context, const char * name, const char * value)
{
ssize_t howmany = frame - framesRead;
if (howmany > 1024) howmany = 1024;
usf_render(emulatorCore, temp, howmany, NULL);
if ( usf_render(emulatorCore, temp, howmany, NULL) != 0 )
return -1;
framesRead += howmany;
} while (framesRead < frame);
}