Update 2021-03-29: netlistsvg has been updated by yours truly to fix some of the bugs that required workarounds in this blog post. This has been updated to remove those workarounds as they’re no longer required for the latest version of netlistsvg. A blog post about those changes is available here.
Block diagrams are a useful way of presenting state machines and other HDL code in a visual manner. They are useful for learning how the code works, documenting it for future programmers and reports, or debugging code that may not be working as expected.
While tools for generating block diagrams are already included in most HDL development environments, these are typically proprietary (though they may be free as in beer, they’re not free as in freedom). Here is how to generate a block diagram from VHDL using netlistsvg and the open source FPGA toolchain on Linux.
I would recommend downloading the latest FPGA toolchain binaries provided by Open Tool Forge here (or if you’re on an Arch-based distro, it’s available from the AUR as fpga-toolchain-bin
). Make sure to export GHDL_PREFIX=$install_dir/lib/ghdl
to wherever you installed the toolchain, and add the toolchain to your PATH
. netlistsvg
is available via npm, and can be installed by running npm install netlistsvg
.
The procedure is as follows:
- Use GHDL to analyze and synthesize all of the source files. This is done by doing
ghdl -a *.vhdl
assuming all of your files are in the same directory, and end with the.vhdl
suffix. - For each of the VHDL entities for which a block diagram is needed:
- Use Yosys and ghdl-yosys-plugin to create the netlist for that entity
- Use netlistsvg to generate the SVG image
Here is an example of how to integrate this into a Makefile:
ENTITY=top alu counter
simulate:
ghdl -a *.vhdl
svg:
@$(MAKE) simulate
-mkdir svg
for en in $(ENTITY); do \
yosys -p "ghdl $$en; prep -top $$en; write_json -compat-int svg.json"; \
netlistsvg svg.json -o svg/$$en.svg; \
done
Here is another example of how to integrate this into a bash script:
export ENTITY=top alu counter
ghdl -a *.vhdl
mkdir svg
for entity in $ENTITY; do
yosys -p "ghdl $$entity; prep -top $$entity; write_json -compat-int svg.json";
netlistsvg svg.json -o svg/$$entity.svg;
done
For both of these, replace ENTITY=top alu counter
with the list of entities you want to make block diagrams for.
Here’s an example from my blog post about running VGA on the Upduino FPGA:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity vga is
port (
Clk : in std_logic;
row, col : out unsigned(10 downto 0);
HSYNC, VSYNC : out std_logic
);
end vga;
architecture synth of vga is
signal H_A, H_F, H_S, H_B, H_T : integer := 0;
signal V_A, V_F, V_S, V_B, V_T : integer := 0;
signal vert, hori : unsigned(10 downto 0);
begin
-- 49.5 MHz / 800x600
H_A <= 800;
H_F <= 16;
H_S <= 80;
H_B <= 160;
H_T <= H_A + H_F + H_S + H_B;
V_A <= 600;
V_F <= 1;
V_S <= 3;
V_B <= 21;
V_T <= V_A + V_F + V_S + V_B;
process (Clk) begin
if (rising_edge(Clk)) then
if (hori < H_T - 1) then
hori <= hori + 1;
else
hori <= (others => '0');
if (vert < V_T - 1) then
vert <= vert + 1;
else
vert <= (others => '0');
end if;
end if;
if (hori >= (H_A + H_F) and hori <= (H_A + H_F + H_S)) then
hsync <= '0';
else
hsync <= '1';
end if;
if (vert >= (V_A + V_F) and vert <= (V_A + V_F + V_S)) then
vsync <= '0';
else
vsync <= '1';
end if;
row <= vert;
col <= hori;
end if;
end process;
end;
And that’s it! Assuming you did everything correctly (and the tools haven’t changed) this should work for generating block diagrams from VHDL using open source tools. To note as well there’s a Sphinx extension that uses Yosys and netlistsvg to embed block diagrams, but at the time of writing only supports Verilog. Here’s an example of it in action.
Special thanks to Neil Turley for developing and maintaining netlistsvg! Also thanks to all the amazing developers behind the open source FPGA toolchain!