Dumping your own pet
There’s always fun to be had with unknown mask ROMs. Well, apparently it was assumed that the pinout on this one was unknown… Let’s figure it out, from zero to dump. If you are only interested in a dumping guide, see feriedoc.
If it looks like a MPR-18201-S…
Sega Ferie had a PCB photo online of its kitty model:
We spot MPR-17062-T, which didn’t match anything documented, but the markings were pretty close to some Sega Master System / Sega Game Gear ROMs.
If we follow traces out of this ROM, some lead to the CPU. No public datasheet was found when searching for T6A84, but someone was kind enough to put the pinout on an unrelated patent:
Now we were able to label some traces, and ROM pins started to match, along with some educated guesses for others, such as data pins also going upwards to test points:
Eventually I got myself one of these consoles, and confirmed that all pins were identical to the MPR-18201-S pinout:
What if we could leverage a Game Gear dumper for Ferie? While looking at existing options, it became clear to me that modifying an open-source solution would be the way to go. If needed, we wanted flexibility to replace pin connections.
Most options aren’t clear on their support for ROM variants, and we needed at least support for 1MB ROMs. Smaller ROMs didn’t use the 315-5912 mapper, since they relied on an internal mapper. Bank switching occurs on mapper slot 2, implying writes to its control address 0xffff
, so these ROMs have a different pinout, including a “Write Enable” pin.
Taking all this into account, the most promising option was cartreader.
Adapting a Game Gear dumper
One possibility would be to swap the ROM on a 1MB Game Gear cart, build cartreader with a Sega Master System slot, and use an off-the-shelf adapter. Again, support from adapters was unclear for me here, as some would consider pins A15
and OE
to be connected, which is not true for 1MB carts.
We can confirm this by doing some continuity tests with a multimeter. In fact, someone already did it for us, here’s the pinout of a less-than-1MB ROM:
This matches my tests with 512K ROM MPR-17271-S. Note that, despite the PCB pinout being the same, chip connections have these differences:
- pin
OE/RD
on MPR-18201-S is pinA15
on MPR-17271-S (PCB tab 28); - pin
A15
on MPR-18201-S is pinWR
on MPR-17271-S (PCB tab 3);
I prepared for the worst case: soldering some flying wires directly to PCB tab contacts a.k.a. gold fingers. 🫣 Very janky, but it does remove unknown variables regarding several layers of connector indirection.
This implied simplifying a lot of cartreader code: no leds, no slots… not much more other than pins and a serial console. I hardcoded the adapter to Retron, since it used Arduino ports that matched SMS pins as documented on the project’s pinout spreadsheet.
Although several specific features are guarded by #ifdef
directives and can be toggled with #define
directives, its hard to follow the relevant parts in code, so I found it easier to just remove features I knew wouldn’t be used. The end result of all that refactoring can be found on branch gg
of my fork.
Here it is, dumping MPR-17271-S:
Maybe I could have spared using a breadboard here, since there’s no need for resistors or capacitors, but it does make it easier to do logic analyzer tests, or even multimeter tests: just connect an alligator clip probe on a multimeter port, have it grab a Dupont cable on one end, then insert the other cable end on the breadboard, while checking ROM pins directly with a 2nd multimeter probe.
Note how I left M0-7 and OE/RD disconnected on PCB side, while A15 and OE/RD are shorted at the bottom left of the breadboard, thus both connect to A15 PCB tab.
Dumping an 1MB cart would have a very similar setup, but with A15 and OE/RD separated, each connected to their corresponding PCB tabs. M0-7
can be left disconnected as well. One thing that confused me for a moment was that CLOCK
has a test point, but the pin itself doesn’t connect to any chip… which means we wouldn’t need any clock generator. I guess it was only used on Codemasters carts? As usual, it’s hard to follow how original dumping breakthroughs were done, but it seems to be the case:
it’s a problem of one pin (CLOCK) that is unconnected on the SMSReader but is used as a clock input by the mapper chip in Codemasters games. Without it, the mapper does not respond to writes and therefore does not map anything.
Dumping a Ferie or two
Although an enthusiastic use of ribbon cables could have done the job in connecting ROM pins, I decided to play safe and get a breakout board.
Yeah, change of plans… I’m sure swapping ROMs with a 1MB cart would have worked, but maybe I got a bit too fixated with removing any variables I didn’t control, and that included mapper magic. After all, its just doing a more complicated hardware implementation of “please read these higher address pins”. You can find this alternative approach on branch ferie
.
Most interesting differences include setup for the higher address pins:
@@ -109,6 +82,11 @@
DDRK = 0xFF;
//A15
DDRH |= (1 << 3);
+ //A16-A19
+ DDRB |= (1 << DDB4);
+ DDRB |= (1 << DDB5);
+ DDRB |= (1 << DDB6);
+ DDRB |= (1 << DDB7);
Passing the full 32-bit address to read:
-byte readByte_SMS(word myAddress) {
+byte readByte_SMS(unsigned long myAddress) {
if (adapter_retrode && system_gg) {
// Set Data Pins (D8-D15) to Input
DDRA = 0x00;
@@ -256,10 +135,15 @@
// CE(PH3) and OE(PH6) are connected
PORTH = (PORTH & 0b11110111) | ((myAddress >> 12) & 0b00001000);
}
+ PORTB = (PORTB & 0b11101111) | ((myAddress >> 12) & 0b00010000);
+ PORTB = (PORTB & 0b11011111) | ((myAddress >> 12) & 0b00100000);
+ PORTB = (PORTB & 0b10111111) | ((myAddress >> 12) & 0b01000000);
+ PORTB = (PORTB & 0b01111111) | ((myAddress >> 12) & 0b10000000);
And reading that address directly without bank switching:
- // Write current 16KB bank to slot 2 register 0xFFFF
- if (!system_sg1000) {
- writeByte_SMS(0xFFFF, currBank);
- }
-
- // Blink led
- //blinkLED();
-
int addr_i = 0;
- // Read 16KB from slot 2 which starts at 0x8000
+ // Read 16KB
for (word currBuffer = 0; currBuffer < bankSize; currBuffer += 512) {
// Fill SD buffer
for (int currByte = 0; currByte < 512; currByte++) {
- sdBuffer[currByte] = readByte_SMS(((system_sg1000) || (cartSize == 32 * 1024UL) ? 0 : 0x8000) + currBuffer + currByte);
+ sdBuffer[currByte] = readByte_SMS((0x4000UL * currBank) + (unsigned long)(currBuffer + currByte));
}
There’s plenty of options for a TSOP-32 adapter, but only type I
(pins on package’s short edges), not type II
(pins on package’s long edges), which is what we need. I was considering designing one in KiCad, but eventually found a perfect fit: TSOP-32 (II) to DIP-32 SMT Adapter (1.27 mm pitch, 10.16mm body). Pitch is the distance between 2 pins, which I kind of eye-balled with a ruler. 😅
Now it was a matter of ROM transplanting. For desoldering SMD components, I don’t have anything fancy like hot air rework stations. A cheaper solution is to use low melt solder: by combining it with regular solder, the resulting alloy will have a lower melting temperature, and stay in a molten state for longer. After applying flux, add the alloy over all pins, and just keep spreading it with an iron, while gently pushing the chip with ESD tweezers until the chip eventually starts moving. You can find some examples on Youtube of “ChipQuik Alloy”, and also on arcade repairs. To avoid messing up neighbouring components, I protected them with heat-resistant tape.
Dumping rig setup after surgery:
If you look at the orange data wires at the bottom right, I actually had to replace one of them with the white wire, since I was getting a suspicious looking dump:
START
wait_serial
setup_SMS
readROM_SMS
bank 0000
wait_serial
00000000 B3 AF 93 A8 83 B7 02 00 83 00 01 00 00 00 00 00
00000010 83 28 00 00 00 00 00 00 83 34 01 00 00 00 00 00
00000020 83 28 00 00 00 00 00 00 83 28 00 00 00 00 00 00
00000030 83 28 00 00 00 00 00 00 83 28 00 00 00 00 00 00
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000060 00 00 00 00 00 00 AD 05 BB AD 0D 00 00 00 00 00
00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
000000A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
000000B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
000000C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
000000D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
000000E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
000000F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000100 08 99 9B BD 32 00 00 3E 08 93 BD 21 3B 00 8B 86
00000110 3A 00 00 93 BD 99 08 BB AD 0D 08 99 9B BD 32 00
00000120 00 3E 08 93 BD 21 3C 00 8B 86 3A 00 00 93 BD 99
00000130 08 BB AD 0D 08 99 9B BD 07 3E 08 93 BD 38 32 00
00000140 00 8D 1F 06 8D 21 01 07 3A 16 00 3C 80 32 16 00
00000150 3A 2B 00 3C 32 2B 00 3A 00 00 93 BD 99 08 BB AD
00000160 0D 3A 3A 00 BE 01 8A 92 01 BE 02 8A AB 01 21 0C
00000170 01 8B 06 82 82 01 9B B4 8B 07 8A 99 02 36 BF 83
00000180 8B 01 9B B4 8B 07 82 99 02 36 00 3E BF 32 0B 01
00000190 3A 38 00 07 3A 39 00 B0 82 A5 01 2A 29 00 23 22
000001A0 29 00 83 AB 01 21 00 00 22 29 00 3A 13 00 3C 32
000001B0 13 00 8D 06 2F 8D 19 2B 3A 0A 01 86 01 27 32 0A
000001C0 01 BE 1A 9A 99 02 3E 00 32 0A 01 3A 15 00 3C 32
000001D0 15 00 8D 88 2F 2A 10 00 23 3C BE BF 8A A2 01 22
000001E0 10 00 3A 09 01 86 01 27 32 09 01 BE 1A 9A 38 2B
000001F0 3E 00 32 09 01 3A 08 01 86 01 27 32 08 01 BE 24
00000200 9A 38 2B 3E 00 32 08 01 8D 38 2B 3A 07 01 86 01
Notice how there are no bytes ranged in 0xC0..0xF0
? Let’s look at such values in binary:
>>> bin(0xc0)
'0b11000000'
>>> bin(0xd0)
'0b11010000'
>>> bin(0xe0)
'0b11100000'
>>> bin(0xf0)
'0b11110000'
The 2nd most significant bit is always set, which corresponds to pin D6
. After replacing the flying wire from Arduino Mega, it now dumped as expected.
Actually, that’s not all, there’s yet another quirk here: The ROM image is mirrored at 0x80000
, however pin A19
is connected between ROM and CPU. Another faulty connection?
I decided to check with a logic analyzer, my cheap Saleae clone (Cypress FX2LP):
CH0 is connected to ROM pin A19
, and CH1 to one of the least-significant bits for addresses, just as a sanity check. I modified cartreader to just dump the first 0x200
bytes starting at address 0
, then at address 0x80000
.
Not a surprise, but the logic analyzer couldn’t sample at max frequency with just 2 channels, it just aborted the capture… I doubt my USB 3.0 bus was too busy to handle this data, but after bringing the sampling rate down to 12MHz, I was able to at least check in PulseView that A19
was being set as expected, going high only when we started reading from 0x80000
:
What’s going on? Let’s go back to the PCB:
ROM pin 1 and 32 are shorted, and connect to VCC, not A19! I hadn’t notice this the first time I tested continuity, since these CPU pins are right next to each other, but it explains why we get a mirror: A19 is always set high.
Eventually I dumped the World Travel model as well, and got another interesting difference, right at offset 0
:
-00 AF D3 E8 C3 CF 02 00 C3 00 01 00 00 00 00 00
+F3 AF D3 E8 C3 CF 02 00 C3 00 01 00 00 00 00 00
This time I forgot to connect VCC on the breakout board! Apparently every address was read correctly expect the first one, which always returned 00
.
Model rabbit hole
So, how many Feries are left?
It appears that the kitty model was the first one to be made in 1994, just named “フェリエ”. Later came the puppy model “フェリエパピー”, and in 1995, World Travel or “ワールドトラベル”.
One suggestion was that the model letter at the back of the case identified these versions. Is kitty “A” and puppy “E”? Well, there’s also a kitty “C” and a puppy “A”. I have a World Travel “C”, but there’s also an “A”… It doesn’t look like there’s a pattern here, maybe these letters identify production runs or revisions?
What about “Kid’s Life 21 Series”, shown in a “Ciao January 1996 Issue Insert”? A 4th model?
Next steps
Emulation, of course. 😁 I just gave a quick disassembly of these ROMs. Language is Z80, which matches what we expected from previous Toshiba IC research:
The T6A43 and T6M53 are based on the Z80-ASSP family, other known device numbers are T6A84, T6B31 and T6N21.
Right at the beginning we get the reset vector, which follows through to valid subroutines, giving some confidence on at least the first 0x10000
bytes:
Kitty ROM has debug strings at offset 0x7f000
:
ROM CHECK
RAM CHECK
LCD CHECK
TABLET CHECK
BACK UP OK
ROM ERROR 0
ROM ERROR 1
ROM ERROR 2
ROM ERROR 3
ROM ERROR 4
ROM ERROR 5
ROM ERROR 6
ROM ERROR 7
RAM ERROR
TABLET ERROR
LOW BATTERY
PUSH RESET SW
(C) SEGA 1994
Followed by credits:
MANAGER
N.YAMAZAKI
DIRECTOR
Y.ENDO
PROGRAMMER
S.FUJITA
SOFT & HARD
H.UCHIDA
DESIGNER
N.IMAI
SPECIAL THANKS
E.HAMA
H.KATO
N.MASAKI
TOY
SEKKEI SEISAN
HINSHITSUHOSYOU
OTHERS
(C) SEGA 1994
SEGA
TOY PLANNING
DIVISION
Before we go, enjoy these bitmaps from the other 0x70000
bytes of both ROMs, viewed in Tile Molester: