0
\$\begingroup\$

Here is the source code of what I created for experimental purpose:

library ieee;
use ieee.std_logic_1164.all;

entity experiment_5 is
end entity;

architecture beh of experiment_5 is

constant myconstant : integer := -1;
signal mysignal : integer := -3;

  function add_1(
  a: integer;
  b: integer)
  return integer 
  is
  begin
    return a+b;
  end function add;
  
  function add_2(
  a: integer;
  b: integer)
  return integer 
  is
  begin
    return a+b+myconstant;
  end function add_2;              
  
  function add_3(
  a: integer;
  b: integer)
  return integer 
  is
  begin
    return a+b+mysignal;
  end function add_3;


begin
    
    process
    begin
        report "result is " & integer'image(add_3(3,7)) severity warning;   
        report "result is " & integer'image(add_3(10,12)) severity warning; 
        wait;
    end process;
    
end architecture beh;

Now as expected, the add_1 works just fine and add_3 does not compile. Compiling add_3 gives error message: "# Error: COMP96_0391: experiment_5.vhd : (37, 13): Cannot access "mysignal" from inside pure function "add_3"."

This is all well and good. My questions are:

  1. Why does add_2 compile although it accesses something outside the function which is the constant outside it and is not passed to it as a parameter, and add_2 is declared as a pure function!
  2. Are impure functions supposed to be synthesizable under any circumstances in VHDL?
\$\endgroup\$
1
  • 1
    \$\begingroup\$ 1) Because it's constant. (specifically, "locally static"). Unlike (for example) "const" in C, its value cannot change. Compiler sees the function body as return a + b - 1; which is pure. Try a generic : that's a more interesting case because its value isn't known until elaboration (after which, it cannot change) 2) Sure. There are circumstances where they can be. \$\endgroup\$ Aug 7, 2021 at 18:46

1 Answer 1

1
\$\begingroup\$

At the most basic level, pure functions are defined as follows:

  1. They always generate the same output for the same input. For example a square-root function is pure (sqrt(x) should always return the same value for the same input x), but a random-number generator function is impure.
  2. They have no side effects. Other variables (and signals) are the same as they were before the function got called. (And the file system and stdin/stdout haven't been modified, if your programming language has such things.)

Since add_1 doesn't access anything besides its inputs a and b, it's pretty easy to see that it's a pure function. As you point out, add_2 is accessing something outside it's own scope, but since it's a constant that doesn't matter. If you call add_2(a,b) with the same values of a and b over and over, you'll get the same result over and over. That's a pure function.

The same cannot be said for add_3. Similar to add_2, the function add_3 accesses something outside its own scope (i.e. mysignal), but the important bit is that its value cannot be known in advance (i.e. at elaboration).

So, the key question isn't "does the function access anything outside its own function body?", it's actually "can the output of the function be known based only on its inputs?" (As user_1818839 commented, generics should work as well as constants, since their value is also known at elaboration.)

To your second question, having a function be "impure" doesn't present any problems for synthesis. The main benefit of "pure" functions is that they allow for optimizations since the synthesizer doesn't need to worry about state or any other signals. (Note that it's considered best practice to write "pure" functions whenever possible; functions which satisfy the two criteria above are much easier to understand and to troubleshoot.)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.