Quick-and-Dirty ROM Dumping

September 2009

AVR EPROM Dumper

If you're like me, you spend plenty of time at electronics surplus stores, wake up at dawn to go to flea markets, spend hours browsing eBay, and accumulate a fair quantity of interesting junk.

The other day I found this curious thing at the WeirdStuff Warehouse; a chunky keyboard in a big box with an RJ12 cable coming out of it. I did some searching and it looks like the keyboard came from a TI99/4a computer. But what the heck was this thing?

Mystery Keyboard

Of course, the natural thing to do was to open it. No screws to be found, so I had to rip the sides of the case off. Inside, I found lots of goodies: a Z80 CPU, an 8K RAM chip, a 6MHz crystal, a real-time clock, a battery, and a piezo transducer. The only marking on the board said

HI-LIGHTER INC. 12/15/92
Searching online for "hi-lighter inc" brought up nothing. No part number or anything else to search for. This was probably some device used internally and never meant for mass production.

Underside

Then I noticed one of the chips had a round window on it. "Aha," I thought, "that's an EPROM! I bet I can dump it and look for ASCII strings!"

Step 1: Find the datasheet

This particular EPROM (Erasable Programmable Read-Only Memory) is a Texas Instruments TMS27C128, a 16 kilobyte ROM chip. A quick search returned the datasheet. These old parallel-interface ROMs are embarrassingly easy to read; set the A0..A13 lines to the desired address, and read the stored byte on the DQ0..DQ7 lines. Dumping the ROM is as simple as iterating through all 16,384 addresses (0x0000 to 0x3FFF) and recording the stored bytes. Serial-access ROM chips require more effort, but most of the random crap I find is from the Golden Age of Through-Hole Technology, when giant DIP packages and parallel address buses were the norm, and hacking was a piece of cake.

Step 2: Build the circuit

Of course, we could step through each byte individually and write down the values, but this is The Future, we can use Technology! I had an AVR lying around on a breadboard (as I'm sure most of you do) and connected it to the EPROM chip. I used a SparkFun FT232R breakout board so the AVR could send the read bytes back to the computer, which would log them. Of course, you could use one of those, but we'd probably laugh at you.

The ATmega168 doesn't have enough data pins for a 16-bit output and an 8-bit input, so I wired up two 74HC595 shift registers to the address lines of the EPROM. Larger (40-pin DIP) AVRs can be connected directly to the address bus, making this even easier.

Step 3: Write the code

The code was simple. For addresses from 0x0000 to 0x3FFF, bit-bang the address into the shift registers, wait a bit, read the byte from the EPROM, send it over the serial line, and repeat. I used CuteCom on Linux to read the data from the AVR and log it to a file. Here's the main routine:

#include <stdio.h>
#include "uart.h" /* avr-libc example UART library */
#define ROM_LENGTH 16384

int main(void)
{
  /* set up UART for serial communication with the FT232 chip */
  uart_init();

  /* direct standard output to the UART */
  FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
  stdout = stdin = &uart_stream;

  /* upper bits of port D are serial address output lines */
  /* 4 bits of PORTD are used as data inputs */
  DDRD = 0b11000000;

  /* pin 1 of port D connected to strobe pin of shift registers */
  DDRB = 0b00000010;

  /* lower 4 bits of port C used for data inputs */
  DDRC = 0b00000000;

  unsigned int addr;
  for (addr = 0; addr < ROM_LENGTH; addr++)
  {
    /* bit-bang the 14-bit address into the shift registers */
    serialout16(addr);
    _delay_us(1); /* just to be safe, allow the data lines to be safe */
    
    /* read the data byte */
    unsigned char data, high low;
    low = PINC & 0b00001111;
    high = PIND & 0b00111100;
    data = low | (high >> 2); /* combine low and high nibbles */

    /* send the byte to the PC */
    uart_putchar(data, stdout);
  }
  return 0;
}

Notes: I'm using uart.h and uart.c from an avr-libc demo project, and the serialout16() function is an unrolled serial bit-banging routine I wrote, available here.

Step 4: Read the data

Once I had my binary ROM dump, I ran it through xxd to search for strings. The strings utility can do the this automatically, but I wanted to browse it by hand. The first few bytes looked like Z80 opcodes to me:

f3         di
31 f0 5f   ld SP,5ff0h
ed 56      im 1
etc.
Ah, that brings back memories of hacking assembly language on the TI-83 calculator back in middle school...

Scrolling down I found some interesting messages:

00015e0: 3620 23c9 004a 414e 4645 424d 4152 4150  6 #..JANFEBMARAP
00015f0: 524d 4159 4a55 4e4a 554c 4155 4753 4550  RMAYJUNJULAUGSEP
0001600: 4f43 544e 4f56 4445 4353 554e 4d4f 4e54  OCTNOVDECSUNMONT
0001610: 5545 5745 4454 4852 4652 4953 4154 2a40  UEWEDTHRFRISAT*@
...
0001f90: 1a58 184c 4947 4854 4552 4849 1a2b 184c  .X.LIGHTERHI.+.L
0001fa0: 4947 4854 4552 4849 1a2a 184c 4947 4854  IGHTERHI.*.LIGHT
0001fb0: 4552 1f30 1a12 1548 4918 2a1a 4c49 4748  ER.0...HI.*.LIGH
0001fc0: 5445 5213 1f33 0003 0003 0003 0003 1215  TER..3..........
0001fd0: 1f30 1218 0c20 2049 204e 2043 202e 2009  .0...  I N C . .
0001fe0: 1f43 1f43 1f43 2013 1f31 0c1f 3009 171f  .C.C.C ..1..0...
0001ff0: 4343 4f4c 4f52 4449 5350 4c41 0606 591f  CCOLORDISPLA..Y.
0002000: 3203 1f30 091a 2318 4119 3032 391a 4319  2..0..#.A.029.C.
0002010: 3139 3932 1f34 0403 0305 0e3b 0000 0000  1992.4.....;....
...
00031e0: 4400 061f 4d18 1f30 2020 504c 4541 5345  D...M..0  PLEASE
00031f0: 2020 1f31 1b1f 3020 4320 4f20 4d20 4520    .1..0 C O M E 
0003200: 201f 321b 1f30 2020 2020 494e 2020 2020   .2..0    IN    
...
0003ae0: 8a40 1206 1f49 1920 5320 4f20 5220 5220  .@...I. S O R R 
0003af0: 591b 1b20 2057 4527 5245 2020 2043 4c4f  Y..  WE'RE   CLO
0003b00: 5345 4420 201b 1b1b 0518 504c 4541 5345  SED  .....PLEASE
0003b10: 2043 4f4d 4520 4147 4149 4e10 3b3b 0000   COME AGAIN.;;..
Aha! It looks like this weird black box was, most likely, the control unit for a programmable scrolling LED sign. With a Z80, 8KB of RAM, a real-time-clock, and an awesome keyboard, this thing is practically screaming "HACK ME PLEASE!" It looks like some poking around with a logic analyzer is in order.

Conclusion

So, if you find any old hardware you want to reverse-engineer, or old game cartridges you want to legally back up onto your computer, and you've got an AVR on your bench, you can wire up a ROM dumper in a few minutes with spare components you probably already have!