summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/common.h10
-rw-r--r--source/dstwo/port.h2
-rw-r--r--source/gcw0/draw.c458
-rw-r--r--source/gcw0/gui.c1441
-rw-r--r--source/gcw0/main.c609
-rw-r--r--source/gcw0/main.h123
-rw-r--r--source/gcw0/port.h49
-rw-r--r--source/psp/gui.c293
-rw-r--r--source/psp/main.c778
-rw-r--r--source/psp/port.h53
-rw-r--r--source/zip.h2
11 files changed, 3806 insertions, 12 deletions
diff --git a/source/common.h b/source/common.h
index d61ddf2..54cd5c9 100644
--- a/source/common.h
+++ b/source/common.h
@@ -39,6 +39,16 @@
#include <string.h>
#include <math.h>
+#ifdef __GNUC__
+# define likely(x) __builtin_expect((x),1)
+# define unlikely(x) __builtin_expect((x),0)
+# define prefetch(x, y) __builtin_prefetch((x),(y))
+#else
+# define likely(x) (x)
+# define unlikely(x) (x)
+# define prefetch(x, y)
+#endif
+
#define SYS_CLOCK (16777216.0)
#define ROR(dest, value, shift) \
diff --git a/source/dstwo/port.h b/source/dstwo/port.h
index 420ee60..fbf1bf1 100644
--- a/source/dstwo/port.h
+++ b/source/dstwo/port.h
@@ -53,8 +53,6 @@ typedef u32 FIXED16_16; // Q16.16 fixed-point
* STMDB R0!, {R0,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12,R13,R14,R15} */
#define TRANSLATION_CACHE_LIMIT_THRESHOLD (1024)
-#define NO_VOLATILE_SOUND
-
#define FILE_OPEN_APPEND ("a+")
#define FILE_OPEN_READ ("rb")
diff --git a/source/gcw0/draw.c b/source/gcw0/draw.c
new file mode 100644
index 0000000..6eadbff
--- /dev/null
+++ b/source/gcw0/draw.c
@@ -0,0 +1,458 @@
+/* gameplaySP
+ *
+ * Copyright (C) 2006 Exophase <exophase@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "common.h"
+
+SDL_Surface *screen = NULL;
+SDL_Surface *display = NULL;
+
+const u32 video_scale = 1;
+
+void init_video()
+{
+ if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0)
+ {
+ printf("Failed to initialize SDL !!\n");
+ return; // for debug
+ // exit(1);
+ }
+
+ display = SDL_SetVideoMode(320, 240, 16, SDL_HWSURFACE | SDL_DOUBLEBUF);
+ screen = SDL_CreateRGBSurface(SDL_SWSURFACE, 320, 240, 16,
+ display->format->Rmask,
+ display->format->Gmask,
+ display->format->Bmask,
+ display->format->Amask);
+
+ SDL_ShowCursor(0);
+}
+
+void video_resolution_large()
+{
+ if(current_scale != unscaled)
+ {
+ resolution_width = 320;
+ resolution_height = 240;
+ }
+}
+
+void video_resolution_small()
+{
+ if(current_scale != screen_scale)
+ {
+ resolution_width = small_resolution_width;
+ resolution_height = small_resolution_height;
+ }
+}
+
+void set_gba_resolution(video_scale_type scale)
+{
+ if(screen_scale != scale)
+ {
+ screen_scale = scale;
+ switch(scale)
+ {
+ case unscaled:
+ case scaled_aspect:
+ case fullscreen:
+ small_resolution_width = 240 * video_scale;
+ small_resolution_height = 160 * video_scale;
+ break;
+ }
+ }
+}
+
+void clear_screen(u16 color)
+{
+ u16 *dest_ptr = get_screen_pixels();
+ u32 line_skip = get_screen_pitch() - screen->w;
+ u32 x, y;
+
+ for(y = 0; y < screen->h; y++)
+ {
+ for(x = 0; x < screen->w; x++, dest_ptr++)
+ {
+ *dest_ptr = color;
+ }
+ dest_ptr += line_skip;
+ }
+}
+
+#define integer_scale_copy_2() \
+ current_scanline_ptr[x2] = current_pixel; \
+ current_scanline_ptr[x2 - 1] = current_pixel; \
+ x2 -= 2 \
+
+#define integer_scale_copy_3() \
+ current_scanline_ptr[x2] = current_pixel; \
+ current_scanline_ptr[x2 - 1] = current_pixel; \
+ current_scanline_ptr[x2 - 2] = current_pixel; \
+ x2 -= 3 \
+
+#define integer_scale_copy_4() \
+ current_scanline_ptr[x2] = current_pixel; \
+ current_scanline_ptr[x2 - 1] = current_pixel; \
+ current_scanline_ptr[x2 - 2] = current_pixel; \
+ current_scanline_ptr[x2 - 3] = current_pixel; \
+ x2 -= 4 \
+
+#define integer_scale_horizontal(scale_factor) \
+ for(y = 0; y < 160; y++) \
+ { \
+ for(x = 239, x2 = (240 * video_scale) - 1; x >= 0; x--) \
+ { \
+ current_pixel = current_scanline_ptr[x]; \
+ integer_scale_copy_##scale_factor(); \
+ current_scanline_ptr[x2] = current_scanline_ptr[x]; \
+ current_scanline_ptr[x2 - 1] = current_scanline_ptr[x]; \
+ current_scanline_ptr[x2 - 2] = current_scanline_ptr[x]; \
+ } \
+ current_scanline_ptr += pitch; \
+ } \
+
+
+// GPL software scaler, courtesy of Ayla (paul@crapouillou.net)
+// Upscale from 240x160 to 320x240
+void gba_upscale(uint32_t *to, uint32_t *from, uint32_t src_x, uint32_t src_y, uint32_t pitch)
+{
+ /* Before:
+ * a b c d e f
+ * g h i j k l
+ *
+ * After (parenthesis = average):
+ * a (a,b) (b,c) c d (d,e) (e,f) f
+ * (a,g) (a,b,g,h) (b,c,h,i) (c,i) (d,j) (d,e,j,k) (e,f,k,l) (f,l)
+ * g (g,h) (h,i) i j (j,k) (k,l) l
+ */
+
+ const uint32_t dst_x = src_x * 4/3;
+
+ uint32_t reg1, reg2, reg3, reg4, reg5;
+ size_t x, y;
+
+
+ for (y=0; y<src_y/2; y++) {
+ for (x=0; x<src_x/6; x++) {
+ prefetch(to+4, 1);
+
+ /* Read b-a */
+ reg1 = *from;
+ reg2 = ((reg1 & 0xf7de0000) >> 1) + (reg1 & 0x08210000);
+
+ /* Read h-g */
+ reg3 = *(from++ + src_x/2 + pitch/2);
+ reg4 = ((reg3 & 0xf7de0000) >> 1) + (reg3 & 0x08210000);
+
+ reg1 &= 0xffff;
+ reg1 |= reg2 + ((reg1 & 0xf7de) << 15);
+
+ /* Write (a,b)-a */
+ *to = reg1;
+
+ reg3 &= 0xffff;
+ reg3 |= reg4 + ((reg3 & 0xf7de) << 15);
+
+ /* Write (g,h)-g */
+ *(to + 2*dst_x/2) = reg3;
+
+ if (unlikely(reg1 != reg3))
+ reg1 = (reg1 & 0x08210821)
+ + ((reg1 & 0xf7def7de) >> 1)
+ + ((reg3 & 0xf7def7de) >> 1);
+
+ /* Write (a,b,g,h)-(a,g) */
+ *(to++ + dst_x/2) = reg1;
+
+ /* Read d-c */
+ reg1 = *from;
+ reg2 = ((reg2 + ((reg1 & 0xf7de) << 15)) >> 16) | ((reg1 & 0xffff) << 16);
+
+ /* Write c-(b,c) */
+ *to = reg2;
+
+ /* Read j-i */
+ reg3 = *(from++ + src_x/2 + pitch/2);
+ reg4 = ((reg4 + ((reg3 & 0xf7de) << 15)) >> 16) | ((reg3 & 0xffff) << 16);
+
+ /* Write i-(h,i) */
+ *(to + 2*dst_x/2) = reg4;
+
+ if (unlikely(reg2 != reg4))
+ reg2 = (reg2 & 0x08210821)
+ + ((reg2 & 0xf7def7de) >> 1)
+ + ((reg4 & 0xf7def7de) >> 1);
+
+ /* Write (c,i)-(b,c,h,i) */
+ *(to++ + dst_x/2) = reg2;
+
+ /* Read f-e */
+ reg2 = *from;
+ reg4 = (reg2 & 0xf7def7de) >> 1;
+
+ /* Write (d,e)-d */
+ reg1 >>= 16;
+ reg4 = reg1 | ((reg4 + ((reg1 & 0xf7de) >> 1) + (reg1 & 0x0821)) << 16);
+ *to = reg4;
+
+ /* Read l-k */
+ reg1 = *(from++ + src_x/2 + pitch/2);
+ reg5 = (reg1 & 0xf7def7de) >> 1;
+
+ /* Write (j,k)-j */
+ reg3 >>= 16;
+ reg5 = reg3 | ((reg5 + ((reg3 & 0xf7de) >> 1) + (reg3 & 0x0821)) << 16);
+ *(to + 2*dst_x/2) = reg5;
+
+ if (unlikely(reg4 != reg5))
+ reg4 = (reg4 & 0x08210821)
+ + ((reg4 & 0xf7def7de) >> 1)
+ + ((reg5 & 0xf7def7de) >> 1);
+
+ /* Write (d,e,j,k)-(d,j) */
+ *(to++ + dst_x/2) = reg4;
+
+ /* Write f-(e,f) */
+ reg3 = ((reg2 & 0xf7def7de) >> 1);
+ reg2 = (reg2 & 0xffff0000) | ((reg3 + (reg3 >> 16) + (reg2 & 0x0821)) & 0xffff);
+ *to = reg2;
+
+ /* Write l-(k,l) */
+ reg3 = ((reg1 & 0xf7def7de) >> 1);
+ reg1 = (reg1 & 0xffff0000) | ((reg3 + (reg3 >> 16) + (reg1 & 0x0821)) & 0xffff);
+ *(to + 2*dst_x/2) = reg1;
+
+ if (unlikely(reg1 != reg2))
+ reg1 = (reg1 & 0x08210821)
+ + ((reg1 & 0xf7def7de) >> 1)
+ + ((reg2 & 0xf7def7de) >> 1);
+
+ /* Write (f,l)-(e,f,k,l) */
+ *(to++ + dst_x/2) = reg1;
+ }
+
+ to += 2*dst_x/2;
+ from += src_x/2 + 2*pitch/2;
+ }
+}
+
+void update_normal(void)
+{
+ SDL_BlitSurface(screen,NULL,display,NULL);
+ SDL_Flip(display);
+}
+
+void update_display(void)
+{
+ if (!screen_scale)
+ SDL_BlitSurface(screen,NULL,display,NULL);
+ else
+ {
+ uint32_t *src = (uint32_t *)screen->pixels + 20 + 80 * (320 - 240);
+ gba_upscale((uint32_t*)display->pixels, src, 240, 160, 320 - 240);
+ }
+
+ SDL_Flip(display);
+}
+
+void flip_screen()
+{
+ if (!screen)
+ return;
+
+ if((video_scale != 1) && (current_scale != unscaled))
+ {
+ s32 x, y;
+ s32 x2, y2;
+ u16 *screen_ptr = get_screen_pixels();
+ u16 *current_scanline_ptr = screen_ptr;
+ u32 pitch = get_screen_pitch();
+ u16 current_pixel;
+ u32 i;
+
+ switch(video_scale)
+ {
+ case 2:
+ integer_scale_horizontal(2);
+ break;
+
+ case 3:
+ integer_scale_horizontal(3);
+ break;
+
+ default:
+ case 4:
+ integer_scale_horizontal(4);
+ break;
+
+ }
+
+ for(y = 159, y2 = (160 * video_scale) - 1; y >= 0; y--)
+ {
+ for(i = 0; i < video_scale; i++)
+ {
+ memcpy(screen_ptr + (y2 * pitch),
+ screen_ptr + (y * pitch), 480 * video_scale);
+ y2--;
+ }
+ }
+ }
+ update_normal();
+}
+
+u32 frame_to_render;
+
+void update_screen()
+{
+#ifdef ZAURUS
+ if (!screen)
+ return;
+ if(!skip_next_frame)
+ update_display();
+
+#else
+ if(!skip_next_frame)
+ flip_screen();
+#endif
+}
+
+video_scale_type screen_scale = fullscreen;
+video_scale_type current_scale = fullscreen;
+video_filter_type screen_filter = filter_bilinear;
+
+u16 *copy_screen()
+{
+#ifdef ZAURUS
+ u32 pitch = get_screen_pitch();
+ u16 *copy = malloc(240 * 160 * 2);
+ u16 *dest_ptr = copy;
+ u16 *src_ptr = get_screen_pixels() + 40 + (40 * pitch);
+ u32 line_skip = pitch - 240;
+ u32 x, y;
+
+ for(y = 0; y < 160; y++)
+ {
+ for(x = 0; x < 240; x++, src_ptr++, dest_ptr++)
+ {
+ *dest_ptr = *src_ptr;
+ }
+ src_ptr += line_skip;
+ }
+#else
+ u16 *copy = malloc(240 * 160 * 2);
+ memcpy(copy, get_screen_pixels(), 240 * 160 * 2);
+#endif
+ return copy;
+}
+
+void blit_to_screen(u16 *src, u32 w, u32 h, u32 dest_x, u32 dest_y)
+{
+ u32 pitch = get_screen_pitch();
+#ifdef ZAURUS
+ u16 *dest_ptr = get_screen_pixels();
+#else
+ u16 *dest_ptr = get_screen_pixels() + dest_x + (dest_y * pitch);
+#endif
+ u16 *src_ptr = src;
+ u32 line_skip = pitch - w;
+ u32 x, y;
+
+ for(y = 0; y < h; y++)
+ {
+ for(x = 0; x < w; x++, src_ptr++, dest_ptr++)
+ {
+ *dest_ptr = *src_ptr;
+ }
+ dest_ptr += line_skip;
+ }
+}
+
+void print_string_ext(const char *str, u16 fg_color, u16 bg_color,
+ u32 x, u32 y, void *_dest_ptr, u32 pitch, u32 pad)
+{
+ u16 *dest_ptr = (u16 *)_dest_ptr + (y * pitch) + x;
+ u8 current_char = str[0];
+ u32 current_row;
+ u32 glyph_offset;
+ u32 i = 0, i2, i3;
+ u32 str_index = 1;
+ u32 current_x = x;
+
+ while(current_char)
+ {
+ if(current_char == '\n')
+ {
+ y += FONT_HEIGHT;
+ current_x = x;
+ dest_ptr = get_screen_pixels() + (y * pitch) + x;
+ }
+ else
+ {
+ glyph_offset = _font_offset[current_char];
+ current_x += FONT_WIDTH;
+ for(i2 = 0; i2 < FONT_HEIGHT; i2++, glyph_offset++)
+ {
+ current_row = _font_bits[glyph_offset];
+ for(i3 = 0; i3 < FONT_WIDTH; i3++)
+ {
+ if((current_row >> (15 - i3)) & 0x01)
+ *dest_ptr = fg_color;
+ else
+ *dest_ptr = bg_color;
+ dest_ptr++;
+ }
+ dest_ptr += (pitch - FONT_WIDTH);
+ }
+ dest_ptr = dest_ptr - (pitch * FONT_HEIGHT) + FONT_WIDTH;
+ }
+
+ i++;
+
+ current_char = str[str_index];
+
+ if((i < pad) && (current_char == 0))
+ {
+ current_char = ' ';
+ }
+ else
+ {
+ str_index++;
+ }
+
+#ifdef ZAURUS
+ if(current_x >= 320)
+#else
+ if(current_x >= 480)
+#endif
+ break;
+ }
+}
+
+void print_string(const char *str, u16 fg_color, u16 bg_color,
+ u32 x, u32 y)
+{
+ print_string_ext(str, fg_color, bg_color, x, y, get_screen_pixels(),
+ get_screen_pitch(), 0);
+}
+
+void print_string_pad(const char *str, u16 fg_color, u16 bg_color,
+ u32 x, u32 y, u32 pad)
+{
+ print_string_ext(str, fg_color, bg_color, x, y, get_screen_pixels(),
+ get_screen_pitch(), pad);
+}
diff --git a/source/gcw0/gui.c b/source/gcw0/gui.c
new file mode 100644
index 0000000..c0f8789
--- /dev/null
+++ b/source/gcw0/gui.c
@@ -0,0 +1,1441 @@
+/* gameplaySP
+ *
+ * Copyright (C) 2006 Exophase <exophase@gmail.com>
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licens e as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <dirent.h>
+#include "common.h"
+
+#define MAX_PATH 1024
+
+// Blatantly stolen and trimmed from MZX (megazeux.sourceforge.net)
+#ifdef ZAURUS
+#define FILE_LIST_ROWS 20
+#define FILE_LIST_POSITION 1
+#define DIR_LIST_POSITION 240
+#else
+#define FILE_LIST_ROWS 25
+#define FILE_LIST_POSITION 5
+#define DIR_LIST_POSITION 360
+#endif
+
+#ifdef PSP_BUILD
+
+#define color16(red, green, blue) \
+ (blue << 11) | (green << 5) | red \
+
+#else
+
+#define color16(red, green, blue) \
+ (red << 11) | (green << 5) | blue \
+
+#endif
+
+#define COLOR_BG color16(20, 10, 10)
+#define COLOR_ROM_INFO color16(22, 36, 26)
+#define COLOR_ACTIVE_ITEM color16(31, 63, 31)
+#define COLOR_INACTIVE_ITEM color16(13, 40, 18)
+#define COLOR_FRAMESKIP_BAR color16(15, 31, 31)
+#define COLOR_HELP_TEXT color16(16, 40, 24)
+
+int sort_function(const void *dest_str_ptr, const void *src_str_ptr)
+{
+ char *dest_str = *((char **)dest_str_ptr);
+ char *src_str = *((char **)src_str_ptr);
+
+ if(src_str[0] == '.')
+ return 1;
+
+ if(dest_str[0] == '.')
+ return -1;
+
+ return strcasecmp(dest_str, src_str);
+}
+
+s32 load_file(u8 **wildcards, u8 *result)
+{
+ DIR *current_dir;
+ struct dirent *current_file;
+ struct stat file_info;
+ u8 current_dir_name[MAX_PATH];
+ u8 current_dir_short[81];
+ u32 current_dir_length;
+ u32 total_filenames_allocated;
+ u32 total_dirnames_allocated;
+ u8 **file_list;
+ u8 **dir_list;
+ u32 num_files;
+ u32 num_dirs;
+ u8 *file_name;
+ u32 file_name_length;
+ u32 ext_pos = -1;
+ u32 chosen_file, chosen_dir;
+ u32 dialog_result = 1;
+ s32 return_value = 1;
+ u32 current_file_selection;
+ u32 current_file_scroll_value;
+ u32 current_dir_selection;
+ u32 current_dir_scroll_value;
+ u32 current_file_in_scroll;
+ u32 current_dir_in_scroll;
+ u32 current_file_number, current_dir_number;
+ u32 current_column = 0;
+ u32 repeat;
+ u32 i;
+ gui_action_type gui_action;
+
+ while(return_value == 1)
+ {
+ current_file_selection = 0;
+ current_file_scroll_value = 0;
+ current_dir_selection = 0;
+ current_dir_scroll_value = 0;
+ current_file_in_scroll = 0;
+ current_dir_in_scroll = 0;
+
+ total_filenames_allocated = 32;
+ total_dirnames_allocated = 32;
+ file_list = (u8 **)malloc(sizeof(u8 *) * 32);
+ dir_list = (u8 **)malloc(sizeof(u8 *) * 32);
+ memset(file_list, 0, sizeof(u8 *) * 32);
+ memset(dir_list, 0, sizeof(u8 *) * 32);
+
+ num_files = 0;
+ num_dirs = 0;
+ chosen_file = 0;
+ chosen_dir = 0;
+
+ sprintf(current_dir_name, "%s/.gpsp", getenv("HOME"));
+ mkdir(current_dir_name, 0755);
+ current_dir = opendir(current_dir_name);
+
+ do
+ {
+ if(current_dir)
+ current_file = readdir(current_dir);
+ else
+ current_file = NULL;
+
+ if(current_file)
+ {
+ file_name = current_file->d_name;
+ file_name_length = strlen(file_name);
+
+ if((stat(file_name, &file_info) >= 0) &&
+ ((file_name[0] != '.') || (file_name[1] == '.')))
+ {
+ if(S_ISDIR(file_info.st_mode))
+ {
+ dir_list[num_dirs] =
+ (u8 *)malloc(file_name_length + 1);
+ strcpy(dir_list[num_dirs], file_name);
+
+ num_dirs++;
+ }
+ else
+ {
+ // Must match one of the wildcards, also ignore the .
+ if(file_name_length >= 4)
+ {
+ if(file_name[file_name_length - 4] == '.')
+ ext_pos = file_name_length - 4;
+ else
+
+ if(file_name[file_name_length - 3] == '.')
+ ext_pos = file_name_length - 3;
+
+ else
+ ext_pos = 0;
+
+ for(i = 0; wildcards[i] != NULL; i++)
+ {
+ if(!strcasecmp((file_name + ext_pos),
+ wildcards[i]))
+ {
+ file_list[num_files] =
+ (u8 *)malloc(file_name_length + 1);
+
+ strcpy(file_list[num_files], file_name);
+
+ num_files++;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if(num_files == total_filenames_allocated)
+ {
+ file_list = (u8 **)realloc(file_list, sizeof(u8 *) *
+ total_filenames_allocated * 2);
+ memset(file_list + total_filenames_allocated, 0,
+ sizeof(u8 *) * total_filenames_allocated);
+ total_filenames_allocated *= 2;
+ }
+
+ if(num_dirs == total_dirnames_allocated)
+ {
+ dir_list = (u8 **)realloc(dir_list, sizeof(u8 *) *
+ total_dirnames_allocated * 2);
+ memset(dir_list + total_dirnames_allocated, 0,
+ sizeof(u8 *) * total_dirnames_allocated);
+ total_dirnames_allocated *= 2;
+ }
+ }
+ } while(current_file);
+
+ qsort((void *)file_list, num_files, sizeof(u8 *), sort_function);
+ qsort((void *)dir_list, num_dirs, sizeof(u8 *), sort_function);
+
+ closedir(current_dir);
+
+ current_dir_length = strlen(current_dir_name);
+
+ if(current_dir_length > 80)
+ {
+ memcpy(current_dir_short, "...", 3);
+ memcpy(current_dir_short + 3,
+ current_dir_name + current_dir_length - 77, 77);
+ current_dir_short[80] = 0;
+ }
+ else
+ {
+ memcpy(current_dir_short, current_dir_name,
+ current_dir_length + 1);
+ }
+
+ repeat = 1;
+
+ if(num_files == 0)
+ current_column = 1;
+
+ clear_screen(COLOR_BG);
+ u8 print_buffer[81];
+
+ while(repeat)
+ {
+ flip_screen();
+
+ print_string(current_dir_short, COLOR_ACTIVE_ITEM, COLOR_BG, 0, 0);
+
+ print_string("Press Cancel to return to the main menu.",
+ COLOR_HELP_TEXT, COLOR_BG, 20, 220);
+ for(i = 0, current_file_number = i + current_file_scroll_value;
+ i < FILE_LIST_ROWS; i++, current_file_number++)
+ {
+ if(current_file_number < num_files)
+ {
+ strncpy(print_buffer,file_list[current_file_number],38);
+ print_buffer[38] = 0;
+ if((current_file_number == current_file_selection) &&
+ (current_column == 0))
+ {
+ print_string(print_buffer, COLOR_ACTIVE_ITEM,
+ COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
+ }
+ else
+ {
+ print_string(print_buffer, COLOR_INACTIVE_ITEM,
+ COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
+ }
+ }
+ }
+
+ for(i = 0, current_dir_number = i + current_dir_scroll_value;
+ i < FILE_LIST_ROWS; i++, current_dir_number++)
+ {
+ if(current_dir_number < num_dirs)
+ {
+ strncpy(print_buffer,dir_list[current_dir_number], 13);
+ print_buffer[14] = 0;
+ if((current_dir_number == current_dir_selection) &&
+ (current_column == 1))
+ {
+ print_string(print_buffer, COLOR_ACTIVE_ITEM,
+ COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
+ }
+ else
+ {
+ print_string(print_buffer, COLOR_INACTIVE_ITEM,
+ COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
+ }
+ }
+ }
+
+ gui_action = get_gui_input();
+
+ switch(gui_action)
+ {
+ case CURSOR_DOWN:
+ if(current_column == 0)
+ {
+ if(current_file_selection < (num_files - 1))
+ {
+ current_file_selection++;
+ if(current_file_in_scroll == (FILE_LIST_ROWS - 1))
+ {
+ clear_screen(COLOR_BG);
+ current_file_scroll_value++;
+ }
+ else
+ {
+ current_file_in_scroll++;
+ }
+ }
+ }
+ else
+ {
+ if(current_dir_selection < (num_dirs - 1))
+ {
+ current_dir_selection++;
+ if(current_dir_in_scroll == (FILE_LIST_ROWS - 1))
+ {
+ clear_screen(COLOR_BG);
+ current_dir_scroll_value++;
+ }
+ else
+ {
+ current_dir_in_scroll++;
+ }
+ }
+ }
+
+ break;
+
+ case CURSOR_UP:
+ if(current_column == 0)
+ {
+ if(current_file_selection)
+ {
+ current_file_selection--;
+ if(current_file_in_scroll == 0)
+ {
+ clear_screen(COLOR_BG);
+ current_file_scroll_value--;
+ }
+ else
+ {
+ current_file_in_scroll--;
+ }
+ }
+ }
+ else
+ {
+ if(current_dir_selection)
+ {
+ current_dir_selection--;
+ if(current_dir_in_scroll == 0)
+ {
+ clear_screen(COLOR_BG);
+ current_dir_scroll_value--;
+ }
+ else
+ {
+ current_dir_in_scroll--;
+ }
+ }
+ }
+ break;
+
+ case CURSOR_RIGHT:
+ if(current_column == 0)
+ {
+ if(num_dirs != 0)
+ current_column = 1;
+ }
+ break;
+
+ case CURSOR_LEFT:
+ if(current_column == 1)
+ {
+ if(num_files != 0)
+ current_column = 0;
+ }
+ break;
+
+ case CURSOR_SELECT:
+ if(current_column == 1)
+ {
+ repeat = 0;
+ chdir(dir_list[current_dir_selection]);
+ }
+ else
+ {
+ if(num_files != 0)
+ {
+ repeat = 0;
+ return_value = 0;
+ strcpy(result, file_list[current_file_selection]);
+ }
+ }
+ break;
+
+ case CURSOR_BACK:
+ repeat = 0;
+ chdir("..");
+ break;
+
+ case CURSOR_EXIT:
+ return_value = -1;
+ repeat = 0;
+ break;
+ }
+ }
+
+ for(i = 0; i < num_files; i++)
+ {
+ free(file_list[i]);
+ }
+ free(file_list);
+
+ for(i = 0; i < num_dirs; i++)
+ {
+ free(dir_list[i]);
+ }
+ free(dir_list);
+ }
+
+ clear_screen(COLOR_BG);
+ return return_value;
+}
+
+typedef enum
+{
+ NUMBER_SELECTION_OPTION = 0x01,
+ STRING_SELECTION_OPTION = 0x02,
+ SUBMENU_OPTION = 0x04,
+ ACTION_OPTION = 0x08
+} menu_option_type_enum;
+
+struct _menu_type
+{
+ void (* init_function)();
+ void (* passive_function)();
+ struct _menu_option_type *options;
+ u32 num_options;
+};
+
+struct _menu_option_type
+{
+ void (* action_function)();
+ void (* passive_function)();
+ struct _menu_type *sub_menu;
+ char *display_string;
+ void *options;
+ u32 *current_option;
+ u32 num_options;
+ char *help_string;
+ u32 line_number;
+ menu_option_type_enum option_type;
+};
+
+typedef struct _menu_option_type menu_option_type;
+typedef struct _menu_type menu_type;
+
+#define make_menu(name, init_function, passive_function) \
+ menu_type name##_menu = \
+ { \
+ init_function, \
+ passive_function, \
+ name##_options, \
+ sizeof(name##_options) / sizeof(menu_option_type) \
+ } \
+
+#define gamepad_config_option(display_string, number) \
+{ \
+ NULL, \
+ menu_fix_gamepad_help, \
+ NULL, \
+ display_string ": %s", \
+ gamepad_config_buttons, \
+ gamepad_config_map + gamepad_config_line_to_psp_button[number], \
+ sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
+ gamepad_help[gamepad_config_map[ \
+ gamepad_config_line_to_psp_button[number]]], \
+ number, \
+ STRING_SELECTION_OPTION \
+} \
+
+#define analog_config_option(display_string, number) \
+{ \
+ NULL, \
+ menu_fix_gamepad_help, \
+ NULL, \
+ display_string ": %s", \
+ gamepad_config_buttons, \
+ gamepad_config_map + number + 12, \
+ sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
+ gamepad_help[gamepad_config_map[number + 12]], \
+ number + 2, \
+ STRING_SELECTION_OPTION \
+} \
+
+#define cheat_option(number) \
+{ \
+ NULL, \
+ NULL, \
+ NULL, \
+ cheat_format_str[number], \
+ enable_disable_options, \
+ &(cheats[number].cheat_active), \
+ 2, \
+ "Activate/deactivate this cheat code.", \
+ number, \
+ STRING_SELECTION_OPTION \
+} \
+
+#define action_option(action_function, passive_function, display_string, \
+ help_string, line_number) \
+{ \
+ action_function, \
+ passive_function, \
+ NULL, \
+ display_string, \
+ NULL, \
+ NULL, \
+ 0, \
+ help_string, \
+ line_number, \
+ ACTION_OPTION \
+} \
+
+#define submenu_option(sub_menu, display_string, help_string, line_number) \
+{ \
+ NULL, \
+ NULL, \
+ sub_menu, \
+ display_string, \
+ NULL, \
+ NULL, \
+ sizeof(sub_menu) / sizeof(menu_option_type), \
+ help_string, \
+ line_number, \
+ SUBMENU_OPTION \
+} \
+
+#define selection_option(passive_function, display_string, options, \
+ option_ptr, num_options, help_string, line_number, type) \
+{ \
+ NULL, \
+ passive_function, \
+ NULL, \
+ display_string, \
+ options, \
+ option_ptr, \
+ num_options, \
+ help_string, \
+ line_number, \
+ type \
+} \
+
+#define action_selection_option(action_function, passive_function, \
+ display_string, options, option_ptr, num_options, help_string, line_number, \
+ type) \
+{ \
+ action_function, \
+ passive_function, \
+ NULL, \
+ display_string, \
+ options, \
+ option_ptr, \
+ num_options, \
+ help_string, \
+ line_number, \
+ type | ACTION_OPTION \
+} \
+
+
+#define string_selection_option(passive_function, display_string, options, \
+ option_ptr, num_options, help_string, line_number) \
+ selection_option(passive_function, display_string ": %s", options, \
+ option_ptr, num_options, help_string, line_number, STRING_SELECTION_OPTION)\
+
+#define numeric_selection_option(passive_function, display_string, \
+ option_ptr, num_options, help_string, line_number) \
+ selection_option(passive_function, display_string ": %d", NULL, option_ptr, \
+ num_options, help_string, line_number, NUMBER_SELECTION_OPTION) \
+
+#define string_selection_action_option(action_function, passive_function, \
+ display_string, options, option_ptr, num_options, help_string, line_number) \
+ action_selection_option(action_function, passive_function, \
+ display_string ": %s", options, option_ptr, num_options, help_string, \
+ line_number, STRING_SELECTION_OPTION) \
+
+#define numeric_selection_action_option(action_function, passive_function, \
+ display_string, option_ptr, num_options, help_string, line_number) \
+ action_selection_option(action_function, passive_function, \
+ display_string ": %d", NULL, option_ptr, num_options, help_string, \
+ line_number, NUMBER_SELECTION_OPTION) \
+
+#define numeric_selection_action_hide_option(action_function, \
+ passive_function, display_string, option_ptr, num_options, help_string, \
+ line_number) \
+ action_selection_option(action_function, passive_function, \
+ display_string, NULL, option_ptr, num_options, help_string, \
+ line_number, NUMBER_SELECTION_OPTION) \
+
+
+#define GAMEPAD_MENU_WIDTH 15
+
+u32 gamepad_config_line_to_psp_button[] =
+ { 8, 6, 7, 9, 1, 2, 3, 0, 4, 5, 11, 10 };
+
+s32 load_game_config_file()
+{
+ u8 game_config_filename[512];
+ u32 file_loaded = 0;
+ u32 i;
+ change_ext(gamepak_filename, game_config_filename, ".cfg");
+
+ FILE_OPEN(game_config_file, game_config_filename, read);
+
+ if(file_check_valid(game_config_file))
+ {
+ u32 file_size = FILE_LENGTH(game_config_file);
+
+ // Sanity check: File size must be the right size
+ if(file_size == 56)
+ {
+ u32 file_options[file_size / 4];
+
+ FILE_READ_ARRAY(game_config_file, file_options);
+ current_frameskip_type = file_options[0] % 3;
+ frameskip_value = file_options[1];
+ random_skip = file_options[2] & 1;
+ clock_speed = global_cycles_per_instruction = file_options[3];
+
+ if(frameskip_value < 0)
+ frameskip_value = 0;
+
+ if(frameskip_value > 99)
+ frameskip_value = 99;
+
+
+ file_loaded = 1;
+ }
+ FILE_CLOSE(game_config_file);
+ }
+
+ if(file_loaded)
+ return 0;
+
+ current_frameskip_type = auto_frameskip;
+ frameskip_value = 4;
+ random_skip = 0;
+ clock_speed = 4;
+
+ for(i = 0; i < 10; i++)
+ {
+ cheats[i].cheat_active = 0;
+ }
+
+ return -1;
+}
+
+s32 load_config_file()
+{
+ u8 config_path[512];
+ sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
+
+ FILE_OPEN(config_file, config_path, read);
+
+ if(FILE_CHECK_VALID(config_file))
+ {
+ u32 file_size = FILE_LENGTH(config_file);
+
+ // Sanity check: File size must be the right size
+ if(file_size == 92)
+ {
+ u32 file_options[file_size / 4];
+ u32 i;
+ s32 menu_button = -1;
+ file_read_array(config_file, file_options);
+
+ screen_scale = file_options[0] % 2;
+ screen_filter = file_options[1] % 2;
+ global_enable_audio = file_options[2] % 2;
+#ifdef ZAURUS
+ audio_buffer_size_number = file_options[3] % 4;
+#else
+ audio_buffer_size_number = file_options[3] % 11;
+#endif
+ update_backup_flag = file_options[4] % 2;
+ global_enable_analog = file_options[5] % 2;
+ analog_sensitivity_level = file_options[6] % 8;
+
+ // Sanity check: Make sure there's a MENU or FRAMESKIP
+ // key, if not assign to triangle
+
+ for(i = 0; i < 16; i++)
+ {
+ gamepad_config_map[i] = file_options[7 + i] %
+ (BUTTON_ID_NONE + 1);
+
+ if(gamepad_config_map[i] == BUTTON_ID_MENU)
+ {
+ menu_button = i;
+ }
+ }
+
+ if(menu_button == -1)
+ {
+ gamepad_config_map[0] = BUTTON_ID_MENU;
+ }
+ }
+
+ FILE_CLOSE(config_file);
+
+ return 0;
+ }
+
+ return -1;
+}
+
+s32 save_game_config_file()
+{
+ u8 game_config_filename[512];
+ u32 i;
+
+ change_ext(gamepak_filename, game_config_filename, ".cfg");
+
+ FILE_OPEN(game_config_file, game_config_filename, write);
+
+ if(FILE_CHECK_VALID(game_config_file))
+ {
+ u32 file_options[14];
+
+ file_options[0] = current_frameskip_type;
+ file_options[1] = frameskip_value;
+ file_options[2] = random_skip;
+ file_options[3] = clock_speed;
+
+ for(i = 0; i < 10; i++)
+ {
+ file_options[4 + i] = cheats[i].cheat_active;
+ }
+
+ FILE_WRITE_ARRAY(game_config_file, file_options);
+ FILE_CLOSE(game_config_file);
+
+ return 0;
+ }
+
+ return -1;
+}
+
+s32 save_config_file()
+{
+ u8 config_path[512];
+ sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
+
+ FILE_OPEN(config_file, config_path, write);
+
+ save_game_config_file();
+
+ if(FILE_CHECK_VALID(config_file))
+ {
+ u32 file_options[23];
+ u32 i;
+
+ file_options[0] = screen_scale;
+ file_options[1] = screen_filter;
+ file_options[2] = global_enable_audio;
+ file_options[3] = audio_buffer_size_number;
+ file_options[4] = update_backup_flag;
+ file_options[5] = global_enable_analog;
+ file_options[6] = analog_sensitivity_level;
+
+ for(i = 0; i < 16; i++)
+ {
+ file_options[7 + i] = gamepad_config_map[i];
+ }
+
+ FILE_WRITE_ARRAY(config_file, file_options);
+ FILE_CLOSE(config_file);
+
+ return 0;
+ }
+
+ return -1;
+}
+
+typedef enum
+{
+ MAIN_MENU,
+ GAMEPAD_MENU,
+ SAVESTATE_MENU,
+ FRAMESKIP_MENU,
+ CHEAT_MENU
+} menu_enum;
+
+u32 savestate_slot = 0;
+u8 ssmsg[8];
+u32 status_display = 0;
+
+void get_savestate_snapshot(u8 *savestate_filename)
+{
+ /* Unimplemented. Need to figure out a way to show this screenshot on a
+ * 320x240 screen first. - Neb, 2013-08-19 */
+#if 0
+ u16 snapshot_buffer[240 * 160];
+ u8 savestate_timestamp_string[80];
+
+ FILE_OPEN(savestate_file, savestate_filename, read);
+
+ if(FILE_CHECK_VALID(savestate_file))
+ {
+ u8 weekday_strings[7][11] =
+ {
+ "Sunday", "Monday", "Tuesday", "Wednesday",
+ "Thursday", "Friday", "Saturday"
+ };
+ time_t savestate_time_flat;
+ struct tm *current_time;
+ file_read_array(savestate_file, snapshot_buffer);
+ file_read_variable(savestate_file, savestate_time_flat);
+
+ file_close(savestate_file);
+
+ current_time = localtime(&savestate_time_flat);
+ sprintf(savestate_timestamp_string,
+ "%s %02d/%02d/%04d %02d:%02d:%02d ",
+ weekday_strings[current_time->tm_wday], current_time->tm_mon + 1,
+ current_time->tm_mday, current_time->tm_year + 1900,
+ current_time->tm_hour, current_time->tm_min, current_time->tm_sec);
+
+ savestate_timestamp_string[40] = 0;
+ print_string(savestate_timestamp_string, COLOR_HELP_TEXT, COLOR_BG,
+ 10, 40);
+ }
+ else
+ {
+ memset(snapshot_buffer, 0, 240 * 160 * 2);
+ print_string_ext("No savestate exists for this slot.",
+ 0xFFFF, 0x0000, 15, 75, snapshot_buffer, 240, 0);
+ print_string("---------- --/--/---- --:--:-- ", COLOR_HELP_TEXT,
+ COLOR_BG, 10, 40);
+ }
+#endif
+}
+
+void get_savestate_filename(u32 slot, u8 *name_buffer)
+{
+ u8 savestate_ext[16];
+
+ sprintf(savestate_ext, "%d.svs", slot);
+ change_ext(gamepak_filename, name_buffer, savestate_ext);
+
+ get_savestate_snapshot(name_buffer);
+}
+
+void get_savestate_filename_noshot(u32 slot, u8 *name_buffer)
+{
+ u8 savestate_ext[16];
+
+ sprintf(savestate_ext, "%d.svs", slot);
+ change_ext(gamepak_filename, name_buffer, savestate_ext);
+}
+
+u32 ReGBA_Menu(enum ReGBA_MenuEntryReason EntryReason)
+{
+ u32 clock_speed_number = clock_speed - 1;
+ u8 print_buffer[81];
+ u32 _current_option = 0;
+ gui_action_type gui_action;
+ menu_enum _current_menu = MAIN_MENU;
+ u32 i;
+ u32 repeat = 1;
+ u32 return_value = 0;
+ u32 first_load = 0;
+ u8 savestate_ext[16];
+ u8 current_savestate_filename[512];
+ u8 line_buffer[80];
+ u8 cheat_format_str[10][41];
+
+ menu_type *current_menu;
+ menu_option_type *current_option;
+ menu_option_type *display_option;
+ u32 current_option_num;
+
+ auto void choose_menu();
+ auto void clear_help();
+
+ u8 *gamepad_help[] =
+ {
+ "Up button on GBA d-pad.",
+ "Down button on GBA d-pad.",
+ "Left button on GBA d-pad.",
+ "Right button on GBA d-pad.",
+ "A button on GBA.",
+ "B button on GBA.",
+ "Left shoulder button on GBA.",
+ "Right shoulder button on GBA.",
+ "Start button on GBA.",
+ "Select button on GBA.",
+ "Brings up frameskip adjust bar and menu access.",
+ "Jumps directly to the menu.",
+ "Toggles fastforward on/off (don't expect it to do much or anything)",
+ "Loads the game state from the current slot.",
+ "Saves the game state to the current slot.",
+ "Rapidly press/release the A button on GBA.",
+ "Rapidly press/release the B button on GBA.",
+ "Rapidly press/release the Left shoulder button on GBA.",
+ "Rapidly press/release the Right shoulder button on GBA.",
+ "Does nothing."
+ };
+
+ void menu_exit()
+ {
+ if(!first_load)
+ repeat = 0;
+ }
+
+ void menu_quit()
+ {
+ clock_speed = clock_speed_number + 1;
+ save_config_file();
+ quit();
+ }
+
+ void menu_load()
+ {
+ u8 *file_ext[] = { ".gba", ".bin", ".zip", NULL };
+ u8 load_filename[512];
+ save_game_config_file();
+ if(load_file(file_ext, load_filename) != -1)
+ {
+ if(load_gamepak(load_filename) == -1)
+ {
+ quit();
+ }
+ reset_gba();
+ return_value = 1;
+ repeat = 0;
+ reg[CHANGED_PC_STATUS] = 1;
+ }
+ else
+ {
+ choose_menu(current_menu);
+ }
+ }
+
+ void menu_restart()
+ {
+ if(!first_load)
+ {
+ reset_gba();
+ reg[CHANGED_PC_STATUS] = 1;
+ return_value = 1;
+ repeat = 0;
+ }
+ }
+
+ void menu_change_state()
+ {
+ get_savestate_filename(savestate_slot, current_savestate_filename);
+ }
+
+ void menu_save_state()
+ {
+ if(!first_load)
+ {
+ get_savestate_filename_noshot(savestate_slot,
+ current_savestate_filename);
+ save_state(current_savestate_filename, original_screen);
+ }
+ menu_change_state();
+ }
+
+ void menu_load_state()
+ {
+ if(!first_load)
+ {
+ load_state(current_savestate_filename);
+ return_value = 1;
+ repeat = 0;
+ }
+ }
+
+ void menu_load_state_file()
+ {
+ u8 *file_ext[] = { ".svs", NULL };
+ u8 load_filename[512];
+ if(load_file(file_ext, load_filename) != -1)
+ {
+ load_state(load_filename);
+ return_value = 1;
+ repeat = 0;
+ }
+ else
+ {
+ choose_menu(current_menu);
+ }
+ }
+
+ void menu_fix_gamepad_help()
+ {
+ clear_help();
+ current_option->help_string =
+ gamepad_help[gamepad_config_map[
+ gamepad_config_line_to_psp_button[current_option_num]]];
+ }
+
+ void submenu_graphics_sound()
+ {
+
+ }
+
+ void submenu_cheats_misc()
+ {
+
+ }
+
+ void submenu_gamepad()
+ {
+
+ }
+
+ void submenu_analog()
+ {
+
+ }
+
+ void submenu_savestate()
+ {
+ print_string("Savestate options:", COLOR_ACTIVE_ITEM, COLOR_BG, 10, 70);
+ menu_change_state();
+ }
+
+ void submenu_main()
+ {
+ get_savestate_filename_noshot(savestate_slot,
+ current_savestate_filename);
+ }
+
+ u8 *yes_no_options[] = { "no", "yes" };
+ u8 *enable_disable_options[] = { "disabled", "enabled" };
+
+ u8 *scale_options[] =
+ {
+ "normal", "fullscreen"
+ };
+
+ u8 *frameskip_options[] = { "automatic", "manual", "off" };
+ u8 *frameskip_variation_options[] = { "uniform", "random" };
+
+#if 0
+ u8 *audio_buffer_options[] =
+ {
+ "3072 bytes", "4096 bytes", "5120 bystes", "6144 bytes", "7168 bytes",
+ "8192 bytes", "9216 bytes", "10240 bytes", "11264 bytes", "12288 bytes"
+ };
+
+#endif
+ u8 *update_backup_options[] = { "Exit only", "Automatic" };
+
+#ifndef ZAURUS
+ u8 *gamepad_config_buttons[] =
+ {
+ "UP",
+ "DOWN",
+ "LEFT",
+ "RIGHT",
+ "A",
+ "B",
+ "L",
+ "R",
+ "START",
+ "SELECT",
+ "MENU",
+ "FASTFORWARD",
+ "LOAD STATE",
+ "SAVE STATE",
+ "RAPIDFIRE A",
+ "RAPIDFIRE B",
+ "RAPIDFIRE L",
+ "RAPIDFIRE R",
+ "NOTHING"
+ };
+#endif
+
+ // Marker for help information, don't go past this mark (except \n)------*
+ menu_option_type graphics_sound_options[] =
+ {
+ string_selection_option(NULL, "Display scaling", scale_options,
+ (u32 *)(&screen_scale), 2,
+ "Determines how the GBA screen is resized in relation to the entire\n"
+ "screen. Select unscaled 3:2 for GBA resolution, scaled 3:2 for GBA\n"
+ "aspect ratio scaled to fill the height of the PSP screen, and\n"
+ "fullscreen to fill the entire PSP screen.", 2),
+#ifndef ZAURUS
+ string_selection_option(NULL, "Screen filtering", yes_no_options,
+ (u32 *)(&screen_filter), 2,
+ "Determines whether or not bilinear filtering should be used when\n"
+ "scaling the screen. Selecting this will produce a more even and\n"
+ "smooth image, at the cost of being blurry and having less vibrant\n"
+ "colors.", 3),
+#endif
+ string_selection_option(NULL, "Frameskip type", frameskip_options,
+ (u32 *)(&current_frameskip_type), 3,
+ "Determines what kind of frameskipping should be employed.\n"
+ "Frameskipping may improve emulation speed of many games.\n"
+ "Off: Do not skip any frames.\n"
+ "Auto: Skip up to N frames (see next option) as needed.\n"
+ "Manual: Always render only 1 out of N + 1 frames.", 5),
+ numeric_selection_option(NULL, "Frameskip value", &frameskip_value, 100,
+ "For auto frameskip, determines the maximum number of frames that\n"
+ "are allowed to be skipped consecutively.\n"
+ "For manual frameskip, determines the number of frames that will\n"
+ "always be skipped.", 6),
+ string_selection_option(NULL, "Framskip variation",
+ frameskip_variation_options, &random_skip, 2,
+ "If objects in the game flicker at a regular rate certain manual\n"
+ "frameskip values may cause them to normally disappear. Change this\n"
+ "value to 'random' to avoid this. Do not use otherwise, as it tends to\n"
+ "make the image quality worse, especially in high motion games.", 7),
+ string_selection_option(NULL, "Audio output", yes_no_options,
+ &global_enable_audio, 2,
+ "Select 'no' to turn off all audio output. This will not result in a\n"
+ "significant change in performance.", 9),
+#if 0
+ string_selection_option(NULL, "Audio buffer", audio_buffer_options,
+ &audio_buffer_size_number, 10,
+ "Set the size (in bytes) of the audio buffer. Larger values may result\n"
+ "in slightly better performance at the cost of latency; the lowest\n"
+ "value will give the most responsive audio.\n"
+ "This option requires gpSP to be restarted before it will take effect.",
+ 10),
+#endif
+ string_selection_option(NULL, "Status Display", enable_disable_options,
+ &status_display, 2,
+ "Display fps and some infomation.",12),
+
+ submenu_option(NULL, "Back", "Return to the main menu.", 14)
+ };
+
+ make_menu(graphics_sound, submenu_graphics_sound, NULL);
+
+ menu_option_type cheats_misc_options[] =
+ {
+ cheat_option(0),
+ cheat_option(1),
+ cheat_option(2),
+ cheat_option(3),
+ cheat_option(4),
+ cheat_option(5),
+ cheat_option(6),
+ cheat_option(7),
+ cheat_option(8),
+ cheat_option(9),
+ string_selection_option(NULL, "Update backup",
+ update_backup_options, &update_backup_flag, 2,
+ "Determines when in-game save files should be written back to\n"
+ "memstick. If set to 'automatic' writebacks will occur shortly after\n"
+ "the game's backup is altered. On 'exit only' it will only be written\n"
+ "back when you exit from this menu (NOT from using the home button).\n"
+ "Use the latter with extreme care.", 12),
+ submenu_option(NULL, "Back", "Return to the main menu.", 14)
+ };
+
+ make_menu(cheats_misc, submenu_cheats_misc, NULL);
+
+ menu_option_type savestate_options[] =
+ {
+ numeric_selection_action_hide_option(menu_load_state, menu_change_state,
+ "Load savestate from current slot", &savestate_slot, 10,
+ "Select to load the game state from the current slot for this game.\n"
+ "Press left + right to change the current slot.", 6),
+ numeric_selection_action_hide_option(menu_save_state, menu_change_state,
+ "Save savestate to current slot", &savestate_slot, 10,
+ "Select to save the game state to the current slot for this game.\n"
+ "Press left + right to change the current slot.", 7),
+ numeric_selection_action_hide_option(menu_load_state_file,
+ menu_change_state,
+ "Load savestate from file", &savestate_slot, 10,
+ "Restore gameplay from a savestate file.\n"
+ "Note: The same file used to save the state must be present.\n", 9),
+ numeric_selection_option(menu_change_state,
+ "Current savestate slot", &savestate_slot, 10,
+ "Change the current savestate slot.\n", 11),
+ submenu_option(NULL, "Back", "Return to the main menu.", 13)
+ };
+
+ make_menu(savestate, submenu_savestate, NULL);
+
+#ifndef ZAURUS
+ menu_option_type gamepad_config_options[] =
+ {
+ gamepad_config_option("D-pad up ", 0),
+ gamepad_config_option("D-pad down ", 1),
+ gamepad_config_option("D-pad left ", 2),
+ gamepad_config_option("D-pad right ", 3),
+ gamepad_config_option("Circle ", 4),
+ gamepad_config_option("Cross ", 5),
+ gamepad_config_option("Square ", 6),
+ gamepad_config_option("Triangle ", 7),
+ gamepad_config_option("Left Trigger ", 8),
+ gamepad_config_option("Right Trigger", 9),
+ gamepad_config_option("Start ", 10),
+ gamepad_config_option("Select ", 11),
+ submenu_option(NULL, "Back", "Return to the main menu.", 13)
+ };
+
+ make_menu(gamepad_config, submenu_gamepad, NULL);
+
+ menu_option_type analog_config_options[] =
+ {
+ analog_config_option("Analog up ", 0),
+ analog_config_option("Analog down ", 1),
+ analog_config_option("Analog left ", 2),
+ analog_config_option("Analog right", 3),
+ string_selection_option(NULL, "Enable analog", yes_no_options,
+ &global_enable_analog, 2,
+ "Select 'no' to block analog input entirely.", 7),
+ numeric_selection_option(NULL, "Analog sensitivity",
+ &analog_sensitivity_level, 10,
+ "Determine sensitivity/responsiveness of the analog input.\n"
+ "Lower numbers are less sensitive.", 8),
+ submenu_option(NULL, "Back", "Return to the main menu.", 11)
+ };
+
+ make_menu(analog_config, submenu_analog, NULL);
+#endif
+
+ menu_option_type main_options[] =
+ {
+ submenu_option(&graphics_sound_menu, "Graphics and Sound options",
+ "Select to set display parameters and frameskip behavior,\n"
+ "audio on/off, audio buffer size, and audio filtering.", 0),
+ numeric_selection_action_option(menu_load_state, NULL,
+ "Load state from slot", &savestate_slot, 10,
+ "Select to load the game state from the current slot for this game,\n"
+ "if it exists (see the extended menu for more information)\n"
+ "Press left + right to change the current slot.", 2),
+ numeric_selection_action_option(menu_save_state, NULL,
+ "Save state to slot", &savestate_slot, 10,
+ "Select to save the game state to the current slot for this game.\n"
+ "See the extended menu for more information.\n"
+ "Press left + right to change the current slot.", 3),
+ submenu_option(&savestate_menu, "Savestate options",
+ "Select to enter a menu for loading, saving, and viewing the\n"
+ "currently active savestate for this game (or to load a savestate\n"
+ "file from another game)", 4),
+#ifndef ZAURUS
+ submenu_option(&gamepad_config_menu, "Configure gamepad input",
+ "Select to change the in-game behavior of the PSP buttons and d-pad.",
+ 6),
+ submenu_option(&analog_config_menu, "Configure analog input",
+ "Select to change the in-game behavior of the PSP analog nub.", 7),
+#endif
+ submenu_option(&cheats_misc_menu, "Cheats and Miscellaneous options",
+ "Select to manage cheats, set backup behavior, and set device clock\n"
+ "speed.", 9),
+ action_option(menu_restart, NULL, "Restart game",
+ "Select to reset the GBA with the current game loaded.", 11),
+ action_option(menu_exit, NULL, "Return to game",
+ "Select to exit this menu and resume gameplay.", 12),
+ action_option(menu_quit, NULL, "Exit gpSP",
+ "Select to exit gpSP and return to the PSP XMB/loader.", 14)
+ };
+
+ make_menu(main, submenu_main, NULL);
+
+ void choose_menu(menu_type *new_menu)
+ {
+ if(new_menu == NULL)
+ new_menu = &main_menu;
+
+ clear_screen(COLOR_BG);
+
+ blit_to_screen(original_screen, 240, 160, 230, 40);
+
+ current_menu = new_menu;
+ current_option = new_menu->options;
+ current_option_num = 0;
+ if(current_menu->init_function)
+ current_menu->init_function();
+ }
+
+ void clear_help()
+ {
+#ifndef ZAURUS
+ for(i = 0; i < 6; i++)
+ {
+ print_string_pad(" ", COLOR_BG, COLOR_BG, 30, 210 + (i * 10), 70);
+ }
+#endif
+ }
+
+ video_resolution_large();
+
+ SDL_LockMutex(sound_mutex);
+ SDL_PauseAudio(1);
+ SDL_UnlockMutex(sound_mutex);
+
+ if(gamepak_filename[0] == 0)
+ {
+ first_load = 1;
+ memset(original_screen, 0x00, 240 * 160 * 2);
+ print_string_ext("No game loaded yet.", 0xFFFF, 0x0000,
+ 60, 75,original_screen, 240, 0);
+ }
+
+ choose_menu(&main_menu);
+
+ for(i = 0; i < 10; i++)
+ {
+ if(i >= num_cheats)
+ {
+ sprintf(cheat_format_str[i], "cheat %d (none loaded)", i);
+ }
+ else
+ {
+ sprintf(cheat_format_str[i], "cheat %d (%s): %%s", i,
+ cheats[i].cheat_name);
+ }
+ }
+
+ current_menu->init_function();
+
+ while(repeat)
+ {
+ display_option = current_menu->options;
+
+ for(i = 0; i < current_menu->num_options; i++, display_option++)
+ {
+ if(display_option->option_type & NUMBER_SELECTION_OPTION)
+ {
+ sprintf(line_buffer, display_option->display_string,
+ *(display_option->current_option));
+ }
+ else
+
+ if(display_option->option_type & STRING_SELECTION_OPTION && strchr(display_option->display_string, '%'))
+ {
+ sprintf(line_buffer, display_option->display_string,
+ ((u32 *)display_option->options)[*(display_option->current_option)]);
+ }
+ else
+ {
+ strcpy(line_buffer, display_option->display_string);
+ }
+
+ if(display_option == current_option)
+ {
+ print_string_pad(line_buffer, COLOR_ACTIVE_ITEM, COLOR_BG, 10,
+ (display_option->line_number * 10) + 40, 36);
+ }
+ else
+ {
+ print_string_pad(line_buffer, COLOR_INACTIVE_ITEM, COLOR_BG, 10,
+ (display_option->line_number * 10) + 40, 36);
+ }
+ }
+#ifndef ZAURUS
+ print_string(current_option->help_string, COLOR_HELP_TEXT,
+ COLOR_BG, 30, 210);
+#endif
+ flip_screen();
+
+ gui_action = get_gui_input();
+
+ switch(gui_action)
+ {
+ case CURSOR_DOWN:
+ current_option_num = (current_option_num + 1) %
+ current_menu->num_options;
+
+ current_option = current_menu->options + current_option_num;
+ clear_help();
+ break;
+
+ case CURSOR_UP:
+ if(current_option_num)
+ current_option_num--;
+ else
+ current_option_num = current_menu->num_options - 1;
+
+ current_option = current_menu->options + current_option_num;
+ clear_help();
+ break;
+
+ case CURSOR_RIGHT:
+ if(current_option->option_type & (NUMBER_SELECTION_OPTION |
+ STRING_SELECTION_OPTION))
+ {
+ *(current_option->current_option) =
+ (*current_option->current_option + 1) %
+ current_option->num_options;
+
+ if(current_option->passive_function)
+ current_option->passive_function();
+ }
+ break;
+
+ case CURSOR_LEFT:
+ if(current_option->option_type & (NUMBER_SELECTION_OPTION |
+ STRING_SELECTION_OPTION))
+ {
+ u32 current_option_val = *(current_option->current_option);
+
+ if(current_option_val)
+ current_option_val--;
+ else
+ current_option_val = current_option->num_options - 1;
+
+ *(current_option->current_option) = current_option_val;
+
+ if(current_option->passive_function)
+ current_option->passive_function();
+ }
+ break;
+
+ case CURSOR_EXIT:
+ if(current_menu == &main_menu)
+ menu_exit();
+
+ choose_menu(&main_menu);
+ break;
+
+ case CURSOR_SELECT:
+ if(current_option->option_type & ACTION_OPTION)
+ current_option->action_function();
+
+ if(current_option->option_type & SUBMENU_OPTION)
+ choose_menu(current_option->sub_menu);
+ break;
+ }
+ }
+
+ set_gba_resolution(screen_scale);
+ video_resolution_small();
+
+ global_cycles_per_instruction = clock_speed_number + 1;
+
+ SDL_PauseAudio(0);
+
+ clear_screen(0);
+ flip_screen();
+ flip_screen();
+
+ return return_value;
+}
diff --git a/source/gcw0/main.c b/source/gcw0/main.c
new file mode 100644
index 0000000..8bfea80
--- /dev/null
+++ b/source/gcw0/main.c
@@ -0,0 +1,609 @@
+/* gameplaySP
+ *
+ * Copyright (C) 2006 Exophase <exophase@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "common.h"
+#include <sys/time.h>
+#include <stdlib.h>
+
+extern SDL_Surface *screen;
+
+timer_type timer[4];
+
+frameskip_type current_frameskip_type = auto_frameskip;
+u32 frameskip_value = 4;
+u32 random_skip = 0;
+u32 global_cycles_per_instruction = 3;
+u32 skip_next_frame = 0;
+
+u32 frameskip_counter = 0;
+
+u32 cpu_ticks = 0;
+u32 frame_ticks = 0;
+
+u32 execute_cycles = 960;
+s32 video_count = 960;
+u32 ticks;
+
+u32 arm_frame = 0;
+u32 thumb_frame = 0;
+u32 last_frame = 0;
+
+u32 cycle_memory_access = 0;
+u32 cycle_pc_relative_access = 0;
+u32 cycle_sp_relative_access = 0;
+u32 cycle_block_memory_access = 0;
+u32 cycle_block_memory_sp_access = 0;
+u32 cycle_block_memory_words = 0;
+u32 cycle_dma16_words = 0;
+u32 cycle_dma32_words = 0;
+u32 flush_ram_count = 0;
+u32 gbc_update_count = 0;
+u32 oam_update_count = 0;
+
+u32 synchronize_flag = 1;
+
+u32 update_backup_flag = 1;
+u32 clock_speed = 333;
+u8 main_path[512];
+
+#define check_count(count_var) \
+ if(count_var < execute_cycles) \
+ execute_cycles = count_var; \
+
+#define check_timer(timer_number) \
+ if(timer[timer_number].status == TIMER_PRESCALE) \
+ check_count(timer[timer_number].count); \
+
+#define update_timer(timer_number) \
+ if(timer[timer_number].status != TIMER_INACTIVE) \
+ { \
+ if(timer[timer_number].status != TIMER_CASCADE) \
+ { \
+ timer[timer_number].count -= execute_cycles; \
+ io_registers[REG_TM##timer_number##D] = \
+ -(timer[timer_number].count >> timer[timer_number].prescale); \
+ } \
+ \
+ if(timer[timer_number].count <= 0) \
+ { \
+ if(timer[timer_number].irq == TIMER_TRIGGER_IRQ) \
+ irq_raised |= IRQ_TIMER##timer_number; \
+ \
+ if((timer_number != 3) && \
+ (timer[timer_number + 1].status == TIMER_CASCADE)) \
+ { \
+ timer[timer_number + 1].count--; \
+ io_registers[REG_TM0D + (timer_number + 1) * 2] = \
+ -(timer[timer_number + 1].count); \
+ } \
+ \
+ if(timer_number < 2) \
+ { \
+ if(timer[timer_number].direct_sound_channels & 0x01) \
+ sound_timer(timer[timer_number].frequency_step, 0); \
+ \
+ if(timer[timer_number].direct_sound_channels & 0x02) \
+ sound_timer(timer[timer_number].frequency_step, 1); \
+ } \
+ \
+ timer[timer_number].count += \
+ (timer[timer_number].reload << timer[timer_number].prescale); \
+ } \
+ } \
+
+u8 *file_ext[] = { ".gba", ".bin", ".zip", NULL };
+
+static u8 caches_inited = 0;
+
+void init_main()
+{
+ u32 i;
+
+ skip_next_frame = 0;
+
+ for(i = 0; i < 4; i++)
+ {
+ dma[i].start_type = DMA_INACTIVE;
+ dma[i].direct_sound_channel = DMA_NO_DIRECT_SOUND;
+ timer[i].status = TIMER_INACTIVE;
+ timer[i].reload = 0x10000;
+ timer[i].stop_cpu_ticks = 0;
+ }
+
+ timer[0].direct_sound_channels = TIMER_DS_CHANNEL_BOTH;
+ timer[1].direct_sound_channels = TIMER_DS_CHANNEL_NONE;
+
+ cpu_ticks = 0;
+ frame_ticks = 0;
+
+ execute_cycles = 960;
+ video_count = 960;
+
+ if (!caches_inited)
+ {
+ flush_translation_cache(TRANSLATION_REGION_READONLY, FLUSH_REASON_INITIALIZING);
+ flush_translation_cache(TRANSLATION_REGION_WRITABLE, FLUSH_REASON_INITIALIZING);
+ }
+ else
+ {
+ flush_translation_cache(TRANSLATION_REGION_READONLY, FLUSH_REASON_LOADING_ROM);
+ clear_metadata_area(METADATA_AREA_EWRAM, CLEAR_REASON_LOADING_ROM);
+ clear_metadata_area(METADATA_AREA_IWRAM, CLEAR_REASON_LOADING_ROM);
+ clear_metadata_area(METADATA_AREA_VRAM, CLEAR_REASON_LOADING_ROM);
+ }
+
+ caches_inited = 1;
+
+ StatsInitGame();
+}
+
+int main(int argc, char *argv[])
+{
+ u32 i;
+ u32 vcount = 0;
+ u32 ticks;
+ u32 dispstat;
+ u8 load_filename[512];
+ u8 bios_file[512];
+
+#ifdef PSP_BUILD
+ sceKernelRegisterSubIntrHandler(PSP_VBLANK_INT, 0,
+ vblank_interrupt_handler, NULL);
+ sceKernelEnableSubIntr(PSP_VBLANK_INT, 0);
+#else
+#ifndef ZAURUS
+ freopen("CON", "wb", stdout);
+#endif
+#endif
+
+ init_gamepak_buffer();
+
+ // Copy the directory path of the executable into main_path
+ sprintf(main_path, "%s/.gpsp", getenv("HOME"));
+ mkdir(main_path, 0755);
+ load_config_file();
+
+ gamepak_filename[0] = 0;
+
+ sprintf(bios_file, "%s/gba_bios.bin", main_path);
+ if(load_bios(bios_file) == -1)
+ {
+ printf("Sorry, but ReGBA requires a Gameboy Advance BIOS image to run\n");
+ printf("correctly. Make sure to get an authentic one (search the web,\n");
+ printf("beg other people if you want, but don't hold me accountable\n");
+ printf("if you get hated or banned for it), it'll be exactly 16384\n");
+ printf("bytes large and should have the following md5sum value:\n\n");
+ printf("a860e8c0b6d573d191e4ec7db1b1e4f6\n\n");
+ printf("Other BIOS files might work either partially completely, I\n");
+ printf("really don't know.\n\n");
+ printf("When you do get it name it gba_bios.bin and put it in\n");
+ printf("/boot/local/home/.gpsp.\n\n");
+ printf("Good luck.\n");
+
+ quit();
+ }
+
+ init_main();
+
+ video_resolution_large();
+
+ if(argc > 1)
+ {
+ if(load_gamepak(argv[1]) == -1)
+ {
+ printf("Failed to load gamepak %s, exiting.\n", load_filename);
+ quit();
+ }
+
+ init_video();
+ init_sound();
+ init_input();
+
+ set_gba_resolution(screen_scale);
+ video_resolution_small();
+
+ init_cpu();
+ init_memory();
+ }
+ else
+ {
+ init_video();
+ init_sound();
+ init_input();
+
+ if(load_file(file_ext, load_filename) == -1)
+ {
+ ReGBA_Menu(REGBA_MENU_ENTRY_REASON_NO_ROM);
+ }
+ else
+ {
+ if(load_gamepak(load_filename) == -1)
+ {
+ printf("Failed to load gamepak %s, exiting.\n", load_filename);
+ delay_us(5000000);
+ quit();
+ }
+
+ set_gba_resolution(screen_scale);
+ video_resolution_small();
+ clear_screen(0);
+ flip_screen();
+ init_cpu();
+ init_memory();
+ }
+ }
+
+ last_frame = 0;
+
+ // We'll never actually return from here.
+
+ execute_arm_translate(execute_cycles);
+ return 0;
+}
+
+u32 update_gba()
+{
+ irq_type irq_raised = IRQ_NONE;
+ do
+ {
+ cpu_ticks += execute_cycles;
+ reg[CHANGED_PC_STATUS] = 0;
+
+ if(gbc_sound_update)
+ {
+ gbc_update_count++;
+ update_gbc_sound(cpu_ticks);
+ gbc_sound_update = 0;
+ }
+
+ update_timer(0);
+ update_timer(1);
+ update_timer(2);
+ update_timer(3);
+
+ video_count -= execute_cycles;
+
+ if(video_count <= 0)
+ {
+ u32 vcount = io_registers[REG_VCOUNT];
+ u32 dispstat = io_registers[REG_DISPSTAT];
+
+ if((dispstat & 0x02) == 0)
+ {
+ // Transition from hrefresh to hblank
+ video_count += (272);
+ dispstat |= 0x02;
+
+ if((dispstat & 0x01) == 0)
+ {
+ u32 i;
+ if(oam_update)
+ oam_update_count++;
+
+ if(no_alpha)
+ io_registers[REG_BLDCNT] = 0;
+
+ update_scanline();
+
+ // If in visible area also fire HDMA
+ for(i = 0; i < 4; i++)
+ {
+ if(dma[i].start_type == DMA_START_HBLANK)
+ dma_transfer(dma + i);
+ }
+ }
+
+ if(dispstat & 0x10)
+ irq_raised |= IRQ_HBLANK;
+ }
+ else
+ {
+ // Transition from hblank to next line
+ video_count += 960;
+ dispstat &= ~0x02;
+
+ vcount++;
+
+ if(vcount == 160)
+ {
+ // Transition from vrefresh to vblank
+ u32 i;
+
+ dispstat |= 0x01;
+ if(dispstat & 0x8)
+ {
+ irq_raised |= IRQ_VBLANK;
+ }
+
+ affine_reference_x[0] =
+ (s32)(address32(io_registers, 0x28) << 4) >> 4;
+ affine_reference_y[0] =
+ (s32)(address32(io_registers, 0x2C) << 4) >> 4;
+ affine_reference_x[1] =
+ (s32)(address32(io_registers, 0x38) << 4) >> 4;
+ affine_reference_y[1] =
+ (s32)(address32(io_registers, 0x3C) << 4) >> 4;
+
+ for(i = 0; i < 4; i++)
+ {
+ if(dma[i].start_type == DMA_START_VBLANK)
+ dma_transfer(dma + i);
+ }
+ }
+ else
+
+ if(vcount == 228)
+ {
+ // Transition from vblank to next screen
+ dispstat &= ~0x01;
+ frame_ticks++;
+
+ #if 0
+ printf("frame update (%x), %d instructions total, %d RAM flushes\n",
+ reg[REG_PC], instruction_count - last_frame, flush_ram_count);
+ last_frame = instruction_count;
+
+/* printf("%d gbc audio updates\n", gbc_update_count);
+ printf("%d oam updates\n", oam_update_count); */
+ gbc_update_count = 0;
+ oam_update_count = 0;
+ flush_ram_count = 0;
+ #endif
+
+ if(update_input())
+ continue;
+
+ update_gbc_sound(cpu_ticks);
+ synchronize();
+
+ update_screen();
+
+ if(update_backup_flag)
+ update_backup();
+
+ process_cheats();
+
+ vcount = 0;
+ }
+
+ if(vcount == (dispstat >> 8))
+ {
+ // vcount trigger
+ dispstat |= 0x04;
+ if(dispstat & 0x20)
+ {
+ irq_raised |= IRQ_VCOUNT;
+ }
+ }
+ else
+ {
+ dispstat &= ~0x04;
+ }
+
+ io_registers[REG_VCOUNT] = vcount;
+ }
+ io_registers[REG_DISPSTAT] = dispstat;
+ }
+
+ if(irq_raised)
+ raise_interrupt(irq_raised);
+
+ execute_cycles = video_count;
+
+ check_timer(0);
+ check_timer(1);
+ check_timer(2);
+ check_timer(3);
+ } while(reg[CPU_HALT_STATE] != CPU_ACTIVE);
+ return execute_cycles;
+}
+
+u64 last_screen_timestamp = 0;
+u32 frame_speed = 15000;
+
+u32 ticks_needed_total = 0;
+float us_needed = 0.0;
+u32 frames = 0;
+u32 skipped_num_frame = 60;
+const u32 frame_interval = 60;
+u32 skipped_num = 0;
+
+void synchronize()
+{
+ u64 new_ticks;
+ char char_buffer[64];
+ u64 time_delta = 16667;
+ u32 fpsw = 60;
+
+ get_ticks_us(&new_ticks);
+ time_delta = new_ticks - last_screen_timestamp;
+ last_screen_timestamp = new_ticks;
+ ticks_needed_total += time_delta;
+
+ skip_next_frame = 0;
+ if((time_delta < frame_speed) && synchronize_flag)
+ {
+ delay_us(frame_speed - time_delta);
+ }
+ frames++;
+
+ if(frames == 60)
+ {
+ if(status_display) {
+ us_needed = (float)ticks_needed_total / frame_interval;
+ fpsw = (u32)(1000000.0 / us_needed);
+ ticks_needed_total = 0;
+ if(current_frameskip_type == manual_frameskip) {
+ sprintf(char_buffer, "%s%3dfps %s:%d slot:%d ", synchronize_flag?" ":">>", fpsw,
+ current_frameskip_type==auto_frameskip?"Auto":current_frameskip_type==manual_frameskip?"Manu":"Off ",
+ frameskip_value, savestate_slot);
+ } else {
+ sprintf(char_buffer, "%s%3dfps %s:%d slot:%d ", synchronize_flag?" ":">>",
+ (skipped_num_frame==60&&fpsw>60)?fpsw:skipped_num_frame,
+ current_frameskip_type==auto_frameskip?"Auto":current_frameskip_type==manual_frameskip?"Manu":"Off ",
+ frameskip_value, savestate_slot);
+ }
+ } else
+ strcpy(char_buffer, " ");
+ print_string(char_buffer, 0xFFFF, 0x000, 40, 30);
+ print_string(ssmsg, 0xF000, 0x000, 180, 30);
+ strcpy(ssmsg, " ");
+ frames = 0;
+ skipped_num_frame = 60;
+ }
+
+ if(current_frameskip_type == manual_frameskip)
+ {
+ frameskip_counter = (frameskip_counter + 1) %
+ (frameskip_value + 1);
+ if(random_skip)
+ {
+ if(frameskip_counter != (rand() % (frameskip_value + 1)))
+ skip_next_frame = 1;
+ }
+ else
+ {
+ if(frameskip_counter)
+ skip_next_frame = 1;
+ }
+ } else if(current_frameskip_type == auto_frameskip) {
+ static struct timeval next1 = {0, 0};
+ static struct timeval now;
+
+ gettimeofday(&now, NULL);
+ if(next1.tv_sec == 0) {
+ next1 = now;
+ next1.tv_usec++;
+ }
+ if(timercmp(&next1, &now, >)) {
+ //struct timeval tdiff;
+ if(synchronize_flag)
+ do {
+ synchronize_sound();
+ gettimeofday(&now, NULL);
+ } while (timercmp(&next1, &now, >));
+ else
+ gettimeofday(&now, NULL);
+ //timersub(&next1, &now, &tdiff);
+ //usleep(tdiff.tv_usec/2);
+ //gettimeofday(&now, NULL);
+ skipped_num = 0;
+ next1 = now;
+ } else {
+ if(skipped_num < frameskip_value) {
+ skipped_num++;
+ skipped_num_frame--;
+ skip_next_frame = 1;
+ } else {
+ //synchronize_sound();
+ skipped_num = 0;
+ next1 = now;
+ }
+ }
+ next1.tv_usec += 16667;
+ if(next1.tv_usec >= 1000000) {
+ next1.tv_sec++;
+ next1.tv_usec -= 1000000;
+ }
+ }
+}
+
+void quit()
+{
+ if(!update_backup_flag)
+ update_backup_force();
+
+ sound_exit();
+
+ SDL_Quit();
+ exit(0);
+}
+
+void reset_gba()
+{
+ init_main();
+ init_memory();
+ init_cpu();
+ reset_sound();
+}
+
+u32 FILE_LENGTH(FILE_TAG_TYPE fp)
+{
+ u32 length;
+
+ fseek(fp, 0, SEEK_END);
+ length = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ return length;
+}
+
+void delay_us(u32 us_count)
+{
+ SDL_Delay(us_count / 1000); // for dingux
+ // sleep(0);
+}
+
+void get_ticks_us(u64 *ticks_return)
+{
+ *ticks_return = (SDL_GetTicks() * 1000);
+}
+
+void change_ext(u8 *src, u8 *buffer, u8 *extension)
+{
+ u8 *position;
+
+ strcpy(buffer, main_path);
+ strcat(buffer, "/");
+
+ position = strrchr(src, '/');
+ if (position)
+ src = position+1;
+
+ strcat(buffer, src);
+ position = strrchr(buffer, '.');
+
+ if(position)
+ strcpy(position, extension);
+}
+
+// type = READ / WRITE_MEM
+#define MAIN_SAVESTATE_BODY(type) \
+{ \
+ FILE_##type##_VARIABLE(g_state_buffer_ptr, cpu_ticks); \
+ FILE_##type##_VARIABLE(g_state_buffer_ptr, execute_cycles); \
+ FILE_##type##_VARIABLE(g_state_buffer_ptr, video_count); \
+ FILE_##type##_ARRAY(g_state_buffer_ptr, timer); \
+} \
+
+void main_read_mem_savestate()
+MAIN_SAVESTATE_BODY(READ_MEM);
+
+void main_write_mem_savestate()
+MAIN_SAVESTATE_BODY(WRITE_MEM);
+
+void print_out(u32 address, u32 pc)
+{
+ char buffer[256];
+ sprintf(buffer, "patching from gp8 %x", address);
+ print_string(buffer, 0xFFFF, 0x0000, 0, 0);
+ update_screen();
+ delay_us(5000000);
+}
+
diff --git a/source/gcw0/main.h b/source/gcw0/main.h
new file mode 100644
index 0000000..aad69c3
--- /dev/null
+++ b/source/gcw0/main.h
@@ -0,0 +1,123 @@
+/* gameplaySP
+ *
+ * Copyright (C) 2006 Exophase <exophase@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef MAIN_H
+#define MAIN_H
+
+typedef enum
+{
+ TIMER_INACTIVE,
+ TIMER_PRESCALE,
+ TIMER_CASCADE
+} timer_status_type;
+
+typedef enum
+{
+ TIMER_NO_IRQ,
+ TIMER_TRIGGER_IRQ
+} timer_irq_type;
+
+
+typedef enum
+{
+ TIMER_DS_CHANNEL_NONE,
+ TIMER_DS_CHANNEL_A,
+ TIMER_DS_CHANNEL_B,
+ TIMER_DS_CHANNEL_BOTH
+} timer_ds_channel_type;
+
+typedef struct
+{
+ s32 count;
+ u32 reload;
+ u32 prescale;
+ u32 stop_cpu_ticks;
+ FIXED16_16 frequency_step;
+ timer_ds_channel_type direct_sound_channels;
+ timer_irq_type irq;
+ timer_status_type status;
+} timer_type;
+
+typedef enum
+{
+ auto_frameskip,
+ manual_frameskip,
+ no_frameskip
+} frameskip_type;
+
+extern u32 cpu_ticks;
+extern u32 frame_ticks;
+extern u32 execute_cycles;
+extern frameskip_type current_frameskip_type;
+extern u32 frameskip_value;
+extern u32 random_skip;
+extern u32 global_cycles_per_instruction;
+extern u32 synchronize_flag;
+extern u32 skip_next_frame;
+
+extern timer_type timer[4];
+static u32 prescale_table[] = { 0, 6, 8, 10 };
+
+extern u32 cycle_memory_access;
+extern u32 cycle_pc_relative_access;
+extern u32 cycle_sp_relative_access;
+extern u32 cycle_block_memory_access;
+extern u32 cycle_block_memory_sp_access;
+extern u32 cycle_block_memory_words;
+extern u32 cycle_dma16_words;
+extern u32 cycle_dma32_words;
+extern u32 flush_ram_count;
+
+extern u64 base_timestamp;
+
+extern u8 main_path[512];
+
+extern u32 update_backup_flag;
+extern u32 clock_speed;
+
+u32 update_gba();
+void reset_gba();
+void synchronize();
+void quit();
+void delay_us(u32 us_count);
+void get_ticks_us(u64 *tick_return);
+void game_name_ext(u8 *src, u8 *buffer, u8 *extension);
+void main_write_mem_savestate(FILE_TAG_TYPE savestate_file);
+void main_read_mem_savestate(FILE_TAG_TYPE savestate_file);
+
+#define count_timer(timer_number) \
+ timer[timer_number].reload = 0x10000 - value; \
+ if(timer_number < 2) \
+ { \
+ u32 timer_reload = \
+ timer[timer_number].reload << timer[timer_number].prescale; \
+ sound_update_frequency_step(timer_number); \
+ } \
+
+#define adjust_sound_buffer(timer_number, channel) \
+ if(timer[timer_number].direct_sound_channels & (0x01 << channel)) \
+ { \
+ direct_sound_channel[channel].buffer_index = \
+ (direct_sound_channel[channel].buffer_index + buffer_adjust) % \
+ BUFFER_SIZE; \
+ } \
+
+#endif
+
+
diff --git a/source/gcw0/port.h b/source/gcw0/port.h
new file mode 100644
index 0000000..5bb04b0
--- /dev/null
+++ b/source/gcw0/port.h
@@ -0,0 +1,49 @@
+#ifndef _PORT_H_
+#define _PORT_H_
+
+#include <SDL/SDL.h>
+
+/* Tuning parameters for the GCW Zero version of gpSP */
+/* Its processor is an Ingenic JZ4770 at 1000 MHz with 256..512 MiB of RAM */
+#define READONLY_CODE_CACHE_SIZE (4 * 1024 * 1024)
+#define WRITABLE_CODE_CACHE_SIZE (4 * 1024 * 1024)
+/* The following parameter needs to be at least enough bytes to hold
+ * the generated code for the largest instruction on your platform.
+ * In most cases, that will be the ARM instruction
+ * STMDB R0!, {R0,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12,R13,R14,R15} */
+#define TRANSLATION_CACHE_LIMIT_THRESHOLD (1024)
+
+#define FILE_OPEN_APPEND ("a+")
+
+#define FILE_OPEN_READ ("rb")
+
+#define FILE_OPEN_WRITE ("wb")
+
+#define FILE_OPEN(filename_tag, filename, mode) \
+ filename_tag = fopen(filename, FILE_OPEN_##mode) \
+
+#define FILE_CHECK_VALID(filename_tag) \
+ (filename_tag != FILE_TAG_INVALID) \
+
+#define FILE_TAG_INVALID \
+ (NULL) \
+
+#define FILE_CLOSE(filename_tag) \
+ fclose(filename_tag) \
+
+#define FILE_DELETE(filename) \
+ unlink(filename) \
+
+#define FILE_READ(filename_tag, buffer, size) \
+ fread(buffer, 1, size, filename_tag) \
+
+#define FILE_WRITE(filename_tag, buffer, size) \
+ fwrite(buffer, 1, size, filename_tag) \
+
+#define FILE_SEEK(filename_tag, offset, type) \
+ fseek(filename_tag, offset, type) \
+
+#define FILE_TELL(filename_tag) \
+ ftell(filename_tag) \
+
+#endif \ No newline at end of file
diff --git a/source/psp/gui.c b/source/psp/gui.c
new file mode 100644
index 0000000..c135cb4
--- /dev/null
+++ b/source/psp/gui.c
@@ -0,0 +1,293 @@
+/* gameplaySP
+ *
+ * Copyright (C) 2006 Exophase <exophase@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "common.h"
+#include "font.h"
+
+#include <pspctrl.h>
+
+#include <pspkernel.h>
+#include <pspdebug.h>
+#include <pspdisplay.h>
+
+#include <pspgu.h>
+#include <psppower.h>
+#include <psprtc.h>
+
+static float *screen_vertex = (float *)0x441FC100;
+static u32 *ge_cmd = (u32 *)0x441FC000;
+static u16 *psp_gu_vram_base = (u16 *)(0x44000000);
+static u32 *ge_cmd_ptr = (u32 *)0x441FC000;
+static u32 gecbid;
+static u32 video_direct = 0;
+
+static u32 __attribute__((aligned(16))) display_list[32];
+
+#define GBA_SCREEN_WIDTH 240
+#define GBA_SCREEN_HEIGHT 160
+
+#define PSP_SCREEN_WIDTH 480
+#define PSP_SCREEN_HEIGHT 272
+#define PSP_LINE_SIZE 512
+
+#define PSP_ALL_BUTTON_MASK 0xFFFF
+
+#define GE_CMD_FBP 0x9C
+#define GE_CMD_FBW 0x9D
+#define GE_CMD_TBP0 0xA0
+#define GE_CMD_TBW0 0xA8
+#define GE_CMD_TSIZE0 0xB8
+#define GE_CMD_TFLUSH 0xCB
+#define GE_CMD_CLEAR 0xD3
+#define GE_CMD_VTYPE 0x12
+#define GE_CMD_BASE 0x10
+#define GE_CMD_VADDR 0x01
+#define GE_CMD_IADDR 0x02
+#define GE_CMD_PRIM 0x04
+#define GE_CMD_FINISH 0x0F
+#define GE_CMD_SIGNAL 0x0C
+#define GE_CMD_NOP 0x00
+
+#define GE_CMD(cmd, operand) \
+ *ge_cmd_ptr = (((GE_CMD_##cmd) << 24) | (operand)); \
+ ge_cmd_ptr++ \
+
+static u16 *screen_texture = (u16 *)(0x4000000 + (512 * 272 * 2));
+static u16 *current_screen_texture = (u16 *)(0x4000000 + (512 * 272 * 2));
+static u16 *GBAScreen = (u16 *)(0x4000000 + (512 * 272 * 2));
+static u32 GBAScreenPitch = 240;
+
+static void Ge_Finish_Callback(int id, void *arg)
+{
+}
+
+void init_video()
+{
+ sceDisplaySetMode(0, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
+
+ sceDisplayWaitVblankStart();
+ sceDisplaySetFrameBuf((void*)psp_gu_vram_base, PSP_LINE_SIZE,
+ PSP_DISPLAY_PIXEL_FORMAT_565, PSP_DISPLAY_SETBUF_NEXTFRAME);
+
+ sceGuInit();
+
+ sceGuStart(GU_DIRECT, display_list);
+ sceGuDrawBuffer(GU_PSM_5650, (void*)0, PSP_LINE_SIZE);
+ sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT,
+ (void*)0, PSP_LINE_SIZE);
+ sceGuClear(GU_COLOR_BUFFER_BIT);
+
+ sceGuOffset(2048 - (PSP_SCREEN_WIDTH / 2), 2048 - (PSP_SCREEN_HEIGHT / 2));
+ sceGuViewport(2048, 2048, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
+
+ sceGuScissor(0, 0, PSP_SCREEN_WIDTH + 1, PSP_SCREEN_HEIGHT + 1);
+ sceGuEnable(GU_SCISSOR_TEST);
+ sceGuTexMode(GU_PSM_5650, 0, 0, GU_FALSE);
+ sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
+ sceGuTexFilter(GU_LINEAR, GU_LINEAR);
+ sceGuEnable(GU_TEXTURE_2D);
+
+ sceGuFrontFace(GU_CW);
+ sceGuDisable(GU_BLEND);
+
+ sceGuFinish();
+ sceGuSync(0, 0);
+
+ sceDisplayWaitVblankStart();
+ sceGuDisplay(GU_TRUE);
+
+ PspGeCallbackData gecb;
+ gecb.signal_func = NULL;
+ gecb.signal_arg = NULL;
+ gecb.finish_func = Ge_Finish_Callback;
+ gecb.finish_arg = NULL;
+ gecbid = sceGeSetCallback(&gecb);
+
+ screen_vertex[0] = 0 + 0.5;
+ screen_vertex[1] = 0 + 0.5;
+ screen_vertex[2] = 0 + 0.5;
+ screen_vertex[3] = 0 + 0.5;
+ screen_vertex[4] = 0;
+ screen_vertex[5] = GBA_SCREEN_WIDTH - 0.5;
+ screen_vertex[6] = GBA_SCREEN_HEIGHT - 0.5;
+ screen_vertex[7] = PSP_SCREEN_WIDTH - 0.5;
+ screen_vertex[8] = PSP_SCREEN_HEIGHT - 0.5;
+ screen_vertex[9] = 0;
+
+ // Set framebuffer to PSP VRAM
+ GE_CMD(FBP, ((u32)psp_gu_vram_base & 0x00FFFFFF));
+ GE_CMD(FBW, (((u32)psp_gu_vram_base & 0xFF000000) >> 8) | PSP_LINE_SIZE);
+ // Set texture 0 to the screen texture
+ GE_CMD(TBP0, ((u32)screen_texture & 0x00FFFFFF));
+ GE_CMD(TBW0, (((u32)screen_texture & 0xFF000000) >> 8) | GBA_SCREEN_WIDTH);
+ // Set the texture size to 256 by 256 (2^8 by 2^8)
+ GE_CMD(TSIZE0, (8 << 8) | 8);
+ // Flush the texture cache
+ GE_CMD(TFLUSH, 0);
+ // Use 2D coordinates, no indeces, no weights, 32bit float positions,
+ // 32bit float texture coordinates
+ GE_CMD(VTYPE, (1 << 23) | (0 << 11) | (0 << 9) |
+ (3 << 7) | (0 << 5) | (0 << 2) | 3);
+ // Set the base of the index list pointer to 0
+ GE_CMD(BASE, 0);
+ // Set the rest of index list pointer to 0 (not being used)
+ GE_CMD(IADDR, 0);
+ // Set the base of the screen vertex list pointer
+ GE_CMD(BASE, ((u32)screen_vertex & 0xFF000000) >> 8);
+ // Set the rest of the screen vertex list pointer
+ GE_CMD(VADDR, ((u32)screen_vertex & 0x00FFFFFF));
+ // Primitive kick: render sprite (primitive 6), 2 vertices
+ GE_CMD(PRIM, (6 << 16) | 2);
+ // Done with commands
+ GE_CMD(FINISH, 0);
+ // Raise signal interrupt
+ GE_CMD(SIGNAL, 0);
+ GE_CMD(NOP, 0);
+ GE_CMD(NOP, 0);
+}
+
+u32 screen_flip = 0;
+
+void ReGBA_RenderScreen()
+{
+ if(video_direct == 0)
+ {
+ u32 *old_ge_cmd_ptr = ge_cmd_ptr;
+ sceKernelDcacheWritebackAll();
+
+ // Render the current screen
+ ge_cmd_ptr = ge_cmd + 2;
+ GE_CMD(TBP0, ((u32) GBAScreen & 0x00FFFFFF));
+ GE_CMD(TBW0, (((u32) GBAScreen & 0xFF000000) >> 8) |
+ GBA_SCREEN_WIDTH);
+ ge_cmd_ptr = old_ge_cmd_ptr;
+
+ sceGeListEnQueue(ge_cmd, ge_cmd_ptr, gecbid, NULL);
+
+ // Flip to the next screen
+ screen_flip ^= 1;
+
+ if(screen_flip)
+ GBAScreen = screen_texture + (240 * 160 * 2);
+ else
+ GBAScreen = screen_texture;
+ }
+}
+
+void video_resolution_large()
+{
+ if(video_direct != 1)
+ {
+ video_direct = 1;
+ screen_pixels = psp_gu_vram_base;
+ screen_pitch = 512;
+ sceGuStart(GU_DIRECT, display_list);
+ sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT,
+ (void*)0, PSP_LINE_SIZE);
+ sceGuFinish();
+ }
+}
+
+void set_gba_resolution(video_scale_type scale)
+{
+ u32 filter_linear = 0;
+ screen_scale = scale;
+ switch(scale)
+ {
+ case unscaled:
+ screen_vertex[2] = 120 + 0.5;
+ screen_vertex[3] = 56 + 0.5;
+ screen_vertex[7] = GBA_SCREEN_WIDTH + 120 - 0.5;
+ screen_vertex[8] = GBA_SCREEN_HEIGHT + 56 - 0.5;
+ break;
+
+ case scaled_aspect:
+ screen_vertex[2] = 36 + 0.5;
+ screen_vertex[3] = 0 + 0.5;
+ screen_vertex[7] = 408 + 36 - 0.5;
+ screen_vertex[8] = PSP_SCREEN_HEIGHT - 0.5;
+ break;
+
+ case fullscreen:
+ screen_vertex[2] = 0;
+ screen_vertex[3] = 0;
+ screen_vertex[7] = PSP_SCREEN_WIDTH;
+ screen_vertex[8] = PSP_SCREEN_HEIGHT;
+ break;
+ }
+
+ sceGuStart(GU_DIRECT, display_list);
+ if(screen_filter == filter_bilinear)
+ sceGuTexFilter(GU_LINEAR, GU_LINEAR);
+ else
+ sceGuTexFilter(GU_NEAREST, GU_NEAREST);
+
+ sceGuFinish();
+ sceGuSync(0, 0);
+
+ clear_screen(0x0000);
+}
+
+void video_resolution_small()
+{
+ if(video_direct != 0)
+ {
+ set_gba_resolution(screen_scale);
+ video_direct = 0;
+ screen_pixels = screen_texture;
+ screen_flip = 0;
+ screen_pitch = 240;
+ sceGuStart(GU_DIRECT, display_list);
+ sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT,
+ (void*)0, PSP_LINE_SIZE);
+ sceGuFinish();
+ }
+}
+
+void clear_screen(u16 color)
+{
+ u32 i;
+ u16 *src_ptr = get_screen_pixels();
+
+ sceGuSync(0, 0);
+
+ for(i = 0; i < (512 * 272); i++, src_ptr++)
+ {
+ *src_ptr = color;
+ }
+
+ // I don't know why this doesn't work.
+/* color = (((color & 0x1F) * 255 / 31) << 0) |
+ ((((color >> 5) & 0x3F) * 255 / 63) << 8) |
+ ((((color >> 11) & 0x1F) * 255 / 31) << 16) | (0xFF << 24);
+
+ sceGuStart(GU_DIRECT, display_list);
+ sceGuDrawBuffer(GU_PSM_5650, (void*)0, PSP_LINE_SIZE);
+ //sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT,
+ // (void*)0, PSP_LINE_SIZE);
+ sceGuClearColor(color);
+ sceGuClear(GU_COLOR_BUFFER_BIT);
+ sceGuFinish();
+ sceGuSync(0, 0); */
+}
+
+void _flush_cache()
+{
+ sceKernelDcacheWritebackAll();
+}
diff --git a/source/psp/main.c b/source/psp/main.c
new file mode 100644
index 0000000..b820653
--- /dev/null
+++ b/source/psp/main.c
@@ -0,0 +1,778 @@
+/* gameplaySP
+ *
+ * Copyright (C) 2006 Exophase <exophase@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+//PSP_MODULE_INFO("gpSP", 0x1000, 0, 6);
+//PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER);
+
+#include "common.h"
+#include <sys/time.h>
+#include <stdlib.h>
+
+void vblank_interrupt_handler(u32 sub, u32 *parg);
+
+extern SDL_Surface *screen;
+
+timer_type timer[4];
+
+frameskip_type current_frameskip_type = auto_frameskip;
+u32 frameskip_value = 4;
+u32 random_skip = 0;
+u32 global_cycles_per_instruction = 3;
+u32 skip_next_frame = 0;
+
+u32 frameskip_counter = 0;
+
+u32 cpu_ticks = 0;
+u32 frame_ticks = 0;
+
+u32 execute_cycles = 960;
+s32 video_count = 960;
+u32 ticks;
+
+u32 arm_frame = 0;
+u32 thumb_frame = 0;
+u32 last_frame = 0;
+
+u32 cycle_memory_access = 0;
+u32 cycle_pc_relative_access = 0;
+u32 cycle_sp_relative_access = 0;
+u32 cycle_block_memory_access = 0;
+u32 cycle_block_memory_sp_access = 0;
+u32 cycle_block_memory_words = 0;
+u32 cycle_dma16_words = 0;
+u32 cycle_dma32_words = 0;
+u32 flush_ram_count = 0;
+u32 gbc_update_count = 0;
+u32 oam_update_count = 0;
+
+u32 synchronize_flag = 1;
+
+u32 update_backup_flag = 1;
+u32 clock_speed = 333;
+u8 main_path[512];
+
+#define check_count(count_var) \
+ if(count_var < execute_cycles) \
+ execute_cycles = count_var; \
+
+#define check_timer(timer_number) \
+ if(timer[timer_number].status == TIMER_PRESCALE) \
+ check_count(timer[timer_number].count); \
+
+#define update_timer(timer_number) \
+ if(timer[timer_number].status != TIMER_INACTIVE) \
+ { \
+ if(timer[timer_number].status != TIMER_CASCADE) \
+ { \
+ timer[timer_number].count -= execute_cycles; \
+ io_registers[REG_TM##timer_number##D] = \
+ -(timer[timer_number].count >> timer[timer_number].prescale); \
+ } \
+ \
+ if(timer[timer_number].count <= 0) \
+ { \
+ if(timer[timer_number].irq == TIMER_TRIGGER_IRQ) \
+ irq_raised |= IRQ_TIMER##timer_number; \
+ \
+ if((timer_number != 3) && \
+ (timer[timer_number + 1].status == TIMER_CASCADE)) \
+ { \
+ timer[timer_number + 1].count--; \
+ io_registers[REG_TM0D + (timer_number + 1) * 2] = \
+ -(timer[timer_number + 1].count); \
+ } \
+ \
+ if(timer_number < 2) \
+ { \
+ if(timer[timer_number].direct_sound_channels & 0x01) \
+ sound_timer(timer[timer_number].frequency_step, 0); \
+ \
+ if(timer[timer_number].direct_sound_channels & 0x02) \
+ sound_timer(timer[timer_number].frequency_step, 1); \
+ } \
+ \
+ timer[timer_number].count += \
+ (timer[timer_number].reload << timer[timer_number].prescale); \
+ } \
+ } \
+
+u8 *file_ext[] = { ".gba", ".bin", ".zip", NULL };
+
+void init_main()
+{
+ u32 i;
+
+ skip_next_frame = 0;
+
+ for(i = 0; i < 4; i++)
+ {
+ dma[i].start_type = DMA_INACTIVE;
+ dma[i].direct_sound_channel = DMA_NO_DIRECT_SOUND;
+ timer[i].status = TIMER_INACTIVE;
+ timer[i].reload = 0x10000;
+ timer[i].stop_cpu_ticks = 0;
+ }
+
+ timer[0].direct_sound_channels = TIMER_DS_CHANNEL_BOTH;
+ timer[1].direct_sound_channels = TIMER_DS_CHANNEL_NONE;
+
+ cpu_ticks = 0;
+ frame_ticks = 0;
+
+ execute_cycles = 960;
+ video_count = 960;
+
+ flush_translation_cache_rom();
+ flush_translation_cache_ram();
+ flush_translation_cache_bios();
+}
+
+int main(int argc, char *argv[])
+{
+ u32 i;
+ u32 vcount = 0;
+ u32 ticks;
+ u32 dispstat;
+ u8 load_filename[512];
+ u8 bios_file[512];
+
+#ifdef PSP_BUILD
+ sceKernelRegisterSubIntrHandler(PSP_VBLANK_INT, 0,
+ vblank_interrupt_handler, NULL);
+ sceKernelEnableSubIntr(PSP_VBLANK_INT, 0);
+#else
+#ifndef ZAURUS
+ freopen("CON", "wb", stdout);
+#endif
+#endif
+
+ init_gamepak_buffer();
+
+ // Copy the directory path of the executable into main_path
+ sprintf(main_path, "%s/.gpsp", getenv("HOME"));
+ mkdir(main_path, 0755);
+ load_config_file();
+
+ gamepak_filename[0] = 0;
+
+ sprintf(bios_file, "%s/gba_bios.bin", main_path);
+ if(load_bios(bios_file) == -1)
+ {
+#ifdef PSP_BUILD
+ gui_action_type gui_action = CURSOR_NONE;
+
+ printf("Sorry, but gpSP requires a Gameboy Advance BIOS image to run\n");
+ printf("correctly. Make sure to get an authentic one (search the web,\n");
+ printf("beg other people if you want, but don't hold me accountable\n");
+ printf("if you get hated or banned for it), it'll be exactly 16384\n");
+ printf("bytes large and should have the following md5sum value:\n\n");
+ printf("a860e8c0b6d573d191e4ec7db1b1e4f6\n\n");
+ printf("Other BIOS files might work either partially completely, I\n");
+ printf("really don't know.\n\n");
+ printf("When you do get it name it gba_bios.bin and put it in the\n");
+ printf("same directory as this EBOOT.\n\n");
+ printf("Good luck. Press any button to exit.\n");
+
+ while(gui_action == CURSOR_NONE)
+ {
+ gui_action = get_gui_input();
+ delay_us(15000);
+ }
+
+ quit();
+#endif
+#ifdef ZAURUS
+ printf("Failed to load bios.\n");
+ quit();
+#endif
+ }
+
+#ifdef PSP_BUILD
+ delay_us(2500000);
+#endif
+
+ init_main();
+
+ video_resolution_large();
+
+ if(argc > 1)
+ {
+ if(load_gamepak(argv[1]) == -1)
+ {
+ printf("Failed to load gamepak %s, exiting.\n", load_filename);
+ quit();
+ }
+
+ init_video();
+ init_sound();
+ init_input();
+
+ set_gba_resolution(screen_scale);
+ video_resolution_small();
+
+ init_cpu();
+ init_memory();
+ }
+ else
+ {
+ init_video();
+ init_sound();
+ init_input();
+
+ if(load_file(file_ext, load_filename) == -1)
+ {
+ menu(copy_screen());
+ }
+ else
+ {
+ if(load_gamepak(load_filename) == -1)
+ {
+ printf("Failed to load gamepak %s, exiting.\n", load_filename);
+ delay_us(5000000);
+ quit();
+ }
+
+ set_gba_resolution(screen_scale);
+ video_resolution_small();
+#ifdef ZAURUS
+ clear_screen(0);
+ flip_screen();
+#endif
+ init_cpu();
+ init_memory();
+ }
+ }
+
+ last_frame = 0;
+
+ // We'll never actually return from here.
+
+ execute_arm_translate(execute_cycles);
+ return 0;
+}
+
+void print_memory_stats(u32 *counter, u32 *region_stats, u8 *stats_str)
+{
+ u32 other_region_counter = region_stats[0x1] + region_stats[0xE] + region_stats[0xF];
+ u32 rom_region_counter = region_stats[0x8] + region_stats[0x9] + region_stats[0xA] +
+ region_stats[0xB] + region_stats[0xC] + region_stats[0xD];
+ u32 _counter = *counter;
+
+ printf("memory access stats: %s (out of %d)\n", stats_str, _counter);
+ printf("bios: %f%%\tiwram: %f%%\tewram: %f%%\tvram: %f\n",
+ region_stats[0x0] * 100.0 / _counter, region_stats[0x3] * 100.0 / _counter,
+ region_stats[0x2] * 100.0 / _counter, region_stats[0x6] * 100.0 / _counter);
+
+ printf("oam: %f%%\tpalette: %f%%\trom: %f%%\tother: %f%%\n",
+ region_stats[0x7] * 100.0 / _counter, region_stats[0x5] * 100.0 / _counter,
+ rom_region_counter * 100.0 / _counter, other_region_counter * 100.0 / _counter);
+
+ *counter = 0;
+ memset(region_stats, 0, sizeof(u32) * 16);
+}
+
+u32 update_gba()
+{
+ irq_type irq_raised = IRQ_NONE;
+ do
+ {
+ cpu_ticks += execute_cycles;
+ reg[CHANGED_PC_STATUS] = 0;
+
+ if(gbc_sound_update)
+ {
+ gbc_update_count++;
+ update_gbc_sound(cpu_ticks);
+ gbc_sound_update = 0;
+ }
+
+ update_timer(0);
+ update_timer(1);
+ update_timer(2);
+ update_timer(3);
+
+ video_count -= execute_cycles;
+
+ if(video_count <= 0)
+ {
+ u32 vcount = io_registers[REG_VCOUNT];
+ u32 dispstat = io_registers[REG_DISPSTAT];
+
+ if((dispstat & 0x02) == 0)
+ {
+ // Transition from hrefresh to hblank
+ video_count += (272);
+ dispstat |= 0x02;
+
+ if((dispstat & 0x01) == 0)
+ {
+ u32 i;
+ if(oam_update)
+ oam_update_count++;
+
+ if(no_alpha)
+ io_registers[REG_BLDCNT] = 0;
+
+ update_scanline();
+
+ // If in visible area also fire HDMA
+ for(i = 0; i < 4; i++)
+ {
+ if(dma[i].start_type == DMA_START_HBLANK)
+ dma_transfer(dma + i);
+ }
+ }
+
+ if(dispstat & 0x10)
+ irq_raised |= IRQ_HBLANK;
+ }
+ else
+ {
+ // Transition from hblank to next line
+ video_count += 960;
+ dispstat &= ~0x02;
+
+ vcount++;
+
+ if(vcount == 160)
+ {
+ // Transition from vrefresh to vblank
+ u32 i;
+
+ dispstat |= 0x01;
+ if(dispstat & 0x8)
+ {
+ irq_raised |= IRQ_VBLANK;
+ }
+
+ affine_reference_x[0] =
+ (s32)(address32(io_registers, 0x28) << 4) >> 4;
+ affine_reference_y[0] =
+ (s32)(address32(io_registers, 0x2C) << 4) >> 4;
+ affine_reference_x[1] =
+ (s32)(address32(io_registers, 0x38) << 4) >> 4;
+ affine_reference_y[1] =
+ (s32)(address32(io_registers, 0x3C) << 4) >> 4;
+
+ for(i = 0; i < 4; i++)
+ {
+ if(dma[i].start_type == DMA_START_VBLANK)
+ dma_transfer(dma + i);
+ }
+ }
+ else
+
+ if(vcount == 228)
+ {
+ // Transition from vblank to next screen
+ dispstat &= ~0x01;
+ frame_ticks++;
+
+ #if 0
+ printf("frame update (%x), %d instructions total, %d RAM flushes\n",
+ reg[REG_PC], instruction_count - last_frame, flush_ram_count);
+ last_frame = instruction_count;
+
+/* printf("%d gbc audio updates\n", gbc_update_count);
+ printf("%d oam updates\n", oam_update_count); */
+ gbc_update_count = 0;
+ oam_update_count = 0;
+ flush_ram_count = 0;
+ #endif
+
+ if(update_input())
+ continue;
+
+ update_gbc_sound(cpu_ticks);
+ synchronize();
+
+ update_screen();
+
+ if(update_backup_flag)
+ update_backup();
+
+ process_cheats();
+
+ vcount = 0;
+ }
+
+ if(vcount == (dispstat >> 8))
+ {
+ // vcount trigger
+ dispstat |= 0x04;
+ if(dispstat & 0x20)
+ {
+ irq_raised |= IRQ_VCOUNT;
+ }
+ }
+ else
+ {
+ dispstat &= ~0x04;
+ }
+
+ io_registers[REG_VCOUNT] = vcount;
+ }
+ io_registers[REG_DISPSTAT] = dispstat;
+ }
+
+ if(irq_raised)
+ raise_interrupt(irq_raised);
+
+ execute_cycles = video_count;
+
+ check_timer(0);
+ check_timer(1);
+ check_timer(2);
+ check_timer(3);
+ } while(reg[CPU_HALT_STATE] != CPU_ACTIVE);
+ return execute_cycles;
+}
+
+u64 last_screen_timestamp = 0;
+u32 frame_speed = 15000;
+
+#ifdef PSP_BUILD
+
+u32 real_frame_count = 0;
+u32 virtual_frame_count = 0;
+u32 num_skipped_frames = 0;
+
+void vblank_interrupt_handler(u32 sub, u32 *parg)
+{
+ real_frame_count++;
+}
+
+void synchronize()
+{
+ char char_buffer[64];
+ u64 new_ticks, time_delta;
+ s32 used_frameskip = frameskip_value;
+
+ if(!synchronize_flag)
+ {
+ print_string("--FF--", 0xFFFF, 0x000, 0, 0);
+ used_frameskip = 4;
+ virtual_frame_count = real_frame_count - 1;
+ }
+
+ skip_next_frame = 0;
+
+ virtual_frame_count++;
+
+ if(real_frame_count >= virtual_frame_count)
+ {
+ if((real_frame_count > virtual_frame_count) &&
+ (current_frameskip_type == auto_frameskip) &&
+ (num_skipped_frames < frameskip_value))
+ {
+ skip_next_frame = 1;
+ num_skipped_frames++;
+ }
+ else
+ {
+ virtual_frame_count = real_frame_count;
+ num_skipped_frames = 0;
+ }
+
+ // Here so that the home button return will eventually work.
+ // If it's not running fullspeed anyway this won't really hurt
+ // it much more.
+
+ delay_us(1);
+ }
+ else
+ {
+ if(synchronize_flag)
+ sceDisplayWaitVblankStart();
+ }
+
+ if(current_frameskip_type == manual_frameskip)
+ {
+ frameskip_counter = (frameskip_counter + 1) %
+ (used_frameskip + 1);
+ if(random_skip)
+ {
+ if(frameskip_counter != (rand() % (used_frameskip + 1)))
+ skip_next_frame = 1;
+ }
+ else
+ {
+ if(frameskip_counter)
+ skip_next_frame = 1;
+ }
+ }
+
+/* sprintf(char_buffer, "%08d %08d %d %d %d\n",
+ real_frame_count, virtual_frame_count, num_skipped_frames,
+ real_frame_count - virtual_frame_count, skip_next_frame);
+ print_string(char_buffer, 0xFFFF, 0x0000, 0, 10); */
+
+/*
+ sprintf(char_buffer, "%02d %02d %06d %07d", frameskip, (u32)ms_needed,
+ ram_translation_ptr - ram_translation_cache, rom_translation_ptr -
+ rom_translation_cache);
+ print_string(char_buffer, 0xFFFF, 0x0000, 0, 0);
+*/
+}
+
+#else
+
+u32 ticks_needed_total = 0;
+float us_needed = 0.0;
+u32 frames = 0;
+u32 skipped_num_frame = 60;
+const u32 frame_interval = 60;
+u32 skipped_num = 0;
+
+void synchronize()
+{
+ u64 new_ticks;
+ char char_buffer[64];
+ u64 time_delta = 16667;
+ u32 fpsw = 60;
+
+ get_ticks_us(&new_ticks);
+ time_delta = new_ticks - last_screen_timestamp;
+ last_screen_timestamp = new_ticks;
+ ticks_needed_total += time_delta;
+
+ skip_next_frame = 0;
+#ifndef ZAURUS
+ if((time_delta < frame_speed) && synchronize_flag)
+ {
+ delay_us(frame_speed - time_delta);
+ }
+#endif
+ frames++;
+
+ if(frames == 60)
+ {
+ if(status_display) {
+ us_needed = (float)ticks_needed_total / frame_interval;
+ fpsw = (u32)(1000000.0 / us_needed);
+ ticks_needed_total = 0;
+ if(current_frameskip_type == manual_frameskip) {
+ sprintf(char_buffer, "%s%3dfps %s:%d slot:%d ", synchronize_flag?" ":">>", fpsw,
+ current_frameskip_type==auto_frameskip?"Auto":current_frameskip_type==manual_frameskip?"Manu":"Off ",
+ frameskip_value, savestate_slot);
+ } else {
+ sprintf(char_buffer, "%s%3dfps %s:%d slot:%d ", synchronize_flag?" ":">>",
+ (skipped_num_frame==60&&fpsw>60)?fpsw:skipped_num_frame,
+ current_frameskip_type==auto_frameskip?"Auto":current_frameskip_type==manual_frameskip?"Manu":"Off ",
+ frameskip_value, savestate_slot);
+ }
+ } else
+ strcpy(char_buffer, " ");
+ print_string(char_buffer, 0xFFFF, 0x000, 40, 30);
+ print_string(ssmsg, 0xF000, 0x000, 180, 30);
+ strcpy(ssmsg, " ");
+ frames = 0;
+ skipped_num_frame = 60;
+ }
+
+ if(current_frameskip_type == manual_frameskip)
+ {
+ frameskip_counter = (frameskip_counter + 1) %
+ (frameskip_value + 1);
+ if(random_skip)
+ {
+ if(frameskip_counter != (rand() % (frameskip_value + 1)))
+ skip_next_frame = 1;
+ }
+ else
+ {
+ if(frameskip_counter)
+ skip_next_frame = 1;
+ }
+#ifndef ZAURUS
+ }
+#else
+ } else if(current_frameskip_type == auto_frameskip) {
+ static struct timeval next1 = {0, 0};
+ static struct timeval now;
+
+ gettimeofday(&now, NULL);
+ if(next1.tv_sec == 0) {
+ next1 = now;
+ next1.tv_usec++;
+ }
+ if(timercmp(&next1, &now, >)) {
+ //struct timeval tdiff;
+ if(synchronize_flag)
+ do {
+ synchronize_sound();
+ gettimeofday(&now, NULL);
+ } while (timercmp(&next1, &now, >));
+ else
+ gettimeofday(&now, NULL);
+ //timersub(&next1, &now, &tdiff);
+ //usleep(tdiff.tv_usec/2);
+ //gettimeofday(&now, NULL);
+ skipped_num = 0;
+ next1 = now;
+ } else {
+ if(skipped_num < frameskip_value) {
+ skipped_num++;
+ skipped_num_frame--;
+ skip_next_frame = 1;
+ } else {
+ //synchronize_sound();
+ skipped_num = 0;
+ next1 = now;
+ }
+ }
+ next1.tv_usec += 16667;
+ if(next1.tv_usec >= 1000000) {
+ next1.tv_sec++;
+ next1.tv_usec -= 1000000;
+ }
+ }
+#endif
+
+// if(synchronize_flag == 0)
+// print_string("--FF--", 0xFFFF, 0x000, 0, 0);
+#ifdef ZAURUS
+ //sprintf(char_buffer, "%.1ffps", 1000000.0 / us_needed);
+ //print_string(" ", 0xFFFF, 0x000, 40, 30);
+ //print_string(char_buffer, 0xFFFF, 0x000, 40, 30);
+#else
+ sprintf(char_buffer, "gpSP: %.1fms %.1ffps", us_needed / 1000.0,
+ 1000000.0 / us_needed);
+ SDL_WM_SetCaption(char_buffer, "gpSP");
+#endif
+
+/*
+ sprintf(char_buffer, "%02d %02d %06d %07d", frameskip, (u32)ms_needed,
+ ram_translation_ptr - ram_translation_cache, rom_translation_ptr -
+ rom_translation_cache);
+ print_string(char_buffer, 0xFFFF, 0x0000, 0, 0);
+*/
+}
+
+#endif
+
+void quit()
+{
+ if(!update_backup_flag)
+ update_backup_force();
+
+ sound_exit();
+
+#ifdef PSP_BUILD
+ sceKernelExitGame();
+#else
+ SDL_Quit();
+ exit(0);
+#endif
+}
+
+void reset_gba()
+{
+ init_main();
+ init_memory();
+ init_cpu();
+ reset_sound();
+}
+
+#ifdef PSP_BUILD
+
+u32 file_length(u8 *filename, s32 dummy)
+{
+ SceIoStat stats;
+ sceIoGetstat(filename, &stats);
+ return stats.st_size;
+}
+
+void delay_us(u32 us_count)
+{
+ sceKernelDelayThread(us_count);
+}
+
+void get_ticks_us(u64 *tick_return)
+{
+ u64 ticks;
+ sceRtcGetCurrentTick(&ticks);
+
+ *tick_return = (ticks * 1000000) / sceRtcGetTickResolution();
+}
+
+#else
+
+u32 file_length(u8 *dummy, FILE *fp)
+{
+ u32 length;
+
+ fseek(fp, 0, SEEK_END);
+ length = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ return length;
+}
+
+void delay_us(u32 us_count)
+{
+ SDL_Delay(us_count / 1000); // for dingux
+ // sleep(0);
+}
+
+void get_ticks_us(u64 *ticks_return)
+{
+ *ticks_return = (SDL_GetTicks() * 1000);
+}
+
+#endif
+
+void change_ext(u8 *src, u8 *buffer, u8 *extension)
+{
+ u8 *position;
+
+ strcpy(buffer, main_path);
+ strcat(buffer, "/");
+
+ position = strrchr(src, '/');
+ if (position)
+ src = position+1;
+
+ strcat(buffer, src);
+ position = strrchr(buffer, '.');
+
+ if(position)
+ strcpy(position, extension);
+}
+
+#define main_savestate_builder(type) \
+void main_##type##_savestate(file_tag_type savestate_file) \
+{ \
+ file_##type##_variable(savestate_file, cpu_ticks); \
+ file_##type##_variable(savestate_file, execute_cycles); \
+ file_##type##_variable(savestate_file, video_count); \
+ file_##type##_array(savestate_file, timer); \
+} \
+
+main_savestate_builder(read);
+main_savestate_builder(write_mem);
+
+void print_out(u32 address, u32 pc)
+{
+ char buffer[256];
+ sprintf(buffer, "patching from gp8 %x", address);
+ print_string(buffer, 0xFFFF, 0x0000, 0, 0);
+ update_screen();
+ delay_us(5000000);
+}
+
diff --git a/source/psp/port.h b/source/psp/port.h
index aa74fdd..a9ea25e 100644
--- a/source/psp/port.h
+++ b/source/psp/port.h
@@ -50,6 +50,47 @@
#include "homehook.h"
#include "dvemgr.h"
+#include <pspkernel.h>
+#include <pspdebug.h>
+#include <pspctrl.h>
+#include <pspgu.h>
+#include <pspaudio.h>
+#include <pspaudiolib.h>
+#include <psprtc.h>
+
+#define printf pspDebugScreenPrintf
+
+#define convert_palette(value) \
+ value = ((value & 0x7FE0) << 1) | (value & 0x1F) \
+
+
+typedef u32 FIXED16_16; // Q16.16 fixed-point
+
+#define FILE_OPEN_APPEND (PSP_O_CREAT | PSP_O_APPEND | PSP_O_TRUNC)
+#define FILE_OPEN_READ PSP_O_RDONLY
+#define FILE_OPEN_WRITE (PSP_O_CREAT | PSP_O_WRONLY | PSP_O_TRUNC)
+
+#define FILE_OPEN(filename_tag, filename, mode) \
+ s32 filename_tag = sceIoOpen(filename, FILE_OPEN_##mode, 0777) \
+
+#define FILE_CHECK_VALID(filename_tag) \
+ (filename_tag >= 0) \
+
+#define FILE_TAG_INVALID \
+ (-1) \
+
+#define FILE_CLOSE(filename_tag) \
+ sceIoClose(filename_tag) \
+
+#define FILE_READ(filename_tag, buffer, size) \
+ sceIoRead(filename_tag, buffer, size) \
+
+#define FILE_WRITE(filename_tag, buffer, size) \
+ sceIoWrite(filename_tag, buffer, size) \
+
+#define FILE_SEEK(filename_tag, offset, type) \
+ sceIoLseek(filename_tag, offset, PSP_##type) \
+
/* Tuning parameters for the PSP version of gpSP */
/* Its processors are:
* a) a Sony CXD2962GG at 222 MHz based on the MIPS R4000
@@ -58,8 +99,8 @@
* b) an embedded graphics core at 111 MHz;
* c) a Sony CXD1876 Media Engine chip based on the MIPS R4000
* 64-bit core with 2 MiB of RAM (2.6 Gbit/s). */
-#define READONLY_CODE_CACHE_SIZE (2 * 1024 * 1024)
-#define WRITABLE_CODE_CACHE_SIZE (6 * 1024 * 1024)
+#define READONLY_CODE_CACHE_SIZE (4 * 1024 * 1024)
+#define WRITABLE_CODE_CACHE_SIZE (4 * 1024 * 1024)
/* The following parameter needs to be at least enough bytes to hold
* the generated code for the largest instruction on your platform.
* In most cases, that will be the ARM instruction
@@ -68,12 +109,6 @@
#define GET_DISK_FREE_SPACE FS_CMD_GET_DISKFREE
-typedef SceUID FILE_TAG_TYPE;
-
-#define FILE_OPEN_APPEND (PSP_O_CREAT | PSP_O_APPEND | PSP_O_TRUNC)
-
-#define FILE_OPEN_READ PSP_O_RDONLY
-
-#define FILE_OPEN_WRITE (PSP_O_CREAT | PSP_O_WRONLY | PSP_O_TRUNC)
+typedef s32 FILE_TAG_TYPE;
#endif
diff --git a/source/zip.h b/source/zip.h
index a9fc1f3..2d72e69 100644
--- a/source/zip.h
+++ b/source/zip.h
@@ -22,7 +22,7 @@
#ifndef ZIP_H
#define ZIP_H
-#include "zlib.h"
+#include <zlib.h>
#define ZIP_TMP "ZIPTMP.GBA" /* Acceptable on all platforms */