A first project: Buffered I/O

I/O expansion for the GameBoy

Click the picture for an enlargement in a new window.

After we made the extender, we also need something to connect to that extender. And keeping in mind that the GBC is intended to be used for control applications, some forms of I/O and memory are required. What I came up with, is in the picture above. Below we will stp through the various parts and design considerations.

The design

There are other designs for control applications for the GameBoy. Most just hook up some circuits to the systembus and then hope for glory. But glory is not based on luck. It's based on preparation, consideration and design.
The design goals for this GameBoy extension were as follows:

In the following sections each main design consideration is justified and explained.

The buffer sections.

busdrivers A central processor unit cannot drive a lot of inputs. Each input gate absorbs some current and if there are too many inputs paralelled, the CPU cannot pump enough electrons into the circuits. The result is that the CPU lowers it's output voltage, which will result in the loss of logic levels. What you end up with, is a system that behaves well in 99.999% of the cases, but that will let you down just when you need it. Remember that the CPU carries out millions of instructions per second, so a 10 ppm chance of system error will halt the system within a minute. Which is not acceptable.

So we introduce the concept of buffering all relevant signals. The advantage is, that now the CPU only sees one load and the buffer (who can easily drive up to 20 loads) takes care of the rest.
The addressbus is unidirectional. It needs to deliver an address to the rest of the system and it is "output only". So the best choice would have been to use a set of 74HC541 buffers. But for the ease of purchasing materials I decided in using bidirectional buffers, which were fixed in direction. The reason will be clear in a few moments.

The databus needs to deliver data to the peripherals, but it also needs to access the I/O and memory locations. So the databus buffers need to be bidirectional. The well known 74HC245 buffer is used for this.
The HC245 is a very strong buffer. So when the buffer is sending data back to the GBC mainboard, it will easily overpower the CPU, so it is only allowed to function if asked to.
That's why the HC245 has a direction control input which is tied to the /RD control line. And to prevent the 245 from disrupting memory accesses in higher memory, the 245 is enabled ONLY when the A15 line is LOW.

In order to make the purchase of parts easier, I chose for the 245 instead of the 541. The latter is also not available everywhere and hence it can be more expensive.

The control lines are buffered by means of a 74HC243, which is half of a 245. It is set to function as output only.

I/O space

I/O space decoder Since the GameBoy CPU does not have I/O instructions and related /IORQ pins, we need to find another way to access the outside world. The solution is easy: we go memory mapped. In the old days, when the Z80 was still young, there were two schools of thought for processors. One was the Intel family that used different address spaces for memory and I/O devices. The other was the Motorola section that saw everything as memory. Both schools have their own advantages.

We are not interested in the advantages of one or the other: we just are faced with the lack of separate address spaces. So we go memory mapped. The trick is to decode one section of memory and assign it a unique signal. In a way, we make our own IORQ signal. This is done with the 74HC30 (8 input NAND) and double 74HC32 (2 input OR) gates. The output of HC30 is LOW only when all inputs are HIGH at the same time.

In the circuit drawing on the left, you see how it's done in this interface. The /IO signal is our proprietary /IORQ signal and the /CE signal is the chip enable of the ROM device.
The three gates respond to the address range characterized by 0011.1111.11xx.xxxx or in hexadecimal 3FC0 through 3FFF, which is the last part of the lower 16 KB memory. If addresslines are in this range, the /IO signal is valid.

The ROM must respond to all memory accesses in our range: 0000 to 7FFF. Except for the IO range. This is accomplished by the U2C and U3A in the drawing on the left.

I/O selector circuit

IO selector We need to decode the IO range a little further. As can be seen to the left, a 74HC154 chip is used for this. This is a 4 to 16 decoder. It takes 4 address lines as input. It puts a logical zero on the addressed output pin. So when the input lines are '1010', output /Y10 is LOW and all other pins are HIGH. The outputs are labeled 'IOCSxx' as an acronym for I/O port Chip Select nr xx.

Most I/O chips have 4 internal registers so they need two address lines to function properly. In total we have reserved 6 address lines for our I/O space. So there are four remaining (A02 through A05) and these are fed into the HC154.

I chose to do the decoding on this mainboard and not send all the buffered address lines to all other expansion boards. Now each board can just pick one or more ChipSelects from the set of 15 and do what's needed. This is easier and better for the circuit since there are not much high speed switching signal lines on the expansion connector.

The chip may only activate one of it's outputs when we really are INSIDE the I/O space, so we use the /IO signal (described above) to enable the HC154.
We end up with a decoder that enables us to connect 16 intelligent I/O devices to the GBC. Each device may use four addresses. One address is preconfigured (see below) and the other fifteen outputs are brought out to the 40 pin expansion connector.

Memory bank controller MBC-F

MBC-F circuit drawing I made my own memory bank controller, the MBC-F (the F is for Fruttenboel). The reason is easy: why make things difficult by removing an MBC-1 from a game cart? The MBC-1 is clearly more sophisticated than my MBC-F, but mine is easier to make and fully transparent. The circuit drawing is on the left, as you undoubtly have seen.

The MBC-F is built around a 74HC259 chip. It has 8 individually addressable bits. One bit is addressed by putting the correct number on the address input lines A0, A1 and A2. We do that with databits 0, 1 and 2. This makes it easy to access consecutive output bits by simply incrementing the value in the accumulator.
The chip has a /CLR input. If this gets LOW at any time, all output pins are reset to ZERO. That's why the pin is connected to the /RESET line on the GBC edge connector.

The value stored in bit 7 of the databus is copied to the addressed output pin, when the /Enable input is strobed. This only happens when two conditions are met:

  1. The MBC must be addressed
  2. The /WR control signal must be active
This is taken care of by OR-ring the /WR pin with the output Q15 of the 74HC154 I/O space decoder chip. This action writes the value of bit 7 on the databus into the output pin addressed by bits 0, 1 and 2 of the same databus. Doing so we create the following signals:
  1. A16
  2. A17
  3. A18
  4. A19
  5. /WE = Write Enable for the Flash or EEPROM device
  6. CLEAR to reset 8255 I/O chip's
  7. A status LED (which is ON when the output is ONE)
  8. A free signal, which is brought out to the expansion bus
The four additional address lines make a grand total of 20 address lines, but we cannot use all of them. A14 and A15 are used elsewhere in the system, so we only have effectively 18 address lines for the ROM, which yields us a ROM capacity of 256 KB. Quite a lot for an 8 bit controller.
But there's a catch. If A14 is LOW, the bottom 16 KB of the ROM must always be available for the system. So we need to AND the new address lines with A14. Now, if A14 is LOW, the Bxx lines will be LOW as well. If A14 is one, we are in the bankswitching window and all values of A16..A19 are allowed. In a piece of pseudo code this would be:
     IF  A14 = 0  THEN
        B16 := 0;
	B17 := 0;
	B18 := 0;
	B19 := 0
        B16 := A16;
	B17 := A17;
	B18 := A18;
	B19 := A19
The WE pin is there to prevent accidental writes to the ROM memory device. Otherwise run-away programs could easily overwrite large portions of the softare we put there to stay forever. The WE pin must be "1" to enable the Write signal for the ROM device.

The CLEAR line is an additional line to reset the 82C55 chip. I chose to use a seperate line for this, instead of an inverted /RESET signal since the 8255 is a strange beast and sometimes it canb be handy to just simply reset the lot and start reprogramming it from scratch.

The status LED is a general purpose signal that can be used at will. I am now thinking of incorporating it in a timer routine so that it blinks once every two seconds.

The eighth pin can be used for anything you want. It is brought out to the 40 pin expansion connceor.

Alternative MBC-F

Alternative MBC Below the 259 is a so called 'wired or' constructed. In this case, I need 5 OR gates whereas the 74HC32 package contains only 4. So either I install another HC32 and waste 3 gates, or I use a wired OR circuit.

       Wired OR truth table

     /MBC     /WR      pin 14
     ----    ----      ------
      0        0          0
      0        1          1
      1        0          1
      1        1          1
The diode will only let a "1" pass. A "0" is blocked. The resistor is a kind of pre-charge or bias for the output.

This circuit is an alternative design for the MBC-F. It's function is identical. Construction may be easier, but this 257 is 7 cents more expensive... The 257 is a quad 2 to 1 multiplexer. Depending on the A/B selector, the A or B inputs are connected with the corresponding Y output. I omitted the flashing LED and the extra output in this drawing.

Memory device

ROM circuit drawing The memory device I put in the drawing is a 28C010. This is an EEPROM device of 128 KB. EEPROM stands for Electrically Erasable Programmable Read Only Memory. It can be programmed byte for byte if enabled by hardware (the WE and /WR signals). In most cases however the device acts as a ROM.

For the memory hungry among us: you can also connect other memory devices like a big EPROM or a more modern FLASH device. I want to go for the EEPROM or FLASH device to start with. EPROM's are nice but they cannot be altered in system.

The drawing on the left tells it all. The first 14 address lines A00 .. A13 are just taken from the address bus that happens to have a bus stop there. On the other side, the data bus is connected to the ROM device (D0 .. D7). Easy.

ROM address line A14 is not accessible from the system address bus. Therefore we made one ourselves in our MBC-F. The same goes for ROM address line A15. ROM address lines A16 and A17 would not even be available for us, if we wanted it, on a normal Z80 system. So, again, we made our own.

The Bxx address lines are the BankSwitch selectors. For this 'small' EEPROM, B19 is not necessary, but for a 29F020 Flash device (which has an upward compatible pinout) it is indispensible.

Power supply

Above is a circuit drawing for a simple yet efficient power supply for this entire project. I will give a short explanation for those of us who are new to the sybject.

On the left is the transformer, in this case one that transforms the 230 Volts from the mains to 7.5 Volts. The transformer is a 16 VA type, meaning that the product of maximum Voltage and Current is 16. In our case, this means 7.5 Volts at 2.1 A on the secondary side.
Since the transformer is one with two separate windings (the only kind I have in stock), we need to parallel the both of them. Now we have single voltage and double current (one winding would be 1.1 A max).
The parallelled windings are connected to a full bridge rectifier which converts the AC from the powerline into DC.

This DC voltage is yet a series of half sinus waves (all values above the horizontal axis) and we need a flat line elevated around 10 Volts above the ground level. With the aid of the big electrolytical capacitor (10,000 uF) we achieve this. The small 100 nF capacitor is used to get rid of high frequency noise.
This flattened out voltage which is still far from good enough to feed into a microprocessor, is fed into a 7805 style voltage regulator. This is a three pin device that just does all we want. It converts the raw 9 Volts DC into a very constant +5 Volts. If the 7805 is shorted, it will limit the current to a safe value in order not to selfdestruct.
If, on the other hand, the 7805 gets too hot, it will start to pulsate the output voltage, again in order not to selfdestruct.

There are many kinds of 7805's depending on the letter between the '8' and the '0'. A 78S05 is capable of producing 5 Volts at 2 Ampere's. This wonderful chip will cost you around EUR 0,35.

Some math. We feed 9 Volts at 1.5 Ampere into the 78S05. We get out 5 Volts at 1.5 A, so we loose something. In fact, we loose (9 - 5) * 1.5 = 6 Watts (under full load).

The package of the 78S05 is too small to get rid of all that heat. So we need to attach it to a so called heatsink (picture on the left). This particular one has a thermal resistance of 3.5 Kelvin per Watt (K/W). If we pump 6 Watts into this heatsink, it will rise it's temperature for 6 * 3.5 = 21 Kelvin. So at roomtemperature, the heatsink will get a temperature of around 40 degrees centigrade.
This kind of heatsink will set you back around EUR 3. You might have an old Pentium processor heatsink in your junkbox. You can use that as well, if there is a fan on top of the heatsink. Power the fan with the RAW 9 Volts (i.e. the power before the 78S05!).

The heat resistance of a heatsink is in most cases determined in still air. If you mount a fan on a 10 K/W heatsink, the resistance may well drop to less than 2 K/W. So any Pentium heatsink with a fan on top will be big enough to remove the excess power from the voltage regulator. Do not use a heatsink for processors above the Pentium II. These heatsinks have thermal resistances of much less than 1 K/W so it's a bit of a pity to use these monsters for such a small dissipation application.
You can mount the 78S05 on the heatsink by drilling a 2.5 mm hole in it and then screwing an M3 bolt right into the heatsink material. It's aluminium, so no need to cut threads in it with a threadcuttertool. Apply some thermal grease on the bottom of the 78S05 and screw it tight to the heatsink. Make sure the heatsink doesn't touch any other metal part or you might get a short circuit.

This text is just an explanation to get started. If you are interested in this topic, please buy the book 'The art of electronics' by Horowitz and Hill.

Expansion connector

On the left, we see the kind of connector that is to be used for the various applications. A 34 pin boxed header and the mating plug are used on the extender board. The interconnections between the buffer board and the various I/O stations will be made with 40 pin boxed headers.

These boxed headers are available in several forms:

  1. receptacles for PCB mount
  2. plugs for PCB mount
  3. receptacles for flatcable mount
  4. plugs for flatcable mount
We will only use the first two kinds for the interface boards. For prototyping, the flatcable versions can be used as well, but flatcables tend to pick up noise. The table below lists which functions are assigned to which pin number.
      pin    function                pin    function
      ---    ------------------      ---    ------------------
        1    +5 Volts                  2    +5 Volts
	3    CLK                       4    /WR
	5    /RD                       6    /CS
	7    Ground                    8    Ground
	9    Sound in                 10    /RESET
       11    A00                      12    A01
       13    I/O range 0              14    I/O range 1
       15    I/O range 2              16    I/O range 3
       17    I/O range 4              18    I/O range 5
       19    I/O range 6              20    I/O range 7
       21    I/O range 8              22    I/O range 9
       23    I/O range 10             24    I/O range 11
       25    I/O range 12             26    I/O range 13
       27    I/O range 14             28    Ground
       29    D0                       30    D1
       31    D2                       32    D3
       33    D4                       34    D5
       35    D6                       36    D7
       37    Clear                    38    Bit 7 of HC259
       39    Ground                   40    Ground

Page created January 2006,