Krzysztof B
Krzysztof B

Reputation: 1

VHDL - synthesis results is not the same as behavioral

I have to write program in VHDL which calculate sqrt using Newton method. I wrote the code which seems to me to be ok but it does not work. Behavioral simulation gives proper output value but post synthesis (and launched on hardware) not. Program was implemented as state machine. Input value is an integer (used format is std_logic_vector), and output is fixed point (for calculation purposes input value was multiplied by 64^2 so output value has 6 LSB bits are fractional part).
I used function to divide in vhdl from vhdlguru blogspot. In behavioral simulation calculating sqrt takes about 350 ns (Tclk=10 ns) but in post synthesis only 50 ns.

Used code:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

        entity moore_sqrt is
port (clk : in std_logic;
      enable : in std_logic;
      input : in std_logic_vector (15 downto 0);
      data_ready : out std_logic;
      output : out std_logic_vector (31 downto 0)
  );
end moore_sqrt;

architecture behavioral of moore_sqrt is
------------------------------------------------------------
function  division  (x : std_logic_vector; y : std_logic_vector) return std_logic_vector is
variable a1 : std_logic_vector(x'length-1 downto 0):=x;
variable b1 : std_logic_vector(y'length-1 downto 0):=y;
variable p1 : std_logic_vector(y'length downto 0):= (others => '0');
variable i : integer:=0;
    begin
        for i in 0 to y'length-1 loop
            p1(y'length-1 downto 1) := p1(y'length-2 downto 0);
            p1(0) := a1(x'length-1);
            a1(x'length-1 downto 1) := a1(x'length-2 downto 0);
            p1 := p1-b1;
            if(p1(y'length-1) ='1') then
                a1(0) :='0';
                p1 := p1+b1;
            else
                a1(0) :='1';
            end if;
        end loop;
return a1;
end division;
-------------------------------------------------------------- 
type state_type is (s0, s1, s2, s3, s4, s5, s6);  --type of state machine
signal current_state,next_state: state_type;  --current and next state declaration

signal xk : std_logic_vector (31 downto 0);
signal temp : std_logic_vector (31 downto 0);
signal latched_input : std_logic_vector (15 downto 0);
signal iterations : integer := 0;
signal max_iterations : integer := 10;  --corresponds with accuracy

begin

process (clk,enable)
begin
if enable = '0' then
    current_state <= s0; 
elsif clk'event and clk = '1' then
    current_state <= next_state;   --state change
end if;
end process;

--state machine
process (current_state)
begin
  case current_state is
    when s0 =>          -- reset       
        output <= "00000000000000000000000000000000";
        data_ready <= '0';
        next_state <= s1;
    when s1 =>          -- latching input data
        latched_input <= input;
        next_state <= s2;        
     when s2 =>         -- start calculating
        -- initial value is set as a half of input data
        output <= "00000000000000000000000000000000";
        data_ready <= '0';
        xk <= "0000000000000000" & division(latched_input, "0000000000000010");
        next_state <= s3;
        iterations <= 0;
    when s3 =>         -- division
        temp <= division ("0000" & latched_input & "000000000000", xk);
        next_state <= s4;
    when s4 =>          -- calculating 
        if(iterations < max_iterations) then
            xk <= xk + temp;
            next_state <= s5;
            iterations <= iterations + 1;
        else
            next_state <= s6;
        end if;
    when s5 =>          -- shift logic right by 1
            xk <= division(xk, "00000000000000000000000000000010");
            next_state <= s3;       
    when s6 =>             -- stop - proper data
--          output <= division(xk, "00000000000000000000000001000000");  --the nearest integer value
            output <= xk;    -- fixed point 24.6, sqrt = output/64;
            data_ready <= '1';
    end case;
end process;
end behavioral;

Below screenshoots of behavioral and post-sythesis simulation results:

Behavioral simulation

Post-synthesis simulation

I have only little experience with VHDL and I have no idea what can I do to fix problem. I tried to exclude other process which was for calculation but it also did not work.

I hope you can help me. Platform: Zynq ZedBoard IDE: Vivado 2014.4

Regards, Michal

Upvotes: 0

Views: 1400

Answers (3)

user1818839
user1818839

Reputation:

A lot of the problems can be eliminated if you rewrite the state machine in single process form, in a pattern similar to this. That will eliminate both the unwanted latches, and the simulation /synthesis mismatches arising from sensitivity list errors.

I believe you are also going to have to rewrite the division function with its loop in the form of a state machine - either a separate state machine, handshaking with the main one to start a divide and signal its completion, or as part of a single hierarchical state machine as described in this Q&A.

Upvotes: 2

bogl
bogl

Reputation: 1863

VHDL code may by synthesizable or not, and the synthesis result may behave as the simulation, or not. This depends on the code, the synthesizer, and the target platform, and is very normal.

Behavioral code is good for test-benches, but - in general - cannot be synthesized.

Here I see the most obvious issue with your code:

process (current_state)
begin
[...]
             iterations <= iterations + 1;
[...]
end process;

You are iterating over a signal which does not appear in the sensitivity list of the process. This might be ok for the simulator which executes the process blocks just like software. On the other hand side, the synthesis result is totally unpredictable. But adding iterations to the sensitivity list is not enough. You would just end up with an asynchronous design. Your target platform is a clocked device. State changes may only occur at the trigger edge of the clock. You need to tell the synthesizer how to map the iterations required to perform this calculation over the clock cycles. The safest way to do that is to break down the behavioural code into RTL code (https://en.wikipedia.org/wiki/Register-transfer_level#RTL_in_the_circuit_design_cycle).

Upvotes: 1

Paebbels
Paebbels

Reputation: 16211

This code is neither correct for simulation nor for synthesis.

Simulation issues:

  • Your sensitivity list is not complete, so the simulation does not show the correct behavior of the synthesized hardware. All right-hand-side signals should be include if the process is not clocked.

Synthesis issues:

  • Your code produces masses of latches. There is only one register called current_state. Latches should be avoided unless you know exactly what you are doing.
  • You can't divide numbers in the way you are using the function, if you want to keep a proper frequency of your circuit.
    => So check your Fmax report and
    => the RTL schematic or synthesis report for resource utilization.
  • Don't use the devision to shift bits. Neither in software the compiler implements a division if a value is shifted by a power of two. Us a shift operation to shift a value.

Other things to rethink:

  • enable is a low active asynchronous reset. Synchronous resets are better for FPGA implementations.

Upvotes: 1

Related Questions