HDMI is just "DVI with knobs on" on the video side.
As to "can it be done"... my first question is "what FPGA"? Some of them can create HDMI/DVI signals with the IO blocks, others just fundamentally can't.
DVI uses TMDS signalling, which is an encoding on top of a Current Mode Logic (CML) differential pair. CML is actively pulled down by a current source for a '0' and floats high with a termination resistor at the far end for a '1'. It might be emulatable for a hobby project by using a bidirectional LVDS pair driven low and using the tristate line to drive and release (a bit like doing an open-drain drive).
Then you have to encode and serialise the data. TMDS describes how to encode the data bits, and then you you "just" have to serialise the data bits across the data pairs. The specification can be found here - see section 3:
Digital Visual Interface Spec
The TFP410 chip data sheet also has a reasonable description of what goes on:
TFP410 - TI PanelBus™ DIGITAL TRANSMITTER
A couple of approaches which may be useful for some styles of display is to divide the display panel into tiles, and
- restrict each tile to using a small set of colors, allowing the use of fewer than 8 bits per pixel, or
- use a byte or two from each tile to select a location from which to read bitmap data.
The first approach could reduce the rate at which data had to be read from display memory. For example, if one used tiles that were 16x16 and could each have four colors chosen from a set of 256, then without using any extra RAM in the FPGA one could reduce the number of memory reads per 16 pixels to eight (four color values, plus four bytes for the bitmap). If one added 160 bytes' worth of buffering/RAM(*) to the FPGA, one could reduce the number of memory reads per 16 pixels to four, using an extra 160 reads every 16 scan lines to read the next set of tile colors. If one wanted 16 colors per tile, the second approach would require an extra 640 bytes of RAM unless one placed some restrictions on the number of different palettes that could exist on a line.
The second approach would probably increase rather than reduce the total memory bandwidth required to produce a display, but would reduce the amount of memory that would have to be updated to change the display--one could change a byte or two to update an 8x8 or 16x16 area of the screen. Depending upon what you're trying to display, it may be helpful when using this style of approach to use one memory device to hold the tile shapes, and another to hold the tile selection. One might, for example, use a fast 32Kx8 RAM to hold a couple 80x60 tile maps with two bytes per tile. If the FPGA didn't have any buffering, it would have to read one byte every four pixels; even with a 40ns static RAM, that would leave plenty of time for the CPU to update the display (an entire screen would only be 9600 bytes). The memory bandwidth for reading out the tile shapes would be no better than it is now, but that part of memory wouldn't have to be updated.
Incidentally, if one didn't want to add a 32Kx8 RAM but could add add 320 bytes of buffering/RAM(**) to the FPGA, one could use a tile-map approach but have the CPU or DMA feed 160 bytes to the display every 8 scan lines. That would burden the controller somewhat even when nothing on the display was changing, but could simplify the circuitry.
(*) The buffer could be implemented as RAM, or as a sequence of 32 40-bit-long shift registers plus a little control logic.
(**) The buffer could be implemented as two 160-byte RAMs, or as two groups of sixteen 80-bit shift registers.
Best Answer
VGA output on the Basys3 board uses binary-weighted R-2R-4R-8R hand-made resistor network to make a simple 4-bit DAC out of digital logic-level outputs from FPGA.
The coding of "VGA_XX" logic signals can be anything, YPbPr, or whatever. The 4-bit converter will produce the same ~0.7 V output when delivered to the standard 75-Ohm analog interface.
If you don't like the resulting levels, you can change the resistors to suit your needs.
EDIT: As follows from the very useful appnote from Rohde&Schwarz (Testing of Analog Video Component Signals) linked by user below, both R-G-B and YPbPr signals have a peak-to-peak amplitude of 700 mV. However, both signals have a sync pulse with negative (350 mV) amplitude, and YPbPr goes from -350 to +350. As it is designed into Basys3 board, the primitive DAC can't generate negative levels, so the signal, even for RGB format, will be sub-standard. It might show something on a VGA display, but image might be unstable. The YPbPr signal will be even less resembling the standard, so you can forget about accurate color reproduction on component monitors.
In summary, the Basys3 board doesn't have proper means to generate standard RGB nor YPbPr signals.