Really I should be adding RAM next (because a computer isn’t much good without it) but before I do that, I want to make my computer control a peripheral. Just something that will control some LEDs will do for now.
To prove that the RAM works, I would need to add code that tests it. To do that, I really need to add some indicator to say whether that test passes or fails. So I’ll do the indicators first (because that doesn’t require RAM) and when that works, I can move on to the actual RAM.
As I’ve built write-enable into my address decoding logic, in theory this should be pretty straightforward. But it’s all very well knowing it in theory, isn’t it?
The 6522 is a VIA (“versatile interface adaptor”). It provides serial and parallel I/O ports in a typical bus-addressable fashion. It is very much designed to be used in conjunction with the 6502 – for example, every BBC micro from the model B onwards has two as standard.
I’ve added a 6522 to my computer like this:
Note that I’ve used the select line “/THIRD” (from part three) as the selector for this IC. This means that the 6522 becomes selected when the CPU accesses any memory location between &8000 and &BFFF. This is incredibly wasteful (the 6522 has four RS lines, which means that I’ve provided 16,384 addresses for a device that only actually needs 16) but this is just a first test. Remember that I’ve built address decoding on a separate board, so I can iterate on it later.
You’ll see on the right-side of the 6522 in that diagram I’ve marked parallel ports A and B (eight bits each) and the serial lines CA1, CA2, CB1 and CB2. For my first test I’m just going to make an LED flash – so I’ve attached an LED from PB0 (pin 10) to ground, via a 470 ohm resistor.
About the “Register Select” lines
The 6522 has four register select pins – numbered 0 to 3. Register select pins are quite common in digital electronics like this, so it’s worth going into a bit of detail for anyone who hasn’t seen them before. You’ll certainly see more examples in future.
To “send” a byte to any peripheral in these sort of circuits, you set the eight data lines (D0-D7) to the byte, then assert the right combination of control lines to make that byte “latch” inside the peripheral. The act of selecting which peripheral on the bus is to accept the byte is done by the “chip select” pin(s) – for some peripherals there’s just one, and others there’s more than one. On the 6522 there’s CS1 and /CS2.
To read a byte from the peripheral, the same chip select pin(s) function, but we set the R/W pin to the “read” state – and this time, the peripheral itself controls the eight data lines, and the CPU reads them instead.
But many peripherals can have so much capability, just sending a single byte to it (or reading a single byte from it) isn’t quite enough. To overcome this, those peripherals contain something called registers. Conceptually they’re like registers in the 6502 itself – places for numbers to get stored, to influence behaviour.
For these peripherals: whilst sending or reading a byte, we also set the register select pins to say what piece of information we want to read or write.
Register select lines act just like address lines – set them on or off in different combinations, to say which register you want to access. The 6522 has four such register select lines – so that’s sixteen different registers.
Here’s the bit that I find elegant: register select lines act so much like address lines, that to access them from our CPU we just wire them to the address lines and then write code that accesses the right memory addresses that correspond to those registers.
So in my circuit above, the four register select lines are connected to the lowest four address lines. We’re using /THIRD as the chip select line, so we know that the 6522 will be selected when accessing any RAM between &8000 and &BFFF. But more than that: now, the lowest four bits of the address will select the correct register within the 6522.
Here’s how the address lines are used, when accessing the 6522 in this circuit:
A15 must be 1, and A14 must be 0 – that’s what makes the address decoder assert /THIRD, which selects the 6522. The address lines marked with ‘x’ aren’t wired to the 6522, so they have no effect. The lowest four bits are wired to the register select lines.
By finding the list of registers in the 6522 datasheet, we can calculate what memory addresses will access them:
For this simple test, I just want to set all the pins of port B to be outputs, then set each pin of that port. So I’ll need to access &8002 (the “direction register” for port B) and &8000 (the state of port B).
The test code writes &FF to port B’s data-direction register, to tell the 6522 that all pins should be outputs. Then it simply loops, writing an incrementing byte to port B. By adding extra LEDs to the other pins of port B I can see the binary count in action, as the pins toggle at different rates.
via_base = &8000 via_portb = via_base via_ddrb = via_base + 2 ORG &C000 .start_here lda #&FF:sta via_ddrb ; set all portb as outputs ldx #&00 ; X = 0 .via_cycle stx via_portb ; write X to PORTB inx ; increment X jmp via_cycle ; ... and repeat ORG &FFFA equw start_here ; NMI address (not used at the moment) equw start_here ; RESET address equw start_here ; IRQ address (not used at the moment)
Look at that! I have a computer that flashes LEDs on and off! I’m pretty sure that early on I said I’d be happy if I could build a computer that could do that … which means that anything from this point on is just a bonus!
It’s good to see the addresses appear on my hex display – mostly running through my code at &Cxxx, but occasionally writing to &8000 when it’s time to update the 6522’s output.