1 /* gameplaySP
2 *
3 * Copyright (C) 2006 Exophase <exophase@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include "common.h"
21 #include <ctype.h>
22
23 timer_type timer[4];
24
25 u32 global_cycles_per_instruction = 1;
26
27 u32 cpu_ticks = 0;
28
29 u32 execute_cycles = 960;
30 s32 video_count = 960;
31 u32 ticks;
32
33 u32 arm_frame = 0;
34 u32 thumb_frame = 0;
35 u32 last_frame = 0;
36
37 u32 cycle_memory_access = 0;
38 u32 cycle_pc_relative_access = 0;
39 u32 cycle_sp_relative_access = 0;
40 u32 cycle_block_memory_access = 0;
41 u32 cycle_block_memory_sp_access = 0;
42 u32 cycle_block_memory_words = 0;
43 u32 cycle_dma16_words = 0;
44 u32 cycle_dma32_words = 0;
45 u32 flush_ram_count = 0;
46 u32 gbc_update_count = 0;
47 u32 oam_update_count = 0;
48
49 char main_path[512];
50 char save_path[512];
51
52 void trigger_ext_event(void);
53
update_timers(irq_type * irq_raised)54 static void update_timers(irq_type *irq_raised)
55 {
56 unsigned i;
57 for (i = 0; i < 4; i++)
58 {
59 if(timer[i].status == TIMER_INACTIVE)
60 continue;
61
62 if(timer[i].status != TIMER_CASCADE)
63 {
64 timer[i].count -= execute_cycles;
65 /* io_registers accessors range: REG_TM0D, REG_TM1D, REG_TM2D, REG_TM3D */
66 io_registers[128 + (i * 2)] = -(timer[i].count > timer[i].prescale);
67 }
68
69 if(timer[i].count > 0)
70 continue;
71
72 /* irq_raised value range: IRQ_TIMER0, IRQ_TIMER1, IRQ_TIMER2, IRQ_TIMER3 */
73 if(timer[i].irq == TIMER_TRIGGER_IRQ)
74 *irq_raised |= (8 << i);
75
76 if((i != 3) && (timer[i + 1].status == TIMER_CASCADE))
77 {
78 timer[i + 1].count--;
79 io_registers[REG_TM0D + (i + 1) * 2] = -(timer[i + 1].count);
80 }
81
82 if(i < 2)
83 {
84 if(timer[i].direct_sound_channels & 0x01)
85 sound_timer(timer[i].frequency_step, 0);
86
87 if(timer[i].direct_sound_channels & 0x02)
88 sound_timer(timer[i].frequency_step, 1);
89 }
90
91 timer[i].count += (timer[i].reload << timer[i].prescale);
92 }
93 }
94
init_main(void)95 void init_main(void)
96 {
97 u32 i;
98
99 for(i = 0; i < 4; i++)
100 {
101 dma[i].start_type = DMA_INACTIVE;
102 dma[i].direct_sound_channel = DMA_NO_DIRECT_SOUND;
103 timer[i].status = TIMER_INACTIVE;
104 timer[i].reload = 0x10000;
105 timer[i].stop_cpu_ticks = 0;
106 }
107
108 timer[0].direct_sound_channels = TIMER_DS_CHANNEL_BOTH;
109 timer[1].direct_sound_channels = TIMER_DS_CHANNEL_NONE;
110
111 cpu_ticks = 0;
112
113 execute_cycles = 960;
114 video_count = 960;
115
116 #ifdef HAVE_DYNAREC
117 flush_translation_cache_rom();
118 flush_translation_cache_ram();
119 flush_translation_cache_bios();
120 #endif
121 }
122
123 u32 no_alpha = 0;
124
update_gba(void)125 u32 update_gba(void)
126 {
127 irq_type irq_raised = IRQ_NONE;
128
129 do
130 {
131 unsigned i;
132 cpu_ticks += execute_cycles;
133
134 reg[CHANGED_PC_STATUS] = 0;
135
136 if(gbc_sound_update)
137 {
138 gbc_update_count++;
139 update_gbc_sound(cpu_ticks);
140 gbc_sound_update = 0;
141 }
142
143 update_timers(&irq_raised);
144
145 video_count -= execute_cycles;
146
147 if(video_count <= 0)
148 {
149 u32 vcount = io_registers[REG_VCOUNT];
150 u32 dispstat = io_registers[REG_DISPSTAT];
151
152 if((dispstat & 0x02) == 0)
153 {
154 // Transition from hrefresh to hblank
155 video_count += (272);
156 dispstat |= 0x02;
157
158 if((dispstat & 0x01) == 0)
159 {
160 u32 i;
161 if(oam_update)
162 oam_update_count++;
163
164 if(no_alpha)
165 io_registers[REG_BLDCNT] = 0;
166 update_scanline();
167
168 // If in visible area also fire HDMA
169 for(i = 0; i < 4; i++)
170 {
171 if(dma[i].start_type == DMA_START_HBLANK)
172 dma_transfer(dma + i);
173 }
174 }
175
176 if(dispstat & 0x10)
177 irq_raised |= IRQ_HBLANK;
178 }
179 else
180 {
181 // Transition from hblank to next line
182 video_count += 960;
183 dispstat &= ~0x02;
184
185 vcount++;
186
187 if(vcount == 160)
188 {
189 // Transition from vrefresh to vblank
190 u32 i;
191
192 dispstat |= 0x01;
193 if(dispstat & 0x8)
194 {
195 irq_raised |= IRQ_VBLANK;
196 }
197
198 affine_reference_x[0] =
199 (s32)(address32(io_registers, 0x28) << 4) >> 4;
200 affine_reference_y[0] =
201 (s32)(address32(io_registers, 0x2C) << 4) >> 4;
202 affine_reference_x[1] =
203 (s32)(address32(io_registers, 0x38) << 4) >> 4;
204 affine_reference_y[1] =
205 (s32)(address32(io_registers, 0x3C) << 4) >> 4;
206
207 for(i = 0; i < 4; i++)
208 {
209 if(dma[i].start_type == DMA_START_VBLANK)
210 dma_transfer(dma + i);
211 }
212 }
213 else
214
215 if(vcount == 228)
216 {
217 // Transition from vblank to next screen
218 dispstat &= ~0x01;
219
220 /* printf("frame update (%x), %d instructions total, %d RAM flushes\n",
221 reg[REG_PC], instruction_count - last_frame, flush_ram_count);
222 last_frame = instruction_count;
223 */
224 /* printf("%d gbc audio updates\n", gbc_update_count);
225 printf("%d oam updates\n", oam_update_count); */
226 gbc_update_count = 0;
227 oam_update_count = 0;
228 flush_ram_count = 0;
229
230 switch_to_main_thread();
231
232 update_gbc_sound(cpu_ticks);
233 gbc_sound_update = 0;
234
235 process_cheats();
236
237 vcount = 0;
238 }
239
240 if(vcount == (dispstat >> 8))
241 {
242 // vcount trigger
243 dispstat |= 0x04;
244 if(dispstat & 0x20)
245 {
246 irq_raised |= IRQ_VCOUNT;
247 }
248 }
249 else
250 dispstat &= ~0x04;
251
252 io_registers[REG_VCOUNT] = vcount;
253 }
254 io_registers[REG_DISPSTAT] = dispstat;
255 }
256
257 if(irq_raised)
258 raise_interrupt(irq_raised);
259
260 execute_cycles = video_count;
261
262 for (i = 0; i < 4; i++)
263 {
264 if(timer[i].status != TIMER_PRESCALE)
265 continue;
266
267 if(timer[i].count < execute_cycles)
268 execute_cycles = timer[i].count;
269 }
270 } while(reg[CPU_HALT_STATE] != CPU_ACTIVE);
271
272 return execute_cycles;
273 }
274
reset_gba(void)275 void reset_gba(void)
276 {
277 init_main();
278 init_memory();
279 init_cpu();
280 reset_sound();
281 }
282
283 #ifdef PSP
file_length(const char * filename,s32 dummy)284 u32 file_length(const char *filename, s32 dummy)
285 {
286 SceIoStat stats;
287 sceIoGetstat(filename, &stats);
288 return stats.st_size;
289 #else
290 u32 file_length(const char *dummy, FILE *fp)
291 {
292 u32 length;
293
294 fseek(fp, 0, SEEK_END);
295 length = ftell(fp);
296 fseek(fp, 0, SEEK_SET);
297
298 return length;
299 #endif
300 }
301
302 void change_ext(const char *src, char *buffer, const char *extension)
303 {
304 char *dot_position;
305 strcpy(buffer, src);
306 dot_position = strrchr(buffer, '.');
307
308 if(dot_position)
309 strcpy(dot_position, extension);
310 }
311
312 #define main_savestate_builder(type) \
313 void main_##type##_savestate(void) \
314 { \
315 state_mem_##type##_variable(cpu_ticks); \
316 state_mem_##type##_variable(execute_cycles); \
317 state_mem_##type##_variable(video_count); \
318 state_mem_##type##_array(timer); \
319 }
320
321 main_savestate_builder(read)
322 main_savestate_builder(write)
323
324
325 void printout(void *str, u32 val)
326 {
327 printf(str, val);
328 }
329