With regards to graphics, if one were to dedicate 2k of ram to a frame-buffer, you should be able to get ~5fps by just continuously rendering the frame-buffer to the graphics controller. setPixel is slow because it does 2 r/m/w per pixel, but rendering an already known 8 pixel block would do two writes per block or 1/4 write per pixel for an 8x speedup.
This could be further optimized by keeping a map of dirty/clean bits for each character; then you could just add to the game loop something that polls the ready bit on the latch and writes the next dirty character.
Your setPixel now becomes (read from frame buffer, write if different, mark-dirty if different), which is only a few cycles.
[edit]
Just noticed he mentions something similar as an idea for otimizing. I think my idea is slightly better than his because it can be done with about half as much memory.
You forgot the buffer for the attribute ram, which is needed because otherwise you can only set 7 out of every 8 pixels in a block (you have to set the ‘inverse video’ bit to access all 256 possible combos) =)
There are 16000 1-bit pixels. It can be stored as a bitmap rather than the format used by the graphics adapter. Adding a dirty-bit for each character adds another 2000 bits, making a total of about 2.2k
Reminds me of writing some simple C programs to calculate and display Mandelbrot and Julia sets on my 2x.
Still, wish I'd ended up with an early Mac, for a better entre into microcomputer graphics, but "the powers that be" at that time insisted on the 2x.
I don't know whether the rubber components (e.g. for the floppy drives) in my shelved 2x have deteriorated to the point of failure, but that linked RS-232C WiFi modem is kind of tempting.
There are also various DOS emulators for running CP/M stuff. Which reminds me that I owe archive.org an image of a CD full of contemporary share- and free-ware.
This could be further optimized by keeping a map of dirty/clean bits for each character; then you could just add to the game loop something that polls the ready bit on the latch and writes the next dirty character.
Your setPixel now becomes (read from frame buffer, write if different, mark-dirty if different), which is only a few cycles.
[edit]
Just noticed he mentions something similar as an idea for otimizing. I think my idea is slightly better than his because it can be done with about half as much memory.