Saturday, January 18, 2014

VIC-20 Flash Memory Programmer Part 1/2

My first computer was the Commodore VIC-20 which my dad bought me when I was something like 7 years old (thanks dad!). VIC-20 is the predecessor to the mighty Commodore 64, the most popular microcomputer ever. VIC has much the same feel as the C64 and both machines share the same basic design centered around the timings of the video signal generation. Unlike the C64 though, which had great graphics and sound capabilities for making games, the VIC-20 system is very bare bones. Most notably, the VIC does not have sprites and has only 5 kilobytes of RAM, of which less than 4KB can be used for programming. Compared to C64's 64 kilobytes, making games or basically anything at all moderately complex is a much more challenging exercise. However, the VIC has a charm of its own, mainly because of its simplicity. For example, the chip which handles both graphics and sound has only fifteen 8-bit hardware registers, so it's easy to master everything there is about it.

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.

Prototype #1


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.

Desoldered ROM chip of a cartridge game, ribbon cable soldered in its place.


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!

Flash programmer with ATMega328P, 256Kx8 flash memory and
two '595 shift registers. Powered by "BreadPower" (more about that
in a future blog post, perhaps).


Prototype #2


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
           JMP A000

(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!



8 comments:

  1. Instead the Arduino board you could use a MAX232 chip and then interface the board with any computer equipped with a USB port.

    ReplyDelete
  2. Could you please tell me what the J1 / J2, that is, pin #12 or #13 top side of the cartridge, trace line connected to? Is that connected to ground?

    Thank you!

    ReplyDelete
  3. Hello! Pins 12 and 13 are memory block selection signals. Do not connect these pins to ground!

    Pin 12 is left unconnected. Pin 13, active low, selects the ROM memory block starting at address $A000. In cartridge games it is normally connected to the chip select pin of the ROM chip. In my schematic it is connected to the 74HC541 buffers, IC1-IC3.

    Hope this answered your question!

    ReplyDelete
    Replies
    1. Thank you very much!

      I bought a VIC20 cartridge board on eBay ( search for item # 111338337060).

      I hook up that board to my breadboard and I use the PDIP flash chip SST39F040, which is 512Kx8 flash chip.

      And I dump an 8K rom into the flash chip from address 0 to 8191, 8KB total.

      I understand that the VIC20's cartridge area starts at address 0xA000. So, should I dump the ROM image into my flash chip starting at address 0x0000 or 0xA000?

      In my attempt, I tried to connect /BLK5 to GND and also my flash IC's /CE pin to GND, but that is wrong as you indicated. The /BLK5 needs to be connected to the flash IC's /CE pin for the VIC20 to activate it during boot up and inactivate if no cartridge program is found.

      By having /BLK5 connected to the flash's IC /CE pin, my VIC20 does not hang now and boots up but does not detect a cartridge.

      Thanks!

      Delete
    2. One additional question.

      Do you connect the VIC20's C R/W pin (pin #18 on the cartridge) to your flash's /OE pin? Note that for the VIC20's, a HIGH means READ. The flash's /OE pin must be connected to an inverter from the VIC20's C R/W pin.

      Looking at your cartridge image, looks like the VIC20's C R/W is not connected at all, because the cartridge uses a 24-pin EPROM, which does not have the /OE pin.

      Just wondering what your flash IC's /OE pin is connected to.

      Thanks!

      Delete
    3. >should I dump the ROM image into my flash chip starting at address 0x0000 or 0xA000?
      If you wire the address lines directly to the ROM chip, the ROM image should be loaded starting at address 0. /BLK5 will be pulled low when VIC is accessing the memory block starting at address $A000. This will automatically map $A000 in VIC's address space to 0 in your ROM.

      I simply ignore VIC's R/W signal because VIC can't write to the ROM anyway. I connect /BLK5 to /OE and let the MCU control the /CE and /WE signals needed for updating the ROM. If you don't need to update the ROM on the fly, you can hardwire /CE to low and /WE to high and let the VIC the control /OE. I use the buffer chips to disconnect the ROM from the address and data busses of the VIC20 when I'm uploading new code to ROM.

      Also please see the schematic in the blog post. Hope this helps!

      Delete
    4. >If you wire the address lines directly to the ROM chip, the ROM image should be loaded starting at address 0. /BLK5 will be pulled low when VIC is accessing the memory block starting at address $A000. This will automatically map $A000 in VIC's address space to 0 in your ROM.

      Thanks for the confirmation. I just wanted to be sure, as all cartridges ROMs go from address. Good to know that the VIC20 has address decoding logic when /BLK5 is pulled low.

      Thanks again!

      Delete