This post is part of a series of three post about the recent updates on the FPGA implementation of Compy.
- Compy FPGA – Palettes and line buffers
- Compy FPGA – VRAM and Cornet CPU (this one)
- Compy FPGAs and how I got here
Simultaneous access to RAM from the CPU and the video chip has been always an issue. When using a single bus as most 8 bit computers did, the CPU cannot access the video memory while the video chip is accessing it. There are some notable cases that I’ve seen, for example in the ZX80 computer the CPU had the priority to access the bus, so if you pressed a key and the CPU handled it, the image got corrupted because the video chip couldn’t read the pixels from memory at the same time. On other cases, if a computer has high resolution modes that require to read a lot from the memory, the CPU is most of the time just blocked for access, halted, so you end up with a very slow system, regardless the CPU speed or frequency.
Computers like the MSX took a different approach: The video RAM is isolated from the CPU and only the video chip can access it. This method solves the CPU blocking but produces an additional problem because it is more complex to read and write from video RAM because you cannot access it as memory, you need to do several reads / writes to access each pixel through the video chip.
Compy will use a more modern approach, again thanks to the dual port RAM. The CPU and Chroni will be able to access the video RAM at the same time, each using one port and their own clock! So the CPU runs at full speed and sees the video RAM as normal memory.
There is one additional feature that is not yet implemented but it will be very easy to do. When you use direct access to video RAM in the addressing space (65KB), it’s easy to read/write using the CPU because is “just RAM” so you use the normal LD/ST instrctions, but as you go higher in resolution, colors and other features like sprites, you reduce the amount of addressable memory for code and data. For example in the ZX Spectrum you have 48KB of RAM, but around 6KB is used as video RAM, so you only have around 42KB for your code and data. In the Atari800 a high resolution mode could bring the available RAM from 48KB to only 30KB+ if you are using double buffer, so there is always a compromise between video quality and amount of RAM available for your code and data.
For Chroni to provide high resolution modes with more colors and sprites than these computers, you need a lot more memory. To not sacrifice address space for code and data, I defined that the 128KB of video RAM will be mapped on memory as 8KB blocks, so it wouldn’t take more space than the other computers still allowing to access it at full. The problem now is that the code to access that video RAM may need to handle page traversal, this is, changing the currently mapped 8KB page for another one when needed.
Quite at the beginning it was a though decision to make, because the alternative was to use the method used in the MSX but… why not both? Using the dual port RAM it is quite easy to provide both methods giving more options to the developers depending on what they need. If you need precise read/write operations, you can map the video RAM into the addressable space, if you need just large reads/writes spanning several pages or you want to use the full RAM to store the code and data, you just can unmap the video RAM and access it using the MSX method. The best of both worlds.
“Cornet” 6502 CPU
Adding more features to the FPGA implementation has not been easy at all. One of the problems is that some features require other features that cannot be isolated. For example when adding palettes I also needed a way to initialize that palette from somewhere, so I started to require more sequential code…. a CPU was needed.
Or well, some sort of CPU, even a laughable one.
There are rock solid implementations of several processors, but with my little experience I knew that adding such a big component would be very hard to troubleshoot if I didn’t understand the implementation first. So I decided to create a small 6502 like CPU with just a few instructions, only the ones that I need for now. In the future it will be easy to swap this CPU for a good one because I’ll know that the system works and it is not a fault of the big block of code being added.
Adding this naive CPU was a complete success. It not only allowed me to make some parts of the system work, but it also helped me realize of many of the improvements described in these posts, and I’m starting to feel that Compy in the FPGA is a bit more of a computer rather than only a video output.
Continue on: Compy FPGAs and how I got here