Zolatron: 6502 address decoding

      2 Comments on Zolatron: 6502 address decoding

This was something I’d always wondered. When you have data on a bus, how do you ensure it’s read by the device that needs it, and only that device? And when you read data from a device into the microprocessor, how does the processor read data only from that device?

What we’re about to embark on here is address decoding. And as I’m learning as I go, and sharing my experiences, what you’re reading is my understanding of the subject. Which might be wrong, or at least imperfect. Accept it in the spirit in which it’s given.

So anyhoo…

In a microcomputer – at least the 1970s/80s-style machine I’m building with my Zolatron project – you’ll typically have two buses. We’re dealing here with an eight-bit computer with 64K of addressable space. So the data bus is 8 bits wide and the address bus is 16 bits wide. In each case, a bus is just a collection of wires/tracks that run in parallel. And at various places in the computer, devices that need to be addressed and send or receive data attach to the bus.

The 6502 chip has 16 address pins (A0-A15), each of which can be set high or low to represent a 16-bit binary number. Similarly it has eight data pins, but we don’t care about them here.

When you put 16 bits of data on the address bus that you want to send to, say, the memory chip, how does the memory chip know it’s expected to read that address? And how do all the other devices – a VIA, for instance, or some other interface – know to ignore it?

In essence the answer is simple. Each chip has an ‘enable’ pin. Only when this pin is activated (usually by taking it low, to ground), does the chip spring into life. Sometimes you need to activate more than one pin, but that’s the basic principle. So if you want to send data to the VIA, you put the data on the data bus, then activate the VIA’s enable pin by addressing it with the relevant setting on the address pins.

(Like I said, this is all, so far, something of a simplification, but we’ll get to the complications soon enough.)

Address map

Before we can go much further we have to decide how the 64K of addressable space is going to be split up. We’ll need some for RAM, some for ROM, some for peripherals (eg, via VIAs).

The address space runs from hex values $0000 to $FFFF. (Using ‘$’ to denote hex is how we rolled in the 80s – none of that 0x nonsense.)

To make life easy, we’ll say the bottom half of the space, values $0000-$7FFF, will be used to address the 32K of RAM I intend to use. You need 15 bits of data to hold that range of values – ie, address pins A0-A14 on the 6502 chip. That leaves A15 (representing a value of $8000) in its default condition of being set low.

So here’s a quick preview of how decoding goes. The pins on the 6502 are ‘active high’. So, if you put a value of anything in the range $0000-$7FFF on the address bus, pins A0-A14 will be low or high as needed to represent the value while pin A15 will always be low because it’s never used for values in the bottom 32K of the 64K address space.

Now, you remember that we said the ‘chip enable’ (CE) pin on most chips is ‘active low’? All we need do to address the memory chip is to connect A15 on the 6502 to the CE pin on the memory chip. Any value below $8000 will automatically enable the memory chip because A15 will be low. Any higher value we put on the address bus, in the range $8000-$FFFF, will be ignored by the memory chip because in that case A15 will always be high.

That’s the easy part.

For the upper half of the address space we’ll split it into blocks. And we’ll need the help of another chip.

So in our address map the bottom half is RAM.

Above that is a collection of eight 1K spaces. I’m not yet sure what I’m going to do with these, but at least one and possibly two will be used to talk to VIA chips for various interfaces.

Above that are three 8K spaces. The very top one will be used for a ROM chip. But I’m also allowing for the possibility of a 16K chip, or two 8K ROMs.

The space starting at $A000 and going up to $BFFF is currently unassigned, but I think it might be a buffer of some sort, or maybe some additional RAM, perhaps used for video. Who knows? The possibilities are endless.

Decoding

To help us along, here’s a little table of the values associated with the address pins of the 6502 when each is set high. The ones in red are the most important from an address decoding point of view.

pin hex dec
A0 $0001 1
A1 $0002 2
A2 $0004 4
A3 $0008 8
A4 $0010 16
A5 $0020 32
A6 $0040 64
A7 $0080 128
A8 $0100 256
A9 $0200 512
A10 $0400 1024
A11 $0800 2048
A12 $1000 4096
A13 $2000 8192
A14 $4000 16384
A15 $8000 32768

The chip we’re going to use is the humble 74LS138 three-line to 8-line decoder/demultiplexer. Other chips are available. Indeed, online you’ll see lots of advice about how other chips are better, mainly because of performance. But the Zolatron 64 is designed to run at a gentlemanly pace. And at this stage in my education, simplicity rules over performance (as it does in my life).

The important features of the 74LS138 are:

  1. There are three digital input lines/pins, A, B and C. In other words, you can input a 3-bit value by feeding these pins. The range of values you can input is therefore 0-7.
  2. The value you feed into the input pins determines which one of the eight output pins (Y0-Y7)  is selected. These pins are active low (inverted). If you input the value 4, for example, by giving a high (+5V) voltage to C and 0V to A and B, then Y4 will go low and the other output pins will be high. By default, when the chip is not enabled, all the pins are held high.
  3. There are three enable pins – G1, /G2A and /G2B. The slash in front of /G2A and /G2B shows that they are active low while G1 is active high.

It’s crucial to understand that only one output pin is ever active (ie, low) at any time – that’s important because we’re going to connect the outputs to the CE pins of other chips. The purpose of the 74LS138 is to select chips other than memory by making the CE of the selected chip go low.

You may already have spotted one trick we can use. We’ll want our 74LS138 decoders (and yes, there’ll be more than one) active only when we’re addressing space from $8000 upwards. In the upper half of the address space, pin A15 ($8000) on the 6502 is always high. Therefore we can tie this to the G1 pins of the decoders.

When we’re addressing RAM (in the lower half of the address space), A15 will be low and the decoders will be suitably inactive because the G1 enable pins on the decoders will be low.

When we’re addressing any address in the upper half of the memory space, A15 will always be high and therefore one of the enable pins (G1) of each the decoders will be set. Whether the decoder chips are actually enabled, and which one of them it is, depends on the other two enable pins, /G2A and /G2B. This is why it’s important there are three enable pins.

Da-doo-ROM-ROM

Let’s get going with the three 8K spaces at the top of the map. We can address these with one decoder chip.

Note that in the images below the representation of the 74LS138 is diagrammatic. It doesn’t reflect the actual pin layout. (And some pins, like power supply and ground, are ignored.)

How does this work? First, you’ll see that /G2A and /G2B are both tied to ground while G1 is tied to A15. This means this decoder will become active whenever we put any address on the address bus of $8000 or more – ie, the top half of the address space. We’ll see in a minute why this isn’t a problem.

We’ve connected the 6502’s A13 to B and A14 to C. On the output side, Y2 goes to the CE pin of whatever chip is meant to be at address $A000, Y4 goes to the CE of whatever chip is at $C000 (an 8K or 16K ROM) and Y6 goes to whatever sits in the highest 8K space – eg, an 8K ROM. (If I decide to use a 16K ROM at address $C000, Y6 won’t be connected to anything and neither will A13 be connected to the decoder.)

So let’s walk through what happens. Let’s say we set the address bus to the value $8020. This is below the address space serviced by this decoder. (By the way, that ’20’ at the end is arbitrary. I’m just making the point that we’re not talking about a value of exactly $8000, but somewhere in the 8K space from $8000 to $9FFF.)

A15 will be high, so G1 is enabled. As /G2A and /G2B are both tied to ground, they’re already enabled. With all three CE pins set, the ROM select decoder is enabled.

However, A13 and A14 will both be low, because the value we’ve set on the address bus is too low for them to be active. So all three input pins, A, B and C will be low – a binary value of b000, if you like. When the 74LS138 is enabled but input is 0 then Y0 is selected as the output (ie, it’s set low) and the other pins are high. As we haven’t connected Y0 to anything then the decoder doesn’t select any chip. So that’s all good.

Let’s put the value $A020 on the address bus (or any value in the range $A000-$BFFF). This causes the 6502’s A13 to go high (among other pins, including A15). The decoder is enabled as before. Now input pin B is set high, while A and C are still low, giving an input value of 2 (b010). This sets Y2 low and the other output pins high. So any chip connected to Y2 will be enabled and chips connected to the other outputs will be disabled.

Let’s increase the address bus value to $C020. A13 will go low and A14 high. (A15 is also high, as before.) This gives an input value of 4 (b100), so Y4 goes low and Y2 goes high again. So now we’ve selected the chip connected to Y4.

And finally, let’s increase the address value to $E020. Both A13 and A14 will be high, giving an input value of 6 (b110) and setting Y6 low and the other output pins high.

So this is how we select which of these three 8K spaces we want to talk to. To select specific locations within them, as well as the pins that select the base values (A15 plus A13 and/or A14), pins A0-A12 are employed to add values ranging from 0 to 8191 (ie, 8K’s worth of values). So you can see that all the address pins are in use – all are significant – when selecting address values up at the top of the map, as you’d expect. Why point this out? It becomes crucial when we start addressing stuff lower down.

1K spaces

Now let’s look at those eight 1K spaces starting at $8000. We’ll use a second decoder which we’ll call the 1K select. And this time the CE connections on the 74LS138 are a bit different.

You’ll notice that A10, A11 and A12 are now used to select the output value. Isn’t this a problem if these are also used when dealing with higher addresses – eg, the ROMs? Well no, because you’ll also notice that A13 and A14 are now connected to the chip enable pins /G2A and /G2B.

When dealing with addresses at $A000 or above, either A13 or A14 (or both) will be high. As /G2A and /G2B are active low, whenever you’re in the higher areas of the address map, this second decoder will be disabled because at least one of the active low enable pins will be high. So the fact that there are values being put on A10-A12 doesn’t matter – they’ll just be ignored.

With addresses below $A000 but above $7FFF, both A13 and A14 will be low and A15 high, and so this decoder will be enabled. A10-A12 determine the base address for the section you’re addressing and pins A0-A9 are used to determine the precise address within each 1K space.

Using the example provided for the ROM select, you can probably work out how each output pin is selected. Just note the special case that when an address in the range $8000-$83FF is selected, all three input pins (A10-A12) will be low but A15 still high. This means the decoder is enabled with an input value of 0, so Y0 will be selected.

From there, the addresses go in steps of $0400 (1024 or 1K). You could almost think in terms of the input pins representing numbers in base-1024 (starting at $8000, of course).

And that’s essentially it for this time. If you spot an error, please do let me know.

[Updated 31/12/2016 to fix a couple of typos.
Updated 13/04/2017 to add three diagrams of pinouts.]

[Update 04/04/2018] I mention using the 74LS138 for decoding … well, the ‘LS’ range of chips is now regarded as somewhat power-hungry and sometimes too slow. So I’m going to be using the 74HC138 or even 74HCT138 version instead.

Also, selecting RAM by simply connecting A15 from the 6502 to the chip-enable pin of the RAM might work for slow clock speeds, but there’s a better way of doing it, as I discuss here »

2 thoughts on “Zolatron: 6502 address decoding

  1. Chris Zuhars

    Outstanding content. Thank you! I myself am in the beginning stages of building my own 8-bit 6502 based machine. I’m not a electrical engineer, so my knowledge comes from multiple sources such as your blog. The missing link for me at this point is exactly what you’re covering in this post – how do you choose which “module” (RAM, VIA, ROM, etc) the 6502 is talking to. Your explanation of the 74LS138 fills this blank wonderfully.
    My next hurdle will be understanding pull up/pull down resistors. I look forward to reading your future posts.
    It blows me away the simplicity and genius of how these various chips and logic are put together to solve otherwise complicated problems. A chip that accepts a 3 bit binary input to choose a representative 8 bit switch – it’s just amazing how all of these parts fit together so well.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.