Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > VHDL > Synthesizing code with intermediate real values

Reply
Thread Tools

Synthesizing code with intermediate real values

 
 
Topi
Guest
Posts: n/a
 
      05-05-2011
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
 
Reply With Quote
 
 
 
 
Tricky
Guest
Posts: n/a
 
      05-05-2011
On May 5, 10:41*am, Topi <(E-Mail Removed)> 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/
 
Reply With Quote
 
 
 
 
Brian Drummond
Guest
Posts: n/a
 
      05-05-2011
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
 
Reply With Quote
 
Allan Herriman
Guest
Posts: n/a
 
      05-05-2011
On Thu, 05 May 2011 03:26:29 -0700, Tricky wrote:

> On May 5, 10:41*am, Topi <(E-Mail Removed)> 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
 
Reply With Quote
 
Topi
Guest
Posts: n/a
 
      05-05-2011
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
 
Reply With Quote
 
KJ
Guest
Posts: n/a
 
      05-05-2011
On May 5, 4:12*pm, Topi <(E-Mail Removed)> 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
 
Reply With Quote
 
Brian Drummond
Guest
Posts: n/a
 
      05-06-2011
On Thu, 05 May 2011 13:53:03 -0700, KJ wrote:

> On May 5, 4:12*pm, Topi <(E-Mail Removed)> 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
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Synthesizing high-density designs in Quartus Divyang M VHDL 4 08-08-2005 08:20 PM
JSP - saving textfield values before loading 'intermediate' page Rico Java 4 03-14-2005 07:16 PM
Avoiding "Bad Synchronous Description" Error when Synthesizing Takuon Soho VHDL 5 03-09-2005 05:41 AM
Synthesizing a design with RAM. Kelvin @ Singapore VHDL 0 09-08-2003 11:37 PM



Advertisments