All right! I have "solved" the problems I was having in the time honored tradition of avoiding them.
I have some more components on the way; when they get here I'll make a new backplane with - hopefully - a better power supply. In the meantime, as long as I don't put anything into the two bus slots next to the voltage regulator, Blue April is running rock solid. This afternoon I finished the keyboard interface, so I now have actual I/O. I can type on the LCD!
SHIFT, ENTER, ESC (clears the screen), and BACKSPACE all work. I haven't implemented any of the extended scan-codes (so no arrow keys), but what I do have is enough to start using some of the interesting routines from old [s]BYTE magazines[/s] Dr. Dobb's Journals. I should have an actual monitor up and running soon! Unfortunately, I have discovered that my LCD is not exactly ASCII compatible - it has an asian character set! I guess that makes sense, since it comes from an ELEGOO (Chinese) electronics kit. This doesn't really matter much, except that '\' looks like '¥!'
This is not that big of a deal, really, but it does reduce my motivation to make a full-featured shell for it. I might as well leave it rudimentary and get on with reading the CRT Controller Handbook and making a real VDU module.
A couple of design notes:
I started out working from Ben Eater's PS/2 keyboard videos, like many people. My keyboard interface hardware is almost identical, except that I added some 3.3k pullup resistors to the CLK and DATA lines; they're required by the PS/2 spec. Ben left them out, for some reason, but I was getting all kinds of ghostly interrupts from an unstable CLK line until I added them.
My software is a bit different (although I did use his circular buffer - it was cool). Ben does everything in the interrupt handler, and I didn't want to do that; my interrupt handler just puts the next scan-code into a buffer and returns. I wrote a dispatcher subroutine, and ran into the first thing so far that has seemed really strange about the 6502: no conditional calling - only branching! I ended up doing this:
Code:
kb_dispatcher:
lda <next scancode>
cmp #$<case1>
beq kb_case1
.
.
.
cmp #$<caseN>
beq kb_caseN
; default
jmp kb_default
kb_case1:
<do some work>
rts
kb_caseN:
<do some work>
rts
kb_default:
<do some work>
rts
I don't know if that's the cleanest way to structure this sort of thing, but it looks the most like how I used to do it in SCHEME, so it's at least logically clear, and it works!