From 576e14d64c007552897694aefd64fa0e72a7c61a Mon Sep 17 00:00:00 2001 From: clobber Date: Fri, 17 Sep 2021 00:24:44 -0600 Subject: [PATCH] Sync with upstream https://github.com/ekeeke/Genesis-Plus-GX/commit/35ed78cc71f6b2c69b1377c9520416d0253b6633 --- GenesisPlus.xcodeproj/project.pbxproj | 2 + genplusgx_source/cart_hw/areplay.c | 96 +++--- genplusgx_source/cart_hw/areplay.h | 4 +- genplusgx_source/cart_hw/ggenie.c | 29 +- genplusgx_source/cart_hw/ggenie.h | 4 +- genplusgx_source/cart_hw/md_cart.c | 199 +++++++----- genplusgx_source/cart_hw/md_cart.h | 6 +- genplusgx_source/cart_hw/sms_cart.c | 12 +- genplusgx_source/cart_hw/sms_cart.h | 2 +- genplusgx_source/cart_hw/sram.c | 9 +- genplusgx_source/cart_hw/sram.h | 4 +- genplusgx_source/cd_hw/cd_cart.c | 3 +- genplusgx_source/cd_hw/cd_cart.h | 4 +- genplusgx_source/cd_hw/cdd.c | 43 ++- genplusgx_source/cd_hw/libchdr/src/chd.c | 65 ++-- genplusgx_source/cd_hw/scd.c | 15 +- genplusgx_source/sound/ym2413.c | 374 +++++++++++++++-------- genplusgx_source/sound/ym2612.c | 7 +- genplusgx_source/sound/ym3438.c | 106 ++++--- genplusgx_source/sound/ym3438.h | 26 +- 20 files changed, 612 insertions(+), 398 deletions(-) diff --git a/GenesisPlus.xcodeproj/project.pbxproj b/GenesisPlus.xcodeproj/project.pbxproj index 9fe3be8..f73f98e 100644 --- a/GenesisPlus.xcodeproj/project.pbxproj +++ b/GenesisPlus.xcodeproj/project.pbxproj @@ -733,6 +733,7 @@ OTHER_CFLAGS = ( "-DLSB_FIRST", "-DUSE_32BPP_RENDERING", + "-DMAXROMSIZE=33554432", ); PRODUCT_BUNDLE_IDENTIFIER = "org.openemu.${PRODUCT_NAME:identifier}"; PRODUCT_NAME = GenesisPlus; @@ -753,6 +754,7 @@ OTHER_CFLAGS = ( "-DLSB_FIRST", "-DUSE_32BPP_RENDERING", + "-DMAXROMSIZE=33554432", ); PRODUCT_BUNDLE_IDENTIFIER = "org.openemu.${PRODUCT_NAME:identifier}"; PRODUCT_NAME = GenesisPlus; diff --git a/genplusgx_source/cart_hw/areplay.c b/genplusgx_source/cart_hw/areplay.c index 73b16a4..1b99a70 100644 --- a/genplusgx_source/cart_hw/areplay.c +++ b/genplusgx_source/cart_hw/areplay.c @@ -1,8 +1,8 @@ /**************************************************************************** * Genesis Plus - * Action Replay / Pro Action Replay emulation + * Action Replay / Pro Action Replay hardware support * - * Copyright (C) 2009-2014 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2009-2021 Eke-Eke (Genesis Plus GX) * * Redistribution and use of this code or any derivative works are permitted * provided that the following conditions are met: @@ -45,8 +45,7 @@ static struct { uint8 enabled; uint8 status; - uint8 *rom; - uint8 *ram; + uint8 ram[0x10000]; uint16 regs[13]; uint16 old[4]; uint16 data[4]; @@ -54,64 +53,52 @@ static struct } action_replay; static void ar_write_regs(uint32 address, uint32 data); -static void ar_write_regs_2(uint32 address, uint32 data); +static void ar2_write_reg(uint32 address, uint32 data); static void ar_write_ram_8(uint32 address, uint32 data); void areplay_init(void) { - int size; - - memset(&action_replay,0,sizeof(action_replay)); + action_replay.enabled = action_replay.status = 0; - /* store Action replay ROM (max. 128k) & RAM (64k) above cartridge ROM + SRAM area */ - if (cart.romsize > 0x810000) return; - action_replay.rom = cart.rom + 0x810000; - action_replay.ram = cart.rom + 0x830000; - - /* try to load Action Replay ROM file */ - size = load_archive(AR_ROM, action_replay.rom, 0x20000, NULL); - - /* detect Action Replay board type */ - switch (size) + /* try to load Action Replay ROM file (max. 64KB) */ + if (load_archive(AR_ROM, cart.lockrom, 0x10000, NULL) > 0) { - case 0x8000: + /* detect Action Replay board type */ + if (!memcmp(cart.lockrom + 0x120, "ACTION REPLAY ", 16)) { - if (!memcmp(action_replay.rom + 0x120, "ACTION REPLAY ", 16)) - { - /* normal Action Replay (32K) */ - action_replay.enabled = TYPE_AR; - - /* internal registers mapped at $010000-$01ffff */ - m68k.memory_map[0x01].write16 = ar_write_regs; - break; - } - } + /* normal Action Replay (32KB ROM) */ + action_replay.enabled = TYPE_AR; - case 0x10000: - case 0x20000: + /* $0000-$7fff mirrored into $8000-$ffff */ + memcpy(cart.lockrom + 0x8000, cart.lockrom, 0x8000); + + /* internal registers mapped at $010000-$01ffff */ + m68k.memory_map[0x01].write16 = ar_write_regs; + } + else { /* Read stack pointer MSB */ - uint8 sp = READ_BYTE(action_replay.rom, 0x01); + uint8 sp = cart.lockrom[0x01]; /* Detect board version */ - if ((sp == 0x42) && !memcmp(action_replay.rom + 0x120, "ACTION REPLAY 2 ", 16)) + if ((sp == 0x42) && !memcmp(cart.lockrom + 0x120, "ACTION REPLAY 2 ", 16)) { - /* PRO Action Replay 1 (64/128K) */ + /* PRO Action Replay (2x32KB ROM) */ action_replay.enabled = TYPE_PRO1; /* internal registers mapped at $010000-$01ffff */ m68k.memory_map[0x01].write16 = ar_write_regs; } - else if ((sp == 0x60) && !memcmp(action_replay.rom + 0x3c6, "ACTION REPLAY II", 16)) + else if ((sp == 0x60) && !memcmp(cart.lockrom + 0x3c6, "ACTION REPLAY II", 16)) { - /* PRO Action Replay 2 (64K) */ + /* PRO Action Replay 2 (2x32KB ROM) */ action_replay.enabled = TYPE_PRO2; - /* internal registers mapped at $100000-$10ffff */ - m68k.memory_map[0x10].write16 = ar_write_regs_2; + /* internal register mapped at $100000-$10ffff */ + m68k.memory_map[0x10].write16 = ar2_write_reg; } - /* internal RAM (64k), mapped at $420000-$42ffff or $600000-$60ffff */ + /* internal RAM (64KB), mapped at $420000-$42ffff or $600000-$60ffff */ if (action_replay.enabled) { m68k.memory_map[sp].base = action_replay.ram; @@ -120,28 +107,22 @@ void areplay_init(void) m68k.memory_map[sp].write8 = ar_write_ram_8; m68k.memory_map[sp].write16 = NULL; } - break; } - default: - { - break; - } - } - #ifdef LSB_FIRST - if (action_replay.enabled) - { - int i; - for (i= 0; i 0x810000) return; - ggenie.rom = cart.rom + 0x810000; - - /* Try to load Game Genie ROM file */ - if (load_archive(GG_ROM, ggenie.rom, 0x8000, NULL) > 0) + /* Try to load Game Genie ROM file (32KB) */ + if (load_archive(GG_ROM, cart.lockrom, 0x8000, NULL) > 0) { #ifdef LSB_FIRST int i; for (i=0; i<0x8000; i+=2) { /* Byteswap ROM */ - uint8 temp = ggenie.rom[i]; - ggenie.rom[i] = ggenie.rom[i+1]; - ggenie.rom[i+1] = temp; + uint8 temp = cart.lockrom[i]; + cart.lockrom[i] = cart.lockrom[i+1]; + cart.lockrom[i+1] = temp; } #endif /* $0000-$7fff mirrored into $8000-$ffff */ - memcpy(ggenie.rom + 0x8000, ggenie.rom, 0x8000); + memcpy(cart.lockrom + 0x8000, cart.lockrom, 0x8000); /* Game Genie hardware is enabled */ ggenie.enabled = 1; @@ -113,7 +108,7 @@ void ggenie_reset(int hard) } /* Game Genie ROM is mapped at $000000-$007fff */ - m68k.memory_map[0].base = ggenie.rom; + m68k.memory_map[0].base = cart.lockrom; /* Internal registers are mapped at $000000-$00001f */ m68k.memory_map[0].write8 = ggenie_write_byte; @@ -214,7 +209,7 @@ static void ggenie_write_regs(unsigned int offset, unsigned int data) else { /* $0000-$7ffff reads mapped to Game Genie ROM */ - m68k.memory_map[0].base = ggenie.rom; + m68k.memory_map[0].base = cart.lockrom; m68k.memory_map[0].read8 = NULL; m68k.memory_map[0].read16 = NULL; diff --git a/genplusgx_source/cart_hw/ggenie.h b/genplusgx_source/cart_hw/ggenie.h index a67f007..0e36ff9 100644 --- a/genplusgx_source/cart_hw/ggenie.h +++ b/genplusgx_source/cart_hw/ggenie.h @@ -1,8 +1,8 @@ /**************************************************************************** * Genesis Plus - * Game Genie Hardware emulation + * Game Genie hardware support * - * Copyright (C) 2009-2014 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2009-2021 Eke-Eke (Genesis Plus GX) * * Based on documentation from Charles McDonald * (http://cgfm2.emuviews.com/txt/genie.txt) diff --git a/genplusgx_source/cart_hw/md_cart.c b/genplusgx_source/cart_hw/md_cart.c index 3a4f567..6ff9e9f 100644 --- a/genplusgx_source/cart_hw/md_cart.c +++ b/genplusgx_source/cart_hw/md_cart.c @@ -2,7 +2,7 @@ * Genesis Plus * Mega Drive cartridge hardware support * - * Copyright (C) 2007-2020 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2007-2021 Eke-Eke (Genesis Plus GX) * * Many cartridge protections were initially documented by Haze * (http://haze.mameworld.info/) @@ -79,6 +79,7 @@ static void mapper_256k_multi_w(uint32 address, uint32 data); static void mapper_wd1601_w(uint32 address, uint32 data); static uint32 mapper_64k_radica_r(uint32 address); static uint32 mapper_128k_radica_r(uint32 address); +static void mapper_sr16v1_w(uint32 address, uint32 data); static void default_time_w(uint32 address, uint32 data); static void default_regs_w(uint32 address, uint32 data); static uint32 default_regs_r(uint32 address); @@ -227,6 +228,12 @@ static const md_entry_t rom_database[] = {0x0000,0xd0a0,0x48,0x4f,{{0x00,0x00,0xaa,0xf0},{0xffffff,0xffffff,0xfc0000,0xfc0000},{0x000000,0x000000,0x480000,0x4c0000},0,0,NULL,NULL,default_regs_r,NULL}}, +/* Rock Heaven */ + {0x6cca,0x2395,0x50,0x50,{{0x50,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x500008,0x000000,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,NULL}}, +/* Rock World */ + {0x3547,0xa3da,0x50,0x50,{{0x50,0xa0,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x500008,0x500208,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,NULL}}, + + /* Rockman X3 (bootleg version ? two last register returned values are ignored, note that 0xaa/0x18 would work as well) */ {0x0000,0x9d0e,0x40,0x40,{{0x0c,0x00,0xc9,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0x000000,0x400004,0x400006},0,0,default_regs_r,NULL,default_regs_r,NULL}}, @@ -441,84 +448,11 @@ void md_cart_init(void) SVP CHIP ***********************************************/ svp = NULL; - if (strstr(rominfo.international,"Virtua Racing")) + if ((READ_BYTE(cart.rom, 0x1c8) == 'S') && (READ_BYTE(cart.rom, 0x1c9) == 'V')) { svp_init(); } - /********************************************** - LOCK-ON - ***********************************************/ - - /* clear existing patches */ - ggenie_shutdown(); - areplay_shutdown(); - - /* initialize extra hardware */ - switch (config.lock_on) - { - case TYPE_GG: - { - ggenie_init(); - break; - } - - case TYPE_AR: - { - areplay_init(); - break; - } - - case TYPE_SK: - { - /* store S&K ROM above cartridge ROM (and before backup memory) */ - if (cart.romsize > 0x600000) break; - - /* try to load Sonic & Knuckles ROM file (2 MB) */ - if (load_archive(SK_ROM, cart.rom + 0x600000, 0x200000, NULL) == 0x200000) - { - /* check ROM header */ - if (!memcmp(cart.rom + 0x600000 + 0x120, "SONIC & KNUCKLES",16)) - { - /* try to load Sonic 2 & Knuckles UPMEM ROM (256 KB) */ - if (load_archive(SK_UPMEM, cart.rom + 0x900000, 0x40000, NULL) == 0x40000) - { - /* $000000-$1FFFFF is mapped to S&K ROM */ - for (i=0x00; i<0x20; i++) - { - m68k.memory_map[i].base = cart.rom + 0x600000 + (i << 16); - } - -#ifdef LSB_FIRST - for (i=0; i<0x200000; i+=2) - { - /* Byteswap ROM */ - uint8 temp = cart.rom[i + 0x600000]; - cart.rom[i + 0x600000] = cart.rom[i + 0x600000 + 1]; - cart.rom[i + 0x600000 + 1] = temp; - } - - for (i=0; i<0x40000; i+=2) - { - /* Byteswap ROM */ - uint8 temp = cart.rom[i + 0x900000]; - cart.rom[i + 0x900000] = cart.rom[i + 0x900000 + 1]; - cart.rom[i + 0x900000 + 1] = temp; - } -#endif - cart.special |= HW_LOCK_ON; - } - } - } - break; - } - - default: - { - break; - } - } - /********************************************** CARTRIDGE EXTRA HARDWARE ***********************************************/ @@ -562,16 +496,16 @@ void md_cart_init(void) /* Realtec mapper */ if (cart.hw.realtec) { - /* 8k BOOT ROM */ + /* copy 8KB Boot ROM after cartridge ROM area */ for (i=0; i<8; i++) { - memcpy(cart.rom + 0x900000 + i*0x2000, cart.rom + 0x7e000, 0x2000); + memcpy(cart.rom + 0x400000 + i*0x2000, cart.rom + 0x7e000, 0x2000); } - /* BOOT ROM is mapped to $000000-$3FFFFF */ + /* Boot ROM (8KB mirrored) is mapped to $000000-$3FFFFF */ for (i=0x00; i<0x40; i++) { - m68k.memory_map[i].base = cart.rom + 0x900000; + m68k.memory_map[i].base = cart.rom + 0x400000; } } @@ -731,6 +665,11 @@ void md_cart_init(void) zbank_memory_map[i].write = mapper_smw_64_w; } } + else if ((*(uint16 *)(cart.rom + 0x04) == 0x0000) && (*(uint16 *)(cart.rom + 0x06) == 0x0104) && (rominfo.checksum == 0x31fc)) + { + /* Micro Machines (USA) custom TMSS bypass logic */ + m68k.memory_map[0xa1].write8 = mapper_sr16v1_w; + } else if (cart.romsize > 0x400000) { /* assume linear ROM mapping by default (max. 10MB) */ @@ -748,6 +687,79 @@ void md_cart_init(void) { cart.hw.time_w = default_time_w; } + + /********************************************** + LOCK-ON + ***********************************************/ + + /* clear existing patches */ + ggenie_shutdown(); + areplay_shutdown(); + + /* initialize extra hardware */ + switch (config.lock_on) + { + case TYPE_GG: + { + ggenie_init(); + break; + } + + case TYPE_AR: + { + areplay_init(); + break; + } + + case TYPE_SK: + { + /* store Sonic & Knuckles ROM files after cartridge ROM area */ + if (cart.romsize > 0x400000) break; + + /* try to load Sonic & Knuckles ROM file (2MB) */ + if (load_archive(SK_ROM, cart.rom + 0x400000, 0x200000, NULL) == 0x200000) + { + /* check ROM header */ + if (!memcmp(cart.rom + 0x400000 + 0x120, "SONIC & KNUCKLES",16)) + { + /* try to load Sonic 2 & Knuckles upmem ROM file (256KB) */ + if (load_archive(SK_UPMEM, cart.rom + 0x600000, 0x40000, NULL) == 0x40000) + { + /* $000000-$1FFFFF is mapped to S&K ROM */ + for (i=0x00; i<0x20; i++) + { + m68k.memory_map[i].base = cart.rom + 0x400000 + (i << 16); + } + +#ifdef LSB_FIRST + for (i=0; i<0x200000; i+=2) + { + /* Byteswap ROM */ + uint8 temp = cart.rom[i + 0x400000]; + cart.rom[i + 0x400000] = cart.rom[i + 0x400000 + 1]; + cart.rom[i + 0x400000 + 1] = temp; + } + + for (i=0; i<0x40000; i+=2) + { + /* Byteswap ROM */ + uint8 temp = cart.rom[i + 0x600000]; + cart.rom[i + 0x600000] = cart.rom[i + 0x600000 + 1]; + cart.rom[i + 0x600000 + 1] = temp; + } +#endif + cart.special |= HW_LOCK_ON; + } + } + } + break; + } + + default: + { + break; + } + } } /* hardware that need to be reseted on power on */ @@ -941,12 +953,12 @@ static void mapper_sega_w(uint32 data) } /* S&K lock-on chip */ - if ((cart.special & HW_LOCK_ON) && (config.lock_on == TYPE_SK)) + if (cart.special & HW_LOCK_ON) { - /* S2K upmem chip mapped to $300000-$3fffff (256K mirrored) */ + /* S2K upmem chip mapped to $300000-$3fffff (256KB mirrored) */ for (i=0x30; i<0x40; i++) { - m68k.memory_map[i].base = (cart.rom + 0x900000) + ((i & 3) << 16); + m68k.memory_map[i].base = (cart.rom + 0x600000) + ((i & 3) << 16); } } } @@ -1891,6 +1903,29 @@ static uint32 mapper_128k_radica_r(uint32 address) return 0xffff; } + +/* + Custom logic (ST 16S25HB1 PAL) used in Micro Machines US cartridge (SR16V1.1 board) + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + /VRES is asserted after write access to 0xA14101 (TMSS bank-shift register) + with D0=1 (cartridge ROM access enabled instead of TMSS Boot ROM) being detected +*/ +static void mapper_sr16v1_w(uint32 address, uint32 data) +{ + /* 0xA10000-0xA1FFFF address range is mapped to I/O and Control registers */ + ctrl_io_write_byte(address, data); + + /* cartridge uses /LWR, /AS and VA1-VA18 (only VA8-VA17 required to decode access to TMSS bank-shift register) */ + if ((address & 0xff01) == 0x4101) + { + /* cartridge ROM is enabled when D0=1 */ + if (data & 0x01) + { + gen_reset(0); + } + } +} + /************************************************************ default !TIME signal handler *************************************************************/ diff --git a/genplusgx_source/cart_hw/md_cart.h b/genplusgx_source/cart_hw/md_cart.h index 94e1520..b34fb8f 100644 --- a/genplusgx_source/cart_hw/md_cart.h +++ b/genplusgx_source/cart_hw/md_cart.h @@ -2,7 +2,7 @@ * Genesis Plus * Mega Drive cartridge hardware support * - * Copyright (C) 2007-2020 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2007-2021 Eke-Eke (Genesis Plus GX) * * Most cartridge protections were initially documented by Haze * (http://haze.mameworld.info/) @@ -81,10 +81,10 @@ typedef struct uint32 mask; /* ROM mask */ uint8 special; /* custom external hardware (Lock-On, J-Cart, 3-D glasses, Terebi Oekaki,...) */ cart_hw_t hw; /* cartridge internal hardware */ - uint8 rom[MAXROMSIZE]; /* ROM area */ + uint8 lockrom[0x10000]; /* Game Genie / (Pro) Action Replay Lock-On ROM area (max 64KB) */ + uint8 rom[MAXROMSIZE]; /* cartridge ROM area */ } md_cart_t; - /* Function prototypes */ extern void md_cart_init(void); extern void md_cart_reset(int hard_reset); diff --git a/genplusgx_source/cart_hw/sms_cart.c b/genplusgx_source/cart_hw/sms_cart.c index 88d8999..9443157 100644 --- a/genplusgx_source/cart_hw/sms_cart.c +++ b/genplusgx_source/cart_hw/sms_cart.c @@ -2,7 +2,7 @@ * Genesis Plus * SG-1000, Master System & Game Gear cartridge hardware support * - * Copyright (C) 2007-2019 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2007-2020 Eke-Eke (Genesis Plus GX) * * Redistribution and use of this code or any derivative works are permitted * provided that the following conditions are met: @@ -134,9 +134,12 @@ static const rominfo_t game_list[] = {0x5E53C7F7, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Ernie Els Golf */ {0xD9A7F170, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Man Overboard! */ {0xF7C524F6, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Micro Machines [GG] */ + {0xC21E6CD0, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Micro Machines [GG] [Proto] */ {0xDBE8895C, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Micro Machines 2 - Turbo Tournament */ {0xC1756BEE, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Pete Sampras Tennis */ {0x72981057, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* CJ Elephant Fugitive */ + {0x3ACE6335, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* CJ Elephant Fugitive [Proto] */ + {0x2306AAF4, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Dinobasher - Starring Bignose the Caveman [GG] [Proto] */ /* games using serial EEPROM */ {0x36EBCD6D, 0, 0, 0, MAPPER_93C46, SYSTEM_GG, REGION_USA}, /* Majors Pro Baseball */ @@ -197,6 +200,7 @@ static const rominfo_t game_list[] = {0xC0E25D62, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* California Games II */ {0x45C50294, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* Jogos de Verao II (BR) */ {0xC9DBF936, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* Home Alone */ + {0xA109A6FE, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* Power Strike II */ {0x0047B615, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* Predator2 */ {0xF42E145C, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* Quest for the Shaven Yak Starring Ren Hoek & Stimpy (BR) */ {0x9F951756, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* RoboCop 3 */ @@ -238,6 +242,7 @@ static const rominfo_t game_list[] = {0xA3EF13CB, 1, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Zaxxon 3-D */ {0xBBA74147, 1, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Zaxxon 3-D [Proto] */ {0xD6F43DDA, 1, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Out Run 3-D */ + {0x4E684EC0, 1, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Out Run 3-D [Proto] */ {0x871562b0, 1, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Maze Walker */ {0x156948f9, 1, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Space Harrier 3-D (J) */ @@ -245,6 +250,7 @@ static const rominfo_t game_list[] = {0xFBE5CFBB, 1, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Missile Defense 3D */ {0xE79BB689, 1, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Missile Defense 3D [BIOS] */ {0x43DEF05D, 1, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Missile Defense 3D [Proto] */ + {0x56DCB2D4, 1, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* 3D Gunner [Proto] */ /* games requiring Sega Light Phaser */ {0x861B6E79, 0, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Assault City [Light Phaser] */ @@ -339,6 +345,8 @@ static const rominfo_t game_list[] = {0x56BD2455, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Doki Doki Penguin Land - Uchuu-Daibouken [Proto] */ {0xC722FB42, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Fantasy Zone II (J) */ {0x7ABC70E9, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Family Games (Party Games) */ + {0x9AFAB511, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Game De Check! Koutsuu Anzen [Proto] (JP) */ + {0x9E9DEB18, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Game De Check! Koutsuu Anzen [Proto] (JP) [T-Eng] */ {0x6586BD1F, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Masters Golf */ {0x4847BC91, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Masters Golf [Proto] */ {0xB9FDF6D9, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Haja no Fuuin */ @@ -351,6 +359,8 @@ static const rominfo_t game_list[] = {0x5B5F9106, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Nekyuu Kousien */ {0xBEA27D5C, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Opa Opa */ {0x6605D36A, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Phantasy Star (J) */ + {0x70E89681, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Phantasy Star (J) [T-Eng v1.02] */ + {0xA04CF71A, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Phantasy Star (J) [T-Eng v2.00] */ {0xE1FFF1BB, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Shinobi (J) */ {0x11645549, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Solomon no Kagi - Oujo Rihita no Namida */ {0x7E0EF8CB, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Super Racing */ diff --git a/genplusgx_source/cart_hw/sms_cart.h b/genplusgx_source/cart_hw/sms_cart.h index 4ebac0f..99b0b0b 100644 --- a/genplusgx_source/cart_hw/sms_cart.h +++ b/genplusgx_source/cart_hw/sms_cart.h @@ -2,7 +2,7 @@ * Genesis Plus * SG-1000, Master System & Game Gear cartridge hardware support * - * Copyright (C) 2007-2019 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2007-2020 Eke-Eke (Genesis Plus GX) * * Redistribution and use of this code or any derivative works are permitted * provided that the following conditions are met: diff --git a/genplusgx_source/cart_hw/sram.c b/genplusgx_source/cart_hw/sram.c index 29025f0..2e9327e 100644 --- a/genplusgx_source/cart_hw/sram.c +++ b/genplusgx_source/cart_hw/sram.c @@ -2,7 +2,7 @@ * Genesis Plus * Backup RAM support * - * Copyright (C) 2007-2020 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2007-2021 Eke-Eke (Genesis Plus GX) * * Redistribution and use of this code or any derivative works are permitted * provided that the following conditions are met: @@ -62,11 +62,8 @@ T_SRAM sram; ****************************************************************************/ void sram_init() { - memset(&sram, 0, sizeof (T_SRAM)); - - /* backup RAM data is stored above cartridge ROM area, at $800000-$80FFFF (max. 64K) */ - if (cart.romsize > 0x800000) return; - sram.sram = cart.rom + 0x800000; + /* disable Backup RAM by default */ + sram.detected = sram.on = sram.custom = sram.start = sram.end = 0; /* initialize Backup RAM */ if (strstr(rominfo.international,"Sonic 1 Remastered")) diff --git a/genplusgx_source/cart_hw/sram.h b/genplusgx_source/cart_hw/sram.h index 3b505c5..e33f6e4 100644 --- a/genplusgx_source/cart_hw/sram.h +++ b/genplusgx_source/cart_hw/sram.h @@ -2,7 +2,7 @@ * Genesis Plus * Backup RAM support * - * Copyright (C) 2007-2020 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2007-2021 Eke-Eke (Genesis Plus GX) * * Redistribution and use of this code or any derivative works are permitted * provided that the following conditions are met: @@ -47,7 +47,7 @@ typedef struct uint32 start; uint32 end; uint32 crc; - uint8 *sram; + uint8 sram[0x10000]; } T_SRAM; /* Function prototypes */ diff --git a/genplusgx_source/cd_hw/cd_cart.c b/genplusgx_source/cd_hw/cd_cart.c index 09e84df..a380bd2 100644 --- a/genplusgx_source/cd_hw/cd_cart.c +++ b/genplusgx_source/cd_hw/cd_cart.c @@ -2,7 +2,7 @@ * Genesis Plus * CD compatible ROM/RAM cartridge support * - * Copyright (C) 2012-2016 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2012-2021 Eke-Eke (Genesis Plus GX) * * Redistribution and use of this code or any derivative works are permitted * provided that the following conditions are met: @@ -38,7 +38,6 @@ #include "shared.h" - /*--------------------------------------------------------------------------*/ /* backup RAM cartridge (max. 512KB) */ /*--------------------------------------------------------------------------*/ diff --git a/genplusgx_source/cd_hw/cd_cart.h b/genplusgx_source/cd_hw/cd_cart.h index 6ee7cad..c708a78 100644 --- a/genplusgx_source/cd_hw/cd_cart.h +++ b/genplusgx_source/cd_hw/cd_cart.h @@ -2,7 +2,7 @@ * Genesis Plus * CD compatible ROM/RAM cartridge support * - * Copyright (C) 2012-2016 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2012-2021 Eke-Eke (Genesis Plus GX) * * Redistribution and use of this code or any derivative works are permitted * provided that the following conditions are met: @@ -41,7 +41,7 @@ typedef struct { uint8 reserved[0x80]; /* reserved for ROM cartridge infos (see md_cart.h) */ - uint8 area[0x840000]; /* cartridge ROM/RAM area (max. 8MB ROM + 64KB backup memory + Pro Action Replay 128KB ROM / 64KB RAM) */ + uint8 area[0x810000]; /* cartridge ROM/RAM area (max. 8MB ROM + Pro Action Replay 64KB ROM) */ uint8 boot; /* cartridge boot mode (0x00: boot from CD with ROM/RAM cartridge enabled, 0x40: boot from ROM cartridge with CD enabled) */ uint8 id; /* RAM cartridge ID (related to RAM size, 0 if disabled) */ uint8 prot; /* RAM cartridge write protection */ diff --git a/genplusgx_source/cd_hw/cdd.c b/genplusgx_source/cd_hw/cdd.c index 9b8e821..2bf32d3 100644 --- a/genplusgx_source/cd_hw/cdd.c +++ b/genplusgx_source/cd_hw/cdd.c @@ -2,7 +2,7 @@ * Genesis Plus * CD drive processor & CD-DA fader * - * Copyright (C) 2012-2020 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2012-2021 Eke-Eke (Genesis Plus GX) * * Redistribution and use of this code or any derivative works are permitted * provided that the following conditions are met: @@ -315,7 +315,11 @@ int cdd_load(char *filename, char *header) /* open file */ fd = cdStreamOpen(filename); if (!fd) - return (-1); + { + /* do not return an error as this could be a ROM loaded in memory */ + /* which should be handled by load_archive function */ + return (0); + } #if defined(USE_LIBCHDR) if (!memcmp("chd", &filename[strlen(filename) - 3], 3) || !memcmp("CHD", &filename[strlen(filename) - 3], 3)) @@ -1795,7 +1799,7 @@ void cdd_process(void) { case 0x00: /* Get Drive Status */ { - /* RS0-RS8 are normally unchanged unless reported drive status needs to be updated (i.e previous drive command has been processed) */ + /* RS0-RS1 are normally unchanged unless reported drive status needs to be updated (i.e previous drive command has been processed) */ /* Note: this function is called one 75hz frame ahead of CDD update so latency counter is always one step ahead of upcoming status */ /* Radical Rex and Annet Futatabi both need at least respectively 2 and 3 interrupts with 'playing' status returned before sectors start getting incremented */ if (cdd.latency <= 3) @@ -1806,8 +1810,37 @@ void cdd_process(void) /* check if RS1 indicated invalid track infos (during seeking) */ if (scd.regs[0x38>>1].byte.l == 0x0f) { - /* seeking has ended so we return valid track infos, e.g current track number in RS2-RS3 (fixes Lunar - The Silver Star) */ - scd.regs[0x38>>1].byte.l = 0x02; + /* seeking has ended so we return valid track infos, e.g current absolute time by default (fixes Lunar - The Silver Star) */ + int lba = cdd.lba + 150; + scd.regs[0x38>>1].byte.l = 0x00; + scd.regs[0x3a>>1].w = lut_BCD_16[(lba/75)/60]; + scd.regs[0x3c>>1].w = lut_BCD_16[(lba/75)%60]; + scd.regs[0x3e>>1].w = lut_BCD_16[(lba%75)]; + scd.regs[0x40>>1].byte.h = cdd.toc.tracks[cdd.index].type ? 0x04 : 0x00; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */ + } + + /* otherwise, check if RS2-RS8 need to be updated */ + else if (scd.regs[0x38>>1].byte.l == 0x00) + { + /* current absolute time */ + int lba = cdd.lba + 150; + scd.regs[0x3a>>1].w = lut_BCD_16[(lba/75)/60]; + scd.regs[0x3c>>1].w = lut_BCD_16[(lba/75)%60]; + scd.regs[0x3e>>1].w = lut_BCD_16[(lba%75)]; + scd.regs[0x40>>1].byte.h = cdd.toc.tracks[cdd.index].type ? 0x04 : 0x00; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */ + } + else if (scd.regs[0x38>>1].byte.l == 0x01) + { + /* current track relative time */ + int lba = abs(cdd.lba - cdd.toc.tracks[cdd.index].start); + scd.regs[0x3a>>1].w = lut_BCD_16[(lba/75)/60]; + scd.regs[0x3c>>1].w = lut_BCD_16[(lba/75)%60]; + scd.regs[0x3e>>1].w = lut_BCD_16[(lba%75)]; + scd.regs[0x40>>1].byte.h = cdd.toc.tracks[cdd.index].type ? 0x04 : 0x00; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */ + } + else if (scd.regs[0x38>>1].byte.l == 0x02) + { + /* current track number */ scd.regs[0x3a>>1].w = (cdd.index < cdd.toc.last) ? lut_BCD_16[cdd.index + 1] : 0x0A0A; } } diff --git a/genplusgx_source/cd_hw/libchdr/src/chd.c b/genplusgx_source/cd_hw/libchdr/src/chd.c index cba334f..4e1ad93 100644 --- a/genplusgx_source/cd_hw/libchdr/src/chd.c +++ b/genplusgx_source/cd_hw/libchdr/src/chd.c @@ -201,6 +201,7 @@ typedef struct _zlib_allocator zlib_allocator; struct _zlib_allocator { UINT32 * allocptr[MAX_ZLIB_ALLOCS]; + UINT32 * allocptr2[MAX_ZLIB_ALLOCS]; }; typedef struct _zlib_codec_data zlib_codec_data; @@ -220,10 +221,11 @@ struct _lzma_allocator void (*Free)(void *p, void *address); /* address can be 0 */ void (*FreeSz)(void *p, void *address, size_t size); /* address can be 0 */ uint32_t* allocptr[MAX_LZMA_ALLOCS]; + uint32_t* allocptr2[MAX_LZMA_ALLOCS]; }; typedef struct _lzma_codec_data lzma_codec_data; -struct _lzma_codec_data +struct _lzma_codec_data { CLzmaDec decoder; lzma_allocator allocator; @@ -375,6 +377,7 @@ void lzma_allocator_init(void* p) /* reset pointer list */ memset(codec->allocptr, 0, sizeof(codec->allocptr)); + memset(codec->allocptr2, 0, sizeof(codec->allocptr2)); codec->Alloc = lzma_fast_alloc; codec->Free = lzma_fast_free; } @@ -403,11 +406,16 @@ void lzma_allocator_free(void* p ) *------------------------------------------------- */ +/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */ +#define LZMA_MIN_ALIGNMENT_BITS 512 +#define LZMA_MIN_ALIGNMENT_BYTES (LZMA_MIN_ALIGNMENT_BITS / 8) + void *lzma_fast_alloc(void *p, size_t size) { int scan; - uint32_t *addr; + uint32_t *addr = NULL; lzma_allocator *codec = (lzma_allocator *)(p); + uintptr_t vaddr = 0; /* compute the size, rounding to the nearest 1k */ size = (size + 0x3ff) & ~0x3ff; @@ -420,28 +428,37 @@ void *lzma_fast_alloc(void *p, size_t size) { /* set the low bit of the size so we don't match next time */ *ptr |= 1; - return ptr + 1; + + /* return aligned address of the block */ + return codec->allocptr2[scan]; } } /* alloc a new one and put it into the list */ - addr = (uint32_t *)malloc(sizeof(uint8_t) * (size + sizeof(uint32_t))); + addr = (uint32_t *)malloc(size + sizeof(uint32_t) + LZMA_MIN_ALIGNMENT_BYTES); if (addr==NULL) return NULL; - for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) + for (int scan = 0; scan < MAX_LZMA_ALLOCS; scan++) { if (codec->allocptr[scan] == NULL) { + /* store block address */ codec->allocptr[scan] = addr; + + /* compute aligned address, store it */ + vaddr = (uintptr_t)addr; + vaddr = (vaddr + sizeof(uint32_t) + (LZMA_MIN_ALIGNMENT_BYTES-1)) & (~(LZMA_MIN_ALIGNMENT_BYTES-1)); + codec->allocptr2[scan] = (uint32_t*)vaddr; break; } } /* set the low bit of the size so we don't match next time */ *addr = size | 1; - return addr + 1; -} + /* return aligned address */ + return (void*)vaddr; +} /*------------------------------------------------- * lzma_fast_free - fast free for lzma, which @@ -452,21 +469,22 @@ void *lzma_fast_alloc(void *p, size_t size) void lzma_fast_free(void *p, void *address) { int scan; - uint32_t *ptr; - lzma_allocator *codec; + uint32_t *ptr = NULL; + lzma_allocator *codec = NULL; + if (address == NULL) return; codec = (lzma_allocator *)(p); /* find the hunk */ - ptr = (uint32_t *)(address) - 1; + ptr = (uint32_t *)address; for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) { - if (ptr == codec->allocptr[scan]) + if (ptr == codec->allocptr2[scan]) { /* clear the low bit of the size to allow matches */ - *ptr &= ~1; + *codec->allocptr[scan] &= ~1; return; } } @@ -2458,9 +2476,14 @@ static chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t allocates and frees memory frequently -------------------------------------------------*/ +/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */ +#define ZLIB_MIN_ALIGNMENT_BITS 512 +#define ZLIB_MIN_ALIGNMENT_BYTES (ZLIB_MIN_ALIGNMENT_BITS / 8) + static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size) { zlib_allocator *alloc = (zlib_allocator *)opaque; + uintptr_t paddr = 0; UINT32 *ptr; int i; @@ -2475,12 +2498,14 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size) { /* set the low bit of the size so we don't match next time */ *ptr |= 1; - return ptr + 1; + + /* return aligned block address */ + return (voidpf)(alloc->allocptr2[i]); } } /* alloc a new one */ - ptr = (UINT32 *)malloc(size + sizeof(UINT32)); + ptr = (UINT32 *)malloc(size + sizeof(UINT32) + ZLIB_MIN_ALIGNMENT_BYTES); if (!ptr) return NULL; @@ -2489,12 +2514,16 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size) if (!alloc->allocptr[i]) { alloc->allocptr[i] = ptr; + paddr = (((uintptr_t)ptr) + sizeof(UINT32) + (ZLIB_MIN_ALIGNMENT_BYTES-1)) & (~(ZLIB_MIN_ALIGNMENT_BYTES-1)); + alloc->allocptr2[i] = (uint32_t*)paddr; break; } /* set the low bit of the size so we don't match next time */ *ptr = size | 1; - return ptr + 1; + + /* return aligned block address */ + return (voidpf)paddr; } @@ -2506,15 +2535,15 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size) static void zlib_fast_free(voidpf opaque, voidpf address) { zlib_allocator *alloc = (zlib_allocator *)opaque; - UINT32 *ptr = (UINT32 *)address - 1; + UINT32 *ptr = (UINT32 *)address; int i; /* find the hunk */ for (i = 0; i < MAX_ZLIB_ALLOCS; i++) - if (ptr == alloc->allocptr[i]) + if (ptr == alloc->allocptr2[i]) { /* clear the low bit of the size to allow matches */ - *ptr &= ~1; + *(alloc->allocptr[i]) &= ~1; return; } } diff --git a/genplusgx_source/cd_hw/scd.c b/genplusgx_source/cd_hw/scd.c index 9ce3a57..a52b285 100644 --- a/genplusgx_source/cd_hw/scd.c +++ b/genplusgx_source/cd_hw/scd.c @@ -1306,6 +1306,13 @@ static void scd_write_word(unsigned int address, unsigned int data) return; } + case 0x36: /* CDD control */ + { + /* only bit 2 is writable (bits [1:0] forced to 0 by default) */ + scd.regs[0x37>>1].byte.l = data & 0x04; + return; + } + case 0x4a: /* CDD command 9 (controlled by BIOS, word access only ?) */ { scd.regs[0x4a>>1].w = 0; @@ -1557,7 +1564,6 @@ void scd_init(void) void scd_reset(int hard) { - /* TODO: figure what exactly is resetted when RESET bit is cleared by SUB-CPU */ if (hard) { /* Clear all ASIC registers by default */ @@ -1605,8 +1611,11 @@ void scd_reset(int hard) } else { - /* Clear only SUB-CPU side registers */ - memset(&scd.regs[0x04>>1], 0, sizeof(scd.regs) - 4); + /* TODO: figure what exactly is reset when RESET bit is cleared by SUB-CPU */ + /* Clear only SUB-CPU side registers (communication registers are not cleared, see msu-md-sample.bin) */ + scd.regs[0x04>>1].w = 0x0000; + scd.regs[0x0c>>1].w = 0x0000; + memset(&scd.regs[0x30>>1], 0, sizeof(scd.regs) - 0x30); } /* SUB-CPU side default values */ diff --git a/genplusgx_source/sound/ym2413.c b/genplusgx_source/sound/ym2413.c index ad453fa..97fe030 100644 --- a/genplusgx_source/sound/ym2413.c +++ b/genplusgx_source/sound/ym2413.c @@ -25,7 +25,21 @@ to do: */ -/** EkeEke (2011): removed multiple chips support, cleaned code & added FM board interface for Genesis Plus GX **/ +/************************************************/ +/** Modifications for Genesis Plus GX (EkeEke) **/ +/************************************************/ +/** 2011/xx/xx: removed multiple chips support, cleaned code & added FM board interface **/ +/** 2021/04/23: fixed synchronization of carrier/modulator phase reset after channel Key ON (fixes Japanese Master System BIOS music) **/ +/** 2021/04/24: fixed intruments ROM (verified on YM2413B die, cf. https://siliconpr0n.org/archive/doku.php?id=vendor:yamaha:opl2#ym2413_instrument_rom) **/ +/** 2021/04/24: fixed EG resolution bits (verified on YM2413B die, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2015-03-20) **/ +/** 2021/04/24: fixed EG dump rate (verified on YM2413 real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2015-12-31) **/ +/** 2021/04/25: fixed EG behavior for fastest attack rates (verified on YM2413 real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2017-01-26) **/ +/** 2021/04/25: fixed EG behavior when SL = 0 (verified on YM2413 real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2015-12-24) **/ +/** 2021/04/25: improved EG sustain phase transition comparator accuracy (verified on YM2413 real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2015-12-31) **/ +/** 2021/05/04: improved EG increment steps accuracy (verified on YM2413 real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2015-03-20) **/ +/** 2021/05/08: improved EG transitions accuracy (verified against https://github.com/nukeykt/Nuked-OPLL/blob/master/opll.c) **/ +/** 2021/05/11: improved EG attack phase algorithm accuracy (verified on YM2413 real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2017-01-26) **/ +/************************************************/ #include "shared.h" @@ -40,7 +54,7 @@ to do: #define ENV_LEN (1<state) { - case EG_DMP: /* dump phase */ - /*dump phase is performed by both operators in each channel*/ - /*when CARRIER envelope gets down to zero level, - ** phases in BOTH opearators are reset (at the same time ?) - */ - if ( !(ym2413.eg_cnt & ((1<eg_sh_dp)-1) ) ) + case EG_DMP: /* dump phase */ + if ( (op->volume & ~3) == (MAX_ATT_INDEX & ~3) ) /* envelope level lowest 2 bits are ignored by the comparator */ { - op->volume += eg_inc[op->eg_sel_dp + ((ym2413.eg_cnt>>op->eg_sh_dp)&7)]; + op->state = EG_ATT; - if ( op->volume >= MAX_ATT_INDEX ) + /* force envelope to zero when attack rate is set to 15.0-15.3 */ + if ((op->ar + op->ksr) >= 16+60) { - op->volume = MAX_ATT_INDEX; - op->state = EG_ATT; - /* restart Phase Generator */ - op->phase = 0; + op->volume = MIN_ATT_INDEX; } + + /*dump phase is performed by both operators in each channel*/ + /*when CARRIER envelope gets down to zero level, + *phases in BOTH operators are reset (at the same time ?) + */ + if (i&1) + { + CH->SLOT[0].phase = CH->SLOT[1].phase = 0; + } + } + else if ( !(ym2413.eg_cnt & ((1<eg_sh_dp)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_dp + ((ym2413.eg_cnt>>op->eg_sh_dp)&15)]; } break; - case EG_ATT: /* attack phase */ - if ( !(ym2413.eg_cnt & ((1<eg_sh_ar)-1) ) ) + case EG_ATT: /* attack phase */ + if (op->volume == MIN_ATT_INDEX) { - op->volume += (~op->volume * - (eg_inc[op->eg_sel_ar + ((ym2413.eg_cnt>>op->eg_sh_ar)&7)]) - ) >>2; - - if (op->volume <= MIN_ATT_INDEX) - { - op->volume = MIN_ATT_INDEX; - op->state = EG_DEC; - } + op->state = EG_DEC; + } + else if ( !(ym2413.eg_cnt & (((1<eg_sh_ar)-1) & ~3)) ) + { + op->volume += (~op->volume * (eg_mul[op->eg_sel_ar + ((ym2413.eg_cnt>>op->eg_sh_ar)&15)]))>>4; } break; case EG_DEC: /* decay phase */ - if ( !(ym2413.eg_cnt & ((1<eg_sh_dr)-1) ) ) + if ( (op->volume & ~7) == op->sl ) /* envelope level lowest 3 bits are ignored by the comparator */ { - op->volume += eg_inc[op->eg_sel_dr + ((ym2413.eg_cnt>>op->eg_sh_dr)&7)]; - - if ( op->volume >= op->sl ) - op->state = EG_SUS; + op->state = EG_SUS; + } + else if ( !(ym2413.eg_cnt & ((1<eg_sh_dr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_dr + ((ym2413.eg_cnt>>op->eg_sh_dr)&15)]; + if ( (op->volume & ~3) == (MAX_ATT_INDEX & ~3) ) /* envelope level lowest 2 bits are ignored by the comparator */ + { + op->state = EG_OFF; + } } break; @@ -591,19 +678,20 @@ INLINE void advance(void) one can change percusive/non-percussive modes on the fly and the chip will remain in sustain phase - verified on real YM3812 */ - if(op->eg_type) /* non-percussive mode (sustained tone) */ + if (op->eg_type) /* non-percussive mode (sustained tone) */ { /* do nothing */ } - else /* percussive mode */ + else /* percussive mode */ { /* during sustain phase chip adds Release Rate (in percussive mode) */ if ( !(ym2413.eg_cnt & ((1<eg_sh_rr)-1) ) ) { - op->volume += eg_inc[op->eg_sel_rr + ((ym2413.eg_cnt>>op->eg_sh_rr)&7)]; - - if ( op->volume >= MAX_ATT_INDEX ) - op->volume = MAX_ATT_INDEX; + op->volume += eg_inc[op->eg_sel_rr + ((ym2413.eg_cnt>>op->eg_sh_rr)&15)]; + if ( (op->volume & ~3) == (MAX_ATT_INDEX & ~3) ) /* envelope level lowest 2 bits are ignored by the comparator */ + { + op->state = EG_OFF; + } } /* else do nothing in sustain phase */ } @@ -629,7 +717,7 @@ INLINE void advance(void) */ if ( (i&1) || ((ym2413.rhythm&0x20) && (i>=12)) )/* exclude modulators */ { - if(op->eg_type) /* non-percussive mode (sustained tone) */ + if (op->eg_type) /* non-percussive mode (sustained tone) */ /*this is correct: use RR when SUS = OFF*/ /*and use RS when SUS = ON*/ { @@ -637,10 +725,9 @@ INLINE void advance(void) { if ( !(ym2413.eg_cnt & ((1<eg_sh_rs)-1) ) ) { - op->volume += eg_inc[op->eg_sel_rs + ((ym2413.eg_cnt>>op->eg_sh_rs)&7)]; - if ( op->volume >= MAX_ATT_INDEX ) + op->volume += eg_inc[op->eg_sel_rs + ((ym2413.eg_cnt>>op->eg_sh_rs)&15)]; + if ( (op->volume & ~3) == (MAX_ATT_INDEX & ~3) ) /* envelope level lowest 2 bits are ignored by the comparator */ { - op->volume = MAX_ATT_INDEX; op->state = EG_OFF; } } @@ -649,23 +736,21 @@ INLINE void advance(void) { if ( !(ym2413.eg_cnt & ((1<eg_sh_rr)-1) ) ) { - op->volume += eg_inc[op->eg_sel_rr + ((ym2413.eg_cnt>>op->eg_sh_rr)&7)]; - if ( op->volume >= MAX_ATT_INDEX ) + op->volume += eg_inc[op->eg_sel_rr + ((ym2413.eg_cnt>>op->eg_sh_rr)&15)]; + if ( (op->volume & ~3) == (MAX_ATT_INDEX & ~3) ) /* envelope level lowest 2 bits are ignored by the comparator */ { - op->volume = MAX_ATT_INDEX; op->state = EG_OFF; } } } } - else /* percussive mode */ + else /* percussive mode */ { if ( !(ym2413.eg_cnt & ((1<eg_sh_rs)-1) ) ) { - op->volume += eg_inc[op->eg_sel_rs + ((ym2413.eg_cnt>>op->eg_sh_rs)&7)]; - if ( op->volume >= MAX_ATT_INDEX ) + op->volume += eg_inc[op->eg_sel_rs + ((ym2413.eg_cnt>>op->eg_sh_rs)&15)]; + if ( (op->volume & ~3) == (MAX_ATT_INDEX & ~3) ) /* envelope level lowest 2 bits are ignored by the comparator */ { - op->volume = MAX_ATT_INDEX; op->state = EG_OFF; } } @@ -673,8 +758,12 @@ INLINE void advance(void) } break; - default: - break; + case EG_OFF: /* envelope off */ + op->volume = MAX_ATT_INDEX; + break; + + default: + break; } } } @@ -1142,21 +1231,30 @@ INLINE void CALC_FCSLOT(YM2413_OPLL_CH *CH,YM2413_OPLL_SLOT *SLOT) SLOT->ksr = ksr; /* calculate envelope generator rates */ - if ((SLOT->ar + SLOT->ksr) < 16+62) + if ((SLOT->ar + SLOT->ksr) >= 16+60) { - SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; - SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + /* attack phase is skipped in case attack rate is set to 15.0-15.3 before attack phase is started */ + /* during attack phase, in case attack rate is changed to 15.0-15.3, attack phase is blocked */ + /* (verified on real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2017-01-26) */ + SLOT->eg_sh_ar = 13; + SLOT->eg_sel_ar = 0 * RATE_STEPS; } - else + else if ((SLOT->ar + SLOT->ksr) >= 16+48) { + /* attack rates 12.0 to 14.3 have similar specific behavior */ + /* (verified on real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2017-01-26) */ SLOT->eg_sh_ar = 0; - SLOT->eg_sel_ar = 13*RATE_STEPS; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr] + (4 * RATE_STEPS); + } + else + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr]; } SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; - } if (CH->sus) @@ -1167,7 +1265,7 @@ INLINE void CALC_FCSLOT(YM2413_OPLL_CH *CH,YM2413_OPLL_SLOT *SLOT) SLOT->eg_sh_rs = eg_rate_shift [SLOT_rs + SLOT->ksr ]; SLOT->eg_sel_rs = eg_rate_select[SLOT_rs + SLOT->ksr ]; - SLOT_dp = 16 + (13<<2); + SLOT_dp = 16 + (12<<2); SLOT->eg_sh_dp = eg_rate_shift [SLOT_dp + SLOT->ksr ]; SLOT->eg_sel_dp = eg_rate_select[SLOT_dp + SLOT->ksr ]; } @@ -1225,15 +1323,25 @@ INLINE void set_ar_dr(int slot,int v) SLOT->ar = (v>>4) ? 16 + ((v>>4) <<2) : 0; - if ((SLOT->ar + SLOT->ksr) < 16+62) + if ((SLOT->ar + SLOT->ksr) >= 16+60) { - SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; - SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + /* attack phase is skipped in case attack rate is set to 15.0-15.3 before attack phase is started */ + /* during attack phase, in case attack rate is changed to 15.0-15.3, attack phase is blocked */ + /* (verified on real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2017-01-26) */ + SLOT->eg_sh_ar = 13; + SLOT->eg_sel_ar = 0 * RATE_STEPS; } - else + else if ((SLOT->ar + SLOT->ksr) >= 16+48) { + /* attack rates 12.0 to 14.3 have similar specific behavior */ + /* (verified on real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2017-01-26) */ SLOT->eg_sh_ar = 0; - SLOT->eg_sel_ar = 13*RATE_STEPS; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr] + (4 * RATE_STEPS); + } + else + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr]; } SLOT->dr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; diff --git a/genplusgx_source/sound/ym2612.c b/genplusgx_source/sound/ym2612.c index 9b6092f..585ffe2 100644 --- a/genplusgx_source/sound/ym2612.c +++ b/genplusgx_source/sound/ym2612.c @@ -20,6 +20,9 @@ /* ** CHANGELOG: ** +** 11-05-2021 Eke-Eke (Genesis Plus GX): +** - fixed potential issue with SSG-EG inverted attenuation level on Key OFF +** ** 03-12-2017 Eke-Eke (Genesis Plus GX): ** - improved 9-bit DAC emulation accuracy ** - added discrete YM2612 DAC distortion emulation ("ladder effect") @@ -684,7 +687,7 @@ INLINE void FM_KEYOFF(FM_CH *CH , int s ) { /* convert EG attenuation level */ if (SLOT->ssgn ^ (SLOT->ssg&0x04)) - SLOT->volume = (0x200 - SLOT->volume); + SLOT->volume = (0x200 - SLOT->volume) & MAX_ATT_INDEX; /* force EG attenuation level */ if (SLOT->volume >= 0x200) @@ -749,7 +752,7 @@ INLINE void FM_KEYOFF_CSM(FM_CH *CH , int s ) { /* convert EG attenuation level */ if (SLOT->ssgn ^ (SLOT->ssg&0x04)) - SLOT->volume = (0x200 - SLOT->volume); + SLOT->volume = (0x200 - SLOT->volume) & MAX_ATT_INDEX; /* force EG attenuation level */ if (SLOT->volume >= 0x200) diff --git a/genplusgx_source/sound/ym3438.c b/genplusgx_source/sound/ym3438.c index 3917815..01d1c82 100644 --- a/genplusgx_source/sound/ym3438.c +++ b/genplusgx_source/sound/ym3438.c @@ -1,6 +1,6 @@ #ifdef HAVE_YM3438_CORE /* - * Copyright (C) 2017 Alexey Khokholov (Nuke.YKT) + * Copyright (C) 2017-2018 Alexey Khokholov (Nuke.YKT) * * Redistribution and use of this code or any derivative works are permitted * provided that the following conditions are met: @@ -40,7 +40,7 @@ * OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): * OPL2 ROMs. * - * version: 1.0.8 + * version: 1.0.10 */ #include @@ -235,7 +235,7 @@ static const Bit32u fm_algorithm[4][6][8] = { static Bit32u chip_type = ym3438_mode_readmode; -void OPN2_DoIO(ym3438_t *chip) +static void OPN2_DoIO(ym3438_t *chip) { /* Write signal check */ chip->write_a_en = (chip->write_a & 0x03) == 0x01; @@ -249,10 +249,10 @@ void OPN2_DoIO(ym3438_t *chip) chip->write_busy_cnt &= 0x1f; } -void OPN2_DoRegWrite(ym3438_t *chip) +static void OPN2_DoRegWrite(ym3438_t *chip) { Bit32u i; - Bit32u slot = chip->slot % 12; + Bit32u slot = chip->cycles % 12; Bit32u address; Bit32u channel = chip->channel; /* Update registers */ @@ -379,7 +379,7 @@ void OPN2_DoRegWrite(ym3438_t *chip) /* Data */ if (chip->write_d_en && (chip->write_data & 0x100) == 0) { - switch (chip->address) + switch (chip->write_fm_mode_a) { case 0x21: /* LSI test 1 */ for (i = 0; i < 8; i++) @@ -458,7 +458,7 @@ void OPN2_DoRegWrite(ym3438_t *chip) /* Address */ if (chip->write_a_en) { - chip->write_fm_mode_a = chip->write_data & 0xff; + chip->write_fm_mode_a = chip->write_data & 0x1ff; } } @@ -468,16 +468,18 @@ void OPN2_DoRegWrite(ym3438_t *chip) } } -void OPN2_PhaseCalcIncrement(ym3438_t *chip) +static void OPN2_PhaseCalcIncrement(ym3438_t *chip) { + Bit32u chan = chip->channel; + Bit32u slot = chip->cycles; Bit32u fnum = chip->pg_fnum; Bit32u fnum_h = fnum >> 4; Bit32u fm; Bit32u basefreq; Bit8u lfo = chip->lfo_pm; Bit8u lfo_l = lfo & 0x0f; - Bit8u pms = chip->pms[chip->channel]; - Bit8u dt = chip->dt[chip->slot]; + Bit8u pms = chip->pms[chan]; + Bit8u dt = chip->dt[slot]; Bit8u dt_l = dt & 0x03; Bit8u detune = 0; Bit8u block, note; @@ -531,32 +533,32 @@ void OPN2_PhaseCalcIncrement(ym3438_t *chip) basefreq += detune; } basefreq &= 0x1ffff; - chip->pg_inc[chip->slot] = (basefreq * chip->multi[chip->slot]) >> 1; - chip->pg_inc[chip->slot] &= 0xfffff; + chip->pg_inc[slot] = (basefreq * chip->multi[slot]) >> 1; + chip->pg_inc[slot] &= 0xfffff; } -void OPN2_PhaseGenerate(ym3438_t *chip) +static void OPN2_PhaseGenerate(ym3438_t *chip) { Bit32u slot; /* Mask increment */ - slot = (chip->slot + 20) % 24; + slot = (chip->cycles + 20) % 24; if (chip->pg_reset[slot]) { chip->pg_inc[slot] = 0; } /* Phase step */ - slot = (chip->slot + 19) % 24; - chip->pg_phase[slot] += chip->pg_inc[slot]; - chip->pg_phase[slot] &= 0xfffff; + slot = (chip->cycles + 19) % 24; if (chip->pg_reset[slot] || chip->mode_test_21[3]) { chip->pg_phase[slot] = 0; } + chip->pg_phase[slot] += chip->pg_inc[slot]; + chip->pg_phase[slot] &= 0xfffff; } -void OPN2_EnvelopeSSGEG(ym3438_t *chip) +static void OPN2_EnvelopeSSGEG(ym3438_t *chip) { - Bit32u slot = chip->slot; + Bit32u slot = chip->cycles; Bit8u direction = 0; chip->eg_ssg_pgrst_latch[slot] = 0; chip->eg_ssg_repeat_latch[slot] = 0; @@ -601,9 +603,9 @@ void OPN2_EnvelopeSSGEG(ym3438_t *chip) chip->eg_ssg_enable[slot] = (chip->ssg_eg[slot] >> 3) & 0x01; } -void OPN2_EnvelopeADSR(ym3438_t *chip) +static void OPN2_EnvelopeADSR(ym3438_t *chip) { - Bit32u slot = (chip->slot + 22) % 24; + Bit32u slot = (chip->cycles + 22) % 24; Bit8u nkon = chip->eg_kon_latch[slot]; Bit8u okon = chip->eg_kon[slot]; @@ -725,12 +727,12 @@ void OPN2_EnvelopeADSR(ym3438_t *chip) chip->eg_state[slot] = nextstate; } -void OPN2_EnvelopePrepare(ym3438_t *chip) +static void OPN2_EnvelopePrepare(ym3438_t *chip) { Bit8u rate; Bit8u sum; Bit8u inc = 0; - Bit32u slot = chip->slot; + Bit32u slot = chip->cycles; Bit8u rate_sel; /* Prepare increment */ @@ -813,9 +815,9 @@ void OPN2_EnvelopePrepare(ym3438_t *chip) chip->eg_sl[0] = chip->sl[slot]; } -void OPN2_EnvelopeGenerate(ym3438_t *chip) +static void OPN2_EnvelopeGenerate(ym3438_t *chip) { - Bit32u slot = (chip->slot + 23) % 24; + Bit32u slot = (chip->cycles + 23) % 24; Bit16u level; level = chip->eg_level[slot]; @@ -846,7 +848,7 @@ void OPN2_EnvelopeGenerate(ym3438_t *chip) chip->eg_out[slot] = level; } -void OPN2_UpdateLFO(ym3438_t *chip) +static void OPN2_UpdateLFO(ym3438_t *chip) { if ((chip->lfo_quotient & lfo_cycles[chip->lfo_freq]) == lfo_cycles[chip->lfo_freq]) { @@ -860,14 +862,14 @@ void OPN2_UpdateLFO(ym3438_t *chip) chip->lfo_cnt &= chip->lfo_en; } -void OPN2_FMPrepare(ym3438_t *chip) +static void OPN2_FMPrepare(ym3438_t *chip) { - Bit32u slot = (chip->slot + 6) % 24; + Bit32u slot = (chip->cycles + 6) % 24; Bit32u channel = chip->channel; Bit16s mod, mod1, mod2; Bit32u op = slot / 6; Bit8u connect = chip->connect[channel]; - Bit32u prevslot = (chip->slot + 18) % 24; + Bit32u prevslot = (chip->cycles + 18) % 24; /* Calculate modulation */ mod1 = mod2 = 0; @@ -908,7 +910,7 @@ void OPN2_FMPrepare(ym3438_t *chip) } chip->fm_mod[slot] = mod; - slot = (chip->slot + 18) % 24; + slot = (chip->cycles + 18) % 24; /* OP1 */ if (slot / 6 == 0) { @@ -922,9 +924,9 @@ void OPN2_FMPrepare(ym3438_t *chip) } } -void OPN2_ChGenerate(ym3438_t *chip) +static void OPN2_ChGenerate(ym3438_t *chip) { - Bit32u slot = (chip->slot + 18) % 24; + Bit32u slot = (chip->cycles + 18) % 24; Bit32u channel = chip->channel; Bit32u op = slot / 6; Bit32u test_dac = chip->mode_test_2c[5]; @@ -957,16 +959,17 @@ void OPN2_ChGenerate(ym3438_t *chip) chip->ch_acc[channel] = sum; } -void OPN2_ChOutput(ym3438_t *chip) +static void OPN2_ChOutput(ym3438_t *chip) { Bit32u cycles = chip->cycles; + Bit32u slot = chip->cycles; Bit32u channel = chip->channel; Bit32u test_dac = chip->mode_test_2c[5]; Bit16s out; Bit16s sign; Bit32u out_en; chip->ch_read = chip->ch_lock; - if (chip->slot < 12) + if (slot < 12) { /* Ch 4,5,6 */ channel++; @@ -1039,9 +1042,9 @@ void OPN2_ChOutput(ym3438_t *chip) } } -void OPN2_FMGenerate(ym3438_t *chip) +static void OPN2_FMGenerate(ym3438_t *chip) { - Bit32u slot = (chip->slot + 19) % 24; + Bit32u slot = (chip->cycles + 19) % 24; /* Calculate phase */ Bit16u phase = (chip->fm_mod[slot] + (chip->pg_phase[slot] >> 10)) & 0x3ff; Bit16u quarter; @@ -1077,7 +1080,7 @@ void OPN2_FMGenerate(ym3438_t *chip) chip->fm_out[slot] = output; } -void OPN2_DoTimerA(ym3438_t *chip) +static void OPN2_DoTimerA(ym3438_t *chip) { Bit16u time; Bit8u load; @@ -1126,7 +1129,7 @@ void OPN2_DoTimerA(ym3438_t *chip) chip->timer_a_cnt = time & 0x3ff; } -void OPN2_DoTimerB(ym3438_t *chip) +static void OPN2_DoTimerB(ym3438_t *chip) { Bit16u time; Bit8u load; @@ -1171,27 +1174,29 @@ void OPN2_DoTimerB(ym3438_t *chip) chip->timer_b_cnt = time & 0xff; } -void OPN2_KeyOn(ym3438_t*chip) +static void OPN2_KeyOn(ym3438_t*chip) { + Bit32u slot = chip->cycles; + Bit32u chan = chip->channel; /* Key On */ - chip->eg_kon_latch[chip->slot] = chip->mode_kon[chip->slot]; - chip->eg_kon_csm[chip->slot] = 0; + chip->eg_kon_latch[slot] = chip->mode_kon[slot]; + chip->eg_kon_csm[slot] = 0; if (chip->channel == 2 && chip->mode_kon_csm) { /* CSM Key On */ - chip->eg_kon_latch[chip->slot] = 1; - chip->eg_kon_csm[chip->slot] = 1; + chip->eg_kon_latch[slot] = 1; + chip->eg_kon_csm[slot] = 1; } if (chip->cycles == chip->mode_kon_channel) { /* OP1 */ - chip->mode_kon[chip->channel] = chip->mode_kon_operator[0]; + chip->mode_kon[chan] = chip->mode_kon_operator[0]; /* OP2 */ - chip->mode_kon[chip->channel + 12] = chip->mode_kon_operator[1]; + chip->mode_kon[chan + 12] = chip->mode_kon_operator[1]; /* OP3 */ - chip->mode_kon[chip->channel + 6] = chip->mode_kon_operator[2]; + chip->mode_kon[chan + 6] = chip->mode_kon_operator[2]; /* OP4 */ - chip->mode_kon[chip->channel + 18] = chip->mode_kon_operator[3]; + chip->mode_kon[chan + 18] = chip->mode_kon_operator[3]; } } @@ -1220,6 +1225,7 @@ void OPN2_SetChipType(Bit32u type) void OPN2_Clock(ym3438_t *chip, Bit16s *buffer) { + Bit32u slot = chip->cycles; chip->lfo_inc = chip->mode_test_21[1]; chip->pg_read >>= 1; chip->eg_read[1] >>= 1; @@ -1310,7 +1316,7 @@ void OPN2_Clock(ym3438_t *chip, Bit16s *buffer) if (chip->mode_ch3) { /* Channel 3 special mode */ - switch (chip->slot) + switch (slot) { case 1: /* OP1 */ chip->pg_fnum = chip->fnum_3ch[1]; @@ -1345,7 +1351,6 @@ void OPN2_Clock(ym3438_t *chip, Bit16s *buffer) OPN2_UpdateLFO(chip); OPN2_DoRegWrite(chip); chip->cycles = (chip->cycles + 1) % 24; - chip->slot = chip->cycles; chip->channel = chip->cycles % 6; buffer[0] = chip->mol; @@ -1397,6 +1402,7 @@ Bit8u OPN2_Read(ym3438_t *chip, Bit32u port) if (chip->mode_test_21[6]) { /* Read test data */ + Bit32u slot = (chip->cycles + 18) % 24; Bit16u testdata = ((chip->pg_read & 0x01) << 15) | ((chip->eg_read[chip->mode_test_21[0]] & 0x01) << 14); if (chip->mode_test_2c[4]) @@ -1405,7 +1411,7 @@ Bit8u OPN2_Read(ym3438_t *chip, Bit32u port) } else { - testdata |= chip->fm_out[(chip->slot + 18) % 24] & 0x3fff; + testdata |= chip->fm_out[slot] & 0x3fff; } if (chip->mode_test_21[7]) { diff --git a/genplusgx_source/sound/ym3438.h b/genplusgx_source/sound/ym3438.h index 5ab284f..7123858 100644 --- a/genplusgx_source/sound/ym3438.h +++ b/genplusgx_source/sound/ym3438.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Alexey Khokholov (Nuke.YKT) + * Copyright (C) 2017-2018 Alexey Khokholov (Nuke.YKT) * * Redistribution and use of this code or any derivative works are permitted * provided that the following conditions are met: @@ -39,15 +39,19 @@ * OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): * OPL2 ROMs. * - * version: 1.0.8 + * version: 1.0.9 */ #ifndef YM3438_H #define YM3438_H +#ifdef __cplusplus +extern "C" { +#endif + enum { ym3438_mode_ym2612 = 0x01, /* Enables YM2612 emulation (MD1, MD2 VA2) */ - ym3438_mode_readmode = 0x02, /* Enables status read on any port (TeraDrive, MD1 VA7, MD2, etc) */ + ym3438_mode_readmode = 0x02 /* Enables status read on any port (TeraDrive, MD1 VA7, MD2, etc) */ }; #include @@ -66,7 +70,6 @@ typedef int8_t Bit8s; typedef struct { Bit32u cycles; - Bit32u slot; Bit32u channel; Bit16s mol, mor; /* IO */ @@ -79,7 +82,7 @@ typedef struct Bit8u write_busy_cnt; Bit8u write_fm_address; Bit8u write_fm_data; - Bit8u write_fm_mode_a; + Bit16u write_fm_mode_a; Bit16u address; Bit8u data; Bit8u pin_test_in; @@ -155,7 +158,7 @@ typedef struct Bit8u timer_a_load_latch; Bit8u timer_a_overflow_flag; Bit8u timer_a_overflow; - + Bit16u timer_b_cnt; Bit8u timer_b_subcnt; Bit16u timer_b_reg; @@ -166,7 +169,7 @@ typedef struct Bit8u timer_b_load_latch; Bit8u timer_b_overflow_flag; Bit8u timer_b_overflow; - + /* Register set */ Bit8u mode_test_21[8]; Bit8u mode_test_2c[8]; @@ -178,7 +181,7 @@ typedef struct Bit8u mode_kon_csm; Bit8u dacen; Bit16s dacdata; - + Bit8u ks[24]; Bit8u ar[24]; Bit8u sr[24]; @@ -190,7 +193,7 @@ typedef struct Bit8u am[24]; Bit8u tl[24]; Bit8u ssg_eg[24]; - + Bit16u fnum[6]; Bit8u block[6]; Bit8u kcode[6]; @@ -216,4 +219,9 @@ void OPN2_SetTestPin(ym3438_t *chip, Bit32u value); Bit32u OPN2_ReadTestPin(ym3438_t *chip); Bit32u OPN2_ReadIRQPin(ym3438_t *chip); Bit8u OPN2_Read(ym3438_t *chip, Bit32u port); + +#ifdef __cplusplus +} +#endif + #endif