6502: Programmable Logic Devices – Address Decoder Revisited

I mentioned in my last post, Venturing Forth, that I ordered a programmable logic device to better refine my address decoding as my current circuit wastes about 16k on I/O. I worked up the new memory map and PLD files while waiting for the device to arrive. Then, as seems all too common with me, I got sidetracked with enhancing py65, a 6502 emulator that I’ve mentioned before. Over the last two months or so I’ve added enhancements to py65 to allow file access, handle interrupts, open a separate debug window and emulate the 65816, the 6502’s 16-bit sibling (and yet another sidetrack for me). I’ll probably have a post on this but in the meantime, you can find out more at my GitHub.

In responding to a recent post on Reddit, I realized that I was starting to forget some of the details of the PLD work I did back in December. Since this blog probably gets its most use by me looking up stuff I’ve forgotten, I figured it was time to do a little writeup on this.

New Memory Map

There is plenty of information out there on using a PLD as a single chip address decoder for the 6502, just google “6502 pld memory map”, it’s likely you’ll find exactly what you need or at least something close. I wanted a memory map that used most of the 64k memory space for RAM and ROM. I found this Reddit post by Eric Badger helpful to get started. Eric worked up a memory map with almost 32k RAM, 32k ROM, and 16 I/O devices, using 16 bytes each for a total of 256 bytes. (unfortunately, it appears that Eric’s related GitHub repository is no longer public).

While close, Eric’s design had one major drawback for me, it was a two-chip design. He needed an extra chip to qualify I/O device selection as he ran out of I/O pins on his PLD. Not needing that many I/O devices, I worked up a map with six I/O devices rather than sixteen. (Note that a three I/O device memory map is possible and even easier, but my build calls for four I/O devices).

The resulting memory map is as follows.

Memory Map for ATF2210V10C Address Decoder
Memory Map for ATF2210V10C Address Decoder

Compared to my third build, I’ve gained 16k bytes of ROM but lost 256 bytes of RAM and four I/O devices. This is a satisfactory tradeoff for me. I’ve seen other designs with less wasted memory, but at least for now I figure, why bother? With a memory map in hand, an important question remained, “what PLD could accommodate it”.

PLD Selection

I could not find much information on how best to choose a PLD. It seems that the common advice is to choose the simplest and smallest chip that appears to meet your needs and see if it can accommodate your logic design.

Rather than randomly selecting PLDs for testing, a good start seemed to simply select one that others have successfully used. As my memory map was closely related to Eric Badger’s, I started with the one he used, an ATF22V10C. This chip has 12 logic inputs and 10 bidirectional buffers that can be used as either logical inputs or outputs. This is obviously one of the key features to consider in choosing a PLD.

My current 74AC139-based address decoder uses only 3 inputs, the clock and the 6502’s A14 and A15 address lines to give a memory map with 32k RAM, 16k ROM and up to 10 I/O devices in the remaining 16k of memory space. These are selected with three output signals, RAM and ROM chip enable and an I/O chip select. Address lines A4-A13 are used separate from the address decoding circuit as the chip select signals for the I/O devices. All but 160 bytes of the I/O reserved memory is non-addressable (or if used must consider possible conflicts with attached devices).

With the new memory map, I needed pins for the clock and nine address line input signals, the same RAM and ROM output signals and two separate output signals for the I/O. Address lines A4-A6 are used as separate chip select signals for the I/O devices with each I/O signal from the PLD. The ATF22V10C is more than sufficient based on input and output pins, but would the design fit within the chip’s programmable architecture? The only tip I found to answer this question was to “test it and see”. Luckily there are PC tools available to confirm that a particular design will fit within a given chip before you actually buy it.

I used Microchip’s WinCUPL, a Windows-based program, to test my design and create the files needed to program my PLD. Here is the code for this design.

Name     6502PLD ;
PartNo   00 ;
Date     11/26/2021 ;
Revision 01 ;
Designer tmrob ;
Company   ;
Assembly  ;
Location  ;
Device   g22V10 ;

/* Input */
Pin 1        = CLK;
Pin [3..11]  = [A15..A7];

/* Output */
Pin 19 = RAM_CS;
Pin 20 = ROM_CS;
Pin 21 = IO_CS1;
Pin 22 = IO_CS2;

/* Local Variables */
FIELD Address = [A15..A7];

/* Logic */
RAM       = Address:[0000..7EFF];
IO1       = Address:[7F00..7F7F];
IO2       = Address:[7F80..7FFF];
ROM       = Address:[8000..FFFF];

!RAM_CS   = RAM & CLK;
!ROM_CS   = ROM;
!IO_CS1   = IO1;
!IO_CS2   = IO2;

This code may look much more compact than examples you may find online. Turns out that WinCUPL has pretty flexible and powerful syntax. The key is getting the proper clues to what that syntax is since its documentation doesn’t provide enough detail, at least for a new user. Examining other examples and googling helps.

My design compiled successfully so I assume it fits within the PLD. I couldn’t find any statistics though, which would seem natural for such a program to provide. Still, I had extra I/O pins which begs the question, “what else can I do with the chip”?

Refining the PLD Logic Design

Having extra I/O pins on the PLD, I decided to incorporate a commonly used refinement to my address decoding to use the clock to qualify the read/write signal rather than the RAM select as I’m doing currently. Though I haven’t had any problems with the way I’ve been doing it so far, I’ve read that doing this can reduce problems when interfacing with some devices. See discussions here, here and here for example. Doing this would use three more I/O pins on the PLD. But could I do more?

I use a 74HC11 AND logic chip in my third build design to combine the four interrupt request signals from my VIAs and ACIAs into a single interrupt request signal to the 6502. It seems the PLD should be able to perform this function just as well, perhaps better, and with a shorter propagation delay, though this probably isn’t important here. To accomplish this, I would need three additional input pins and one additional output pin on the PLD. I had just enough, leaving me with only a single I/O pin for possible further refinement. The best part of this is that I reduce my overall chip count by one, giving me more layout and routing flexibility on my 100×100 mm PCB. (I’ll leave the schematic and PCB layout to another post after I’ve completed a breadboard build).

Here is the code reflecting these refinements.

Name     6502PLD ;
PartNo   00 ;
Date     11/26/2021 ;
Revision 02 ;
Designer tmrob ;
Company   ;
Assembly  ;
Location  ;
Device   g22V10 ;

/* Input */
Pin 1        = CLK;
Pin 2        = RW;
Pin [3..11]  = [A15..A7];
Pin 13 = VIA1_IRQ;
Pin 14 = VIA2_IRQ;
Pin 15 = ACIAs_IRQ;

/* Output */
Pin 17 = WE;
Pin 18 = OE;
Pin 19 = RAM_CS;
Pin 20 = ROM_CS;
Pin 21 = IO_CS1;
Pin 22 = IO_CS2;
Pin 23 = IRQ;

/* Local Variables */
FIELD Address = [A15..A7];

/*  Logic */
RAM       = Address:[0000..7EFF];
IO1       = Address:[7F00..7F7F];
IO2       = Address:[7F80..7FFF];
ROM       = Address:[8000..FFFF];
!WE       = CLK & !RW;
!OE       = CLK & RW;
!RAM_CS   = RAM;
!ROM_CS   = ROM & RW;
!IO_CS1   = IO1;
!IO_CS2   = IO2;
IRQ       = VIA1_IRQ & VIA2_IRQ & ACIAs_IRQ;

PLD Programming: WinCUPL Quirks

There are several free options for preparing the files needed to program PLDs. I used WinCUPL, an older, Windows-based program. This isn’t a tutorial on using WinCUPL, but I thought I’d pass on some tips about how I dealt with some of its quirks. Perhaps some of these reflect my inexperience using the program, or its incompatibility with modern operating systems, but it may help some to be forewarned. In any case, expect to spend some time getting to know how to use the program. As mentioned above, taking advantage of the flexible syntax can greatly simplify your code and make WinCUPL do all of the logic calculations for you.

First up, pay special attention when installing WinCUPL. It’s likely due to me missing an option or not following the instructions properly, but after installing WinCUPL, none of my 6502 programming tools worked. Turns out the installation had overwritten my Path environment variable. You might want to take note of yours prior to installation, just in case.

A natural place to start seems to be creating a new project, to me at least, with the File-New-Project command. I’d recommend skipping this and just pasting some sample code into a new code window opened by pressing the New button.

The new project option takes you through some setup dialogs that don’t seem to add value and actually create errors. For example, the default value for Company is a semicolon. This will cause an error when you try to compile if unchanged. Also, entering ATF22V10C as the device will cause a “device not in library” compile error, even though the ATF22V10 is in the WinCupl device library. Google to the rescue again. You need to use “g22V10”. Finally, the new project option asks some questions about the number of input and output pins (what about bi-directional I/O pins?) and pin nodes (what are these?). These seem only to create a fairly useless empty structure in the project code file. Much faster to just edit a sample code file.

A second quirk for me, the program commonly crashes with a “Key is not unique in collection” error when trying to compile with the Device Dependent Compile command. It seems as if many people just give up at this point, but googling yielded a solution for me. If you run into this problem, try unticking Project in the View menu. This could again be the result of user error or the older program, but it happened pretty consistently for me.

A crashing program seems to be a common result of something going wrong with WinCUPL. For me, my project file needed to be in the WinCUPL folder or the program would crash without error when opening it. While I normally don’t like to keep my project files within a program’s folder, I don’t plan to use WinCUPL enough to bother finding a work-around.

I suppose that WinCUPL is about as good as any of the other older legacy tools I’ve used in my 6502 projects. You’d hope for better, but when they’re providing the programs for free, I suppose you can’t complain, not too much at least.

The Proof is in the Pudding

I now have a memory map with its related logic design and related files ready to program my PLD. I’ll be using the TL866II+ programmer with the manufacturer provided software. Be aware that there are a lot of clones of this device. I’ve done a test run with the programmer, absent the actual chip, and everything seems to work correctly.

It’s all waiting for me to complete my fourth 6502 build. I debated just modifying my third build for the new PLD address decoder, but I’d like to keep it to allow me to compare the two. I suppose it’s time for me to buckle down and get building. Let’s see if I can get focused.

BTW – you may have noticed I turned off comments. Sorry, I just got tired of dealing with the spam.