For more than a week now I’ve been describing this project to my friends as “So close to working perfectly!” Here’s where you’ll start to see why.
In my last post, I handwaved the issue of actually generating the interrupts for transmit and receive events from the MAX3100 UART. I think this has actually been the biggest stumbling block for this project, and even right now I’m only pretty sure I have a good solution.
The MAX3100 only has one IRQ output, but it can actually be configured to generate interrupts for several different reasons. There were two that I was particularly interested in. The first, “R”, is a receive interrupt. The R interrupt is asserted whenever there’s incoming data ready to be read, and it stays asserted as long as there is unread data. That seems pretty straightforward. The transmit interrupt, “T”, is a little different, and I found the details of how it worked a little confusing.
Because of my confusion, I took small incremental steps. At first, I configured the Max3100 to only send R interrupts. I figured I could use those interrupts to read data, and use the 100 Hz timer interrupts to handle transmitting data.
I also had to figure out how to get the interrupt inputs into the 6502, since I wanted both the 3100’s interrupts and the timer interrupts from the 6522 VIA to connect to the 6502’s single IRQ input.
Since all the other connections from the MAX3100 were going into the VIA, I thought it would make sense for the interrupt line to connect to it also. Each of the VIA’s parallel ports have a couple of control lines, and according to the datasheet one of the things you can do with the control lines is have them cause an interrupt when they see a particular signal.
This seemed really elegant to me. As a bonus, the interrupt service routine could just look at the VIA’s interrupt flags register to figure out the source of the interrupt. I wired it up, gave it a try, and it just worked.
Then the next morning it didn’t.
And then a couple hours later it did again.
Something weird was going on. I spent a lot of time double- and triple-checking that I was running the exact same executable every time, regardless of the results. I looked at the datasheets again, and noticed that the MAX3100’s IRQ output is an “open drain” – that means that it needs a pullup resister to make the voltage consistently high when the IRQ isn’t being asserted. But adding the pullup resister didn’t make any difference to the behavior.
When I switched the P:65 computer on, it would either work or not. If it was working, it would keep working consistently for hours, across multiple resets. If it wasn’t working, it would stay not working for hours, across multiple resets.
Looking at the logic analyzer, it seemed like the MAX3100 was always generating interrupts. The 6522 apparently wasn’t always noticing. At one point I disconnected the 3100, so the only thing connected to the VIA pin I was using was the pullup resistor, and the logic analyzer was still showing a zero on that pin.
I suspected that I wasn’t initializing the 6522 correctly, but checking the datasheet again and again I couldn’t find anything that I was missing. I also wondered if there was something happening at the analog level that wasn’t being picked up by the logic analyzer. Unfortunately, I don’t have an oscilloscope to test that idea with.
I also considered that maybe the 6522 or the breadboard was malfunctioning. I replaced the wires, shifted the position of the 6522 on the breadboard, and tried using a different input pin, but none of those things helped. Since the 65c22 only costs about $5, I ordered a new one just to see if it would behave differently.
While waiting for that to arrive, I revisited my design. Instead of hooking up the 3100’s IRQ output to an input on the 6522, I thought I could just hook both inputs directly into the 6502 CPU’s IRQ input.
Both of the IRQ outputs are low when an interrupt is being asserted, and I need the CPU’s IRQ input to be low when either of the inputs were low. So that’s:
IRQ_IN = IRQ_3100 AND IRQ_6522
I didn’t have room on the breadboard for another logic chip, but I did have a 74HC00 quad 2-input NAND gate in the address decoder that was only half used. I was able to get the effect I wanted with this bit of wiring:
The first NAND gate gives me exactly the opposite of what I want, and then the second one inverts it. This seemed to resolve the erratic behavior I was seeing, and things were definitely looking up. It wasn’t until I started trying to use the 3100’s Transmit interrupts that I saw the downside of this approach…