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;
callgraph.ps
Description: PostScript document
