void S9xDoHBlankProcessing_HBLANK_START_EVENT () { //START_PROFILE_FUNC (S9xDoHBlankProcessing); #ifdef CPU_SHUTDOWN CPUPack.CPU.WaitCounter++; #endif if (IPPU.HDMA && CPUPack.CPU.V_Counter <= PPU.ScreenHeight) IPPU.HDMA = S9xDoHDMA (IPPU.HDMA); S9xReschedule (); //FINISH_PROFILE_FUNC (S9xDoHBlankProcessing); }
int os9x_load(const char *ext) { FILE *savefile; const char *save_filename; os9x_externstate_mode=0; save_filename=S9xGetSaveFilename (ext); savefile=fopen(save_filename,"rb"); if (savefile) { fclose(savefile); S9xUnfreezeGame(save_filename); // S9xInitUpdate(); S9xReschedule (); return 1; } return 0; }
void SnesEmu::sl() { if (emsl.save) { S9xSRTCPreSaveState(); } else { S9xReset(); } snesCpuSl(); snesMemSl(); snesPpuSl(); snesDmaSl(); snesSoundSl(); snesSpuSl(); if (!emsl.save) { S9xFixSoundAfterSnapshotLoad(); S9xSetPCBase(ICPU.ShiftedPB + Registers.PC); S9xReschedule(); S9xSRTCPostLoadState(); if (Settings.SDD1) S9xSDD1PostLoadState(); S9xSetSoundMute(FALSE); } }
void S9xDoHBlankProcessing_HBLANK_END_EVENT () { //START_PROFILE_FUNC (S9xDoHBlankProcessing); #ifdef CPU_SHUTDOWN CPUPack.CPU.WaitCounter++; #endif if (Settings.SuperFX) S9xSuperFXExec (); cpu_glob_cycles += CPUPack.CPU.Cycles-old_cpu_cycles; CPUPack.CPU.Cycles -= Settings.H_Max; old_cpu_cycles=CPUPack.CPU.Cycles; #ifdef FAST_IAPU_APUEXECUTING_CHECK if (IAPU_APUExecuting_Main==false || APUExecuting_Main_Counter==0) IAPU_APUExecuting_Main = IAPU_APUExecuting; if (IAPU_APUExecuting_Main){ apu_glob_cycles_Main=cpu_glob_cycles; if (cpu_glob_cycles>=0x00700000) { APU_EXECUTE2(); } } else { apu_glob_cycles=apu_glob_cycles_Main=0; Uncache_APU_Cycles = 0; } if (APUExecuting_Main_Counter==0){ FLUSH_APU(); } #else //(IAPUuncached.NextAPUTimerPos) -= (Settings.H_Max * 10000L); if ( (IAPU_APUExecuting_Main)) { //(APUPack.APU.Cycles) -= Settings.H_Max; apu_glob_cycles=cpu_glob_cycles; #ifdef ME_SOUND if (cpu_glob_cycles>=0x00700000) { APU_EXECUTE2 (); } #else // if (cpu_glob_cycles>=0x00000000) { // APU_EXECUTE2 (); // } #endif } else { //(APUPack.APU.Cycles) = 0; apu_glob_cycles=0; Uncache_APU_Cycles = 0; } #endif CPUPack.CPU.NextEvent = -1; // not use // CPUPack.ICPU.Scanline++; if (++CPUPack.CPU.V_Counter > (Settings.PAL ? SNES_MAX_PAL_VCOUNTER : SNES_MAX_NTSC_VCOUNTER)) { //PPU.OAMAddr = PPU.SavedOAMAddr; //PPU.OAMFlip = 0; CPUPack.CPU.V_Counter = 0; ROM_GLOBAL[0x213F]^=0x80; CPUPack.CPU.NMIActive = FALSE; //CPUPack.ICPU.Frame++; PPU.HVBeamCounterLatched = 0; CPUPack.CPU.Flags |= SCAN_KEYS_FLAG; S9xStartHDMA (); } if (PPU.VTimerEnabled && !PPU.HTimerEnabled && CPUPack.CPU.V_Counter == PPU.IRQVBeamPos) S9xSetIRQ (PPU_V_BEAM_IRQ_SOURCE); #if (1) // pEvent->apu_event1[pEvent->apu_event1_cpt2 & 0xFFFF]=(os9x_apu_ratio != 256) ? cpu_glob_cycles * os9x_apu_ratio / 256: cpu_glob_cycles; // pEvent->apu_event1_cpt2++; uint32 EventVal = (os9x_apu_ratio != 256) ? cpu_glob_cycles * os9x_apu_ratio / 256: cpu_glob_cycles; if (CPUPack.CPU.V_Counter & 1) { EventVal |= 0x80000000; } #ifdef ME_SOUND int pos=apu_event1_cpt2_main++; apu_event1[pos & APU_EVENT_MASK] = EventVal; apu_event1_cpt2=apu_event1_cpt2_main; #else int pos=apu_event1_cpt2; apu_event1[pos & APU_EVENT_MASK] = EventVal; apu_event1_cpt2=pos+1; #endif //APU_EXECUTE2 (); /*if ((APUPack.APU.TimerEnabled) [2]) { (APUPack.APU.Timer) [2] += 4; while ((APUPack.APU.Timer) [2] >= (APUPack.APU.TimerTarget) [2]) { (IAPUuncached.RAM) [0xff] = ((IAPUuncached.RAM) [0xff] + 1) & 0xf; (APUPack.APU.Timer) [2] -= (APUPack.APU.TimerTarget) [2]; #ifdef SPC700_SHUTDOWN (IAPUuncached.WaitCounter)++; (IAPU_APUExecuting)= TRUE; #endif } }*/ #else if (CPUPack.CPU.V_Counter & 1) { apu_event2[(apu_event2_cpt2)&0xFFFF]=cpu_glob_cycles * os9x_apu_ratio / 256; (apu_event2_cpt2)++; /*if ((APUPack.APU.TimerEnabled) [0]) { (APUPack.APU.Timer) [0]++; if ((APUPack.APU.Timer) [0] >= (APUPack.APU.TimerTarget) [0]) { (IAPUuncached.RAM) [0xfd] = ((IAPUuncached.RAM) [0xfd] + 1) & 0xf; (APUPack.APU.Timer) [0] = 0; #ifdef SPC700_SHUTDOWN (IAPUuncached.WaitCounter)++; (IAPU_APUExecuting)= TRUE; #endif } } if ((APUPack.APU.TimerEnabled) [1]) { (APUPack.APU.Timer) [1]++; if ((APUPack.APU.Timer) [1] >= (APUPack.APU.TimerTarget) [1]) { (IAPUuncached.RAM) [0xfe] = ((IAPUuncached.RAM) [0xfe] + 1) & 0xf; (APUPack.APU.Timer) [1] = 0; #ifdef SPC700_SHUTDOWN (IAPUuncached.WaitCounter)++; (IAPU_APUExecuting) = TRUE; #endif } }*/ } #endif if (CPUPack.CPU.V_Counter == FIRST_VISIBLE_LINE) { ROM_GLOBAL[0x4210] = 0; CPUPack.CPU.Flags &= ~NMI_FLAG; S9xStartScreenRefresh (); } if (CPUPack.CPU.V_Counter >= FIRST_VISIBLE_LINE && CPUPack.CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE) { RenderLine (CPUPack.CPU.V_Counter - FIRST_VISIBLE_LINE); S9xReschedule (); //FINISH_PROFILE_FUNC (S9xDoHBlankProcessing); return; } if (CPUPack.CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE) { // Start of V-blank S9xEndScreenRefresh (); //PPU.FirstSprite = 0; IPPU.HDMA = 0; // Bits 7 and 6 of $4212 are computed when read in S9xGetPPU. #ifdef DEBUGGER missing.dma_this_frame = 0; #endif IPPU.MaxBrightness = PPU.Brightness; PPU.ForcedBlanking = (ROM_GLOBAL[0x2100] >> 7) & 1; if(!PPU.ForcedBlanking){ PPU.OAMAddr = PPU.SavedOAMAddr; uint8 tmp = 0; if(PPU.OAMPriorityRotation) tmp = (PPU.OAMAddr&0xFE)>>1; if((PPU.OAMFlip&1) || PPU.FirstSprite!=tmp){ PPU.FirstSprite=tmp; IPPU.OBJChanged=TRUE; } PPU.OAMFlip = 0; }
void S9xDoHEventProcessing (void) { #ifdef DEBUGGER static char eventname[7][32] = { "", "HC_HBLANK_START_EVENT", "HC_HDMA_START_EVENT ", "HC_HCOUNTER_MAX_EVENT", "HC_HDMA_INIT_EVENT ", "HC_RENDER_EVENT ", "HC_WRAM_REFRESH_EVENT" }; #endif #ifdef DEBUGGER if (Settings.TraceHCEvent) S9xTraceFormattedMessage("--- HC event processing (%s) expected HC:%04d executed HC:%04d", eventname[CPU.WhichEvent], CPU.NextEvent, CPU.Cycles); #endif switch (CPU.WhichEvent) { case HC_HBLANK_START_EVENT: S9xReschedule(); break; case HC_HDMA_START_EVENT: S9xReschedule(); if (PPU.HDMA && CPU.V_Counter <= PPU.ScreenHeight) { #ifdef DEBUGGER S9xTraceFormattedMessage("*** HDMA Transfer HC:%04d, Channel:%02x", CPU.Cycles, PPU.HDMA); #endif PPU.HDMA = S9xDoHDMA(PPU.HDMA); } break; case HC_HCOUNTER_MAX_EVENT: if (Settings.SuperFX) { if (!SuperFX.oneLineDone) S9xSuperFXExec(); SuperFX.oneLineDone = FALSE; } S9xAPUEndScanline(); CPU.Cycles -= Timings.H_Max; CPU.PrevCycles -= Timings.H_Max; S9xAPUSetReferenceTime(CPU.Cycles); if ((Timings.NMITriggerPos != 0xffff) && (Timings.NMITriggerPos >= Timings.H_Max)) Timings.NMITriggerPos -= Timings.H_Max; CPU.V_Counter++; if (CPU.V_Counter >= Timings.V_Max) // V ranges from 0 to Timings.V_Max - 1 { CPU.V_Counter = 0; Timings.InterlaceField ^= 1; // From byuu: // [NTSC] // interlace mode has 525 scanlines: 263 on the even frame, and 262 on the odd. // non-interlace mode has 524 scanlines: 262 scanlines on both even and odd frames. // [PAL] <PAL info is unverified on hardware> // interlace mode has 625 scanlines: 313 on the even frame, and 312 on the odd. // non-interlace mode has 624 scanlines: 312 scanlines on both even and odd frames. if (IPPU.Interlace && !Timings.InterlaceField) Timings.V_Max = Timings.V_Max_Master + 1; // 263 (NTSC), 313?(PAL) else Timings.V_Max = Timings.V_Max_Master; // 262 (NTSC), 312?(PAL) Memory.FillRAM[0x213F] ^= 0x80; PPU.RangeTimeOver = 0; // FIXME: reading $4210 will wait 2 cycles, then perform reading, then wait 4 more cycles. Memory.FillRAM[0x4210] = Model->_5A22; CPU.NMILine = FALSE; Timings.NMITriggerPos = 0xffff; ICPU.Frame++; PPU.HVBeamCounterLatched = 0; CPU.Flags |= SCAN_KEYS_FLAG; } // From byuu: // In non-interlace mode, there are 341 dots per scanline, and 262 scanlines per frame. // On odd frames, scanline 240 is one dot short. // In interlace mode, there are always 341 dots per scanline. Even frames have 263 scanlines, // and odd frames have 262 scanlines. // Interlace mode scanline 240 on odd frames is not missing a dot. if (CPU.V_Counter == 240 && !IPPU.Interlace && Timings.InterlaceField) // V=240 Timings.H_Max = Timings.H_Max_Master - ONE_DOT_CYCLE; // HC=1360 else Timings.H_Max = Timings.H_Max_Master; // HC=1364 if (Model->_5A22 == 2) { if (CPU.V_Counter != 240 || IPPU.Interlace || !Timings.InterlaceField) // V=240 { if (Timings.WRAMRefreshPos == SNES_WRAM_REFRESH_HC_v2 - ONE_DOT_CYCLE) // HC=534 Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2; // HC=538 else Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2 - ONE_DOT_CYCLE; // HC=534 } } else Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v1; if (CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE) // VBlank starts from V=225(240). { S9xEndScreenRefresh(); PPU.HDMA = 0; // Bits 7 and 6 of $4212 are computed when read in S9xGetPPU. #ifdef DEBUGGER missing.dma_this_frame = 0; #endif IPPU.MaxBrightness = PPU.Brightness; PPU.ForcedBlanking = (Memory.FillRAM[0x2100] >> 7) & 1; if (!PPU.ForcedBlanking) { PPU.OAMAddr = PPU.SavedOAMAddr; uint8 tmp = 0; if (PPU.OAMPriorityRotation) tmp = (PPU.OAMAddr & 0xFE) >> 1; if ((PPU.OAMFlip & 1) || PPU.FirstSprite != tmp) { PPU.FirstSprite = tmp; IPPU.OBJChanged = TRUE; } PPU.OAMFlip = 0; } // FIXME: writing to $4210 will wait 6 cycles. Memory.FillRAM[0x4210] = 0x80 | Model->_5A22; if (Memory.FillRAM[0x4200] & 0x80) { // FIXME: triggered at HC=6, checked just before the final CPU cycle, // then, when to call S9xOpcode_NMI()? CPU.NMILine = TRUE; Timings.NMITriggerPos = 6 + 6; } }
static int ReadOrigSnapshot (STREAM snap) { char buffer [_MAX_PATH]; char rom_filename [_MAX_PATH]; int result; int i; int j; int version; int len = strlen (ORIG_SNAPSHOT_MAGIC) + 1 + 4 + 1; if (READ_STREAM (buffer, len, snap) != len) return (WRONG_FORMAT); if (strncmp (buffer, ORIG_SNAPSHOT_MAGIC, strlen (ORIG_SNAPSHOT_MAGIC)) != 0) return (WRONG_FORMAT); if ((version = atoi (&buffer [strlen (SNAPSHOT_MAGIC) + 1])) > ORIG_SNAPSHOT_VERSION) return (WRONG_VERSION); if ((result = ReadBlock ("NAM:", rom_filename, _MAX_PATH, snap)) != SUCCESS) return (result); if ((result = ReadBlock ("HiR:", buffer, 0x41, snap)) != SUCCESS) return (result); if (strcasecmp (rom_filename, Memory.ROMFilename) != 0 && strcasecmp (S9xBasename (rom_filename), S9xBasename (Memory.ROMFilename)) != 0) { S9xMessage (S9X_WARNING, S9X_FREEZE_ROM_NAME, "Current loaded ROM image doesn't match that required by freeze-game file."); } S9xReset (); S9xSetSoundMute (TRUE); if ((result = ReadBlock ("CPU:", &OrigCPU, sizeof (OrigCPU), snap)) != SUCCESS) return (result); OrigCPU.FastROMSpeed = OrigCPU.FastROMSpeed_old; Memory.FixROMSpeed (); if (version == 3) { OrigCPU.Cycles = OrigCPU.Cycles_old; OrigCPU.NextEvent = OrigCPU.NextEvent_old; OrigCPU.V_Counter = OrigCPU.V_Counter_old; OrigCPU.MemSpeed = OrigCPU.MemSpeed_old; OrigCPU.MemSpeedx2 = OrigCPU.MemSpeedx2_old; OrigCPU.FastROMSpeed = OrigCPU.FastROMSpeed_old; } CPU.Flags = OrigCPU.Flags; CPU.BranchSkip = OrigCPU.BranchSkip; CPU.NMIActive = OrigCPU.NMIActive; CPU.IRQActive = OrigCPU.IRQActive; CPU.WaitingForInterrupt = OrigCPU.WaitingForInterrupt; CPU.WhichEvent = OrigCPU.WhichEvent; CPU.Cycles = OrigCPU.Cycles; CPU.NextEvent = OrigCPU.NextEvent; CPU.V_Counter = OrigCPU.V_Counter; CPU.MemSpeed = OrigCPU.MemSpeed; CPU.MemSpeedx2 = OrigCPU.MemSpeedx2; CPU.FastROMSpeed = OrigCPU.FastROMSpeed; if ((result = ReadBlock ("REG:", &OrigRegisters, sizeof (OrigRegisters), snap)) != SUCCESS) return (result); Registers = *(struct SRegisters *) &OrigRegisters; if ((result = ReadBlock ("PPU:", &OrigPPU, sizeof (OrigPPU), snap)) != SUCCESS) return (result); if (version == 2) { OrigPPU.OBJNameSelect = OrigPPU.OBJNameSelect_old << 13; OrigPPU.OBJNameBase <<= 1; OrigPPU.OBJNameSelect <<= 13; } PPU.BGMode = OrigPPU.BGMode; PPU.BG3Priority = OrigPPU.BG3Priority; PPU.Brightness = OrigPPU.Brightness; PPU.VMA.High = OrigPPU.VMA.High; PPU.VMA.Increment = OrigPPU.VMA.Increment; PPU.VMA.Address = OrigPPU.VMA.Address; PPU.VMA.Mask1 = OrigPPU.VMA.Mask1; PPU.VMA.FullGraphicCount = OrigPPU.VMA.FullGraphicCount; PPU.VMA.Shift = OrigPPU.VMA.Shift; for (i = 0; i < 4; i++) { PPU.BG[i].SCBase = OrigPPU.BG[i].SCBase; PPU.BG[i].VOffset = OrigPPU.BG[i].VOffset; PPU.BG[i].HOffset = OrigPPU.BG[i].HOffset; PPU.BG[i].BGSize = OrigPPU.BG[i].BGSize; PPU.BG[i].NameBase = OrigPPU.BG[i].NameBase; PPU.BG[i].SCSize = OrigPPU.BG[i].SCSize; } PPU.CGFLIP = OrigPPU.CGFLIP; for (i = 0; i < 256; i++) PPU.CGDATA [i] = OrigPPU.CGDATA [i]; PPU.FirstSprite = OrigPPU.FirstSprite; for (i = 0; i < 128; i++) { PPU.OBJ[i].HPos = OrigPPU.OBJ [i].HPos; PPU.OBJ[i].VPos = OrigPPU.OBJ [i].VPos; PPU.OBJ[i].Name = OrigPPU.OBJ [i].Name; PPU.OBJ[i].VFlip = OrigPPU.OBJ [i].VFlip; PPU.OBJ[i].HFlip = OrigPPU.OBJ [i].HFlip; PPU.OBJ[i].Priority = OrigPPU.OBJ [i].Priority; PPU.OBJ[i].Palette = OrigPPU.OBJ [i].Palette; PPU.OBJ[i].Size = OrigPPU.OBJ [i].Size; } PPU.OAMPriorityRotation = OrigPPU.OAMPriorityRotation; PPU.OAMAddr = OrigPPU.OAMAddr; PPU.OAMFlip = OrigPPU.OAMFlip; PPU.OAMTileAddress = OrigPPU.OAMTileAddress; PPU.IRQVBeamPos = OrigPPU.IRQVBeamPos; PPU.IRQHBeamPos = OrigPPU.IRQHBeamPos; PPU.VBeamPosLatched = OrigPPU.VBeamPosLatched; PPU.HBeamPosLatched = OrigPPU.HBeamPosLatched; PPU.HBeamFlip = OrigPPU.HBeamFlip; PPU.VBeamFlip = OrigPPU.VBeamFlip; PPU.HVBeamCounterLatched = OrigPPU.HVBeamCounterLatched; PPU.MatrixA = OrigPPU.MatrixA; PPU.MatrixB = OrigPPU.MatrixB; PPU.MatrixC = OrigPPU.MatrixC; PPU.MatrixD = OrigPPU.MatrixD; PPU.CentreX = OrigPPU.CentreX; PPU.CentreY = OrigPPU.CentreY; PPU.Joypad1ButtonReadPos = OrigPPU.Joypad1ButtonReadPos; PPU.Joypad2ButtonReadPos = OrigPPU.Joypad2ButtonReadPos; PPU.Joypad3ButtonReadPos = OrigPPU.Joypad3ButtonReadPos; PPU.CGADD = OrigPPU.CGADD; PPU.FixedColourRed = OrigPPU.FixedColourRed; PPU.FixedColourGreen = OrigPPU.FixedColourGreen; PPU.FixedColourBlue = OrigPPU.FixedColourBlue; PPU.SavedOAMAddr = OrigPPU.SavedOAMAddr; PPU.ScreenHeight = OrigPPU.ScreenHeight; PPU.WRAM = OrigPPU.WRAM; PPU.ForcedBlanking = OrigPPU.ForcedBlanking; PPU.OBJNameSelect = OrigPPU.OBJNameSelect; PPU.OBJSizeSelect = OrigPPU.OBJSizeSelect; PPU.OBJNameBase = OrigPPU.OBJNameBase; PPU.OAMReadFlip = OrigPPU.OAMReadFlip; memmove (PPU.OAMData, OrigPPU.OAMData, sizeof (PPU.OAMData)); PPU.VTimerEnabled = OrigPPU.VTimerEnabled; PPU.HTimerEnabled = OrigPPU.HTimerEnabled; PPU.HTimerPosition = OrigPPU.HTimerPosition; PPU.Mosaic = OrigPPU.Mosaic; memmove (PPU.BGMosaic, OrigPPU.BGMosaic, sizeof (PPU.BGMosaic)); PPU.Mode7HFlip = OrigPPU.Mode7HFlip; PPU.Mode7VFlip = OrigPPU.Mode7VFlip; PPU.Mode7Repeat = OrigPPU.Mode7Repeat; PPU.Window1Left = OrigPPU.Window1Left; PPU.Window1Right = OrigPPU.Window1Right; PPU.Window2Left = OrigPPU.Window2Left; PPU.Window2Right = OrigPPU.Window2Right; for (i = 0; i < 6; i++) { PPU.ClipWindowOverlapLogic [i] = OrigPPU.ClipWindowOverlapLogic [i]; PPU.ClipWindow1Enable [i] = OrigPPU.ClipWindow1Enable [i]; PPU.ClipWindow2Enable [i] = OrigPPU.ClipWindow2Enable [i]; PPU.ClipWindow1Inside [i] = OrigPPU.ClipWindow1Inside [i]; PPU.ClipWindow2Inside [i] = OrigPPU.ClipWindow2Inside [i]; } PPU.CGFLIPRead = OrigPPU.CGFLIPRead; PPU.Need16x8Mulitply = OrigPPU.Need16x8Mulitply; IPPU.ColorsChanged = TRUE; IPPU.OBJChanged = TRUE; S9xFixColourBrightness (); IPPU.RenderThisFrame = FALSE; if ((result = ReadBlock ("DMA:", OrigDMA, sizeof (OrigDMA), snap)) != SUCCESS) return (result); for (i = 0; i < 8; i++) { DMA[i].TransferDirection = OrigDMA[i].TransferDirection; DMA[i].AAddressFixed = OrigDMA[i].AAddressFixed; DMA[i].AAddressDecrement = OrigDMA[i].AAddressDecrement; DMA[i].TransferMode = OrigDMA[i].TransferMode; DMA[i].ABank = OrigDMA[i].ABank; DMA[i].AAddress = OrigDMA[i].AAddress; DMA[i].Address = OrigDMA[i].Address; DMA[i].BAddress = OrigDMA[i].BAddress; DMA[i].TransferBytes = OrigDMA[i].TransferBytes; DMA[i].HDMAIndirectAddressing = OrigDMA[i].HDMAIndirectAddressing; DMA[i].IndirectAddress = OrigDMA[i].IndirectAddress; DMA[i].IndirectBank = OrigDMA[i].IndirectBank; DMA[i].Repeat = OrigDMA[i].Repeat; DMA[i].LineCount = OrigDMA[i].LineCount; DMA[i].FirstLine = OrigDMA[i].FirstLine; } if ((result = ReadBlock ("VRA:", Memory.VRAM, 0x10000, snap)) != SUCCESS) return (result); if ((result = ReadBlock ("RAM:", Memory.RAM, 0x20000, snap)) != SUCCESS) return (result); if ((result = ReadBlock ("SRA:", Memory.SRAM, 0x10000, snap)) != SUCCESS) return (result); if ((result = ReadBlock ("FIL:", Memory.FillRAM, 0x8000, snap)) != SUCCESS) return (result); if (ReadBlock ("APU:", &OrigAPU, sizeof (OrigAPU), snap) == SUCCESS) { APU = *(struct SAPU *) &OrigAPU; if ((result = ReadBlock ("ARE:", &OrigAPURegisters, sizeof (OrigAPURegisters), snap)) != SUCCESS) return (result); APURegisters = *(struct SAPURegisters *) &OrigAPURegisters; if ((result = ReadBlock ("ARA:", IAPU.RAM, 0x10000, snap)) != SUCCESS) return (result); if ((result = ReadBlock ("SOU:", &OrigSoundData, sizeof (SOrigSoundData), snap)) != SUCCESS) return (result); SoundData.master_volume_left = OrigSoundData.master_volume_left; SoundData.master_volume_right = OrigSoundData.master_volume_right; SoundData.echo_volume_left = OrigSoundData.echo_volume_left; SoundData.echo_volume_right = OrigSoundData.echo_volume_right; SoundData.echo_enable = OrigSoundData.echo_enable; SoundData.echo_feedback = OrigSoundData.echo_feedback; SoundData.echo_ptr = OrigSoundData.echo_ptr; SoundData.echo_buffer_size = OrigSoundData.echo_buffer_size; SoundData.echo_write_enabled = OrigSoundData.echo_write_enabled; SoundData.echo_channel_enable = OrigSoundData.echo_channel_enable; SoundData.pitch_mod = OrigSoundData.pitch_mod; for (i = 0; i < 3; i++) SoundData.dummy [i] = OrigSoundData.dummy [i]; for (i = 0; i < NUM_CHANNELS; i++) { SoundData.channels [i].state = OrigSoundData.channels [i].state; SoundData.channels [i].type = OrigSoundData.channels [i].type; SoundData.channels [i].volume_left = OrigSoundData.channels [i].volume_left; SoundData.channels [i].volume_right = OrigSoundData.channels [i].volume_right; SoundData.channels [i].hertz = OrigSoundData.channels [i].frequency; SoundData.channels [i].count = OrigSoundData.channels [i].count; SoundData.channels [i].loop = OrigSoundData.channels [i].loop; SoundData.channels [i].envx = OrigSoundData.channels [i].envx; SoundData.channels [i].left_vol_level = OrigSoundData.channels [i].left_vol_level; SoundData.channels [i].right_vol_level = OrigSoundData.channels [i].right_vol_level; SoundData.channels [i].envx_target = OrigSoundData.channels [i].envx_target; SoundData.channels [i].env_error = OrigSoundData.channels [i].env_error; SoundData.channels [i].erate = OrigSoundData.channels [i].erate; SoundData.channels [i].direction = OrigSoundData.channels [i].direction; SoundData.channels [i].attack_rate = OrigSoundData.channels [i].attack_rate; SoundData.channels [i].decay_rate = OrigSoundData.channels [i].decay_rate; SoundData.channels [i].sustain_rate = OrigSoundData.channels [i].sustain_rate; SoundData.channels [i].release_rate = OrigSoundData.channels [i].release_rate; SoundData.channels [i].sustain_level = OrigSoundData.channels [i].sustain_level; SoundData.channels [i].sample = OrigSoundData.channels [i].sample; for (j = 0; j < 16; j++) SoundData.channels [i].decoded [j] = OrigSoundData.channels [i].decoded [j]; for (j = 0; j < 2; j++) SoundData.channels [i].previous [j] = OrigSoundData.channels [i].previous [j]; SoundData.channels [i].sample_number = OrigSoundData.channels [i].sample_number; SoundData.channels [i].last_block = OrigSoundData.channels [i].last_block; SoundData.channels [i].needs_decode = OrigSoundData.channels [i].needs_decode; SoundData.channels [i].block_pointer = OrigSoundData.channels [i].block_pointer; SoundData.channels [i].sample_pointer = OrigSoundData.channels [i].sample_pointer; SoundData.channels [i].mode = OrigSoundData.channels [i].mode; } S9xSetSoundMute (FALSE); IAPU.PC = IAPU.RAM + APURegisters.PC; S9xAPUUnpackStatus (); if (APUCheckDirectPage ()) IAPU.DirectPage = IAPU.RAM + 0x100; else IAPU.DirectPage = IAPU.RAM; Settings.APUEnabled = TRUE; IAPU.APUExecuting = TRUE; } else { Settings.APUEnabled = FALSE; IAPU.APUExecuting = FALSE; S9xSetSoundMute (TRUE); } S9xFixSoundAfterSnapshotLoad (1); ICPU.ShiftedPB = Registers.PB << 16; ICPU.ShiftedDB = Registers.DB << 16; S9xSetPCBase (ICPU.ShiftedPB + Registers.PC); S9xUnpackStatus (); S9xFixCycles (); S9xReschedule (); return (SUCCESS); }
static int Unfreeze() { // notaz: overflowing the damn Symbian stack again char buffer [16]; char rom_filename [512]; int result; int version; unsigned int len = strlen(SNAPSHOT_MAGIC) + 1 + 4 + 1; if (statef_read(buffer, len) != (int)len) return (WRONG_FORMAT); if (strncmp(buffer, SNAPSHOT_MAGIC, strlen(SNAPSHOT_MAGIC)) != 0) return (WRONG_FORMAT); if ((version = atoi(&buffer [strlen(SNAPSHOT_MAGIC) + 1])) > SNAPSHOT_VERSION) return (WRONG_VERSION); if ((result = UnfreezeBlock("NAM", (uint8*) rom_filename, 512)) != SUCCESS) return (result); if (strcasecmp(rom_filename, Memory.ROMFilename) != 0 && strcasecmp(S9xBasename(rom_filename), S9xBasename(Memory.ROMFilename)) != 0) { S9xMessage(S9X_WARNING, S9X_FREEZE_ROM_NAME, "Current loaded ROM image doesn't match that required by freeze-game file."); } uint32 old_flags = CPU.Flags; #ifdef USE_SA1 uint32 sa1_old_flags = SA1.Flags; #endif S9xReset(); S9xSetSoundMute(TRUE); if ((result = UnfreezeStruct("CPU", &CPU, SnapCPU, COUNT(SnapCPU))) != SUCCESS) return (result); FixROMSpeed(); CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG | SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG); if ((result = UnfreezeStruct("REG", &Registers, SnapRegisters, COUNT(SnapRegisters))) != SUCCESS) return (result); if ((result = UnfreezeStruct("PPU", &PPU, SnapPPU, COUNT(SnapPPU))) != SUCCESS) return (result); IPPU.ColorsChanged = TRUE; IPPU.OBJChanged = TRUE; CPU.InDMA = FALSE; // Restore colors from PPU unsigned int i; for (i = 0; i < 256; i++) { IPPU.Red[i] = PPU.CGDATA[i] & 0x1f; IPPU.Green[i] = (PPU.CGDATA[i] >> 5) & 0x1f; IPPU.Blue[i] = (PPU.CGDATA[i] >> 10) & 0x1f; } S9xFixColourBrightness(); IPPU.RenderThisFrame = FALSE; if ((result = UnfreezeStruct("DMA", DMA, SnapDMA, COUNT(SnapDMA))) != SUCCESS) return (result); if ((result = UnfreezeBlock("VRA", Memory.VRAM, 0x10000)) != SUCCESS) return (result); if ((result = UnfreezeBlock("RAM", Memory.RAM, 0x20000)) != SUCCESS) return (result); if ((result = UnfreezeBlock("SRA", SRAM, 0x20000)) != SUCCESS) return (result); if ((result = UnfreezeBlock("FIL", Memory.FillRAM, 0x8000)) != SUCCESS) return (result); // Restore graphics shadow registers GFX.r212c_s = Memory.FillRAM[0x212c]; GFX.r212d_s = Memory.FillRAM[0x212d]; GFX.r212e_s = Memory.FillRAM[0x212e]; GFX.r212f_s = Memory.FillRAM[0x212f]; GFX.r2130_s = Memory.FillRAM[0x2130]; GFX.r2131_s = Memory.FillRAM[0x2131]; if (UnfreezeStruct("APU", &APU, SnapAPU, COUNT(SnapAPU)) == SUCCESS) { SAPURegisters spcregs; if ((result = UnfreezeStruct("ARE", &spcregs, SnapAPURegisters, COUNT(SnapAPURegisters))) != SUCCESS) return (result); // reload all SPC700 regs from savestate compatible struct IAPU.P = spcregs.P; IAPU.YA.W = spcregs.YA.W; IAPU.X = spcregs.X; IAPU.S = spcregs.S; IAPU.PC = IAPU.RAM + spcregs.PC; if ((result = UnfreezeBlock("ARA", IAPU.RAM, 0x10000)) != SUCCESS) return (result); if ((result = UnfreezeStruct("SOU", &SoundData, SnapSoundData, COUNT(SnapSoundData))) != SUCCESS) return (result); // notaz: just to be sure int u; for (u = 0; u < 8; u++) { SoundData.channels[u].env_ind_attack &= 0xf; SoundData.channels[u].env_ind_decay &= 0x7; SoundData.channels[u].env_ind_sustain &= 0x1f; } S9xSetSoundMute(FALSE); S9xAPUUnpackStatus(); if (APUCheckDirectPage()) IAPU.DirectPage = IAPU.RAM + 0x100; else IAPU.DirectPage = IAPU.RAM; Settings.APUEnabled = TRUE; /*IAPU.APUExecuting*/CPU.APU_APUExecuting = TRUE; } else { Settings.APUEnabled = FALSE; /*IAPU.APUExecuting*/CPU.APU_APUExecuting = FALSE; S9xSetSoundMute(TRUE); } #ifdef USE_SA1 if ((result = UnfreezeStruct("SA1", &SA1, SnapSA1, COUNT(SnapSA1))) == SUCCESS) { if ((result = UnfreezeStruct("SAR", &SA1Registers, SnapSA1Registers, COUNT(SnapSA1Registers))) != SUCCESS) return (result); S9xFixSA1AfterSnapshotLoad(); SA1.Flags |= sa1_old_flags & (TRACE_FLAG); } #endif S9xFixSoundAfterSnapshotLoad(); ICPU.ShiftedPB = Registers.PB << 16; ICPU.ShiftedDB = Registers.DB << 16; S9xSetPCBase(ICPU.ShiftedPB + Registers.PC); #ifndef ASMCPU S9xUnpackStatus(); // not needed S9xFixCycles(); // also not needed? #endif S9xReschedule(); S9xSRTCPostLoadState(); if (Settings.SDD1) S9xSDD1PostLoadState(); return (SUCCESS); }
void S9xDoHEventProcessing (void) { uint8 tmp; switch (CPU.WhichEvent) { case HC_HBLANK_START_EVENT: if (PPU.HTimerPosition == Timings.HBlankStart) S9xCheckMissingHTimerPosition(); S9xReschedule(); break; case HC_HDMA_START_EVENT: if (PPU.HTimerPosition == Timings.HDMAStart) S9xCheckMissingHTimerPosition(); S9xReschedule(); if (PPU.HDMA && CPU.V_Counter <= PPU.ScreenHeight) PPU.HDMA = S9xDoHDMA(PPU.HDMA); break; case HC_HCOUNTER_MAX_EVENT: if (Settings.SuperFX && !SuperFX.oneLineDone && CHECK_EXEC_SUPERFX()) S9xSuperFXExec(); SuperFX.oneLineDone = FALSE; // do this even without SFX S9xAPUExecute(); CPU.Cycles -= Timings.H_Max; S9xAPUSetReferenceTime(CPU.Cycles); if ((Timings.NMITriggerPos != 0xffff) && (Timings.NMITriggerPos >= Timings.H_Max)) Timings.NMITriggerPos -= Timings.H_Max; CPU.V_Counter++; if (CPU.V_Counter >= Timings.V_Max) /* V ranges from 0 to Timings.V_Max - 1 */ { CPU.V_Counter = 0; Timings.InterlaceField ^= 1; /* From byuu: [NTSC] interlace mode has 525 scanlines: 263 on the even frame, and 262 on the odd. non-interlace mode has 524 scanlines: 262 scanlines on both even and odd frames. [PAL] <PAL info is unverified on hardware> interlace mode has 625 scanlines: 313 on the even frame, and 312 on the odd. non-interlace mode has 624 scanlines: 312 scanlines on both even and odd frames. */ Timings.V_Max = Timings.V_Max_Master; /* 262 (NTSC), 312?(PAL) */ if (IPPU.Interlace && !Timings.InterlaceField) Timings.V_Max += 1; /* 263 (NTSC), 313?(PAL) */ Memory.FillRAM[0x213F] ^= 0x80; PPU.RangeTimeOver = 0; /* FIXME: reading $4210 will wait 2 cycles, then perform reading, then wait 4 more cycles. */ Memory.FillRAM[0x4210] = MAX_5A22_VERSION; CPU.Flags &= ~NMI_FLAG; Timings.NMITriggerPos = 0xffff; ICPU.Frame++; PPU.HVBeamCounterLatched = 0; CPU.Flags |= SCAN_KEYS_FLAG; } /* From byuu: In non-interlace mode, there are 341 dots per scanline, and 262 scanlines per frame. On odd frames, scanline 240 is one dot short. In interlace mode, there are always 341 dots per scanline. Even frames have 263 scanlines, and odd frames have 262 scanlines. Interlace mode scanline 240 on odd frames is not missing a dot. */ Timings.H_Max = Timings.H_Max_Master; /* HC=1364 */ if (CPU.V_Counter == 240 && !IPPU.Interlace && Timings.InterlaceField) /* V=240 */ Timings.H_Max -= ONE_DOT_CYCLE; /* HC=1360 */ if (CPU.V_Counter != 240 || IPPU.Interlace || !Timings.InterlaceField) /* V=240 */ { if (Timings.WRAMRefreshPos == SNES_WRAM_REFRESH_HC_v2_MIN_ONE_DOT_CYCLE) /* HC=534 */ Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2; /* HC=538 */ else Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2_MIN_ONE_DOT_CYCLE; /* HC=534 */ } if (PPU.HTimerPosition == 0) S9xCheckMissingHTimerPosition(); if (CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE) /* VBlank starts from V=225(240). */ { S9xEndScreenRefresh(); PPU.HDMA = 0; /* Bits 7 and 6 of $4212 are computed when read in S9xGetPPU. */ PPU.ForcedBlanking = (Memory.FillRAM[0x2100] >> 7) & 1; if (!PPU.ForcedBlanking) { PPU.OAMAddr = PPU.SavedOAMAddr; tmp = 0; if (PPU.OAMPriorityRotation) tmp = (PPU.OAMAddr & 0xFE) >> 1; if ((PPU.OAMFlip & 1) || PPU.FirstSprite != tmp) { PPU.FirstSprite = tmp; IPPU.OBJChanged = TRUE; } PPU.OAMFlip = 0; } /* FIXME: writing to $4210 will wait 6 cycles. */ Memory.FillRAM[0x4210] = 0x80 | MAX_5A22_VERSION; if (Memory.FillRAM[0x4200] & 0x80) { /* FIXME: triggered at HC=6, checked just before the final CPU cycle, then, when to call S9xOpcode_NMI()? */ CPU.Flags |= NMI_FLAG; Timings.NMITriggerPos = 6 + 6; } }