libretro / FBNeo

FBNeo - We are Team FBNeo.
https://neo-source.com
Other
224 stars 134 forks source link

[TUTORIAL] porting romsets from hbmame #7

Open barbudreadmon opened 5 years ago

barbudreadmon commented 5 years ago

So i wanted to sync kof98pfe with the hbmame version (having a hack of a hack just to get it working is no good, i won't keep it in the core if it's not fixed), and i thought it would be a good idea to open an issue that might become a reference for @SumavisionQ5 or whoever who want to add support for more hacks in the future.

First, here is the original romset from hbmame :

ROM_START( kof98pfe ) // px,s1,m1,c1,2,7,8 confirmed
    ROM_REGION( 0x720000, "maincpu", 0 )
    ROM_LOAD16_WORD_SWAP( "242pfe.p1", 0x000000, 0x100000, CRC(23876d95) SHA1(1e3bcd98d861618fa8b02503f1c8d342d6d45768) )
    ROM_LOAD16_WORD_SWAP( "242pfe.p2", 0x100000, 0x400000, CRC(adbaa852) SHA1(afcc76da85c0598e6f5c96ad112c458a4ed59941) )
    ROM_LOAD16_WORD_SWAP( "242pfe.p3", 0x700000, 0x020000, CRC(930ea34e) SHA1(8eb58c20a6854a8feba454ef280147eb1319c0c5) )
    // patch out protection
    ROM_FILL(0x701af4,1,0x4e)
    ROM_FILL(0x701af5,1,0x71)
    ROM_FILL(0x701b18,1,0x60)
    ROM_FILL(0x701ca2,1,0x60)

    NEO_SFIX_128K( "242pfe.s1", CRC(7f4dbf23) SHA1(bce6dcea6dc40d4072afe67682c7dacde2edce8d) )

    NEO_BIOS_AUDIO_256K( "242-mg1.m1", CRC(4e7a6b1b) SHA1(b54d08f88713ed0271aa06f9f7c9c572ef555b1a) )

    ROM_REGION( 0x1000000, "ymsnd", 0 )
    ROM_LOAD( "242.v1", 0x000000, 0x400000, CRC(b9ea8051) SHA1(49606f64eb249263b3341b4f50cc1763c390b2af) )
    ROM_LOAD( "242.v2", 0x400000, 0x400000, CRC(cc11106e) SHA1(d3108bc05c9bf041d4236b2fa0c66b013aa8db1b) )
    ROM_LOAD( "242.v3", 0x800000, 0x400000, CRC(044ea4e1) SHA1(062a2f2e52098d73bc31c9ad66f5db8080395ce8) )
    ROM_LOAD( "242.v4", 0xc00000, 0x400000, CRC(7985ea30) SHA1(54ed5f0324de6164ea81943ebccb3e8d298368ec) )

    ROM_REGION( 0x4000000, "sprites", 0 )
    ROM_LOAD16_BYTE( "242hx73.c1", 0x0000000, 0x800000, CRC(379654a5) SHA1(fe5d9f1d3072ac83224382abd7f371cf065a8366) )
    ROM_LOAD16_BYTE( "242hx73.c2", 0x0000001, 0x800000, CRC(9c71fa3d) SHA1(1ccbab3378aeef5445fa73d6c59b93c6f9d65557) )
    ROM_LOAD16_BYTE( "242.c3", 0x1000000, 0x800000, CRC(22127b4f) SHA1(bd0d00f889d9da7c6ac48f287d9ed8c605ae22cf) )
    ROM_LOAD16_BYTE( "242.c4", 0x1000001, 0x800000, CRC(0b4fa044) SHA1(fa13c3764fae6b035a626601bc43629f1ebaaffd) )
    ROM_LOAD16_BYTE( "242.c5", 0x2000000, 0x800000, CRC(9d10bed3) SHA1(4d44addc7c808649bfb03ec45fb9529da413adff) )
    ROM_LOAD16_BYTE( "242.c6", 0x2000001, 0x800000, CRC(da07b6a2) SHA1(9c3f0da7cde1ffa8feca89efc88f07096e502acf) )
    ROM_LOAD16_BYTE( "242pfe.c7", 0x3000000, 0x800000, CRC(02f09b2e) SHA1(f72246873e425f4b78c453f30b78eabc5a244fd3) )
    ROM_LOAD16_BYTE( "242pfe.c8", 0x3000001, 0x800000, CRC(d43ab3e6) SHA1(90fbc49c687245fcde1b3e58289b3b0728dc6b0c) )
ROM_END

I think there are 2 difficulties in this romset, which weren't handled correctly in the present implementation from @SumavisionQ5 (hence the modified 242pfe.p2 and 242pfe.p3 files). The first one is that the 2 files aren't contiguous in memory (hence the 2M padding), iirc the correct way to do this would be more like this (updated with latest version + some comments) :

static struct BurnRomInfo kof98pfeRomDesc[] = {
    { "242pfe.p1",  0x100000, 0x23876d95, 1 | BRF_ESS | BRF_PRG }, //  1 68K code
    { "242pfe.p2",  0x400000, 0xadbaa852, 1 | BRF_ESS | BRF_PRG }, //  1 68K code
    { "242pfe.p3",  0x020000, 0x930ea34e, 1 | BRF_ESS | BRF_PRG }, //  1 68K code

    { "242pfe.s1",  0x020000, 0x7f4dbf23, 2 | BRF_GRA },           //  2 Text layer tiles / TC531000

    { "242hx73.c1", 0x800000, 0x379654a5, 3 | BRF_GRA },           //  3 Sprite data
    { "242hx73.c2", 0x800000, 0x9c71fa3d, 3 | BRF_GRA },           //  4 
    { "242.c3",     0x800000, 0x22127b4f, 3 | BRF_GRA },           //  5 
    { "242.c4",     0x800000, 0x0b4fa044, 3 | BRF_GRA },           //  6 
    { "242.c5",     0x800000, 0x9d10bed3, 3 | BRF_GRA },           //  7 
    { "242.c6",     0x800000, 0xda07b6a2, 3 | BRF_GRA },           //  8 
    { "242pfe.c7",  0x800000, 0x02f09b2e, 3 | BRF_GRA },           //  9 
    { "242pfe.c8",  0x800000, 0xd43ab3e6, 3 | BRF_GRA },           // 10 

    { "242-mg1.m1", 0x040000, 0x4e7a6b1b, 4 | BRF_ESS | BRF_PRG }, // 11 Z80 code

    { "242.v1",     0x400000, 0xb9ea8051, 5 | BRF_SND },           // 12 Sound data
    { "242.v2",     0x400000, 0xcc11106e, 5 | BRF_SND },           // 13 
    { "242.v3",     0x400000, 0x044ea4e1, 5 | BRF_SND },           // 14 
    { "242.v4",     0x400000, 0x7985ea30, 5 | BRF_SND },           // 15 
};

STDROMPICKEXT(kof98pfe, kof98pfe, neogeo)
STD_ROM_FN(kof98pfe)

static UINT8 *kof98pfeExtraROM;

static void kof98pfeCallback()
{
    BurnLoadRom(Neo68KROMActive + 0x700000, 2, 1); // Third 68k code rom needs to be loaded at the 0x700000 offset
    Neo68KROMActive[0x701af4] = 0x4e; // Soft patching rom
    Neo68KROMActive[0x701af5] = 0x71; // Soft patching rom
    Neo68KROMActive[0x701b18] = 0x60; // Soft patching rom
    Neo68KROMActive[0x701ca2] = 0x60; // Soft patching rom
}

static INT32 kof98pfeInit()
{
    NeoCallbackActive->pInitialise = kof98pfeCallback; // Use this callback when loading the romset

    INT32 nRet = NeoInit();

    if (nRet == 0) {
        kof98pfeExtraROM = (UINT8*)BurnMalloc(0x20000);

        if (BurnLoadRom(kof98pfeExtraROM, 2, 1)) return 1;

        UINT16 *rom = (UINT16*)kof98pfeExtraROM;
        for (INT32 i = 0; i < 0x20000/2; i++) {
            if (rom[i] == 0x4e7d) rom[i] = 0x4e71;
            if (rom[i] == 0x4e7c) rom[i] = 0x4e75;
        }

        rom = (UINT16*)Neo68KROMActive;

        for (INT32 i = 0; i < 0x100000/2; i++) {
            if (rom[i] == 0x4e7d) rom[i] = 0x4e71;
            if (rom[i] == 0x4e7c) rom[i] = 0x4e75;
        }

        SekOpen(0);
        SekMapMemory(kof98pfeExtraROM, 0x900000, 0x91ffff, MAP_ROM);
        SekClose();
    }

    return nRet;
}

static INT32 kof98pfeExit()
{
    BurnFree (kof98pfeExtraROM);

    return NeoExit();
}

struct BurnDriver BurnDrvkof98pfe = {
    "kof98pfe", "kof98", "neogeo", NULL, "2017",
    "Kof'98 (Plus Final Edition)(2017-07-23)(Korean board)\0", NULL, "hack", "Miscellaneous",
    NULL, NULL, NULL, NULL,
    BDF_GAME_WORKING | BDF_CLONE | BDF_HACK, 2, HARDWARE_PREFIX_CARTRIDGE | HARDWARE_SNK_NEOGEO, GBF_VSFIGHT, FBF_KOF,
    NULL, kof98pfeRomInfo, kof98pfeRomName, NULL, NULL, NULL, NULL, neogeoInputInfo, neogeoDIPInfo,
    kof98pfeInit, kof98pfeExit, NeoFrame, NeoRender, NeoScan, &NeoRecalcPalette,
    0x1000, 320, 224, 4, 3
};

@dinkc64 correct me if i'm wrong, but the callback + burnloadrom thing allows to load a rom at a specific offset ? (that's what i used for the kof2k2omg hacks)

The second issue would be the ROM_FILL thing from hbmame, i think it's something like replacing data at a specific offset ? How should i deal with this in fba ?

dinkc64 commented 5 years ago

Barbudreadmon, yes, of course. This topic is a great idea! Let's go:

On patching the rom, let's take for example these: ROM_FILL(0x701af4,1,0x4e) ROM_FILL(0x701af5,1,0x71) ROM_FILL(0x701b18,1,0x60) ROM_FILL(0x701ca2,1,0x60) ROM_FILL(a,b,c) is basically memset(rom+a,c,b);

But, let's do it in a bit differently - to learn some other methods:

UINT16 ROM = (UINT16)Neo68KROMActive; ROM[0x701af4 / 2] = 0x4e71; // word-write nop Neo68KROMActive[0x701b18] = 0x60; // byte-write 0x60 Neo68KROMActive[0x701ca2] = 0x60; // byte-write 0x60

Let's explain a few things: 0: Neo68KROMActive is a byte-array, but can be word(UINT16)-accessed using a simple cast. 1: notice the first 2 ROM_FILL's are contiguous? 0x701af4, 0x701af5, that's why we are able to write both bytes at once using a UINT16 cast for ROM[]. 0x4e71 is commonly known as NOP on 68k cpu's 2: notice the /2 when writing a word using ROM[]? When indexing using UINT16 (word), each word address is 2 bytes, that's why the address is divided by 2. For example: WORD0 BYTE0,BYTE1 WORD1 BYTE2,BYTE3 WORD2 BYTE4,BYTE5 .. and so on :) Take for example BYTE4, divide that by 2 and you get WORD2.

Maybe you just want to do it exactly the same way as HBMAME? Neo68KROMActive[0x701af4] = 0x4e; Neo68KROMActive[0x701af5] = 0x71; Neo68KROMActive[0x701b18] = 0x60; // byte-write 0x60 Neo68KROMActive[0x701ca2] = 0x60; // byte-write 0x60

or even with memset():

memset(Neo68KROMActive + 0x701af4, 0x4e, 1); memset(Neo68KROMActive + 0x701af5, 0x71, 1); memset(Neo68KROMActive + 0x701b18, 0x60, 1); memset(Neo68KROMActive + 0x701ca2, 0x60, 1); ... and so on...

hope this clears some things up :)

best regards,

barbudreadmon commented 5 years ago

Updated the first post with latest version of the code. It's currently crashing with the following trace :

    #0 0x7f9f3e4488af in inflate_fast src/dep/libs/zlib/inffast.c:120
    #1 0x7f9f3e454e20 in inflate src/dep/libs/zlib/inflate.c:1047
    #2 0x7f9f3e227277 in unzReadCurrentFile src/burner/unzip.c:1854
    #3 0x7f9f3e4a62c1 in ZipLoadFile(unsigned char*, int, int*, int) src/burner/zipfn.cpp:229
    #4 0x7f9f3fd04ef6 in archive_load_rom src/burner/libretro/libretro.cpp:584
    #5 0x7f9f3e522f5b in BurnLoadRomExt(unsigned char*, int, int, int) src/burn/load.cpp:80
    #6 0x7f9f3e523aa5 in BurnLoadRom(unsigned char*, int, int) src/burn/load.cpp:100
    #7 0x7f9f3edc6a52 in kof98pfeCallback src/burn/drv/neogeo/d_neogeo.cpp:17454
    #8 0x7f9f3ed810f4 in LoadRoms src/burn/drv/neogeo/neo_run.cpp:759
    #9 0x7f9f3ed8feda in NeoInit() src/burn/drv/neogeo/neo_run.cpp:4143
    #10 0x7f9f3edd6c15 in kof98pfeInit src/burn/drv/neogeo/d_neogeo.cpp:17465
    #11 0x7f9f3e51c796 in BurnDrvInit src/burn/burn.cpp:647
    #12 0x7f9f3fd0d63f in retro_load_game_common src/burner/libretro/libretro.cpp:1281
    #13 0x7f9f3fd0f609 in retro_load_game src/burner/libretro/libretro.cpp:1353
    #14 0x56433e6e18f8  (/usr/bin/retroarch+0x468f8)
    #15 0x56433e6fb689  (/usr/bin/retroarch+0x60689)
    #16 0x56433e6ec063  (/usr/bin/retroarch+0x51063)
    #17 0x56433e6e4e78  (/usr/bin/retroarch+0x49e78)
    #18 0x56433e6f9164  (/usr/bin/retroarch+0x5e164)
    #19 0x56433e6f953b  (/usr/bin/retroarch+0x5e53b)
    #20 0x56433e6f9db4  (/usr/bin/retroarch+0x5edb4)
    #21 0x56433e6e08f8  (/usr/bin/retroarch+0x458f8)
    #22 0x7f9f5956bae6 in __libc_start_main (/lib64/libc.so.6+0x21ae6)
    #23 0x56433e6dd859  (/usr/bin/retroarch+0x42859)

Seems like it's failing on BurnLoadRom(Neo68KROMActive + 0x700000, 2, 1);, any idea ?

dinkc64 commented 5 years ago

Looks like we'll need a kludge in neo_run for this set to have it allocate the required memory for the main roms. try this: edit neo_run.cpp, search for burnmalloc(ncodesize add this line above it: if (!strcmp("kof98pfe", BurnDrvGetTextA(DRV_NAME))) nCodeSize[nNeoActiveSlot] = 0x720000;

in the driver d_neogeo, remove the extrarom stuff & change a things a bit: if (nRet == 0) { rom = (UINT16*)Neo68KROMActive;

    for (INT32 i = 0; i < 0x100000/2; i++) {
        if (rom[i] == 0x4e7d) rom[i] = 0x4e71;
        if (rom[i] == 0x4e7c) rom[i] = 0x4e75;
    }

    for (INT32 i = 0x700000/2; i < 0x720000/2; i++) {
        if (rom[i] == 0x4e7d) rom[i] = 0x4e71;
        if (rom[i] == 0x4e7c) rom[i] = 0x4e75;
    }
}

.. and should be good :)

barbudreadmon commented 5 years ago

@dinkc64 got the game working with "official" kof98pfe from hbmame (see commit above), some details :

if (!strcmp("kof98pfe", BurnDrvGetTextA(DRV_NAME))) nCodeSize[nNeoActiveSlot] = 0x720000;

I think i understand this part, we need an allocation of 0x700000+0x020000 which is last 68k code rom offset+size, and it was previously failing because fba compute it only from file size by default (which makes me realize that maybe we are over-allocating 68k code memory for the kof2k2omg romset, it's computed 0x3bd4c1+0x400000 while we only need 0x100000+0x400000, but maybe that's not an issue ?).

I got a similar issue with the sound data roms and fixed it like this : https://github.com/libretro/fbalpha/blob/f9f067906613181615aca662baafd281d169300e/src/burn/drv/neogeo/neo_run.cpp#L675 There are 4 roms of 0x400000 each for sound data, which is 0x1000000. However i don't understand why there was no crash with previous version of the implementation (size is the same)

I didn't understand the changes in kof98pfeInit, and actually the game will stop working (black screen after the neogeo logo) if i apply those changes (edit : actually i understand what you are trying to do now, however it's still not working for some reason). Here is the code i tried :

static struct BurnRomInfo kof98pfeRomDesc[] = {
    { "242pfe.p1",  0x100000, 0x23876d95, 1 | BRF_ESS | BRF_PRG }, //  1 68K code
    { "242pfe.p2",  0x400000, 0xadbaa852, 1 | BRF_ESS | BRF_PRG }, //  1 68K code, 2MB zero bytes are added to the end of file so the file size expands to 6MB.
    { "242pfe.p3",  0x020000, 0x930ea34e, 1 | BRF_ESS | BRF_PRG }, //  1 68K code, protections are patched out. 

    { "242pfe.s1",  0x020000, 0x7f4dbf23, 2 | BRF_GRA },           //  2 Text layer tiles / TC531000

    { "242hx73.c1", 0x800000, 0x379654a5, 3 | BRF_GRA },           //  3 Sprite data
    { "242hx73.c2", 0x800000, 0x9c71fa3d, 3 | BRF_GRA },           //  4 
    { "242.c3",     0x800000, 0x22127b4f, 3 | BRF_GRA },           //  5 
    { "242.c4",     0x800000, 0x0b4fa044, 3 | BRF_GRA },           //  6 
    { "242.c5",     0x800000, 0x9d10bed3, 3 | BRF_GRA },           //  7 
    { "242.c6",     0x800000, 0xda07b6a2, 3 | BRF_GRA },           //  8 
    { "242pfe.c7",  0x800000, 0x02f09b2e, 3 | BRF_GRA },           //  9 
    { "242pfe.c8",  0x800000, 0xd43ab3e6, 3 | BRF_GRA },           // 10 

    { "242-mg1.m1", 0x040000, 0x4e7a6b1b, 4 | BRF_ESS | BRF_PRG }, // 11 Z80 code

    { "242.v1",     0x400000, 0xb9ea8051, 5 | BRF_SND },           // 12 Sound data
    { "242.v2",     0x400000, 0xcc11106e, 5 | BRF_SND },           // 13 
    { "242.v3",     0x400000, 0x044ea4e1, 5 | BRF_SND },           // 14 
    { "242.v4",     0x400000, 0x7985ea30, 5 | BRF_SND },           // 15 
};

STDROMPICKEXT(kof98pfe, kof98pfe, neogeo)
STD_ROM_FN(kof98pfe)

static void kof98pfeCallback()
{
    BurnLoadRom(Neo68KROMActive + 0x000000, 0, 1);
    BurnLoadRom(Neo68KROMActive + 0x100000, 1, 1);
    BurnLoadRom(Neo68KROMActive + 0x700000, 2, 1);
    Neo68KROMActive[0x701af4] = 0x4e;
    Neo68KROMActive[0x701af5] = 0x71;
    Neo68KROMActive[0x701b18] = 0x60; // byte-write 0x60
    Neo68KROMActive[0x701ca2] = 0x60; // byte-write 0x60
}

static INT32 kof98pfeInit()
{
    NeoCallbackActive->pInitialise = kof98pfeCallback;

    INT32 nRet = NeoInit();

    if (nRet == 0) {

        UINT16 *rom = (UINT16*)Neo68KROMActive;

        for (INT32 i = 0; i < 0x100000/2; i++) {
            if (rom[i] == 0x4e7d) rom[i] = 0x4e71;
            if (rom[i] == 0x4e7c) rom[i] = 0x4e75;
        }

        for (INT32 i = 0x700000/2; i < 0x720000/2; i++) {
            if (rom[i] == 0x4e7d) rom[i] = 0x4e71;
            if (rom[i] == 0x4e7c) rom[i] = 0x4e75;
        }
    }

    return nRet;
}

struct BurnDriver BurnDrvkof98pfe = {
    "kof98pfe", "kof98", "neogeo", NULL, "2017",
    "KOF'98 (Plus Final Edition)(2017-07-23)\0", NULL, "hack", "Neo Geo MVS",
    NULL, NULL, NULL, NULL,
    BDF_GAME_WORKING | BDF_CLONE | BDF_HACK, 2, HARDWARE_PREFIX_CARTRIDGE | HARDWARE_SNK_NEOGEO, GBF_VSFIGHT, FBF_KOF,
    NULL, kof98pfeRomInfo, kof98pfeRomName, NULL, NULL, NULL, NULL, neogeoInputInfo, neogeoDIPInfo,
    kof98pfeInit, NeoExit, NeoFrame, NeoRender, NeoScan, &NeoRecalcPalette,
    0x1000, 320, 224, 4, 3
};
dinkc64 commented 5 years ago

Nice job figuring it out :) So basically, the rom search & replace code is not needed then, right?

barbudreadmon commented 5 years ago

@dinkc64 it's needed, but i'm just not too sure why

static INT32 kof98pfeInit()
{
    NeoCallbackActive->pInitialise = kof98pfeCallback; // Use this callback when loading the romset

    INT32 nRet = NeoInit();

    if (nRet == 0) {
        kof98pfeExtraROM = (UINT8*)BurnMalloc(0x20000);

        if (BurnLoadRom(kof98pfeExtraROM, 2, 1)) return 1;

        UINT16 *rom = (UINT16*)kof98pfeExtraROM;
        for (INT32 i = 0; i < 0x20000/2; i++) {
            if (rom[i] == 0x4e7d) rom[i] = 0x4e71;
            if (rom[i] == 0x4e7c) rom[i] = 0x4e75;
        }

        rom = (UINT16*)Neo68KROMActive;

        for (INT32 i = 0; i < 0x100000/2; i++) {
            if (rom[i] == 0x4e7d) rom[i] = 0x4e71;
            if (rom[i] == 0x4e7c) rom[i] = 0x4e75;
        }

        SekOpen(0);
        SekMapMemory(kof98pfeExtraROM, 0x900000, 0x91ffff, MAP_ROM);
        SekClose();
    }

    return nRet;
}

works and

static INT32 kof98pfeInit()
{
    NeoCallbackActive->pInitialise = kof98pfeCallback;

    INT32 nRet = NeoInit();

    if (nRet == 0) {

        UINT16 *rom = (UINT16*)Neo68KROMActive;

        for (INT32 i = 0; i < 0x100000/2; i++) {
            if (rom[i] == 0x4e7d) rom[i] = 0x4e71;
            if (rom[i] == 0x4e7c) rom[i] = 0x4e75;
        }

        for (INT32 i = 0x700000/2; i < 0x720000/2; i++) {
            if (rom[i] == 0x4e7d) rom[i] = 0x4e71;
            if (rom[i] == 0x4e7c) rom[i] = 0x4e75;
        }
    }

    return nRet;
}

don't. With the third c68k code rom already loaded, patching directly on Neo68KROMActive makes more sense to me. if (BurnLoadRom(kof98pfeExtraROM, 2, 1)) return 1; is definitely needed (black screen without it), while it's returning false (because BurnLoadRom(Neo68KROMActive + 0x700000, 2, 1); was called in the callback i guess), so i'm not too sure what is happening behind the scene. If you have any explanation i would be curious.

dinkc64 commented 5 years ago

Oh, ok, I must have looked at the wrong code in hbmame then when I came up with that alternate init. oops :) BurnLoadRom shouldn't return bad if you load a rom a second (or third) time - that's odd :/ Try ignoring the load status?

barbudreadmon commented 5 years ago

BurnLoadRom shouldn't return bad if you load a rom a second (or third) time

My bad, it seems the good return value for BurnLoadRom is actually 0, so having the return value equivalent to false is actually a good thing.

I think the code you looked at in hbmame is the right one. You can see the same kind of differences for lastbladsp between hbmame and fba : https://github.com/Robbbert/hbmame/blob/fce87309c706c6e9626bdc735ed82eddef342811/src/hbmame/drivers/nglastblade.cpp#L8-L28 and https://github.com/libretro/fbalpha/blob/89aaee4338869b3f8f10df97023353805846c4bf/src/burn/drv/neogeo/d_neogeo.cpp#L15733-L15770

I don't understand why, in both cases, direct access to Neo68KROMActive doesn't work for this 3rd rom, but you can backport the kof98pfe romset to standalone anyway.