- CRT-based VGA
- 640 x 480 pixels, 60Hz refresh rate
- RGB color code (4-bit per color) -> 12-bit per pixel
-
Convert JPG file to 24-bit BMP file (online converter)
- 24-bit means RGB color code, 8-bit per color (ex. red = ff0000)
-
Convert
.coe
file from 24-bit to 12-bit using regex (8-bit * 3 -> 4-bit * 3)- Under ubuntu command line
- run command
sed 's/.//6' filename.coe > newFile_1.coe
(ex. ff0000 -> ff000) - run command
sed 's/.//4' newFile_1.coe > newFile_2.coe
(ex. ff000 -> ff00) - run command
sed 's/.//2' newFile_2.coe > finalFileName.coe
(ex. ff00 -> f00) - replace first two rows with
memory_initialization_radix = 16; memory_initialization_vector =
However, a single 12-bit RGB COE file of a 640x480 picture fills the block memory of the Nexys4 DDR up to approximately 70%.
This means we would have to compress the size of pictures if we want to achieve horizontal scrolling background.
Note: Python 3.8 and the PILLOW library are required
32-bit is RGBA color coding, 8-bit for each variable.
Using the Python library Image (from PIL), extract the RGBA value (A
= opacity) of each pixel from the PNG file.
Convert the 8-bit R/G/B values to 3-bit binary values (abort value of A
), then concatenate the three into a 9-bit value.
Write the 9-bit value of each pixel into an output COE file.
- Save PNG file in the same directory as
32bitpng_to_9bitcoe.py
(the converter) - At windows cmd, run
$ python 32bitpng_to_9bitcoe.py
- Type in the filename of the PNG file
- Receive COE file under the same directory named
<in_filename>_9bit.coe
Notice how the colors significantly differs from the original PNG file. This is because only the 3 most significant bits of R, G, and B (originally 8-bits each) are concatenated. This brutal solution causes an obvious color distortion.
The simple PNG-to-9bit-COE solution previously presented has a serious distortion in color convertion. Therefore a linear transformation method is introduced here to preserve the color scheme of the original image to the maximum extend. The idea is to have the RGB values between 8-bit (0 ~ 255) be linearly mapped to 3-bit (0 ~ 7). Thus the equation:
Although this convertion method still cannot convert the color scheme completely due to the limited color palette of 9-bit RGB, it did create a much better portrayl of the original image.
- https://stackoverflow.com/questions/12807669/how-to-convert-an-rgb-color-to-the-closest-matching-8-bit-color?fbclid=IwZXh0bgNhZW0CMTAAAR2quU1vXapxB_7i4PH6pAtKHepgDO9oD6pAL2jqr80RxePaxBntHD00WGc_aem_ATH-CjI_HFjCCoazRLQmv4BbaiWMK8Nxit4m6MyYDwNAJm2gAfIcPWPK-v-Pvxw9WEGhIZ2T_s7TtT72Q-HeeF6N
- https://stackoverflow.com/questions/138250/how-to-read-the-rgb-value-of-a-given-pixel-in-python
- https://www.browserstack.com/guide/how-to-use-css-rgba
- https://stackoverflow.com/questions/5676646/how-can-i-fill-out-a-python-string-with-spaces
- https://www.codeproject.com/Questions/1077234/How-to-convert-a-bit-rgb-to-bit-rgb
Create a VGA driver prototype that is able to print a image (saved in ROM) onto the screen.
-
100MHz to 25MHz using Xilinx IP Clocking Wizard
- Don't use homemade counter-based frequency divider or may cause severe clock jittering
- change
CLK_IN1
board interface fromcustom
tosys clock
- rename
clk_out1
toclk_25mhz
- Primitive =
PLL
- output frequency request =
25MHz
- disable
reset
,power_down
, andlocked
-
VRAM using Xilinx IP Block Memory Generator
- interface type =
Native
- memory type =
Single Port ROM
- Enable Port Type =
always enabled
- Port A width =
12
(∵ 4-bit per color) - Port A depth = `307200 (∵ 680 x 480 pixels)
- Load init file =
.coe file location
- interface type =
-
top module:
VGA
- links modules together
- feeds .coe file to
VGA_output
module
-
VGA driving module:
VGA_output
- reads data from data input and scan-prints onto VGA screen
In order to show sprites and other objects above the ROM background, a read-and-write VRAM should be constructed.
A VRAM is a video buffer that saves the rendered image ready to be shown on-screen.
This means that the VRAM_ctrl
module should compare the positions and transparency of sprites to the background and
determine either the color of the sprite or the background should be saved to the VRAM at each pixel.
-
Reads
bg_pos
fromscrolling
module as the starting x position of the frame to scroll through the map as the character moves. -
100MHz to 25MHz using Xilinx IP Clocking Wizard
- Don't use homemade counter-based frequency divider or may cause severe clock jittering
- change
CLK_IN1
board interface fromcustom
tosys clock
- Primitive =
PLL
- output frequency request =
25MHz
- disable
reset
,power_down
, andlocked
-
VRAM using Xilinx IP Block Memory Generator
- interface type =
Native
- memory type =
True Dual Port RAM
True Dual Port RAM: allows simultaneous read and write (4 data buses)
Simple Dual Port RAM: can only read or write at the moment (2 data buses) - Enable Port Type =
always enabled
- Port A width =
9
(∵ 3-bit per color) - Port A depth =
460800
(∵ 960 x 480 pixels) - Load init file =
.coe file location
- Additional output
vga_end
: outputs a pulse signal when finish printing whole screen
- interface type =
Overlays movable sprites on top of VRAM.
- Reads the current VGA printing coordinates, sprite on-screen coordinates, sprite enable, and sprite RAM.
- Checks if the sprite is within screen boundary (aka
block
) - Sprite RAM using Xilinx IP Block Memory Generator
- interface type =
Native
- memory type =
Single Port RAM
- Enable Port Type =
always enabled
- Port A width =
9
(∵ 3-bit per color) - Port A depth = m * n (∵ m * n pixels)
- Load init file =
.coe file location
- Additional output
vga_end
: outputs a pulse signal when finish printing whole screen
- interface type =
- Compares sprite with vram to decide which color data to print onto screen
- https://stackoverflow.com/questions/54592202/24-bit-rgb-to-12-bit-conversion
- http://www.tinyvga.com/vga-timing
- https://projectf.io/posts/video-timings-vga-720p-1080p/
- http://ca.olin.edu/2005/fpga_sprites/new_plan.htm
- http://ca.olin.edu/2005/fpga_sprites/results.htm
- https://support.xilinx.com/s/question/0D52E00006hpaYzSAI/difference-between-bram-configurations-tdp-vs-sdp?language=en_US