2022 is supposed to be the year where I plan to dig deeper into fpga programming. I really did not do anything of that kind in over 25 years (back then, I did some GAL logic). So for all intents and purposes, you can consider this the post of a newbie as far as HDL stuff goes.
And what I try to do is trivial, really - a simple adder with carry and borrow and a respective test bench.
-- add1.vhdl
library IEEE;
use IEEE.std_logic_1164.all;
entity add1 is
port (
borrow : in std_ulogic;
a : in std_ulogic;
b : in std_ulogic;
o : out std_ulogic;
carry : out std_ulogic;
err : out std_ulogic);
end add1;
architecture add1arch of add1 is
begin
process
variable inputs : std_ulogic_vector(2 downto 0);
begin
inputs := borrow & a & b;
err <= '0';
case inputs is
when "000" =>
o <= '0';
carry <= '0';
when "100" =>
o <= '1';
carry <= '0';
when "010" =>
o <= '1';
carry <= '0';
when "001" =>
o <= '1';
carry <= '0';
when "011" =>
o <= '0';
carry <= '1';
when "110" =>
o <= '0';
carry <= '0';
when "101" =>
o <= '0';
carry <= '0';
when "111" =>
o <= '1';
carry <= '1';
when others =>
o <= '0';
carry <= '0';
err <= '1';
end case;
end process;
end architecture;
And the test bench looks like this:
-- add1_tb.vhdl
library IEEE;
use IEEE.std_logic_1164.all;
entity add1_tb is
end add1_tb;
architecture test of add1_tb is
component add1
port (
borrow : in std_ulogic;
a : in std_ulogic;
b : in std_ulogic;
o : out std_ulogic;
carry : out std_ulogic;
err : out std_ulogic);
end component;
signal borrow, a, b, o, carry, err : std_ulogic;
signal inputs : std_ulogic_vector(2 downto 0);
begin
adder: add1 port map
(borrow => borrow,
a => a,
b => b,
o => o,
carry => carry,
err => err);
process
begin
inputs <= borrow & a & b;
inputs <= "XXX";
wait for 1 ns;
inputs <= "000";
wait for 1 ns;
inputs <= "001";
wait for 1 ns;
inputs <= "010";
wait for 1 ns;
inputs <= "011";
wait for 1 ns;
inputs <= "100";
wait for 1 ns;
inputs <= "101";
wait for 1 ns;
inputs <= "110";
wait for 1 ns;
inputs <= "111";
wait for 1 ns;
assert false report "done.";
wait;
end process;
end architecture;
Using
ghdl --version
GHDL 1.0.0 (Debian 1.0.0+dfsg-3) [Dunoon edition]
Compiled with GNAT Version: 10.2.1 20210110
mcode code generator
Written by Tristan Gingold.
Copyright (C) 2003 - 2021 Tristan Gingold.
GHDL is free software, covered by the GNU General Public License. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
On a Debian bullseye 64 bit machine.
Building with:
ghdl --clean
ghdl -a add1.vhdl
ghdl -a add1_tb.vhdl
ghdl -e add1_tb
ghdl -r add1_tb --vcd=add1.vcd
The last command never terminates and when I control-c it after a while, the add1.vcd file is empty.
Now here the question, which will help me determine if I have tool chain problems or bugs in my vhdl code:
Does anyone see anything wrong with my code? (I know its clumsy but since I get no errors or warnings, I assume it is syntactically correct.)
As it turns out, the suggestion about "sensitivity lists" (I had to look up first, what that means...) grants an easy fix to my problem
Obviously, the way, processes are "simulated" when the design is being run, depends on some "triggers" to make the "state machine" proceed. This can be waits or - as I learned now - changes to signals contained in the "sensitivity list" (which is a kind of argument list for a process in programming terms).
So, In order to fix my little problem, all I had to do was...
As for the other problem in the test bench, my attempt to find nicer notation for my input signals (
"001" instead of "borrow <= 0; a <= 0; b <= 1;"), I had to make the following changes:Now it behaves as expected and I can see the gtkwave output. The only drawback is, that gtkwave does not offer to display the alias values, so I am stuck with the inputs vector for now, instead.