another wARM update
[gpsp.git] / main.c
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
22 #ifdef PSP_BUILD
23
24 //PSP_MODULE_INFO("gpSP", 0x1000, 0, 6);
25 //PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER);
26
27 void vblank_interrupt_handler(u32 sub, u32 *parg);
28
29 #endif
30
31 timer_type timer[4];
32
33 //debug_state current_debug_state = COUNTDOWN_BREAKPOINT;
34 //debug_state current_debug_state = PC_BREAKPOINT;
35 u32 breakpoint_value = 0x7c5000;
36 debug_state current_debug_state = RUN;
37 //debug_state current_debug_state = STEP_RUN;
38
39 //u32 breakpoint_value = 0;
40
41 frameskip_type current_frameskip_type = auto_frameskip;
42 u32 global_cycles_per_instruction = 1;
43 u32 random_skip = 0;
44
45 #ifdef GP2X_BUILD
46 u32 frameskip_value = 2;
47
48 u64 frame_count_initial_timestamp = 0;
49 u64 last_frame_interval_timestamp;
50 u32 gp2x_fps_debug = 0;
51
52 void gp2x_init(void);
53 void gp2x_quit(void);
54 #else
55
56 u32 frameskip_value = 4;
57 #endif
58 u32 skip_next_frame = 0;
59
60 u32 frameskip_counter = 0;
61
62 u32 cpu_ticks = 0;
63 u32 frame_ticks = 0;
64
65 u32 execute_cycles = 960;
66 s32 video_count = 960;
67 u32 ticks;
68
69 u32 arm_frame = 0;
70 u32 thumb_frame = 0;
71 u32 last_frame = 0;
72
73 u32 cycle_memory_access = 0;
74 u32 cycle_pc_relative_access = 0;
75 u32 cycle_sp_relative_access = 0;
76 u32 cycle_block_memory_access = 0;
77 u32 cycle_block_memory_sp_access = 0;
78 u32 cycle_block_memory_words = 0;
79 u32 cycle_dma16_words = 0;
80 u32 cycle_dma32_words = 0;
81 u32 flush_ram_count = 0;
82 u32 gbc_update_count = 0;
83 u32 oam_update_count = 0;
84
85 u32 synchronize_flag = 1;
86
87 u32 update_backup_flag = 1;
88 #ifdef GP2X_BUILD
89 u32 clock_speed = 200;
90 #else
91 u32 clock_speed = 333;
92 #endif
93 u8 main_path[512];
94
95 void trigger_ext_event();
96
97 #define check_count(count_var)                                                \
98   if(count_var < execute_cycles)                                              \
99     execute_cycles = count_var;                                               \
100
101 #define check_timer(timer_number)                                             \
102   if(timer[timer_number].status == TIMER_PRESCALE)                            \
103     check_count(timer[timer_number].count);                                   \
104
105 #define update_timer(timer_number)                                            \
106   if(timer[timer_number].status != TIMER_INACTIVE)                            \
107   {                                                                           \
108     if(timer[timer_number].status != TIMER_CASCADE)                           \
109     {                                                                         \
110       timer[timer_number].count -= execute_cycles;                            \
111       io_registers[REG_TM##timer_number##D] =                                 \
112        -(timer[timer_number].count >> timer[timer_number].prescale);          \
113     }                                                                         \
114                                                                               \
115     if(timer[timer_number].count <= 0)                                        \
116     {                                                                         \
117       if(timer[timer_number].irq == TIMER_TRIGGER_IRQ)                        \
118         irq_raised |= IRQ_TIMER##timer_number;                                \
119                                                                               \
120       if((timer_number != 3) &&                                               \
121        (timer[timer_number + 1].status == TIMER_CASCADE))                     \
122       {                                                                       \
123         timer[timer_number + 1].count--;                                      \
124         io_registers[REG_TM0D + (timer_number + 1) * 2] =                     \
125          -(timer[timer_number + 1].count);                                    \
126       }                                                                       \
127                                                                               \
128       if(timer_number < 2)                                                    \
129       {                                                                       \
130         if(timer[timer_number].direct_sound_channels & 0x01)                  \
131           sound_timer(timer[timer_number].frequency_step, 0);                 \
132                                                                               \
133         if(timer[timer_number].direct_sound_channels & 0x02)                  \
134           sound_timer(timer[timer_number].frequency_step, 1);                 \
135       }                                                                       \
136                                                                               \
137       timer[timer_number].count +=                                            \
138        (timer[timer_number].reload << timer[timer_number].prescale);          \
139     }                                                                         \
140   }                                                                           \
141
142 u8 *file_ext[] = { ".gba", ".bin", ".zip", NULL };
143
144 #ifdef ARM_ARCH
145 void ChangeWorkingDirectory(char *exe)
146 {
147 #ifndef _WIN32_WCE
148   char *s = strrchr(exe, '/');
149   if (s != NULL) {
150     *s = '\0';
151     chdir(exe);
152     *s = '/';
153   }
154 #endif
155 }
156 #endif
157
158 void init_main()
159 {
160   u32 i;
161
162   skip_next_frame = 0;
163
164   for(i = 0; i < 4; i++)
165   {
166     dma[i].start_type = DMA_INACTIVE;
167     dma[i].direct_sound_channel = DMA_NO_DIRECT_SOUND;
168     timer[i].status = TIMER_INACTIVE;
169     timer[i].reload = 0x10000;
170     timer[i].stop_cpu_ticks = 0;
171   }
172
173   timer[0].direct_sound_channels = TIMER_DS_CHANNEL_BOTH;
174   timer[1].direct_sound_channels = TIMER_DS_CHANNEL_NONE;
175
176   cpu_ticks = 0;
177   frame_ticks = 0;
178
179   execute_cycles = 960;
180   video_count = 960;
181
182   flush_translation_cache_rom();
183   flush_translation_cache_ram();
184   flush_translation_cache_bios();
185 }
186
187 int main(int argc, char *argv[])
188 {
189   u32 i;
190   u32 vcount = 0;
191   u32 ticks;
192   u32 dispstat;
193   u8 load_filename[512];
194   u8 bios_filename[512];
195
196 #ifdef PSP_BUILD
197   sceKernelRegisterSubIntrHandler(PSP_VBLANK_INT, 0,
198    vblank_interrupt_handler, NULL);
199   sceKernelEnableSubIntr(PSP_VBLANK_INT, 0);
200 #elif !defined(GP2X_BUILD)
201   freopen("CON", "wb", stdout);
202 #endif
203
204   extern char *cpu_mode_names[];
205
206   init_gamepak_buffer();
207
208   // Copy the directory path of the executable into main_path
209
210 #ifdef ARM_ARCH
211   // ChangeWorkingDirectory will null out the filename out of the path
212   ChangeWorkingDirectory(argv[0]);
213 #endif
214
215   getcwd(main_path, 512);
216   load_config_file();
217
218   gamepak_filename[0] = 0;
219
220 #ifdef PSP_BUILD
221   delay_us(2500000);
222 #endif
223
224 #ifdef GP2X_BUILD
225   // Overclocking GP2X and MMU patch goes here
226   gp2x_init();
227 #endif
228
229   init_video();
230
231 #ifdef GP2X_BUILD
232   sprintf(bios_filename, "%s/%s", main_path, "gba_bios.bin");
233   if(load_bios(bios_filename) == -1)
234 #else
235   if(load_bios("gba_bios.bin") == -1)
236 #endif
237   {
238     gui_action_type gui_action = CURSOR_NONE;
239
240     debug_screen_start();
241     debug_screen_printl("Sorry, but gpSP requires a Gameboy Advance BIOS   ");
242     debug_screen_printl("image to run correctly. Make sure to get an       ");
243     debug_screen_printl("authentic one, it'll be exactly 16384 bytes large ");
244     debug_screen_printl("and should have the following md5sum value:       ");
245     debug_screen_printl("                                                  ");
246     debug_screen_printl("a860e8c0b6d573d191e4ec7db1b1e4f6                  ");
247     debug_screen_printl("                                                  ");
248     debug_screen_printl("When you do get it name it gba_bios.bin and put it");
249     debug_screen_printl("in the same directory as gpSP.                    ");
250     debug_screen_printl("                                                  ");
251     debug_screen_printl("Press any button to exit.                         ");
252
253     debug_screen_update();
254
255     while(gui_action == CURSOR_NONE)
256     {
257       gui_action = get_gui_input();
258       delay_us(15000);
259     }
260
261     debug_screen_end();
262
263     quit();
264   }
265
266   if(bios_rom[0] != 0x18)
267   {
268     gui_action_type gui_action = CURSOR_NONE;
269
270     debug_screen_start();
271     debug_screen_printl("You have an incorrect BIOS image.                 ");
272     debug_screen_printl("While many games will work fine, some will not. It");
273     debug_screen_printl("is strongly recommended that you obtain the       ");
274     debug_screen_printl("correct BIOS file. Do NOT report any bugs if you  ");
275     debug_screen_printl("are seeing this message.                          ");
276     debug_screen_printl("                                                  ");
277     debug_screen_printl("Press any button to resume, at your own risk.     ");
278
279     debug_screen_update();
280
281     while(gui_action == CURSOR_NONE)
282     {
283       gui_action = get_gui_input();
284       delay_us(15000);
285     }
286
287     debug_screen_end();
288   }
289
290   init_main();
291   init_sound();
292
293   init_input();
294
295   video_resolution_large();
296
297   if(argc > 1)
298   {
299     if(load_gamepak(argv[1]) == -1)
300     {
301 #ifdef PC_BUILD
302       printf("Failed to load gamepak %s, exiting.\n", load_filename);
303 #endif
304       exit(-1);
305     }
306
307     set_gba_resolution(screen_scale);
308     video_resolution_small();
309
310     init_cpu();
311     init_memory();
312   }
313   else
314   {
315     if(load_file(file_ext, load_filename) == -1)
316     {
317       menu(copy_screen());
318     }
319     else
320     {
321       if(load_gamepak(load_filename) == -1)
322       {
323 #ifdef PC_BUILD
324         printf("Failed to load gamepak %s, exiting.\n", load_filename);
325 #endif
326         exit(-1);
327       }
328
329       set_clock_speed();
330       set_gba_resolution(screen_scale);
331       video_resolution_small();
332
333       init_cpu();
334       init_memory();
335     }
336   }
337
338   last_frame = 0;
339
340   // We'll never actually return from here.
341
342 #ifdef PSP_BUILD
343   execute_arm_translate(execute_cycles);
344 #else
345
346 #ifdef GP2X_BUILD
347   get_ticks_us(&frame_count_initial_timestamp);
348 #endif
349
350 /*  u8 current_savestate_filename[512];
351   get_savestate_filename_noshot(savestate_slot,
352    current_savestate_filename);
353   load_state(current_savestate_filename); */
354
355 //  debug_on();
356
357   if(argc > 2)
358   {
359     current_debug_state = COUNTDOWN_BREAKPOINT;
360     breakpoint_value = strtol(argv[2], NULL, 16);
361   }
362
363   trigger_ext_event();
364
365   execute_arm_translate(execute_cycles);
366   execute_arm(execute_cycles);
367 #endif
368   return 0;
369 }
370
371 void print_memory_stats(u32 *counter, u32 *region_stats, char *stats_str)
372 {
373   u32 other_region_counter = region_stats[0x1] + region_stats[0xE] +
374    region_stats[0xF];
375   u32 rom_region_counter = region_stats[0x8] + region_stats[0x9] +
376    region_stats[0xA] + region_stats[0xB] + region_stats[0xC] +
377    region_stats[0xD];
378   u32 _counter = *counter;
379
380   printf("memory access stats: %s (out of %d)\n", stats_str, _counter);
381   printf("bios: %f%%\tiwram: %f%%\tewram: %f%%\tvram: %f\n",
382    region_stats[0x0] * 100.0 / _counter, region_stats[0x3] * 100.0 /
383    _counter,
384    region_stats[0x2] * 100.0 / _counter, region_stats[0x6] * 100.0 /
385    _counter);
386
387   printf("oam: %f%%\tpalette: %f%%\trom: %f%%\tother: %f%%\n",
388    region_stats[0x7] * 100.0 / _counter, region_stats[0x5] * 100.0 /
389    _counter,
390    rom_region_counter * 100.0 / _counter, other_region_counter * 100.0 /
391    _counter);
392
393   *counter = 0;
394   memset(region_stats, 0, sizeof(u32) * 16);
395 }
396
397 u32 event_cycles = 0;
398 const u32 event_cycles_trigger = 60 * 5;
399 u32 no_alpha = 0;
400
401 void trigger_ext_event()
402 {
403   static u32 event_number = 0;
404   static u64 benchmark_ticks[16];
405   u64 new_ticks;
406   u8 current_savestate_filename[512];
407
408   return;
409
410   if(event_number)
411   {
412     get_ticks_us(&new_ticks);
413     benchmark_ticks[event_number - 1] =
414      new_ticks - benchmark_ticks[event_number - 1];
415   }
416
417   current_frameskip_type = no_frameskip;
418   no_alpha = 0;
419   synchronize_flag = 0;
420
421   get_savestate_filename_noshot(savestate_slot,
422    current_savestate_filename);
423   load_state(current_savestate_filename);
424
425   switch(event_number)
426   {
427     case 0:
428       // Full benchmark, run normally
429       break;
430
431     case 1:
432       // No alpha blending
433       no_alpha = 1;
434       break;
435
436     case 2:
437       // No video benchmark
438       // Set frameskip really high + manual
439       current_frameskip_type = manual_frameskip;
440       frameskip_value = 1000000;
441       break;
442
443     case 3:
444       // No CPU benchmark
445       // Put CPU in halt mode, put it in IRQ mode with interrupts off
446       reg[CPU_HALT_STATE] = CPU_HALT;
447       reg[REG_CPSR] = 0xD2;
448       break;
449
450     case 4:
451       // No CPU or video benchmark
452       reg[CPU_HALT_STATE] = CPU_HALT;
453       reg[REG_CPSR] = 0xD2;
454       current_frameskip_type = manual_frameskip;
455       frameskip_value = 1000000;
456       break;
457
458     case 5:
459     {
460       // Done
461       char *print_strings[] =
462       {
463         "Full test   ",
464         "No blending ",
465         "No video    ",
466         "No CPU      ",
467         "No CPU/video",
468         "CPU speed   ",
469         "Video speed ",
470         "Alpha cost  "
471       };
472       u32 i;
473
474       benchmark_ticks[6] = benchmark_ticks[0] - benchmark_ticks[2];
475       benchmark_ticks[5] = benchmark_ticks[0] - benchmark_ticks[4] -
476        benchmark_ticks[6];
477       benchmark_ticks[7] = benchmark_ticks[0] - benchmark_ticks[1];
478
479       printf("Benchmark results (%d frames): \n", event_cycles_trigger);
480       for(i = 0; i < 8; i++)
481       {
482         printf("   %s: %d ms (%f ms per frame)\n",
483          print_strings[i], (u32)benchmark_ticks[i] / 1000,
484          (float)(benchmark_ticks[i] / (1000.0 * event_cycles_trigger)));
485         if(i == 4)
486           printf("\n");
487       }
488       quit();
489     }
490   }
491
492   event_cycles = 0;
493
494   get_ticks_us(benchmark_ticks + event_number);
495   event_number++;
496 }
497
498 static u32 fps = 60;
499 static u32 frames_drawn = 60;
500
501 u32 update_gba()
502 {
503   irq_type irq_raised = IRQ_NONE;
504
505   do
506   {
507     cpu_ticks += execute_cycles;
508
509     reg[CHANGED_PC_STATUS] = 0;
510
511     if(gbc_sound_update)
512     {
513       gbc_update_count++;
514       update_gbc_sound(cpu_ticks);
515       gbc_sound_update = 0;
516     }
517
518     update_timer(0);
519     update_timer(1);
520     update_timer(2);
521     update_timer(3);
522
523     video_count -= execute_cycles;
524
525     if(video_count <= 0)
526     {
527       u32 vcount = io_registers[REG_VCOUNT];
528       u32 dispstat = io_registers[REG_DISPSTAT];
529
530       if((dispstat & 0x02) == 0)
531       {
532         // Transition from hrefresh to hblank
533         video_count += (272);
534         dispstat |= 0x02;
535
536         if((dispstat & 0x01) == 0)
537         {
538           u32 i;
539           if(oam_update)
540             oam_update_count++;
541
542           if(no_alpha)
543             io_registers[REG_BLDCNT] = 0;
544           update_scanline();
545
546           // If in visible area also fire HDMA
547           for(i = 0; i < 4; i++)
548           {
549             if(dma[i].start_type == DMA_START_HBLANK)
550               dma_transfer(dma + i);
551           }
552         }
553
554         if(dispstat & 0x10)
555           irq_raised |= IRQ_HBLANK;
556       }
557       else
558       {
559         // Transition from hblank to next line
560         video_count += 960;
561         dispstat &= ~0x02;
562
563         vcount++;
564
565         if(vcount == 160)
566         {
567           // Transition from vrefresh to vblank
568           u32 i;
569
570           dispstat |= 0x01;
571           if(dispstat & 0x8)
572           {
573             irq_raised |= IRQ_VBLANK;
574           }
575
576           affine_reference_x[0] =
577            (s32)(address32(io_registers, 0x28) << 4) >> 4;
578           affine_reference_y[0] =
579            (s32)(address32(io_registers, 0x2C) << 4) >> 4;
580           affine_reference_x[1] =
581            (s32)(address32(io_registers, 0x38) << 4) >> 4;
582           affine_reference_y[1] =
583            (s32)(address32(io_registers, 0x3C) << 4) >> 4;
584
585           for(i = 0; i < 4; i++)
586           {
587             if(dma[i].start_type == DMA_START_VBLANK)
588               dma_transfer(dma + i);
589           }
590         }
591         else
592
593         if(vcount == 228)
594         {
595           // Transition from vblank to next screen
596           dispstat &= ~0x01;
597           frame_ticks++;
598
599   #ifdef PC_BUILD
600         printf("frame update (%x), %d instructions total, %d RAM flushes\n",
601            reg[REG_PC], instruction_count - last_frame, flush_ram_count);
602           last_frame = instruction_count;
603
604 /*          printf("%d gbc audio updates\n", gbc_update_count);
605           printf("%d oam updates\n", oam_update_count); */
606           gbc_update_count = 0;
607           oam_update_count = 0;
608           flush_ram_count = 0;
609   #endif
610
611           if(update_input())
612             continue;
613
614           update_gbc_sound(cpu_ticks);
615
616           if(gp2x_fps_debug)
617           {
618             char print_buffer[32];
619             sprintf(print_buffer, "%d (%d)", fps, frames_drawn);
620             print_string(print_buffer, 0xFFFF, 0x000, 0, 0);
621           }
622
623           update_screen();
624
625           synchronize();
626
627           if(update_backup_flag)
628             update_backup();
629
630           process_cheats();
631
632           event_cycles++;
633           if(event_cycles == event_cycles_trigger)
634           {
635             trigger_ext_event();
636             continue;
637           }
638
639           vcount = 0;
640         }
641
642         if(vcount == (dispstat >> 8))
643         {
644           // vcount trigger
645           dispstat |= 0x04;
646           if(dispstat & 0x20)
647           {
648             irq_raised |= IRQ_VCOUNT;
649           }
650         }
651         else
652         {
653           dispstat &= ~0x04;
654         }
655
656         io_registers[REG_VCOUNT] = vcount;
657       }
658       io_registers[REG_DISPSTAT] = dispstat;
659     }
660
661     if(irq_raised)
662       raise_interrupt(irq_raised);
663
664     execute_cycles = video_count;
665
666     check_timer(0);
667     check_timer(1);
668     check_timer(2);
669     check_timer(3);
670   } while(reg[CPU_HALT_STATE] != CPU_ACTIVE);
671
672   return execute_cycles;
673 }
674
675 u64 last_screen_timestamp = 0;
676 u32 frame_speed = 15000;
677
678
679 #ifdef PSP_BUILD
680
681 u32 real_frame_count = 0;
682 u32 virtual_frame_count = 0;
683 u32 num_skipped_frames = 0;
684
685 void vblank_interrupt_handler(u32 sub, u32 *parg)
686 {
687   real_frame_count++;
688 }
689
690 void synchronize()
691 {
692   char char_buffer[64];
693   u64 new_ticks, time_delta;
694   s32 used_frameskip = frameskip_value;
695
696   if(!synchronize_flag)
697   {
698     print_string("--FF--", 0xFFFF, 0x000, 0, 0);
699     used_frameskip = 4;
700     virtual_frame_count = real_frame_count - 1;
701   }
702
703   skip_next_frame = 0;
704
705   virtual_frame_count++;
706
707   if(real_frame_count >= virtual_frame_count)
708   {
709     if((real_frame_count > virtual_frame_count) &&
710      (current_frameskip_type == auto_frameskip) &&
711      (num_skipped_frames < frameskip_value))
712     {
713       skip_next_frame = 1;
714       num_skipped_frames++;
715     }
716     else
717     {
718       virtual_frame_count = real_frame_count;
719       num_skipped_frames = 0;
720     }
721
722     // Here so that the home button return will eventually work.
723     // If it's not running fullspeed anyway this won't really hurt
724     // it much more.
725
726     delay_us(1);
727   }
728   else
729   {
730     if(synchronize_flag)
731       sceDisplayWaitVblankStart();
732   }
733
734   if(current_frameskip_type == manual_frameskip)
735   {
736     frameskip_counter = (frameskip_counter + 1) %
737      (used_frameskip + 1);
738     if(random_skip)
739     {
740       if(frameskip_counter != (rand() % (used_frameskip + 1)))
741         skip_next_frame = 1;
742     }
743     else
744     {
745       if(frameskip_counter)
746         skip_next_frame = 1;
747     }
748   }
749
750 /*  sprintf(char_buffer, "%08d %08d %d %d %d\n",
751    real_frame_count, virtual_frame_count, num_skipped_frames,
752    real_frame_count - virtual_frame_count, skip_next_frame);
753   print_string(char_buffer, 0xFFFF, 0x0000, 0, 10); */
754
755 /*
756     sprintf(char_buffer, "%02d %02d %06d %07d", frameskip, (u32)ms_needed,
757      ram_translation_ptr - ram_translation_cache, rom_translation_ptr -
758      rom_translation_cache);
759     print_string(char_buffer, 0xFFFF, 0x0000, 0, 0);
760 */
761 }
762
763 #endif
764
765 #ifdef GP2X_BUILD
766
767 u32 real_frame_count = 0;
768 u32 virtual_frame_count = 0;
769 u32 num_skipped_frames = 0;
770 u32 interval_skipped_frames;
771 u32 frames;
772
773 const u32 frame_interval = 60;
774
775 void synchronize()
776 {
777   u64 new_ticks;
778   u64 time_delta;
779
780   get_ticks_us(&new_ticks);
781   time_delta = new_ticks - last_screen_timestamp;
782   last_screen_timestamp = new_ticks;
783
784   skip_next_frame = 0;
785   virtual_frame_count++;
786
787   real_frame_count = ((new_ticks -
788     frame_count_initial_timestamp) * 3) / 50000;
789
790   if(real_frame_count >= virtual_frame_count)
791   {
792     if((real_frame_count > virtual_frame_count) &&
793      (current_frameskip_type == auto_frameskip) &&
794      (num_skipped_frames < frameskip_value))
795     {
796       skip_next_frame = 1;
797       num_skipped_frames++;
798     }
799     else
800     {
801       virtual_frame_count = real_frame_count;
802       num_skipped_frames = 0;
803     }
804   }
805
806   frames++;
807
808   if(frames == frame_interval)
809   {
810     u32 new_fps;
811     u32 new_frames_drawn;
812
813     time_delta = new_ticks - last_frame_interval_timestamp;
814     new_fps = (u64)((u64)1000000 * (u64)frame_interval) / time_delta;
815     new_frames_drawn =
816      (frame_interval - interval_skipped_frames) * (60 / frame_interval);
817
818     // Left open for rolling averages
819     fps = new_fps;
820     frames_drawn = new_frames_drawn;
821
822     last_frame_interval_timestamp = new_ticks;
823     interval_skipped_frames = 0;
824     frames = 0;
825   }
826
827   if(current_frameskip_type == manual_frameskip)
828   {
829     frameskip_counter = (frameskip_counter + 1) %
830      (frameskip_value + 1);
831     if(random_skip)
832     {
833       if(frameskip_counter != (rand() % (frameskip_value + 1)))
834         skip_next_frame = 1;
835     }
836     else
837     {
838       if(frameskip_counter)
839         skip_next_frame = 1;
840     }
841   }
842
843   interval_skipped_frames += skip_next_frame;
844
845   if(!synchronize_flag)
846     print_string("--FF--", 0xFFFF, 0x000, 0, 0);
847 }
848
849 #endif
850
851
852 #ifdef PC_BUILD
853
854 u32 ticks_needed_total = 0;
855 float us_needed = 0.0;
856 u32 frames = 0;
857 const u32 frame_interval = 60;
858
859 void synchronize()
860 {
861   u64 new_ticks;
862   u64 time_delta;
863   char char_buffer[64];
864
865   get_ticks_us(&new_ticks);
866   time_delta = new_ticks - last_screen_timestamp;
867   last_screen_timestamp = new_ticks;
868   ticks_needed_total += time_delta;
869
870   skip_next_frame = 0;
871
872   if((time_delta < frame_speed) && synchronize_flag)
873   {
874     delay_us(frame_speed - time_delta);
875   }
876
877   frames++;
878
879   if(frames == frame_interval)
880   {
881     us_needed = (float)ticks_needed_total / frame_interval;
882     ticks_needed_total = 0;
883     frames = 0;
884   }
885
886   if(current_frameskip_type == manual_frameskip)
887   {
888     frameskip_counter = (frameskip_counter + 1) %
889      (frameskip_value + 1);
890     if(random_skip)
891     {
892       if(frameskip_counter != (rand() % (frameskip_value + 1)))
893         skip_next_frame = 1;
894     }
895     else
896     {
897       if(frameskip_counter)
898         skip_next_frame = 1;
899     }
900   }
901
902   if(synchronize_flag == 0)
903     print_string("--FF--", 0xFFFF, 0x000, 0, 0);
904
905   sprintf(char_buffer, "gpSP: %.1fms %.1ffps", us_needed / 1000.0,
906    1000000.0 / us_needed);
907   SDL_WM_SetCaption(char_buffer, "gpSP");
908
909 /*
910     sprintf(char_buffer, "%02d %02d %06d %07d", frameskip, (u32)ms_needed,
911      ram_translation_ptr - ram_translation_cache, rom_translation_ptr -
912      rom_translation_cache);
913     print_string(char_buffer, 0xFFFF, 0x0000, 0, 0);
914 */
915 }
916
917 #endif
918
919 void quit()
920 {
921   if(!update_backup_flag)
922     update_backup_force();
923
924   sound_exit();
925
926 #ifdef REGISTER_USAGE_ANALYZE
927   print_register_usage();
928 #endif
929
930 #ifdef PSP_BUILD
931   sceKernelExitGame();
932 #else
933   SDL_Quit();
934
935 #ifdef GP2X_BUILD
936   gp2x_quit();
937 #endif
938
939   exit(0);
940 #endif
941 }
942
943 void reset_gba()
944 {
945   init_main();
946   init_memory();
947   init_cpu();
948   reset_sound();
949 }
950
951 #ifdef PSP_BUILD
952
953 u32 file_length(u8 *filename, s32 dummy)
954 {
955   SceIoStat stats;
956   sceIoGetstat(filename, &stats);
957   return stats.st_size;
958 }
959
960 void delay_us(u32 us_count)
961 {
962   sceKernelDelayThread(us_count);
963 }
964
965 void get_ticks_us(u64 *tick_return)
966 {
967   u64 ticks;
968   sceRtcGetCurrentTick(&ticks);
969
970   *tick_return = (ticks * 1000000) / sceRtcGetTickResolution();
971 }
972
973 #else
974
975 u32 file_length(u8 *dummy, FILE *fp)
976 {
977   u32 length;
978
979   fseek(fp, 0, SEEK_END);
980   length = ftell(fp);
981   fseek(fp, 0, SEEK_SET);
982
983   return length;
984 }
985
986 #ifdef PC_BUILD
987
988 void delay_us(u32 us_count)
989 {
990   SDL_Delay(us_count / 1000);
991 }
992
993 void get_ticks_us(u64 *ticks_return)
994 {
995   *ticks_return = (SDL_GetTicks() * 1000);
996 }
997
998 #else
999
1000 void delay_us(u32 us_count)
1001 {
1002   //usleep(us_count);
1003   SDL_Delay(us_count / 1000);
1004 }
1005
1006 void get_ticks_us(u64 *ticks_return)
1007 {
1008   struct timeval current_time;
1009   gettimeofday(&current_time, NULL);
1010
1011   *ticks_return =
1012    (u64)current_time.tv_sec * 1000000 + current_time.tv_usec;
1013 }
1014
1015 #endif
1016
1017 #endif
1018
1019 void change_ext(u8 *src, u8 *buffer, u8 *extension)
1020 {
1021   u8 *dot_position;
1022   strcpy(buffer, src);
1023   dot_position = strrchr(buffer, '.');
1024
1025   if(dot_position)
1026     strcpy(dot_position, extension);
1027 }
1028
1029 #define main_savestate_builder(type)                                          \
1030 void main_##type##_savestate(file_tag_type savestate_file)                    \
1031 {                                                                             \
1032   file_##type##_variable(savestate_file, cpu_ticks);                          \
1033   file_##type##_variable(savestate_file, execute_cycles);                     \
1034   file_##type##_variable(savestate_file, video_count);                        \
1035   file_##type##_array(savestate_file, timer);                                 \
1036 }                                                                             \
1037
1038 main_savestate_builder(read);
1039 main_savestate_builder(write_mem);
1040
1041
1042 void printout(void *str, u32 val)
1043 {
1044   printf(str, val);
1045 }
1046
1047 void set_clock_speed()
1048 {
1049   static u32 clock_speed_old = default_clock_speed;
1050   if (clock_speed != clock_speed_old)
1051   {
1052     printf("about to set CPU clock to %iMHz\n", clock_speed);
1053   #ifdef PSP_BUILD
1054     scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
1055   #elif defined(GP2X_BUILD)
1056     set_FCLK(clock_speed);
1057   #endif
1058     clock_speed_old = clock_speed;
1059   }
1060 }
1061