Aplicación de búfer de rendimiento Boost [Xillybus - VHDL]

0

En esta pregunta anterior link He desarrollado una aplicación que secuencialmente lo hizo:

  1. obtenga y almacene 8 valores de entrada (8 caracteres)
  2. alternar entre mayúsculas y minúsculas (o viceversa) solo el primer carácter
  3. saca los ocho caracteres

El problema es que es demasiado lento y tengo que acelerar el tiempo total de ejecución. Supongo que el problema es que la aplicación realiza los puntos 1, 2 y 3 de forma secuencial. Para mejorar el rendimiento, supongo que debo paralelizar la operación de escritura y lectura.

USO DE 2 FIFOs versión 2: como se sugiere en el comentario, tengo que implementar 2 FIFOs. Si mi entendimiento es correcto, el primer FIFO se usa para escribir datos de PCI a FIFO y el segundo FIFO se usa para copiar datos de FPGA a PCI. Por lo tanto, la aplicación debe realizar los siguientes pasos:

  • tan pronto como los datos estén en write_device_file, almacénelos en STD_FIFO_WRITE
  • alternar entre mayúsculas y minúsculas (o viceversa) solo el primer carácter
  • tan pronto como los datos estén listos, escríbalos en STD_FIFO_READ

Como solución a este problema, utilicé el FIFO de este enlace . Aquí el código (STD_FIFO.vhd):

library IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;

entity STD_FIFO is
Generic (
    constant DATA_WIDTH  : positive := 8;
    constant FIFO_DEPTH : positive := 256
);
Port ( 
    CLK     : in  STD_LOGIC;
    RST     : in  STD_LOGIC;
    WriteEn : in  STD_LOGIC;
    DataIn  : in  STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
    ReadEn  : in  STD_LOGIC;
    DataOut : out STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
    Empty   : out STD_LOGIC;
    Full    : out STD_LOGIC
);
end STD_FIFO;

architecture Behavioral of STD_FIFO is

begin

-- Memory Pointer Process
fifo_proc : process (CLK)
    type FIFO_Memory is array (0 to FIFO_DEPTH - 1) of STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
    variable Memory : FIFO_Memory;

    variable Head : natural range 0 to FIFO_DEPTH - 1;
    variable Tail : natural range 0 to FIFO_DEPTH - 1;

    variable Looped : boolean;
begin
    if rising_edge(CLK) then
        if RST = '1' then
            Head := 0;
            Tail := 0;

            Looped := false;

            Full  <= '0';
            Empty <= '1';
        else
            if (ReadEn = '1') then
                if ((Looped = true) or (Head /= Tail)) then
                    -- Update data output
                    DataOut <= Memory(Tail);

                    -- Update Tail pointer as needed
                    if (Tail = FIFO_DEPTH - 1) then
                        Tail := 0;

                        Looped := false;
                    else
                        Tail := Tail + 1;
                    end if;


                end if;
            end if;

            if (WriteEn = '1') then
                if ((Looped = false) or (Head /= Tail)) then
                    -- Write Data to Memory
                    Memory(Head) := DataIn;

                    -- Increment Head pointer as needed
                    if (Head = FIFO_DEPTH - 1) then
                        Head := 0;

                        Looped := true;
                    else
                        Head := Head + 1;
                    end if;
                end if;
            end if;

            -- Update Empty and Full flags
            if (Head = Tail) then
                if Looped then
                    Full <= '1';
                else
                    Empty <= '1';
                end if;
            else
                Empty   <= '0';
                Full    <= '0';
            end if;
        end if;
    end if;
end process;

end Behavioral;

En este enlace entendí que no es posible conectar los FIFO de esta manera: Debidoaunposibleproblemademecanismodeapretóndemanos.Comosoluciónalternativa,elenlaceanteriorproporcionaelcódigoVHDLparaconvertirunFIFOestándardedoblepuertoenunFIFOautónomodedoblepuerto:

El código VHDL del FIFO de puerto dual en cascada autónomo es ac_fifo_wrap.vhd (en el que ya he incluido el STD_FIFO ):

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;

ENTITY ac_fifo_wrap IS
GENERIC(
      --== Data Width ==--
      data_width : NATURAL := 8
     );
  PORT(
   --==  General Interface ==--
   rst    : IN  STD_LOGIC;
   clk    : IN  STD_LOGIC;

   --== Input Interface ==--
   nwrite : IN  STD_LOGIC;
   full   : OUT STD_LOGIC;
   din    : IN  STD_LOGIC_VECTOR(data_width-1 DOWNTO 0);

   --== Output Interface ==--
   empty  : OUT STD_LOGIC;
   nread  : IN  STD_LOGIC;
   dout   : OUT STD_LOGIC_VECTOR(data_width-1 DOWNTO 0)
  );
END ac_fifo_wrap;


ARCHITECTURE rtl OF ac_fifo_wrap IS

---==========================---
--== Component Declarations ==--
---==========================---


component STD_FIFO
port (
  CLK: IN std_logic;
  RST: IN std_logic;
  WriteEn: IN std_logic;
  DataIn: IN std_logic_VECTOR(7 downto 0);
  ReadEn: IN std_logic;
  DataOut: OUT std_logic_VECTOR(7 downto 0);
  Empty: OUT std_logic;
  Full: OUT std_logic
);
end component;

---=======================---
--== Signal Declarations ==--
---=======================---

SIGNAL empty_int : STD_LOGIC;
SIGNAL empty_i   : STD_LOGIC;
SIGNAL full_i    : STD_LOGIC;
SIGNAL rd_en     : STD_LOGIC;
SIGNAL wr_en     : STD_LOGIC;

BEGIN

  ---====================---
  --== FIFO write logic ==--
  ---====================---

  wr_en <= NOT(full_i) AND NOT(nwrite);

  full <= full_i;

  ---================================---
  --== STD_FIFO (CoreGen Module) ==--
  ---================================---

  -- CPU to FPGA FIFO
  U0: STD_FIFO
  port map(
    RST       => rst,
    CLK       => clk,
    WriteEn    => wr_en,
    Full      => full_i,
    DataIn       => din,
    Empty     => empty_int,
    ReadEn     => rd_en,
    DataOut      => dout
  );


  ---===================---
  --== FIFO read logic ==--
  ---===================---

  rd_en <= NOT(empty_int) AND (empty_i OR NOT(nread));

  PROCESS(clk)
  BEGIN
IF RISING_EDGE(clk) THEN
  IF (rst = '1') THEN
    empty_i <= '1';
  ELSE
    empty_i <= empty_int AND (empty_i OR NOT(nread));
  END IF;
END IF;
  END PROCESS;

  empty <= empty_i;

END rtl;

Lo que he hecho:

en ac_fifo_wrap He definido el componente STD_FIFO . De esta manera conecté el FIFO de puerto dual en cascada autónomo ( ac_fifo_wrap ) con el FIFO de puerto dual ( STD_FIFO ).

En xillydemo.vhd definí 2 ac_fifo_wrap, ac_fifo_wrap_write y ac_fifo_wrap_read respectivamente. De esta manera, tengo 2 FIFO conectados y no debería tener problemas con el protocolo de enlace. Aquí xillydemo.vhd :

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

entity xillydemo is
  port (
PCIE_PERST_B_LS : IN std_logic;
PCIE_REFCLK_N : IN std_logic;
PCIE_REFCLK_P : IN std_logic;
PCIE_RX_N : IN std_logic_vector(3 DOWNTO 0);
PCIE_RX_P : IN std_logic_vector(3 DOWNTO 0);
GPIO_LED : OUT std_logic_vector(3 DOWNTO 0);
PCIE_TX_N : OUT std_logic_vector(3 DOWNTO 0);
PCIE_TX_P : OUT std_logic_vector(3 DOWNTO 0));
end xillydemo;

architecture sample_arch of xillydemo is
  component xillybus
port (
  PCIE_PERST_B_LS : IN std_logic;
  PCIE_REFCLK_N : IN std_logic;
  PCIE_REFCLK_P : IN std_logic;
  PCIE_RX_N : IN std_logic_vector(3 DOWNTO 0);
  PCIE_RX_P : IN std_logic_vector(3 DOWNTO 0);
  GPIO_LED : OUT std_logic_vector(3 DOWNTO 0);
  PCIE_TX_N : OUT std_logic_vector(3 DOWNTO 0);
  PCIE_TX_P : OUT std_logic_vector(3 DOWNTO 0);
  bus_clk : OUT std_logic;
  quiesce : OUT std_logic;

  user_r_read_8_rden : OUT std_logic;
  user_r_read_8_empty : IN std_logic;
  user_r_read_8_data : IN std_logic_vector(7 DOWNTO 0);
  user_r_read_8_eof : IN std_logic;
  user_r_read_8_open : OUT std_logic;
  user_w_write_8_wren : OUT std_logic;
  user_w_write_8_full : IN std_logic;
  user_w_write_8_data : OUT std_logic_vector(7 DOWNTO 0);
  user_w_write_8_open : OUT std_logic);
  end component;


component ac_fifo_wrap
port (
  --==  General Interface ==--
  RST: IN std_logic;
  CLK: IN std_logic;

  --== Input Interface ==--
  nwrite: IN std_logic;
  full: OUT std_logic;
  din: IN std_logic_VECTOR(7 downto 0);

  --== Output Interface ==--
  empty: OUT std_logic;
  nread: IN std_logic;
  dout: OUT std_logic_VECTOR(7 downto 0) 
);
end component;


  signal bus_clk :  std_logic;
  signal quiesce : std_logic;

  signal reset_8 : std_logic;

  signal user_r_read_8_rden :  std_logic;
  signal user_r_read_8_empty :  std_logic;
  signal user_r_read_8_data :  std_logic_vector(7 DOWNTO 0);
  signal user_r_read_8_eof :  std_logic;
  signal user_r_read_8_open :  std_logic;

  signal user_w_write_8_wren :  std_logic;
  signal user_w_write_8_full :  std_logic;
  signal user_w_write_8_data :  std_logic_vector(7 DOWNTO 0);
  signal user_w_write_8_open :  std_logic;

  signal s_dout_din : std_logic_vector(7 DOWNTO 0);
  signal s_nread_full :  std_logic;
  signal s_empty_nwrite :  std_logic;

begin
  xillybus_ins : xillybus
port map (


  -- Ports related to /dev/xillybus_read_8
  -- FPGA to CPU signals:
  user_r_read_8_rden => user_r_read_8_rden,
  user_r_read_8_empty => user_r_read_8_empty,
  user_r_read_8_data => user_r_read_8_data,
  user_r_read_8_eof => user_r_read_8_eof,
  user_r_read_8_open => user_r_read_8_open,

  -- Ports related to /dev/xillybus_write_8
  -- CPU to FPGA signals:
  user_w_write_8_wren => user_w_write_8_wren,
  user_w_write_8_full => user_w_write_8_full,
  user_w_write_8_data => user_w_write_8_data,
  user_w_write_8_open => user_w_write_8_open,

  -- General signals
  PCIE_PERST_B_LS => PCIE_PERST_B_LS,
  PCIE_REFCLK_N => PCIE_REFCLK_N,
  PCIE_REFCLK_P => PCIE_REFCLK_P,
  PCIE_RX_N => PCIE_RX_N,
  PCIE_RX_P => PCIE_RX_P,
  GPIO_LED => GPIO_LED,
  PCIE_TX_N => PCIE_TX_N,
  PCIE_TX_P => PCIE_TX_P,
  bus_clk => bus_clk,
  quiesce => quiesce
  );


-- CPU to FPGA FIFO
ac_fifo_wrap_write: ac_fifo_wrap
port map(
  RST       => reset_8,
  CLK       => bus_clk,
  nwrite    => not user_w_write_8_wren,
  full      => user_w_write_8_full,
  din       => user_w_write_8_data,
  empty     => s_empty_nwrite, --
  nread     => s_nread_full, --
  dout      => s_dout_din--
);

-- FPGA to CPU FIFO  
ac_fifo_wrap_read: ac_fifo_wrap
  port map(
RST       => reset_8,
CLK       => bus_clk,
nwrite    => s_empty_nwrite, --
full      => s_nread_full, --
din       => s_dout_din, --
empty     => user_r_read_8_empty,
nread     => not user_r_read_8_rden,
dout      => user_r_read_8_data
  );


-- these lines must be preserved in the XillyDemo
reset_8 <= not (user_w_write_8_open or user_r_read_8_open);
user_r_read_8_eof <= user_r_read_8_empty and not(user_w_write_8_open);

end sample_arch;

Problema: Ahora tengo que probar mi código y escribí este banco de pruebas basado en el sugerido por @MartinZabel. Bueno, he adaptado el banco de pruebas sugerido para esta versión. La cosa es que necesito probar 2 ac_fifo_wrap juntos, porque el primer ac_fifo_wrap debería simular la escritura de datos de PCI a FIFO y el segundo ac_fifo_wrap debería simular la escritura de datos de FPGA a PCI. Aquí, mi banco de pruebas se usó para probar 2 ac_fifo_wrap juntos. ¿Está bien?

library ieee;
use ieee.std_logic_1164.all;

entity ac_fifo_wrap_tb is
end ac_fifo_wrap_tb;

architecture sim of ac_fifo_wrap_tb is

component ac_fifo_wrap
port (
  --==  General Interface ==--
  RST: IN std_logic;
  CLK: IN std_logic;

  --== Input Interface ==--
  nwrite: IN std_logic;
  full: OUT std_logic;
  din: IN std_logic_VECTOR(7 downto 0);

  --== Output Interface ==--
  empty: OUT std_logic;
  nread: IN std_logic;
  dout: OUT std_logic_VECTOR(7 downto 0) 
);
end component;

  signal bus_clk             : std_logic := '1';
  signal reset_8             : std_logic;
  signal user_w_write_8_wren : std_logic;
  signal user_w_write_8_full : std_logic;
  signal user_w_write_8_data : std_logic_vector(7 DOWNTO 0);
  signal user_r_read_8_rden  : std_logic;
  signal user_r_read_8_empty : std_logic;
  signal user_r_read_8_data  : std_logic_vector(7 DOWNTO 0);

  signal s_dout_din : std_logic_vector(7 DOWNTO 0);
  signal s_nread_full :  std_logic;
  signal s_empty_nwrite :  std_logic;


begin
  -- component instantiation
  DUT_write: entity work.ac_fifo_wrap
port map (
  RST       => reset_8,
  CLK       => bus_clk,
  nwrite    => not user_w_write_8_wren,
  full      => user_w_write_8_full,
  din       => user_w_write_8_data,
  empty     => s_empty_nwrite, --
  nread     => s_nread_full, --
  dout      => s_dout_din
);

  -- component instantiation
  DUT_read: entity work.ac_fifo_wrap
port map (
    RST       => reset_8,
    CLK       => bus_clk,
    nwrite    => s_empty_nwrite, --
    full      => s_nread_full, --
    din       => s_dout_din, --
    empty     => user_r_read_8_empty,
    nread     => not user_r_read_8_rden,
    dout      => user_r_read_8_data
);     



  -- clock generation
  bus_clk <= not bus_clk after 5 ns;

  -- waveform generation
  WaveGen_Proc: process
  begin
        reset_8  <= '1';                     -- apply reset
        -- other input values don't care during reset
        wait until rising_edge(bus_clk);

        -- Endless idle cycles
        reset_8 <= '0';
        user_w_write_8_wren <= '0';
        user_w_write_8_data <= (others => '-');
        user_r_read_8_rden  <= '0';
        wait;
  end process WaveGen_Proc;
end sim;
    
pregunta Message Passing

1 respuesta

1

Nota : esta respuesta solo se aplica a la versión original de la pregunta.

Su diseño no funciona porque, después de que reset_8 no sea confirmado por XillyBus (es decir, baja), su unidad nunca establece user_w_write_8_full a bajo para indicar que está listo para recibir datos.

El banco de pruebas más corto posible para verificar esto es:

library ieee;
use ieee.std_logic_1164.all;

entity my_buffer_tb is
end my_buffer_tb;

architecture sim of my_buffer_tb is
  signal bus_clk             : std_logic := '1';
  signal reset_8             : std_logic;
  signal user_w_write_8_wren : std_logic;
  signal user_w_write_8_full : std_logic;
  signal user_w_write_8_data : std_logic_vector(7 DOWNTO 0);
  signal user_r_read_8_rden  : std_logic;
  signal user_r_read_8_empty : std_logic;
  signal user_r_read_8_data  : std_logic_vector(7 DOWNTO 0);
begin
  -- component instantiation
  DUT: entity work.my_buffer
    port map (
      bus_clk             => bus_clk,
      reset_8             => reset_8,
      user_w_write_8_wren => user_w_write_8_wren,
      user_w_write_8_full => user_w_write_8_full,
      user_w_write_8_data => user_w_write_8_data,
      user_r_read_8_rden  => user_r_read_8_rden,
      user_r_read_8_empty => user_r_read_8_empty,
      user_r_read_8_data  => user_r_read_8_data);

  -- clock generation
  bus_clk <= not bus_clk after 5 ns;

  -- waveform generation
  WaveGen_Proc: process
  begin
    reset_8 <= '1';                     -- apply reset
    -- other input values don't care during reset
    wait until rising_edge(bus_clk);

    -- Endless idle cycles
    reset_8 <= '0';
    user_w_write_8_wren <= '0';
    user_w_write_8_data <= (others => '-');
    user_r_read_8_rden  <= '0';
    wait;
  end process WaveGen_Proc;
end sim;

La salida de simulación correspondiente es la siguiente. Como puede ver, después de que reset se anula a 10 ns, full se mantiene alto y nunca baja. Por lo tanto, XillyBus no te envía ningún dato.

Todavía no has publicado tu banco de pruebas y / o la salida de simulación, pero creo que no viste si full está bajando.

    
respondido por el Martin Zabel

Lea otras preguntas en las etiquetas