sms, add sg-1000 support

This commit is contained in:
kub 2022-02-28 21:45:50 +00:00
parent 216c9f17fa
commit df6c895c5c
9 changed files with 72 additions and 41 deletions

View file

@ -313,10 +313,13 @@ enum media_type_e PicoLoadMedia(const char *filename,
rom_data = NULL; // now belongs to PicoCart rom_data = NULL; // now belongs to PicoCart
// simple test for GG. Do this here since m.hardware is nulled in Insert // simple test for GG. Do this here since m.hardware is nulled in Insert
if (PicoIn.AHW & PAHW_SMS) { if ((PicoIn.AHW & PAHW_SMS) && !PicoIn.hwSelect) {
if (!strcmp(rom->ext,"gg") && !PicoIn.hwSelect) { if (!strcmp(rom->ext,"gg")) {
Pico.m.hardware |= 0x1; Pico.m.hardware |= PMS_HW_GG;
lprintf("detected GG ROM\n"); lprintf("detected GG ROM\n");
} else if (!strcmp(rom->ext,"sg")) {
Pico.m.hardware |= PMS_HW_SG;
lprintf("detected SG-1000 ROM\n");
} else } else
lprintf("detected SMS ROM\n"); lprintf("detected SMS ROM\n");
} }

View file

@ -163,7 +163,7 @@ static void ParseSpritesM4(int scanline)
if (pv->reg[0] & 8) if (pv->reg[0] & 8)
xoff = 0; xoff = 0;
xoff += line_offset; 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 xoff -= 48; // GG LCD, adjust to center 160 px
sat = (u8 *)PicoMem.vram + ((pv->reg[5] & 0x7e) << 7); sat = (u8 *)PicoMem.vram + ((pv->reg[5] & 0x7e) << 7);
@ -302,7 +302,7 @@ static void DrawDisplayM4(int scanline)
// tiles // tiles
if (!(pv->debug_p & PVD_KILL_B)) { 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 // on GG render only the center 160 px
DrawStripM4(nametab , dx | ((cells-12)<< 16),(tilex+6) | (ty << 16)); DrawStripM4(nametab , dx | ((cells-12)<< 16),(tilex+6) | (ty << 16));
} else if (pv->reg[0] & 0x80) { } else if (pv->reg[0] & 0x80) {
@ -318,7 +318,7 @@ static void DrawDisplayM4(int scanline)
if (!(pv->debug_p & PVD_KILL_S_LO)) if (!(pv->debug_p & PVD_KILL_S_LO))
DrawSpritesM4(); 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 // first column masked with background, caculate offset to start of line
dx = (dx&~0x1f) / 4; dx = (dx&~0x1f) / 4;
ty = ((pv->reg[7]&0x0f)|0x10) * 0x01010101; ty = ((pv->reg[7]&0x0f)|0x10) * 0x01010101;
@ -736,11 +736,11 @@ void PicoFrameStartSMS(void)
} }
// Copy LCD enable flag for easier handling // Copy LCD enable flag for easier handling
Pico.m.hardware &= ~0x2; Pico.m.hardware &= ~PMS_HW_LCD;
if (PicoIn.opt & POPT_EN_GG_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 // GG LCD always has 160x144 regardless of settings
screen_offset = 24; // nonetheless the vdp timing has 224 lines screen_offset = 24; // nonetheless the vdp timing has 224 lines
loffs = 48; loffs = 48;
@ -796,7 +796,7 @@ void PicoLineSMS(int line)
unsigned bgcolor; unsigned bgcolor;
// GG LCD, render only visible part of screen // 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; goto norender;
if (PicoScanBegin != NULL && skip == 0) if (PicoScanBegin != NULL && skip == 0)
@ -832,12 +832,10 @@ norender:
/* Palette for TMS9918 mode, see https://www.smspower.org/Development/Palette */ /* Palette for TMS9918 mode, see https://www.smspower.org/Development/Palette */
// RGB values: #000000 #000000 #21c842 #5edc78 #5455ed #7d76fc #d4524d #42ebf5 // RGB values: #000000 #000000 #21c842 #5edc78 #5455ed #7d76fc #d4524d #42ebf5
// #fc5554 #ff7978 #d4c154 #e6ce80 #21b03b #c95bba #cccccc #ffffff // #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] = { static u16 tmspal[32] = {
// SMS palette // SMS palette
// 0x0000, 0x0000, 0x00a0, 0x00f0, 0x0a00, 0x0f00, 0x0005, 0x0ff0, 0x0000, 0x0000, 0x00a0, 0x00f0, 0x0a00, 0x0f00, 0x0005, 0x0ff0,
// 0x000a, 0x000f, 0x0055, 0x00ff, 0x0050, 0x0f0f, 0x0555, 0x0fff, 0x000a, 0x000f, 0x0055, 0x00ff, 0x0050, 0x0f0f, 0x0555, 0x0fff,
// GG palette // GG palette
0x0000, 0x0000, 0x04c2, 0x07d6, 0x0e55, 0x0f77, 0x055d, 0x0ee4, 0x0000, 0x0000, 0x04c2, 0x07d6, 0x0e55, 0x0f77, 0x055d, 0x0ee4,
0x055f, 0x077f, 0x05bd, 0x08ce, 0x04a2, 0x0b5c, 0x0ccc, 0x0fff, 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, /* 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 */ * hence GG/SMS/TMS can all be handled the same here */
for (j = cnt; j > 0; j--) { for (j = cnt; j > 0; j--) {
if (!(Pico.video.reg[0] & 0x4)) if (!(Pico.video.reg[0] & 0x4)) // fixed palette in TMS modes
spal = (u32 *)tmspal; // 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++) { for (i = 0x20/2; i > 0; i--, spal++, dpal++) {
t = *spal; t = *spal;
#if defined(USE_BGR555) #if defined(USE_BGR555)

View file

@ -86,7 +86,7 @@ extern void *p32x_bios_g, *p32x_bios_m, *p32x_bios_s;
#define PHWS_AUTO 0 #define PHWS_AUTO 0
#define PHWS_GG 1 #define PHWS_GG 1
#define PHWS_SMS 2 #define PHWS_SMS 2
#define PHWS_SG1000 3 #define PHWS_SG 3
#define PQUIRK_FORCE_6BTN (1<<0) #define PQUIRK_FORCE_6BTN (1<<0)

View file

@ -368,7 +368,8 @@ struct PicoMS
unsigned char vdp_buffer; unsigned char vdp_buffer;
unsigned char vdp_hlatch; unsigned char vdp_hlatch;
unsigned char io_gg[0x08]; unsigned char io_gg[0x08];
unsigned char pad[0x42]; unsigned char mapcnt;
unsigned char pad[0x41];
}; };
// emu state and data for the asm code // emu state and data for the asm code

View file

@ -346,7 +346,7 @@ static void write_bank_msx(unsigned short a, unsigned char d)
{ {
if (a > 0x0003) return; if (a > 0x0003) return;
// don't detect linear mapping to avoid confusing with Codemasters // 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()); elprintf(EL_Z80BNK, "bank msx %04x %02x @ %04x", a, d, z80_pc());
Pico.ms.mapper = PMS_MAP_MSX; Pico.ms.mapper = PMS_MAP_MSX;
Pico.ms.carthw[a] = d; 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 // SG-1000 8KB RAM Adaptor mapper. 8KB RAM at address 0x2000
static void write_bank_x8k(unsigned short a, unsigned char d) 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; 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) return;
if (Pico.ms.mapper != PMS_MAP_8KBRAM && (Pico.ms.mapper || !(Pico.m.hardware & PMS_HW_SG))) return;
elprintf(EL_Z80BNK, "bank x8k %04x %02x @ %04x", a, d, z80_pc()); 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; Pico.ms.mapper = PMS_MAP_8KBRAM;
((unsigned char *)PicoMem.vram)[(a&0x1fff)+0x8000] = d;
a &= 0xe000; 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_read_map, a, a+0x1fff, PicoMem.vram+0x4000, 0);
z80_map_set(z80_write_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. // TODO auto-selecting is not really reliable.
// Before adding more mappers this should be revised. // Before adding more mappers this should be revised.
static void xwrite(unsigned int a, unsigned char d) 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_8KBRAM: write_bank_x8k(a, d); break;
case PMS_MAP_AUTO: 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 // NB the sequence of mappers is crucial for the auto detection
write_bank_x8k(a, d); if (Pico.m.hardware & PMS_HW_SG)
write_bank_n32k(a, d); write_bank_x8k(a, d);
write_bank_sega(a, d); else {
write_bank_msx(a, d); write_bank_n32k(a, d);
write_bank_codem(a, d); write_bank_sega(a, d);
write_bank_korea(a, d); write_bank_msx(a, d);
write_bank_n16k(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; break;
} }
} }
@ -520,23 +542,23 @@ void PicoResetMS(void)
// set preselected hw/mapper from config // set preselected hw/mapper from config
if (PicoIn.hwSelect) { if (PicoIn.hwSelect) {
Pico.m.hardware &= ~(PMS_HW_GG|PMS_HW_SG);
switch (PicoIn.hwSelect) { switch (PicoIn.hwSelect) {
case PHWS_GG: Pico.m.hardware |= PMS_HW_GG; break; 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) if (PicoIn.mapper)
Pico.ms.mapper = 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_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 // check if the ROM header contains more system information
for (tmr = 0x2000; tmr < 0xbfff && tmr <= Pico.romsize; tmr *= 2) { for (tmr = 0x2000; tmr < 0xbfff && tmr <= Pico.romsize; tmr *= 2) {
if (!memcmp(Pico.rom + tmr-16, "TMR SEGA", 8)) { if (!memcmp(Pico.rom + tmr-16, "TMR SEGA", 8)) {
Pico.m.hardware &= ~PMS_HW_SG; // not SG-1000
hw = Pico.rom[tmr-1] >> 4; hw = Pico.rom[tmr-1] >> 4;
if (!PicoIn.hwSelect) { if (!PicoIn.hwSelect) {
Pico.m.hardware &= ~PMS_HW_GG; Pico.m.hardware &= ~(PMS_HW_GG|PMS_HW_SG);
if (hw >= 0x5 && hw < 0x8) if (hw >= 0x5 && hw < 0x8)
Pico.m.hardware |= PMS_HW_GG; // GG cartridge detected Pico.m.hardware |= PMS_HW_GG; // GG cartridge detected
} }
@ -647,19 +669,21 @@ void PicoMemSetupMS(void)
xwrite(0x0000, 0); xwrite(0x0000, 0);
xwrite(0x4000, 1); xwrite(0x4000, 1);
xwrite(0x8000, 2); xwrite(0x8000, 2);
} else { } else if (mapper) {
xwrite(0xfffc, 0); xwrite(0xfffc, 0);
xwrite(0xfffd, 0); xwrite(0xfffd, 0);
xwrite(0xfffe, 1); xwrite(0xfffe, 1);
xwrite(0xffff, 2); xwrite(0xffff, 2);
} }
Pico.ms.mapper = mapper;
} }
void PicoStateLoadedMS(void) void PicoStateLoadedMS(void)
{ {
u8 mapper = Pico.ms.mapper; 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(0x0000, Pico.ms.carthw[0]);
xwrite(0x0001, Pico.ms.carthw[1]); xwrite(0x0001, Pico.ms.carthw[1]);
xwrite(0x0002, Pico.ms.carthw[2]); xwrite(0x0002, Pico.ms.carthw[2]);

View file

@ -332,9 +332,11 @@ static void system_announce(void)
if (PicoIn.AHW & PAHW_SMS) { if (PicoIn.AHW & PAHW_SMS) {
sys_name = "Master System"; sys_name = "Master System";
if (Pico.m.hardware & 0x1) if (Pico.m.hardware & PMS_HW_GG)
sys_name = "Game Gear"; sys_name = "Game Gear";
else if (Pico.m.hardware & 0x4) else if (Pico.m.hardware & PMS_HW_SG)
sys_name = "SG-1000";
else if (Pico.m.hardware & PMS_HW_JAP)
sys_name = "Mark III"; sys_name = "Mark III";
#ifdef NO_SMS #ifdef NO_SMS
extra = " [no support]"; extra = " [no support]";

View file

@ -536,7 +536,7 @@ static int menu_loop_32x_options(int id, int keys)
#ifndef NO_SMS #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 *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"; static const char h_smsfm[] = "FM sound is only supported by few games\nOther games may crash with FM enabled";

View file

@ -1494,6 +1494,8 @@ static void update_variables(bool first_run)
PicoIn.hwSelect = PHWS_AUTO; PicoIn.hwSelect = PHWS_AUTO;
else if (strcmp(var.value, "Game Gear") == 0) else if (strcmp(var.value, "Game Gear") == 0)
PicoIn.hwSelect = PHWS_GG; PicoIn.hwSelect = PHWS_GG;
else if (strcmp(var.value, "SG-1000") == 0)
PicoIn.hwSelect = PHWS_SG;
else else
PicoIn.hwSelect = PHWS_SMS; PicoIn.hwSelect = PHWS_SMS;
} }
@ -1527,7 +1529,7 @@ static void update_variables(bool first_run)
else if (strcmp(var.value, "Korea Nemesis") == 0) else if (strcmp(var.value, "Korea Nemesis") == 0)
PicoIn.mapper = PMS_MAP_NEMESIS; PicoIn.mapper = PMS_MAP_NEMESIS;
else if (strcmp(var.value, "Taiwan 8K RAM") == 0) else if (strcmp(var.value, "Taiwan 8K RAM") == 0)
PicoIn.mapper = PMS_MAP_8KRAM; PicoIn.mapper = PMS_MAP_8KBRAM;
else else
PicoIn.mapper = PMS_MAP_SEGA; PicoIn.mapper = PMS_MAP_SEGA;
} }

View file

@ -117,6 +117,7 @@ struct retro_core_option_v2_definition option_defs_us[] = {
{ "Auto", NULL }, { "Auto", NULL },
{ "Game Gear", NULL }, { "Game Gear", NULL },
{ "Master System", NULL }, { "Master System", NULL },
{ "SG-1000" , NULL },
{ NULL, NULL }, { NULL, NULL },
}, },
"Auto" "Auto"