Why Does This VHDL Work in Sumulation and Does not Work on the Virtex 5 Device

StackOverflow https://stackoverflow.com/questions/20386979

  •  29-08-2022
  •  | 
  •  

Вопрос

I have spent the whole day trying to solve the following problem. I am building a small averaging multichannel oscilloscope and I have the following module for storing the signal:


library IEEE;

use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.numeric_std.all;

entity storage is
    port
    (
        clk_in                           : in  std_logic;
        reset                            : in  std_logic;
        element_in                       : in  std_logic;
        data_in                          : in  std_logic_vector(11 downto 0);
        addr                             : in  std_logic_vector(9 downto 0);
        add                              : in  std_logic; -- add = '1' means add to RAM
                                                          -- add = '0' means write to RAM
        dump                             : in  std_logic;
        element_out                      : out std_logic;
        data_out                         : out std_logic_vector(31 downto 0)
    );
end storage;

architecture rtl of storage is
    component bram is
    port
    (
        clk                              : in  std_logic;
        we                               : in  std_logic;
        en                               : in  std_logic;
        addr                             : in  std_logic_vector(9 downto 0);
        di                               : in  std_logic_vector(31 downto 0);
        do                               : out std_logic_vector(31 downto 0)
    );
    end component bram;

    type state is (st_startwait, st_add, st_write);

    signal current_state                 : state := st_startwait;
    signal next_state                    : state := st_startwait;

    signal start                         : std_logic;

    signal we                            : std_logic;
    signal en                            : std_logic;
    signal di                            : std_logic_vector(31 downto 0);
    signal do                            : std_logic_vector(31 downto 0);

    signal data                          : std_logic_vector(11 downto 0);
begin
    ram : bram port map
    (
        clk  => clk_in,
        we   => we,
        en   => en,
        addr => addr,
        di   => di,
        do   => do  
    );

    process(clk_in, reset, start)
    begin
        if rising_edge(clk_in) then
            if (reset = '1') then
                current_state           <= st_startwait;
            else
                start                   <= '0';
                current_state           <= next_state;

                if (element_in = '1') then
                    start               <= '1';
                end if;
            end if;
        end if;
    end process;

    process(current_state, start, dump)
        variable acc                    : std_logic_vector(31 downto 0);
    begin
        element_out                       <= '0';

        en                                <= '1';
        we                                <= '0';

        case current_state is
            when st_startwait =>          
                if (start = '1') then
                    acc(11 downto 0)    := data_in;
                    acc(31 downto 12)   := (others => '0');

                    next_state          <= st_add;
                else
                    next_state          <= st_startwait;
                end if;
            when st_add =>
                if (add = '1') then
                    acc                 := acc + do;
                end if;

                we                      <= '1';
                di                      <= acc;

                next_state              <= st_write;
            when st_write =>      
                if (dump = '1') then
                    data_out            <= acc;
                    element_out         <= '1';
                end if;

                next_state              <= st_startwait;
        end case;
    end process;  
end rtl;

Below is the BRAM module as copied from the XST manual. This is a no-change type of BRAM and I believe there is the problem. The symptom is that, while this simulates fine, I read only zeroes from the memory when I use the design on the device.


library IEEE;

use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;

entity bram is
    port
    (
        clk  : in  std_logic;
        we   : in  std_logic;
        en   : in  std_logic;
        addr : in  std_logic_vector(9 downto 0);
        di   : in  std_logic_vector(31 downto 0);
        do   : out std_logic_vector(31 downto 0)
    );
end bram;

architecture rtl of bram is
    type ram_type is array (0 to 999) of std_logic_vector (31 downto 0);
    signal buf : ram_type;
begin
    process(clk, en, we)
    begin
        if rising_edge(clk) then
            if en = '1' then
                if we = '1' then
                    buf(conv_integer(addr)) <= di;
                else
                    do <= buf(conv_integer(addr));
                end if;
            end if;
        end if;
    end process;
end rtl;

What follows is a description of the chip use and the expected output. "clk_in" is a 50 MHz clock. "element_in" is '1' for 20 ns and '0' for 60 ns. "addr_in" iterates from 0 to 999 and changes every 80 ns. "element_in", "data_in", and "addr" are all aligned and synchronous. Now "add" is '1' for 1000 elements, then both "add" and "dump" are zero for 8000 elements and, finally "dump" is '1' for 1000 elements. Now, if I have a test bench that supplies "data_in" from 0 to 999, I expect data_out to be 0, 10, 20, 30, ..., 9990 when "dump" is '1'. That is according to the simulation. In reality I get 0, 1, 2, 3, ..., 999....

Это было полезно?

Решение

Some initial issues to address are listed below.


The process(current_state, start, dump) in storage entity looks like it is intended to implement a combinatorial element (gates), but the signal (port) data_in is not in the sensitivity list.

This is very likely to cause a difference between simulation and synthesis behavior, since simulation will typically only react to the signals in the sensitivity list, where synthesis will implement the combinatorial design and react on all used signals, but may give a warning about incomplete sensitivity list or inferred latches. If you are using VHDL-2008 then use can use a sensitivity list of (all) to have the process sensitivity to all used signals, and otherwise you need to add missing signals manually.


The case current_state is in process(current_state, start, dump) lacks an when others => ..., so the synthesis tool has probably given you a warning about inferred latches. This should be fixed by adding the when others => with and assign all signals driven by the process to the relevant value.


The use clause lists:

use IEEE.std_logic_unsigned.all;
use IEEE.numeric_std.all;

But both of these should not be used at the same time, since they declare some of the same identifiers, for example is unsigned declared in both. Since the RAM uses std_logic_unsigned I suggest that you stick with that only, and delete use of numeric_std. For new code I would though recommend use of numeric_std.


Also the process(clk_in, reset, start) in storage entity implements a sequential element (flip flop) sensitive to only rising edge of clk_in, so the two last signals in sensitivity list ..., reset, start) are unnecessary, but does not cause a problem.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top