mirror of https://github.com/parasyte/alt64
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4453 lines
128 KiB
4453 lines
128 KiB
/* |
|
* ALT64 Menu v0.1.8.6 - 2013 |
|
* a menu for the Everdrive64 |
|
* based on libdragon, Neo64Menu, ED64IO, libn64-hkz, libmikmod |
|
* by saturnu |
|
*/ |
|
|
|
#include <stdio.h> |
|
#include <stdint.h> |
|
#include <stdlib.h> |
|
#include <malloc.h> |
|
#include <string.h> |
|
#include <math.h> |
|
|
|
//libdragon n64 lib |
|
#include <libdragon.h> |
|
|
|
//everdrive system libs |
|
#include "types.h" |
|
#include "sys.h" |
|
#include "everdrive.h" |
|
#include "everdrive.h" |
|
|
|
//filesystem |
|
#include "disk.h" |
|
#include "fat.h" |
|
|
|
//utils |
|
#include "utils.h" |
|
|
|
//config file on sd |
|
#include "ini.h" |
|
#include "strlib.h" |
|
|
|
//menu header |
|
#include "menu.h" |
|
|
|
//sound |
|
#include <mikmod.h> |
|
#include "mp3.h" |
|
|
|
// YAML parser |
|
#include <yaml.h> |
|
|
|
#ifdef USE_TRUETYPE |
|
#define STB_TRUETYPE_IMPLEMENTATION |
|
#include "stb_truetype.h" |
|
|
|
struct glyph { |
|
int xoff; |
|
int yoff; |
|
int adv; |
|
int lsb; |
|
float scale; |
|
unsigned int color; |
|
unsigned char *alpha; |
|
sprite_t sprite; |
|
}; |
|
typedef struct glyph glyph_t; |
|
|
|
glyph_t sans[96]; |
|
glyph_t serif[96]; |
|
#endif |
|
|
|
|
|
typedef struct |
|
{ |
|
uint32_t type; |
|
uint32_t color; |
|
char filename[MAX_FILENAME_LEN+1]; |
|
} direntry_t; |
|
|
|
|
|
//ini file |
|
typedef struct |
|
{ |
|
int version; |
|
const char* name; |
|
char* background_image; |
|
char* border_color_1; |
|
char* border_color_2; |
|
char* box_color; |
|
char* selection_color; |
|
char* list_font_color; |
|
char* list_dir_font_color; |
|
char* selection_font_color; |
|
char* mempak_path; |
|
char* save_path; |
|
int sound_on; |
|
int page_display; |
|
int tv_mode; |
|
int quick_boot; |
|
int enable_colored_list; |
|
int ext_type; |
|
int cd_behaviour; |
|
int scroll_behaviour; |
|
int text_offset; |
|
int hide_sysfolder; |
|
int sd_speed; |
|
|
|
} configuration; |
|
|
|
|
|
volatile u32 *romaddr_ptr = (u32 *) ROM_ADDR; |
|
unsigned int gBootCic=CIC_6102; |
|
u8 debug=DBG_MODE; |
|
|
|
static uint8_t mempak_data[128 * 256]; |
|
static void *bg_buffer; |
|
void *__safe_bg_buffer; |
|
|
|
#define __get_buffer( x ) __safe_buffer[(x)-1] |
|
extern uint32_t __bitdepth; |
|
extern uint32_t __width; |
|
extern uint32_t __height; |
|
extern void *__safe_buffer[]; |
|
|
|
char firmware_str[64]; |
|
int firm_found=0; |
|
char rom_config[10]; |
|
|
|
display_context_t lockVideo(int wait); |
|
|
|
int select_mode = 0; |
|
int toplist_reload=1; |
|
int toplist_cursor=0; |
|
char toplist15[15][256]; |
|
|
|
int fat_initialized=0; |
|
int exit_ok = 0; |
|
int boot_cic=0; |
|
int boot_save=0; |
|
int cursor_line=0; |
|
int cursor_lastline=0; |
|
u16 cursor_history[32]; |
|
u16 cursor_history_pos=0; |
|
u8 empty=0; |
|
u8 playing=0; |
|
u8 gb_load_y=0; |
|
|
|
//start with filebrowser menu key settings |
|
int input_mapping=1; |
|
/* 1=filemanager |
|
* 2=mempak-menu |
|
* 3=charinput |
|
* 4=rom loaded |
|
* 5=format mpk |
|
* 6=restore mpk |
|
* 7=rom config box |
|
* 8=toplist |
|
* 9=mpk choice |
|
* 10=mpk quick-backup |
|
* 11=mp3 |
|
* 98= A/B abort screen |
|
*/ |
|
|
|
//holds the string of the character input screen result |
|
int text_input_on=0; |
|
|
|
//char input vars |
|
int x,y,position,set; |
|
|
|
unsigned char input_text[32]; |
|
uint32_t chr_forecolor; |
|
uint32_t chr_backcolor; |
|
|
|
//save type still set - save todo after reboot |
|
int save_reboot=0; |
|
|
|
//cart id from rom header |
|
unsigned char cartID[4]; |
|
char curr_dirname[64]; |
|
char pwd[64]; |
|
char rom_filename[128]; |
|
|
|
u32 rom_buff[128]; //rom buffer |
|
u8 *rom_buff8; //rom buffer |
|
|
|
u8 *firmware; |
|
u8 gbload=0; |
|
|
|
int cheats_on=0; |
|
int checksum_fix_on=0; |
|
short int gCheats = 0; /* 0 = off, 1 = select, 2 = all */ |
|
short int force_tv = 0; |
|
short int boot_country=0; |
|
|
|
static resolution_t res = RESOLUTION_320x240; |
|
|
|
//background sprites |
|
sprite_t *loadPng(u8 *png_filename); |
|
sprite_t *background; //background |
|
sprite_t *background0; //splash screen |
|
|
|
//config file theme settings |
|
u32 border_color_1=0xFFFFFFFF; //hex 0xRRGGBBAA AA=transparenxy |
|
u32 border_color_2=0x3F3F3FFF; |
|
u32 box_color=0x00000080; |
|
u32 selection_color=0x6495ED60; |
|
u32 selection_font_color=0xFFFFFFFF; |
|
u32 list_font_color=0xFFFFFFFF; |
|
u32 list_dir_font_color=0xFFFFFFFF; |
|
|
|
char* border_color_1_s; |
|
char* border_color_2_s; |
|
char* box_color_s; |
|
char* selection_color_s; |
|
char* selection_font_color_s; |
|
char* list_font_color_s; |
|
char* list_dir_font_color_s; |
|
|
|
char* mempak_path; |
|
char* save_path; |
|
|
|
u8 sound_on=0; |
|
u8 page_display=0; |
|
int text_offset=0; |
|
u8 tv_mode=0; // 1=ntsc 2=pal 3=mpal 0=default automatic |
|
u8 quick_boot=0; |
|
u8 enable_colored_list=0; |
|
u8 cd_behaviour=0; //0=first entry 1=last entry |
|
u8 scroll_behaviour=0; //1=classic 0=new page-system |
|
u8 ext_type=0; //0=classic 1=org os |
|
u8 sd_speed=1; // 1=25Mhz 2=50Mhz |
|
u8 hide_sysfolder=0; |
|
char* background_image; |
|
|
|
//toplist helper |
|
int list_pos_backup[3]; |
|
char list_pwd_backup[256]; |
|
|
|
char dirz[512] = "rom://"; |
|
|
|
short int gCursorX; |
|
short int gCursorY; |
|
|
|
int count = 0; |
|
int page = 0; |
|
int cursor = 0; |
|
direntry_t *list; |
|
|
|
int filesize( FILE *pFile ) |
|
{ |
|
fseek( pFile, 0, SEEK_END ); |
|
int lSize = ftell( pFile ); |
|
rewind( pFile ); |
|
|
|
return lSize; |
|
} |
|
|
|
sprite_t *read_sprite( const char * const spritename ) { |
|
FILE *fp = fopen( spritename, "r" ); |
|
|
|
if( fp ) { |
|
sprite_t *sp = malloc( filesize( fp ) ); |
|
fread( sp, 1, filesize( fp ), fp ); |
|
fclose( fp ); |
|
|
|
return sp; |
|
} |
|
else { |
|
return 0; |
|
} |
|
} |
|
|
|
|
|
void drawSelection(display_context_t disp,int p){ |
|
int s_x=23+(text_offset*8); |
|
|
|
if(scroll_behaviour){ |
|
if(select_mode){ |
|
if(cursor_lastline>cursor && cursor_line > 0) { |
|
cursor_line--; |
|
} |
|
|
|
if(cursor_lastline<cursor && cursor_line < 19) { |
|
cursor_line++; |
|
} |
|
|
|
p=cursor_line; |
|
graphics_draw_box_trans(disp, s_x, (((p+3)*8)+24), 272, 8, selection_color); //(p+3) diff |
|
cursor_lastline=cursor; |
|
} |
|
} |
|
else { //new page-system |
|
//accept p |
|
graphics_draw_box_trans(disp, s_x, (((p+3)*8)+24), 272, 8, selection_color); |
|
} |
|
} |
|
|
|
void drawConfigSelection(display_context_t disp,int l){ |
|
int s_x=62+(text_offset*8); |
|
|
|
l=l+5; |
|
graphics_draw_box_trans(disp, s_x, (((l+3)*8)+24), 193, 8, 0x00000080); //(p+3) diff |
|
} |
|
|
|
void drawToplistSelection(display_context_t disp,int l){ |
|
int s_x=30+(text_offset*8); |
|
|
|
l=l+2; |
|
graphics_draw_box_trans(disp, s_x, (((l+3)*8)+24), 256, 8, 0xFFFFFF70); //(p+3) diff |
|
} |
|
|
|
|
|
|
|
void chdir( const char * const dirent ) { |
|
/* Ghetto implementation */ |
|
if( strcmp( dirent, ".." ) == 0 ) { |
|
/* Go up one */ |
|
int len = strlen( dirz ) - 1; |
|
|
|
/* Stop going past the min */ |
|
if( dirz[len] == '/' && dirz[len-1] == '/' && dirz[len-2] == ':' ) { |
|
//return if :// |
|
return; |
|
} |
|
|
|
if( dirz[len] == '/' ) { |
|
dirz[len] = 0; |
|
len--; |
|
} |
|
|
|
while( dirz[len] != '/') { |
|
dirz[len] = 0; |
|
len--; |
|
} |
|
} |
|
else { |
|
/* Add to end */ |
|
strcat( dirz, dirent ); |
|
strcat( dirz, "/" ); |
|
} |
|
} |
|
|
|
|
|
int compare(const void * a, const void * b) { |
|
direntry_t *first = (direntry_t *)a; |
|
direntry_t *second = (direntry_t *)b; |
|
|
|
if(first->type == DT_DIR && second->type != DT_DIR) { |
|
/* First should be first */ |
|
return -1; |
|
} |
|
|
|
if(first->type != DT_DIR && second->type == DT_DIR) { |
|
/* First should be second */ |
|
return 1; |
|
} |
|
|
|
return strcmp(first->filename, second->filename); |
|
} |
|
|
|
int compare_int (const void *a, const void *b) { |
|
const int *ia = (const int *)a; // casting pointer types |
|
const int *ib = (const int *)b; |
|
return *ia - *ib; |
|
} |
|
|
|
int compare_int_reverse (const void *a, const void *b) { |
|
const int *ia = (const int *)a; // casting pointer types |
|
const int *ib = (const int *)b; |
|
return *ib - *ia; |
|
} |
|
|
|
void free_dir(direntry_t *dirz) { |
|
if(dirz) { free(dirz); } |
|
} |
|
|
|
void new_scroll_pos(int *cursor, int *page, int max, int count) { |
|
/* Make sure windows too small can be calculated right */ |
|
if(max > count) { |
|
max = count; |
|
} |
|
|
|
/* Bounds checking */ |
|
if(*cursor >= count) { |
|
*cursor = count-1; |
|
} |
|
|
|
if(*cursor < 0) { |
|
*cursor = 0; |
|
} |
|
|
|
/* Scrolled up? */ |
|
if(*cursor < *page) { |
|
*page = *cursor; |
|
return; |
|
} |
|
|
|
/* Scrolled down/ */ |
|
if(*cursor >= (*page + max)) { |
|
*page = (*cursor - max) + 1; |
|
return; |
|
} |
|
|
|
/* Nothing here, should be good! */ |
|
} |
|
|
|
void display_dir(direntry_t *list, int cursor, int page, int max, int count, display_context_t disp) { |
|
//system color |
|
uint32_t forecolor=0; |
|
uint32_t forecolor_menu=0; |
|
uint32_t backcolor; |
|
backcolor = graphics_make_color(0x00, 0x00, 0x00, 0xFF); //bg |
|
forecolor_menu = graphics_make_color(0xFF, 0xFF, 0xFF, 0xFF); //fg |
|
|
|
graphics_set_color (list_font_color, backcolor); |
|
|
|
u8 c_pos[MAX_LIST+1]; |
|
int c_pos_counter=0; |
|
|
|
c_pos[c_pos_counter++]=0; |
|
|
|
u8 c_dirname[64]; |
|
|
|
if(page_display){ |
|
|
|
u8 pi = page/20; |
|
u8 ci=0; |
|
|
|
if(count%20==0) |
|
ci = (count-1)/20; |
|
else |
|
ci = count/20; |
|
sprintf(c_dirname, "%i/%i SD:/%s", pi+1, ci+1, pwd); |
|
} |
|
else{ |
|
sprintf(c_dirname, "SD:/%s", pwd); |
|
} |
|
char sel_str[128]; |
|
|
|
printText(c_dirname, 3, 4, disp); |
|
|
|
int firstrun=1; |
|
/* Page bounds checking */ |
|
if(max > count) { //count = directories starting at 1 |
|
max = count; |
|
} |
|
|
|
/* Cursor bounds checking */ |
|
if(cursor >= (page + max)) { |
|
cursor = (page + max) - 1; |
|
} |
|
|
|
if(cursor < page) { |
|
cursor = page; |
|
} |
|
|
|
if( max == 0 ) { |
|
printText("dir empty...", 3, 6, disp); |
|
sprintf(sel_str, "dir empty..."); |
|
empty=1; |
|
} |
|
else { |
|
empty=0; |
|
} |
|
|
|
//last page anti ghosting entries |
|
if(page == (count/20)*20) |
|
max=count%20; |
|
|
|
for(int i = page; i < (page + max); i++) {//from page to page + max |
|
if(list[i].type == DT_DIR) { |
|
char tmpdir[(CONSOLE_WIDTH-5)+1]; |
|
strncpy(tmpdir, list[i].filename, CONSOLE_WIDTH-5); |
|
|
|
tmpdir[CONSOLE_WIDTH-5] = 0; |
|
|
|
char *dir_str; |
|
dir_str = malloc(slen(tmpdir)+3); |
|
|
|
if(i == cursor){ |
|
sprintf(dir_str, " [%s]", tmpdir); |
|
sprintf(sel_str, " [%s]", tmpdir); |
|
|
|
if(scroll_behaviour) |
|
drawSelection(disp,i); |
|
|
|
c_pos[c_pos_counter++]=1; |
|
} |
|
else{ |
|
sprintf(dir_str, "[%s]", tmpdir); |
|
c_pos[c_pos_counter++]=0; |
|
} |
|
graphics_set_color (list_dir_font_color, backcolor); |
|
if(firstrun){ |
|
printText(dir_str, 3, 6, disp); |
|
firstrun=0; |
|
} |
|
else{ |
|
printText(dir_str, 3, -1, disp); |
|
} |
|
free(dir_str); |
|
} |
|
else { //if(list[i].type == DT_REG) |
|
int fcolor=list[i].color; |
|
|
|
if(fcolor!=0){ |
|
switch(fcolor){ |
|
case 1: forecolor = graphics_make_color(0xFF, 0xFF, 0xFF, 0xFF); //common (white) |
|
break; |
|
case 2: forecolor = graphics_make_color(0x00, 0xFF, 0x00, 0xCF); //uncommon (green) |
|
break; |
|
case 3: forecolor = graphics_make_color(0x1E, 0x90, 0xFF, 0xFF); //rare (blue) |
|
break; |
|
case 4: forecolor = graphics_make_color(0x9B, 0x30, 0xFF, 0xFF); //epic (purple) |
|
break; |
|
case 5: forecolor = graphics_make_color(0xFF, 0xA5, 0x00, 0xFF); //legendary (orange) |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
else |
|
forecolor = list_font_color; |
|
|
|
char tmpdir[(CONSOLE_WIDTH-3)+1]; |
|
strncpy(tmpdir, list[i].filename, CONSOLE_WIDTH-3); |
|
tmpdir[CONSOLE_WIDTH-3] = 0; |
|
|
|
char *dir_str; |
|
dir_str = malloc(slen(tmpdir)+1); |
|
|
|
if(i == cursor){ |
|
sprintf(dir_str, " %s", tmpdir); |
|
sprintf(sel_str, " %s", tmpdir); |
|
|
|
if(scroll_behaviour) |
|
drawSelection(disp,i); |
|
|
|
c_pos[c_pos_counter++]=1; |
|
} |
|
else{ |
|
sprintf(dir_str, "%s", tmpdir); |
|
c_pos[c_pos_counter++]=0; |
|
} |
|
|
|
graphics_set_color(list_font_color, backcolor); |
|
|
|
if(firstrun){ |
|
if(enable_colored_list) |
|
graphics_set_color(forecolor, backcolor); |
|
|
|
printText(dir_str, 3, 6, disp); //3,6 |
|
firstrun=0; |
|
} |
|
else{ |
|
if(enable_colored_list) |
|
graphics_set_color(forecolor, backcolor); |
|
|
|
printText(dir_str, 3, -1, disp); //3,1 |
|
} |
|
free(dir_str); |
|
} |
|
} |
|
|
|
//for page-wise scrolling |
|
if(scroll_behaviour==0){ |
|
int c=0; |
|
for(c=0;c<max+1;c++){ |
|
if(c_pos[c]==1){ |
|
drawSelection(disp,c-1); |
|
//todo: set selection color |
|
graphics_set_color(selection_font_color, backcolor); |
|
printText(sel_str, 3, 6+c-1, disp); |
|
graphics_set_color(forecolor, backcolor); |
|
} |
|
} |
|
} |
|
graphics_set_color(forecolor_menu, backcolor); |
|
} |
|
|
|
|
|
void printText(char *msg, int x, int y, display_context_t dcon) { |
|
x=x+text_offset; |
|
|
|
if (x != -1) |
|
gCursorX = x; |
|
if (y != -1) |
|
gCursorY = y; |
|
|
|
if (dcon) |
|
graphics_draw_text(dcon, gCursorX*8, gCursorY*8, msg); |
|
|
|
gCursorY++; |
|
if (gCursorY > 29) { |
|
gCursorY = 0; |
|
gCursorX ++; |
|
} |
|
} |
|
|
|
void lprintText(char *msg, int x, int y, display_context_t dcon) { |
|
x=x+text_offset; |
|
|
|
if (x != -1) |
|
gCursorX = x; |
|
if (y != -1) |
|
gCursorY = y; |
|
|
|
if (dcon) |
|
graphics_draw_text(dcon, gCursorX*8, gCursorY*8, msg); |
|
|
|
if (gCursorY > 29) { |
|
gCursorY = 0; |
|
gCursorX ++; |
|
} |
|
} |
|
|
|
//background sprite |
|
void drawBg(display_context_t disp){ |
|
graphics_draw_sprite( disp, 0, 0, background ); |
|
} |
|
|
|
void drawBox(short x, short y, short width, short height, display_context_t disp){ |
|
x=x+(text_offset*8); |
|
|
|
/* |
|
* |Y |
|
* | x0/y0 |
|
* | |
|
* | |
|
* | x1/y1 |
|
* |_______________X |
|
* |
|
*/ |
|
|
|
// X0 Y0 X1 Y1 |
|
graphics_draw_line(disp, x, y, width+x, y, border_color_1); //A top left tp bottom right ok |
|
graphics_draw_line(disp, width+x, y, width+x, height+y, border_color_1); //B top right to bottom right |
|
graphics_draw_line(disp, x, y, x, height+y, border_color_2); //C //152-20 |
|
graphics_draw_line(disp, x, height+y, width+x, height+y, border_color_2); //D |
|
graphics_draw_box_trans(disp, x+1, y+1, width-1, height-1, box_color); //red light transparent |
|
} |
|
|
|
void drawBoxNumber(display_context_t disp, int box){ |
|
int old_color = box_color; |
|
//backup color |
|
|
|
switch(box){ |
|
case 1: drawBox(20, 24, 277, 193, disp); break; //filebrowser |
|
case 2: drawBox(60, 56, 200, 128, disp); break; //info screen |
|
case 3: |
|
box_color= graphics_make_color(0x00, 0x00, 0x60, 0xC9); |
|
drawBox(79, 29, 161, 180, disp); |
|
break; //cover |
|
case 4: |
|
box_color= graphics_make_color(0x30, 0x00, 0x00, 0xA3); |
|
drawBox(79, 29, 161, 180, disp); |
|
break; //mempak content |
|
case 5: |
|
box_color= graphics_make_color(0x60, 0x00, 0x00, 0xD3); |
|
drawBox(60, 64, 197, 114, disp); //red confirm screen |
|
break; //mempak content |
|
case 6: |
|
box_color= graphics_make_color(0x60, 0x60, 0x00, 0xC3); |
|
drawBox(60, 64, 197, 125, disp); //yellow screen |
|
break; //rom config box |
|
case 7: |
|
box_color= graphics_make_color(0x00, 0x00, 0x60, 0xC3); |
|
drawBox(60, 105, 197, 20, disp); //blue info screen |
|
break; //info screen |
|
case 8: |
|
box_color= graphics_make_color(0x60, 0x00, 0x00, 0xD3); |
|
drawBox(60, 105, 197, 20, disp); //red error screen |
|
break; //info screen |
|
case 9: |
|
box_color= graphics_make_color(0x00, 0x00, 0x00, 0xB6); |
|
drawBox(28, 49, 260, 150, disp); |
|
break; //yellow toplist |
|
case 10: |
|
box_color= graphics_make_color(0x00, 0x60, 0x00, 0xC3); |
|
drawBox(60, 105, 197, 20, disp); //green info screen |
|
break; //info screen |
|
case 11: |
|
box_color= graphics_make_color(0x00, 0x60, 0x00, 0xC3); |
|
drawBox(28, 105, 260, 30, disp); |
|
break; //green full filename |
|
|
|
default: |
|
break; |
|
} |
|
|
|
//restore color |
|
box_color=old_color; |
|
} |
|
|
|
//is setting the config file vars into the pconfig-structure |
|
static int configHandler(void* user, const char* section, const char* name, const char* value) { |
|
configuration* pconfig = (configuration*)user; |
|
|
|
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0 |
|
|
|
if (MATCH("ed64", "border_color_1")) { |
|
pconfig->border_color_1 = strdup(value); |
|
} |
|
else if (MATCH("ed64", "border_color_2")) { |
|
pconfig->border_color_2 = strdup(value); |
|
} |
|
else if (MATCH("ed64", "box_color")) { |
|
pconfig->box_color = strdup(value); |
|
} |
|
else if (MATCH("ed64", "selection_color")) { |
|
pconfig->selection_color = strdup(value); |
|
} |
|
else if (MATCH("ed64", "list_font_color")) { |
|
pconfig->list_font_color = strdup(value); |
|
} |
|
else if (MATCH("ed64", "list_dir_font_color")) { |
|
pconfig->list_dir_font_color = strdup(value); |
|
} |
|
else if (MATCH("ed64", "selection_font_color")) { |
|
pconfig->selection_font_color = strdup(value); |
|
} |
|
else if (MATCH("ed64", "mempak_path")) { |
|
pconfig->mempak_path = strdup(value); |
|
} |
|
else if (MATCH("ed64", "save_path")) { |
|
pconfig->save_path = strdup(value); |
|
} |
|
else if (MATCH("ed64", "sound_on")) { |
|
pconfig->sound_on = atoi(value); |
|
} |
|
else if (MATCH("ed64", "page_display")) { |
|
pconfig->page_display = atoi(value); |
|
} |
|
else if (MATCH("ed64", "tv_mode")) { |
|
pconfig->tv_mode = atoi(value); |
|
} |
|
else if (MATCH("ed64", "quick_boot")) { |
|
pconfig->quick_boot = atoi(value); |
|
} |
|
else if (MATCH("ed64", "enable_colored_list")) { |
|
pconfig->enable_colored_list = atoi(value); |
|
} |
|
else if (MATCH("ed64", "ext_type")) { |
|
pconfig->ext_type = atoi(value); |
|
} |
|
else if (MATCH("ed64", "cd_behaviour")) { |
|
pconfig->cd_behaviour = atoi(value); |
|
} |
|
else if (MATCH("ed64", "scroll_behaviour")) { |
|
pconfig->scroll_behaviour = atoi(value); |
|
} |
|
else if (MATCH("ed64", "text_offset")) { |
|
pconfig->text_offset = atoi(value); |
|
} |
|
else if (MATCH("ed64", "sd_speed")) { |
|
pconfig->sd_speed = atoi(value); |
|
} |
|
else if (MATCH("ed64", "hide_sysfolder")) { |
|
pconfig->hide_sysfolder = atoi(value); |
|
} |
|
else if (MATCH("ed64", "background_image")) { |
|
pconfig->background_image = strdup(value); |
|
} |
|
else if (MATCH("user", "name")) { |
|
pconfig->name = strdup(value); |
|
} |
|
|
|
else { |
|
return 0; /* unknown section/name, error */ |
|
} |
|
|
|
return 1; |
|
} |
|
|
|
|
|
//everdrive init functions |
|
void configure() { |
|
u16 tv; |
|
u16 msg = 0; |
|
u16 sd_mode = 0; |
|
u8 buff[16]; |
|
u16 firm; |
|
|
|
evd_init(); |
|
//REG_MAX_MSG |
|
evd_setCfgBit(ED_CFG_SDRAM_ON, 0); |
|
dma_read_s(buff, ROM_ADDR + 0x20, 16); |
|
asm_date = memRomRead32(0x38); |
|
evd_setCfgBit(ED_CFG_SDRAM_ON, 1); |
|
|
|
firm = evd_readReg(REG_VER); |
|
|
|
if (streql("ED64 SD boot", buff, 12) && firm >= 0x0116) { |
|
sd_mode = 1; |
|
} |
|
|
|
if (firm >= 0x0200) { |
|
sleep(1); |
|
evd_setCfgBit(ED_CFG_SDRAM_ON, 0); |
|
sleep(1); |
|
|
|
msg = evd_readReg(REG_MAX_MSG); |
|
|
|
if (!(msg & (1 << 14))) { |
|
msg |= 1 << 14; |
|
evd_writeReg(REG_MAX_MSG, msg); |
|
|
|
bi_load_firmware(firmware); |
|
|
|
sleep(1); |
|
evd_init(); |
|
} |
|
sleep(1); |
|
|
|
evd_setCfgBit(ED_CFG_SDRAM_ON, 1); |
|
} |
|
|
|
if (sd_mode) { |
|
diskSetInterface(DISK_IFACE_SD); |
|
} else { |
|
diskSetInterface(DISK_IFACE_SPI); |
|
} |
|
memSpiSetDma(0); |
|
} |
|
|
|
//rewrites the background and the box to clear the screen |
|
void clearScreen(display_context_t disp){ |
|
drawBg(disp); //background |
|
drawBoxNumber(disp,1); //filebrowser box |
|
} |
|
|
|
void romInfoScreen(display_context_t disp, u8 *buff, int silent){ |
|
if(silent!=1) |
|
sleep(10); |
|
|
|
u8 tmp[32]; |
|
u8 filename[64]; |
|
u8 ok=0; |
|
|
|
sprintf(filename, "%s",buff); |
|
int swapped=0; |
|
|
|
FatRecord rec_tmpf; |
|
//not needed any longer :> |
|
//file IS there, it's selected at this point |
|
ok = fatFindRecord(filename, &rec_tmpf, 0); |
|
|
|
u8 resp = 0; |
|
|
|
resp = fatOpenFileByeName(filename, 0); //err if not found ^^ |
|
|
|
int mb = file.sec_available/2048; |
|
int block_offset = 0; |
|
u32 cart_buff_offset = 0; |
|
u32 begin_sector = file.sector; |
|
|
|
//filesize -> readfile / 512 |
|
int fsize=512; //rom-headersize 4096 but the bootcode is not needed |
|
unsigned char headerdata[fsize]; //1*512 |
|
|
|
resp = fatReadFile(&headerdata, fsize / 512); //1 cluster |
|
|
|
int sw_type=is_valid_rom(headerdata); |
|
|
|
if(sw_type!=0){ |
|
swapped=1; |
|
swap_header(headerdata, 512); |
|
} |
|
|
|
//char 32-51 name |
|
unsigned char rom_name[32]; |
|
|
|
for(int u=0; u<19;u++){ |
|
if(u!=0) |
|
sprintf(rom_name, "%s%c", rom_name, headerdata[32+u]); |
|
else |
|
sprintf(rom_name, "%c", headerdata[32+u]); |
|
} |
|
//trim right spaces |
|
//romname=trimmed rom name for filename |
|
sprintf(rom_name, "%s", trim(rom_name)); |
|
|
|
if(silent!=1) |
|
printText(rom_name, 11, 19, disp); |
|
|
|
sprintf(rom_name, "Size: %iMb", mb); |
|
|
|
if(silent!=1) |
|
printText(rom_name, 11, -1, disp); |
|
|
|
//unique cart id for gametype |
|
unsigned char cartID_str[12]; |
|
sprintf(cartID_str, "ID: %c%c%c%c", headerdata[0x3B], headerdata[0x3C], headerdata[0x3D], headerdata[0x3E]); |
|
|
|
if(silent!=1) |
|
printText(cartID_str, 11, -1, disp); |
|
|
|
int cic, save; |
|
|
|
cic = get_cic(&headerdata[0x40]); |
|
|
|
unsigned char cartID_short[4]; |
|
sprintf(cartID_short, "%c%c\0", headerdata[0x3C], headerdata[0x3D]); |
|
|
|
if (get_cic_save(cartID_short, &cic, &save)) { |
|
if(silent!=1) |
|
printText("found in db", 11, -1, disp); |
|
unsigned char save_type_str[12]; |
|
sprintf(save_type_str, "Save: %s", saveTypeToExtension(save,ext_type)); |
|
if(silent!=1) |
|
printText(save_type_str, 11, -1, disp); |
|
|
|
unsigned char cic_type_str[12]; |
|
sprintf(cic_type_str, "CIC: CIC-610%i", cic); |
|
if(silent!=1) |
|
printText(cic_type_str, 11, -1, disp); |
|
|
|
//thanks for the db :> |
|
//cart was found, use CIC and SaveRAM type |
|
} |
|
|
|
if(silent!=1){ |
|
char box_path[32]; |
|
|
|
sprite_t *n64cover; |
|
|
|
sprintf(box_path, "/ED64/boxart/lowres/%c%c.png", headerdata[0x3C], headerdata[0x3D]); |
|
|
|
int found; |
|
|
|
found = fatFindRecord(box_path, &rec_tmpf, 0); |
|
|
|
if(found!=0){ |
|
//not found |
|
sprintf(box_path, "/ED64/boxart/lowres/00.png"); |
|
} |
|
|
|
n64cover = loadPng(box_path); |
|
graphics_draw_sprite( disp, 81, 32, n64cover ); |
|
display_show(disp); |
|
} |
|
else { |
|
rom_config[1]=cic-1; |
|
rom_config[2]=save; |
|
rom_config[3]=0; //tv force off |
|
rom_config[4]=0; //cheat off |
|
rom_config[5]=0; //chk_sum off |
|
rom_config[6]=0; //rating |
|
rom_config[7]=0; //country |
|
rom_config[8]=0; //reserved |
|
rom_config[9]=0; //reserved |
|
} |
|
} |
|
|
|
|
|
sprite_t *loadPng(u8 *png_filename){ |
|
u8 *filename; |
|
u8 ok=0; |
|
|
|
filename = (u8 *) malloc(slen(png_filename)); |
|
//config filename |
|
|
|
sprintf(filename, "%s",png_filename); |
|
FatRecord rec_tmpf; |
|
ok = fatFindRecord(filename, &rec_tmpf, 0); |
|
|
|
u8 resp = 0; |
|
resp = fatOpenFileByeName(filename, 0); |
|
|
|
//filesize of the opend file -> is the readfile / 512 |
|
int fsize= file.sec_available*512; |
|
|
|
u8 png_rawdata[fsize]; |
|
|
|
resp = fatReadFile(&png_rawdata, fsize / 512); //1 cluster |
|
|
|
return loadImage32(png_rawdata, fsize); |
|
|
|
free(filename); |
|
} |
|
|
|
void loadgbrom(display_context_t disp, u8 *buff){ |
|
FatRecord rec_tmpf; |
|
|
|
u8 exist=0; |
|
exist = fatFindRecord("/ED64/gblite.z64", &rec_tmpf, 0); //filename already exists |
|
|
|
if (exist == 0) { |
|
u8 gb_sram_file[64]; |
|
|
|
u8 resp=0; |
|
|
|
sprintf(gb_sram_file, "/ED64/%s/gblite.SRM",save_path); |
|
|
|
resp = fatFindRecord(gb_sram_file, &rec_tmpf, 0); //filename already exists |
|
resp = fatCreateRecIfNotExist(gb_sram_file, 0); |
|
resp = fatOpenFileByeName(gb_sram_file, 32768 / 512); |
|
|
|
static uint8_t sram_buffer[36928]; |
|
|
|
for(int i=0;i<36928;i++) |
|
sram_buffer[i]=0; |
|
|
|
sprintf(sram_buffer, buff); |
|
|
|
resp = fatWriteFile(&sram_buffer, 32768 / 512); |
|
|
|
while( !(disp = display_lock()) ); |
|
|
|
sprintf(rom_filename, "gblite"); |
|
gbload=1; |
|
|
|
loadrom(disp, "/ED64/gblite.z64", 1); |
|
} |
|
} |
|
|
|
void loadmsx2rom(display_context_t disp, u8 *rom_path){ |
|
//max 128kb rom |
|
int max_ok = fatOpenFileByeName(rom_path, 0); |
|
int fsize = file.sec_available*512; //fsize in bytes |
|
|
|
if(fsize>128*1024){ |
|
//error |
|
|
|
drawShortInfoBox(disp, " error: rom > 128kB",1); |
|
input_mapping=98; |
|
|
|
return; |
|
} |
|
else{ |
|
drawShortInfoBox(disp, " loading please wait",0); |
|
input_mapping=100;//disable all |
|
} |
|
|
|
FatRecord rec_tmpf; |
|
|
|
u8 exist=0; |
|
exist = fatFindRecord("/ED64/ultraMSX2.z64", &rec_tmpf, 0); //filename already exists |
|
|
|
if (exist == 0) { |
|
u8 resp=0; |
|
//load nes emulator |
|
resp = fatOpenFileByeName("/ED64/ultraMSX2.z64", 0); //err if not found ^^ |
|
|
|
int fsize=1024*1024; |
|
u8 buffer[fsize]; |
|
|
|
//injecting in buffer... slow but working :/ |
|
resp = fatReadFile(buffer, file.sec_available); |
|
resp = fatOpenFileByeName(rom_path, 0); //err if not found ^^ |
|
resp = fatReadFile(buffer+0x2df48, file.sec_available); |
|
dma_write_s(buffer, 0xb0000000, fsize); |
|
|
|
boot_cic=2; //cic 6102 |
|
boot_save=0; //save off/cpak |
|
force_tv=0; //no force |
|
cheats_on=0; //cheats off |
|
checksum_fix_on=0; |
|
|
|
checksum_sdram(); |
|
|
|
bootRom(disp, 1); |
|
} |
|
} |
|
|
|
|
|
void loadggrom(display_context_t disp, u8 *rom_path){ |
|
//max 512kb rom |
|
int max_ok = fatOpenFileByeName(rom_path, 0); |
|
int fsize = file.sec_available*512; //fsize in bytes |
|
|
|
if(fsize>512*1024){ |
|
//error |
|
drawShortInfoBox(disp, " error: rom > 512kB",1); |
|
input_mapping=98; |
|
|
|
return; |
|
} |
|
else{ |
|
drawShortInfoBox(disp, " loading please wait",0); |
|
input_mapping=100;//disable all |
|
} |
|
|
|
FatRecord rec_tmpf; |
|
|
|
u8 exist=0; |
|
exist = fatFindRecord("/ED64/UltraSMS.z64", &rec_tmpf, 0); //filename already exists |
|
|
|
if (exist == 0) { |
|
u8 resp=0; |
|
//load nes emulator |
|
resp = fatOpenFileByeName("/ED64/UltraSMS.z64", 0); //err if not found ^^ |
|
|
|
int fsize=1024*1024; |
|
u8 buffer[fsize]; |
|
|
|
//injecting in buffer... slow but working :/ |
|
resp = fatReadFile(buffer, file.sec_available); |
|
resp = fatOpenFileByeName(rom_path, 0); //err if not found ^^ |
|
resp = fatReadFile(buffer+0x1b410, file.sec_available); |
|
dma_write_s(buffer, 0xb0000000, fsize); |
|
|
|
boot_cic=2; //cic 6102 |
|
boot_save=0; //save off/cpak |
|
force_tv=0; //no force |
|
cheats_on=0; //cheats off |
|
checksum_fix_on=0; |
|
|
|
checksum_sdram(); |
|
|
|
bootRom(disp, 1); |
|
} |
|
} |
|
|
|
void rom_load_y(void){ |
|
FatRecord rec_tmpf; |
|
|
|
u8 gb_sram_file[64]; |
|
u8 gb_sram_file2[64]; |
|
sprintf(gb_sram_file, "%c%c%c%c%c%c%c",'O', 'S', '6', '4', 'P', '/', 'O'); |
|
sprintf(gb_sram_file2, "%s%c%c%c%c%c%c%c%c", gb_sram_file, 'S', '6', '4', 'P', '.', 'v', '6', '4'); |
|
|
|
u8 exist=0; |
|
exist = fatFindRecord(gb_sram_file2, &rec_tmpf, 0); //filename already exists |
|
if (exist == 0) { |
|
gb_load_y=1; |
|
} |
|
} |
|
|
|
void loadnesrom(display_context_t disp, u8 *rom_path){ |
|
FatRecord rec_tmpf; |
|
|
|
u8 exist=0; |
|
exist = fatFindRecord("/ED64/neon64bu.rom", &rec_tmpf, 0); //filename already exists |
|
|
|
if (exist == 0) { |
|
u8 resp=0; |
|
//load nes emulator |
|
resp = fatOpenFileByeName("/ED64/neon64bu.rom", 0); //err if not found ^^ |
|
resp = diskRead(file.sector, (void *)0xb0000000, file.sec_available); |
|
|
|
//load nes rom |
|
resp = fatOpenFileByeName(rom_path, 0); //err if not found ^^ |
|
resp = diskRead(file.sector, (void *)0xb0200000, file.sec_available); |
|
|
|
boot_cic=2; //cic 6102 |
|
boot_save=0; //save off/cpak |
|
force_tv=0; //no force |
|
cheats_on=0; //cheats off |
|
checksum_fix_on=0; |
|
|
|
bootRom(disp, 1); |
|
} |
|
} |
|
|
|
//load a z64/v64/n64 rom to the sdram |
|
void loadrom(display_context_t disp, u8 *buff, int fast){ |
|
clearScreen(disp); |
|
|
|
display_show(disp); |
|
|
|
if(!fast) |
|
printText("Restoring:", 3, 4, disp); |
|
|
|
sleep(10); |
|
sleep(1000); //needless waiting :> |
|
|
|
if (debug) |
|
printText("timing done", 3, -1, disp); |
|
|
|
u8 tmp[32]; |
|
u8 filename[64]; |
|
u8 ok=0; |
|
|
|
sprintf(filename, "%s",buff); |
|
int swapped=0; |
|
|
|
if (debug) |
|
printText(buff, 3, -1, disp); |
|
|
|
FatRecord rec_tmpf; |
|
//not needed any longer :> |
|
//file IS there, it's selected at this point |
|
ok = fatFindRecord(filename, &rec_tmpf, 0); |
|
if (debug) |
|
printText("found", 3, -1, disp); |
|
|
|
u8 resp = 0; |
|
|
|
resp = fatOpenFileByeName(filename, 0); //err if not found ^^ |
|
|
|
if (debug) |
|
printText("opened", 3, -1, disp); |
|
|
|
int mb = file.sec_available/2048; |
|
int file_sectors = file.sec_available; |
|
int block_offset = 0; |
|
u32 cart_buff_offset = 0; |
|
u32 begin_sector = file.sector; |
|
|
|
//filesize -> readfile / 512 |
|
int fsize=512; //rom-headersize 4096 but the bootcode is not needed |
|
unsigned char headerdata[fsize]; //1*512 |
|
|
|
resp = fatReadFile(&headerdata, fsize / 512); //1 cluster |
|
|
|
int sw_type=is_valid_rom(headerdata); |
|
|
|
if(sw_type!=0){ |
|
if(!fast) |
|
printText("byteswapped file", 3, -1, disp); |
|
|
|
swapped=1; |
|
swap_header(headerdata, 512); |
|
} |
|
|
|
//char 32-51 name |
|
unsigned char rom_name[32]; |
|
|
|
for(int u=0; u<19;u++){ |
|
if(u!=0) |
|
sprintf(rom_name, "%s%c", rom_name, headerdata[32+u]); |
|
else |
|
sprintf(rom_name, "%c", headerdata[32+u]); |
|
} |
|
//trim right spaces |
|
//romname=trimmed rom name for filename |
|
sprintf(rom_name, "%s", trim(rom_name)); |
|
|
|
if(!fast) |
|
printText(rom_name, 3, -1, disp); |
|
|
|
//unique cart id for gametype |
|
|
|
sprintf(cartID, "%c%c%c%c", headerdata[0x3B], headerdata[0x3C], headerdata[0x3D], headerdata[0x3E]); |
|
|
|
int cic, save; |
|
|
|
cic = get_cic(&headerdata[0x40]); |
|
|
|
unsigned char cartID_short[4]; |
|
sprintf(cartID_short, "%c%c\0", headerdata[0x3C], headerdata[0x3D]); |
|
|
|
if (get_cic_save(cartID_short, &cic, &save)) { |
|
if(!fast) |
|
printText("found in db", 3, -1, disp); |
|
//thanks for the db :> |
|
// cart was found, use CIC and SaveRAM type |
|
} |
|
|
|
if (debug) { |
|
sprintf(tmp, "Info: cic=%i save=%i",cic,save); |
|
printText(tmp, 3, -1, disp); |
|
} |
|
|
|
//new rom_config |
|
boot_cic=rom_config[1]+1; |
|
boot_save=rom_config[2]; |
|
force_tv=rom_config[3]; |
|
cheats_on=rom_config[4]; |
|
checksum_fix_on=rom_config[5]; |
|
boot_country=rom_config[7]; //boot_block |
|
|
|
if (gbload==1) |
|
boot_save=1; |
|
|
|
else if (resp) { |
|
sprintf(tmp, "resp: %i",resp); |
|
printText(tmp, 3, -1, disp); |
|
} |
|
|
|
if (debug) |
|
printText("enalbe sd_mode", 3, -1, disp); |
|
|
|
resp = evd_isSDMode(); |
|
|
|
if (debug) { |
|
sprintf(tmp, "sdmode: %i",resp); |
|
printText(tmp, 3, -1, disp); |
|
|
|
sprintf(tmp, "Size: %i", file.sec_available); |
|
printText(tmp, 3, -1, disp); |
|
|
|
sprintf(tmp, "f_sector: %i", file.sector); |
|
printText(tmp, 3, -1, disp); |
|
|
|
printText("loading:", 3, -1, disp); |
|
} |
|
sleep(10); |
|
|
|
if(swapped==1){ |
|
while (evd_isDmaBusy()); |
|
sleep(400); |
|
evd_mmcSetDmaSwap(1); |
|
|
|
if (debug) |
|
printText("swapping on", 3, -1, disp); |
|
|
|
sleep(10); |
|
} |
|
|
|
if(!fast) |
|
printText("loading please wait...", 3, -1, disp); |
|
else |
|
printText("loading please wait...", 3, 4, disp); |
|
|
|
sleep(10); |
|
|
|
int lower_half=2048*32; |
|
|
|
if(mb<=32){ |
|
resp = diskRead(begin_sector, (void *)0xb0000000, file_sectors); //2048 cluster 1Mb |
|
} |
|
else{ |
|
resp = diskRead(begin_sector, (void *)0xb0000000, lower_half); |
|
resp = diskRead(begin_sector+lower_half, (void *)0xb2000000, file_sectors-lower_half); |
|
} |
|
|
|
if(resp){ |
|
if (debug) { |
|
sprintf(tmp, "mmcToCart: %i",resp); |
|
printText(tmp, 3, -1, disp); |
|
} |
|
} |
|
|
|
if (debug) { |
|
for (int i = 0; i < 4; i++) { |
|
u8 buff[16]; |
|
dma_read_s(buff, 0xb0000000 + 0x00100000*i, 1); |
|
sprintf(tmp, "probe: %hhx",buff[0]); |
|
printText(tmp, 3, -1, disp); |
|
|
|
} |
|
} |
|
|
|
if(!fast){ |
|
sleep(200); |
|
|
|
printText(" ", 3, -1, disp); |
|
printText("(C-UP to activate cheats)", 3, -1, disp); |
|
printText("(C-RIGHT to force menu tv mode)", 3, -1, disp); |
|
printText("done: PRESS START", 3, -1, disp); |
|
} |
|
else{ |
|
bootRom(disp, 1); |
|
} |
|
} |
|
|
|
|
|
int backupSaveData(display_context_t disp){ |
|
//backup cart-save on sd after reboot |
|
u8 fname[32]; |
|
u8 found=0; |
|
int save_t; |
|
|
|
sprintf(fname, "/ED64/%s/LAST.CRT",save_path); |
|
uint8_t cfg_data[512]; |
|
|
|
FatRecord rec_tmpf; |
|
found = fatFindRecord(fname, &rec_tmpf, 0); |
|
|
|
printText("Save System - please stand by", 3, 4, disp); |
|
|
|
if(found==0){ |
|
//found |
|
|
|
//file to cfg_data buffer |
|
u8 resp = 0; |
|
resp = fatOpenFileByeName(fname, 0); |
|
resp = fatReadFile(&cfg_data, 1); |
|
|
|
//split in save type and cart-id |
|
save_t=cfg_data[0]; |
|
int last_cic=cfg_data[1]; |
|
scopy(cfg_data+2, rom_filename); |
|
|
|
//set savetype to 0 disable for next boot |
|
if(save_t!=0){ |
|
//set savetype to off |
|
cfg_data[0]=0; |
|
|
|
u8 tmp[32]; |
|
|
|
resp = fatOpenFileByeName(fname, 1); //if sector is set filemode=WR writeable |
|
|
|
if (debug) { |
|
sprintf(tmp, "fatOpenFileByeName ret=%i",resp); |
|
printText(tmp, 3, -1, disp); |
|
} |
|
|
|
resp = fatWriteFile(&cfg_data, 1); //filemode must be wr |
|
|
|
if (debug) { |
|
sprintf(tmp, "fatWriteFile ret=%i",resp); |
|
printText(tmp, 3, -1, disp); |
|
|
|
printText("SaveType-tag has been disabled for next boot", 3, -1, disp); |
|
} |
|
|
|
volatile u8 save_cfg_stat=0; |
|
volatile u8 val=0; |
|
val = evd_readReg(0); |
|
save_cfg_stat = evd_readReg(REG_SAV_CFG); |
|
|
|
if(save_cfg_stat!=0) |
|
save_reboot=1; |
|
} |
|
else { |
|
if (debug) |
|
printText("no need to save to sd", 3, -1, disp); |
|
else |
|
printText("...ready", 3, -1, disp); |
|
|
|
sleep(200); |
|
|
|
return 1; |
|
} |
|
} |
|
else{ |
|
if (debug) |
|
printText("last.crt not found", 3, -1, disp); |
|
else |
|
printText("...ready", 3, -1, disp); |
|
|
|
return 0; |
|
} |
|
|
|
if (debug) { |
|
sleep(5000); |
|
} |
|
|
|
//reset with save request |
|
if(save_reboot){ |
|
printText("saving...", 3, -1, disp); |
|
if( saveTypeToSd(disp, rom_filename, save_t) ){ |
|
if (debug) |
|
printText("save upload done...", 3, -1, disp); |
|
else |
|
printText("...ready", 3, -1, disp); |
|
} |
|
else if (debug) |
|
printText("not saved...", 3, -1, disp); |
|
} |
|
else { |
|
if (debug) |
|
printText("no reset - save request", 3, -1, disp); |
|
else |
|
printText("...ready", 3, -1, disp); |
|
|
|
sleep(300); |
|
} |
|
|
|
return 1; |
|
} |
|
|
|
//old method to write a file to the mempak at controller 1 |
|
void file_to_mpk(display_context_t disp, u8 *filename){ |
|
u8 tmp[32]; |
|
u8 buff[64]; |
|
u8 ok=0; |
|
|
|
printText(filename, 9, -1, disp); |
|
FatRecord rec_tmpf; |
|
ok = fatFindRecord(filename, &rec_tmpf, 0); |
|
|
|
u8 resp = 0; |
|
resp = fatOpenFileByeName(filename, 0); |
|
|
|
u8 *pch; |
|
pch=strrchr(filename,'.'); |
|
sprintf(buff, "%s",(pch+2)); |
|
|
|
if(strcmp(buff,"64")==0){ |
|
printText("Dexdrive format", 9, -1, disp); |
|
printText("skip header", 9, -1, disp); |
|
|
|
static uint8_t mempak_data_buff[36928]; |
|
resp = fatReadFile(&mempak_data_buff, 36928 / 512); |
|
|
|
memcpy( &mempak_data, mempak_data_buff+4160, 32768); |
|
} |
|
else { |
|
printText("Z64 format", 9, -1, disp); |
|
resp = fatReadFile(&mempak_data, 32768 / 512); |
|
} |
|
|
|
int err = 0; |
|
for( int j = 0; j < 128; j++ ) { |
|
err |= write_mempak_sector( 0, j, &mempak_data[j * MEMPAK_BLOCK_SIZE] ); |
|
} |
|
} |
|
|
|
char TranslateNotes( char *bNote, char *Text ) { |
|
#pragma warning( disable : 4305 4309 ) |
|
char cReturn = 0x00; |
|
const char aSpecial[] = { 0x21, 0x22, 0x23, 0x60, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x3A, 0x3D, 0x3F, 0x40, 0x74, 0xA9, 0xAE }; |
|
// { '!' , '\"', '#' , '`' , '*' , '+' , ',' , '-' , '.' , '/' , ':' , '=' , '?' , '>' , 'tm', '(r)','(c)' }; |
|
#pragma warning( default : 4305 4309 ) |
|
int i = 16; |
|
do { |
|
char b = bNote[i]; |
|
if(( b > 0 ) && i < 32 ) { |
|
if( b <= 0x0F ) // translate Icons as Spaces |
|
*Text = 0x20; |
|
else if( b <= 0x19 ) // Numbers |
|
*Text = 0x20 + b; |
|
else if( b <= 0x33 ) // Characters |
|
*Text = 0x47 + b; |
|
else if( b <= 0x44 ) // special Symbols |
|
*Text = aSpecial[b - 0x34]; |
|
else if( b <= 0x94 ) // Japan |
|
*Text = 0xC0 + ( b % 40 ); |
|
else // unknown |
|
*Text = (char)0xA4; |
|
|
|
++i; |
|
++Text; |
|
} |
|
else { |
|
*Text = '\0'; |
|
if( b ) { |
|
i = 12; |
|
Text = &cReturn; |
|
} |
|
else |
|
i = 13; |
|
} |
|
} while( i != 13 ); |
|
|
|
return cReturn; |
|
} |
|
|
|
char CountBlocks( char *bMemPakBinary, char *aNoteSizes ) { |
|
int wRemainingBlocks = 123; |
|
char bNextIndex; |
|
int i = 0; |
|
while( i < 16 && wRemainingBlocks <= 123 ) { |
|
aNoteSizes[i] = 0; |
|
bNextIndex = bMemPakBinary[0x307 + (i*0x20)]; |
|
while(( bNextIndex >= 5 ) && ( aNoteSizes[i] < wRemainingBlocks)) { |
|
aNoteSizes[i]++; |
|
bNextIndex = bMemPakBinary[0x101 + (bNextIndex*2)]; |
|
} |
|
|
|
if( aNoteSizes[i] > wRemainingBlocks ) |
|
wRemainingBlocks = 0xFF; |
|
else |
|
wRemainingBlocks -= aNoteSizes[i]; |
|
|
|
i++; |
|
} |
|
return wRemainingBlocks; |
|
} |
|
|
|
void view_mpk_file(display_context_t disp, char *mpk_filename){ |
|
u8 tmp[32]; |
|
u8 buff[64]; |
|
u8 ok=0; |
|
|
|
FatRecord rec_tmpf; |
|
ok = fatFindRecord(mpk_filename, &rec_tmpf, 0); |
|
|
|
u8 resp = 0; |
|
resp = fatOpenFileByeName(mpk_filename, 0); |
|
|
|
u8 * pch; |
|
pch=strrchr(mpk_filename,'.'); |
|
sprintf(buff, "%s",(pch+2)); |
|
|
|
if (strcmp(buff, "64") == 0) { |
|
static uint8_t mempak_data_buff[36928]; |
|
resp = fatReadFile(&mempak_data_buff, 36928 / 512); |
|
memcpy( &mempak_data, mempak_data_buff+4160, 32768); |
|
} |
|
else { |
|
resp = fatReadFile(&mempak_data, 32768 / 512); |
|
} |
|
|
|
printText("File content:", 11, 5, disp); |
|
printText(" ", 11, -1, disp); |
|
|
|
int notes_c=0; |
|
|
|
char szBuffer[40], |
|
cAppendix; |
|
int bFirstChar; |
|
|
|
int i = 0, |
|
nNotes = 0, |
|
iSum = 0, |
|
iRemainingBlocks; |
|
|
|
char aNoteSizes[16]; |
|
|
|
for( i = 0x10A; i < 0x200; i++ ) |
|
iSum += mempak_data[i]; |
|
|
|
if((( iSum % 256 ) == mempak_data[0x101] )) { |
|
iRemainingBlocks = CountBlocks( mempak_data, aNoteSizes ); |
|
|
|
if( iRemainingBlocks <= 123 ) { |
|
for( notes_c = 0; notes_c < 16; notes_c++ ){ |
|
if( mempak_data[0x300 + (notes_c*32)] || |
|
mempak_data[0x301 + (notes_c*32)] || |
|
mempak_data[0x302 + (notes_c*32)] ) |
|
{ |
|
cAppendix = TranslateNotes( &mempak_data[0x300 + (notes_c*32)], szBuffer ); |
|
|
|
if( cAppendix != '\0' ) |
|
sprintf( szBuffer, "%s. %c", szBuffer, cAppendix ); |
|
|
|
bFirstChar = 1; |
|
for( i = 0; i < (int)strlen(szBuffer); i++ ) { |
|
if( szBuffer[i] == ' ' ) |
|
bFirstChar = 1; |
|
else { |
|
if( bFirstChar && ( szBuffer[i] >= 'a') && ( szBuffer[i] <= 'z')) { |
|
bFirstChar = 0; |
|
szBuffer[i] -= 0x20; |
|
} |
|
} |
|
} |
|
printText(szBuffer, 11, -1, disp); |
|
|
|
switch( mempak_data[0x303 + (notes_c*32)] ) |
|
{ |
|
case 0x00: |
|
sprintf( szBuffer, "None" ); |
|
break; |
|
case 0x37: |
|
sprintf( szBuffer, "Beta" ); |
|
break; |
|
case 0x41: |
|
sprintf( szBuffer, "NTSC" ); |
|
break; |
|
case 0x44: |
|
sprintf( szBuffer, "Germany" ); |
|
break; |
|
case 0x45: |
|
sprintf( szBuffer, "USA" ); |
|
break; |
|
case 0x46: |
|
sprintf( szBuffer, "France" ); |
|
break; |
|
case 0x49: |
|
sprintf( szBuffer, "Italy" ); |
|
break; |
|
case 0x4A: |
|
sprintf( szBuffer, "Japan" ); |
|
break; |
|
case 0x50: |
|
sprintf( szBuffer, "Europe" ); |
|
break; |
|
case 0x53: |
|
sprintf( szBuffer, "Spain" ); |
|
break; |
|
case 0x55: |
|
sprintf( szBuffer, "Australia" ); |
|
break; |
|
case 0x58: |
|
case 0x59: |
|
sprintf( szBuffer, "PAL" ); |
|
break; |
|
default: |
|
sprintf( szBuffer, "Unknown(%02X)", mempak_data[0x303 + (notes_c*32)] ); |
|
} |
|
|
|
sprintf( szBuffer, "%i", aNoteSizes[notes_c] ); |
|
nNotes++; |
|
} |
|
} |
|
} |
|
|
|
int free_c=0; |
|
for(free_c=nNotes;free_c<16;free_c++) |
|
printText("[free]", 11, -1, disp); |
|
|
|
char buff[512]; |
|
printText(" ", 11, -1, disp); |
|
printText("Free space:", 11, -1, disp); |
|
sprintf(buff, "%i blocks", iRemainingBlocks ); |
|
printText(buff, 11, -1, disp); |
|
} |
|
else { |
|
printText("empty", 11, -1, disp); |
|
} |
|
} |
|
|
|
void view_mpk(display_context_t disp){ |
|
int err; |
|
|
|
printText("Mempak content:", 11, 5, disp); |
|
get_accessories_present(); |
|
|
|
/* Make sure they don't have a rumble pak inserted instead */ |
|
switch( identify_accessory( 0 ) ) |
|
{ |
|
case ACCESSORY_NONE: |
|
|
|
printText(" ", 11, -1, disp); |
|
printText("no Mempak", 11, -1, disp); |
|
break; |
|
|
|
case ACCESSORY_MEMPAK: |
|
if( (err = validate_mempak( 0 )) ) { |
|
if( err == -3 ) { |
|
printText(" ", 11, -1, disp); |
|
|
|
printText("not formatted", 11, -1, disp); |
|
} |
|
else { |
|
printText(" ", 11, -1, disp); |
|
printText("read error" , 11, -1, disp); |
|
} |
|
} |
|
else { |
|
printText(" ", 11, -1, disp); |
|
for( int j = 0; j < 16; j++ ) { |
|
entry_structure_t entry; |
|
|
|
get_mempak_entry( 0, j, &entry ); |
|
|
|
if( entry.valid ) { |
|
char tmp[512]; |
|
sprintf(tmp, "%s", entry.name ); |
|
printText(tmp, 11, -1, disp); |
|
} |
|
else { |
|
printText("[free]", 11, -1, disp); |
|
} |
|
} |
|
|
|
char buff[512]; |
|
printText(" ", 11, -1, disp); |
|
printText("Free space:", 11, -1, disp); |
|
sprintf(buff, "%d blocks", get_mempak_free_space( 0 ) ); |
|
printText(buff, 11, -1, disp); |
|
} |
|
break; |
|
|
|
case ACCESSORY_RUMBLEPAK: |
|
printText("rumblepak inserted", 11, -1, disp); |
|
break; |
|
} |
|
} |
|
|
|
|
|
//old function to dump a mempak to a file |
|
void mpk_to_file(display_context_t disp, char *mpk_filename, int quick) { |
|
u8 buff[64]; |
|
u8 v=0; |
|
u8 ok=0; |
|
|
|
if(quick) |
|
sprintf(buff, "%s%s",mempak_path, mpk_filename); |
|
else |
|
sprintf(buff, "%s%s.MPK",mempak_path,mpk_filename); |
|
|
|
FatRecord rec_tmpf; |
|
|
|
if(!fatFindRecord(buff, &rec_tmpf, 0)){ //filename already exists |
|
printText("File exists", 9, -1, disp); |
|
if(quick) |
|
printText("override", 9, -1, disp); |
|
else |
|
while(ok==0){ |
|
sprintf(buff, "%s%s%i.MPK",mempak_path, mpk_filename,v); |
|
|
|
ok = fatFindRecord(buff, &rec_tmpf, 0); |
|
if (ok==0) |
|
v++; |
|
else |
|
break; |
|
} |
|
} |
|
|
|
u8 resp=0; |
|
resp = fatCreateRecIfNotExist(buff, 0); |
|
resp = fatOpenFileByeName(buff, 32768 / 512); |
|
|
|
controller_init(); |
|
|
|
int err = 0; |
|
for( int j = 0; j < 128; j++ ) { |
|
err |= read_mempak_sector( 0, j, &mempak_data[j * 256] ); |
|
} |
|
|
|
fatWriteFile(&mempak_data, 32768 / 512); |
|
|
|
sleep(500); |
|
|
|
sprintf(buff, "File: %s%i.MPK",mpk_filename,v); |
|
|
|
printText(buff, 9, -1, disp); |
|
printText("backup done...", 9, -1, disp); |
|
} |
|
|
|
//before boot_simulation |
|
//writes a cart-save from a file to the fpga/cart |
|
int saveTypeFromSd(display_context_t disp, char* rom_name, int stype) { |
|
rom_load_y(); |
|
|
|
u8 tmp[32]; |
|
u8 fname[128]; |
|
u8 found=0; |
|
|
|
int size; |
|
size = saveTypeToSize(stype); // int byte |
|
|
|
sprintf(fname, "/ED64/%s/%s.%s",save_path,rom_name, saveTypeToExtension(stype,ext_type)); |
|
|
|
uint8_t cartsave_data[size]; |
|
|
|
if (debug) { |
|
printText(fname, 3, -1, disp); |
|
sleep(2000); |
|
} |
|
|
|
FatRecord rec_tmpf; |
|
found = fatFindRecord(fname, &rec_tmpf, 0); |
|
|
|
if (debug) { |
|
sprintf(tmp, "fatFindRecord ret=%i",found); |
|
printText(tmp, 3, -1, disp); |
|
} |
|
|
|
if(found==0){ |
|
u8 resp = 0; |
|
resp = fatOpenFileByeName(fname, 0); |
|
|
|
if (debug) { |
|
sprintf(tmp, "fatOpenFileByeName ret=%i",resp); |
|
printText(tmp, 3, -1, disp); |
|
} |
|
|
|
resp = fatReadFile(cartsave_data, size / 512); |
|
|
|
if (debug) { |
|
sprintf(tmp, "fatReadFile ret=%i",resp); |
|
printText(tmp, 3, -1, disp); |
|
} |
|
} |
|
else{ |
|
printText("no savegame found", 3, -1, disp); |
|
//todo clear memory arena |
|
|
|
return 0; |
|
} |
|
|
|
if(gb_load_y!=1) { |
|
if( pushSaveToCart(stype, cartsave_data) ){ |
|
|
|
printText("save upload done...", 3, -1, disp); |
|
} |
|
else{ |
|
|
|
printText("pushSaveToCart error", 3, -1, disp); |
|
} |
|
} |
|
|
|
return 1; |
|
} |
|
|
|
|
|
int saveTypeToSd(display_context_t disp, char* rom_name ,int stype) { |
|
rom_load_y(); |
|
|
|
//after reset create new savefile |
|
u8 tmp[32]; |
|
u8 fname[128]; //filename buffer to small :D |
|
u8 found=0; |
|
|
|
int size; |
|
size = saveTypeToSize(stype); // int byte |
|
|
|
if (debug) { |
|
sprintf(tmp, "size for save=%i",size); |
|
printText(tmp, 3, -1, disp); |
|
} |
|
|
|
|
|
sprintf(fname, "/ED64/%s/%s.%s",save_path,rom_name,saveTypeToExtension(stype,ext_type)); |
|
|
|
FatRecord rec_tmpf; |
|
found = fatFindRecord(fname, &rec_tmpf, 0); |
|
|
|
if (debug) { |
|
sprintf(tmp, "found=%i",found); |
|
printText(tmp, 3, -1, disp); |
|
} |
|
|
|
u8 resp=0; |
|
|
|
//FAT_ERR_NOT_EXIST 100 |
|
if(found!=0){ |
|
//create before save |
|
printText("try fatCreateRecIfNotExist", 3, -1, disp); |
|
resp = fatCreateRecIfNotExist(fname, 0); |
|
|
|
if (debug) { |
|
sprintf(tmp, "fatCreateRecIfNotExist ret=%i",resp); //0 means try to create |
|
printText(tmp, 3, -1, disp); |
|
} |
|
} |
|
|
|
//open file with stype size |
|
resp = fatOpenFileByeName(fname, size / 512); |
|
|
|
if (debug) { |
|
sprintf(tmp, "fatOpenFileByeName ret=%i",resp); //100 not exist |
|
printText(tmp, 3, -1, disp); |
|
} |
|
|
|
//for savegame |
|
uint8_t cartsave_data[size]; |
|
|
|
for(int zero=0; zero<size;zero++) |
|
cartsave_data[zero]=0; |
|
|
|
if (debug) { |
|
sprintf(tmp, "cartsave_data=%p",&cartsave_data); |
|
printText(tmp, 3, -1, disp); |
|
} |
|
|
|
//universal dumpfunction |
|
//returns data from fpga/cart to save on sd |
|
|
|
if(getSaveFromCart(stype, cartsave_data)) { |
|
printText("got save from fpga", 3, -1, disp); |
|
//write to file |
|
|
|
if(gb_load_y!=1) |
|
fatWriteFile(&cartsave_data, size / 512); |
|
|
|
printText("reset-save done...", 3, -1, disp); |
|
sleep(3000); |
|
return 1; |
|
} |
|
else { |
|
printText("getSaveFromCart error", 3, -1, disp); |
|
sleep(3000); |
|
return 0; |
|
} |
|
} |
|
|
|
|
|
//check out the userfriendly ini file for config-information |
|
|
|
int readConfigFile(void){ |
|
//var file readin |
|
u8 tmp[32]; |
|
u8 filename[32]; |
|
u8 ok=0; |
|
|
|
//config filename |
|
sprintf(filename, "/ED64/ALT64.INI"); |
|
FatRecord rec_tmpf; |
|
ok = fatFindRecord(filename, &rec_tmpf, 0); |
|
|
|
u8 resp = 0; |
|
resp = fatOpenFileByeName(filename, 0); |
|
|
|
//filesize of the opend file -> is the readfile / 512 |
|
int fsize= file.sec_available*512; |
|
char config_rawdata[fsize]; |
|
|
|
resp = fatReadFile(&config_rawdata, fsize / 512); //1 cluster |
|
configuration config; |
|
|
|
if (ini_parse_str(config_rawdata, configHandler, &config) < 0) { |
|
return 0; |
|
} |
|
else { |
|
border_color_1_s=config.border_color_1; |
|
border_color_2_s=config.border_color_2; |
|
box_color_s=config.box_color; |
|
selection_color_s=config.selection_color; |
|
selection_font_color_s=config.selection_font_color; |
|
list_font_color_s=config.list_font_color; |
|
list_dir_font_color_s=config.list_dir_font_color; |
|
|
|
mempak_path=config.mempak_path; |
|
save_path=config.save_path; |
|
sound_on=config.sound_on; |
|
page_display=config.page_display; |
|
tv_mode=config.tv_mode; |
|
quick_boot=config.quick_boot; |
|
enable_colored_list=config.enable_colored_list; |
|
ext_type=config.ext_type; |
|
cd_behaviour=config.cd_behaviour; |
|
scroll_behaviour=config.scroll_behaviour; |
|
text_offset=config.text_offset; |
|
hide_sysfolder=config.hide_sysfolder; |
|
sd_speed=config.sd_speed; |
|
background_image=config.background_image; |
|
|
|
return 1; |
|
} |
|
} |
|
|
|
int str2int(char data){ |
|
data -= '0'; |
|
if (data>9) |
|
data-= 7; |
|
|
|
return data; |
|
} |
|
|
|
uint32_t translate_color(char *hexstring){ |
|
int r = str2int(hexstring[0])*16 + str2int(hexstring[1]); |
|
int g = str2int(hexstring[2])*16 + str2int(hexstring[3]); |
|
int b = str2int(hexstring[4])*16 + str2int(hexstring[5]); |
|
int a = str2int(hexstring[6])*16 + str2int(hexstring[7]); |
|
|
|
return graphics_make_color(r,g,b,a); |
|
} |
|
|
|
//init fat filesystem after everdrive init and before sdcard access |
|
void initFilesystem(void){ |
|
sleep(1000); |
|
evd_ulockRegs(); |
|
sleep(1000); |
|
|
|
fatInitRam(); |
|
fatInit(); |
|
fat_initialized=1; |
|
} |
|
|
|
//prints the sdcard-filesystem content |
|
void readSDcard(display_context_t disp, char *directory){ |
|
//todo: check out the minimal sleeping needs |
|
//color test |
|
|
|
FatRecord *frec; |
|
u8 cresp = 0; |
|
count = 1; |
|
|
|
//load the directory-entry |
|
cresp = fatLoadDirByName("/ED64/CFG"); |
|
|
|
int dsize=dir->size; |
|
char colorlist[dsize][256]; |
|
|
|
if(enable_colored_list){ |
|
for (int i = 0; i < dir->size; i++){ |
|
frec = dir->rec[i]; |
|
u8 rom_cfg_file[128]; |
|
|
|
//set rom_cfg |
|
sprintf(rom_cfg_file, "/ED64/CFG/%s",frec->name ); |
|
|
|
static uint8_t cfg_file_data[512] = { 0 }; |
|
cresp = fatOpenFileByeName(rom_cfg_file, 0); //512 bytes fix one cluster |
|
cresp = fatReadFile(&cfg_file_data, 1); |
|
|
|
colorlist[i][0]=(char)cfg_file_data[5]; //color |
|
strcpy(colorlist[i]+1, cfg_file_data+32); //fullpath |
|
} |
|
} |
|
|
|
|
|
clearScreen(disp); |
|
printText("SD-Card loading...", 3, 4, disp); //very short display time maybe comment out |
|
|
|
u8 buff[32]; |
|
|
|
//some trash buffer |
|
FatRecord *rec; |
|
u8 resp = 0; |
|
|
|
count = 1; |
|
dir_t buf; |
|
|
|
//load the directory-entry |
|
resp = fatLoadDirByName(directory); |
|
|
|
if (resp!=0){ |
|
char error_msg[32]; |
|
sprintf(error_msg,"CHDIR ERROR: %i", resp); |
|
printText(error_msg, 3, -1, disp); |
|
sleep(3000); |
|
} |
|
|
|
|
|
//clear screen and print the directory name |
|
clearScreen(disp); |
|
|
|
//creates string list of files and directorys |
|
for (int i = 0; i < dir->size; i++) { |
|
char name_tmpl[32]; |
|
rec = dir->rec[i]; |
|
|
|
if(strcmp(rec->name,"ED64")==0 && hide_sysfolder==1){ |
|
//don't add |
|
} |
|
else{ |
|
if(rec->is_dir){ |
|
list[count-1].type = DT_DIR; //2 is dir +1 |
|
} |
|
else{ |
|
list[count-1].type = DT_REG; //1 is file +1 |
|
} |
|
|
|
strcpy(list[count-1].filename, rec->name); //+1 |
|
|
|
//new color test |
|
list[count-1].color = 0; |
|
|
|
if(enable_colored_list){ |
|
for(int c=0; c<dsize; c++){ |
|
|
|
u8 short_name[256]; |
|
|
|
sprintf(short_name, "%s", colorlist[c]+1); |
|
|
|
u8 * pch_s; // point-offset |
|
pch_s=strrchr(short_name,'/'); |
|
|
|
if(strcmp(list[count-1].filename, pch_s+1)==0){ |
|
|
|
list[count-1].color = colorlist[c][0]; |
|
|
|
} |
|
} |
|
//new color test end |
|
} |
|
|
|
count++; |
|
list = realloc(list, sizeof(direntry_t) * count); |
|
} |
|
} |
|
count--; |
|
|
|
page = 0; |
|
cursor = 0; |
|
select_mode=1; |
|
|
|
if(count > 0) { |
|
/* Should sort! */ |
|
qsort(list, count, sizeof(direntry_t), compare); |
|
} |
|
|
|
//print directory |
|
display_dir(list, cursor, page, MAX_LIST, count, disp); |
|
} |
|
|
|
/* |
|
* Returns two cheat lists: |
|
* - One for the "at boot" cheats |
|
* - Another for the "in-game" cheats |
|
*/ |
|
int readCheatFile(char *filename, u32 *cheat_lists[2]) { |
|
// YAML parser |
|
yaml_parser_t parser; |
|
yaml_event_t event; |
|
|
|
// State for YAML parser |
|
int is_code = 0; |
|
int code_on = 1; |
|
int done = 0; |
|
u32 *list1; |
|
u32 *list2; |
|
char *next; |
|
|
|
int repeater = 0; |
|
u32 address; |
|
u32 value; |
|
|
|
yaml_parser_initialize(&parser); |
|
|
|
FatRecord rec_tmpf; |
|
int ok = fatFindRecord(filename, &rec_tmpf, 0); |
|
if (ok != 0) { |
|
return -1; //err file not found |
|
} |
|
|
|
u8 resp = 0; |
|
resp = fatOpenFileByeName(filename, 0); |
|
|
|
//filesize of the opend file -> is the readfile / 512 |
|
int fsize = file.sec_available * 512; |
|
char *cheatfile = malloc(fsize); |
|
if (!cheatfile) { |
|
return -2; // Out of memory |
|
} |
|
|
|
/* |
|
* Size of the cheat list can never be more than half the size of the YAML |
|
* Minimum YAML example: |
|
* A:-80001234 FFFF |
|
* Which is exactly 16 bytes. |
|
* The cheat list in this case fits into exactly 8 bytes (2 words): |
|
* 0x80001234, 0x0000FFFF |
|
*/ |
|
list1 = calloc(1, fsize + 2 * sizeof(u32)); // Plus 2 words to be safe |
|
if (!list1) { |
|
// Free |
|
free(cheatfile); |
|
return -2; // Out of memory |
|
} |
|
list2 = &list1[fsize / sizeof(u32) / 2]; |
|
cheat_lists[0] = list1; |
|
cheat_lists[1] = list2; |
|
|
|
resp = fatReadFile(cheatfile, fsize / 512); //1 cluster |
|
|
|
yaml_parser_set_input_string(&parser, cheatfile, strlen(cheatfile)); |
|
|
|
do { |
|
if (!yaml_parser_parse(&parser, &event)) { |
|
// Free |
|
yaml_parser_delete(&parser); |
|
yaml_event_delete(&event); |
|
free(cheatfile); |
|
free(cheat_lists[0]); |
|
cheat_lists[0] = 0; |
|
cheat_lists[1] = 0; |
|
|
|
return -3; // Parse error |
|
} |
|
|
|
// Process YAML |
|
switch (event.type) { |
|
case YAML_MAPPING_START_EVENT: |
|
// Begin code block |
|
is_code = 0; |
|
break; |
|
|
|
case YAML_SEQUENCE_START_EVENT: |
|
// Begin code lines |
|
is_code = 1; |
|
code_on = (event.data.sequence_start.tag ? |
|
!!strcasecmp(event.data.sequence_start.tag, "!off") : |
|
1 |
|
); |
|
break; |
|
|
|
case YAML_SEQUENCE_END_EVENT: |
|
// End code lines |
|
is_code = 0; |
|
code_on = 1; |
|
repeater = 0; |
|
break; |
|
|
|
case YAML_SCALAR_EVENT: |
|
// Code line |
|
if (!is_code || !code_on) { |
|
break; |
|
} |
|
|
|
address = strtoul(event.data.scalar.value, &next, 16); |
|
value = strtoul(next, NULL, 16); |
|
|
|
// Do not check code types within "repeater data" |
|
if (repeater) { |
|
repeater--; |
|
*list2++ = address; |
|
*list2++ = value; |
|
break; |
|
} |
|
|
|
// Determine destination cheat_list for the code type |
|
switch (address >> 24) { |
|
|
|
// Uncessary code types |
|
case 0x20: // Clear code list |
|
case 0xCC: // Exception Handler Selection |
|
case 0xDE: // Entry Point |
|
break; |
|
|
|
// Boot-time cheats |
|
case 0xEE: // Disable Expansion Pak |
|
case 0xF0: // 8-bit Boot-Time Write |
|
case 0xF1: // 16-bit Boot-Time Write |
|
case 0xFF: // Cheat Engine Location |
|
*list1++ = address; |
|
*list1++ = value; |
|
break; |
|
|
|
// In-game cheats |
|
case 0x50: // Repeater/Patch |
|
// Validate repeater count |
|
if (address & 0x0000FF00) { |
|
repeater = 1; |
|
*list2++ = address; |
|
*list2++ = value; |
|
} |
|
break; |
|
|
|
// Everything else |
|
default: |
|
if (!address) { |
|
// TODO: Support special code types! :) |
|
} |
|
// Fall-through! |
|
|
|
case 0xD0: // 8-bit Equal-To Conditional |
|
case 0xD1: // 16-bit Equal-To Conditional |
|
case 0xD2: // 8-bit Not-Equal-To Conditional |
|
case 0xD3: // 16-bit Not-Equal-To Conditional |
|
// Validate 16-bit codes |
|
if ((address & 0x01000001) == 0x01000001) { |
|
break; |
|
} |
|
|
|
*list2++ = address; |
|
*list2++ = value; |
|
break; |
|
} |
|
break; |
|
|
|
case YAML_STREAM_END_EVENT: |
|
// And we're outta here! |
|
done = 1; |
|
break; |
|
} |
|
|
|
yaml_event_delete(&event); |
|
} while (!done); |
|
|
|
// Free |
|
yaml_parser_delete(&parser); |
|
free(cheatfile); |
|
|
|
return repeater; // Ok or repeater error |
|
} |
|
|
|
void timing(display_context_t disp){ |
|
unsigned char tmp[32]; |
|
|
|
IO_WRITE(PI_STATUS_REG, 0x02); |
|
|
|
u32 pi0 = IO_READ(PI_BSD_DOM1_LAT_REG); |
|
u32 pi1 = IO_READ(PI_BSD_DOM1_PWD_REG); |
|
u32 pi2 = IO_READ(PI_BSD_DOM1_PGS_REG); |
|
u32 pi3 = IO_READ(PI_BSD_DOM1_RLS_REG); |
|
|
|
printText("timing dom1:", 3, -1, disp); |
|
sprintf(tmp, "lat=%x pwd=%x\npgs=%x rls=%x",pi0,pi1,pi2,pi3); |
|
printText(tmp, 3, -1, disp); |
|
} |
|
|
|
void bootRom(display_context_t disp, int silent) { |
|
if (boot_cic != 0) { |
|
if (boot_save != 0){ |
|
u8 cfg_file[32]; |
|
u8 found=0; |
|
u8 resp=0; |
|
u8 tmp[32]; |
|
|
|
//set cfg file with last loaded cart info and save-type |
|
sprintf(cfg_file, "/ED64/%s/LAST.CRT", save_path); |
|
|
|
resp = fatCreateRecIfNotExist(cfg_file, 0); |
|
resp = fatOpenFileByeName(cfg_file, 1); //512 bytes fix one cluster |
|
|
|
static uint8_t cfg_file_data[512] = { 0 }; |
|
cfg_file_data[0] = boot_save; |
|
cfg_file_data[1] = boot_cic; |
|
scopy(rom_filename, cfg_file_data + 2); |
|
|
|
fatWriteFile(&cfg_file_data, 1); |
|
sleep(500); |
|
|
|
//set the fpga cart-save type |
|
evd_setSaveType(boot_save); |
|
|
|
if (debug) { |
|
printText("try to restore save from sd", 3, -1, disp); |
|
} |
|
resp = saveTypeFromSd(disp, rom_filename, boot_save); |
|
|
|
if (debug) { |
|
sprintf(tmp, "saveTypeFromSd ret=%i",resp); |
|
printText(tmp, 3, -1, disp); |
|
} |
|
} |
|
|
|
if (debug) { |
|
printText("Cartridge-Savetype set", 3, -1, disp); |
|
printText("information stored for reboot-save...", 3, -1, disp); |
|
} |
|
|
|
sleep(50); |
|
|
|
u32 cart, country; |
|
u32 info = *(vu32 *)0xB000003C; |
|
cart = info >> 16; |
|
country = (info >> 8) & 0xFF; |
|
|
|
u32 *cheat_lists[2] = { NULL, NULL }; |
|
if (cheats_on) { |
|
gCheats = 1; |
|
printText("try to load cheat-file...", 3, -1, disp); |
|
|
|
char cheat_filename[64]; |
|
sprintf(cheat_filename, "/ED64/CHEATS/%s.yml", rom_filename); |
|
|
|
int ok = readCheatFile(cheat_filename, cheat_lists); |
|
if (ok == 0) { |
|
printText("cheats found...", 3, -1, disp); |
|
sleep(600); |
|
} |
|
else { |
|
printText("cheats not found...", 3, -1, disp); |
|
sleep(2000); |
|
gCheats = 0; |
|
} |
|
} |
|
else { |
|
gCheats = 0; |
|
} |
|
|
|
disable_interrupts(); |
|
int bios_cic = getCicType(1); |
|
|
|
if (checksum_fix_on) { |
|
checksum_sdram(); |
|
} |
|
|
|
evd_lockRegs(); |
|
sleep(1000); |
|
|
|
while( !(disp = display_lock()) ); |
|
//blank screen to avoid glitches |
|
|
|
graphics_fill_screen(disp, 0x000000FF); |
|
display_show(disp); |
|
|
|
simulate_boot(boot_cic, bios_cic, cheat_lists); // boot_cic |
|
} |
|
} |
|
|
|
void playSound(int snd){ |
|
//no thread support in libdragon yet, sounds pause the menu for a time :/ |
|
|
|
//maybe global |
|
int v1; |
|
|
|
static SAMPLE *add_sfx = NULL; |
|
if(snd==1) |
|
add_sfx = Sample_Load("rom://ed64_mono.wav"); |
|
|
|
if(snd==2) |
|
add_sfx = Sample_Load("rom://bamboo.wav"); |
|
|
|
if(snd==3) |
|
add_sfx = Sample_Load("rom://warning.wav"); |
|
|
|
if(snd==4) |
|
add_sfx = Sample_Load("rom://done.wav"); |
|
|
|
MikMod_SetNumVoices(-1, 2); |
|
|
|
if (!add_sfx) { |
|
MikMod_Exit(); |
|
} |
|
else{ |
|
MikMod_EnableOutput(); |
|
|
|
audio_write_silence(); |
|
audio_write_silence(); |
|
|
|
v1 = Sample_Play(add_sfx, 0, 0); |
|