Most of the 'reference' implementations of simple DIY 6502 computers (Searle, Wilson, Eater, etc.) do very simple address decoding of the available 64K address space using a handful of logic gates.
Garth Wilson has written a great intro to address decoding:
https://wilsonminesco.com/6502primer/addr_decoding.html
These two examples from his page are fairly typical of how most of these designs are implemented:
The main benefit of this kind of approach is simplicity, typically only one or two TTL chips required.
The downside is that you 'waste' a large chunk of address space, typically 8K or 16K, to map a few bytes of IO register space. The IO chips shown in these examples are fairly typical:
- 6522 VIA - Versatile Interface Adapter (parallel ports and timers)
- 6551 ACIA - Asynchronous Communications Interface Adapter (serial ports)
In this case, the VIA only needs 16 bytes of address space and the ACIA needs a mere 4 bytes of address space.
This isn't a huge surprise or secret : it is a concious trade-off to simplify the designs, costs and complexity for these experimental boards since the entire address space is probably never going to get used.
MotivationI'm an optimizer at heart and I find it hard to just accept this sort of 'waste'. Also, what better excuse did I need to learn how to program a CPLD? Once this approach is mastered, I can revisit address mapping with an arbitrary choice of RAM and ROM space while still not wasting space on IO (like a 48K RAM machine for example).
I chose to use a CPLD because the amount of logic required to only use 20 bytes for the IO address space would require a much larger number of TTL chips to refine the decoding using the same approach shown above.
I bought half a dozen ATF22V10C's online for less than $5 per chip. I wanted DIP versions for breadboarding and protoboarding so the specific device I purchased is the "ATF22V10C-7PX SPLD, 166MHZ, DIP". You can read more about the "7PX" designation on Microchip's website but the short version is that I bought the DIP version with the shortest propogation delay ("7" as in 7ns).
The second reason I wanted to try this was to consider mapping my IO registers into the 6502 zero page. This would be senseless if there were wasted bytes but, if I could get it down to 20 bytes, there would be advantages to this:
- smaller code : zero page opcodes are shorter in bytes (often less cycles too)
- more bit fiddling instructions available on WDC 65C02S
The bit fiddling is an interest one. Assuming you can live with requiring a WDC 65C02S or later version of your 6502, you get a whole lot more bit fiddling instructions that only work on zero page address. This means instead of the usual sequence of LDA, AND/EOR/ORA, STA you only need a single SMBn or RMBn. The zero page bit-specific conditional branches are even more interesting.
(if you haven't seen this great online 6502 instruction reference, you should take a look : https://www.pagetable.com/c64ref/6502/)
I'll use some coding examples to show what this means. Here is my interrupt service routine that is currently processing a VIA timer interrupt and a pin interrupt for my PS/2 keyboard. These two versions perform the same function but the first assembles to 15 bytes of code and the second assembles to just 10 bytes.
The first version assumes 16 bit port addresses and doesn't use the WDC 65C02S specific instructions. The second version assumes 8 bit zero page port addresses and does use the WDC 65C02S specific instructions.
While both look fairly optimal, the second version looks less cryptic to me. It also has the advantage of allowing any priority order for the VIA interrupts (rather than the order of the bits in the IFR which the first version is limited by).
This next example uses a subroutine from my LCD firmware for the HD44780 driver. Same story again: first version using 16 bit port addresses and no WDC 65C02S specific instructions assembles to 50 bytes. Second version using 8 bit zero page port addresses and WDC 65C02S specific instructions assembles to 36 bytes.
While these are obviously dramatic examples, I have to accept that we usually put IO access code in subroutines (so it doesn't represent a large part of our code in terms of size). However, this smaller code is also bound to be faster too.
I'm happy to pay my toll of 20 bytes of zero page addresses for these benefits.
Programming the ATF22V10CMicrochip has some free software for doing this. I used the Windows version which you can download from here:
https://www.microchip.com/en-us/products/fpgas-and-plds/spld-cplds/pld-design-resources
They show a serial number, 60008009, which is needed to do the install for the free version. This install gives you both WinCUPL and WinSim.
I started by looking for the minimal control lines that would be required for my RAM, ROM, VIA and ACIA. Looks like I need one for each device and a 2nd control line for the RAM since it needs to be activated later in the clock cycle for writing than it does for reading. In all cases I went with active low so even though they show as CS in the schematic, they are all the active low chip select pins.
My memory map is shown below and since the granularity of my blocks goes down to 4 bytes for the smallest (the ACIA), that means I'll need all the address lines except the 2 least significant (all except A0 and A1) as inputs along with the clock (PHI2) for the RAM_OE timing to be correct.
WinCUPL lets you edit .PLD
files and then it compiles them into .JED
files. You can use a regular EEPROM programmer to program these chips.
This is the essence of the logic I'm programming into the CPLD:
Can you see how CS ACIA is active for only 4 bytes and CS VIA is active only for 16 bytes?
I've attached the full source of my .PLD
file to the project so you can see how all these symbols are defined. How did I learn this? I searched and found several sources. The one that was the best and was closest to what I had in mind is David Buchwald's hackaday.io project: address decoding.. and how to get it right.
In terms of testing, I could not see an easy way to automatically generate the .SI
file used by WinSim so I manually added permutations and combinations of the inputs to try to test all the obvious scenarios I could come up with. Just seeing the format of my .SI
file should help you understand how you could build out a test suite.
I have trust issues and need to see things actually work before I'll believe that they are correct so next I manually tested the device by hooking up inputs and outputs on a breadboard.
So now, aside from a 74HC14 for the reset circuitry, my motherboard only has the 6502 CPU and the 22V10 CPLD. Happy optimizer!
Comments
Please log in or sign up to comment.