Memory expansions for the Commodore 128 Marko M\"akel\"a Pekka Pessi April 17th, 1994 (*) [last modified December 22nd, 1999] As the Commodore 128 was first introduced, 128 kilobytes feeled like an unbelievably big amount of memory. Nowadays even plain terminals and game consoles have more, and you can expand even a Commodore 64 to 256 kilobytes, twice as much as its big brother has by default. There are several commercial memory expansions for the Commodores 128 and 64, but they are rather expensive, and most if not all of them are not being manufactured any more. This article introduces three different memory expansions for the Commodore 128 and 128D computers. With these instructions, you can expand your computer to 256, 512 or 1024 kilobytes of internal memory. The 1024 kilobyte expansion is actually a combination of the two former ones, and it is fully compatible with both of them. When built by oneself, the 1024 kB expansion can remain cheaper than 200 Finnish marks. One Americal dollar (USD) is equivalent to five or six Finnish marks (FIM). My expansion costed about 240 FIM, but I bought some parts in vain, and could have bought the memory chips somewhat cheaper. This time they costed 117 FIM. I set three goals to the expansions. The bigger expansions should be fully compatible with the internal 256 kB expansion for the Commodore 64 when the computer is in C64 mode, and the 256 kB and 1024 kB expansions should be downwards compatible with a commercial internal 256 kB expansion for the Commodore 128. Finally, an expanded computer should be fully downwards compatible with an unexpanded one. The design aims to a hardware that supports programming. The 256 kB and 1 MB expansions enhance the capabilities of the MMU in a way that the engineers at Commodore must have planned, and the other memory management logic is even easier to program. --- * This document is partially based on Pekka Pessi's two articles describing an 256 kB internal memory expansion for the Commodore 64. The articles were originally published in the largest Nordic and Finnish home computer users' magazine, MikroBITTI, in its first two issues in the year 1987. Six years later, they were translated to English and edited by Marko M\"akel\"a, with help from Pekka Pessi. The translation should be available via anonymous FTP from FTP.FUNET.FI. August 1996: Thanks to Wolfgang Scherr from Austria, who noticed my mistake in the schematic diagram. The inputs of the 74LS153 chip were mixed, which caused the address block decoding to fail. By now, I know of two Commodore 64 (mine and Pekka Pessi's) where this expansion has been built, and of four Commodore 128s (of which two expanded by me, and the other two by Wolfgang Scherr and Matthias Kirchner from Germany). The expansion never became a success, although the banked concept is technically better than e.g. the Commodore REU. Meanwhile, there is one more program that supports the expansion: my transfer system prlink. You can retrieve this document in PostScript or LaTeX format via anonymous FTP. The files are at FTP.FUNET.FI in the directory /pub/cbm/documents/projects/memory/c128/1028. They are also accessible via . Contents 1 Some basics 1.1 Expansion memory in 16 kB blocks 1.2 Memory chips 1.3 Dynamic headaches 1.4 Memory refresh 1.5 The MMU expansion 2 Building the expansion 2.1 Disclaimer 2.2 Getting started 2.3 Expanding to 512 kilobytes 2.3.1 Removing the old memory chips 2.3.2 Adding the new address line 2.3.3 Prepare for the final step 2.3.4 Testing 2.4 Expanding to 256 or 1024 kilobytes 2.4.1 Realizing the processor bus interface 2.4.2 Adding the new memory banking signals 2.4.3 Soldering the memory chips 3 Using the expansion 3.1 The operation of the block switcher 3.1.1 PIA's location in address space 3.1.2 Block selection 3.1.3 Interfacing the second MMU 3.1.4 Startup settings for the PIA expansion 3.2 Segmented memory 3.3 Critical addresses for the PIA expansion 3.4 Initializing the PIA expansion 3.5 Programming the PIA in machine language 3.5.1 An exception: video memory 3.6 Programming the MMU 3.7 Hints for programming in C128 mode Machine Language 3.8 Programming in C128 mode BASIC 4 Programming the expansion in C64 mode BASIC 4.1 Processing a huge array 4.2 Storing graphics 5 RAM disk and other C64 mode programs 5.1 Memory test 5.2 Poor man's multitasking 5.3 Machine language monitor 5.4 RAM disk 5.4.1 Disk copiers 6 Enhancing the PIA expansion 6.1 Built-in freezer 6.2 New operating system 7 Contacting the author 1 Some basics This article describes two memory expansions: an expansion that adds two new memory banks to the Commodore 128, doubling its memory space, and another expansion which expands each bank to 256 kilobytes, quadrupling the memory space. The former is the 256 kB expansion, from here on the MMU expansion, and the latter is the 512 kB expansion, or the PIA expansion. Combining these two expansions gives you four banks of 256 kilobytes each, that is 1024 kilobytes. When I made the 256 kB expansion to my Commodore 64, I renamed the computer to 2564 --- 256 kB C64. The first three digits specify the amount of memory, whereas the last two ones tell the machine type number. A logical choice for the name of a 512 kB C128 is 5128 --- the first three digits tell the amount of memory in kilobytes, and the last three expose the original machine type. Unfortunately the 256 kB and 1024 kB expansions for the C128 cannot be named so nicely. I have baptized my C128D to C1028D, though. The subsections 1.1 through 1.4 of this section apply for the PIA expansion. You can skip them, if you want to save some trouble and money and are going to expand your machine only to 256 kilobytes. Similarly, the section 1.5 can be skipped if you aim only to the 512 kilobyte expansion. 1.1 Expansion memory in 16 kB blocks The processor of Commodore 128, MOS 8502, has an 8-bit data bus, and its address bus is 16 bits wide. Like other 8-bit processors, it can address only 64 kB of memory at a time. In most 8-bit computers, the memory is limited to these 64 kilobytes. How could one add memory above this limit? The solution is simple: the memory is divided into banks of no more than 64 kB, which are switched on and off. Some processors have been added a special circuit for this purpose, in which case the executing program can be in its own 64 kB bank and the processed data in another bank. For example, MOS 6509, a fellow processor of MOS 8502, works in this way, enabling access to one megabyte. The Commodore 128 uses a sophisticated chip, MOS 8722 MMU (Memory Management Unit), which lets you to activate one 64 kB memory bank of a total of two memory banks at a time. The PIA expansion expands each C128 memory bank to 256 kilobytes. The extended memory is divided to sixteen blocks of sixteen kilobytes each. The processor can address up to four of them at a time. Every four 16 kB segment of the address space can be mapped to any 16 kB block. Figure 1 shows the mapping right after startup. However, the video chip VIC-IIe --- MOS 8566 (8564 for NTSC) --- retrieves its data from the memory outside the normal bus. The internal address registers of VIC-IIe are 14 bits wide, so it can address only 16 kB without external logic. The required two extra bits for accessing the whole 64 kB video bank are provided from the second CIA chip, and the video bank is selected by the MMU. Our extra logic provides additional two address bits for accessing the whole 256 kB of the selected video memory bank. MPU's RAM RAM pool (bank 0) VIC-IIe's RAM +--$10000 --+ +-- $40000 --+ +--$10000 --+ | | /--->| Segment F |<---\ | | | Block 3 |-/ +-- $3C000 --+ \-| Block 0 | | | /--->| Segment E |<---\ | | +-- $C000 --+ | +-- $38000 --+ | +-- $C000 --+ | | |/-->| Segment D |<--\| | | | Block 2 |-/ | +-- $34000 --+ | \-| Block 1 | | | |/->| Segment C |<-\| | | +-- $8000 --+ || +-- $30000 --+ || +-- $8000 --+ | | || | Segment B | || | | | Block 1 |--/ | +-- $2C000 --+ | \--| Block 2 | | | | | Segment A | | | | +-- $4000 --+ | +-- $28000 --+ | +-- $4000 --+ | | | | Segment 9 | | | | | Block 0 |---/ +-- $24000 --+ \---| Block 3 | | | | Segment 8 | | | +-- $0000 --+ +-- $20000 --+ +-- $0000 --+ | Segment 7 | +-- $1C000 --+ | Segment 6 | +-- $18000 --+ | Segment 5 | +-- $14000 --+ | Segment 4 | +-- $10000 --+ | Segment 3 | +-- $0C000 --+ | Segment 2 | +-- $08000 --+ | Segment 1 | +-- $04000 --+ | Segment 0 | +-- $00000 --+ Figure 1. Memory mapping right after power-up 4164 41256 +--------+ +--------+ NC | 1 \/ 16| VSS MA8 | 1 \/ 16| VSS D | 2 15| -CAS D | 2 15| -CAS -W | 3 14| Q -W | 3 14| Q -RAS | 4 13| MA6 -RAS | 4 13| MA6 MA0 | 5 12| MA3 MA0 | 5 12| MA3 MA2 | 6 11| MA4 MA2 | 6 11| MA4 MA1 | 7 10| MA5 MA1 | 7 10| MA5 VDD | 8 9| MA7 VDD | 8 9| MA7 +--------+ +--------+ Figure 2. The Dynamic Random Access Memory Chips 4164 and 41256 1.2 Memory chips Commodore 128 uses 64 kb dynamic RAM chips of JEDEC standard. In 1982, when the Commodore 64 was introduced, they were most modern technology, they needed only one operating voltage supply instead of traditional three. The semiconductor memories have developed fast, however, and now a chip in a DIP of equal size can hold 256 kilobits. The pinout of these 256 kb chips differs minimally from the 64 kb ones. The smaller 64 kb chips, at least the ones used in C64 and C128, have one unused contact. The address line to handle three times bigger memory is tied to this pin. In the DRAMs the address lines are multiplexed: two address bits use the same pin successively. In the MikroBITTI article Pekka wrote that 256 kb chips are rather cheap, and the price would lower as the production rate increases. Nowadays the production must have almost stopped. When Pekka bought his chips between March and April of 1986, they costed about 50 FIM each. When the original article was published, they costed less than 20 FIM. After that the prices rose due to a memory shortage. But nowadays the chips don't cost practically anything, if you're lucky. Many users of IBM PC compatibles want to upgrade their system memory with 1 Mb chips or alike and would like to get rid of their old 256 kb chips. I bought eight second-hand chips with total 35 FIM, and later 36 chips with 117 FIM, including shipping. The lowest price of unused chip I encountered was 13 FIM a piece and the highest was 30 FIM, almost 10 times the price I paid! The 256 kb chips don't consume significantly more power, so there is no need for a bigger power supply. However, devices that take their power directly from the computer can cause problems. You can find this out by experimenting. The speed of the chips doesn't prevent the replacement either. According to their schematics diagrams, Commodore 64 and 128 can use chips with access time of 200 nanoseconds. (Besides, the oldest Commodore 64 I have uses 300 ns chips housed in ceramic packages.) Even the slowest 256 kb dynamic RAMs are not that slow. It might be wise to replace the bypass capacitors near the memory chips with bigger ones, at least if you are going to make the MMU expansion (see Section 1.5). On the other hand, my machine works well with the default 220 nF capacitors. If your computer starts to work unreliably, too small bypass capacitors could be the culprit. 1.3 Dynamic headaches The dynamic RAM chips are organized in rows and columns. In 64 kb chips, a row is 256 bits wide, and in 256 kb ones it is 512 bits wide. Also the memory address is divided into row and column addresses. When a bit is being accessed in the dynamic RAM, the row address is asserted before the column address. First the interfacing circuitry puts the row address on the Multiplexed Address bus, while the video chip asserts the -RAS (Row Address Select) signal for a short period. After that, the video chip pulls the MUX line low, and the interfacing circuitry places the column address on the bus while pulling low the -CAS (Column Address Select) signal of the selected RAM bank. After all this, the bits in that position can be read or written. The computer has two circuitries that take care of this multiplexing. The multiplexers U14 and U15 form the address when either one of the C128's two processors has the bus, whereas the video chip produces the row and column addresses itself when it needs its screen data. You could access a set of nearby locations faster, if you specified the row address only once, and then produced only the column addresses for each location. This technique is supported in the Acorn Archimedes computer on the processor level, and some other computers utilize it with external circuitry as memory interleaving. The Commodore, however, does not have to hassle with this, as its system clock rate is so slow. As a matter of fact, it actually uses the least significant processor address bits (A0--A7) as a row address and the most significant bits (A8--A15) as the column address. 1.4 Memory refresh A dynamic memory chip stores the data bits as charged tiny capacitors, which discharge among the time. The data must be refreshed periodically, every 2--4 milliseconds, by recharging the capacitors. If the whole contents of the memory was refreshed simultaneously, the power peak would cause enormous problems. Only a block of one or two rows can be refreshed at a time. The 64 kb chips have 128 blocks to be refreshed, which implies a 7-bit refresh counter ($2^7$ equals 128). In order to avoid disturbance, 256 kb chips must have more blocks. Thus they require a longer refresh counter (8 bits). As the amount of refresh cycles has increased, the capacitors' ability of keeping charge has been improved. The 64 kilobit DRAMs required 128 refresh cycles every 2 milliseconds, now the 256 kb chips need 256 cycles but every 4 ms. Whenever you select a row address (see Section 1.3), the block to which the row address belongs gets refreshed. As the 64 kilobit chips have a 7-bit refresh counter, the lowest seven row address bits specify the row address, and the highest bit is ignored. The 256 kilobit memory chips have an 8-bit counter, so they ignore the 9th row address bit and determine the block to be refreshed by the eight lowest bits. The VIC-IIe chip refreshes the memory systematically, 5 rows in the end of each screen scan line. It does this by selecting a row address determined by its internal counter, and then increases this counter by one. The video chip could have only 7-bit refresh counter, and it would still operate with 64 kb chips, but fortunately it has an 8-bit counter, so all of the 256 kb chips get refreshed. Newer memory chips can be refreshed using a CAS-before-RAS technique. In this technique, you pull first the -CAS signal low, and then the -RAS signal. The memory chips recognize this as a memory refresh condition, and they refresh a block and increase their internal refresh counter. However, this technique was not available when the Commodore 64 and its video chip were designed. 1.5 The MMU expansion The Commodore 128 has two memory banks, numbered 0 and 1. The banks are switched in and out by a custom chip called MOS 8722 MMU (Memory Management Unit). The chip has the registers for handling four memory banks, but there are only two hardware lines for bank selection, named -CAS0 and -CAS1. They are connected to the -CAS signal (see Section 1.3) of the memory chips in banks 0 and 1, respectively. The MMU expansion adds two new memory banks to the computer. It adds another 8722 MMU chip to the system, routing some signals so that the chip considers bank 2 as bank 1. The -CAS0 and -CAS1 outputs of the two MMU chips will be combined to form the -CAS signals for all four memory banks. The logic glue involved is very simple, and designing it was quite straight-forward. 2 Building the expansion 2.1 Disclaimer Although this procedure worked perfectly for me, I cannot guarantee that anyone else can perform this upgrade without damaging their computer. I therefore disclaim any responsibilty for any damage that may occur as a result of attempting this upgrade. It will also void any warranty on your computer. On a more positive note, there is no reason why someone who is experienced in wielding a soldering iron, and has done some electronic construction or troubleshooting, should not be able to perform this upgrade successfully. 2.2 Getting started A termostate soldering iron, desoldering pump or other desoldering tool, a screwdriver, a spoon and a continuity tester are the only tools needed. The spoon is for removing the chips. A bottle top remover is not suitable for that. A tiny screwdriver is equally good. Just insert the screwdriver tip under one end of the chip and wound it a bit in upward angle so that the chip moves slightly. Then insert it to the other end of the chip and try to lift it a bit. You may have to repeat this procedure. Be careful not to wound the pins too much. The continuity tester is vital for checking suspicious connections. If your tester does not automatically select proper measuring range, use the coarsest (mega-ohm) range, as it uses smallest current, which shouldn't damage any chips on the board. The installation begins of course by opening the machine and removing the keyboard and LED cables (and internal drive and power supply in the C128D). It is useful to memorize, photograph or draw how the parts were initially connected. After removing the cables, open the screws that hold the metal RF shield and the motherboard with the case, and remove the shield and the board. If you are going to expand your machine only to 256 kilobytes, skip the following subsection. If you aim to a whole megabyte, expand your computer first to 512 kilobytes, and then make the MMU expansion. 2.3 Expanding to 512 kilobytes The PIA expansion consists of one daughter board, which contains most of the new logic, one piggy-backed chip, and a spaghetti of wires. In Figure 3, there is a schematics diagram of the daughter board for the PIA expansion. If you cannot read it, try to get the LaTeX, HTML or PostScript version of this document. IC4 ^ ^ /---3->!-4-----\ ^ | | *--11->!-10---\| 20 | < R1 === C1 *---5->!-6---\|| +------+------+ > 4k7 |100nF *---9->!-8--\||| 2-| PA0 Vcc CNT |-40 < V ^ | 74LS05 |||| IC2 3-| PA1 SP |-39 | 20 | \---------\ |||| 74LS153 4-| PA2 -IRQ |-21 | +------+------+ | |||| ^ 5-| PA3 RS0 |-38-|-36-| RS0 Vcc CA1 |-40-* |||| Vcc| 16 6-| PA4 RS1 |-37-|-35-| RS1 CA2 |-39-/ |||| +-------+ 7-| PA5 RS2 |-36 *-38-| -IRQA PA0 |--2---*|||--6-|I0a Za|--7-B15> 8-| PA6 RS3 |-35 | 37-| -IRQB PA1 |--3----*||-10-|I0b Zb|--9-B14> 9-| PA7 -RESET |-34-|-34-| -RESET PA4 |--6-----||--5-|I1a Vss|--8---\ 10-| PB0 D0 |-33-|-33-| D0 PA5 |--7-----*|-11-|I1b Ea|--1---* 11-| PB1 D1 |-32-|-32-| D1 PB0 |-10------*--4-|I2a Eb|-15---* 12-| PB2 D2 |-31-|-31-| D2 PB1 |-11--------12-|I2b | V 13-| PB3 D3 |-30-|-30-| D3 PB4 |-14---------3-|I3a S0|-14-*--22-| CS0 PB2 |-12--------15-|I4 Z|-5 R2 33R M6526 | 1 -I/O2>-23-| -CS2 PB3 |-13--------14-|I5 -Z|-6-^v^-MA8> V | PB6 |-16--------13-|I6 -E|-7-\ | IC1 Vss PB7 |-17--------12-|I7 Vss|-8-* +-------------+ +-------+ | MC6821 | 1 IC3 V V 74LS151 Figure 3. The schematics diagram of the PIA expansion. See text. There are some signals that you must wire to the mother board. You can take the -I/O2 and A7 signals from the cartridge port, or from some through-put location near the daughter board. The -I/O2 signal should be on the pin 7 of the chip U3 (74LS138). The A7 can be also taken from the MMU's (U7, MOS 8722) pin 23, in which case the address range of the PIA will be limited to $DFC0--$DFFF instead of $DF80--$DFFF, or from the 8502's pin 14. It is also on the multiplexor U14 (74LS257A), in pin 3. The MA8 signal is the new Multiplexed Address line for the memory chips and should be soldered to the pin 1 of each chip. All the remaining five signals on the right edge of the diagram interface to the multiplexor chip U14. The MUX signal goes to pin 1. To interface the address lines A14, A15, B14 and B15, you have to desolder two pins of the multiplexor, 2 and 5. The signal A15 should then be wired to the mother board contact under the multiplexor pin 2, or to the 8502's pin 23, and the signal B15, the relocated address line should be soldered to the multiplexor's pin 2. Similarly, the contacts A14 and B14 should be connected to the system bus line A14 and the U14's pin 5, respectively. Figure 4 shows the pinout of the multiplexor chip U14. U14 74LS257A +--\__/--+ MUX -|1 16|- Vdd TA15 -|2 15|- -AEC A7 -|3 14|- TA12 VMA7 -|4 13|- A4 TA14 -|5 12|- VMA4 A6 -|6 11|- TA13 VMA6 -|7 10|- A5 Vss -|8 9|- VMA5 +--------+ Figure 4: Pin-out for the multiplexer chip U14 +-----\___/-----+ +-----\___/-----+ Vss -|1 40|- CNT Vss -|1 40|- CA1 PA0 -|2 39|- SP PA0 -|2 39|- CA2 PA1 -|3 38|- RS0 PA1 -|3 38|- -IRQA PA2 -|4 MOS 37|- RS1 PA2 -|4 MC 37|- -IRQB PA3 -|5 36|- RS2 PA3 -|5 36|- RS0 PA4 -|6 6526 35|- RS3 PA4 -|6 6821 35|- RS1 PA5 -|7 34|- -RESET PA5 -|7 34|- -RESET PA6 -|8 CIA 33|- D0 PA6 -|8 PIA 33|- D0 PA7 -|9 32|- D1 PA7 -|9 32|- D1 PB0 -|10 31|- D2 PB0 -|10 31|- D2 PB1 -|11 30|- D3 PB1 -|11 30|- D3 PB2 -|12 29|- D4 PB2 -|12 29|- D4 PB3 -|13 28|- D5 PB3 -|13 28|- D5 PB4 -|14 27|- D6 PB4 -|14 27|- D6 PB5 -|15 26|- D7 PB5 -|15 26|- D7 PB6 -|16 25|- Phi2 PB6 -|16 25|- E PB7 -|17 24|- -FLAG PB7 -|17 24|- CS1 PC -|18 23|- -CS CB1 -|18 23|- -CS2 TOD -|19 22|- R/-W CB2 -|19 22|- CS0 Vdd -|20 21|- -IRQ Vdd -|20 21|- R/-W +---------------+ +---------------+ Figure 5: The CIA and the PIA +----------------------------------------------+ | Electronic Components | +----------+-----------------------------------+ | Symbol | Description | +----------+-----------------------------------+ | IC1 | MC6821 | | IC2 | 74LS153 (or 74LS253) | | IC3 | 74LS151 (or 74LS251) | | IC4 | 74LS05 | | U9--U12, | 80256 or | | U21--U24 | compatible | | C1 | 100 nF polyester capacitor | | R1 | 33 ohm resistor | | R2 | 4.7 kilo-ohm resistor | +----------+-----------------------------------+ +----------------------------------------------+ | Other Parts | +----------+-----------------------------------+ | Quantity | Quality | +----------+-----------------------------------+ | 2 pcs | 10-pin flat cable connector pair | | ca. 15 cm| 10-wire flat cable | | 1 pc | 16-pin piggyback socket | | 2 pcs | 16-pin WW-socket | | or | one 16-pin piggyback socket and | | | two normal 16-pin sockets | | 1 pc | 40-pin WW-socket | | or | one 40-pin piggyback socket and | | | a normal 40-pin socket | | 10 pcs | 16-pin socket | | 1 pc | 14-pin socket | | plenty of| connection wire | +----------+-----------------------------------+ Table 1. Parts list for the PIA expansion 2.3.1 Removing the old memory chips First you have to remove the memory chips U38 through U53. If you look at the mother board from the front of the computer as if you were typing, the chips are on the front left in two rows of eight chips. They are of type 4164 (or 3164 or 6665 or 6664 or 8064 or...). You could install the new chips into sockets, but I thought that it is a waste of money. If these memory chips are already on sockets, the most of the work is done for you. It helps a lot, if you remove the bypass capacitors before removing the chips. Removing the components is easiest with a desoldering pump. It becomes even easier, when you first solder the pins with fresh solder, so that the hartz from it makes the removal of old solder easier. Using much power is questionable, as the copper folio comes off the board in a surprisingly easy way. As usual, I used a screwdriver like a crowbar, and the through-coppering got lost from several places. This was not crucial, as those pins were connected only to the down side of the board. However, three or four routes broke on the top side also. This made it far more difficult (and slower) to solder the new chips in, but I succeeded on the first try. After you have removed the 4164s, you can solder the 16-pin sockets (or the 41256 memory chips) into their places. You can solder the capacitors back as well, if you removed them. 2.3.2 Adding the new address line You must connect the pin 1 of each memory chip (or socket). It is the extra address line (MA8) to the switcher. The best way is to solder a Wire-Wrap wire to each contact under the mother board, but any thin and pliable uni-strand wire should do. The wire does not affect in any way the computer's operation with 64 kb chips. After the pins have been connected together, they must be temporarily connected to +5 V, which is in the pin 8 of the memory chips. Comparing to TTL chips, the operating voltages are `reversed' in dynamic memories. Now the new 256 kb memory chips can be installed to the sockets (preferably right-side forward), and you can try switching the power on. You do not have to connect anything except the power cable and the cable to the TV set or monitor. Ensure that the ``40/80 display'' key is up, and that the monitor is set to display the 40 column screen, too. It is a good idea to turn on the monitor first and let it warm up, so that it will show the picture from the very beginning. If the screen shows up normally, you may not (yet) have made any mistakes. If it does not show up at all, you have to find possible cut-outs and shorts. Multi-colored `@'s show up usually because of too small bypass capacitors. Another cause is that the pin 1 is not connected to +5 V. In this case the screen may come up normally, but a little disturbance in the operating voltage locks the computer up. Now the computer should operate exactly like an unexpanded C128, so any previously working program should work with it. 2.3.3 Prepare for the final step Next you remove U14 (74LS257, to the right of the memory chips) and U1 (MOS 6526, near the keyboard connector). Either or both of these chips may already be on sockets, and you must remove the rest. Reinsert the chips and check if the machine boots up. If the computer does not work on first try, remember to disconnect any cables from it before trying to fix the problem. The soldering iron may occasionally give little electric pulses to the computer, and this might burn some expensive chips, especially if the computer is hooked to a wall outlet or a television set. When you have completed the preparations, you can start building the control logic. You could build the whole expansion by piggy-backing chips, that is, by soldering new chips on the top of old ones, bending some feet to the side, and connecting messy wires all over your computer. However, the best way is to put most of the chips on a daughter board. I used only a small daughter board, and piggy-backed five or six chips, but you can be wiser and put all new chips on the daughter board. My daughter board interfaces the heart of the expansion, MC 6821 PIA, to the bus of the computer through the pins of U1, the MOS 6526 CIA near the keyboard connector. The CIA is raised on the board, and its pins are lenghtened with two through-put socket halves, so that they can reach the socket on the mother board. I built the daughter board on an uncoppered prototype board, a plastic board with holes punched in it at a 1/10 inch grid. The room reserved for the mother board in the C128 and C128D is very shallow, about one third of the height in the C64. In addition to that, the front edge of the mother board must be even shallower, as the metal shield has an angle in it. Due to this, you cannot use any sockets in the CIA daughter board, and you have to choose the chip layout very carefully. My daughter board has the PIA chip on the left side of the CIA. To leave room for the MMU expansion, I could put only two chips (IC2 and IC3) horizontally next to the notched end of the PIA (IC1) and CIA (U1). I placed the inverter (IC4) with the 100 nF bypass capacitor near the other end of the PIA chip. A far better way is to interface the daughter board to the socket of U7 (MOS 8722 MMU). There are not so terrible space limitations, the RF shield is higher near the rear edge of the machine than on the front edge. In addition to that, the keyboard cable of the flat C128 is not so likely to damage that daughter board than the CIA board, which would be next to the keyboard connector. The MMU daughter board would allow you to make an easily removable expansion, as no chips would be piggy-backed. You could even make an option for installing a second MOS 6581 (8580 for the 9 volt version) SID (Sound Interface Device) on the board to get stereo sound. However, this board should be etched, as the PIA and MMU pin layouts differ very much from each other. See Figure 6 for pinouts for the MMU. Pinouts for the PIA and CIA are presented in Figure 5. Building the CIA daughter board was a real pain. I had to solder the CIA directly to the piggy-back socket pins, and I even bent the CIA pin ends aside, so that I could make it about 1 mm shallower. I put the CIA pins and the through-put socket halves to the same holes and started soldering. To keep the socket halves parallel, I put one half against the outside of the CIA pins, and the other half against the inside. It was very easy to solder the half whose contacts were outside the pins, but the other half was a real pain. It could be done by heating a CIA pin, inserting some solder from the side, and hoping that it connects the piggy-back socket pin. I had to solder those pins four or five times. After raising the CIA on the daughter board, it is a very good idea to insert the board to the socket and check if the machine boots up. If some of the right side pins (21--40) are loose, the machine can jump to ML monitor due to an unexpected interrupt, or it can misread the keyboard. In the C64 mode, it will probably jam. The next step is to add the PIA on the board. The contacts from the CIA except the operating voltages may be difficult to route. I solved the problem by putting the wires through the very small holes that were left between the biggy-back socket halves and the down surface of the daughter board. It was very painful, but the design is very compact. After soldering all CIA contacts to the PIA, I wired the inverter and the rest of the chips. To increase reliability, I used thin multi-strand wire, as uni-strand wire gets easily loose when you push it. Since I had finished the daughter board, I bent up the pins 2 and 5 of the U14 multiplexer chip, and connected its pins 1--3 and 5--6 to the daughter board with wires. First I inserted the wires for A14 and A15 directly to the chip socket, but as it turned out to be unreliable, I located a through-put place for each line, and soldered the wires there instead. When you have wired the multiplexer U14, remove the jumper wire between MA8 and +5 V and connect that address line to the daughter board. Then connect the PIA's -CS line to -I/O2, which is in U3's pin 7 (or one of the through-put places along the trace's path to the cartridge port), and insert the daughter board to the socket. Switch the power on and pray that your dear computer works. If you get only crap consisting of @'s or some randomly changing graphics on the 40 column screen, check that all CIA pins have a good contact to the piggy-back socket, and that the wires from U14 and its socket are firmly connected. If it doesn't help, you have to check all daughter board connections with the continuity tester. Don't panic, you can ensure that the computer works by connecting the MA8 line back to +5 V, by bending the U14 lines back down, and by inserting a spare CIA chip to the CIA socket. 2.3.4 Testing After you have installed the boards to your machine, it is time to test the connections. You can connect LED, keyboard and probably disk drive in addition to the power cable and the TV cable, but do not fasten the mounting screws yet. If the 40 column screen shows up and if the machine seems to operate, input the following test program: 10 PB=57282 20 POKE PB,255:POKE PB+1,4:POKE PB,255 30 PRINT"PRESS A KEY AFTER THIS HAS DISAPPEARED": FOR I=0 TO 3000:NEXT 40 POKE PB,14:WAIT 198,15:GET A$:POKE PB,255 On the line 10 a variable PB is set up. It is the address of the peripheral and data direction registers for the 6821 port B, and the block selection register of the segments 2 and 3 and the VIC-IIe. The line 20 contains initialization of PIA: the lines PB0--PB7 are set outputs, the data direction register is switched to data register with `POKE PB+1,4', and the PB lines are set high. On the line 40 VIC-IIe is given block 0 ($00000--$0FFFF) of the default bank (0), and then the program waits for a keypress and restores the block F ($30000--$3FFFF). If this test program works as expected, the screen will be filled with `@'s and other random characters. At this point, you may want to switch to the C64 mode and to run the TEST program, which is among the distribution files. (See Section 5.1.) Also, you can try the PIAGLOBE.128 program to test almost all of the 512 kB or 1024 kB memory. The PIAGLOBE.128 program is based on Georg Schwarz's globe spinner GLOBE.64 that uses two graphics screens. He has made a slightly faster version for the C128, utilizing the 2 MHz mode in the screen border. But compared to it, PIAGLOBE.128 is from other planet. Depending on the amount of memory available, it calculates 112 or 56 pictures of the globe and then uses them in a continuous animation. One revolution will last approximately 2.23 seconds on PAL systems and 1.87 seconds on NTSC. As the calculation phase lasts more than a minute, the program changes the screen color between each picture. On NTSC systems, the edge of the globe might not display correctly. The edge is rounded with 24 sprites, which are moved around by a raster interrupt routine, starting from $4801. I did not bother to think about the timings, since I had enough troubles with relocating the program and the tables, and in trying to get all that graphics data to fit in the memory. In the distant future I might make a better looking version of the globe spinner, who knows. There is over 80 kilobytes of unused memory when running the program on a C1028. 2.4 Expanding to 256 or 1024 kilobytes This MMU expansion is far easier to understand than the PIA expansion, and maybe faster to build, too. You have to solder the new MMU and a couple of logic chips on top of some chips laying on the mother board, or to install them on a daughter board. I chose the piggy-backing method. The biggest problem with this expansion is that the MOS 8722 MMU is a custom chip from Commodore, and it is only used in the Commodore 128, which has not been manufactured for ages. If you do not happen to have a wreck C128 lying around, you can try ordering the chip from Jameco Electronics. The chip shouldn't cost more than 10 USD. You can reach them at: Orders (phone): 1-800-831-4242 Orders (fax): 1-800-237-6948 Fax (overseas): +1-415-592-2503 Mail: Jameco Electronics 1355 Shoreway Road Belmont, CA 94002 U.S.A. In Figure 6, there is a wiring diagram for this expansion. It is a bit tight, and needs some clarification. The U9 74F32 is a quad OR chip (each C = A OR B) that takes the -CAS0 and -CAS1 outputs from the original MMU and lets them through to the original memory chips as -RAMCAS0 and -RAMCAS1 if and only if both the -CAS output from the video chip and the -CASENB output from the PLA are active. IC9, the 74F32 next to U9, ``hooks'' the -RAMCAS outputs and lets them through when the -CAS0 output of the new MMU is active, that is, when the banks 0 or 1 are being accessed. The IC9 also generates the -CAS signals for the two new memory banks, -RAMCAS2 and -RAMCAS3. The 68 ohm resistors protect the IC9, as the inputs of the DRAM chips are not fully TTL compatible. The logic glue at the lower edge of the picture take care of feeding correct values to the new MMU's data leads D6 and D0. See Section 3.1.3 for a complete description. The IC8 4066 takes the data lines D0, D1, D6 and D7 from the system bus and feeds two of them to the new MMU's data lines D0 and D6 at a time. In my implementation the D0 and D1 lines come from the U20 4066 and the remaining two data leads from the original MMU. The U20 4066 is not really needed at all, as the same lines are on the original MMU, but I chose it as it was easy to piggy-back. On the lower right corner is U3, a 74LS138 which takes care of producing the -CS (Chip Select) signals for the address ranges $D400--$DBFF and $DC00--$DFFF. The IC6 does not actually need any signals from it, not even the -IOCS that is on the contact -G2, but it was easier to piggy-back so. If you build a daughter board for this expansion too, you can wire the IC6's G1 to +5 V and the -G2 and -G3 to ground. The IC6 together with the IC7, a quad Negative-AND chip, inputs the four lowmost address bus bits and produces the Enable signals for the IC8 4066. ^ ^ Vcc | 1 Vcc | 1 +-----------+ +-----------+ 3--|TA15 -RESET|--2-------2-|-RESET TA15|--3 4--|TA14 AEC|-16------16-|AEC TA14|--4 5--|TA13 MUX|-17------17-|MUX TA13|--5 IC9 U9 6--|TA12 A0|-18------18-|A0 TA12|--6 74F32 74F32 7--|TA11 A1|-19------19-|A1 TA11|--7 ^ ^ 8--|TA10 A2|-20------20-|A2 TA10|--8 Vcc | 14 Vcc | 14 9--|TA9 A3|-21------21-|A3 TA9|--9 +-----+ +-----+ 10-|TA8 A5/A4|-22------22-|A5/A4 TA8|-10 /--1-|A1 B1|--2-\ -|B1 A1|- 11-|-CAS1 A7/A6|-23------23-|A7/A6 -CAS1|-11--*--4-|A2 B4|-12-*-\ -|B4 A2|- 12-|-CAS0 A8|-24------24-|A8 -CAS0|-12-*--10-|A3 C4|-11---o\-|C4 A3|- 13-|MS2 A9|-25------25-|A9 MS2|-13 \--13-|A4 B2|--5-\ -|B2 A4|- 14-|MS1 A10|-26------26-|A10 MS1|-14 /-3-|C1 B3|--9-*-\ -|B3 C1|- 15-|MS0 A11|-27------27-|A11 MS0|-15 / /6-|C2 C3|--8---o\-|C3 C2|- | A12|-28------28-|A12 | | | +-----+ +-----+ | A13|-29------29-|A13 | | | Vss | 7 Vss | 7 | A14|-30------30-|A14 | | | V V | A15|-31------31-|A15 | R3< < R4 | R/-W|-32------32-|R/-W |68ohm> > 68ohm | Phi IN|-33------33-|Phi IN | < < | D0|-35 /----35-|D0 | | | | D1|-36-|----36-|D1 | | \---- -RAMCAS2> | U7 D2|-37-|----37-|D2 IC5 | | | M8722 D3|-38-|----38-|D3 M8722 | \------ -RAMCAS3> | MMU D4|-39-|----39-|D4 MMU | | D5|-40-|----40-|D5 | Legend: | D6|-41-|\ /-41-|D6 | | D7|-42-||*|-42-|D7 | | | -Z80EN|-43-||||-43-|-Z80EN | < \ | -FSDIR|-44-||||-44-|-FSDIR | > Resistor &! 74F00 port * Crossing | -GAME|-45-||||-45-|-GAME | < / | -EXROM|-46-||||-46-|-EXROM | | | MS3|-47-||||-47-|MS3 | ^ ^ | 40/-80|-48-||||-48-|40/-80 | Vcc | 16 Vcc | 16 +-----------+/---|||/ +-----------+ +-------+ +-------+ Vss | 34 | |\\------\Vss | 34 A0>--1-|A -G3|-4---|-G3 A|- V | \ \---\ \ V A1>--2-|B -G2|-5---|-G2 B|- | *--\ \ | A2>--3-|C G1|-6---|G1 C|- 1| 4| 8|11| | 1| 4| 8|11| /-''. Then change a blank disk to the drive before RUNning. The second archive file, UTIL256.SFX, contains the following software: 5.1 Memory test The program TEST tests the block selection and the whole memory. If it jams before reporting ``Test passed'', something has gone wrong. Its source code is in the file TEST.A, which requires a library STRING.A. I translated the executable to English by patching the binary file. 5.2 Poor man's multitasking With the MULTI51200 program you can run four different programs. The program does no multitasking, it only holds four environments in the memory, each in its own memory block. MULTI.A is the source code. After loading it with ``LOAD"MULTI51200",,1'' and initializing the BASIC pointers with ``NEW'', you can switch the environments with ``SYS51200,f,b''. The parameter f is a flag determining if the current block should be copied to the destination block (0) or not (1). The parameter b selects the destination block (0--3). The initial block is 3. 5.3 Machine language monitor If you don't like to switch the memory blocks manually in your favourite machine language monitor, the MON256 utility is for you. The memory is again divided to four 64 kB blocks, numbered from 0 to 3. The commands are as follows: a nnnn cmd or Assembles instruction cmd to . nnnn cmd memory address nnnn. b bb ff Selects a block. The bb holds the block number, and ff is a flag. If it is 1, it directs all memory accessing to RAM. If it is 0, you can access the ROMs and I/O. c hhhh iiii jjjj Compares the memory area hhhh--iiii with the area beginning from jjjj. d [hhhh [iiii]] Disassembles memory. f hhhh iiii nn Fills the memory between hhhh and iiii with the byte pattern nn. g [hhhh] Executes program until a BRK is encountered. h hhhh iiii nn mm... or Hunts the memory area hhhh--iiii h hhhh iiii 'text for the byte sequence nn mm... or for `text'. j [hhhh] Calls a subroutine. l "filename"[,n] Loads a program. Default device number is 8. m [hhhh [iiii]] Hexadecimal dump of memory. > hhhh nn mm... Stores bytes in memory. r Dumps the registers (for `g' and `j'). ; Modifies the register values. s "filename",n,hhhh,jjjj Saves the memory area hhhh--jjjj to device n. t hhhh iiii jjjj Copies the memory area hhhh--iiii to jjjj. v "filename"[,n] Verifies a program. Default device number is 8. x Exits the monitor. @ [command] Sends `command' to device 8. If it begins with $, the disk directory will be read. If no command is given, the disk drive's status will be displayed. The source code for the monitor is split in the files MON.A, CONSOLE.A, COM.A, ROUTINES.A and TABELS.A. 5.4 RAM disk The most important utility is a RAM disk program, which occupies about 9 kilobytes of memory. It transfers Kernal and BASIC interpreter to RAM and patches the serial bus routines. The actual program is in the area $00800--$03FFF. It emulates all VC-1541 functions except relative files. For example, the commands U1, U2, B-A etc. work. UI+ and UI- make no difference. The program also detects some fast loaders and works with them installed. The loader is called RAM DISC, and the patched Kernal is in RAM.K. You need only patches to the low-level serial bus routines, so you may want to restore the original colors and keyboard definitions. To minimize incompatibility problems, you should replace the ROM chip that holds the BASIC and Kernal ROMs with an EPROM containing the patched Kernal. The RAM disk routines are in RAM.C. 5.4.1 Disk copiers The program RAM DISC COPY copies a regular 1541 disk to RAM. It utilizes the slow U1 command, and it is included as an example only. The source code DUP.A exposes the RAM disk's storage format. A faster and more useful tool is FDUPLICATE. Using it, you can copy a regular disk to the RAM disk or vice versa. You can make multiple copies of a disk easily. This program's fast transfer routines are designed for PAL systems, and the utility cannot be used in NTSC machines without little modification. Its source code is in the two files S/SUCK and S/DSUCK. 6 Enhancing the PIA expansion There are a couple of unused contacts in the PIA. In addition to that, two 7405 ports are not connected. The extra PIA lines include an input, CB1, an input/output line CB2, and the Interrupt Request line -IRQB. If you connect the -IRQB line to the -IRQ or -NMI input of your system, you can have one or two new interrupt sources, useful for interfacing your custom hardware. And if you are running out of User Port pins, the lines CB1 and CB2 can save you from designing an I/O cartridge. Besides, you can use the -IRQB as an output if you wire the CB1 line to something that you can control with software, CA2 for instance. Just remember to add a pull-up resistor to the -IRQB line if necessary. 6.1 Built-in freezer For the Commodore 64, there are several `freezer' cartridges that let the user to halt theoretically any program (game) to alter it (make the player immortal), or more often merely to make a `back-up copy' of it. Alas, anything cannot be frozen with these cartridges. If the programmer of the game is clever enough to inhibit IRQ and NMI interrupts in his program, and if the code runs at the area $0000--$0FFF, no external cartridge will be able to halt it without asserting the -RESET signal, which would lose most status information of the computer. You can use the PIA expansion to freeze programs, in many cases also in the C128 mode. In the C64 mode, an internal freezer can stop anything except a totally jammed program. In the C128 mode, it can stop software running on the 8502 without using any ROM at the area $C000--$FFFF. This freezer expansion will let you to replace the program's memory with previously initialized RAM by pressing the Restore key. If the NMI interrupts are disabled, freezing will be done with the BRK instruction. As the circuit forces the -HIRAM line to logical zero, the C64 mode interrupt vectors will always be fetched from RAM. All of the freezer software can be stored to RAM, so it is easy to change, and no EPROM programming devices are needed. Another advantage is that the freezer software may freely use 128 kilobytes of memory, and there are 64 kilobytes of working storage, way more than in the best freezer cartridges. Besides, those amounts will be at least doubled or quadrupled in the C128 mode freezer, depending on whether you have built the MMU expansion. For this expansion, you need a double ON--OFF or ON--ON switch, four 1N4148 diodes and two 10 kilo-ohm resistors. First do some preparations. Break the connection between the PIA's -RESET input (pin 34) and the system -RESET, and replace it with a diode with the marked end towards the system bus, so that the pass direction is from the PIA to the system -RESET. Then you have to solder a pull-up resistor between the PIA's -RESET line and the +5 V power outlet. Locate the U29 chip (7406) on the motherboard and desolder its pin 4. Solder a diode between the motherboard connection and the pin with the mark pointing to the chip. Finally, solder the other pull-up resistor between the U29's pin 4 and +5 V. After these modifications, the PIA should continue to reset normally, and the Restore key should remain functional. Now you can mount the switch to the system. If you have an ON--ON switch, hold it in your hand in such an angle that you see two rows of three pins. Solder two diodes from the right-hand contacts of the switch to the U29's pin 4, with the mark pointing to the U29. Solder the PIA's -RESET line (pin 34) to either middle contact of the switch, or to either free contact if you have an ON--OFF switch. Finally, mount the -HIRAM line, which is on the 8502's pin 29, to the remaining middle contact. The switch affects in the operation of the Restore key. When it is open, the Restore key operates normally. When the switch is closed, the Restore key also resets the PIA, switching the default memory blocks in, and forces the -HIRAM line low, so that the interrupt vectors will always be fetched from RAM. The idea of the expansion is that the program runs in some other memory blocks, say 3--0, with the PIA totally disabled from the address space. The default memory blocks ($F--$C) will be initialized mostly with null bytes, which is the opcode of the BRK instruction. You also need the freezer interrupt vectors ($FFFA--$FFFF) and a small interrupt handler that stores the processor registers and switches the main freezer program into the address space. If you want to freeze hanged programs, too, you can do it without losing the state of the I/O chips. By using a custom Kernal ROM, you could even store all 8502 registers except the Program Counter. You just have to be able to reset the 8502 without resetting the rest of the chips. To do this, desolder the -RESET signal, pin 40 on the 8502. Connect a 1N4148 diode between the system -RESET signal and the 8502, with the mark pointing away from the processor. Add a pull-up resistor to the signal, and a switch between the logical ground and the signal. Now, whenever you push the switch, only the 8502 will be reset. If the computer is in the C64 mode at this time, it will remain in that mode, since the MMU does not get reset. You should then use the Autostart code ($C3 $C2 $CD $38 $30 at $8004--$8008), and the Kernal will jump to the vector ($8000). Unfortunately it will destroy all registers except the Y register when searching for that code. More fortunately, if the computer is in the C128 mode, and if the Kernal ROM is not selected in the memory configuration, the processor will fetch the -RESET vector from the active RAM bank. In that case you can store all processor registers except the program counter. Alas, I just have invented a software hack that cannot be frozen with this circuit. If a program runs on the I/O area ($DE00--$DFFF except the range where the PIA is mapped to while the I/O is switched on) and has disabled the NMI interrupts, the program will continue running even if you have activated the freezer and hit the Restore key. Should you ever encounter this type of a software hack, you can use a triple switch and add the LORAM signal (8502's pin 30) to one extra contact. Connect the remaining contact to the U29's pin 4 through a diode with the mark pointing to the U29. This will disable the I/O area for the time the Restore signal is active, so the processor can fetch a BRK from the memory underneath, and will always freeze correctly. I haven't completed the freezer expansion yet, as the daughter-board in my faithful 2564 (C64 with the 256 kB expansion) stopped working when I opened the cover to start the surgery operation. My first attempt of rebuilding it did not succeed, and now I am in Germany, more than one megameter away from the computer. When returning to Finland in August 1994, the freezer expansion will be one of my first projects I am going to finish. So I thought at that time---as of December 1999, I have neither fixed that particular C64 nor completed the freezer expansion. Besides, the expansion would not have much advantage over freezer cartridges or the features present in some emulators. Naturally you also need a program to utilize the freezer circuitry. You don't need to code so much, only the routine to jump back to the freezed program and the routine that saves all registers upon freezing need to be written from scratch. You can patch existing machine language monitors, sprite editors and utilities like that, only the data fetch and data store subroutines must be rewritten. Developing the freezer software is very simple, since you can access the frozen program through a 16 kB window, and you can use the Kernal routines all the time. 6.2 New operating system In my C64, I have replaced the 2364 Kernal ROM with a 32-kilobyte EPROM. The two extra address lines are controlled by the PIA's pins CA2 and CB2. As the C128 uses a 23128 ROM for both C64 BASIC ROM and Kernal ROM, this type of expansion cannot be used. Besides, you can access only 256 kilobytes of the memory in the C64 mode. Why would you want to improve the C64 mode if you can make the C128 mode far better? The C128 has a socket for a Function ROM for your operating system extensions. It can hold a 27256 EPROM, 32 kilobytes. If that does not satisfy your needs, you could use a 27512 EPROM instead. In this case you have to bend the A15 line up. This line could be controlled by the PIA's CB2 line. To ensure that the logic works also when the CB2 line is input, add a 4.7 kilo-ohm pull-up resistor between CB2 and +5 V. 7 Contacting the author If you have anything to ask or comment, feel free to contact me. If you complete either or both expansions, I would like to have an E-mail message or a postcard from you, so that I know I didn't write this document in vain. Finally, if you make any software for the expansion or patch existing programs to make use of the extra memory, I would love to put the software available on the FTP site FTP.FUNET.FI. My addresses are: Internet: Marko.Makela@FTP.FUNET.FI Mail: Marko M\"akel\"a Harakankuja 6 D 19 FIN-02600 Espoo Finland