I was meaning to throw together a silly unboxing-type video this weekend, but, well,
A: I remembered I don't really like unboxing videos that much, and
B: I instead ended up doing a deep-dive into code cleanup and actually trying to lay down a rigid specification set for what I was trying to accomplish.
Item B: is actually the valid excuse, so I guess I'll speak quickly about that. I initially ordered the parts intended for expanding the "Video Card" prototype several weeks ago, and while waiting for them I ended up exploring all sorts of nitpicky side experimentation and refinements. Some of them were worthwhile, and some of them were "feature creepy" or turned out to not be particularly reliable. The reasons for some of the latter may be because of the limits of having the prototype living on a breadboard, but the TL;DR boils down to that a lot of stuff that seems to work well at 12mhz starts getting flaky above that. I kept flirting with higher clocks in part because part of me was concerned that not supporting a full 80 column mode might be a problem; I did have a "7-bit" 80 column mode that works for graphics at 12mhz but it barely fit horizontally on most CRT monitors, and I also ran into a rude surprise when I tried to add the small amount of logic still needed to be able to run in character generator mode.
A possible flaw in the code I'm using is the way it uses interrupts is kind of expensive; it uses one to trigger the Hsync pulse, sleeps, and uses a second interrupt to switch to the active line rendering code. There is a fair amount of overhead for interrupts on the AVR; it has to save a bunch of registers at the start of an interrupt and restore them when the interrupt is over, and the overhead from that is constant in terms of clock tick overhead; if you run a lower clock it takes longer. This eats into the "active time" I can have per line. At 12mhz the overhead is still acceptable, in the sense that you can fill an active area that runs roughly bezel-to-bezel on older CRT monitors, but if you *fill* that space it leaves very few ticks to do anything else. The prototype in the videos so far is essentially always running in "graphics mode"; to do "text mode" there's going to be a *tiny* bit more overhead in setting a "which row am I on?" register. As it turns out doing 560 pixels at a 12mhz pixel clock essentially absorbed *all* the available CPU ticks, I was having issues fitting the character row in there so it wouldn't overrun the next interrupt. Thus, essentially, I could do a 7 bit 560 pixel bitmap mode, but there's zero point in that. So I ditched it.
Since I still had two control lines implementing 4 possible control states for the shift register control GAL I then switched to experimenting with a "super low" pixel clock to emulate something like the VIC-20's 22 character wide display. The weird thing I ran into, though, is about half of my LCD monitors *hated* this mode when done with a 4mhz pixel clock. (A mono CRT was fine.) Worked okay on a large TV and relatively ancient portable, but a newer smaller LCD with composite in and an NTSC-to-HDMI adapter would fritz out and lose video. Wasted too much time on this, I *think* the problem is that the 4mhz pixel clock might be freaking these devices into thinking they see a phantom colorburst and their scalers then react badly. I then tried for laughs programming a 2.5x (instead of 3x) clock divider into the GALs, and ran into a separate issue where on every other line the resulting pixel lines were offset by one subpixel timing and displayed raggedly. To cut to the chase, well, I've decided I don't care for super-low-res mode anymore. I *might* be able to fix the 2.5x clock issue by coming up with some pulse-stretching logic, but instead I've made the executive decision that it's more trouble than it's worth. The 2x "32 column" 6mhz clock is rock stable and if you *really* want a 22 column display it'll render fine, if a little vertically stretched, in that.
So... here's the compromise I finally came up with, and what I'm planning to move forward on:
- Sticking with 3 pixel clocks; 12mhz, 8mhz, and 6mhz. They render beautifully and the code works.
- MCU will remain at 12mhz. Was pondering the idea of using an 18mhz or even 24mhz clocks so I could cut down on the interrupt overhead time, but there really isn't a point. I'll leave overclocking the AVR for a future VGA variant.
- I brought the 7-bit mode back from the dead in the form of a *six bit* mode. This gives a perfectly legible 80 column screen in only 480 horizontal pixels in the 12mhz clock mode. (IE, 80 columns actually renders slightly narrower than 64's 512px.) The downside of this mode is it will not have selectable characters per line, it will support only 80 because I can't use a loop anymore, it has to use an assembly macro. Framebuffer start is still arbitrarily selectable and I think I should still even be able to do the "windowing" thing if the character buffer is actually larger so, well, don't care, it's good enough. If I want to support emulating an 80 column Commodore that will mean I have to come up with a six bit wide version of the Commodore PETSCII character set, but, too bad.
Anyway, at that point that's what I'm shipping for the video section. Since then I've been puzzling over the computer specs. Still finalizing that, especially what I want to aim for for memory banking, but on the bright side I think I've come up with a "clever" idea that *might* let me support user-definable character sets along with sharing a single ROM between the CPU and the video system. Still fleshing it out but, well, I think I know what I need to prototype next.