Here is one of the 2 program storage units from Channel F cart 3 (die marked 31289). It has 1,024 bytes of ROM. This one has had the top metal layer removed with HCl.
Here's a close-up of just the ROM array, with 6 bits of address decoding to the left and 4 above the array. After a bit of work, I figured out how the bits are arranged.
Even closer. I numbered the bits using a 3-hex-digit byte number (000-3FF), followed by a 1-digit bit # (0-7, where 0 is the lsb). Bit 0 for all the bytes are the left 16 columns, then bit 1 for all the bytes are the next 16 columns, etc. The byte index increases going down, then to the right.
The grey and gold ovals aren't the bits; the bits are above and below the ovals. The difference between a 0 and a 1 is pretty subtle. Each bit has a trace running vertically through it. For 0 bits, that's all you can see. For 1 bits, you can also see another layer that seperates the bit from a ground trace.
There is a relationship between the ovals and the bits- if the bit above and below an oval are both 0, the oval is grey; otherwise it is gold. So each oval is a logical OR of the bits above and below it. Since the ovals in the top and bottom rows are only next to one bit, they indicate the value of that bit; grey is 0 and gold is 1.
Looking through the microscope, I read off 1s and 0s while my wife typed them into a text file. The counts of 0s and 1s nearly matched the counts from the ROM dump, so I was confident I had the correct data, but with a few transcription errors. The next step was to group the bits into bytes correctly, then arrange the bits in each byte correctly, then arrange the bytes correctly. I wrote a program to combine the bits into bytes in different ways. Examining the address decoding circuitry to the left and above the ROM array helped. Then I ran that data through another program that counted how many bytes had no 1 bits, how many had one 1 bit, how many had two 1 bits, etc. I compared these counts to those obtained from the ROM dump. When they matched, I had found the correct grouping of bits into bytes. Then I looked at counts of how many bytes had value 00, 01, etc to determine how to arrange the bits in the correct order in each byte. Lastly, I rearranged the bytes until the data matched the ROM dump. It turns out that I had made 20 transcription errors, about a quarter percent error rate. If I'd needed to, I could have also transcribed the grey/gold ovals and compared that info to the OR'ed value of the bits I dumped to help locate the errors.
Silicon Pr0n article about visually reading mask ROMs
rompar the tool I should have used!