Hi Tristan,

some time ago I benchmarked (i.e. ran under valgrind/callgrind) one of
my bigger testbenches, and it turned out that a lot of the runtime is
spent in ieee.numeric_std."+" and friends. The way this routine is coded
does not seem to be very efficient to me. So I've experimented with an
alternative implementation of "+". See the attached VHDL file. According
to callgrind, it is indeed a lot faster, the instruction count needed is
roughly divided by 6. So it seems worthwhile to me to have optimized
libraries. What is your stance on this? Would you want to have this in
the distribution?

BTW, there's another 'image problem, if you uncomment the two lines in
test1_p, ghdl will ICE.

Tom

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

use std.textio.all;

entity addtest is
end addtest;

architecture testbench of addtest is

  constant stdulogic_low : std_ulogic := std_ulogic'low;
  constant stdulogic_high : std_ulogic := std_ulogic'high;
  constant stdulogic_low_bound : integer := std_ulogic'pos(std_ulogic'low);
  constant stdulogic_high_bound : integer := std_ulogic'pos(std_ulogic'high);
  type value_table_t is array (stdulogic_low_bound to stdulogic_high_bound) of 
natural range 0 to 1;
  type valid_table_t is array (stdulogic_low_bound to stdulogic_high_bound) of 
boolean;
  constant value_table : value_table_t := ( std_ulogic'pos('0') => 0,
                                            std_ulogic'pos('1') => 1,
                                            std_ulogic'pos('L') => 0,
                                            std_ulogic'pos('H') => 1,
                                            others => 0 );
  constant valid_table : valid_table_t := ( std_ulogic'pos('0') => true,
                                            std_ulogic'pos('1') => true,
                                            std_ulogic'pos('L') => true,
                                            std_ulogic'pos('H') => true,
                                            others => false );
  type res_table_t is array (0 to 1) of std_ulogic;
  constant res_table : res_table_t := ( '0', '1' );

  function "+" (l, r : unsigned) return unsigned is
    constant l_left : integer := l'length-1;
    alias xl : unsigned(l_left downto 0) is l;
    alias xr : unsigned(l_left downto 0) is r;
    variable xxl, xxr : integer;
    variable res : unsigned(l_left downto 0);
  begin
    if (l_left < 0 or l_left > 30 or l'length /= r'length) then
      return ieee.numeric_std."+"(l, r);
    end if;
    xxl := 0;
    xxr := 0;
    for i in l_left downto 0 loop
      if not (valid_table(std_ulogic'pos(xl(i))) and 
valid_table(std_ulogic'pos(xr(i)))) then
        return ieee.numeric_std."+"(l, r);
      end if;
      xxl := xxl * 2 + value_table(std_ulogic'pos(xl(i)));
      xxr := xxr * 2 + value_table(std_ulogic'pos(xr(i)));
    end loop;
    xxl := xxl + xxr;
    for i in 0 to l_left loop
      res(i) := res_table(xxl mod 2);
      xxl := xxl / 2;
    end loop;
    return res;
  end "+";

  function std_ulogic_vector_image(x : std_ulogic_vector) return string is
    variable s : string(1 to x'length);
    variable s1 : string(1 to 3);
    variable j : positive := 1;
  begin
    for i in x'range loop
      s1 := std_ulogic'image(x(i));
      s(j) := s1(2);
      j := j + 1;
    end loop;
    return s;
  end std_ulogic_vector_image;

  function std_ulogic_vector_image(x : unsigned) return string is
  begin
    return std_ulogic_vector_image(std_ulogic_vector(x));
  end std_ulogic_vector_image;
  
  function random return integer is
  begin
    assert false report "native" severity failure;
  end random;

  attribute foreign of random : function is "VHPIDIRECT random";

  signal siga, sigb, sigr : unsigned(15 downto 0);

begin

  test_p: process
    type sigvalue_t is array (0 to 3) of std_ulogic;
    constant sigvalue : sigvalue_t := ( '0', '1', 'L', 'H' );
    variable a : unsigned(siga'range);
    variable b : unsigned(sigb'range);
    variable r1, r2 : unsigned(sigr'range);
    variable ln : line;
  begin
    for i in 0 to 8191 loop
      for j in a'range loop
        a(j) := std_ulogic'val(std_ulogic'pos(std_ulogic'low) + (random mod 
(std_ulogic'pos(std_ulogic'high)-std_ulogic'pos(std_ulogic'low)+1)));
      end loop;
      for j in b'range loop
        b(j) := std_ulogic'val(std_ulogic'pos(std_ulogic'low) + (random mod 
(std_ulogic'pos(std_ulogic'high)-std_ulogic'pos(std_ulogic'low)+1)));
      end loop;
      siga <= a;
      sigb <= b;
      r1 := "+"(a, b);
      r2 := ieee.numeric_std."+"(a, b);
      assert std_ulogic_vector(r1) = std_ulogic_vector(r2) report
        std_ulogic_vector_image(a) & "+" & std_ulogic_vector_image(b) & "=" &
        std_ulogic_vector_image(r2) & "/=" & std_ulogic_vector_image(r1) 
severity failure;
      sigr <= r1;
      wait for 1 ns;
    end loop;
    write(ln, string'("Invalid number coding ok, now trying acceptable 
values"));
    writeline(output, ln);
    for i in 0 to 65535 loop
      for j in a'range loop
        a(j) := sigvalue(random mod 4);
      end loop;
      for j in b'range loop
        b(j) := sigvalue(random mod 4);
      end loop;
      siga <= a;
      sigb <= b;
      r1 := "+"(a, b);
      r2 := ieee.numeric_std."+"(a, b);
      assert std_ulogic_vector(r1) = std_ulogic_vector(r2) report
        std_ulogic_vector_image(a) & "+" & std_ulogic_vector_image(b) & "=" &
        std_ulogic_vector_image(r2) & "/=" & std_ulogic_vector_image(r1) 
severity failure;
      sigr <= r1;
      wait for 1 ns;
    end loop;
    write(ln, string'("Done!"));
    writeline(output, ln);
    wait;
  end process test_p;








  
  test1_p: process
    constant stdulogic_low : std_ulogic := std_ulogic'low;
    constant stdulogic_high : std_ulogic := std_ulogic'high;
    
    variable ln : line;
    variable l1 : std_ulogic;
    variable l2 : std_ulogic;
    variable s1 : string(1 to 3);
    variable s2 : string(1 to 3);
  begin
    l1 := stdulogic_low;
    l2 := stdulogic_high;
    s1 := std_ulogic'image(l1);
    s2 := std_ulogic'image(l2);
    --s1 := std_ulogic'image(stdulogic_low);
    --s2 := std_ulogic'image(stdulogic_high);
    write(ln, "L " & s1 & " H " & s2);
    writeline(output, ln);
    write(ln, "L " & integer'image(std_ulogic'pos(l1)) & " H " & 
integer'image(std_ulogic'pos(l2)));
    writeline(output, ln);

    wait;
  end process test1_p;

end testbench;

Attachment: callgraph.ps
Description: PostScript document

Reply via email to