Next: , Previous: The hello word program, Up: Starting with GHDL


2.2 A full adder

VHDL is generally used for hardware design. This example starts with a full adder described in the adder.vhdl file:

     entity adder is
       -- i0, i1 and the carry-in ci are inputs of the adder.
       -- s is the sum output, co is the carry-out.
       port (i0, i1 : in bit; ci : in bit; s : out bit; co : out bit);
     end adder;
     
     architecture rtl of adder is
     begin
        --  This full-adder architecture contains two concurrent assignment.
        --  Compute the sum.
        s <= i0 xor i1 xor ci;
        --  Compute the carry.
        co <= (i0 and i1) or (i0 and ci) or (i1 and ci);
     end rtl;

You can analyze this design file:

     $ ghdl -a adder.vhdl

You can try to execute the ‘adder’ design, but this is useless, since nothing externally visible will happen. In order to check this full adder, a testbench has to be run. This testbench is very simple, since the adder is also simple: it checks exhaustively all inputs. Note that only the behaviour is tested, timing constraints are not checked. The file adder_tb.vhdl contains the testbench for the adder:

     --  A testbench has no ports.
     entity adder_tb is
     end adder_tb;
     
     architecture behav of adder_tb is
        --  Declaration of the component that will be instantiated.
        component adder
          port (i0, i1 : in bit; ci : in bit; s : out bit; co : out bit);
        end component;
        --  Specifies which entity is bound with the component.
        for adder_0: adder use entity work.adder;
        signal i0, i1, ci, s, co : bit;
     begin
        --  Component instantiation.
        adder_0: adder port map (i0 => i0, i1 => i1, ci => ci,
                                 s => s, co => co);
     
        --  This process does the real job.
        process
           type pattern_type is record
              --  The inputs of the adder.
              i0, i1, ci : bit;
              --  The expected outputs of the adder.
              s, co : bit;
           end record;
           --  The patterns to apply.
           type pattern_array is array (natural range <>) of pattern_type;
           constant patterns : pattern_array :=
             (('0', '0', '0', '0', '0'),
              ('0', '0', '1', '1', '0'),
              ('0', '1', '0', '1', '0'),
              ('0', '1', '1', '0', '1'),
              ('1', '0', '0', '1', '0'),
              ('1', '0', '1', '0', '1'),
              ('1', '1', '0', '0', '1'),
              ('1', '1', '1', '1', '1'));
        begin
           --  Check each pattern.
           for i in patterns'range loop
              --  Set the inputs.
              i0 <= patterns(i).i0;
              i1 <= patterns(i).i1;
              ci <= patterns(i).ci;
              --  Wait for the results.
              wait for 1 ns;
              --  Check the outputs.
              assert s = patterns(i).s
                 report "bad sum value" severity error;
              assert co = patterns(i).co
                 report "bad carray out value" severity error;
           end loop;
           assert false report "end of test" severity note;
           --  Wait forever; this will finish the simulation.
           wait;
        end process;
     end behav;

As usual, you should analyze the design:

     $ ghdl -a adder_tb.vhdl

And build an executable for the testbench:

     $ ghdl -e adder_tb

You do not need to specify which object files are required: GHDL knows them and automatically adds them in the executable. Now, it is time to run the testbench:

     $ ghdl -r adder_tb
     adder_tb.vhdl:52:7:(assertion note): end of test

If your design is rather complex, you'd like to inspect signals. Signals value can be dumped using the VCD file format. The resulting file can be read with a wave viewer such as GTKWave. First, you should simulate your design and dump a waveform file:

     $ ghdl -r adder_tb --vcd=adder.vcd

Then, you may now view the waves:

     $ gtkwave adder.vcd

See Simulation options, for more details on the --vcd option and other runtime options.