TRIMUI

如何讓GNGEO支援GNO檔案格式


其實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;
}


返回上一頁