0
\$\begingroup\$

The following code is an attempt to implement the responses given in this post, a program that takes in its entry a real number coded in 2's complement in a 16 bit std logic vector (the integer part starts from index 15 down to 6, i.e., 10 bits for the integral and 6 bit for the fractional part). At the output where are going to have the same real number represented in the IEEE 754 single precision format.

Here is a schematic summarizing the above

enter image description here

The VHDL code I used to try to implement the circuit is

entity fixed_to_float is
    Port ( fixed_input : in  STD_LOGIC_VECTOR (15 downto 0);
            float_out :out std_logic_vector(31 downto 0);
                j:out std_logic_vector(4 downto 0);
              clk:in std_logic);
end fixed_to_float;



architecture behavioral of fixed_to_float is

signal x:std_logic_vector(15 downto 0);
signal k:integer:=15;
signal i:integer;

signal sign:std_logic;
signal exponent:std_logic_vector(7 downto 0);
signal mantissa:std_logic_vector(22 downto 0):="00000000000000000000000";

  begin


process (clk) begin

  if fixed_input(15)='1' then
    x<= not (fixed_input)+1;
  else 
  x<= fixed_input;
  end if;

  for i in 15 downto 0 loop

     if( x(i)='1') then
             k<=i;
             exit;
     end if;

 end loop;
      mantissa <=(others=>'0');
      mantissa(22 downto 22-k+1)<= x(k-1 downto 0);
end process;


j<=std_logic_vector(to_unsigned(k,5));

sign<= fixed_input(15);





exponent<= std_logic_vector(to_unsigned(127+k-6,8));

float_out <= sign & exponent & mantissa;


end architecture;

The code, first, locates the index of the first non-zero bit of the 2's complement of the input vector, \$x\$, going down from the 15th position. Everything that's after this index, named \$ k\$ in the code, i.e., everything from \$k\$ down to 0 in the input vector is the mantissa. And the exponent is how far \$ k\$ is from the bit at the 6th position, where the integer part starts. Both the compilation and the synthesis worked fine, no warnings whatsoever. When I tried to run a waveform simulation to try and test some values, the waveform window essentially gets stuck, it doesn't show anything and the simulation keeps running endlessly. Any hints as to why the simulation wouldn't work?

EDIT: The use of a for loop instead of a while has indeed solved the problem. I ran a simple test bench to see how the code behaves, I've inputted "0000000001000000" , 1 in decimal; the output was "0 01111111 00000000100000000000000 ", both the sign bit and the exponent have the correct values, only the mantissa seems to be incorrect, it should be all zeros. I cannot really fathom why did this '1' appear in the mantissa, especially with regard to its position

EDIT2: Setting the mantissa's value to zero inside the process in conjunction with moving the assignment of the upper part of the mantissa (please see the edit) inside the process has solved the problem, I can't see why putting these two assignments inside the process, as opposed to outside, can have any effect on the output.

\$\endgroup\$
  • \$\begingroup\$ I don’t see what is synthesized- this looks like a behavioral (simulation) model. Can you check what RTL code (Register Transfer Logic) was actually synthesized? My guess is that the code didn’t infer any real implementation, so the waveform simulator has nothing to do. \$\endgroup\$ – MarkU Sep 17 at 0:09
  • \$\begingroup\$ What simulator are you using? \$\endgroup\$ – Dave Tweed Sep 17 at 1:00
  • \$\begingroup\$ Sorry for the late reply, I am using Modelsim. \$\endgroup\$ – Hilbert Sep 17 at 8:54
  • 1
    \$\begingroup\$ Signals are updated at the beginning of a simulation cycle before any process resumes. Your simulation hangs in the while loop depending on signal k being updated before evaluating the next element of fixed_input. The while loop can't exit and the process can't suspend. Use a loop statement with a for iteration schem and assign k when exiting after evaluating the condition. There appear to be other things wrong, e.g. You're not using the absolute value of fixed_input for signed magnitude representation. You should evaluate a clock edge for synthesis. \$\endgroup\$ – user8352 Sep 17 at 12:31
  • \$\begingroup\$ After editing the code using the suggestions, I ran a simple test bench to see how the code behaves, I've inputted "0000000001000000" , 1 in decimal; the output was "0 01111111 00000000100000000000000 ", both the sign bit and the exponent have the correct values, only the mantissa seems to be incorrect, it should be all zeros. I cannot really fathom why did this '1' appear in the mantissa, especially with regard to its position. \$\endgroup\$ – Hilbert Sep 17 at 19:04
1
\$\begingroup\$

Using a -2008 compatible implementation using IEEE packages fixed_pkg and float_pkg as a reference, your algorithm was independently implemented using the accepted answer in your previous question to author architecture fixed_to_float(algo). The algo architecture and entity fixed_to_float can be analyzed and elaborated (compiled) using tools compliant with earlier revisions of the VHDL standard than -2008 for synthesis.

Both architectures have the same stimuli applied and their results can be compared (here visually using a -2008 compliant simulator):

library ieee;
use ieee.std_logic_1164.all;

entity fixed_to_float is
    port ( 
        fixed_input:    in  std_logic_vector (15 downto 0);
        float_out:      out std_logic_vector(31 downto 0);
        clk:            in  std_logic
    );
end entity fixed_to_float;

architecture ref of fixed_to_float is
    use ieee.fixed_pkg.all;   
    use ieee.float_pkg.all;
    use ieee.fixed_float_types.all;  -- rounding style

    function slv_to_float32(input:  std_logic_vector) return std_logic_vector is
    begin
        return to_slv(to_float(to_sfixed(input, 9, -6), 8, 23, round_zero));
    end function;
begin
    process (clk) 
    begin
        if rising_edge(clk) then
            float_out <= slv_to_float32(fixed_input);
        end if;
    end process;
end architecture ref;

architecture algo of fixed_to_float is
    use ieee.numeric_std.all;
    function slv_to_float32 (
        input:  std_logic_vector (15 downto 0)
    ) 
    return std_logic_vector is
        variable sinp:      std_logic_vector (input'range) :=
                                std_logic_vector(abs(signed(input)));
        constant sign:      std_logic := input(input'left);
        variable mantissa:  std_logic_vector (22 downto 0) := (others => '0');
        variable exponent:  std_logic_vector (7 downto 0);
        variable k:         integer range input'range;
        constant bias:      integer := 6; -- rightmost integer bit
    begin
        for i in input'left downto 0 loop  -- find left most '1' bit
            if sinp(i) = '1' then
                k := i - 1;   -- don't include  left most '1'
                exit;
            end if;
        end loop;
        -- shifter
        mantissa (mantissa'left downto mantissa'left - k) := sinp(k downto 0);
        -- exponent
        exponent := std_logic_vector (to_signed(k - bias, exponent'length));
        exponent(exponent'left) := not exponent(exponent'left);
        return sign & exponent & mantissa;  -- 32 bits
    end function;
begin
    process (clk) 
    begin
        if rising_edge(clk) then
            float_out <= slv_to_float32(fixed_input);
        end if;
    end process;
end architecture algo;


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

entity fixed_to_float_tb is
end entity;

architecture foo of fixed_to_float_tb is
    signal fixed_input: std_logic_vector (15 downto 0);
    signal float_out:   std_logic_vector(31 downto 0);
    signal rfloat_out:  std_logic_vector(31 downto 0);
    signal clk:         std_logic := '0';

begin
DUT:
    entity work.fixed_to_float (algo)
        port map (
            fixed_input => fixed_input,
            float_out   => float_out,
            clk         => clk
        );
REFIMPL:
    entity work.fixed_to_float (ref)
        port map (
            fixed_input => fixed_input,
            float_out   => rfloat_out,
            clk         => clk
        );
CLOCK:
    process
    begin
        wait for 15 ns;
        clk <= not clk;
        if now > 75 ns then
            wait;
        end if;
    end process;
STIMULUS:
    process
    begin
        fixed_input <= "0011000011101001";
        wait for 30 ns;
        fixed_input <= "0000000000101001";
        wait for 30 ns;
        fixed_input <= "0000000001000000";
        wait;
    end process;
INPUT:
    process
    begin
        wait on fixed_input;
        wait for 0 ns;
        report "fixed_input = " & to_string(fixed_input);
    end process;
RESULT:
    process
    begin
        wait on float_out;
        report "float_out  =" & LF & 
            to_string(std_logic_vector'("" & float_out(31)))  & -- sign
            ':' & to_string(float_out(30 downto 23)) &     -- exponent
            ':' & to_string(float_out(22 downto 0));       -- mantissa
    end process;
REFERENCE:
    process
    begin
        wait on float_out;
        report "rfloat_out =" & LF & 
            to_string(std_logic_vector'("" & rfloat_out(31)))  & -- sign
            ':' & to_string(rfloat_out(30 downto 23)) &     -- exponent
            ':' & to_string(rfloat_out(22 downto 0));       -- mantissa
    end process;
end architecture;

This results in:

/usr/local/bin/ghdl -a  --std=08 fixed_to_float.vhdl
/usr/local/bin/ghdl -e  --std=08 fixed_to_float_tb
/usr/local/bin/ghdl -r --std=08 fixed_to_float_tb
fixed_to_float.vhdl:119:9:@0ms:(report note): fixed_input = 0011000011101001
fixed_to_float.vhdl:134:9:@15ns:(report note): rfloat_out =
0:10000110:10000111010010000000000
fixed_to_float.vhdl:125:9:@15ns:(report note): float_out  =
0:10000110:10000111010010000000000
fixed_to_float.vhdl:119:9:@30ns:(report note): fixed_input = 0000000000101001
fixed_to_float.vhdl:125:9:@45ns:(report note): float_out  =
0:01111110:01001000000000000000000
fixed_to_float.vhdl:134:9:@45ns:(report note): rfloat_out =
0:01111110:01001000000000000000000
fixed_to_float.vhdl:119:9:@60ns:(report note): fixed_input = 0000000001000000
fixed_to_float.vhdl:134:9:@75ns:(report note): rfloat_out =
0:01111111:00000000000000000000000
fixed_to_float.vhdl:125:9:@75ns:(report note): float_out  =
0:01111111:00000000000000000000000

where we see for the test inputs the reference output and result are identical.

Note the order processes are resumed isn't guaranteed in VHDL and shows in the order of the the reference output and result report statements. There's a ':' field separator in the string representation of the float values so the exponent and mantissa boundaries are easy to see.

The idea is that if a reference implementation can be trusted you can use the reference output in validating the implementation using the previous question's accepted answer. It'd be easy enough to add more test cases.

You could also compare the reference output and result in a process and track errors.

Yes, the accepted answer to your previous question didn't 'teach' an implementation, it was 'indefinite' to borrow terminology from patent practitioners. In all fairness IEEE Std 754 is needed as a reference or studying an implementation you're sure works. It's quite laborious to read through the IEEE float_pkg package used to understand floating point without referencing the standard.

From scratch you could also write a C implementation where a 32 bit float value could be assigned real literal values representing fixed_input and have those and the long equivalent value of a 32 bit float output. Potentially using those values as a reference and literal values cast as 10.6 std_logic_vector values as inputs in a testbench using textio. In general you can trust a C compiler sooner than VHDL packages you don't understand.

The amount of effort for this answer is incremental over the effort for the answer to the previous question, done to learn how solve the problem using IEEE packages fixed_pkg and float_pkg (conversion routines to_sfixed and to_float).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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