- TI-80 ROM dumper
- 23 Jul 2020 08:22:26 pm
- Last edited by Zeroko on 25 Jul 2020 05:00:54 pm; edited 1 time in total
Background:
Most TI-80s do not have a link port, making it difficult to dump the ROM. While I have had an arbitrary code execution exploit & an emulator for a while, the original method of dumping the ROM (hand-transcribing the corresponding TI-BASIC tokens & then using constraints & a parallel dump of 3.0 & 4.0 to disambiguate the ones that are visually identical) left a lot to be desired, & the link-port-based dumper requires a (rare) ViewScreen TI-80.
As with the TI-81, that seems to suggest using OCR. However, the TI-80 has half as many pixels, poor contrast, & a 4x6 pixel font. I wrote a QR code generator, but it was impractically large & slow. But I remembered using an AM radio early on to try to determine what the calculator was doing, so here we are.
Idea:
The clock frequency & shielding are such that a suitably-tuned AM radio will make noises when you use the calculator, so I wrote a program that modulates whatever the radio is picking up (which appears to be the data bus between the ASIC & the RAM & external ROM) with the bits of the ROM. Then you can connect the radio to a computer, record the resulting audio, & extract the ROM from it.
The encoding is designed to be balanced, because a radio plus sound card would filter out any DC offset. It is also designed to not require much code be typed into the calculator, so it uses pulses (a high & a low period) of varying length. In between bytes are pulses of 3-unit-long high & low periods, while zero bits consist of a 1-unit-long low & high period (note the reversed ordering) & one bits consist of a 1-unit-long high & low period. This is Manchester encoding (thanks, whomever suggested that) with extra synchronization pulses. (The original encoding took 19 time units per byte, while this one takes 11 units per byte & has a simpler encoder & decoder.)
The encoder starts reading at byte address $8000, then eventually loops around to $0000. This dumps the external ROM ($8000-$FFFF) before the internal ROM ($0000-$3FFF), which was done because the addresses are not contiguous otherwise (with memory-mapped I/O & RAM in between). Due to the lack of interrupts & DMA & equalization of code path lengths, the timing varies only due to clock drift, which simplifies decoding. It encodes approximately 208 (rev. B) bytes per second (I need to re-measure rev. A since changing the encoding), which was chosen as a compromise between ease of decoding (especially, avoiding the need for an error-correcting code) & not taking too long (around 5 minutes, due to padding before for the radio & decoder to lock on & after to avoid needing to know the exact timing).
The decoder determines the byte period (which varies based on hardware revision & possibly also the battery level) via the correlation of the signal with delayed versions of itself. It finds the beginning of the ROM by ignoring bytes until it finds one with the high bit set, because the space just before the ROM is unconnected & reads as the high byte of the address, while both known versions of the external ROM start with $D2. It then uses matched filters to synchronize to the byte boundaries & extract the bit values, which offers some robustness to noise (unlike the previous version that looked for zero-crossings).
Usage (tentative):
Tune an AM radio until you can hear when you press buttons on the calculator, then tune it to where the calculator sounds are the loudest (& no actual station can be heard). It may help to turn the radio volume to maximum once it is connected to the computer (make sure it is not routed to the speakers at maximum volume, of course), especially if it causes clipping (since we are trying to recover a square wave anyway). Type in the ROM dumper program, then perform the exploit (both to be released when the decoder is finished). Save the sound recorded from the radio as raw 48 kHz 16-bit mono PCM (which ends up being somewhere around 27 MB in size). Finally, run the decoder program to turn it into a ROM file in the format the emulator expects.
Most TI-80s do not have a link port, making it difficult to dump the ROM. While I have had an arbitrary code execution exploit & an emulator for a while, the original method of dumping the ROM (hand-transcribing the corresponding TI-BASIC tokens & then using constraints & a parallel dump of 3.0 & 4.0 to disambiguate the ones that are visually identical) left a lot to be desired, & the link-port-based dumper requires a (rare) ViewScreen TI-80.
As with the TI-81, that seems to suggest using OCR. However, the TI-80 has half as many pixels, poor contrast, & a 4x6 pixel font. I wrote a QR code generator, but it was impractically large & slow. But I remembered using an AM radio early on to try to determine what the calculator was doing, so here we are.
Idea:
The clock frequency & shielding are such that a suitably-tuned AM radio will make noises when you use the calculator, so I wrote a program that modulates whatever the radio is picking up (which appears to be the data bus between the ASIC & the RAM & external ROM) with the bits of the ROM. Then you can connect the radio to a computer, record the resulting audio, & extract the ROM from it.
The encoding is designed to be balanced, because a radio plus sound card would filter out any DC offset. It is also designed to not require much code be typed into the calculator, so it uses pulses (a high & a low period) of varying length. In between bytes are pulses of 3-unit-long high & low periods, while zero bits consist of a 1-unit-long low & high period (note the reversed ordering) & one bits consist of a 1-unit-long high & low period. This is Manchester encoding (thanks, whomever suggested that) with extra synchronization pulses. (The original encoding took 19 time units per byte, while this one takes 11 units per byte & has a simpler encoder & decoder.)
The encoder starts reading at byte address $8000, then eventually loops around to $0000. This dumps the external ROM ($8000-$FFFF) before the internal ROM ($0000-$3FFF), which was done because the addresses are not contiguous otherwise (with memory-mapped I/O & RAM in between). Due to the lack of interrupts & DMA & equalization of code path lengths, the timing varies only due to clock drift, which simplifies decoding. It encodes approximately 208 (rev. B) bytes per second (I need to re-measure rev. A since changing the encoding), which was chosen as a compromise between ease of decoding (especially, avoiding the need for an error-correcting code) & not taking too long (around 5 minutes, due to padding before for the radio & decoder to lock on & after to avoid needing to know the exact timing).
The decoder determines the byte period (which varies based on hardware revision & possibly also the battery level) via the correlation of the signal with delayed versions of itself. It finds the beginning of the ROM by ignoring bytes until it finds one with the high bit set, because the space just before the ROM is unconnected & reads as the high byte of the address, while both known versions of the external ROM start with $D2. It then uses matched filters to synchronize to the byte boundaries & extract the bit values, which offers some robustness to noise (unlike the previous version that looked for zero-crossings).
Usage (tentative):
Tune an AM radio until you can hear when you press buttons on the calculator, then tune it to where the calculator sounds are the loudest (& no actual station can be heard). It may help to turn the radio volume to maximum once it is connected to the computer (make sure it is not routed to the speakers at maximum volume, of course), especially if it causes clipping (since we are trying to recover a square wave anyway). Type in the ROM dumper program, then perform the exploit (both to be released when the decoder is finished). Save the sound recorded from the radio as raw 48 kHz 16-bit mono PCM (which ends up being somewhere around 27 MB in size). Finally, run the decoder program to turn it into a ROM file in the format the emulator expects.