32MB RAM Upgrade


NOTE: I DO NOT RECOMMEND THAT YOU PERFORM THIS UPGRADE! If you do, there is a good chance that you will permanently damage your GP32. While you are welcome to use this description as a guide to performing the upgrade, I will not accept any responsibility for the consequences. It's all at your own risk.

I did the upgrade in 4 stages:

Find the right RAM
Modify the BIOS
Replace the RAM chip
Add MMU code to applications

My conclusions from the exercise are:
Find the right RAM

If you click the "Submit" button, you will send your input to a new page called form_action.asp.

The 8MB RAM in the stock GP32 is 133MHz SDRAM. It is arranged as 1M x 16 bits x 4 banks, and is addressed with 8 column and 12 row address signals. It uses 4096 refresh cycles per 64ms.
I got a PC133, 128MB, 4 chip DIMM module from the local PC store. It is vital that the module had 4 chips, because PC DIMM modules have 64 data bits so in a 4-chip module each chip has 16 data bits. The module I got has "V-Data" chips, which are made by A-Data Corporation. Each chip is arranged as 4M x 16 bits x 4 banks, and is addressed with 9 column and 13 row address signals. They use 8192 refresh cycles per 64ms.

This is why the bios needs to be updated: the normal BIOS programs the CPU's memory controller to use only 8 column address lines, and also the refresh rate is not fast enough.
I did a pretty thorough comparison between the data sheets for the two RAM chips, and they seem compatible. However, the data sheet for the 32MB chip is a horrible mess of obviously wrong information (for example, the pinout diagram is for a completely different chip) so I can't be too confident about any of it!

Modify the BIOS

I'm not going to explain the changes in complete detail, if you want more detail then look at the BIOS disassembly on Mr. Spiv's site and figure it out for yourself :-)

The changes that I made were:

Address 0x0002B0 00890543 -> 008906A2
Address 0x0028A0 00002710 -> 00004E20

These change the refresh rate to 8192 cycles/64ms

Address 0x0001A8 E3A0B016 -> E3A0B010

Changes BANKSIZE to have 32M/32M banks 6 & 7, instead of 8M/8M

Address 0x00019C E3A08906 -> E3A09906
Address 0x0001A0 E3A09906 -> E2898001

Changes BANKCON6 to use 9-bit column addressing instead of 8-bit. Note: it is possible to piggy-back two 32MB RAM chips to give 64MB total, but this requires BANKCON7 to be set to use 9-bit column addressing for bank 7. I have not bothered to do it.

Address 0x001B78 000004FF -> 000007FF

Sets the CPU pins GPA8/A23 and GPA9/A24 to be address pins rather than port pins.

Mr. Spiv and I have made a modified copy of the multifw2 BIOS available for download. Many thanks to Mr. Spiv for his improvement to this, which makes the extra memory a LOT easier to use! This bios can be used to flash a GP32, but it must not be done until just before the RAM chip is changed because it does not work with the 8MB chip.

Replace the RAM chip

Because the RAM chip has an extra row address signal, a wire must be added to connect this signal to the CPU. Also, the RAM bank select signals BA0 and BA1 are connected to the CPU pins A22 and A21 for the 8MB chip, these signals must be connected to CPU pins A24 and A23 for the 32MB chip.

So, the connections to be made are:
CPU pin 178 (ADDR13)   to RAM pin 36 (A12)
CPU pin 188 (GPA8/A23) to RAM pin 20 (BA0)
CPU pin 191 (GPA9/A24) to RAM pin 21 (BA1)

Pins 20 and 21 on the RAM must be separated from the PCB traces that they normally contact to, as these traces are connected to CPU pins A22 and A21.

Here's the GP32 and RAM module before I started the job:

GP32 and DIMM

Removing the back of the GP32 exposes the RAM chip. I decided to completely remove the PCB and disconnect it from the LCD, because this removed the LCD from the heat involved in soldering the RAM chip.

Internals before the operation

The RAM chip was pretty easy to remove with a hot-air desoldering tool. It would be more difficult with a soldering iron. One good strategy for removing ICs is to use fine-tipped cutters to cut the legs along one side of the device, and then wiggle the body of the IC up and down until you break the legs on the other side of the device. Then a soldering iron can be used to remove the remaining pieces of the legs.

Before putting the 32MB RAM in the GP32, I gently bent pins 20 and 21 up so that they would not contact the PCB when the RAM was soldered in. Here's the RAM ready to go into the GP32:

RAM outside the GP32

Next, I soldered the RAM onto the GP32, and added the three wires. I ran the wires through one of the holes in the PCB where plastic case clips go through. Although you can't see it too well in the photos below, I also added blobs of silicone compound to the ends of the wires, to stop them breaking due to vibration.
This was definitely the hardest part of the job. The pins on the CPU are 0.5mm apart, and so soldering a wire to one pin without connecting to any other pins took a LOT of care!

CPU side
RAM side

Next, I put it all together again and it worked! Well, it didn't work first time because I'd connected one of the wires to the wrong place. But after I pulled it apart, moved the wire, and closed it up again, it was all good :-)

Add MMU code to applications

With the memory controller changes in the BIOS, and the RAM chip installed, the GP32 has 32MB of working RAM. This RAM is at addresses 0x0C000000 to 0x0DFFFFFF. The BIOS system memory is from 0x0C796000 to 0x0C7FFFFF, so from 0x0C000000 to 0x0C795FFF and from 0x0C800000 to 0x0DFFFFFF is available to programs.

The final issue is how to get programs using all of that extra space. Probably the best solution is put the heap in the extended memory, which means changing the way the malloc function works. I don't know how to do this for the gamepark SDK, but Mr. Spiv is looking into it.

If you are an emulator coder, all you really have to do is put your emulator's ROM image into the extended memory. For example, if you're currently allowing 4MB for ROMs, and you use gm_malloc, you can change


   unsigned char *pROM;
   unsigned int nRomSize;
   nRomSize = 4 * 1024 * 1024;
   /* get 4MB for ROM image */
   pROM = (unsigned char *)gm_malloc( nRomSize );


to


   #define GP32_BANKSIZE (*((unsigned int *)0x14000028))
   unsigned char *pROM;
   unsigned int nRomSize;
   if ( ( GP32_BANKSIZE & 7) == 0)
   {
      nRomSize = 24 * 1024 * 1024;
   /* get 24MB for ROM image */
      pROM = (unsigned char *)0x0c800000;
   }
   else
   {
      nRomSize = 4 * 1024 * 1024;
   /* get 4MB for ROM image */
      pROM = (unsigned char *)gm_malloc( nRomSize );
   }


What this does, is it checks the CPU's BANKSIZE register to see if the RAM memory bank is 32MB in size. If it is, then 24MB is allocated for ROMs. Otherwise, the standard amount of memory (4MB in the example) is allocated.

By doing this, you will make an emulator that will work on either 8MB or 32MB GP32s, and will automatically take advantage of the extra size when it is available!

Personally, I don't use the gamepark SDK. Instead, I use newlib which is well documented and the modification to put the heap in the extended memory area was very simple. I won't put details about that here (yet), but I'm working on a library to replace the gamepark sdk (well, the low-level stuff like file and memory management anyway) and that will appear on this site sometime in the future...

Update:

I have now upgraded my GP32 to 64MB! That is the maximum that the GP32's CPU can handle, and is done by connecting another 32MB RAM chip into the unit. The new RAM chip shares all of its connections except for one with the existing RAM chip, so the upgrade was done by simply sandwiching another chip on top of the one that was already there. I don't imagine that anyone else will seriously consider doing this, so I won't give too many details (e-mail me if you're interested). However, here's a photo of the sandwiched RAM chips:

Sandwiched RAM chips

Valid XHTML 1.0! Valid CSS!