Skip to content

Latest commit

 

History

History

vga

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

VGA test pattern

This component aims to provide Video Graphics Array (VGA) output examples for "all the FPGA dev boards in the world" (sic). It allows quickly testing your FPGA board and a monitor through tens of supported VGA modes (see VGA_config_pkg.vhd).

At the same time, the goal is to provide a reference structure for HDL projects with the following requirements:

  • Design sources are written in VHDL and/or Verilog.
  • Multiple target boards (hence, devices) are supported.
  • Open source tooling and vendor tooling are used, for simulation, synthesis, implementation and programming.
  • Open source resources are reused.

The sources of this component are organised as follows:

  • board: a subdir for each supported board, where HDL sources specific to the board are located.
  • device: a subdir for each supported device, where HDL sources specific to the device are located. These sources are expected to be used in HDL sources located in board/*/.
  • src: HDL sources of the component, which are common for simulation and/or synthesis, and for any target.
  • test: resources for simulation (testing and verification), including testbenches, unit tests and co-simulation cores (such as a virtual screen).

Standing on the shoulders of...

The structure of this repository was heavily inspired by PLC2/Solution-StopWatch; the solution used by Patrick Lehmann in PLC2's 5-day class Professional VHDL.

The idea about supporting "all the FPGA dev boards in the world" was borrowed from fusesoc/blinky; one of the examples in the base library of Olof Kindgren's FuseSoC.

The makefile for mixed language synthesis using open source tooling (GHDL, Yosys, nextpnr, icestorm, etc.) was borrowed from im-tomu/fomu-workshop; the workshop for the Fomu board by Tim Ansell and Sean Cross.

Unlike all previous references, where ad-hoc constraint files (*.xdc, *.pcf, etc.) are used, here implementation constraint are imported from an open source repository. hdl/constraints (based on VLSI-EDA/PoC: ucf/) is a submodule of this repository, and constraints are imported from there.

Co-simulation and the virtual screen are implemented using GHDL's VHPIDIRECT examples from ghdl/ghdl-cosim. See [LCS-202x] VHDL DPI/FFI based on GHDL’s implementation of VHPIDIRECT.

Design

The core of the design (the UUT) is a parameterised synchronism generator (VGA_sync_gen), built by chaining two instances of a four state machine and a counter (VGA_sync_gen_idx). Those components can be used standalone, by providing porch and pulse durations through generics. However, VGA_config contains a record type that wraps all the parameters in a single object. VGA_sync_gen_cfg allows instantiating the synchronism generator by passing a single generic of the given record type.

In the demo architecture, the synchronism generator is instantiated and an static pattern is generated in a process. Users willing to write their own applications/designs with VGA output are encouraged to to adapt demo.vhd for plugging their designs. The synchronism generation module (VGA_sync_gen or VGA_sync_gen_cfg) can be preserved, so that only the application logic needs to be described.

Note that the UUT (Design_Top) does not include any conversion of the input clock frequency. Any instantiation of PLLs or other clock management units should be done in sources specific to some device (in device/) or to some board (in board/). The clock input to the UUT should match the expect pixel clock frequency.

On the other hand, the virtual VGA screen used for testing (see below) is also based on the same synchronism generator component. However, the generator of the UUT and the one in the virtual screen component are unrelated. Only VSYNC and HSYNC are connected between them. Precisely, the virtual screen uses the edges of VSYNC for synchronising frame captures. As a result, simulation and capture is slow, but it tries to accurately model the behaviour of an external VGA device.

Usage

NOTE: for now, the only supported toolchain is: ghdl-yosy-plugin + Yosys + nextpnr. open-tool-forge/fpga-toolchain provides ready-to-use packages for GNU/Linux, Windows or macOS, which include all of them. See github.com/open-tool-forge/fpga-toolchain#installation.

First, run synthesis and implementation:

make VGA_BOARD=<BOARD_SUBDIR>

For instance:

make VGA_BOARD=icestick

Then, load the bitstream to the board. The following pattern should be shown in the monitor:

Select a different VGA mode

Package VGA_config_pkg.vhd contains a table (described as an array of records) with parameter values (pulse, porch, pixel clock rate, polarity, etc.) for +60 VGA/VESA/SXGA/XGA modes. The table is used in the VGA signal generator, allowing changing the mode through a parameter of type integer.

At the same time, the top level entity for each board includes a generic integer with a default value. GHDL allows overriding generics through the CLI. Therefore make GHDL_FLAGS=-gSCREEN=<mode index> allows selecting a different mode without modifying HDL sources.

Testing

Sources in test/hdl/ provide a Virtual VGA screen based on the VGA (RGB image buffer) from ghdl.github.io/ghdl-cosim. A VGA monitor (VHDL) reads the output of the UUT and draws frames in a buffer, packing the colours of each pixel in a 32 bit integer. After each frame is complete, foreign subprogram save_screenshot is executed. Just before finishing the simulation, foreign subprogram sim_cleanup is executed.

Imagemagick (animated GIF)

test/imagemagick/ provides a backend for the virtual screen based on Imagemagick. save_screenshot saves each frame to a binary file in RGB24 format. Then, convert from Imagemagick is used for generating a PNG screenshot. In sim_cleanup, convert is used for merging all the PNGs into an animated GIF. Execute the run script for running the simulation:

./test/imagemagick/run.sh

Images are saved to test/imagemagick/out/.

Tkinter (desktop window)

test/tkinter/ provides a backend for the virtual screen based on tkinter, the built-in Python interface to Tcl/Tk. The Tk GUI toolkit is available on most Unix platforms, as well as on Windows systems. NumPy's ctypeslib and Pillow's ImageTk are used for transforming the VHDL buffer to an image and for displaying the frames in a desktop window. After installing the dependencies, execute the run script for running the simulation:

./test/tkinter/run.sh

A window is shown on the desktop and it is updated after each frame is captured by the VHDL VGA monitor.

NOTE: On MSYS2's MINGW64, numpy needs to be installed through pacman. Furthermore, installing Pillow through pip requires the packages listed in pillow.rtfd.io: Building on Windows using MSYS2/MinGW.

Development

How to add a board

  • Check in Issues whether some other user is already working on it.
  • Create a subdir in board/<SUBDIR_NAME> and a file named board/<SUBDIR_NAME>/<BOARD_NAME>_Top.<EXTENSION>. Create an entity named <BOARD_NAME>_Top and an architecture.
  • Find the board in ../constraints. If not found, open an issue or submit a Pull Request to hdl/constraints.
  • Add ports to <BOARD_NAME>_Top, according to the constraint files corresponding to the board.
  • Instantiate Design_Top(demo) in the <BOARD_NAME>_Top unit.
  • Connect the Design_Top to the top level ports. If required, negate them or do other conversions specific to the board. Typically, the external clock needs to be adapted with some PLL|DCM|MMCM for matching the expected pixel clock for the selected mode.
    • device/ contains components and packages which map multiple PLL|DCM|MMCM parameters to the table of all supported modes. Therefore, an optional board/<SUBDIR_NAME>/<BOARD_NAME>_config_pkg.<EXTENSION> package can be used. See, for example, board/icestick/Icestick_PLL_config_pkg.vhd.

Currently, the only supported build system is a Makefile. However, we are willing to support the following managers/runners:

How to use the virtual VGA screen in existing VHDL designs

  • Add this repository as a submodule of your repo.
  • Copy test/hdl/VGA_tb.vhd somewhere outside of the submodule.
  • Copy test/imagemagick/run.sh and/or test/tkinter/run.sh somewhere outside of the submodule.
  • Modify the paths in the run.sh file(s) for pointing to:
    • The sources of your own design.
    • The auxiliary files in the submodule.
  • Execute the run.sh script(s).

How to implement a different virtual VGA backend

Any application/library which satisfies the following C prototypes can be used as a backend:

void save_screenshot(int32_t *ptr, uint32_t width, uint32_t height, int id)

void sim_cleanup(void)

See test/imagemagick/caux.c for an example of how to convert the 32 bit integer to RGB24.

Nevertheless, implementation is not limited to C/C++. Other languages (such as Python or Rust) provide nice integration with C. See example pycb from ghdl.github.io/ghdl-cosim.