sms, add sg-1000 support
authorkub <derkub@gmail.com>
Mon, 28 Feb 2022 21:45:50 +0000 (21:45 +0000)
committerkub <derkub@gmail.com>
Mon, 28 Feb 2022 21:45:50 +0000 (21:45 +0000)
pico/media.c
pico/mode4.c
pico/pico.h
pico/pico_int.h
pico/sms.c
platform/common/emu.c
platform/common/menu_pico.c
platform/libretro/libretro.c
platform/libretro/libretro_core_options.h

index ae878f9..9bdb637 100644 (file)
@@ -313,10 +313,13 @@ enum media_type_e PicoLoadMedia(const char *filename,
   rom_data = NULL; // now belongs to PicoCart
 
   // simple test for GG. Do this here since m.hardware is nulled in Insert
-  if (PicoIn.AHW & PAHW_SMS) {
-    if (!strcmp(rom->ext,"gg") && !PicoIn.hwSelect) {
-      Pico.m.hardware |= 0x1;
+  if ((PicoIn.AHW & PAHW_SMS) && !PicoIn.hwSelect) {
+    if (!strcmp(rom->ext,"gg")) {
+      Pico.m.hardware |= PMS_HW_GG;
       lprintf("detected GG ROM\n");
+    } else if (!strcmp(rom->ext,"sg")) {
+      Pico.m.hardware |= PMS_HW_SG;
+      lprintf("detected SG-1000 ROM\n");
     } else
       lprintf("detected SMS ROM\n");
   }
index 6cabd38..21bd95b 100644 (file)
@@ -163,7 +163,7 @@ static void ParseSpritesM4(int scanline)
   if (pv->reg[0] & 8)
     xoff = 0;
   xoff += line_offset;
-  if ((Pico.m.hardware & 0x3) == 0x3)
+  if ((Pico.m.hardware & (PMS_HW_GG|PMS_HW_LCD)) == (PMS_HW_GG|PMS_HW_LCD))
     xoff -= 48; // GG LCD, adjust to center 160 px
 
   sat = (u8 *)PicoMem.vram + ((pv->reg[5] & 0x7e) << 7);
@@ -302,7 +302,7 @@ static void DrawDisplayM4(int scanline)
 
   // tiles
   if (!(pv->debug_p & PVD_KILL_B)) {
-    if ((Pico.m.hardware & 0x3) == 0x3) {
+    if ((Pico.m.hardware & (PMS_HW_GG|PMS_HW_LCD)) == (PMS_HW_GG|PMS_HW_LCD)) {
       // on GG render only the center 160 px
       DrawStripM4(nametab , dx | ((cells-12)<< 16),(tilex+6) | (ty  << 16));
     } else if (pv->reg[0] & 0x80) {
@@ -318,7 +318,7 @@ static void DrawDisplayM4(int scanline)
   if (!(pv->debug_p & PVD_KILL_S_LO))
     DrawSpritesM4();
 
-  if ((pv->reg[0] & 0x20) && (Pico.m.hardware & 0x3) != 0x3) {
+  if ((pv->reg[0] & 0x20) && (Pico.m.hardware & (PMS_HW_GG|PMS_HW_LCD)) != (PMS_HW_GG|PMS_HW_LCD)) {
     // first column masked with background, caculate offset to start of line
     dx = (dx&~0x1f) / 4;
     ty = ((pv->reg[7]&0x0f)|0x10) * 0x01010101;
@@ -736,11 +736,11 @@ void PicoFrameStartSMS(void)
   }
 
   // Copy LCD enable flag for easier handling
-  Pico.m.hardware &= ~0x2;
+  Pico.m.hardware &= ~PMS_HW_LCD;
   if (PicoIn.opt & POPT_EN_GG_LCD)
-    Pico.m.hardware |= 0x2;
+    Pico.m.hardware |= PMS_HW_LCD;
 
-  if ((Pico.m.hardware & 0x3) == 0x3) {
+  if ((Pico.m.hardware & (PMS_HW_GG|PMS_HW_LCD)) == (PMS_HW_GG|PMS_HW_LCD)) {
     // GG LCD always has 160x144 regardless of settings
     screen_offset = 24; // nonetheless the vdp timing has 224 lines
     loffs = 48;
@@ -796,7 +796,7 @@ void PicoLineSMS(int line)
   unsigned bgcolor;
 
   // GG LCD, render only visible part of screen
-  if ((Pico.m.hardware & 0x3) == 0x3 && (line < 24 || line >= 24+144))
+  if ((Pico.m.hardware & (PMS_HW_GG|PMS_HW_LCD)) == (PMS_HW_GG|PMS_HW_LCD) && (line < 24 || line >= 24+144))
     goto norender;
 
   if (PicoScanBegin != NULL && skip == 0)
@@ -832,12 +832,10 @@ norender:
 /* Palette for TMS9918 mode, see https://www.smspower.org/Development/Palette */
 // RGB values: #000000 #000000 #21c842 #5edc78 #5455ed #7d76fc #d4524d #42ebf5
 //             #fc5554 #ff7978 #d4c154 #e6ce80 #21b03b #c95bba #cccccc #ffffff
-// 00   11   22   33   44   55   66   77   88   99   aa   bb   cc   dd   ee   ff
-// 0007 0818 1929 2a3a 3b4b 4c5c 5d6d 6e7e 7f8f 90a0 a1b1 b2c2 c3d3 d4e4 e5f5 f6
 static u16 tmspal[32] = {
   // SMS palette
-//  0x0000, 0x0000, 0x00a0, 0x00f0, 0x0a00, 0x0f00, 0x0005, 0x0ff0,
-//  0x000a, 0x000f, 0x0055, 0x00ff, 0x0050, 0x0f0f, 0x0555, 0x0fff,
+  0x0000, 0x0000, 0x00a0, 0x00f0, 0x0a00, 0x0f00, 0x0005, 0x0ff0,
+  0x000a, 0x000f, 0x0055, 0x00ff, 0x0050, 0x0f0f, 0x0555, 0x0fff,
   // GG palette
   0x0000, 0x0000, 0x04c2, 0x07d6, 0x0e55, 0x0f77, 0x055d, 0x0ee4,
   0x055f, 0x077f, 0x05bd, 0x08ce, 0x04a2, 0x0b5c, 0x0ccc, 0x0fff,
@@ -861,8 +859,8 @@ void PicoDoHighPal555SMS(void)
   /* SMS 6 bit cram data was already converted to MD/GG format by vdp write,
    * hence GG/SMS/TMS can all be handled the same here */
   for (j = cnt; j > 0; j--) {
-    if (!(Pico.video.reg[0] & 0x4))
-      spal = (u32 *)tmspal; // fixed palette in TMS modes
+    if (!(Pico.video.reg[0] & 0x4)) // fixed palette in TMS modes
+      spal = (u32 *)tmspal + (Pico.m.hardware & PMS_HW_SG ? 16/2 : 0);
     for (i = 0x20/2; i > 0; i--, spal++, dpal++) { 
       t = *spal;
 #if defined(USE_BGR555)
index 162a9bf..dc59679 100644 (file)
@@ -86,7 +86,7 @@ extern void *p32x_bios_g, *p32x_bios_m, *p32x_bios_s;
 #define PHWS_AUTO   0\r
 #define PHWS_GG     1\r
 #define PHWS_SMS    2\r
-#define PHWS_SG1000 3\r
+#define PHWS_SG     3\r
 \r
 #define PQUIRK_FORCE_6BTN   (1<<0)\r
 \r
index 15d3516..85df6c5 100644 (file)
@@ -368,7 +368,8 @@ struct PicoMS
   unsigned char vdp_buffer;\r
   unsigned char vdp_hlatch;\r
   unsigned char io_gg[0x08];\r
-  unsigned char pad[0x42];\r
+  unsigned char mapcnt;\r
+  unsigned char pad[0x41];\r
 };\r
 \r
 // emu state and data for the asm code\r
index c045d61..6f1cfc3 100644 (file)
@@ -346,7 +346,7 @@ static void write_bank_msx(unsigned short a, unsigned char d)
 {
   if (a > 0x0003) return;
   // don't detect linear mapping to avoid confusing with Codemasters
-  if (Pico.ms.mapper != PMS_MAP_MSX && (Pico.ms.mapper || (a|d) == 0)) return;
+  if (Pico.ms.mapper != PMS_MAP_MSX && (Pico.ms.mapper || (a|d) == 0 || d >= 0x80)) return;
   elprintf(EL_Z80BNK, "bank msx %04x %02x @ %04x", a, d, z80_pc());
   Pico.ms.mapper = PMS_MAP_MSX;
   Pico.ms.carthw[a] = d;
@@ -457,19 +457,32 @@ static void write_bank_jang(unsigned short a, unsigned char d)
 // SG-1000 8KB RAM Adaptor mapper. 8KB RAM at address 0x2000
 static void write_bank_x8k(unsigned short a, unsigned char d)
 {
-  // 8KB address range @ 0x2000
+  // 8KB address range @ 0x2000 (adaptor) or @ 0x8000 (cartridge)
   if ((a&0xe000) != 0x2000 && (a&0xe000) != 0x8000) return;
-  // this is only available on SG-1000
-  if (Pico.ms.mapper != PMS_MAP_8KBRAM && (Pico.ms.mapper || !(Pico.m.hardware & PMS_HW_SG))) return;
+  if (Pico.ms.mapper != PMS_MAP_8KBRAM && Pico.ms.mapper) return;
+
   elprintf(EL_Z80BNK, "bank x8k %04x %02x @ %04x", a, d, z80_pc());
+  ((unsigned char *)PicoMem.vram)[(a&0x1fff)+0x8000] = d;
   Pico.ms.mapper = PMS_MAP_8KBRAM;
 
-  ((unsigned char *)PicoMem.vram)[(a&0x1fff)+0x8000] = d;
   a &= 0xe000;
+  Pico.ms.carthw[0] = a >> 12;
   z80_map_set(z80_read_map,  a, a+0x1fff, PicoMem.vram+0x4000, 0);
   z80_map_set(z80_write_map, a, a+0x1fff, PicoMem.vram+0x4000, 0);
 }
 
+char *mappers[] = {
+  [PMS_MAP_SEGA]     = "Sega",
+  [PMS_MAP_CODEM]    = "Codemasters",
+  [PMS_MAP_KOREA]    = "Korea",
+  [PMS_MAP_MSX]      = "Korea MSX",
+  [PMS_MAP_N32K]     = "Korea X-in-1",
+  [PMS_MAP_N16K]     = "Korea 4-Pak",
+  [PMS_MAP_JANGGUN]  = "Korea Janggun",
+  [PMS_MAP_NEMESIS]  = "Korea Nemesis",
+  [PMS_MAP_8KBRAM]   = "Taiwan 8K RAM",
+};
+
 // TODO auto-selecting is not really reliable.
 // Before adding more mappers this should be revised.
 static void xwrite(unsigned int a, unsigned char d)
@@ -490,14 +503,23 @@ static void xwrite(unsigned int a, unsigned char d)
   case PMS_MAP_8KBRAM:  write_bank_x8k(a, d);   break;
 
   case PMS_MAP_AUTO:
+        // disable autodetection after some time
+        if ((a >= 0xc000 && a < 0xfff8) || Pico.ms.mapcnt > 20) break;
         // NB the sequence of mappers is crucial for the auto detection
-        write_bank_x8k(a, d);
-        write_bank_n32k(a, d);
-        write_bank_sega(a, d);
-        write_bank_msx(a, d);
-        write_bank_codem(a, d);
-        write_bank_korea(a, d);
-        write_bank_n16k(a, d);
+        if (Pico.m.hardware & PMS_HW_SG)
+          write_bank_x8k(a, d);
+       else {
+          write_bank_n32k(a, d);
+          write_bank_sega(a, d);
+          write_bank_msx(a, d);
+          write_bank_codem(a, d);
+          write_bank_korea(a, d);
+          write_bank_n16k(a, d);
+       }
+
+        Pico.ms.mapcnt ++;
+        if (Pico.ms.mapper)
+          elprintf(EL_STATUS, "autodetected %s mapper",mappers[Pico.ms.mapper]);
         break;
   }
 }
@@ -520,23 +542,23 @@ void PicoResetMS(void)
 
   // set preselected hw/mapper from config
   if (PicoIn.hwSelect) {
+    Pico.m.hardware &= ~(PMS_HW_GG|PMS_HW_SG);
     switch (PicoIn.hwSelect) {
     case PHWS_GG:  Pico.m.hardware |=  PMS_HW_GG; break;
-    default:       Pico.m.hardware &= ~PMS_HW_GG; break;
+    case PHWS_SG:  Pico.m.hardware |=  PMS_HW_SG; break;
     }
   }
+  Pico.ms.mapcnt = Pico.ms.mapper = 0;
   if (PicoIn.mapper)
     Pico.ms.mapper = PicoIn.mapper;
   Pico.m.hardware |= PMS_HW_JAP; // default region Japan if no TMR header
-  Pico.m.hardware |= PMS_HW_SG;  // default to SG-1000 if no TMR header
 
   // check if the ROM header contains more system information
   for (tmr = 0x2000; tmr < 0xbfff && tmr <= Pico.romsize; tmr *= 2) {
     if (!memcmp(Pico.rom + tmr-16, "TMR SEGA", 8)) {
-      Pico.m.hardware &= ~PMS_HW_SG; // not SG-1000
       hw = Pico.rom[tmr-1] >> 4;
       if (!PicoIn.hwSelect) {
-        Pico.m.hardware &= ~PMS_HW_GG;
+        Pico.m.hardware &= ~(PMS_HW_GG|PMS_HW_SG);
         if (hw >= 0x5 && hw < 0x8)
           Pico.m.hardware |= PMS_HW_GG; // GG cartridge detected
       }
@@ -647,19 +669,21 @@ void PicoMemSetupMS(void)
     xwrite(0x0000, 0);
     xwrite(0x4000, 1);
     xwrite(0x8000, 2);
-  } else {
+  } else if (mapper) {
     xwrite(0xfffc, 0);
     xwrite(0xfffd, 0);
     xwrite(0xfffe, 1);
     xwrite(0xffff, 2);
   }
-  Pico.ms.mapper = mapper;
 }
 
 void PicoStateLoadedMS(void)
 {
   u8 mapper = Pico.ms.mapper;
-  if (Pico.ms.mapper == PMS_MAP_MSX || Pico.ms.mapper == PMS_MAP_NEMESIS) {
+  if (Pico.ms.mapper == PMS_MAP_8KBRAM) {
+    u16 a = Pico.ms.carthw[0] << 12;
+    xwrite(a+0x888, *((unsigned char *)PicoMem.vram+0x8888));
+  } else if (Pico.ms.mapper == PMS_MAP_MSX || Pico.ms.mapper == PMS_MAP_NEMESIS) {
     xwrite(0x0000, Pico.ms.carthw[0]);
     xwrite(0x0001, Pico.ms.carthw[1]);
     xwrite(0x0002, Pico.ms.carthw[2]);
index 845951e..b233050 100644 (file)
@@ -332,9 +332,11 @@ static void system_announce(void)
 \r
        if (PicoIn.AHW & PAHW_SMS) {\r
                sys_name = "Master System";\r
-               if (Pico.m.hardware & 0x1)\r
+               if (Pico.m.hardware & PMS_HW_GG)\r
                        sys_name = "Game Gear";\r
-               else if (Pico.m.hardware & 0x4)\r
+               else if (Pico.m.hardware & PMS_HW_SG)\r
+                       sys_name = "SG-1000";\r
+               else if (Pico.m.hardware & PMS_HW_JAP)\r
                        sys_name = "Mark III";\r
 #ifdef NO_SMS\r
                extra = " [no support]";\r
index 00da408..6a72bc2 100644 (file)
@@ -536,7 +536,7 @@ static int menu_loop_32x_options(int id, int keys)
 
 #ifndef NO_SMS
 
-static const char *sms_hardwares[] = { "auto", "Game Gear", "Master System", NULL };
+static const char *sms_hardwares[] = { "auto", "Game Gear", "Master System", "SG-1000", NULL };
 static const char *sms_mappers[] = { "auto", "Sega", "Codemasters", "Korea", "Korea MSX", "Korea X-in-1", "Korea 4-Pak", "Korea Janggun", "Korea Nemesis", "Taiwan 8K RAM", NULL };
 static const char h_smsfm[] = "FM sound is only supported by few games\nOther games may crash with FM enabled";
 
index 4bbcb9d..99fc826 100644 (file)
@@ -1494,6 +1494,8 @@ static void update_variables(bool first_run)
          PicoIn.hwSelect = PHWS_AUTO;
       else if (strcmp(var.value, "Game Gear") == 0)
          PicoIn.hwSelect = PHWS_GG;
+      else if (strcmp(var.value, "SG-1000") == 0)
+         PicoIn.hwSelect = PHWS_SG;
       else
          PicoIn.hwSelect = PHWS_SMS;
    }
@@ -1527,7 +1529,7 @@ static void update_variables(bool first_run)
       else if (strcmp(var.value, "Korea Nemesis") == 0)
          PicoIn.mapper = PMS_MAP_NEMESIS;
       else if (strcmp(var.value, "Taiwan 8K RAM") == 0)
-         PicoIn.mapper = PMS_MAP_8KRAM;
+         PicoIn.mapper = PMS_MAP_8KBRAM;
       else
          PicoIn.mapper = PMS_MAP_SEGA;
    }
index 45edb1c..6e627d4 100644 (file)
@@ -117,6 +117,7 @@ struct retro_core_option_v2_definition option_defs_us[] = {
          { "Auto",          NULL },
          { "Game Gear",     NULL },
          { "Master System", NULL },
+         { "SG-1000"      , NULL },
          { NULL, NULL },
        },
       "Auto"