Skip to content

Commit

Permalink
vga/test: fix co-simulation with imagemagick backend
Browse files Browse the repository at this point in the history
  • Loading branch information
umarcor committed Oct 19, 2020
1 parent 3db8128 commit 5add3dc
Show file tree
Hide file tree
Showing 13 changed files with 44 additions and 99 deletions.
6 changes: 6 additions & 0 deletions vga/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ Then, load the bitstream to the board. The following pattern should be shown in

![VGA demo pattern](vga_demo.png)

### Test

Sources in [test/hdl/](test/hdl) provide a *Virtual VGA screen* based on the [VGA (RGB image buffer)](https://ghdl.github.io/ghdl-cosim/vhpidirect/examples/arrays.html#vga-rgb-image-buffer) from [ghdl.github.io/ghdl-cosim](https://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.

[test/hdl/imagemagick/](test/hdl/imagemagick) provides a backend for the virtual screen based on [Imagemagick](https://www.imagemagick.org/). `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. Images are saved to `test/hdl/imagemagick/out/`.

## Development

Currently, the only supported build system is a [Makefile](Makefile). However, we are willing to support the following managers/runners:
Expand Down
4 changes: 2 additions & 2 deletions vga/src/VGA_config_pkg.vhd
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package VGA_config is

type VGA_config is record
type VGA_config_t is record
width : natural; -- W: width
height : natural; -- H: height
rate : natural; -- R: refresh rate
Expand All @@ -19,7 +19,7 @@ end record;
-- __ __
-- _| |XXXXXXX________XXXX|

type VGA_configs_t is array (natural range <>) of VGA_config;
type VGA_configs_t is array (natural range <>) of VGA_config_t;
constant VGA_configs : VGA_configs_t(0 to 61) := (
-- W H R C hS hF hB vS vF vB hP vP
0 => ( 640, 350, 70, 25175, 96, 48, 16, 2, 60, 37, false, true ),
Expand Down
4 changes: 2 additions & 2 deletions vga/src/VGA_sync_gen_cfg.vhd
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
library ieee;
context ieee.ieee_std_context;

use work.VGA_config.all;
use work.VGA_config.VGA_config_t;

entity VGA_sync_gen_cfg is
generic (
CONFIG: VGA_config
CONFIG: VGA_config_t
);
port (
CLK: in std_logic;
Expand Down
2 changes: 1 addition & 1 deletion vga/src/VGA_sync_gen_idx.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ begin
begin
if rising_edge(CLK) then
if RST then
st <= 0;
st <= 2;
else
if EN and p_tc then
st <= 0 when st = 3 else st + 1;
Expand Down
6 changes: 2 additions & 4 deletions vga/src/demo.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use work.VGA_config.all;

architecture demo of Design_Top is

constant cfg : VGA_config := VGA_configs(G_SCREEN);
constant cfg : VGA_config_t := VGA_configs(G_SCREEN);

constant ymid : integer range -1 to cfg.height := cfg.height/2;
constant xmid : integer range -1 to cfg.width := cfg.width/2;
Expand All @@ -30,9 +30,7 @@ architecture demo of Design_Top is
begin

i_sync: entity work.VGA_sync_gen_cfg
generic map (
CONFIG => cfg
)
generic map ( cfg )
port map (
CLK => CLK,
EN => EN,
Expand Down
2 changes: 2 additions & 0 deletions vga/test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
!/imagemagick/out/.gitkeep
/imagemagick/out/
43 changes: 9 additions & 34 deletions vga/test/hdl/screen.vhd → vga/test/hdl/VGA_screen.vhd
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
library ieee;
context ieee.ieee_std_context;

use work.vga_cfg_pkg.all;
use work.VGA_config.all;

entity vga_screen is
entity VGA_screen is
generic (
G_SCREEN : natural;
G_WWIDTH : natural := 0; -- X11 window width
Expand All @@ -16,16 +16,16 @@ entity vga_screen is
RGB: in std_logic_vector(2 downto 0);
VID: in std_logic
);
constant cfg: VGA_config := VGA_configs(G_SCREEN);
package tb_pkg is new work.pkg
constant cfg: VGA_config_t := VGA_configs(G_SCREEN);
package tb_pkg is new work.VGA_screen_pkg
generic map (
G_WIDTH => cfg.width,
G_HEIGHT => cfg.height
);
use tb_pkg.all;
end entity;

architecture arch of vga_screen is
architecture arch of VGA_screen is

constant clk_period : time := (1.0/real(cfg.clk)) * 1 ms;

Expand All @@ -36,36 +36,10 @@ architecture arch of vga_screen is

begin

proc_init: process
begin
-- X11 window size
if G_WWIDTH /= 0 and G_WHEIGHT /= 0 then
sim_init(G_WWIDTH, G_WHEIGHT);
else
sim_init(cfg.width, cfg.height);
end if;
wait;
end process;

proc_clk: process
begin
clk <= '0'; wait for clk_period/2;
clk <= '1'; wait for clk_period/2;
end process;
clk <= not clk after clk_period/2;

i_sync: entity work.vga_sync_gen
generic map (
G_HPULSE => cfg.hpulse,
G_HFRONT => cfg.hfront,
G_WIDTH => cfg.width,
G_HBACK => cfg.hback,
G_HPOL => cfg.hpol,
G_VPULSE => cfg.vpulse,
G_VFRONT => cfg.vfront,
G_HEIGHT => cfg.height,
G_VBACK => cfg.vback,
G_VPOL => cfg.vpol
)
i_sync: entity work.VGA_sync_gen_cfg
generic map ( cfg )
port map (
CLK => clk,
EN => '1',
Expand Down Expand Up @@ -115,6 +89,7 @@ begin
if rising_edge(clk) then
sync(1) <= sync(0);
if sync="01" then
report "save screenshot " & to_string(frame) severity note;
save_screenshot(
screen,
screen'length(2), --width
Expand Down
15 changes: 4 additions & 11 deletions vga/test/hdl/pkg.vhd → vga/test/hdl/VGA_screen_pkg.vhd
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
library ieee;
context ieee.ieee_std_context;

package pkg is
package VGA_screen_pkg is
generic (
G_WIDTH : natural := 640;
G_HEIGHT : natural := 480
Expand All @@ -13,9 +13,6 @@ package pkg is

shared variable screen: screen_t;

procedure sim_init (width, height: natural);
attribute foreign of sim_init : procedure is "VHPIDIRECT sim_init";

-- TODO: pass a fat pointer, so that width and height need not to be passed explicitly
procedure save_screenshot (
variable ptr: screen_t;
Expand All @@ -31,13 +28,9 @@ package pkg is

function RGB_to_integer (rgb: std_logic_vector(2 downto 0)) return integer;

end pkg;

package body pkg is
end VGA_screen_pkg;

procedure sim_init (width, height: natural) is
begin report "VHPIDIRECT sim_init" severity failure;
end procedure;
package body VGA_screen_pkg is

procedure save_screenshot (
variable ptr: screen_t;
Expand Down Expand Up @@ -65,4 +58,4 @@ package body pkg is
return to_integer(unsigned(raw24));
end function;

end pkg;
end VGA_screen_pkg;
20 changes: 8 additions & 12 deletions vga/test/hdl/tb.vhd → vga/test/hdl/VGA_tb.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@ use std.env.stop;
library ieee;
context ieee.ieee_std_context;

use work.VGA_config.all;

entity tb_vga is
generic (
G_SCREEN : natural := 4
G_SCREEN : natural := 22
);
end entity;

architecture arch of tb_vga is

constant clk_period : time := 20 ns;
constant clk_period : time := (1.0/real(VGA_configs(G_SCREEN).clk)) * 1 ms;
signal clk, rst, save_video: std_logic := '0';

type vga_t is record
Expand All @@ -25,28 +27,23 @@ architecture arch of tb_vga is

begin

proc_clk: process
begin
clk <= '0'; wait for clk_period/2;
clk <= '1'; wait for clk_period/2;
end process;
clk <= not clk after clk_period/2;

proc_main: process
begin
report "start simulation" severity note;
rst <= '1';
wait for 10*clk_period;
rst <= '0';
wait for 35 ms;
wait for 100 ms;
report "end simulation" severity note;
save_video <= '1';
wait for 200 ns;
stop(0);
wait;
end process;


VIRT_VGA: entity work.vga_screen
VIRT_VGA: entity work.VGA_screen
generic map (
G_SCREEN => G_SCREEN
)
Expand All @@ -58,8 +55,7 @@ begin
VID => save_video
);


UUT: entity work.vga_pattern
UUT: entity work.Design_Top(demo)
generic map (
G_SCREEN => G_SCREEN
)
Expand Down
27 changes: 0 additions & 27 deletions vga/test/hdl/vga_clk.vhd

This file was deleted.

8 changes: 4 additions & 4 deletions vga/test/caux.c → vga/test/imagemagick/caux.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@
#include <stdint.h>
#include <string.h>

void sim_init(uint32_t width, uint32_t height) {
printf("sim_init is not required, thus empty, in this implementation\n");
}

void integer_to_raw24(int32_t *ptr, uint32_t width, uint32_t height, uint8_t *raw24) {
int x, y;
uint32_t *q = ptr;
Expand All @@ -23,6 +19,10 @@ void integer_to_raw24(int32_t *ptr, uint32_t width, uint32_t height, uint8_t *ra
}

void save_screenshot(int32_t *ptr, uint32_t width, uint32_t height, int id) {
if ( id == 0 ) {
return;
}

assert(ptr != NULL);

uint8_t *raw24 = malloc(width * height * 3);
Expand Down
File renamed without changes.
6 changes: 4 additions & 2 deletions vga/test/run.sh → vga/test/imagemagick/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ set -e
cd $(dirname "$0")

echo "> Analyze ../src/*.vhd and ./hdl/*.vhd"
ghdl -i --std=08 -frelaxed ../src/*.vhd ./hdl/*.vhd
ghdl -i --std=08 -frelaxed ../../src/*.vhd ../hdl/*.vhd

echo "> Build tb (with caux.c)"
ghdl -m --std=08 -frelaxed -Wl,caux.c -o tb tb_vga

rm *.o *.cf

echo "> Execute tb (save wave.ghw)"
./tb --wave=wave.ghw
./tb --wave=out/wave.ghw

0 comments on commit 5add3dc

Please sign in to comment.