Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ported to Android #53

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open

Conversation

infinitesimalau
Copy link

  • Implement on-screen touch controller
  • Use al_read/al_write for all read instead of fread/fwrite (read from apk)
  • Fixed sprite collision for Android/Linux debug
  • Process Android display events (rotate/switch out etc)
  • Use png instead of tga (startup speed)
  • Added cmake support
  • Added java/gradle wrappers from allegro

ocornut and others added 4 commits December 13, 2019 13:14
…ce drift between perceived cursor and what the game will end up using.
- Implement on-screen touch controller
- Use al_read/al_write for all read instead of fread/fwrite (read from apk)
- Fixed sprite collision for Android/Linux debug
- Process Android display events (rotate/switch out etc)
- Use png instead of tga (startup speed)
- Added cmake support
- Added java/gradle wrappers from allegro
@ocornut
Copy link
Owner

ocornut commented Dec 19, 2019

Hello,
Thanks for the PR.

It is going to be tough to merge this as is.

I will try to implement the TGA>PNG conversion first as a separate commit, then we would split this in the less risky / less arguable changes that are easy to merge and the heavier ones. Lots of the change would need to be explained/justified, but we can do that once we removed some of the bigger changes first.

@infinitesimalau
Copy link
Author

No problem. I'm on holidays for two weeks. I'm happy to answer any question you have when I'm back.

@ocornut
Copy link
Owner

ocornut commented Dec 20, 2019

The ideal would be a first separate PR to use PNG and make sure it works on Windows.
At the time I didn't use PNG because I had issue with the color key / transparency but I sure it must be solvable.

bsittler added a commit to bsittler/meka that referenced this pull request Jun 10, 2023
…al 24 in 1 [Sonic II] (Unl)"

I've been calling it "Real 24 in 1 [Sonic II] (Unl)" but the correct name is not obvious

The label says:

REAL 24 IN 1
NEW GAME

The label also has a game listing in English and Traditional Chinese. Transcription of the English part:

```
 1.SONIC Ⅱ
 2.BARE KNUCKLE
 3.SHINOBI Ⅱ
 4.SUPER MONACO GP
 5.MAGIC ADVENTURE
 6.NINJA GAIDEN
 7.PAC MAN
 8.WOODY POP
 9.COLUMAS
10.PENGO
11.TEDDYBOY-BLUES
12.ASTRD FLASH O
13.ACTION BOY
14.BANK PANIC
15.MACHINEGUN
16.HANG-ON
17.GHOST HOUSE
18.SPY VS SPY
19.SUPER TENNIS
20.SATELLITE 7
21.GREAT SOCCER
22.GREAT BASEBALL 2
23.ROAD FIGHTER
24.PIT POT
```

Chinese label text as transcribed by Google:
```
 1.音速小子二代
 2.格闘3人組
 3.GG忍 二代
 4.超級摩洛哥GP
 5.魔法颱風
 6.忍者外傳
 7.小精靈
 8.玩具磚塊
 9.魔法寶石
10.企鵝推冰
11.泰迪男孩
12.空中戰機
13.青春英雄
14.銀行大盗
15.機關槍
16.摩托賽車
17.鬼屋
18.諜對諜
19.網球
20.衛星七號
21.足球
22.棒球
23.路十六
24.陷阱
```

The cartridge plastic is molded with the word "TIME" where you might expect to see "SEGA" instead

The label also includes art for G.G. Shinobi II and a gradient background (yellow at the top, light green at the bottom)

This is a 2MB ROM containing a menu and 24 games, including 10 Game Gear games, 13 SMS games, and one MSX game with an MSX BIOS replacement. The games: GG: Pengo, Columns, Woody Pop, Pac-Man, Ninja Gaiden, Magical Taruruuto-kun, Super Monaco GP, The GG Shinobi II, Bare Knuckle, Sonic the Hedgehog 2; SMS: Pit Pot, Great Baseball, Great Soccer, Satellite-7, Super Tennis, Spy vs Spy, Ghost House, Hang-On, Machine Gun Joe, Bank Panic, Seishun Scandal, Astro Flash, Teddyboy Blues; MSX: Road Fighter

Dumping this was a bit painful. This is the script I used to dump each of the parts, disconnecting and reconnecting the cartridge in between parts:
```
// Real 24 in 1 [Sonic II] (Unl)
//
// |Size| ID | Name                | ID | Name                |
// |----|----|---------------------|----|---------------------|
// | 32K|0x00|Menu                 |0x01|Pit Pot              |
// |    |0x02|MSX Road Fighter     |0x03|Great Baseball       |
// |    |0x04|Great Soccer         |0x05|Satellite-7          |
// |    |0x06|Super Tennis         |0x07|Spy vs Spy           |
// |    |0x08|Ghost House          |0x09|Hang-On              |
// |    |0x0A|Machine Gun Joe      |0x0B|Bank Panic           |
// |    |0x0C|Seishun Scandal      |0x0D|Astro Flash          |
// |    |0x0E|Teddyboy Blues       |0x0F|Pengo                |
// |    |0x10|Columns              |0x11|Woody Pop            |
// |----|----|---------------------|----|---------------------|
// | 64K|0x12|Pac-Man              |    |                     |
// |----|----|---------------------|----|---------------------|
// |128K|0x14|Ninja Gaiden         |0x18|Magical Taruruuto-kun|
// |    |0x1C|Super Monaco GP      |    |                     |
// |----|----|---------------------|----|---------------------|
// |256K|0x20|The GG Shinobi II    |0x28|Bare Knuckle         |
// |----|----|---------------------|----|---------------------|
// |512K|0x30|Sonic the Hedgehog 2 |    |                     |
//
// NOTE: You will need to disconnect and reconnect between
// game_id values. I have not found a way to reliably
// reconfigure the mapper multiple times without power-cycling
local game_id = 0x00;

// seems the hardware does not work reliably with this
// dumping setup unless you repeat yourself a bunch...
local outer_page_attempts = 3;
local quiesce_retries = 2; // for writes to similar-addressed RAM
local write_retries = 5;

// this allows us to avoid multiple identical (slow!)
// reconfigurations after the configuration has already been
// used for reading
local previous_outer_page = -1;
for (local page = game_id; (address_scale_factor * (page - game_id) * 0x8000) < rom_size; page += 1) {

    local extra_bits =
        ((page >= 0x12) ? 0x81 : 0x40) // >= 64K with mapper, otherwise SMS-GG mode
        | ((page >= 0x14) ? 0x02 : 0x00) // >= 128K
        | ((page >= 0x20) ? 0x04 : 0x00) // >= 256K
        | ((page >= 0x30) ? 0x08 : 0x00) // 512K
        | 0;

    local outer_page = page | extra_bits;

    if (outer_page != previous_outer_page) {
        for (local outer_page_attempt = 0; outer_page_attempt < 3; outer_page_attempt += 1) {
            for (local quiesce_retry = 0; quiesce_retry < quiesce_retries; quiesce_retry += 1) {
                cpu_write(d, address_scale_factor * 0xC000, outer_page);
            }
            for (local write_retry = 0; write_retry < write_retries; write_retry += 1) {
                cpu_write(d, address_scale_factor * 0x0000, outer_page);
            }
            for (local quiesce_retry = 0; quiesce_retry < quiesce_retries; quiesce_retry += 1) {
                cpu_write(d, address_scale_factor * 0xC000, outer_page);
            }
        }
        previous_outer_page = outer_page;
    }

    local inner_page = page & 0x0F & ~extra_bits;

    if (inner_page == 0x00) {
        // possibly missing Sega mapper: use 0x0000..0x7FFF
        for (local quiesce_retry = 0; quiesce_retry < quiesce_retries; quiesce_retry += 1) {
            cpu_write(d, address_scale_factor * 0xDFFE, (inner_page << 1) | 1);
        }
        for (local write_retry = 0; write_retry < write_retries; write_retry += 1) {
            cpu_write(d, address_scale_factor * 0xFFFE, (inner_page << 1) | 1);
        }
        for (local quiesce_retry = 0; quiesce_retry < quiesce_retries; quiesce_retry += 1) {
            cpu_write(d, address_scale_factor * 0xDFFE, (inner_page << 1) | 1);
        }
        cpu_read (d, address_scale_factor * 0x0000, address_scale_factor * 0x8000);
    } else {
        // Sega mapper: use 0x8000..0xBFFF twice
        for (local offset = 0; offset < 2; offset += 1) {
            for (local quiesce_retry = 0; quiesce_retry < quiesce_retries; quiesce_retry += 1) {
                cpu_write(d, address_scale_factor * 0xDFFF, (inner_page << 1) | offset);
            }
            for (local write_retry = 0; write_retry < write_retries; write_retry += 1) {
                cpu_write(d, address_scale_factor * 0xFFFF, (inner_page << 1) | offset);
            }
            for (local quiesce_retry = 0; quiesce_retry < quiesce_retries; quiesce_retry += 1) {
                cpu_write(d, address_scale_factor * 0xDFFF, (inner_page << 1) | offset);
            }
            cpu_read (d, address_scale_factor * 0x8000, address_scale_factor * 0x4000);
        }
    }
}
```

The menu is based on Pengo code, but that copy of Pengo is no longer playable. However there is a separate playable copy of Pengo elsewhere in the ROM. At startup the menu writes:

[0xFFFE=0xB0]

The "➡" arrow cursor is movable and shown below in its initial position. Unlike many Game Gear multicart menus, this one preserves cursor offset while switching screens

Menu screen 1:

```

 ┌────────────────┐
 │  REAL 24 IN 1  │
 └────────────────┘

➡ 1 SONIC Ⅱ          [0x0000=0xBF]; it's [GG] part-30-sonic-the-hedgehog-2-512k.gg
  2 BARE KNUCKLE     [0x0000=0xAF]; it's [GG] part-28-bare-knuckle-256k.gg
  3 SHINOBI Ⅱ        [0x0000=0xA7]; it's [GG] part-20-the-gg-shinobi-ii-256k.gg
  4 SUPER MONACO GP  [0x0000=0x1F]; it's [GG] part-1c-super-monaco-gp-128k.gg
  5 MAGIC ADVENTURE  [0x0000=0x1B]; it's [GG] part-18-magical-taruruuto-kun-128k.gg
  6 NINJA GAIDEN     [0x0000=0x17]; it's [GG] part-14-ninja-gaiden-128k.gg
  7 PAC MAN          [0x0000=0x13]; it's [GG] part-12-pac-man-64k.gg
  8 WOODY POP        [0x0000=0x11]; it's [GG] part-11-woody-pop-32k.gg
  9 COLUMNS          [0x0000=0x10]; it's [GG] part-10-columns-32k.gg
 10 PENGO            [0x0000=0x0F]; it's [GG] part-0f-pengo-32k.gg
 11 TEDDYBOY-BLUES   [0x0000=0x4E]; it's [SMS-GG] part-0e-teddyboy-blues-32k.sms
 12 ASTRO FLASH      [0x0000=0x4D]; it's [SMS-GG] part-0d-astro-flash-32k.sms
```

Menu screen 2:

```

 ┌────────────────┐
 │  REAL 24 IN 1  │
 └────────────────┘

➡13 ACTION BOY       [0x0000=0x4C]; it's [SMS-GG] part-0c-seishun-scandal-32k.sms
 14 BANK PANIC       [0x0000=0x4B]; it's [SMS-GG] part-0b-bank-panic-32k.sms
 15 MACHINEGUN       [0x0000=0x4A]; it's [SMS-GG] part-0a-machine-gun-joe-32k.sms
 16 HANG-ON          [0x0000=0x49]; it's [SMS-GG] part-09-hang-on-32k.sms
 17 GHOST HOUSE      [0x0000=0x48]; it's [SMS-GG] part-08-ghost-house-32k.sms
 18 SPY VS SPY       [0x0000=0x47]; it's [SMS-GG] part-07-spy-vs-spy-32k.sms
 19 SUPER TENNIS     [0x0000=0x46]; it's [SMS-GG] part-06-super-tennis-32k.sms
 20 SATELLITE·7      [0x0000=0x45]; it's [SMS-GG] part-05-satellite-7-32k.sms
 21 GREAT SOCCER     [0x0000=0x44]; it's [SMS-GG] part-04-great-soccer-32k.sms
 22 GREAT BASEBALL   [0x0000=0x43]; it's [SMS-GG] part-03-great-baseball-32k.sms
 23 ROAD FIGHTER     [0x0000=0x42]; it's [SMS-GG] part-02-msx-bios-and-road-fighter-32k.sms
 24 PIT POT          [0x0000=0x41]; it's [SMS-GG] part-01-pit-pot-32k.sms
```

The mapper registers seem to be 0x0000, 0xFFFE, and 0xFFFF. Register 0x0000 is used for outer paging and SMS-GG mode selection. The other two are used for Sega-style paging.

Inferred mapper behavior, not yet tested exhaustively:

0x0000:
- bit 0x80: set when mapping the second megabyte, clear otherwise
- bit 0x40: set when activating SMS-GG mode, clear otherwise
- bits 0x3F: 32KB base page for outer page selection

For paging to work, the base page must be in an eligible region and
all paging-modifiable bits of the 32KB base page must be set

16KB paging mask bits:
- 0x10: when base page bit 0x08 is set and base page > 0x30
- 0x08: when base page bit 0x04 is set and base page > 0x20
- 0x04: when base page bit 0x02 is set and base page > 0x14
- 0x02: when base page bit 0x01 is set and base page > 0x12
- 0x01: always available

0xFFFE: 16KB paging offset for region 0x4000..0x7FFF (restricted by 16KB paging mask)
- 0xB0 is a special value and its meaning is unknown; it leaves the page set to 0x01

0xFFFF: 16KB paging offset for region 0x8000..0xBFFF (restricted by 16KB paging mask)

ROM fingerprint info:

2.0M Real 24 in 1 [Sonic II] (Unl).gg crc32:de6471e8 mekacrc:0E01DB0FE65FBA08 md5:d8cadcb912565e410f4278c516f561e8 sha1:763a3cdbfac247a90009f396bf9691ca6024b9de sha256:3054ad4c1d9ba02ba53e5b14d2f476c6c3525ff9fda339ef0d49383d6fd959d0

32K part-00-menu-32k.gg crc32:d80fb38b mekacrc:A19A21C2FEB5CC63 md5:e0ee46da13c7b89ffbcc40dc86a70b47 sha1:482e3563dde051e57bf40a60e5b84e208b134f65 sha256:218106d54268cf7a39a4d1f9c4317b5556df7645e7a16e8fa866b3bfa3a6c11d

32K part-01-pit-pot-32k.sms crc32:f81ab71e mekacrc:CA42846BB2AE8B1A md5:b3e6b1285bf8b820ca1344c7c4519efa sha1:55036c365d7d4496c5c5e0bfd01c13dfdb1a79f1 sha256:6679ea24710cf51b3aaa5fbee043e5ed6c446912cbc4729ab3fe4668424d1877

32K part-02-msx-bios-and-road-fighter-32k.sms crc32:e8d8e99c mekacrc:3395440A4DC7983E md5:7e82a5af56942c64c288c54050ea16fd sha1:9ed1d924035d94c7dad56644b58de88bc7d45612 sha256:01fd02d70e1672e085496c479945a91dc82362a1c7435fd05476c76538a3e0c3

32K part-03-great-baseball-32k.sms crc32:aafafd51 mekacrc:B478FD7132EF8ABB md5:ab3e87f4981bda8c486392719471ef08 sha1:9133fb22586ab10ee142192541ceb368b9b02540 sha256:8afd26d8aa991fee9e755d53cd0d2ee6f18a058580d44b5240a4c70d8997dd0e

32K part-04-great-soccer-32k.sms crc32:be711818 mekacrc:7CB0BCEF29C11827 md5:cecccff2d09d3cc705d848b28037e267 sha1:41d55da9ed00124c570d9964494b791e09d93af8 sha256:b48ce6a09946941fdf62e8ebf611fc1706344e26ea230bb206ba98cf04e9fbd2

32K part-05-satellite-7-32k.sms crc32:eb9a0359 mekacrc:C30BB9170D4D8E7A md5:7cb52be125ef66daa5e7a6e971a2a97f sha1:be0ace7ed8f1f1ab6fa51dfaa3ba2dd167ab3863 sha256:3adcd01767ee06949a930b88b76f9e2d8c89031c41e289af9d2e4290455ee5c1

32K part-06-super-tennis-32k.sms crc32:95d4c673 mekacrc:FEA3F1C357520CF6 md5:6d135ff05b6d440fa329cc060e559244 sha1:62b323b7b3188b2e0557e3e6d799edc71813c82e sha256:aa07700850080a8276bc518183e09035449a73e9c697415555bc14eca80e539b

32K part-07-spy-vs-spy-32k.sms crc32:f13a28c0 mekacrc:98EC9FA8477AEC88 md5:324741e68234ae80ff3df8bc3f411557 sha1:fd7d1bee1ca42c6d962780f21d5ad138b792db59 sha256:bcba12678775542b59694fc8fe3945530490cdd92a2bfafb07f74b189fa03ede

32K part-08-ghost-house-32k.sms crc32:317451a3 mekacrc:A5771FE4EC52960D md5:343210de693491444b452df7b665921d sha1:9917f8f06ed4c99b71d58d8a03fbea13330c84a1 sha256:c690ae4bff9711c0244e9a2ab18a579a429b29191dcc993f0ed5a496b472cfd3

32K part-09-hang-on-32k.sms crc32:40cedfd9 mekacrc:02A62976104874ED md5:5c25b6b38963fc513958a26e64c591d4 sha1:5726c7f7948612ca42daed96ded45745393bd80a sha256:5a2ecca3d78ae9aa8a6ac2c1775122cfdce3744898032ce5763c0017350e58ce

32K part-0a-machine-gun-joe-32k.sms crc32:9a94c7cc mekacrc:5C858AC9BD4714B4 md5:02906381c66601fb49b10bed123455d4 sha1:03a8a50b3b9e97ea5e10d7e094d287b51ca477af sha256:3981649682a895772012a769e8296e24e660ac4fc4102ecfbb747d53d18cee3e

32K part-0b-bank-panic-32k.sms crc32:46e1c722 mekacrc:EBA230C857CA76E4 md5:00a1f4b983ac30d05dd7cfb9bdbb2ee7 sha1:b05ac9fd2478d69f8f3bdd96ad86bbec482541f1 sha256:5c6e1f75255de9d1a7fc7d10db0ea9126633eedd018873597f78b312d2a80032

32K part-0c-seishun-scandal-32k.sms crc32:637dbbef mekacrc:D41A76F3C3411E87 md5:c021bce5a58cfbf513af253a25bc29bd sha1:2c39fdf814e223e2dc14646941a276879ae14c64 sha256:3a1df738527b578e248b6650c9a1498abaf9bef6da813a172dfae0a63be4e746

32K part-0d-astro-flash-32k.sms crc32:b1267d52 mekacrc:13171118D3218C2D md5:4c13f02b69c266ffea80fd7aba160bb2 sha1:b4e2483fbfe9e4c23a6fb14e755e5aa8c6ecece0 sha256:514484c1d4156fc77e4cefcd39cffd71f3e126c708420100ebb07e4972dc3486

32K part-0e-teddyboy-blues-32k.sms crc32:ed8dee80 mekacrc:E805AC40FA83F3B7 md5:acb4e818db613dc6f4737ef21302dc7c sha1:19d03cefeca768b08e708a161d3d6f5398450f49 sha256:e99eb0859de5801fddcf88a7d87651a6209bfe5df4f75bbd85c0b311edf6704c

32K part-0f-pengo-32k.gg crc32:6bd56e95 mekacrc:6C3C703170EBD587 md5:69bf00297cad6ee0bb6046c8084e5e37 sha1:126654feb2975e3a52431d29cefcafbd37bb2ef5 sha256:1c221bcb0b7ef67e644a695b78cb4dd851b800202ee13fd8d03fb099e533c46a

32K part-10-columns-32k.gg crc32:7316423e mekacrc:1DE54704572F032A md5:bfcf0e46ec8df8a51776bd2315b859fc sha1:26d407e8389a5564b836f0a68585a935ca019802 sha256:73f6012c1a92bcc96497668cdecfb3b592162c6b39a8c7efb8b9dc3931380561

32K part-11-woody-pop-32k.gg crc32:0c6e4769 mekacrc:9D2A47DDDF12FD27 md5:3885c64be1dc990918adebcbe9675855 sha1:58516c23f1e1b87daebda1b971fab278a6e7ce59 sha256:0c23fccffa3160b6754fa54ecbf08d3828f5e60a64dbe4203109715644ad94ce

64K part-12-pac-man-64k.gg crc32:dd001845 mekacrc:730EF79FF63F971D md5:fa8940099182cb57dc7eaa3466f43859 sha1:7d4521b55386eb7f06fed6b143c0e97bdfab264b sha256:d5b2c6fc05041802db1e5506ba9df8edf5415bbfe7c5852620cdc5f8bbb261f9

128K part-14-ninja-gaiden-128k.gg crc32:7ca9e75e mekacrc:430F39097D9A3025 md5:d9201f5ced95468d893e0f1b24438eea sha1:86681e978b3c0088d077afe850f4f9d278f5fa30 sha256:dc574770c07c5fc58b9cac371ac16307166a000df9a4015d0a2286626c2e9a72

128K part-18-magical-taruruuto-kun-128k.gg crc32:11d11451 mekacrc:1062032CD75EE446 md5:04fc405128c80de8358903a2a3b967d9 sha1:96fa1d2a82e5d0ccc3f2b7b6f1c85a3e098d048a sha256:bbcb5abea2e18b8d9e4a852b32f0b65e6aea4556f3deb70540dccb91d01b3c1b

128K part-1c-super-monaco-gp-128k.gg crc32:08ebcea1 mekacrc:9D34492A4095AD3A md5:1737583c8a857c84798ff254167025d9 sha1:69ffd99a1589bb77ca9943cbf08e07996dd0e8da sha256:08f11a8927879b681e2b23c7f3bb103002dd5468b3a58e1d6cff7bc0789af4ed

256K part-20-the-gg-shinobi-ii-256k.gg crc32:1f8f7d7c mekacrc:5312EB420F84AA31 md5:735c85911371d3c8fb18c33093307718 sha1:68e2f2b58ecbd038a4c8a9d004f2b9dee8a3b88d sha256:545d4b460b486d29d9f42029e91896eef5b0331b6cb9ea86df0ccc5e42d27de5

256K part-28-bare-knuckle-256k.gg crc32:dacc9061 mekacrc:73DB350D2119AB8B md5:80257cab0a9ed965520beeaba5bd5c9f sha1:815a1c910d016d374fff02604b521f147f529291 sha256:a027321ec909bb69ca44486a8e04193915cf733c88974a7dbc7d8551841f4461

512K part-30-sonic-the-hedgehog-2-512k.gg crc32:cda97bb3 mekacrc:DB692161E347F020 md5:6685be3154439062030746a179589090 sha1:9bd6690330a35e6d3ad6c0230c9d8984a2e2de0c sha256:8c4b4207d8c6be2c5a9d9f1ab0d3df5c76d65ce9e26ae6c9e1c6b45babf3a9b7
bsittler added a commit to bsittler/meka that referenced this pull request Jun 10, 2023
commit 7fc13ae
Author: Benjamin C. Wiley Sittler <bsittler@gmail.com>
Date:   Fri Jun 9 23:16:30 2023 -0700

    Add mapper `ocornut#53` MAPPER_GG_Real_24_in_1_FFFE_0000_FFFF for "Real 24 in 1 [Sonic II] (Unl)"

    I've been calling it "Real 24 in 1 [Sonic II] (Unl)" but the correct name is not obvious

    The label says:

    REAL 24 IN 1
    NEW GAME

    The label also has a game listing in English and Traditional Chinese. Transcription of the English part:

    ```
     1.SONIC Ⅱ
     2.BARE KNUCKLE
     3.SHINOBI Ⅱ
     4.SUPER MONACO GP
     5.MAGIC ADVENTURE
     6.NINJA GAIDEN
     7.PAC MAN
     8.WOODY POP
     9.COLUMAS
    10.PENGO
    11.TEDDYBOY-BLUES
    12.ASTRD FLASH O
    13.ACTION BOY
    14.BANK PANIC
    15.MACHINEGUN
    16.HANG-ON
    17.GHOST HOUSE
    18.SPY VS SPY
    19.SUPER TENNIS
    20.SATELLITE 7
    21.GREAT SOCCER
    22.GREAT BASEBALL 2
    23.ROAD FIGHTER
    24.PIT POT
    ```

    Chinese label text as transcribed by Google:
    ```
     1.音速小子二代
     2.格闘3人組
     3.GG忍 二代
     4.超級摩洛哥GP
     5.魔法颱風
     6.忍者外傳
     7.小精靈
     8.玩具磚塊
     9.魔法寶石
    10.企鵝推冰
    11.泰迪男孩
    12.空中戰機
    13.青春英雄
    14.銀行大盗
    15.機關槍
    16.摩托賽車
    17.鬼屋
    18.諜對諜
    19.網球
    20.衛星七號
    21.足球
    22.棒球
    23.路十六
    24.陷阱
    ```

    The cartridge plastic is molded with the word "TIME" where you might expect to see "SEGA" instead

    The label also includes art for G.G. Shinobi II and a gradient background (yellow at the top, light green at the bottom)

    This is a 2MB ROM containing a menu and 24 games, including 10 Game Gear games, 13 SMS games, and one MSX game with an MSX BIOS replacement. The games: GG: Pengo, Columns, Woody Pop, Pac-Man, Ninja Gaiden, Magical Taruruuto-kun, Super Monaco GP, The GG Shinobi II, Bare Knuckle, Sonic the Hedgehog 2; SMS: Pit Pot, Great Baseball, Great Soccer, Satellite-7, Super Tennis, Spy vs Spy, Ghost House, Hang-On, Machine Gun Joe, Bank Panic, Seishun Scandal, Astro Flash, Teddyboy Blues; MSX: Road Fighter

    Dumping this was a bit painful. This is the script I used to dump each of the parts, disconnecting and reconnecting the cartridge in between parts:
    ```
    // Real 24 in 1 [Sonic II] (Unl)
    //
    // |Size| ID | Name                | ID | Name                |
    // |----|----|---------------------|----|---------------------|
    // | 32K|0x00|Menu                 |0x01|Pit Pot              |
    // |    |0x02|MSX Road Fighter     |0x03|Great Baseball       |
    // |    |0x04|Great Soccer         |0x05|Satellite-7          |
    // |    |0x06|Super Tennis         |0x07|Spy vs Spy           |
    // |    |0x08|Ghost House          |0x09|Hang-On              |
    // |    |0x0A|Machine Gun Joe      |0x0B|Bank Panic           |
    // |    |0x0C|Seishun Scandal      |0x0D|Astro Flash          |
    // |    |0x0E|Teddyboy Blues       |0x0F|Pengo                |
    // |    |0x10|Columns              |0x11|Woody Pop            |
    // |----|----|---------------------|----|---------------------|
    // | 64K|0x12|Pac-Man              |    |                     |
    // |----|----|---------------------|----|---------------------|
    // |128K|0x14|Ninja Gaiden         |0x18|Magical Taruruuto-kun|
    // |    |0x1C|Super Monaco GP      |    |                     |
    // |----|----|---------------------|----|---------------------|
    // |256K|0x20|The GG Shinobi II    |0x28|Bare Knuckle         |
    // |----|----|---------------------|----|---------------------|
    // |512K|0x30|Sonic the Hedgehog 2 |    |                     |
    //
    // NOTE: You will need to disconnect and reconnect between
    // game_id values. I have not found a way to reliably
    // reconfigure the mapper multiple times without power-cycling
    local game_id = 0x00;

    // seems the hardware does not work reliably with this
    // dumping setup unless you repeat yourself a bunch...
    local outer_page_attempts = 3;
    local quiesce_retries = 2; // for writes to similar-addressed RAM
    local write_retries = 5;

    // this allows us to avoid multiple identical (slow!)
    // reconfigurations after the configuration has already been
    // used for reading
    local previous_outer_page = -1;
    for (local page = game_id; (address_scale_factor * (page - game_id) * 0x8000) < rom_size; page += 1) {

        local extra_bits =
            ((page >= 0x12) ? 0x81 : 0x40) // >= 64K with mapper, otherwise SMS-GG mode
            | ((page >= 0x14) ? 0x02 : 0x00) // >= 128K
            | ((page >= 0x20) ? 0x04 : 0x00) // >= 256K
            | ((page >= 0x30) ? 0x08 : 0x00) // 512K
            | 0;

        local outer_page = page | extra_bits;

        if (outer_page != previous_outer_page) {
            for (local outer_page_attempt = 0; outer_page_attempt < 3; outer_page_attempt += 1) {
                for (local quiesce_retry = 0; quiesce_retry < quiesce_retries; quiesce_retry += 1) {
                    cpu_write(d, address_scale_factor * 0xC000, outer_page);
                }
                for (local write_retry = 0; write_retry < write_retries; write_retry += 1) {
                    cpu_write(d, address_scale_factor * 0x0000, outer_page);
                }
                for (local quiesce_retry = 0; quiesce_retry < quiesce_retries; quiesce_retry += 1) {
                    cpu_write(d, address_scale_factor * 0xC000, outer_page);
                }
            }
            previous_outer_page = outer_page;
        }

        local inner_page = page & 0x0F & ~extra_bits;

        if (inner_page == 0x00) {
            // possibly missing Sega mapper: use 0x0000..0x7FFF
            for (local quiesce_retry = 0; quiesce_retry < quiesce_retries; quiesce_retry += 1) {
                cpu_write(d, address_scale_factor * 0xDFFE, (inner_page << 1) | 1);
            }
            for (local write_retry = 0; write_retry < write_retries; write_retry += 1) {
                cpu_write(d, address_scale_factor * 0xFFFE, (inner_page << 1) | 1);
            }
            for (local quiesce_retry = 0; quiesce_retry < quiesce_retries; quiesce_retry += 1) {
                cpu_write(d, address_scale_factor * 0xDFFE, (inner_page << 1) | 1);
            }
            cpu_read (d, address_scale_factor * 0x0000, address_scale_factor * 0x8000);
        } else {
            // Sega mapper: use 0x8000..0xBFFF twice
            for (local offset = 0; offset < 2; offset += 1) {
                for (local quiesce_retry = 0; quiesce_retry < quiesce_retries; quiesce_retry += 1) {
                    cpu_write(d, address_scale_factor * 0xDFFF, (inner_page << 1) | offset);
                }
                for (local write_retry = 0; write_retry < write_retries; write_retry += 1) {
                    cpu_write(d, address_scale_factor * 0xFFFF, (inner_page << 1) | offset);
                }
                for (local quiesce_retry = 0; quiesce_retry < quiesce_retries; quiesce_retry += 1) {
                    cpu_write(d, address_scale_factor * 0xDFFF, (inner_page << 1) | offset);
                }
                cpu_read (d, address_scale_factor * 0x8000, address_scale_factor * 0x4000);
            }
        }
    }
    ```

    The menu is based on Pengo code, but that copy of Pengo is no longer playable. However there is a separate playable copy of Pengo elsewhere in the ROM. At startup the menu writes:

    [0xFFFE=0xB0]

    The "➡" arrow cursor is movable and shown below in its initial position. Unlike many Game Gear multicart menus, this one preserves cursor offset while switching screens

    Menu screen 1:

    ```

     ┌────────────────┐
     │  REAL 24 IN 1  │
     └────────────────┘

    ➡ 1 SONIC Ⅱ          [0x0000=0xBF]; it's [GG] part-30-sonic-the-hedgehog-2-512k.gg
      2 BARE KNUCKLE     [0x0000=0xAF]; it's [GG] part-28-bare-knuckle-256k.gg
      3 SHINOBI Ⅱ        [0x0000=0xA7]; it's [GG] part-20-the-gg-shinobi-ii-256k.gg
      4 SUPER MONACO GP  [0x0000=0x1F]; it's [GG] part-1c-super-monaco-gp-128k.gg
      5 MAGIC ADVENTURE  [0x0000=0x1B]; it's [GG] part-18-magical-taruruuto-kun-128k.gg
      6 NINJA GAIDEN     [0x0000=0x17]; it's [GG] part-14-ninja-gaiden-128k.gg
      7 PAC MAN          [0x0000=0x13]; it's [GG] part-12-pac-man-64k.gg
      8 WOODY POP        [0x0000=0x11]; it's [GG] part-11-woody-pop-32k.gg
      9 COLUMNS          [0x0000=0x10]; it's [GG] part-10-columns-32k.gg
     10 PENGO            [0x0000=0x0F]; it's [GG] part-0f-pengo-32k.gg
     11 TEDDYBOY-BLUES   [0x0000=0x4E]; it's [SMS-GG] part-0e-teddyboy-blues-32k.sms
     12 ASTRO FLASH      [0x0000=0x4D]; it's [SMS-GG] part-0d-astro-flash-32k.sms
    ```

    Menu screen 2:

    ```

     ┌────────────────┐
     │  REAL 24 IN 1  │
     └────────────────┘

    ➡13 ACTION BOY       [0x0000=0x4C]; it's [SMS-GG] part-0c-seishun-scandal-32k.sms
     14 BANK PANIC       [0x0000=0x4B]; it's [SMS-GG] part-0b-bank-panic-32k.sms
     15 MACHINEGUN       [0x0000=0x4A]; it's [SMS-GG] part-0a-machine-gun-joe-32k.sms
     16 HANG-ON          [0x0000=0x49]; it's [SMS-GG] part-09-hang-on-32k.sms
     17 GHOST HOUSE      [0x0000=0x48]; it's [SMS-GG] part-08-ghost-house-32k.sms
     18 SPY VS SPY       [0x0000=0x47]; it's [SMS-GG] part-07-spy-vs-spy-32k.sms
     19 SUPER TENNIS     [0x0000=0x46]; it's [SMS-GG] part-06-super-tennis-32k.sms
     20 SATELLITE·7      [0x0000=0x45]; it's [SMS-GG] part-05-satellite-7-32k.sms
     21 GREAT SOCCER     [0x0000=0x44]; it's [SMS-GG] part-04-great-soccer-32k.sms
     22 GREAT BASEBALL   [0x0000=0x43]; it's [SMS-GG] part-03-great-baseball-32k.sms
     23 ROAD FIGHTER     [0x0000=0x42]; it's [SMS-GG] part-02-msx-bios-and-road-fighter-32k.sms
     24 PIT POT          [0x0000=0x41]; it's [SMS-GG] part-01-pit-pot-32k.sms
    ```

    The mapper registers seem to be 0x0000, 0xFFFE, and 0xFFFF. Register 0x0000 is used for outer paging and SMS-GG mode selection. The other two are used for Sega-style paging.

    Inferred mapper behavior, not yet tested exhaustively:

    0x0000:
    - bit 0x80: set when mapping the second megabyte, clear otherwise
    - bit 0x40: set when activating SMS-GG mode, clear otherwise
    - bits 0x3F: 32KB base page for outer page selection

    For paging to work, the base page must be in an eligible region and
    all paging-modifiable bits of the 32KB base page must be set

    16KB paging mask bits:
    - 0x10: when base page bit 0x08 is set and base page > 0x30
    - 0x08: when base page bit 0x04 is set and base page > 0x20
    - 0x04: when base page bit 0x02 is set and base page > 0x14
    - 0x02: when base page bit 0x01 is set and base page > 0x12
    - 0x01: always available

    0xFFFE: 16KB paging offset for region 0x4000..0x7FFF (restricted by 16KB paging mask)
    - 0xB0 is a special value and its meaning is unknown; it leaves the page set to 0x01

    0xFFFF: 16KB paging offset for region 0x8000..0xBFFF (restricted by 16KB paging mask)

    ROM fingerprint info:

    2.0M Real 24 in 1 [Sonic II] (Unl).gg crc32:de6471e8 mekacrc:0E01DB0FE65FBA08 md5:d8cadcb912565e410f4278c516f561e8 sha1:763a3cdbfac247a90009f396bf9691ca6024b9de sha256:3054ad4c1d9ba02ba53e5b14d2f476c6c3525ff9fda339ef0d49383d6fd959d0

    32K part-00-menu-32k.gg crc32:d80fb38b mekacrc:A19A21C2FEB5CC63 md5:e0ee46da13c7b89ffbcc40dc86a70b47 sha1:482e3563dde051e57bf40a60e5b84e208b134f65 sha256:218106d54268cf7a39a4d1f9c4317b5556df7645e7a16e8fa866b3bfa3a6c11d

    32K part-01-pit-pot-32k.sms crc32:f81ab71e mekacrc:CA42846BB2AE8B1A md5:b3e6b1285bf8b820ca1344c7c4519efa sha1:55036c365d7d4496c5c5e0bfd01c13dfdb1a79f1 sha256:6679ea24710cf51b3aaa5fbee043e5ed6c446912cbc4729ab3fe4668424d1877

    32K part-02-msx-bios-and-road-fighter-32k.sms crc32:e8d8e99c mekacrc:3395440A4DC7983E md5:7e82a5af56942c64c288c54050ea16fd sha1:9ed1d924035d94c7dad56644b58de88bc7d45612 sha256:01fd02d70e1672e085496c479945a91dc82362a1c7435fd05476c76538a3e0c3

    32K part-03-great-baseball-32k.sms crc32:aafafd51 mekacrc:B478FD7132EF8ABB md5:ab3e87f4981bda8c486392719471ef08 sha1:9133fb22586ab10ee142192541ceb368b9b02540 sha256:8afd26d8aa991fee9e755d53cd0d2ee6f18a058580d44b5240a4c70d8997dd0e

    32K part-04-great-soccer-32k.sms crc32:be711818 mekacrc:7CB0BCEF29C11827 md5:cecccff2d09d3cc705d848b28037e267 sha1:41d55da9ed00124c570d9964494b791e09d93af8 sha256:b48ce6a09946941fdf62e8ebf611fc1706344e26ea230bb206ba98cf04e9fbd2

    32K part-05-satellite-7-32k.sms crc32:eb9a0359 mekacrc:C30BB9170D4D8E7A md5:7cb52be125ef66daa5e7a6e971a2a97f sha1:be0ace7ed8f1f1ab6fa51dfaa3ba2dd167ab3863 sha256:3adcd01767ee06949a930b88b76f9e2d8c89031c41e289af9d2e4290455ee5c1

    32K part-06-super-tennis-32k.sms crc32:95d4c673 mekacrc:FEA3F1C357520CF6 md5:6d135ff05b6d440fa329cc060e559244 sha1:62b323b7b3188b2e0557e3e6d799edc71813c82e sha256:aa07700850080a8276bc518183e09035449a73e9c697415555bc14eca80e539b

    32K part-07-spy-vs-spy-32k.sms crc32:f13a28c0 mekacrc:98EC9FA8477AEC88 md5:324741e68234ae80ff3df8bc3f411557 sha1:fd7d1bee1ca42c6d962780f21d5ad138b792db59 sha256:bcba12678775542b59694fc8fe3945530490cdd92a2bfafb07f74b189fa03ede

    32K part-08-ghost-house-32k.sms crc32:317451a3 mekacrc:A5771FE4EC52960D md5:343210de693491444b452df7b665921d sha1:9917f8f06ed4c99b71d58d8a03fbea13330c84a1 sha256:c690ae4bff9711c0244e9a2ab18a579a429b29191dcc993f0ed5a496b472cfd3

    32K part-09-hang-on-32k.sms crc32:40cedfd9 mekacrc:02A62976104874ED md5:5c25b6b38963fc513958a26e64c591d4 sha1:5726c7f7948612ca42daed96ded45745393bd80a sha256:5a2ecca3d78ae9aa8a6ac2c1775122cfdce3744898032ce5763c0017350e58ce

    32K part-0a-machine-gun-joe-32k.sms crc32:9a94c7cc mekacrc:5C858AC9BD4714B4 md5:02906381c66601fb49b10bed123455d4 sha1:03a8a50b3b9e97ea5e10d7e094d287b51ca477af sha256:3981649682a895772012a769e8296e24e660ac4fc4102ecfbb747d53d18cee3e

    32K part-0b-bank-panic-32k.sms crc32:46e1c722 mekacrc:EBA230C857CA76E4 md5:00a1f4b983ac30d05dd7cfb9bdbb2ee7 sha1:b05ac9fd2478d69f8f3bdd96ad86bbec482541f1 sha256:5c6e1f75255de9d1a7fc7d10db0ea9126633eedd018873597f78b312d2a80032

    32K part-0c-seishun-scandal-32k.sms crc32:637dbbef mekacrc:D41A76F3C3411E87 md5:c021bce5a58cfbf513af253a25bc29bd sha1:2c39fdf814e223e2dc14646941a276879ae14c64 sha256:3a1df738527b578e248b6650c9a1498abaf9bef6da813a172dfae0a63be4e746

    32K part-0d-astro-flash-32k.sms crc32:b1267d52 mekacrc:13171118D3218C2D md5:4c13f02b69c266ffea80fd7aba160bb2 sha1:b4e2483fbfe9e4c23a6fb14e755e5aa8c6ecece0 sha256:514484c1d4156fc77e4cefcd39cffd71f3e126c708420100ebb07e4972dc3486

    32K part-0e-teddyboy-blues-32k.sms crc32:ed8dee80 mekacrc:E805AC40FA83F3B7 md5:acb4e818db613dc6f4737ef21302dc7c sha1:19d03cefeca768b08e708a161d3d6f5398450f49 sha256:e99eb0859de5801fddcf88a7d87651a6209bfe5df4f75bbd85c0b311edf6704c

    32K part-0f-pengo-32k.gg crc32:6bd56e95 mekacrc:6C3C703170EBD587 md5:69bf00297cad6ee0bb6046c8084e5e37 sha1:126654feb2975e3a52431d29cefcafbd37bb2ef5 sha256:1c221bcb0b7ef67e644a695b78cb4dd851b800202ee13fd8d03fb099e533c46a

    32K part-10-columns-32k.gg crc32:7316423e mekacrc:1DE54704572F032A md5:bfcf0e46ec8df8a51776bd2315b859fc sha1:26d407e8389a5564b836f0a68585a935ca019802 sha256:73f6012c1a92bcc96497668cdecfb3b592162c6b39a8c7efb8b9dc3931380561

    32K part-11-woody-pop-32k.gg crc32:0c6e4769 mekacrc:9D2A47DDDF12FD27 md5:3885c64be1dc990918adebcbe9675855 sha1:58516c23f1e1b87daebda1b971fab278a6e7ce59 sha256:0c23fccffa3160b6754fa54ecbf08d3828f5e60a64dbe4203109715644ad94ce

    64K part-12-pac-man-64k.gg crc32:dd001845 mekacrc:730EF79FF63F971D md5:fa8940099182cb57dc7eaa3466f43859 sha1:7d4521b55386eb7f06fed6b143c0e97bdfab264b sha256:d5b2c6fc05041802db1e5506ba9df8edf5415bbfe7c5852620cdc5f8bbb261f9

    128K part-14-ninja-gaiden-128k.gg crc32:7ca9e75e mekacrc:430F39097D9A3025 md5:d9201f5ced95468d893e0f1b24438eea sha1:86681e978b3c0088d077afe850f4f9d278f5fa30 sha256:dc574770c07c5fc58b9cac371ac16307166a000df9a4015d0a2286626c2e9a72

    128K part-18-magical-taruruuto-kun-128k.gg crc32:11d11451 mekacrc:1062032CD75EE446 md5:04fc405128c80de8358903a2a3b967d9 sha1:96fa1d2a82e5d0ccc3f2b7b6f1c85a3e098d048a sha256:bbcb5abea2e18b8d9e4a852b32f0b65e6aea4556f3deb70540dccb91d01b3c1b

    128K part-1c-super-monaco-gp-128k.gg crc32:08ebcea1 mekacrc:9D34492A4095AD3A md5:1737583c8a857c84798ff254167025d9 sha1:69ffd99a1589bb77ca9943cbf08e07996dd0e8da sha256:08f11a8927879b681e2b23c7f3bb103002dd5468b3a58e1d6cff7bc0789af4ed

    256K part-20-the-gg-shinobi-ii-256k.gg crc32:1f8f7d7c mekacrc:5312EB420F84AA31 md5:735c85911371d3c8fb18c33093307718 sha1:68e2f2b58ecbd038a4c8a9d004f2b9dee8a3b88d sha256:545d4b460b486d29d9f42029e91896eef5b0331b6cb9ea86df0ccc5e42d27de5

    256K part-28-bare-knuckle-256k.gg crc32:dacc9061 mekacrc:73DB350D2119AB8B md5:80257cab0a9ed965520beeaba5bd5c9f sha1:815a1c910d016d374fff02604b521f147f529291 sha256:a027321ec909bb69ca44486a8e04193915cf733c88974a7dbc7d8551841f4461

    512K part-30-sonic-the-hedgehog-2-512k.gg crc32:cda97bb3 mekacrc:DB692161E347F020 md5:6685be3154439062030746a179589090 sha1:9bd6690330a35e6d3ad6c0230c9d8984a2e2de0c sha256:8c4b4207d8c6be2c5a9d9f1ab0d3df5c76d65ce9e26ae6c9e1c6b45babf3a9b7
bsittler added a commit to bsittler/meka that referenced this pull request Jun 10, 2023
…al 24 in 1 [Sonic II] (Unl)"

I've been calling it "Real 24 in 1 [Sonic II] (Unl)" but the correct name is not obvious

The label says:

REAL 24 IN 1
NEW GAME

The label also has a game listing in English and Traditional Chinese. Transcription of the English part:

```
 1.SONIC Ⅱ
 2.BARE KNUCKLE
 3.SHINOBI Ⅱ
 4.SUPER MONACO GP
 5.MAGIC ADVENTURE
 6.NINJA GAIDEN
 7.PAC MAN
 8.WOODY POP
 9.COLUMAS
10.PENGO
11.TEDDYBOY-BLUES
12.ASTRD FLASH O
13.ACTION BOY
14.BANK PANIC
15.MACHINEGUN
16.HANG-ON
17.GHOST HOUSE
18.SPY VS SPY
19.SUPER TENNIS
20.SATELLITE 7
21.GREAT SOCCER
22.GREAT BASEBALL 2
23.ROAD FIGHTER
24.PIT POT
```

Chinese label text as transcribed by Google:
```
 1.音速小子二代
 2.格闘3人組
 3.GG忍 二代
 4.超級摩洛哥GP
 5.魔法颱風
 6.忍者外傳
 7.小精靈
 8.玩具磚塊
 9.魔法寶石
10.企鵝推冰
11.泰迪男孩
12.空中戰機
13.青春英雄
14.銀行大盗
15.機關槍
16.摩托賽車
17.鬼屋
18.諜對諜
19.網球
20.衛星七號
21.足球
22.棒球
23.路十六
24.陷阱
```

The cartridge plastic is molded with the word "TIME" where you might expect to see "SEGA" instead

The label also includes art for G.G. Shinobi II and a gradient background (yellow at the top, light green at the bottom)

This is a 2MB ROM containing a menu and 24 games, including 10 Game Gear games, 13 SMS games, and one MSX game with an MSX BIOS replacement. The games: GG: Pengo, Columns, Woody Pop, Pac-Man, Ninja Gaiden, Magical Taruruuto-kun, Super Monaco GP, The GG Shinobi II, Bare Knuckle, Sonic the Hedgehog 2; SMS: Pit Pot, Great Baseball, Great Soccer, Satellite-7, Super Tennis, Spy vs Spy, Ghost House, Hang-On, Machine Gun Joe, Bank Panic, Seishun Scandal, Astro Flash, Teddyboy Blues; MSX: Road Fighter

Dumping this was a bit painful. This is the script I used to dump each of the parts, disconnecting and reconnecting the cartridge in between parts:
```
// Real 24 in 1 [Sonic II] (Unl)
//
// |Size| ID | Name                | ID | Name                |
// |----|----|---------------------|----|---------------------|
// | 32K|0x00|Menu                 |0x01|Pit Pot              |
// |    |0x02|MSX Road Fighter     |0x03|Great Baseball       |
// |    |0x04|Great Soccer         |0x05|Satellite-7          |
// |    |0x06|Super Tennis         |0x07|Spy vs Spy           |
// |    |0x08|Ghost House          |0x09|Hang-On              |
// |    |0x0A|Machine Gun Joe      |0x0B|Bank Panic           |
// |    |0x0C|Seishun Scandal      |0x0D|Astro Flash          |
// |    |0x0E|Teddyboy Blues       |0x0F|Pengo                |
// |    |0x10|Columns              |0x11|Woody Pop            |
// |----|----|---------------------|----|---------------------|
// | 64K|0x12|Pac-Man              |    |                     |
// |----|----|---------------------|----|---------------------|
// |128K|0x14|Ninja Gaiden         |0x18|Magical Taruruuto-kun|
// |    |0x1C|Super Monaco GP      |    |                     |
// |----|----|---------------------|----|---------------------|
// |256K|0x20|The GG Shinobi II    |0x28|Bare Knuckle         |
// |----|----|---------------------|----|---------------------|
// |512K|0x30|Sonic the Hedgehog 2 |    |                     |
//
// NOTE: You will need to disconnect and reconnect between
// game_id values. I have not found a way to reliably
// reconfigure the mapper multiple times without power-cycling
local game_id = 0x00;

// seems the hardware does not work reliably with this
// dumping setup unless you repeat yourself a bunch...
local outer_page_attempts = 3;
local quiesce_retries = 2; // for writes to similar-addressed RAM
local write_retries = 5;

// this allows us to avoid multiple identical (slow!)
// reconfigurations after the configuration has already been
// used for reading
local previous_outer_page = -1;
for (local page = game_id; (address_scale_factor * (page - game_id) * 0x8000) < rom_size; page += 1) {

    local extra_bits =
        ((page >= 0x12) ? 0x81 : 0x40) // >= 64K with mapper, otherwise SMS-GG mode
        | ((page >= 0x14) ? 0x02 : 0x00) // >= 128K
        | ((page >= 0x20) ? 0x04 : 0x00) // >= 256K
        | ((page >= 0x30) ? 0x08 : 0x00) // 512K
        | 0;

    local outer_page = page | extra_bits;

    if (outer_page != previous_outer_page) {
        for (local outer_page_attempt = 0; outer_page_attempt < 3; outer_page_attempt += 1) {
            for (local quiesce_retry = 0; quiesce_retry < quiesce_retries; quiesce_retry += 1) {
                cpu_write(d, address_scale_factor * 0xC000, outer_page);
            }
            for (local write_retry = 0; write_retry < write_retries; write_retry += 1) {
                cpu_write(d, address_scale_factor * 0x0000, outer_page);
            }
            for (local quiesce_retry = 0; quiesce_retry < quiesce_retries; quiesce_retry += 1) {
                cpu_write(d, address_scale_factor * 0xC000, outer_page);
            }
        }
        previous_outer_page = outer_page;
    }

    local inner_page = page & 0x0F & ~extra_bits;

    if (inner_page == 0x00) {
        // possibly missing Sega mapper: use 0x0000..0x7FFF
        for (local quiesce_retry = 0; quiesce_retry < quiesce_retries; quiesce_retry += 1) {
            cpu_write(d, address_scale_factor * 0xDFFE, (inner_page << 1) | 1);
        }
        for (local write_retry = 0; write_retry < write_retries; write_retry += 1) {
            cpu_write(d, address_scale_factor * 0xFFFE, (inner_page << 1) | 1);
        }
        for (local quiesce_retry = 0; quiesce_retry < quiesce_retries; quiesce_retry += 1) {
            cpu_write(d, address_scale_factor * 0xDFFE, (inner_page << 1) | 1);
        }
        cpu_read (d, address_scale_factor * 0x0000, address_scale_factor * 0x8000);
    } else {
        // Sega mapper: use 0x8000..0xBFFF twice
        for (local offset = 0; offset < 2; offset += 1) {
            for (local quiesce_retry = 0; quiesce_retry < quiesce_retries; quiesce_retry += 1) {
                cpu_write(d, address_scale_factor * 0xDFFF, (inner_page << 1) | offset);
            }
            for (local write_retry = 0; write_retry < write_retries; write_retry += 1) {
                cpu_write(d, address_scale_factor * 0xFFFF, (inner_page << 1) | offset);
            }
            for (local quiesce_retry = 0; quiesce_retry < quiesce_retries; quiesce_retry += 1) {
                cpu_write(d, address_scale_factor * 0xDFFF, (inner_page << 1) | offset);
            }
            cpu_read (d, address_scale_factor * 0x8000, address_scale_factor * 0x4000);
        }
    }
}
```

The menu is based on Pengo code, but that copy of Pengo is no longer playable. However there is a separate playable copy of Pengo elsewhere in the ROM. At startup the menu writes:

[0xFFFE=0xB0]

The "➡" arrow cursor is movable and shown below in its initial position. Unlike many Game Gear multicart menus, this one preserves cursor offset while switching screens

Menu screen 1:

```

 ┌────────────────┐
 │  REAL 24 IN 1  │
 └────────────────┘

➡ 1 SONIC Ⅱ          [0x0000=0xBF]; it's [GG] part-30-sonic-the-hedgehog-2-512k.gg
  2 BARE KNUCKLE     [0x0000=0xAF]; it's [GG] part-28-bare-knuckle-256k.gg
  3 SHINOBI Ⅱ        [0x0000=0xA7]; it's [GG] part-20-the-gg-shinobi-ii-256k.gg
  4 SUPER MONACO GP  [0x0000=0x1F]; it's [GG] part-1c-super-monaco-gp-128k.gg
  5 MAGIC ADVENTURE  [0x0000=0x1B]; it's [GG] part-18-magical-taruruuto-kun-128k.gg
  6 NINJA GAIDEN     [0x0000=0x17]; it's [GG] part-14-ninja-gaiden-128k.gg
  7 PAC MAN          [0x0000=0x13]; it's [GG] part-12-pac-man-64k.gg
  8 WOODY POP        [0x0000=0x11]; it's [GG] part-11-woody-pop-32k.gg
  9 COLUMNS          [0x0000=0x10]; it's [GG] part-10-columns-32k.gg
 10 PENGO            [0x0000=0x0F]; it's [GG] part-0f-pengo-32k.gg
 11 TEDDYBOY-BLUES   [0x0000=0x4E]; it's [SMS-GG] part-0e-teddyboy-blues-32k.sms
 12 ASTRO FLASH      [0x0000=0x4D]; it's [SMS-GG] part-0d-astro-flash-32k.sms
```

Menu screen 2:

```

 ┌────────────────┐
 │  REAL 24 IN 1  │
 └────────────────┘

➡13 ACTION BOY       [0x0000=0x4C]; it's [SMS-GG] part-0c-seishun-scandal-32k.sms
 14 BANK PANIC       [0x0000=0x4B]; it's [SMS-GG] part-0b-bank-panic-32k.sms
 15 MACHINEGUN       [0x0000=0x4A]; it's [SMS-GG] part-0a-machine-gun-joe-32k.sms
 16 HANG-ON          [0x0000=0x49]; it's [SMS-GG] part-09-hang-on-32k.sms
 17 GHOST HOUSE      [0x0000=0x48]; it's [SMS-GG] part-08-ghost-house-32k.sms
 18 SPY VS SPY       [0x0000=0x47]; it's [SMS-GG] part-07-spy-vs-spy-32k.sms
 19 SUPER TENNIS     [0x0000=0x46]; it's [SMS-GG] part-06-super-tennis-32k.sms
 20 SATELLITE·7      [0x0000=0x45]; it's [SMS-GG] part-05-satellite-7-32k.sms
 21 GREAT SOCCER     [0x0000=0x44]; it's [SMS-GG] part-04-great-soccer-32k.sms
 22 GREAT BASEBALL   [0x0000=0x43]; it's [SMS-GG] part-03-great-baseball-32k.sms
 23 ROAD FIGHTER     [0x0000=0x42]; it's [SMS-GG] part-02-msx-bios-and-road-fighter-32k.sms
 24 PIT POT          [0x0000=0x41]; it's [SMS-GG] part-01-pit-pot-32k.sms
```

The mapper registers seem to be 0x0000, 0xFFFE, and 0xFFFF. Register 0x0000 is used for outer paging and SMS-GG mode selection. The other two are used for Sega-style paging.

Inferred mapper behavior, not yet tested exhaustively:

0x0000:
- bit 0x80: set when mapping the second megabyte, clear otherwise
- bit 0x40: set when activating SMS-GG mode, clear otherwise
- bits 0x3F: 32KB base page for outer page selection

For paging to work, the base page must be in an eligible region and
all paging-modifiable bits of the 32KB base page must be set

16KB paging mask bits:
- 0x10: when base page bit 0x08 is set and base page > 0x30
- 0x08: when base page bit 0x04 is set and base page > 0x20
- 0x04: when base page bit 0x02 is set and base page > 0x14
- 0x02: when base page bit 0x01 is set and base page > 0x12
- 0x01: always available

0xFFFE: 16KB paging offset for region 0x4000..0x7FFF (restricted by 16KB paging mask)
- 0xB0 is a special value and its meaning is unknown; it leaves the page set to 0x01

0xFFFF: 16KB paging offset for region 0x8000..0xBFFF (restricted by 16KB paging mask)

ROM fingerprint info:

2.0M Real 24 in 1 [Sonic II] (Unl).gg crc32:de6471e8 mekacrc:0E01DB0FE65FBA08 md5:d8cadcb912565e410f4278c516f561e8 sha1:763a3cdbfac247a90009f396bf9691ca6024b9de sha256:3054ad4c1d9ba02ba53e5b14d2f476c6c3525ff9fda339ef0d49383d6fd959d0

32K part-00-menu-32k.gg crc32:d80fb38b mekacrc:A19A21C2FEB5CC63 md5:e0ee46da13c7b89ffbcc40dc86a70b47 sha1:482e3563dde051e57bf40a60e5b84e208b134f65 sha256:218106d54268cf7a39a4d1f9c4317b5556df7645e7a16e8fa866b3bfa3a6c11d

32K part-01-pit-pot-32k.sms crc32:f81ab71e mekacrc:CA42846BB2AE8B1A md5:b3e6b1285bf8b820ca1344c7c4519efa sha1:55036c365d7d4496c5c5e0bfd01c13dfdb1a79f1 sha256:6679ea24710cf51b3aaa5fbee043e5ed6c446912cbc4729ab3fe4668424d1877

32K part-02-msx-bios-and-road-fighter-32k.sms crc32:e8d8e99c mekacrc:3395440A4DC7983E md5:7e82a5af56942c64c288c54050ea16fd sha1:9ed1d924035d94c7dad56644b58de88bc7d45612 sha256:01fd02d70e1672e085496c479945a91dc82362a1c7435fd05476c76538a3e0c3

32K part-03-great-baseball-32k.sms crc32:aafafd51 mekacrc:B478FD7132EF8ABB md5:ab3e87f4981bda8c486392719471ef08 sha1:9133fb22586ab10ee142192541ceb368b9b02540 sha256:8afd26d8aa991fee9e755d53cd0d2ee6f18a058580d44b5240a4c70d8997dd0e

32K part-04-great-soccer-32k.sms crc32:be711818 mekacrc:7CB0BCEF29C11827 md5:cecccff2d09d3cc705d848b28037e267 sha1:41d55da9ed00124c570d9964494b791e09d93af8 sha256:b48ce6a09946941fdf62e8ebf611fc1706344e26ea230bb206ba98cf04e9fbd2

32K part-05-satellite-7-32k.sms crc32:eb9a0359 mekacrc:C30BB9170D4D8E7A md5:7cb52be125ef66daa5e7a6e971a2a97f sha1:be0ace7ed8f1f1ab6fa51dfaa3ba2dd167ab3863 sha256:3adcd01767ee06949a930b88b76f9e2d8c89031c41e289af9d2e4290455ee5c1

32K part-06-super-tennis-32k.sms crc32:95d4c673 mekacrc:FEA3F1C357520CF6 md5:6d135ff05b6d440fa329cc060e559244 sha1:62b323b7b3188b2e0557e3e6d799edc71813c82e sha256:aa07700850080a8276bc518183e09035449a73e9c697415555bc14eca80e539b

32K part-07-spy-vs-spy-32k.sms crc32:f13a28c0 mekacrc:98EC9FA8477AEC88 md5:324741e68234ae80ff3df8bc3f411557 sha1:fd7d1bee1ca42c6d962780f21d5ad138b792db59 sha256:bcba12678775542b59694fc8fe3945530490cdd92a2bfafb07f74b189fa03ede

32K part-08-ghost-house-32k.sms crc32:317451a3 mekacrc:A5771FE4EC52960D md5:343210de693491444b452df7b665921d sha1:9917f8f06ed4c99b71d58d8a03fbea13330c84a1 sha256:c690ae4bff9711c0244e9a2ab18a579a429b29191dcc993f0ed5a496b472cfd3

32K part-09-hang-on-32k.sms crc32:40cedfd9 mekacrc:02A62976104874ED md5:5c25b6b38963fc513958a26e64c591d4 sha1:5726c7f7948612ca42daed96ded45745393bd80a sha256:5a2ecca3d78ae9aa8a6ac2c1775122cfdce3744898032ce5763c0017350e58ce

32K part-0a-machine-gun-joe-32k.sms crc32:9a94c7cc mekacrc:5C858AC9BD4714B4 md5:02906381c66601fb49b10bed123455d4 sha1:03a8a50b3b9e97ea5e10d7e094d287b51ca477af sha256:3981649682a895772012a769e8296e24e660ac4fc4102ecfbb747d53d18cee3e

32K part-0b-bank-panic-32k.sms crc32:46e1c722 mekacrc:EBA230C857CA76E4 md5:00a1f4b983ac30d05dd7cfb9bdbb2ee7 sha1:b05ac9fd2478d69f8f3bdd96ad86bbec482541f1 sha256:5c6e1f75255de9d1a7fc7d10db0ea9126633eedd018873597f78b312d2a80032

32K part-0c-seishun-scandal-32k.sms crc32:637dbbef mekacrc:D41A76F3C3411E87 md5:c021bce5a58cfbf513af253a25bc29bd sha1:2c39fdf814e223e2dc14646941a276879ae14c64 sha256:3a1df738527b578e248b6650c9a1498abaf9bef6da813a172dfae0a63be4e746

32K part-0d-astro-flash-32k.sms crc32:b1267d52 mekacrc:13171118D3218C2D md5:4c13f02b69c266ffea80fd7aba160bb2 sha1:b4e2483fbfe9e4c23a6fb14e755e5aa8c6ecece0 sha256:514484c1d4156fc77e4cefcd39cffd71f3e126c708420100ebb07e4972dc3486

32K part-0e-teddyboy-blues-32k.sms crc32:ed8dee80 mekacrc:E805AC40FA83F3B7 md5:acb4e818db613dc6f4737ef21302dc7c sha1:19d03cefeca768b08e708a161d3d6f5398450f49 sha256:e99eb0859de5801fddcf88a7d87651a6209bfe5df4f75bbd85c0b311edf6704c

32K part-0f-pengo-32k.gg crc32:6bd56e95 mekacrc:6C3C703170EBD587 md5:69bf00297cad6ee0bb6046c8084e5e37 sha1:126654feb2975e3a52431d29cefcafbd37bb2ef5 sha256:1c221bcb0b7ef67e644a695b78cb4dd851b800202ee13fd8d03fb099e533c46a

32K part-10-columns-32k.gg crc32:7316423e mekacrc:1DE54704572F032A md5:bfcf0e46ec8df8a51776bd2315b859fc sha1:26d407e8389a5564b836f0a68585a935ca019802 sha256:73f6012c1a92bcc96497668cdecfb3b592162c6b39a8c7efb8b9dc3931380561

32K part-11-woody-pop-32k.gg crc32:0c6e4769 mekacrc:9D2A47DDDF12FD27 md5:3885c64be1dc990918adebcbe9675855 sha1:58516c23f1e1b87daebda1b971fab278a6e7ce59 sha256:0c23fccffa3160b6754fa54ecbf08d3828f5e60a64dbe4203109715644ad94ce

64K part-12-pac-man-64k.gg crc32:dd001845 mekacrc:730EF79FF63F971D md5:fa8940099182cb57dc7eaa3466f43859 sha1:7d4521b55386eb7f06fed6b143c0e97bdfab264b sha256:d5b2c6fc05041802db1e5506ba9df8edf5415bbfe7c5852620cdc5f8bbb261f9

128K part-14-ninja-gaiden-128k.gg crc32:7ca9e75e mekacrc:430F39097D9A3025 md5:d9201f5ced95468d893e0f1b24438eea sha1:86681e978b3c0088d077afe850f4f9d278f5fa30 sha256:dc574770c07c5fc58b9cac371ac16307166a000df9a4015d0a2286626c2e9a72

128K part-18-magical-taruruuto-kun-128k.gg crc32:11d11451 mekacrc:1062032CD75EE446 md5:04fc405128c80de8358903a2a3b967d9 sha1:96fa1d2a82e5d0ccc3f2b7b6f1c85a3e098d048a sha256:bbcb5abea2e18b8d9e4a852b32f0b65e6aea4556f3deb70540dccb91d01b3c1b

128K part-1c-super-monaco-gp-128k.gg crc32:08ebcea1 mekacrc:9D34492A4095AD3A md5:1737583c8a857c84798ff254167025d9 sha1:69ffd99a1589bb77ca9943cbf08e07996dd0e8da sha256:08f11a8927879b681e2b23c7f3bb103002dd5468b3a58e1d6cff7bc0789af4ed

256K part-20-the-gg-shinobi-ii-256k.gg crc32:1f8f7d7c mekacrc:5312EB420F84AA31 md5:735c85911371d3c8fb18c33093307718 sha1:68e2f2b58ecbd038a4c8a9d004f2b9dee8a3b88d sha256:545d4b460b486d29d9f42029e91896eef5b0331b6cb9ea86df0ccc5e42d27de5

256K part-28-bare-knuckle-256k.gg crc32:dacc9061 mekacrc:73DB350D2119AB8B md5:80257cab0a9ed965520beeaba5bd5c9f sha1:815a1c910d016d374fff02604b521f147f529291 sha256:a027321ec909bb69ca44486a8e04193915cf733c88974a7dbc7d8551841f4461

512K part-30-sonic-the-hedgehog-2-512k.gg crc32:cda97bb3 mekacrc:DB692161E347F020 md5:6685be3154439062030746a179589090 sha1:9bd6690330a35e6d3ad6c0230c9d8984a2e2de0c sha256:8c4b4207d8c6be2c5a9d9f1ab0d3df5c76d65ce9e26ae6c9e1c6b45babf3a9b7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants