ghdl never terminates and I don't know, why

206 Views Asked by At

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.)

1

There are 1 best solutions below

1
BitTickler On

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...

-- add1.vhdl
-- ...
architecture add1arch of add1 is
begin
  process (borrow, a, b) -- list signals in sensitivity list to avoid hangs!

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:

-- add1_tb.vhdl
-- ...
  signal inputs : std_ulogic_vector(2 downto 0);
  signal o, carry, err : std_ulogic;
  alias borrow : std_ulogic is inputs(0);
  alias a : std_ulogic is inputs(1);
  alias b : std_ulogic is inputs(2);
-- ...

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.