16K Memory Expansion for the Vic-20

Written by Per Olofsson in January, 2001. Thanks to Ruud Baltissen, Pasi Ojala and Spiro Trikaliotis for help and suggestions.

This article was published in Commodore Hacking #20.

Update 2001-10-16: Added a new version of the memory test program. Fixed missing parenthesis on line 130 (generated false errors) and testing bank 5 (crashed with an illegal quantity error).

Update 2001-12-16: Corrected typo below (/WE where it should say /OE, in the instructions on how to add bank select switches).

I tried to keep the expansion as simple as possible, requiring no chips besides the two memory chips, and a minimum of soldering. It uses two 6264 SRAM chips (62256 also works) piggy-backed to the Kernal and Basic 2364 ROMs. It's recommended that you do the expansion one chip at a time, as this greatly simplifies troubleshooting. After the first chip checks out OK, do the second one. I'll start out by explaining a few basic principles.

Static Electricity

We'll be using CMOS RAM chips, and they are very sensitive to static electricity. If you don't have an anti-static wrist strap, make sure you touch a grounded surface before you touch the chips. Do not work sitting on shag carpet in a mohair sweater while petting the cat :)

Be Careful With ICs

ICs are sensitive to heat, and keeping the soldering iron for too long on a pin can toast the chip. If you need to redo a solder joint on a pin, wait for it to cool down first.

Up, Down, and Pin Numbering

The top of a DIP IC (the kind used in Vic-20s) is marked with a small notch, looking something like this:
       ___ ___ 
  1  =|   V   |=  8
  2  =|       |=  7
  3  =|       |=  6
  4  =|       |=  5
      `-------'
As you can see, the pin numbers start at 1, and the first pin is the top left, going down to the bottom left, then from the bottom right to the top right.



Piggy-backing

Piggy-backing is a quick way of adding another IC on top of an existing one. Normally you would create a PCB with chip sockets, connect it to the expansion port and populate it with memory chips, but with piggy-backing you simply add chips on top of internal ones. This works when the new chip's pins has signals that are identical to, or closely matches, the layout of the one it's being mounted on top of.
                                                6264 RAM     
                                                ___ ___      
             2364 ROM                 NC   1  =|   V   |=  28  Vcc
             ___ ___                 A12   2  =|       |=  27  /WE
   A7   1  =|   V   |=  24  Vcc       A7   3  =|       |=  26  CS2
   A6   2  =|       |=  23  A8        A6   4  =|       |=  25  A8 
   A5   3  =|       |=  22  A9        A5   5  =|       |=  24  A9 
   A4   4  =|       |=  21  A12       A4   6  =|       |=  23  A11
   A3   5  =|       |=  20  /CS       A3   7  =|       |=  22  /OE
   A2   6  =|       |=  19  A10       A2   8  =|       |=  21  A10
   A1   7  =|       |=  18  A11       A1   9  =|       |=  20  /CS1
   A0   8  =|       |=  17  D7        A0  10  =|       |=  19  D7 
   D0   9  =|       |=  16  D6        D0  11  =|       |=  18  D6 
   D1  10  =|       |=  15  D5        D1  12  =|       |=  17  D5 
   D2  11  =|       |=  14  D4        D2  13  =|       |=  16  D4 
  Vss  12  =|       |=  13  D3       Vss  14  =|       |=  15  D3 
            `-------'                          `-------'
I put the pins that don't match in bold, and as you can see there are 8 that don't. However, we don't have to rewire all of them. NC means "No Connection" so we can just ignore that pin. Note that if you're using 62256 chips you'll have to wire this one too, see below. We want to connect CS2 to Vcc, and we'll also swap A11 and A12, leaving 5 pins to solder on each chip. Swapping address bus pins works on RAM chips, as it only affects how bits are stored internally -- when you read them out again, they're swapped back. This also works for the databus.

We'll mount one 6264 on top of the Kernal ROM, and one 6264 on top of the Basic ROM. The ROMs are marked UE11 and UE12 and can be found in the bottom right of the motherboard. The wiring is identical for the two chips, except for the /OE and /CS1 pins. The pins that we want to rewire we carefully bend up so that they don't connect to the ROM. You want to bend them almost all the way up (about 150 degrees) so that you can reach them with the soldering iron. The pins are very sensitive, so make sure you bend the right pins -- bending a pin back again could easily break it.

Sometimes the pins on the RAM are too wide apart to make a good connection when you piggy-back it. In this case, bend all the pins on the RAM slightly inwards. You can do this by putting it on the side on a flat, hard surface and press gently.

Soldering A11/A12 and Vcc

You could get A11, A12, and Vcc from several places on the motherboard, but as they're available on the ROMs we'll just solder small wires from the ROM to the RAM. Remember that we're swapping A11 and A12, so connect pin 18 on the ROM to pin 2 on the RAM. Connect pins 26 and 28 on the RAM to eachother.

Soldering /WE

Pin 27 on the RAMs should be connected to pin 34 on the 6502 CPU. The CPU is the 40-pin chip in socket UE10 on the motherboard, right next to the ROM chips. Pin 34 is the 7th pin if you count from the top right pin on the CPU.

/OE and /CS1

In the Vic-20 memory is divided into 8 blocks of 8K each. Block 0 is further divided into 8 1K blocks, of which 5 are populated with RAM. Block 4 is used by the VIC and the VIA chips, block 6 is the Basic ROM, and block 7 is the kernal ROM. This leaves four blocks (1, 2, 3 and 5) available for cartridges and RAM expansions. For RAM to be visible to the basic interpreter, you must start by adding ram in block 1, then 2 and then 3. RAM in block 5 is never detected by the basic. 8K cartridges use block 5, and 16K cartridges use block 5 together with another one, usually 3. To be as compatible as possible with existing cartridges and to expand basic memory I'll use block 1 and 2 for this expansion, but you could use any two of the available blocks you want. I've added instructions for making the blocks selectable by switches below.

The block signals are available on the 74LS138 decoder chip marked UC5 on the left side of the motherboard. Block 1 is on pin 14, block 2 is on pin 13, block 3 is on pin 12 and block 5 is on pin 10. If you look closely you'll see that the signals for block 1 and 2 go out from the chip a few mm to a small pad. It's much easier to connect your wires to these pads than the pins on the decoder chip. Solder a wire from block 1 to pin 20 and 22 on the first RAM chip, and a wire from block 2 to pin 20 and 22 on the second RAM chip.

You're done!

That's all. When you power up the Vic-20, you should be greeted with a 19967 BYTES FREE message. If you've only done one chip so far, you'll get 11775 BYTES FREE, provided you connected it to block 1. If you've connected memory to other blocks but not block 1, you'll just get the normal 3583 BYTES FREE message. To test your memory, try this program:
  10 input "test which block";b
  20 s = b*8192 : t = s+8191 : e = 0 : o = 0
  25 if s>= 32768 then s = s-32768 : t = s+8191 : o = 32768
  30 print "testing databus"
  40 for a = s to t : poke a+o, 85 : if peek(a+o) <> 85 then gosub 1000
  50 poke a+o, 170 : if peek(a+o) <> 170 then gosub 1000
  60 next : de = e
  70 e=0 : print "testing high address bus"
  80 for a = s to t : poke a+o, int(a/256) : next
  90 for a = s to t : if peek(a+o) <> int(a/256) then gosub 1000
  100 next : he = e
  110 e=0 : print "testing low address bus"
  120 for a = s to t : poke a+o, a and 255 : next
  130 for a = s to t : if peek(a+o) <> (a and 255) then gosub 1000
  140 next : print
  150 print de;"errors found in databus test"
  160 print he;"errors found in high address bus test"
  170 print e;"errors found in low address bus test"
  999 end
  1000 e = e+1 : print "error at";a : return
  10 input "test which block";b
  20 s = b*8192 : t = s+8191 : e = 0
  30 print "testing databus"
  40 for a = s to t : poke a, 85 : if peek(a) <> 85 then gosub 1000
  50 poke a, 170 : if peek(a) <> 170 then gosub 1000
  60 next : de = e
  70 e=0 : print "testing high address bus"
  80 for a = s to t : poke a, int(a/256) : next
  90 for a = s to t : if peek(a) <> int(a/256) then gosub 1000
  100 next : he = e
  110 e=0 : print "testing low address bus"
  120 for a = s to t : poke a, a and 255 : next
  130 for a = s to t : if peek(a) <> a and 255 then gosub 1000
  140 next : print
  150 print de;"errors found in databus test"
  160 print he;"errors found in high address bus test"
  170 print e;"errors found in low address bus test"
  999 end
  1000 e = e+1 : print "error at";a : return
The program takes a couple of minutes to run.

Troubleshooting

The computer doesn't start at all, or all you get is a black screen

You've probably shorted or toasted something. Not good, this could have damaged the computer. Recheck all your soldering and make sure that you haven't accidentally connected something wrong.

The computer powers up with 3583 bytes free

Memory in block 1 is either not connected or not working. Check the connections between block 1, /CS1 and /OE, between R/W and /WE, and between Vcc, CS2 and Vcc.

The computer powers up with something other than 3583, 11775 or 19967 bytes free

Memory is functioning partially, check A11 and A12. This could also indicate that a RAM chip is faulty.

The computer powers up with the correct number of bytes free, but the memory test program fails

Memory is functioning partially. If the databus test fails, check the connections between block 1, /CS1 and /OE, between R/W and /WE, between Vcc, CS2 and Vcc, and D0 through D7. If the address bus test fails, check A0 through A12.


Using 62256 chips instead of 6264

You can freely substitute 62256 chips for the 6264. Only two pins differ:
             6264 RAM                          62256 RAM     
             ___ ___                           ___ ___      
   NC   1  =|   V   |=  28  Vcc     A14   1  =|   V   |=  28  Vcc
  A12   2  =|       |=  27  /WE     A12   2  =|       |=  27  /WE
   A7   3  =|       |=  26  CS2      A7   3  =|       |=  26  A13
   A6   4  =|       |=  25  A8       A6   4  =|       |=  25  A8 
   A5   5  =|       |=  24  A9       A5   5  =|       |=  24  A9 
   A4   6  =|       |=  23  A11      A4   6  =|       |=  23  A11
   A3   7  =|       |=  22  /OE      A3   7  =|       |=  22  /OE
   A2   8  =|       |=  21  A10      A2   8  =|       |=  21  A10
   A1   9  =|       |=  20  /CS1     A1   9  =|       |=  20  /CS1
   A0  10  =|       |=  19  D7       A0  10  =|       |=  19  D7 
   D0  11  =|       |=  18  D6       D0  11  =|       |=  18  D6 
   D1  12  =|       |=  17  D5       D1  12  =|       |=  17  D5 
   D2  13  =|       |=  16  D4       D2  13  =|       |=  16  D4 
  Vss  14  =|       |=  15  D3      Vss  14  =|       |=  15  D3 
            `-------'                         `-------'                         
Pin 26 (A13) can be connected to Vcc just like on the 6264, but we need to wire pin 1 (A14) to either Vcc, Vss or another address bus pin. It's probably easiest to wire it to pin 2 (A12). We won't be using the greater capacity of the 62256 using this method (doing so would require some kind of decoder logic) but sometimes 62256 chips are cheaper than 6264, or maybe you just have some lying around.


Adding Block Select and Write Protect Switches

Adding block select switches allows you to chose which blocks should be populated on the fly. This allows you to chose between a basic expansion and a "cartridge emulator" that allows you to load cartridge images into ram and run them. I added one switch for each chip, giving the first chip the option between block 1 and 3, and the second between 2 and 5.
  block 1 -----o
                \
                 o----- to /CS1 and /OE on chip 1

  block 3 -----o


  block 2 -----o
                \
                 o----- to /CS1 and /OE on chip 2

  block 5 -----o
As a kind of copy protection, some cartridge images try to modify themselves to detect if they're running from RAM. If we add write protect switches we'll be able to run those as well. Switch to write enabled while loading, then switch to write protected and reset.
      R/W -----o
                \
                 o----- to /WE on chip 1

     +5 V -----o


      R/W -----o
                \
                 o----- to /WE on chip 2

     +5 V -----o
+5 V is the same as Vcc.


This document is Copyright © Per Olofsson in 2001.