其實GNGEO模擬器本身是支援GNO檔案格式,只是不知道為何在載入ROM的時候,要做剔除副檔名的動作(src/main.c)
original_rom_name = cf_parse_cmd_line(argc,argv);
printf("original rom name=[%s]\n",original_rom_name);
rom_name = remove_path_and_extension(original_rom_name, '.', '/');
printf("rom name=[%s]\n",rom_name);
但是,後續處理ROM時卻又判斷是否有.GNO檔案
int load_game_config(char *rom_name) {
char *gpath;
char *drconf;
#ifdef EMBEDDED_FS
gpath = ROOTPATH"conf/";
#else
gpath = get_gngeo_dir();
#endif
cf_reset_to_default();
cf_open_file(NULL); /* Reset possible previous setting */
if (rom_name) {
if (strstr(rom_name,".gno") != NULL) {
char *name = dr_gno_romname(rom_name);
if (name) {
printf("Tring to load a gno file %s %s\n",rom_name,name);
因此,司徒在一開始先判斷是否為.GNO副檔名,如果不是,才做剔除的動作
char *rom_name = NULL;
char *ext_name = NULL;
cf_init();
cf_init_cmd_line();
cf_open_file(NULL);
rom_name = cf_parse_cmd_line(argc, argv);
if(rom_name){
ext_name = strrchr(rom_name, '.');
printf("rom name: %s\n", rom_name);
if (strcasecmp(ext_name, ".gno")) {
rom_name = remove_path_and_extension(rom_name, '.', '/');
}
}
那接下來的問題是,什麼是GNO檔案呢?(src/rom.c)
int dr_save_gno(GAME_ROMS *r, char *filename)
{
FILE *gno;
char *fid = "gnodmpv1";
char fname[9];
Uint8 nb_sec = 0;
int i;
gno = fopen(filename, "wb");
if (!gno)
return GN_FALSE;
/* restore game vector */
memcpy(memory.rom.cpu_m68k.p, memory.game_vector, 0x80);
for (i = 0; i < 0x80; i++)
printf("%02x ", memory.rom.cpu_m68k.p[i]);
printf("\n");
if (r->cpu_m68k.p)
nb_sec++;
if (r->cpu_z80.p)
nb_sec++;
if (r->adpcma.p)
nb_sec++;
if (r->adpcmb.p && (r->adpcmb.p != r->adpcma.p))
nb_sec++;
if (r->game_sfix.p)
nb_sec++;
if (r->tiles.p)
nb_sec += 2; /* Sprite + Sprite usage */
if (r->gfix_usage.p)
nb_sec++;
/* Do we need Custom Bios? */
if ((r->info.flags & HAS_CUSTOM_CPU_BIOS))
{
nb_sec++;
}
if ((r->info.flags & HAS_CUSTOM_SFIX_BIOS))
{
nb_sec++;
}
/* Header information */
fwrite(fid, 8, 1, gno);
snprintf(fname, 9, "%-8s", r->info.name);
fwrite(fname, 8, 1, gno);
fwrite(&r->info.flags, sizeof(Uint32), 1, gno);
fwrite(&nb_sec, sizeof(Uint8), 1, gno);
/* Now each section */
dump_region(gno, &r->cpu_m68k, REGION_MAIN_CPU_CARTRIDGE, 0, 0);
dump_region(gno, &r->cpu_z80, REGION_AUDIO_CPU_CARTRIDGE, 0, 0);
dump_region(gno, &r->adpcma, REGION_AUDIO_DATA_1, 0, 0);
if (r->adpcma.p != r->adpcmb.p)
dump_region(gno, &r->adpcmb, REGION_AUDIO_DATA_2, 0, 0);
dump_region(gno, &r->game_sfix, REGION_FIXED_LAYER_CARTRIDGE, 0, 0);
dump_region(gno, &r->spr_usage, REGION_SPR_USAGE, 0, 0);
dump_region(gno, &r->gfix_usage, REGION_GAME_FIX_USAGE, 0, 0);
if ((r->info.flags & HAS_CUSTOM_CPU_BIOS))
{
dump_region(gno, &r->bios_m68k, REGION_MAIN_CPU_BIOS, 0, 0);
}
if ((r->info.flags & HAS_CUSTOM_SFIX_BIOS))
{
dump_region(gno, &r->bios_sfix, REGION_FIXED_LAYER_BIOS, 0, 0);
}
/* TODO, there is a bug in the loading routine, only one compressed (type 1)
* region can be present at the end of the file */
dump_region(gno, &r->tiles, REGION_SPRITES, 1, 4096);
fclose(gno);
return GN_TRUE;
}
P.S. 其實就是儲存已經解完密的每個REGION資料,所以小橫米、TRIMUI掌機應該要使用這種格式
那另外一個問題是,如何DUMP呢?(src/main.c)
/* If asked, do a .gno dump and exit*/
if (CF_BOOL(cf_get_item_by_name("dump"))) {
char dump[8+4+1];
sprintf(dump,"%s.gno",rom_name);
dr_save_gno(&memory.rom,dump);
close_game();
return 0;
}
P.S. 只要在啟動gngeo時,使用--dump就可以做DUMP的動作
如下
$ ./gngeo --dump

P.S. 載入遊戲後,gngeo會自動離開並且產生(null).gno檔案,因為char dump並沒有被初始化
司徒使用小橫米、TRIMUI對比了一下ZIP和GNO的載入速度

司徒把沒有用到的選項都刪除了

FPS顯示還包含CPU使用率

CPU使用率計算方式
static int __attribute__((noinline)) get_cpu_ticks(void)
{
static int fd = 0;
static unsigned long last_utime = 0;
char buf[128] = {0};
unsigned long utime = 0, ret = 0;
if (fd == 0)
{
fd = open("/proc/self/stat", O_RDONLY);
}
lseek(fd, 0, SEEK_SET);
buf[0] = 0;
read(fd, buf, sizeof(buf));
buf[sizeof(buf) - 1] = 0;
sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu", &utime);
ret = utime - last_utime;
if (ret > 200)
{
ret = 0;
}
last_utime = utime;
return ret;
}