starting SMS work
[picodrive.git] / platform / common / emu.c
index 3443c98..1cecc39 100644 (file)
@@ -174,8 +174,7 @@ static int emu_isBios(const char *name)
 \r
 static unsigned char id_header[0x100];\r
 \r
-/* checks if fname points to valid MegaCD image\r
- * if so, checks for suitable BIOS */\r
+/* checks if fname points to valid MegaCD image */\r
 static int emu_cd_check(int *pregion, const char *fname_in)\r
 {\r
        const char *fname = fname_in;\r
@@ -243,6 +242,58 @@ static int emu_cd_check(int *pregion, const char *fname_in)
        return type;\r
 }\r
 \r
+static int detect_media(const char *fname)\r
+{\r
+       static const short sms_offsets[] = { 0x7ff0, 0x3ff0, 0x1ff0 };\r
+       pm_file *pmf;\r
+       char buff[32];\r
+       char ext[5];\r
+       int i;\r
+\r
+       get_ext(fname, ext);\r
+\r
+       // detect wrong extensions\r
+       if (!strcmp(ext, ".srm") || !strcmp(ext, "s.gz") || !strcmp(ext, ".mds")) // s.gz ~ .mds.gz\r
+               return PM_BAD;\r
+\r
+       /* don't believe in extensions, except .cue */\r
+       if (strcasecmp(ext, ".cue") == 0)\r
+               return PM_CD;\r
+\r
+       pmf = pm_open(fname);\r
+       if (pmf == NULL)\r
+               return PM_BAD;\r
+\r
+       if (pm_read(buff, 32, pmf) != 32) {\r
+               pm_close(pmf);\r
+               return PM_BAD;\r
+       }\r
+\r
+       if (strncasecmp("SEGADISCSYSTEM", buff + 0x00, 14) == 0 ||\r
+           strncasecmp("SEGADISCSYSTEM", buff + 0x10, 14) == 0) {\r
+               pm_close(pmf);\r
+               return PM_CD;\r
+       }\r
+\r
+       for (i = 0; i < array_size(sms_offsets); i++) {\r
+               if (pm_seek(pmf, sms_offsets[i], SEEK_SET) != sms_offsets[i])\r
+                       goto not_mark3;         /* actually it could be but can't be detected */\r
+\r
+               if (pm_read(buff, 16, pmf) != 16)\r
+                       goto not_mark3;\r
+\r
+               if (strncasecmp("TMR SEGA", buff, 8) == 0) {\r
+                       pm_close(pmf);\r
+                       return PM_MARK3;\r
+               }\r
+       }\r
+\r
+not_mark3:\r
+       pm_close(pmf);\r
+       /* the main emu function is to emulate MD, so assume MD */\r
+       return PM_MD_CART;\r
+}\r
+\r
 static int extract_text(char *dest, const unsigned char *src, int len, int swab)\r
 {\r
        char *p = dest;\r
@@ -321,6 +372,7 @@ static void shutdown_MCD(void)
 }\r
 \r
 // note: this function might mangle rom_fname\r
+// XXX: portions of this code should move to pico/\r
 int emu_reload_rom(char *rom_fname)\r
 {\r
        unsigned int rom_size = 0;\r
@@ -328,20 +380,14 @@ int emu_reload_rom(char *rom_fname)
        unsigned char *rom_data = NULL;\r
        char ext[5];\r
        pm_file *rom = NULL;\r
-       int ret, cd_state, cd_region, cfg_loaded = 0;\r
+       int cd_state = CIT_NOT_CD;\r
+       int ret, media_type, cd_region;\r
+       int cfg_loaded = 0, bad_rom = 0;\r
 \r
        lprintf("emu_ReloadRom(%s)\n", rom_fname);\r
 \r
        get_ext(rom_fname, ext);\r
 \r
-       // detect wrong extensions\r
-       if (!strcmp(ext, ".srm") || !strcmp(ext, "s.gz") || !strcmp(ext, ".mds")) { // s.gz ~ .mds.gz\r
-               me_update_msg("Not a ROM/CD selected.");\r
-               return 0;\r
-       }\r
-\r
-       PicoPatchUnload();\r
-\r
        // check for movie file\r
        if (movie_data) {\r
                free(movie_data);\r
@@ -396,46 +442,53 @@ int emu_reload_rom(char *rom_fname)
                get_ext(rom_fname, ext);\r
        }\r
 \r
+       media_type = detect_media(rom_fname);\r
+       if (media_type == PM_BAD) {\r
+               me_update_msg("Not a ROM/CD img selected.");\r
+               return 0;\r
+       }\r
+\r
        shutdown_MCD();\r
+       PicoPatchUnload();\r
 \r
-       // check for MegaCD image\r
-       cd_state = emu_cd_check(&cd_region, rom_fname);\r
-       if (cd_state >= 0 && cd_state != CIT_NOT_CD)\r
+       if (media_type == PM_CD)\r
        {\r
-               PicoAHW |= PAHW_MCD;\r
-               // valid CD image, check for BIOS..\r
+               // check for MegaCD image\r
+               cd_state = emu_cd_check(&cd_region, rom_fname);\r
+               if (cd_state >= 0 && cd_state != CIT_NOT_CD)\r
+               {\r
+                       // valid CD image, check for BIOS..\r
 \r
-               // we need to have config loaded at this point\r
-               ret = emu_read_config(1, 0);\r
-               if (!ret) emu_read_config(0, 0);\r
-               cfg_loaded = 1;\r
+                       // we need to have config loaded at this point\r
+                       ret = emu_read_config(1, 0);\r
+                       if (!ret) emu_read_config(0, 0);\r
+                       cfg_loaded = 1;\r
+\r
+                       if (PicoRegionOverride) {\r
+                               cd_region = PicoRegionOverride;\r
+                               lprintf("override region to %s\n", cd_region != 4 ?\r
+                                       (cd_region == 8 ? "EU" : "JAP") : "USA");\r
+                       }\r
+                       if (!find_bios(cd_region, &used_rom_name))\r
+                               return 0;\r
 \r
-               if (PicoRegionOverride) {\r
-                       cd_region = PicoRegionOverride;\r
-                       lprintf("overrided region to %s\n", cd_region != 4 ? (cd_region == 8 ? "EU" : "JAP") : "USA");\r
+                       get_ext(used_rom_name, ext);\r
+                       PicoAHW |= PAHW_MCD;\r
                }\r
-               if (!find_bios(cd_region, &used_rom_name)) {\r
-                       PicoAHW &= ~PAHW_MCD;\r
+               else {\r
+                       me_update_msg("Invalid CD image");\r
                        return 0;\r
                }\r
-\r
-               get_ext(used_rom_name, ext);\r
        }\r
-       else\r
-       {\r
-               if (PicoAHW & PAHW_MCD) Stop_CD();\r
-               PicoAHW &= ~PAHW_MCD;\r
+       else if (media_type == PM_MARK3) {\r
+               lprintf("detected SMS ROM\n");\r
+               PicoAHW = PAHW_SMS;\r
        }\r
 \r
        rom = pm_open(used_rom_name);\r
-       if (!rom) {\r
-               me_update_msg("Failed to open ROM/CD image");\r
-               goto fail;\r
-       }\r
-\r
-       if (cd_state < 0) {\r
-               me_update_msg("Invalid CD image");\r
-               goto fail;\r
+       if (rom == NULL) {\r
+               me_update_msg("Failed to open ROM");\r
+               return 0;\r
        }\r
 \r
        menu_romload_prepare(used_rom_name); // also CD load\r
@@ -443,21 +496,29 @@ int emu_reload_rom(char *rom_fname)
        PicoCartUnload();\r
        rom_loaded = 0;\r
 \r
-       if ( (ret = PicoCartLoad(rom, &rom_data, &rom_size)) ) {\r
+       ret = PicoCartLoad(rom, &rom_data, &rom_size, (PicoAHW & PAHW_SMS) ? 1 : 0);\r
+       pm_close(rom);\r
+       if (ret != 0) {\r
                if      (ret == 2) me_update_msg("Out of memory");\r
                else if (ret == 3) me_update_msg("Read failed");\r
                else               me_update_msg("PicoCartLoad() failed.");\r
-               goto fail2;\r
+               goto fail;\r
        }\r
-       pm_close(rom);\r
-       rom = NULL;\r
-\r
-       // detect wrong files (Pico crashes on very small files), also see if ROM EP is good\r
-       if (rom_size <= 0x200 || strncmp((char *)rom_data, "Pico", 4) == 0 ||\r
-         ((*(unsigned char *)(rom_data+4)<<16)|(*(unsigned short *)(rom_data+6))) >= (int)rom_size) {\r
-               if (rom_data) free(rom_data);\r
-               me_update_msg("Not a ROM selected.");\r
-               goto fail2;\r
+\r
+       // detect wrong files\r
+       if (strncmp((char *)rom_data, "Pico", 4) == 0)\r
+               bad_rom = 1;\r
+       else if (!(PicoAHW & PAHW_SMS)) {\r
+               unsigned short *d = (unsigned short *)(rom_data + 4);\r
+               if ((((d[0] << 16) | d[1]) & 0xffffff) >= (int)rom_size) {\r
+                       lprintf("bad reset vector\n");\r
+                       bad_rom = 1;\r
+               }\r
+       }\r
+\r
+       if (bad_rom) {\r
+               me_update_msg("Bad ROM detected.");\r
+               goto fail;\r
        }\r
 \r
        // load config for this ROM (do this before insert to get correct region)\r
@@ -468,18 +529,19 @@ int emu_reload_rom(char *rom_fname)
                if (!ret) emu_read_config(0, 0);\r
        }\r
 \r
-       lprintf("PicoCartInsert(%p, %d);\n", rom_data, rom_size);\r
        if (PicoCartInsert(rom_data, rom_size)) {\r
                me_update_msg("Failed to load ROM.");\r
-               goto fail2;\r
+               goto fail;\r
        }\r
 \r
        // insert CD if it was detected\r
        if (cd_state != CIT_NOT_CD) {\r
                ret = Insert_CD(rom_fname, cd_state);\r
                if (ret != 0) {\r
+                       PicoCartUnload();\r
+                       rom_data = NULL; // freed by unload\r
                        me_update_msg("Insert_CD() failed, invalid CD image?");\r
-                       goto fail2;\r
+                       goto fail;\r
                }\r
        }\r
 \r
@@ -511,8 +573,22 @@ int emu_reload_rom(char *rom_fname)
        }\r
        else\r
        {\r
+               const char *sys_name, *tv_standard;\r
+               int fps;\r
+\r
+               if (PicoAHW & PAHW_SMS) {\r
+                       sys_name = "Master System";\r
+               } else {\r
+                       sys_name = "MegaDrive";\r
+                       if ((Pico.m.hardware&0xc0) == 0x80)\r
+                               sys_name = "Genesis";\r
+               }\r
+               tv_standard = Pico.m.pal ? "PAL" : "NTSC";\r
+               fps = Pico.m.pal ? 50 : 60;\r
+\r
+               emu_status_msg("%s %s / %dFPS", tv_standard, sys_name, fps);\r
+\r
                PicoOpt &= ~POPT_DIS_VDP_FIFO;\r
-               emu_status_msg(Pico.m.pal ? "PAL SYSTEM / 50 FPS" : "NTSC SYSTEM / 60 FPS");\r
        }\r
 \r
        strncpy(rom_fname_loaded, rom_fname, sizeof(rom_fname_loaded)-1);\r
@@ -525,10 +601,10 @@ int emu_reload_rom(char *rom_fname)
 \r
        return 1;\r
 \r
-fail2:\r
-       menu_romload_end();\r
 fail:\r
-       if (rom != NULL) pm_close(rom);\r
+       if (rom_data)\r
+               free(rom_data);\r
+       menu_romload_end();\r
        return 0;\r
 }\r
 \r