It has been a week since my last post, when we left the action last time the FAP’s video card was working with double buffering and color attributes, and a test run resulted in this:
Remember the program was filling up attribute memory with 0x1b, a purple color, and character memory with letter A. However as you can see above, after running the program some character cells did not turn purple, and some others turned purple, but letters did not change to A. This was because the CPU was trying to write to VRAM while VRAM copying was under way, and the operation was ignored by the GPU. To prevent this from happening we need some way to let CPU know that GPU is busy so it can wait a little until the copying is done. I decided to make a few memory mapped virtual register for my GPU, this way the Z80 can ask GPU if it’s busy first, if it is the CPU will wait, otherwise CPU can write to VRAM right away, here is the updated virtual register code:
Basically I just added a single line of code, now when CPU tries to read address 0x92c0 it will get the value of copy_in_progress, which is 1 when VRAM is underway. This way, the CPU first poll this register every time it wants to write to VRAM, and wait if its value is 1, problem solved! Well not quite:
After running the VRAM-filling program again, there are still a bunch of problem character cells, although much fewer than before. Actually it’s not hard to figure out why: Sometimes the CPU will ask right before VRAM copy starts, so the GPU replies that it’s idle, but when CPU tries to write to VRAM a few clock cycles later the copying will already be underway, and the write gets ignored as a result. We need a way to let CPU know a little while before copy actually starts. I did a dirty little hack by creating another signal that goes active a few scanlines before VBLANK actually starts, this way the CPU will see that GPU is busy a little earlier, so if it happens to try to write before the copy it will have time to do finish the operation. After that, the FAP is finally rendering a beautiful screen full of purple A’s. Time to write a proper “hello world” program:
I created a ‘check’ subroutine which gets called every time before CPU tries to write to VRAM. The program first fill the attribute with yellow, then clear the screen, then print “hello world” at the first row on the screen. Here is how it look like:
Nice isn’t it, it’s the moments like this that keeps me going. A few weeks ago I have no idea how to build a computer, and FAP was just a bunch of 20 year old chips, and now it’s running my program and saying hello to the world like any other proper computers!
Celebration aside though, notice how this hello world program is remarkably slow. I ran it at a slower clock to see the progress, but even at a full 2MHz it still takes like half a second to complete, which is forever in microcomputers. The reason is that the Z80 has to read the gpu_busy register before every single write, which wastes a huge amount of time. A better solution would be let CPU be able to disable GPU copying all together, do the write, then enable copying again. This way the CPU does not have to wait at all, and only has to write to GPU register twice instead of 4800 times. The new copy_enable register is at 0x92c1. Here is the updated code:
I added another if condition so now CPU can read from VRAM too. However most importantly now when CPU writes 0 to 0x92c1, VRAM copy will be disabled. The CPU then can write to VRAM at full speed without interruption. And when it’s done the CPU can enable VRAM copy again and the result will be displayed on the screen on the next frame. I wrote another program to test it.
I put together a “print” function, you put character you want to print in c, attribute in b, index on screen in de, and call it. I first disable the VRAM copy, then clear the screen with char 0 and write “Hello World!” to it, then enable the VRAM copy again. Here is the result:
As you can see this is much faster than the first attempt. The text appears on screen instantly. Looks like disabling copy during bulk VRAM write is the way to go.
However, if you look at the video carefully the supposedly white text appears bit yellow or red. I spent days trying to fix this issue, tweaking the FPGA code and swapping out VRAM chips. In the end I don’t think it’s the VRAM or the copy routine, since the character and attribute are copied together, and all the texts seems fine. I think it’s the noise again, with more than 100 spaghetti wires running around. It might be better than breadboard, but apparently still not good enough. I’ll probably have to design a proper PCB for the video card to see if it gets better. I think I’ll move on for now, I’m just kind of tired with working on the video card right now.
Now the video card is working, next step is setting up the keyboard input for FAP. Find out what happens in my next post!