Another nice thing about these computers is that it's possible to see how they are built and understand how they work by simply looking at the schematic. The schematic of the VIC-20 even fits on three sheets of paper! So it naturally follows that these computers are a tinkerer's dream: it's easy make all sorts of interesting hacks and expansions for them. And that's precisely why I recently bought a VIC-20 (unfortunately I sold my old VIC when I upgraded to the C64 back in the days).
After getting my dirty fingers on my shiny new computer I immediately began to think about various projects I could do with it. Thus the idea for the VIC-20 Flash Memory Programmer cartridge was born! The basic idea is to make a device with a flash memory that would plug into the expansion port of the VIC. Programs would be cross-compiled on a much more powerful host computer and transferred to programmer's flash memory over a serial connection.
To get started I bought a couple of game cartridges and disassembled them. I found out that the hardware inside these cartridges is really simple: they just contain a single 8K x 8 ROM chip and a 0.1uF decoupling cap. The ROM is wired directly to the address and data busses of the VIC-20 through the expansion port. In the hope of achieving greater good I sacrificed one of the cartridges and desoldered its ROM chip and soldered ribbons cables in its place. I then connected the ribbon cable to a breadboard.
Next I bought a few 256K x 8 flash memory chips (yeah, I know, overkill for VIC's 16-bit address space but smaller flash chips aren't available). I wired a flash chip to my Arduino Uno which I use for prototyping new projects and wrote a simple sketch for flashing the chip. It turned out flash chips are buggers to work with! Well, at least they are trickier than other memory chips I have worked with before, but my experience is quite limited... Writing has to be done per 128-byte page, and there is a clever protection scheme which prevents accidental writing to the memory. A certain bit pattern has to be written to special addresses in correct sequence before the chip goes into flash programming mode.
Arduino Uno has only 20 general purpose I/O pins and two are typically reserved for serial debugging. For flashing the chip, I needed 16 pins for addressing and 8 pins for the data so I used a few 74HC595 shift registers to expand the pin count. So no problem, I built this flash programmer on a breadboard. But the damn thing refused to work! I checked the wirings for at least three times and read the code until it burned my eyes, but no, the flash refused all attempts at programming!
Even after a long debugging session I could not find anything wrong with my code or the wirings. Everything seemed right. Then I had an idea that the implementation must be correct and the problem must be caused by a failure in the design. So at this point I went back to reading the datasheets. And then I noticed a crucial detail I had missed: the flash memory is really picky about timings. If the delay between consequent byte writes is longer than 200us, the chip drops out of page writing mode. I timed my code and because I was using shift registers and standard Arduino library calls (which are known to be slow), it took about 250us to write a byte. I quickly replaced standard lib code with direct port manipulation, and the code ran much, much quicker. And more importantly the flash chip began working like a charm!
At this point I unplugged the flash chip with some random data I had written to it and moved it on another breadboard which was connected to the hacked cartridge game. After carefully checking the connections at least twice I nervously powered on my VIC. The familiar CBM Basic V2 welcome screen appeared. Good, the computer was at least working and not crashing and burning because of short circuits on the breadboard. I then typed in a few peeks to checks values in the cartridge address space… and the data I had written to the flash appeared on the screen. SUCCESS!
It was time to combine the separated flash programmer breadboard and the flash chip breadboard together into one working device. After all, the goal was to be able to reprogram the flash when VIC was powered. For this I quickly whipped up the following simple design (see block diagram below): the flash memory would be connected to the expansion port through tri-state buffers. By disabling the buffer the flash chip is detached from the VIC while the MCU is reprogramming it. This is important so that signals don't leak out to the address and data bus, most likely clashing with other signals there, maybe even harming the components inside the computer. In normal operation the buffer is enable and the VIC can access the memory. In this state the MCU needs to tristate its I/O pins so that the VIC is not intefered by the MCU sitting on its lane.
Block diagram of the VIC-20 Flash Memory Programmer showing
the tri-state buffers, flash memory and the microcontroller.
The 74HC541, a 8-bit tri-state buffer with two output enable pins, turned out to be just the right chip for my needs. For VIC's 13 address bits (covering 8 kilos of ROM) and 8 data bits, I would need three of chips. With three '541s, the flash chip, MCU and shift registers that's a lot of chips to breadboard! So I began to look for another microcontroller than the ATMega328 for this project. I really like to work with AVRs so I looked what else they have in store, and I quickly found the ATMega32A, which has almost the same features as the '328, 32KB flash and 2KB SRAM. But the ATMega32A has 32 general purpose I/O pins compared to ATMega328's 20 pins, so with it I wouldn't need any shift registers. It also comes in the breadboard friendly DIL40 package, although those 40 pins make it one phat chip!
After a looong wait, a delivery of five ATMega32As finally arrived from China and I built the second prototype whose schematic is shown below.
Schematic of the final version drawn with Eagle which I'm really starting to like!
So does it actually work? To test this I wrote a very simple program in assembly language, the language understood by the 6502 CPU in charge of the VIC-20 system:
A000 INC 900F
(sorry about the formatting of the code, I need to figure out how to do proper code formatting with Blogger)
What does the program do? Well, A000 (40960 in decimal) is the starting address of the cartridge memory space. The first instruction just increments a video chip register at address $900F which controls the colors of the screen. Then the next instruction jumps back to the start of the program forming an infinite loop. Basically the program just cycles through the colors as fast as it can. I translated the assembly program to machine code by hand and got the following byte sequence: EE 0F 90 4C 00 A0.
At this point I was ready to test the real deal. I plugged in the breadboard to VIC's expansion port, fired up the VIC and connected my laptop to the serial port of the flash programmer. And here's what happened:
At the start of the video I have already typed in a short basic program which prints the first ten bytes from the cartridge memory to the screen. I run the program with the flash memory disconnected (i.e. 74HC541s disabled) which returns some bogus values. I then type in the serial commands on my laptop to load the machine code of my test program. After uploading I verify that the bytes have indeed changed by running the VIC basic program again. Finally I execute the program with "SYS 40960" (A000 in hex) which jumps to my machine routine.
All this trouble for some random stripes of colors you may wonder? Basically yes, but now it's possible to develop some more complex programs, like my own cartridge games! That would be cool indeed! But first I need a more robust solution than that ugly mess on the breadboard...
Three tri-state buffers nearest to the VIC, flash memory in the middle and ATMega32A
in the back. Those ribbon cables with male pin headers soldered to them are very
handy when building complex circuits on a breadboard. It took some time to make them
but it was definitely worth it!