I am using David bishop's fixed point library to do some math in vhdl. and i need to decode the final value into integers. the method i have followed as below, and i do get fine value for fractional part but the decimal value is not correct. i could not find the issue yet. in decimal part 1st two digits are wrong. xx8374.839923 xx numbers are wrong always.
when i perform this, i get 274334.738295 for 174334.738295
inside architecture,
inside process i do declare these variables,
variable cp : sfixed(20 downto -19);
variable mod10 : sfixed(4 downto 0);
variable div10 : sfixed(4 downto 0);
variable L0 : sfixed(4 downto 0);
variable L1 : sfixed(4 downto -4);
variable L2 : sfixed(4 downto -8);
variable L3 : sfixed(4 downto -12);
variable L4 : sfixed(4 downto -16);
variable L5 : sfixed(4 downto -20);
variable L6 : sfixed(4 downto -24);
variable temp_L : sfixed(19 downto 0);
variable temp_L1 : sfixed(20 downto -4);
variable temp_L2 : sfixed(21 downto -8);
variable temp_L3 : sfixed(22 downto -12);
variable temp_L4 : sfixed(23 downto -16);
variable temp_L5 : sfixed(24 downto -20);
variable temp_L6 : sfixed(25 downto -24);
after begin, i need to decode 174334.738295 in sfixed, because some times i get negative number. this number is to replaced by another calculation, which is not provided here, if that number is 174334.738295 (sfixed) then i need to decode this number,
cp := to_sfixed(174334.738295,20,-19);
temp_L := cp(19 downto 0); -- remove sign bit
mod10 :=to_sfixed(10,4,0) ;
div10 :=to_sfixed(10,4,0) ;
L0 := temp_L mod mod10;
temp_L1 := temp_L/div10;
L1 := temp_L1 mod mod10;
temp_L2 := temp_L1/div10;
L2 := temp_L2 mod mod10;
temp_L3 := temp_L2/div10;
L3 := temp_L3 mod mod10;
temp_L4 := temp_L3/div10;
L4 := temp_L4 mod mod10;
temp_L5 := temp_L4/div10;
L5 := temp_L5 mod mod10;
temp_L6 := temp_L5/div10;
L6 := temp_L6 mod mod10;
L6 is the 1st digit and L5 is the 2nd digit.
Modifying your original code with fixes for div10, mod10 (with underscores leaving the declarations alone) and producing an MCVE:
library ieee;
use ieee.fixed_pkg.all;
entity iopertyki is
end entity;
architecture fum of iopertyki is
begin
process
variable cp: sfixed(20 downto -19);
variable mod_10: sfixed(4 downto 0);
variable div_10: sfixed(4 downto 0);
variable mul_10: sfixed(4 downto 0);
variable L0: sfixed(4 downto 0);
variable L1: sfixed(4 downto -4);
variable L2: sfixed(4 downto -8);
variable L3: sfixed(4 downto -12);
variable L4: sfixed(4 downto -16);
variable L5: sfixed(4 downto -20);
variable L6: sfixed(4 downto -24);
variable temp_L: sfixed(19 downto 0);
variable temp_L1: sfixed(20 downto -4);
variable temp_L2: sfixed(21 downto -8);
variable temp_L3: sfixed(22 downto -12);
variable temp_L4: sfixed(23 downto -16);
variable temp_L5: sfixed(24 downto -20);
variable temp_L6: sfixed(25 downto -24);
begin
cp := to_sfixed(174334.738295,20,-19);
report "cp = " & to_string(cp);
temp_L := cp(19 downto 0); -- remove sign bit
report "temp_L = " & to_string(temp_L);
report "integer'image temp_L = " & integer'image(to_integer(temp_L));
mod_10 := to_sfixed(10,4,0);
div_10 := to_sfixed(10,4,0);
mul_10 := to_sfixed(10,4,0);
L0 := temp_L mod mod_10;
temp_L1 := temp_L/div_10;
L1 := temp_L1 mod mod_10;
temp_L2 := temp_L1/div_10;
L2 := temp_L2 mod mod_10;
temp_L3 := temp_L2/div_10;
L3 := temp_L3 mod mod_10;
temp_L4 := temp_L3/div_10;
L4 := temp_L4 mod mod_10;
temp_L5 := temp_L4/div_10;
L5 := temp_L5 mod mod_10;
temp_L6 := temp_L5/div_10;
L6 := temp_L6 mod mod_10;
-- xx8374.839923 ?
report " result = " & integer'image(to_integer(L6)) &
integer'image(to_integer(L5)) &
integer'image(to_integer(L4)) &
integer'image(to_integer(L3)) &
integer'image(to_integer(L2)) &
integer'image(to_integer(L1)) &
integer'image(to_integer(L0));
report " no round = " & integer'image(to_integer(L6(4 downto 0))) &
integer'image(to_integer(L5(4 downto 0))) &
integer'image(to_integer(L4(4 downto 0))) &
integer'image(to_integer(L3(4 downto 0))) &
integer'image(to_integer(L2(4 downto 0))) &
integer'image(to_integer(L1(4 downto 0))) &
integer'image(to_integer(L0(4 downto 0)));
wait;
end process;
end architecture;
This produces the integer part result (you don't demonstrate how you did this in your question, with the new results:
...get 274334.738295 for 174334.738295
You can demonstrate that to_integer rounding is responsible for L5 being 2 instead of 1:
ghdl -a --std=08 iopertyki.vhdl
ghdl -e --std=08 iopertyki
ghdl -r iopertyki
iopertyki.vhdl:91:9:@0ms:(report note): cp = 000101010100011111110.1011110100000000111
iopertyki.vhdl:93:9:@0ms:(report note): temp_L = 00101010100011111110.0
iopertyki.vhdl:94:9:@0ms:(report note): integer'image temp_L = 174334
iopertyki.vhdl:113:9:@0ms:(report note): result = 0274334
iopertyki.vhdl:121:9:@0ms:(report note): no round = 0174334
So all this tells you to only use the integer part of L6 - L1 so there is no rounding. (There's a hint for how clipping an sfixed or ufixed value will work in David Bishop's user guide you commented on).
You could note that clipping an sfixed value will be subject to a sign bias and that you'd either need to change sign of all the recovered decimal digits or use signed magnitude (where your digit calculations might be ufixed) with the sign forwarded to the result for negative numbers. Math in decades can be cumbersome.
Notes on elaboration and simulation when using ghdl
There are three architectures of code generation for ghdl, using a GCC backend, an LLVM back end and an mcode just in time code generator.
From the newest GHDL Documentation section on Invoking GHDL for the run command:
run -r
Runs/simulates a design. The options and arguments are the same as for
the elaboration command.
- GGC/LLVM: simply, the filename of the executable is determined and it is executed. Options are ignored. You may also directly execute
the program. The executable must be in the current directory.
- mcode: the design is elaborated and the simulation is launched. As a consequence, you must use the same options used during analysis.
In an mcode version such as distributed for Win32 the -e elaborate command is redundant and the run command (-r) must include the same options as for the analysis command (-a).
For GCC/LLVM backend codegenerator versions of ghdl the elaborate (-e) command must have the same options as the analysis command (-a). For --std=08
a different working library is used and any object files produced without the std option or with a different STD value will be overwritten if the library directory is not specified separately.
There are no object files for the mcode version. The analyzed objects only exist in the ghdl program's memory where the are subsequently elaborated with the run (-r) command into a simulation design model.
Without specifying versions or release the ghdl user can only rely on ghdl documentation.
You could also note that ghdl-0.34 has been released in the last day and a Win32 binary image (mcode) and 64 bit binary image (llvm) are available (their names include "mingw").
Your divisions should be integer divisions; they are not (fixed point divisions). And I do not even imagine what the modulus operator is supposed to return when applied to non integer (fixed point) arguments. Anyway, this fixed point representation is quite simple, so, if you just want the digits of the integer part of a positive fixed point number, you could first convert it to natural, and then compute the digits:
library ieee;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;
...
variable n: natural;
subtype digit is natural range 0 to 9;
type digit_vector is array(natural range <>) of digits;
variable digits: digit_vector(5 downto 0);
...
n := to_integer(u_unsigned(cp(20 downto 0)));
for i in 0 to 5 loop
digits(i) := n mod 10;
n := n / 10;
end loop;
Or, if you simply want to print the decimal representation of cp
:
use std.textio.all;
...
variable l: line;
...
write(l, to_integer(u_unsigned(cp(20 downto 0)));
writeline(output, n);
Or, even simpler, use the write
procedure from the library itself:
variable tmp: sfixed(20 downto 0);
...
tmp := cp(20 downto 0);
write(l, tmp);
writeline(output, l);