En esta pregunta anterior link He desarrollado una aplicación que secuencialmente lo hizo:
- obtenga y almacene 8 valores de entrada (8 caracteres)
- alternar entre mayúsculas y minúsculas (o viceversa) solo el primer carácter
- 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;