Synthesizing code with intermediate real values

Discussion in 'VHDL' started by Topi, May 5, 2011.

  1. Topi

    Topi Guest

    Hi,

    I am a little surprised that the following code refuses to synthesize
    (at least with Quartus and Synopsys (Lattice's)):

    **********************

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

    entity real_synth is
    port(
    a_in: in unsigned(15 downto 0);
    b_out: out unsigned(15 downto 0)
    );
    end;

    architecture synth of real_synth is
    begin
    process(a_in)
    variable r: real;
    begin
    r := real(to_integer(a_in));
    r := r*1.2;
    if r<0.0 then
    r := 0.0;
    elsif r>65535.0 then
    r := 65535.0;
    end if;
    b_out <= to_unsigned(integer(r),16);
    end process;
    end;

    ****************************

    Ok, I do understand that real values are a problem when they need to
    be stored, or transported (with signals/ports).

    But in this case the mapping of a_in => b_out can be evaluated by
    brute force (by going through all input states, and running the code
    inside the process for every possible input combination and noting the
    output values).

    Upto today I had thought that all synthesizers would fallback to the
    brute force method if intelligent algorithm generator fails. It seems
    that I had mistrusted them, though.

    Any ideas why the synthesizers DO NOT have this brute-force fallback
    method?

    - Topi
     
    Topi, May 5, 2011
    #1
    1. Advertising

  2. Topi

    Tricky Guest

    On May 5, 10:41 am, Topi <> wrote:
    > Hi,
    >
    > I am a little surprised that the following code refuses to synthesize
    > (at least with Quartus and Synopsys (Lattice's)):
    >
    > **********************
    >
    > library ieee;
    > use ieee.std_logic_1164.all;
    > use ieee.numeric_std.all;
    >
    > entity real_synth is
    >         port(
    >                 a_in: in unsigned(15 downto 0);
    >                 b_out: out unsigned(15 downto 0)
    >         );
    > end;
    >
    > architecture synth of real_synth is
    > begin
    >         process(a_in)
    >                 variable r: real;
    >         begin
    >                 r := real(to_integer(a_in));
    >                 r := r*1.2;
    >                 if r<0.0 then
    >                         r := 0.0;
    >                 elsif r>65535.0 then
    >                         r := 65535.0;
    >                 end if;
    >                 b_out <= to_unsigned(integer(r),16);
    >         end process;
    > end;
    >
    > ****************************
    >
    > Ok, I do understand that real values are a problem when they need to
    > be stored, or transported (with signals/ports).
    >
    > But in this case the mapping of a_in => b_out can be evaluated by
    > brute force (by going through all input states, and running the code
    > inside the process for every possible input combination and noting the
    > output values).
    >
    > Upto today I had thought that all synthesizers would fallback to the
    > brute force method if intelligent algorithm generator fails. It seems
    > that I had mistrusted them, though.
    >
    > Any ideas why the synthesizers DO NOT have this brute-force fallback
    > method?
    >
    > - Topi


    Real types are not appropriate for synthesis in any shape or form.
    There is no definition of how they exist in binary (because it is not
    an array type) and so cannot be synthesised into gates and register.

    You will have to convert your real values to fixed point. Try looking
    at the new IEEE fixed packages. 93 compatible versions of the library
    can be found here:
    http://www.vhdl.org/fphdl/
     
    Tricky, May 5, 2011
    #2
    1. Advertising

  3. On Thu, 05 May 2011 02:41:23 -0700, Topi wrote:

    > Hi,
    >
    > I am a little surprised that the following code refuses to synthesize
    > (at least with Quartus and Synopsys (Lattice's)):
    >
    >
    > process(a_in)
    > variable r: real;
    > begin
    > r := real(to_integer(a_in));
    > r := r*1.2;
    > if r<0.0 then
    > r := 0.0;
    > elsif r>65535.0 then
    > r := 65535.0;
    > end if;
    > b_out <= to_unsigned(integer(r),16);
    > end process;


    Rearrange the computation such that all the real arithmetic operates on
    constants, to return a (constant) integer or unsigned result, and
    synthesis tools should behave correctly.

    For this simple example you can afford to test every interesting input
    value in simulation against the "real" version to prove that no rounding
    errors have occurred; in general that may not be feasible.

    Alternatively, explore the fixed point libraries as Tricky suggested.

    - Brian
     
    Brian Drummond, May 5, 2011
    #3
  4. On Thu, 05 May 2011 03:26:29 -0700, Tricky wrote:

    > On May 5, 10:41 am, Topi <> wrote:
    >> Hi,
    >>
    >> I am a little surprised that the following code refuses to synthesize
    >> (at least with Quartus and Synopsys (Lattice's)):
    >>
    >> **********************
    >>
    >> library ieee;
    >> use ieee.std_logic_1164.all;
    >> use ieee.numeric_std.all;
    >>
    >> entity real_synth is
    >>         port(
    >>                 a_in: in unsigned(15 downto 0);
    >>                 b_out: out unsigned(15 downto 0)
    >>         );
    >> end;
    >>
    >> architecture synth of real_synth is
    >> begin
    >>         process(a_in)
    >>                 variable r: real;
    >>         begin
    >>                 r := real(to_integer(a_in));
    >>                 r := r*1.2;
    >>                 if r<0.0 then
    >>                         r := 0.0;
    >>                 elsif r>65535.0 then
    >>                         r := 65535.0;
    >>                 end if;
    >>                 b_out <= to_unsigned(integer(r),16);
    >>         end process;
    >> end;
    >>
    >> ****************************
    >>
    >> Ok, I do understand that real values are a problem when they need to be
    >> stored, or transported (with signals/ports).
    >>
    >> But in this case the mapping of a_in => b_out can be evaluated by brute
    >> force (by going through all input states, and running the code inside
    >> the process for every possible input combination and noting the output
    >> values).
    >>
    >> Upto today I had thought that all synthesizers would fallback to the
    >> brute force method if intelligent algorithm generator fails. It seems
    >> that I had mistrusted them, though.
    >>
    >> Any ideas why the synthesizers DO NOT have this brute-force fallback
    >> method?
    >>
    >> - Topi

    >
    > Real types are not appropriate for synthesis in any shape or form.



    It's quite ok to use real types in synthesisable VHDL for code that only
    gets executed at compile or elaboration time. For example, you could
    write a function that uses real types internally, which is used to
    produce a (non real, e.g. unsigned) value which is assigned to a constant.

    generic myreal : real = 0.0;

    ....

    constant foo : natural := myfuncthatusesreals(myreal);


    This has had major tool support for a long time.

    Regards,
    Allan
     
    Allan Herriman, May 5, 2011
    #4
  5. Topi

    Topi Guest

    Thanks for the suggestions.

    My point of interest is towards understanding synthesizing process,
    not circumventing the problem.

    As Brian pointed out, in simple cases it _could be feasible_ to crawl
    all possible combinations to get a truth table a_in =to> b_out.
    But in more complex cases the result might be too complex to fit in to
    the target (or to optimize the truth table).

    Tricky: The synthesizer does not need to implement any real-valued
    signals in the synthesized netlist. Actually there aren't any in the
    source code either (the variable is not persistent, so it does not map
    to a register). The synthesized result could be, e.g. a 64kx16 bit rom
    memory.

    Anyway I still don't know/understand why the synthesizer companies
    have opted out from supporting "discrete input =to> discrete output
    mapping, even if there are non-trivial intermediate phased".

    I could easily make a vhdl to vhdl preprosessor to crawl through all
    possible input combinations and to produce truth table from input to
    output.

    Wonder what the synthesizers would think, if e.g. I would replace 8 x
    8 multiplier by 65536 entry table. Would it utilize DSP-block (in
    FPGA) to implement the function?

    - Topi
     
    Topi, May 5, 2011
    #5
  6. Topi

    KJ Guest

    On May 5, 4:12 pm, Topi <> wrote:
    > Thanks for the suggestions.
    >
    > As Brian pointed out, in simple cases it _could be feasible_ to crawl
    > all possible combinations to get a truth table a_in =to> b_out.


    That's not what Brian said at all. He said you can use reals to
    compute constants that, in the end, vanish in the resulting function
    output.

    > But in more complex cases the result might be too complex to fit in to
    > the target (or to optimize the truth table).
    >


    Such as what? Your example is not such an example if that's what you
    had in mind. For starters, the comparison with 0 is not needed, the
    input is unsigned, therefore could never be less than 0. Second,
    rather than taking the input and multiplying by 1.2 and comparing that
    to 65535.0, one could instead compare r with the computed constant
    65535.0 / 1.2 converted to an unsigned. That is what Brian general
    case suggestion would be for your specific example by the way.

    There may indeed be more complex examples as you stated, but give an
    example of such that cannot be trivially changed to be equivalent as
    is the case with your original posting.

    > Anyway I still don't know/understand why the synthesizer companies
    > have opted out from supporting "discrete input =to> discrete output
    > mapping, even if there are non-trivial intermediate phased".
    >


    Most likely because there is little market demand from users. Even
    real constants didn't use to be supported. Now (and for the past
    several years) they are. Given a compelling reason the synthesis
    vendors do support user requests although usually not nearly as fast
    as some might like.

    If you can come up with a compelling use case then you should submit
    it to all the vendors as a feature suggestion. However, you would
    have to do better than your example where the only motivation you
    could provide is that you don't like the looks of "65535.0 / 1.2" as
    compared to "r * 1.2".

    > I could easily make a vhdl to vhdl preprosessor to crawl through all
    > possible input combinations and to produce truth table from input to
    > output.
    >


    OK. And then compare what you get with that approach versus computing
    the constant as suggested here. The metrics of importance to most
    people would be amount of logic resources used and performance. If
    your approach is an improvement you're on to something. If not, maybe
    the synthesis vendors aren't doing such a bad job after all.

    > Wonder what the synthesizers would think, if e.g. I would replace 8 x
    > 8 multiplier by 65536 entry table. Would it utilize DSP-block (in
    > FPGA) to implement the function?
    >


    I would find it highly unlikely that any synthesis tool would take a
    truth table specification in the source code and infer a multiply
    operation from it and then use a DSP block to implement the
    multiply...not to say that it couldn't, I would just be very surprised
    if it did.

    Kevin Jennings
     
    KJ, May 5, 2011
    #6
  7. On Thu, 05 May 2011 13:53:03 -0700, KJ wrote:

    > On May 5, 4:12 pm, Topi <> wrote:
    >> Thanks for the suggestions.
    >>
    >> As Brian pointed out, in simple cases it _could be feasible_ to crawl
    >> all possible combinations to get a truth table a_in =to> b_out.

    >
    > That's not what Brian said at all. He said you can use reals to compute
    > constants that, in the end, vanish in the resulting function output.


    Thanks, that was it.

    > Such as what? Your example is not such an example if that's what you
    > had in mind. For starters, the comparison with 0 is not needed, the
    > input is unsigned, therefore could never be less than 0. Second, rather
    > than taking the input and multiplying by 1.2 and comparing that to
    > 65535.0, one could instead compare r with the computed constant 65535.0
    > / 1.2 converted to an unsigned. That is what Brian general case
    > suggestion would be for your specific example by the way.


    Indeed. But to expand on this, the original code would output r * 1.2 in
    cases where saturation did not occur, so at least an integer constant
    multiplication is necessary.

    However it should be a multiplication of the form :
    r := a_in * to_unsigned(1.2 * 65536) / 65536;
    where the division is trivial.

    Now if careful attention is paid to issues of rounding vs. truncation,
    this will deliver identical results to the original, while eliminating
    run-time floating point arithmetic; otherwise it may deliver results
    differing by +/-1 LSB.

    To be explicit about this, you may need to round the coefficient
    r := a_in * to_unsigned(1.2 * 65536 + 0.5) / 65536;
    or the
    r := (a_in * to_unsigned(1.2 * 65536) + 0.5)/ 65536;
    or both
    to match the integer(r) function in the original version.

    THIS is where I recommend exhaustive testing; comparing the modified
    process vs. the original, IN SIMULATION, for every input value.
    Assert the outputs are equal; regard any difference as a failure.

    This is the brute force approach, but for only 2**16 input values it is
    the easiest. I have used it up to 2**24 inputs without too much pain.
    Alternatively, you may find a mathematical analysis to reduce the number
    of test cases required (otherwise, for 2 independent 32-bit inputs, 2**64
    testcases would be required!)

    Or you may need to justify (and document!) that a 1 LSB error is
    permissible in your use case; e.g. because the input data has a noise
    component much grater than this level.


    - Brian
     
    Brian Drummond, May 6, 2011
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Kelvin @ Singapore

    Synthesizing a design with RAM.

    Kelvin @ Singapore, Sep 9, 2003, in forum: VHDL
    Replies:
    0
    Views:
    531
    Kelvin @ Singapore
    Sep 9, 2003
  2. Takuon Soho
    Replies:
    5
    Views:
    738
    Charles Bailey
    Mar 9, 2005
  3. Divyang M
    Replies:
    4
    Views:
    725
    Divyang M
    Aug 8, 2005
  4. sps
    Replies:
    1
    Views:
    651
    Ralf Hildebrandt
    Aug 6, 2005
  5. Rico
    Replies:
    4
    Views:
    1,545
    kaeli
    Mar 14, 2005
Loading...

Share This Page