As I mentioned in my first post, Steve Ciarcia, in his 1981 book Build Your Own Z80 Computer, called his computer ZAP as it stands for Z80 Application Processor. Since I was planning to use FPGA as a part of my own Z80 computer, it’s only natural to name mine FPGA Assisted Processor, or FAP in short. And now after getting CPU to work, adding memory, and programming the processor, the time has finally come for me to put the F in FAP and starting designing the video interface of my computer.
Looking back at the history of personal computers, it’s not hard to see that the graphical capability is one of the most important aspects of determining the popularity of a said computer, everything was hooked up to a monitor or TV, and no one wanted to have a computer that only communicates through a row of 16 LED lights. And it’s the same case with FAP. Right now it has no means of input/output whatsoever, the only way to see if a program is executing correctly is halting the CPU and examining the RAM content. My plan is to adding keyboard as input, and video out as output. As for the video, there are a number of standards to choose from. There’s RF, and composite video, then the slightly more modern VGA, and after that comes DVI, DisplayPort, HDMI and all the HD standards. I picked VGA because it’s a rather straightforward interface, and it is still being supported by a lot of monitors. I need a horizontal sync pulse, a vertical sync pulse, and 3 analog color signals between 0 and 0.7V. A pixel clock pushes out pixels at each line from left to right, at the end of the line is the HSYNC to tell monitor to move down to the next line, and VSYNC is generated when the last line has reached, signalling monitor to start a new frame. Standard resolution of VGA is 640×480, however, there are additional pixels and lines called front and back porch, those are not rendered on screen and were used to allow time for electron beam to move to the next line/frame. Those adds another 100 or so pixels on each line, and another 40 new lines. The porch also gives time to update video buffer.
When it comes to actually designing the video interface, you have to keep in mind that Z80’s resources is actually rather limited. If we are to drive the VGA at 640×480, we need to put what each pixel is displaying somewhere in a memory, and that is called a Video RAM. For 640×480 we’ll need 307200 bits just to store a 1-bit black and white image, and if we want colors, it will use more than 300K of memory if I use one byte for each pixel, and Z80 can only natively address 64K of memory. What’s more, the processor will have to update more than 300K dots at every single frame, which is way too slow for the 1970s CPU. Since most of what was to be displayed was text anyway, a lot of person computers at the time implemented what called the Text Mode. Instead of individual pixels, the screen is divided in to a number of text cells, each one containing a character, and with character ROM and some special circuits, a text screen can be rendered much faster, and the content of a screen can be manipulated easier too. And most importantly, this method saves a lot of memory, a 80×30 text mode screen in 640×480 only needs 2400 bytes, compared to 300K in bitmap mode. If I want color/underline/blinking/etc I could use an additional byte for those functions, this is often called the attribute. Therefore two bytes are often used in VRAM in text mode, one byte to specify what character it is, and another to specify the color and a number of other attributes of the said character.
I’m using FPGA for the VGA video controller, since it’s much faster than bigbanging VGA with a microcontroller. A class I took a few years ago used a FPGA board for a few projects, but I have forgotten most it by now, that class was also in VHDL, while a lot of the resources online are in Verilog, so this is basically starting anew for me. I used Mojo V3 with Spartan 6 chip. I like it because it’s open source, has a lot of pins, cheap, and it uses a ATmega32u4 microcontroller to configure the FPGA so I don’t need to spend more to buy a programmer, most importantly though it doesn’t have random peripherals that I don’t need taking up pins, it’s just a simple, clean, minimalist board with all the pins broken out and nothing else, just how I like it.
Here is FAP’s video spec that I planned: 640×480 resolution, 80×30 text mode with 8×16 monospace font, 64 colors, 2.4K character RAM and 2.4K attribute RAM. It’s rather basic, but I can always add more fancy stuff later.
I wanted to start with something simple like displaying some patterns, and then go from there. Fortunately for me VGA signal generation is one of the most common tasks for FPGA, and there are tons of resources online. I used some code of this rather excellent example, it simply displays some color bars on screen. I tweaked the code so it uses 2-bit color instead of 3, giving the video card 4*4*4 = 64 colors. The color outputs are digital, with 6 bits in total, which means I need to build a simple DAC to convert it to analog signal bewteen 0 and 0.7V, a R-2R DAC is enough, I used 1K-2K for the job.
With everything hooked up, I uploaded the code and hooked it up to an old LCD monitor that I picked up for $7 just for this project.
Voilà, Color bars! However, the colors in question looks extremely dark, despite the monitor on full brightness. I tried another monitor and it was still the same, after measuring the output of DAC it turns out it’s only putting out 0.09V instead of 0.7V at full intensity, it looks like 1K-2K DAC can’t provide enough current to drive VGA inputs, which I should have known. I tried to use an op-amp buffer, but it was too slow for the 25MHz pixel clock. In the end I just used smaller value resistors for the DAC, I used 150 and 330 ohm, it’s not exactly double but it’ll have to do, and the peak output with VGA connected is 0.68V, pretty close to 0.7V in the specification. With the new DAC, the image is back to full brightness.
Eagle-eyed viewers might have spotted the color bars have changed colors, I did it to see the DAC performance, in 00, 01, 10, 11 increments, first only red, then all channels. Well it looks exactly like how it should be like, reds are red, and greys are grey without color casts.
Then it’s time to tackle the details of the text rendering. First I need two counters to know which pixel I’m at, one for each axis, hpos[9:0] is the horizontal counter that goes from 0 to 639, and vpos[9:0] is the vertical counter that goes from 0 to 479. As the controller draws each pixel I also need to know which pixel in the 8*16 font I am at, this is simply the lower 3/4 bit of the hpos/vpos counter. While the upper 7/6 bits of hpos/vpos is the index of the current character being rendered in the 80×30 grid. The controller will fetch a byte from character RAM, which contains the character to render, as well as an attribute byte to see what color that character is. For start I’ll ignore attribute for now, and the memory location of each character would be 80 * vchar + hchar, where vchar and hchar is the coordinate of the letter. And with the memory address, the video controller can give it to character RAM and get a byte of data back to render. I changed the character rendering code to see if it works.
As you can see it calculates a memory address vram_addr based on the pixel counter, and feeds the lower 6 bits of data to the VGA output, I hooked up a leftover SRAM, and here’s what greeted me when I ran the code:
Beautiful isn’t it? You can see each character cell, where letters will go in, only right now it’s just random colors from junk data inside the SRAM. Say I want to display “A” in a character cell, the content of memory of that cell will be 65, the ASCII code of A. Right now the VGA controller gets the data of 65 and just put its lower 6 bit out as color, next step is making a character ROM, so the VGA controller will look up 65 in it, and see which pixel it should render to put the letter A on screen instead of just a block of color.
And what do you know? Open source community to the rescue again! I found the exactly thing I need on github, a 8*16 code page 437 font. After dropping it in and giving it column and row data, I got this:
We actually got text! Instead of color blobs the VGA controller is rendering characters from garbage data in the SRAM. The characters do look somewhat fuzzy though, and some characters are not rendered properly. To compare with a known example, I filled up a EEPROM with 0 to 255 and dropped it in, it should look like this:
And here is what I got:
It looks even worse than before! If you look really closely you can see it follows the pattern of the code page 437, but every single character is mangled, sometimes beyond recognition. I first thought it was a breadboard noise problem, as I’m running 25MHz on it, and Quinn had this issue while designing hers. However looking closer I can tell each character are mangled in the exactly the same way, and they don’t change when I wiggle some wires, noise tends to be random, so it is not the case. I then thought something might be wrong with the character ROM code, but that seemed unlikely. I then thought it was my crappy monitor, but it looks the same on a better one I tried. Drunk and out of ideas, I though I hooked my wires wrong and basically started messing around with the SRAM data lines, while doing so I found something interesting, this is what the screen looks like while hooking up the 2nd data line directly to the address line:
Happy faces! And most importantly it looks perfect! So it’s not noise nor character ROM problem. I then hooked up the same wire to the data output of the EEPROM:
It looks like the faces are shifted to the left, looks like a timing problem to me. Time to break out the logic analyzer.
Channel 4 is pixel clock, channel 0 is address, channel 2 is data, here you can see data lags behind address for a whopping 140ns, that is more than 4 pixel clocks, and that’s why those faces looks shifted 4 pixels, it turned out my SRAM and EEPROM is too slow, who would have thought that? The AT28C256-15PU I have is rated 150ns, so it’s pretty close, the SRAM I have is rated 50ns, which is still not fast enough, that’s why the image with SRAM is still fuzzy, but not as bad as the one with EEPROM.
Time to buy some new parts, IS61c256 looks promising, it’s the same 32K SRAM but with only 10 – 15ns of delay, which is 14 times faster than the one I’m using. It’s in SOJ package though, so I ought a fee breakout board too, I also picked up a newer Z80 CPU to replace the current one I’m using, this one is CMOS so it uses less power and can run up to 8MHz.
Soldered the new SRAM, hope I didn’t burn it out.
And after plugging it in, here’s how it looks like:
The speed does make a difference! All the character are sharply rendered now, it’s still displaying garbage because that’s what in the SRAM and the time, but the system is working.
Now that the text rendering is working, next part is the interface between the processor and the VGA controller. I’m so drunk and tired now so I’m just going to end it here, stay tuned for the next post!