minor filename fixes
[drnoksnes] / cpuexec.cpp
1 /*
2  * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3  *
4  * (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and
5  *                           Jerremy Koot (jkoot@snes9x.com)
6  *
7  * Super FX C emulator code 
8  * (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and
9  *                           Gary Henderson.
10  * Super FX     assembler emulator code (c) Copyright 1998 zsKnight and _Demo_.
11  *
12  * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson.
13  * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_.
14  * C4 C code (c) Copyright 2001 Gary Henderson (gary.henderson@ntlworld.com).
15  *
16  * DOS port code contains the works of other authors. See headers in
17  * individual files.
18  *
19  * Snes9x homepage: http://www.snes9x.com
20  *
21  * Permission to use, copy, modify and distribute Snes9x in both binary and
22  * source form, for non-commercial purposes, is hereby granted without fee,
23  * providing that this license information and copyright notice appear with
24  * all copies and any derived work.
25  *
26  * This software is provided 'as-is', without any express or implied
27  * warranty. In no event shall the authors be held liable for any damages
28  * arising from the use of this software.
29  *
30  * Snes9x is freeware for PERSONAL USE only. Commercial users should
31  * seek permission of the copyright holders first. Commercial use includes
32  * charging money for Snes9x or software derived from Snes9x.
33  *
34  * The copyright holders request that bug fixes and improvements to the code
35  * should be forwarded to them so everyone can benefit from the modifications
36  * in future versions.
37  *
38  * Super NES and Super Nintendo Entertainment System are trademarks of
39  * Nintendo Co., Limited and its subsidiary companies.
40  */
41  
42
43  
44 #include "snes9x.h"
45
46 #include "memmap.h"
47 //#include "cpuops.h"
48 #include "ppu.h"
49 #include "cpuexec.h"
50 #include "debug.h"
51 #include "snapshot.h"
52 #include "gfx.h"
53 #include "missing.h"
54 #include "apu.h"
55 #include "dma.h"
56 #include "fxemu.h"
57 #ifdef USE_SA1
58 #include "sa1.h"
59 #endif
60
61
62 #include "os9x_asm_cpu.h"
63
64
65 // for asm core:
66 uint16 mem_check=0;
67
68
69 #if defined(__showframe__)
70 int framecpt=0;
71 #endif
72
73
74 void S9xMainLoop (void)
75 {       
76 #if defined(__showframe__)
77         framecpt++;
78         char stra[64];  
79         sprintf(stra,"framecpt : %d",framecpt);
80         S9xMessage(0,0,stra);
81 #endif  
82
83 //      asm_S9xMainLoop();
84         asmMainLoop(&CPU);
85
86     Registers.PC = CPU.PC - CPU.PCBase;
87     //S9xPackStatus (); // not needed
88     S9xAPUPackStatus ();
89     
90     if (CPU.Flags & SCAN_KEYS_FLAG)
91     {
92                 CPU.Flags &= ~SCAN_KEYS_FLAG;
93     }
94     
95     if (CPU.BRKTriggered && Settings.SuperFX && !CPU.TriedInterleavedMode2)
96     {
97         CPU.TriedInterleavedMode2 = TRUE;
98         CPU.BRKTriggered = FALSE;
99         S9xDeinterleaveMode2 ();
100     }
101 }
102
103 void S9xSetIRQ (uint32 source)
104 {
105     CPU.IRQActive |= source;
106     CPU.Flags |= IRQ_PENDING_FLAG;
107     CPU.IRQCycleCount = 3;
108     if (CPU.WaitingForInterrupt)
109     {
110         // Force IRQ to trigger immediately after WAI - 
111         // Final Fantasy Mystic Quest crashes without this.
112         CPU.IRQCycleCount = 0;
113         CPU.WaitingForInterrupt = FALSE;
114         CPU.PC++;
115     }
116 }
117
118 void S9xClearIRQ (uint32 source)
119 {
120     CLEAR_IRQ_SOURCE (source);
121 }
122
123
124 void S9xDoHBlankProcessing ()
125 {
126 #ifdef CPU_SHUTDOWN
127     CPU.WaitCounter++;
128 #endif
129     switch (CPU.WhichEvent)
130     {
131     case HBLANK_START_EVENT:
132                 if (IPPU.HDMA && CPU.V_Counter <= PPU.ScreenHeight)
133                         IPPU.HDMA = S9xDoHDMA (IPPU.HDMA);
134                 break;
135
136     case HBLANK_END_EVENT:
137                 APU_EXECUTE(3); // notaz: run spc700 in sound 'speed hack' mode
138
139                 if(Settings.SuperFX)
140                         S9xSuperFXExec ();
141
142                 CPU.Cycles -= Settings.H_Max;
143                 if (/*IAPU.APUExecuting*/CPU.APU_APUExecuting)
144                         CPU.APU_Cycles -= Settings.H_Max;
145                 else
146                         CPU.APU_Cycles = 0;
147
148                 CPU.NextEvent = -1;
149                 ICPU.Scanline++;
150
151                 if (++CPU.V_Counter > (Settings.PAL ? SNES_MAX_PAL_VCOUNTER : SNES_MAX_NTSC_VCOUNTER))
152                 {
153                         PPU.OAMAddr = PPU.SavedOAMAddr;
154                         PPU.OAMFlip = 0;
155                         CPU.V_Counter = 0;
156                         CPU.NMIActive = FALSE;
157                         ICPU.Frame++;
158                         PPU.HVBeamCounterLatched = 0;
159                         CPU.Flags |= SCAN_KEYS_FLAG;
160                         S9xStartHDMA ();
161                 }
162
163                 if (PPU.VTimerEnabled && !PPU.HTimerEnabled &&
164                         CPU.V_Counter == PPU.IRQVBeamPos)
165                 {
166                         S9xSetIRQ (PPU_V_BEAM_IRQ_SOURCE);
167                 }
168
169                 if (CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE)
170                 {
171                         // Start of V-blank
172                         S9xEndScreenRefresh ();
173                         PPU.FirstSprite = 0;
174                         IPPU.HDMA = 0;
175                         // Bits 7 and 6 of $4212 are computed when read in S9xGetPPU.
176                         missing.dma_this_frame = 0;
177                         IPPU.MaxBrightness = PPU.Brightness;
178                         PPU.ForcedBlanking = (Memory.FillRAM [0x2100] >> 7) & 1;
179
180                         Memory.FillRAM[0x4210] = 0x80;
181                         if (Memory.FillRAM[0x4200] & 0x80)
182                         {
183                         CPU.NMIActive = TRUE;
184                         CPU.Flags |= NMI_FLAG;
185                         CPU.NMICycleCount = CPU.NMITriggerPoint;
186                         }
187
188         #ifdef OLD_SNAPSHOT_CODE
189                         if (CPU.Flags & SAVE_SNAPSHOT_FLAG)
190                         {
191                         CPU.Flags &= ~SAVE_SNAPSHOT_FLAG;
192                         Registers.PC = CPU.PC - CPU.PCBase;
193                         //S9xPackStatus (); // not needed
194                         S9xAPUPackStatus ();
195                         Snapshot (NULL);
196                         }
197         #endif
198                         }
199
200                 if (CPU.V_Counter == PPU.ScreenHeight + 3)
201                         S9xUpdateJoypads ();
202
203                 if (CPU.V_Counter == FIRST_VISIBLE_LINE)
204                 {
205                         Memory.FillRAM[0x4210] = 0;
206                         CPU.Flags &= ~NMI_FLAG;
207                         S9xStartScreenRefresh ();
208                 }
209                 if (CPU.V_Counter >= FIRST_VISIBLE_LINE &&
210                         CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE)
211                 {
212                         RenderLine (CPU.V_Counter - FIRST_VISIBLE_LINE);
213                 }
214                 // Use TimerErrorCounter to skip update of SPC700 timers once
215                 // every 128 updates. Needed because this section of code is called
216                 // once every emulated 63.5 microseconds, which coresponds to
217                 // 15.750KHz, but the SPC700 timers need to be updated at multiples
218                 // of 8KHz, hence the error correction.
219         //      IAPU.TimerErrorCounter++;
220         //      if (IAPU.TimerErrorCounter >= )
221         //          IAPU.TimerErrorCounter = 0;
222         //      else
223                 {
224                         if (APU.TimerEnabled [2])
225                         {
226                         APU.Timer [2] += 4;
227                         while (APU.Timer [2] >= APU.TimerTarget [2])
228                         {
229                                 IAPU.RAM [0xff] = (IAPU.RAM [0xff] + 1) & 0xf;
230                                 APU.Timer [2] -= APU.TimerTarget [2];
231 #ifdef SPC700_SHUTDOWN          
232                                 IAPU.WaitCounter++;
233                                 /*IAPU.APUExecuting*/CPU.APU_APUExecuting= TRUE;
234 #endif          
235                         }
236                         }
237                         if (CPU.V_Counter & 1)
238                         {
239                         if (APU.TimerEnabled [0])
240                         {
241                                 APU.Timer [0]++;
242                                 if (APU.Timer [0] >= APU.TimerTarget [0])
243                                 {
244                                 IAPU.RAM [0xfd] = (IAPU.RAM [0xfd] + 1) & 0xf;
245                                 APU.Timer [0] = 0;
246 #ifdef SPC700_SHUTDOWN          
247                                 IAPU.WaitCounter++;
248                                 /*IAPU.APUExecuting*/CPU.APU_APUExecuting = TRUE;
249 #endif              
250                                 }
251                         }
252                         if (APU.TimerEnabled [1])
253                         {
254                                 APU.Timer [1]++;
255                                 if (APU.Timer [1] >= APU.TimerTarget [1])
256                                 {
257                                 IAPU.RAM [0xfe] = (IAPU.RAM [0xfe] + 1) & 0xf;
258                                 APU.Timer [1] = 0;
259 #ifdef SPC700_SHUTDOWN          
260                                 IAPU.WaitCounter++;
261                                 /*IAPU.APUExecuting*/CPU.APU_APUExecuting = TRUE;
262 #endif              
263                                 }
264                         }
265                         }
266                 }
267                 break;
268         case HTIMER_BEFORE_EVENT:
269         case HTIMER_AFTER_EVENT:
270                 if (PPU.HTimerEnabled &&
271                         (!PPU.VTimerEnabled || CPU.V_Counter == PPU.IRQVBeamPos))
272                 {
273                         S9xSetIRQ (PPU_H_BEAM_IRQ_SOURCE);
274                 }
275                 break;
276     }
277     S9xReschedule ();
278 }