Using GHDL to simulate VHDL16. Oct '14
Open-source tools for VHDL seem to be lacking, I am mainly using GHDL 1 to analyze and simulate VHDL design. Verilog on the other hand has a lot of open-source tools available 2 3. Note that VHDL is case insensitive, at least for modern compilers. Personally I think it's nice to have your code yelling at you therefore I default to lowercase. Consistency throughout any software project is of course the most important aspect.
I have used packages built by Joris van Rantwijk to install GHDL on my Debian Wheezy machine 4. These instructions should be double-checked for any other distribution of course:
wget http://sourceforge.net/projects/ghdl-updates/files/Builds/ghdl-0.31/Debian/ghdl_0.31-2wheezy1_amd64.deb sudo dpkg -i ghdl_0.31-2wheezy1_amd64.deb
I think it's a good convention to keep the entity name synchronized with the filename and also in lower case. GHDL also seems to look up components by the filename. So for example following entity should be saved to full_adder.vhd:
library ieee; use ieee.std_logic_1164.all; entity full_adder is port ( a : in std_logic; b : in std_logic; ci : in std_logic; s : out std_logic; co : out std_logic); end; architecture behavioral of full_adder is begin s <= a xor b xor ci; co <= (a and b) or ((a xor b) and ci); end;
To compile binary object full_adder.o from a VHDL source file full_adder.vhd use the -a analyze command-line option:
ghdl -a full_adder.vhd
Now these object files can be referred by other entities via component declaration.
Consider following testbench source code in file full_adder_testbench.vhd:
library ieee; use ieee.std_logic_1164.all; entity full_adder_testbench is end full_adder_testbench; architecture behavior of full_adder_testbench is component full_adder is port ( a : in std_logic; b : in std_logic; ci : in std_logic; s : out std_logic; co : out std_logic); end component; signal input : std_logic_vector(2 downto 0); signal output : std_logic_vector(1 downto 0); begin uut: full_adder port map ( a => input(0), b => input(1), ci => input(2), s => output(0), co => output(1) ); stim_proc: process begin input <= "000"; wait for 10 ns; assert output = "00" report "0+0+0 failed"; input <= "001"; wait for 10 ns; assert output = "01" report "0+0+1 failed"; input <= "010"; wait for 10 ns; assert output = "01" report "0+1+0 failed"; input <= "100"; wait for 10 ns; assert output = "01" report "1+0+0 failed"; input <= "011"; wait for 10 ns; assert output = "10" report "0+1+1 failed"; input <= "110"; wait for 10 ns; assert output = "10" report "1+1+0 failed"; input <= "111"; wait for 10 ns; assert output = "11" report "1+1+1 failed"; report "Full adder testbench finished"; wait; end process; end;
The object file for testbench must be compiled aswell:
ghdl -a full_adder_testbench.vhd
Running GHDL with the elaborate option -e will produce a binary and link all the related entities to the binary. Note that object file full_adder_testbench.o here is referred by the entity name full_adder_testbench:
ghdl -e full_adder_testbench
Now you have binary ready to go:
Which should output:
full_adder_testbench.vhd:36:9:@70ns:(report note): Full adder testbench finished
Putting it all together
Makefiles help out tracing changes to modified files:
GHDL=ghdl GHDLFLAGS= MODULES=\ carry_ripple_adder.o \ alu.o \ full_adder.o \ alu_testbench \ carry_ripple_adder_testbench \ full_adder_testbench test: $(MODULES) ./full_adder_testbench --vcd=full_adder_testbench.vcd ./carry_ripple_adder_testbench --vcd=carry_ripple_adder_testbench.vcd ./alu_testbench --vcd=alu_testbench.vcd # Binary depends on the object file %: %.o $(GHDL) -e $(GHDLFLAGS) $@ # Object file depends on source %.o: %.vhd $(GHDL) -a $(GHDLFLAGS) $< clean: echo "Cleaning up..." rm -f *.o *_testbench full_adder carry_ripple_adder work*.cf e*.lst
Place the file as Makefile next to VHDL files. In this case issuing simply make in that directory would compile all necessary files and execute testbenches.