vivado 中行为模拟与综合后功能模拟之间的不匹配

问题描述 投票:0回答:1

我正在编写一个VHDL模块,通过axi流(tdata、tvalid、tready和tlast)转换传入流,其中tdata具有8位,以便前4个字节注册在32位的输出端口A中,连续的4个字节输出到端口 B 也是 32 位。并非如此,但目标是使 A 和 B 具有有效且准备就绪的状态,以便在注册所有 4 个字节时设置有效,并保存它们的值,直到就绪为 1(表示已被以下模块或一个读取) HLS IP)。

为此,我编写了一个具有两个来回状态的状态机。我还编写了一个 vhdl 模块来从 .txt 文件读取十六进制数字并将其转换为 axi 流。

问题是综合后模拟的行为符合预期(某种程度上)。我本来预计,当 tdata 被注册时,这意味着有一个时钟周期延迟,这不在综合后模拟中,但在行为模拟中。这里有一个问题,因为在行为模拟中,A 和 B 的输出与综合后模拟中的输出不同(这是正确的。A=ddccbbaa 和 B=44332211)。

这是综合后的模拟: enter image description here

这是行为模拟: enter image description here

代码是:

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

entity a2m is
    port (
        -- AXI Stream Interface
        clk         : in std_logic;
        reset       : in std_logic;
        tdata       : in std_logic_vector(7 downto 0);
        tvalid      : in std_logic;
        tready      : out std_logic;
        tlast       : in std_logic;

        test_port : out std_logic_vector(7 downto 0);

        -- Port A and B
        A           : out std_logic_vector(31 downto 0);
        A_valid     : out std_logic;
        A_ready     : in std_logic;
        B           : out std_logic_vector(31 downto 0);
        B_valid     : out std_logic;
        B_ready     : in std_logic
    );
end a2m;

architecture fsm of a2m is

    -- State Machine States
    type state_type is (RECEIVE_A, RECEIVE_B);
    signal state : state_type := RECEIVE_A;

    signal test_port_reg : std_logic_vector(7 downto 0) := (others => '0');

    -- Internal data storage
    signal A_reg : std_logic_vector(31 downto 0) := (others => '0');

    signal B_reg : std_logic_vector(31 downto 0) := (others => '0');
    signal a_count : integer range 0 to 3 := 0;
    signal a_count_en : std_logic := '1';
    signal b_count : integer range 0 to 3 := 0;

    -- Valid signals
    signal A_valid_reg : std_logic := '0';
    signal A_ready_reg : std_logic := '0';
    signal B_valid_reg : std_logic := '0';
    signal B_ready_reg : std_logic := '0';

begin

    -- State Machine Process
    process(clk, reset)
    begin
        if rising_edge(clk) then
            if reset = '1' then
                -- Reset all registers and state machine
                state <= RECEIVE_A;
                A_reg <= (others => '0');
                B_reg <= (others => '0');
                A_valid_reg <= '0';
                B_valid_reg <= '0';
                a_count <= 0;
                b_count <= 0;
            else

                test_port_reg <= tdata;

                case state is

                    when RECEIVE_A =>
                        if tvalid = '1' then
                            case a_count is
                                when 0 =>
                                    A_reg(7 downto 0) <= tdata;
                                when 1 =>
                                    A_reg(15 downto 8) <= tdata;
                                when 2 =>
                                    A_reg(23 downto 16) <= tdata;
                                when 3 =>
                                    A_reg(31 downto 24) <= tdata;
                                    A_valid_reg <= '1';  -- All 4 bytes for A received
                                when others =>
                                    null;
                            end case;
                            if(a_count<3) then
                                a_count <= a_count + 1;
                            end if;
                        end if;

                        -- Hold until A_ready is asserted
                        if A_valid_reg = '1' and A_ready = '1' then
                            A_valid_reg <= '0';  -- Clear A_valid when ready is high
                            a_count <= 0;     -- Reset a_count for B reception
                            state <= RECEIVE_B;  -- Move to receive B
                        end if;

                    when RECEIVE_B =>
                        if tvalid = '1' then
                            case b_count is
                                when 0 =>
                                    B_reg(7 downto 0) <= tdata;
                                when 1 =>
                                    B_reg(15 downto 8) <= tdata;
                                when 2 =>
                                    B_reg(23 downto 16) <= tdata;
                                when 3 =>
                                    B_reg(31 downto 24) <= tdata;
                                    B_valid_reg <= '1';  -- All 4 bytes for B received
                                when others =>
                                    null;
                            end case;
                            if(b_count<3) then
                                b_count <= b_count + 1;
                            end if;
                        end if;

                        -- Hold until B_ready is asserted
                        if B_valid_reg = '1' and B_ready = '1' then
                            B_valid_reg <= '0';  -- Clear B_valid when ready is high
                            b_count <= 0;
                            state <= RECEIVE_A;       -- Return to RECEIVE_A for the next frame
                        end if;

                end case;
            end if;
        end if;
    end process;

    -- Output assignments
    A <= A_reg;
    A_valid <= A_valid_reg;
    B <= B_reg;
    B_valid <= B_valid_reg;
    test_port <= test_port_reg;

    -- tready logic: Assert when the state machine is ready to accept data
    tready <= '1' when ((state = RECEIVE_A and a_count < 4 and A_valid_reg='0') or (state = RECEIVE_B and b_count < 4 and B_valid_reg='0')) else
            '0';

end architecture;

文件阅读器:

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
use STD.TEXTIO.all;
use IEEE.std_logic_textio.all;

entity file_to_axi_stream is
    port (
        clk : in std_logic;
        rst : in std_logic;
        -- AXI Stream output interface
        m_axis_tdata : out std_logic_vector(7 downto 0);
        m_axis_tvalid : out std_logic;
        m_axis_tready : in std_logic;
        m_axis_tlast : out std_logic
    );
end file_to_axi_stream;

architecture Behavioral of file_to_axi_stream is

    signal valid : std_logic := '0';
    signal last : std_logic := '0';
    signal s_tdata : std_logic_vector(7 downto 0) := (others=>'0');
    signal file_opened : boolean := true;
    signal total_length : std_logic_vector(31 downto 0) := (others=>'0');
    file input_file : text;

    -- TODO read same file N times

begin
    file_open(input_file, "/tmp/stimulus_input.txt", read_mode);

    process (clk, rst)
        variable row_input : line;
        variable v_number : std_logic_vector(7 downto 0);
        variable count : integer := 0; -- Used variable to count the first 4 bytes (for total length)
    begin
        if (rising_edge(clk)) then
            if (rst = '1') then
                valid <= '0';
                last <= '0';
            else
                last <= '0';
                valid <= '1';
                if(file_opened=true) then
                    if(count=(to_integer(unsigned(total_length))+4)) then
                        last <= '1';
                        file_opened <= false;
                    else
                        if(m_axis_tready='1') then
                            readline(input_file, row_input);
                            hread(row_input, v_number);
                            s_tdata <= v_number;
                            if(count<4) then
                                total_length(count*8+7 downto count*8) <= v_number;
                            end if;
                            count := count + 1;
                        end if;
                    end if;
                else
                    valid <= '0';
                    last <= '0';
                    s_tdata <= (others=>'0');
                end if;
            end if;
        end if;
    end process;

    m_axis_tvalid <= valid;
    m_axis_tdata <= s_tdata;
    m_axis_tlast <= last;

end Behavioral;

测试台:

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

entity tb_a2m is
end tb_a2m;

architecture sim of tb_a2m is

    -- Signals to connect to the DUT
    signal clk       : std_logic := '0';
    signal reset     : std_logic := '0';
    signal tdata     : std_logic_vector(7 downto 0) := (others => '0');
    signal tvalid    : std_logic := '0';
    signal tready    : std_logic;
    signal tlast     : std_logic := '0';

    signal test_port : std_logic_vector(7 downto 0) := (others => '0');
    
    signal A         : std_logic_vector(31 downto 0);
    signal A_valid   : std_logic;
    signal A_ready   : std_logic := '0';
    signal B         : std_logic_vector(31 downto 0);
    signal B_valid   : std_logic;
    signal B_ready   : std_logic := '0';

    -- Clock period definition
    constant clk_period : time := 10 ns;

    component file_to_axi_stream
        port (
            clk : in std_logic;
            rst : in std_logic;
            -- AXI Stream output interface
            m_axis_tdata : out std_logic_vector(7 downto 0);
            m_axis_tvalid : out std_logic;
            m_axis_tready : in std_logic;
            m_axis_tlast : out std_logic
        );
    end component;

begin

    -- DUT Instantiation
    uut: entity work.a2m
        port map (
            clk     => clk,
            reset   => reset,
            tdata   => tdata,
            tvalid  => tvalid,
            tready  => tready,
            tlast   => tlast,
            test_port => test_port,
            A       => A,
            A_valid => A_valid,
            A_ready => A_ready,
            B       => B,
            B_valid => B_valid,
            B_ready => B_ready
        );

    -- Clock generation
    clk_process : process
    begin
        clk <= '1';
        wait for clk_period/2;
        clk <= '0';
        wait for clk_period/2;
    end process;


    file_reader : file_to_axi_stream port map(
        clk => clk,
        rst => reset,
        m_axis_tdata => tdata,
        m_axis_tvalid => tvalid,
        m_axis_tready => tready,
        m_axis_tlast => tlast
    );

    -- Stimulus process
    stim_proc: process
    begin
        -- Initialize
        reset <= '1';
        wait for 2*clk_period;
        reset <= '0';

        wait for 6*clk_period;
        A_ready <= '1';
        wait for 1*clk_period;
        A_ready <= '0';

        wait for 10*clk_period;
        B_ready <= '1';
        wait for 1*clk_period;
        B_ready <= '0';

        wait;
    end process;

end architecture;

忽略要读取并转换为 axi 流的文件读取前 4 个字节以获取文件中总共有多少字节。

要测试的文件如下所示:

AA
BB
CC
DD
11
22
33
44
AA
BB
CC
DD
11
22
33
44

我正在 ubuntu 22.04 下使用 vivado 2024.1 进行测试。

任何帮助将不胜感激。

vhdl fpga vivado synthesis
1个回答
0
投票

在两个模拟中,异步重置的处理方式不同。它恰好在时钟边沿处变低,在一种情况下被识别为时钟边沿之前,在另一种情况下被识别为在时钟边沿之后。尝试在时钟周期中间取消断言它。

© www.soinside.com 2019 - 2024. All rights reserved.