590 lines
16 KiB
C
590 lines
16 KiB
C
/*
|
|
* 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) {
|
|
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;
|
|
|
|
CheckInterrupts(state);
|
|
|
|
DPC_STATUS_REG &= ~0x0002;
|
|
return;
|
|
|
|
}
|
|
break;
|
|
case 2: {
|
|
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
|
|
break;
|
|
}
|
|
|
|
real_run_rsp(state, 100);
|
|
SP_STATUS_REG |= (0x0203 );
|
|
if ((SP_STATUS_REG & SP_STATUS_INTR_BREAK) != 0 ) {
|
|
MI_INTR_REG |= 1;
|
|
CheckInterrupts(state);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|