Hello. My application is based on xillybus because I have to take data from a Linux machine, process it on FPGA and pass it back to linux machine. In particular, my application uses 2 FIFOs. One to receive data from PCI, and one to store data to send to PCI. In between there is the logic to process data. The figure "schema" summarizes the data flow of my application. So, xillybus is used to pass data from and to PCI and the 2 FIFOs are used to take data from xillybus, process it and pass it back to xillybus. In order to solve this problem I used the FIFO from this [link 1]. Here the code in STD_FIFO.vhd:
1 | library IEEE; |
2 | USE IEEE.STD_LOGIC_1164.ALL; |
3 | USE IEEE.NUMERIC_STD.ALL; |
4 | |
5 | entity STD_FIFO is |
6 | Generic ( |
7 | constant DATA_WIDTH : positive := 8; |
8 | constant FIFO_DEPTH : positive := 256 |
9 | );
|
10 | Port ( |
11 | CLK : in STD_LOGIC; |
12 | RST : in STD_LOGIC; |
13 | WriteEn : in STD_LOGIC; |
14 | DataIn : in STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0); |
15 | ReadEn : in STD_LOGIC; |
16 | DataOut : out STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0); |
17 | Empty : out STD_LOGIC; |
18 | Full : out STD_LOGIC |
19 | );
|
20 | end STD_FIFO; |
21 | |
22 | architecture Behavioral of STD_FIFO is |
23 | |
24 | begin
|
25 | |
26 | -- Memory Pointer Process
|
27 | fifo_proc : process (CLK) |
28 | type FIFO_Memory is array (0 to FIFO_DEPTH - 1) of STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0); |
29 | variable Memory : FIFO_Memory; |
30 | |
31 | variable Head : natural range 0 to FIFO_DEPTH - 1; |
32 | variable Tail : natural range 0 to FIFO_DEPTH - 1; |
33 | |
34 | variable Looped : boolean; |
35 | begin
|
36 | if rising_edge(CLK) then |
37 | if RST = '1' then |
38 | Head := 0; |
39 | Tail := 0; |
40 | |
41 | Looped := false; |
42 | |
43 | Full <= '0'; |
44 | Empty <= '1'; |
45 | else
|
46 | if (ReadEn = '1') then |
47 | if ((Looped = true) or (Head /= Tail)) then |
48 | -- Update data output
|
49 | DataOut <= Memory(Tail); |
50 | |
51 | -- Update Tail pointer as needed
|
52 | if (Tail = FIFO_DEPTH - 1) then |
53 | Tail := 0; |
54 | |
55 | Looped := false; |
56 | else
|
57 | Tail := Tail + 1; |
58 | end if; |
59 | |
60 | |
61 | end if; |
62 | end if; |
63 | |
64 | if (WriteEn = '1') then |
65 | if ((Looped = false) or (Head /= Tail)) then |
66 | -- Write Data to Memory
|
67 | Memory(Head) := DataIn; |
68 | |
69 | -- Increment Head pointer as needed
|
70 | if (Head = FIFO_DEPTH - 1) then |
71 | Head := 0; |
72 | |
73 | Looped := true; |
74 | else
|
75 | Head := Head + 1; |
76 | end if; |
77 | end if; |
78 | end if; |
79 | |
80 | -- Update Empty and Full flags
|
81 | if (Head = Tail) then |
82 | if Looped then |
83 | Full <= '1'; |
84 | else
|
85 | Empty <= '1'; |
86 | end if; |
87 | else
|
88 | Empty <= '0'; |
89 | Full <= '0'; |
90 | end if; |
91 | end if; |
92 | end if; |
93 | end process; |
94 | |
95 | end Behavioral; |
In this [link 2] I understood that it is not possible to connect the FIFOs as shown in Figure 1 because of possible problem of handshake mechanism. As workaround, the previous link provides the VHDL code to convert a standard dual port FIFO into an Autonomous Cascadable Dual Port FIFO. The Figure 2 shows how to convert a standard dual port FIFO into an Autonomous Cascadable Dual Port FIFO. The VHDL code of the Autonomous Cascadable Dual Port FIFO is ac_fifo_wrap.vhd (in which I have already included the STD_FIFO):
1 | LIBRARY IEEE; |
2 | USE IEEE.STD_LOGIC_1164.ALL; |
3 | |
4 | ENTITY ac_fifo_wrap IS |
5 | GENERIC( |
6 | --== Data Width ==--
|
7 | data_width : NATURAL := 8 |
8 | );
|
9 | PORT( |
10 | --== General Interface ==--
|
11 | rst : IN STD_LOGIC; |
12 | clk : IN STD_LOGIC; |
13 | |
14 | --== Input Interface ==--
|
15 | nwrite : IN STD_LOGIC; |
16 | full : OUT STD_LOGIC; |
17 | din : IN STD_LOGIC_VECTOR(data_width-1 DOWNTO 0); |
18 | |
19 | --== Output Interface ==--
|
20 | empty : OUT STD_LOGIC; |
21 | nread : IN STD_LOGIC; |
22 | dout : OUT STD_LOGIC_VECTOR(data_width-1 DOWNTO 0) |
23 | );
|
24 | END ac_fifo_wrap; |
25 | |
26 | |
27 | ARCHITECTURE rtl OF ac_fifo_wrap IS |
28 | |
29 | ---==========================---
|
30 | --== Component Declarations ==--
|
31 | ---==========================---
|
32 | |
33 | |
34 | component STD_FIFO |
35 | port ( |
36 | CLK: IN std_logic; |
37 | RST: IN std_logic; |
38 | WriteEn: IN std_logic; |
39 | DataIn: IN std_logic_VECTOR(7 downto 0); |
40 | ReadEn: IN std_logic; |
41 | DataOut: OUT std_logic_VECTOR(7 downto 0); |
42 | Empty: OUT std_logic; |
43 | Full: OUT std_logic |
44 | );
|
45 | end component; |
46 | |
47 | ---=======================---
|
48 | --== Signal Declarations ==--
|
49 | ---=======================---
|
50 | |
51 | SIGNAL empty_int : STD_LOGIC; |
52 | SIGNAL empty_i : STD_LOGIC; |
53 | SIGNAL full_i : STD_LOGIC; |
54 | SIGNAL rd_en : STD_LOGIC; |
55 | SIGNAL wr_en : STD_LOGIC; |
56 | |
57 | BEGIN
|
58 | |
59 | ---====================---
|
60 | --== FIFO write logic ==--
|
61 | ---====================---
|
62 | |
63 | wr_en <= NOT(full_i) AND NOT(nwrite); |
64 | |
65 | full <= full_i; |
66 | |
67 | ---================================---
|
68 | --== STD_FIFO (CoreGen Module) ==--
|
69 | ---================================---
|
70 | |
71 | -- CPU to FPGA FIFO
|
72 | U0: STD_FIFO |
73 | port map( |
74 | RST => rst, |
75 | CLK => clk, |
76 | WriteEn => wr_en, |
77 | Full => full_i, |
78 | DataIn => din, |
79 | Empty => empty_int, |
80 | ReadEn => rd_en, |
81 | DataOut => dout |
82 | );
|
83 | |
84 | |
85 | ---===================---
|
86 | --== FIFO read logic ==--
|
87 | ---===================---
|
88 | |
89 | rd_en <= NOT(empty_int) AND (empty_i OR NOT(nread)); |
90 | |
91 | PROCESS(clk) |
92 | BEGIN
|
93 | IF RISING_EDGE(clk) THEN |
94 | IF (rst = '1') THEN |
95 | empty_i <= '1'; |
96 | ELSE
|
97 | empty_i <= empty_int AND (empty_i OR NOT(nread)); |
98 | END IF; |
99 | END IF; |
100 | END PROCESS; |
101 | |
102 | empty <= empty_i; |
103 | |
104 | END rtl; |
What I have done: in ac_fifo_wrap I defined the component STD_FIFO. In this way I connected Autonomous Cascadable Dual Port FIFO (ac_fifo_wrap) with the dual port FIFO (STD_FIFO). In xillydemo.vhd I defined 2 ac_fifo_wrap, ac_fifo_wrap_write and ac_fifo_wrap_read respectively. In this way I have 2 FIFOs connected and I should not have handshake problem. Here xillydemo.vhd:
1 | library ieee; |
2 | use ieee.std_logic_1164.all; |
3 | use ieee.std_logic_unsigned.all; |
4 | use ieee.numeric_std.all; |
5 | |
6 | entity xillydemo is |
7 | port ( |
8 | PCIE_PERST_B_LS : IN std_logic; |
9 | PCIE_REFCLK_N : IN std_logic; |
10 | PCIE_REFCLK_P : IN std_logic; |
11 | PCIE_RX_N : IN std_logic_vector(3 DOWNTO 0); |
12 | PCIE_RX_P : IN std_logic_vector(3 DOWNTO 0); |
13 | GPIO_LED : OUT std_logic_vector(3 DOWNTO 0); |
14 | PCIE_TX_N : OUT std_logic_vector(3 DOWNTO 0); |
15 | PCIE_TX_P : OUT std_logic_vector(3 DOWNTO 0)); |
16 | end xillydemo; |
17 | |
18 | architecture sample_arch of xillydemo is |
19 | component xillybus |
20 | port ( |
21 | PCIE_PERST_B_LS : IN std_logic; |
22 | PCIE_REFCLK_N : IN std_logic; |
23 | PCIE_REFCLK_P : IN std_logic; |
24 | PCIE_RX_N : IN std_logic_vector(3 DOWNTO 0); |
25 | PCIE_RX_P : IN std_logic_vector(3 DOWNTO 0); |
26 | GPIO_LED : OUT std_logic_vector(3 DOWNTO 0); |
27 | PCIE_TX_N : OUT std_logic_vector(3 DOWNTO 0); |
28 | PCIE_TX_P : OUT std_logic_vector(3 DOWNTO 0); |
29 | bus_clk : OUT std_logic; |
30 | quiesce : OUT std_logic; |
31 | |
32 | user_r_read_8_rden : OUT std_logic; |
33 | user_r_read_8_empty : IN std_logic; |
34 | user_r_read_8_data : IN std_logic_vector(7 DOWNTO 0); |
35 | user_r_read_8_eof : IN std_logic; |
36 | user_r_read_8_open : OUT std_logic; |
37 | user_w_write_8_wren : OUT std_logic; |
38 | user_w_write_8_full : IN std_logic; |
39 | user_w_write_8_data : OUT std_logic_vector(7 DOWNTO 0); |
40 | user_w_write_8_open : OUT std_logic); |
41 | end component; |
42 | |
43 | |
44 | component ac_fifo_wrap |
45 | port ( |
46 | --== General Interface ==--
|
47 | RST: IN std_logic; |
48 | CLK: IN std_logic; |
49 | |
50 | --== Input Interface ==--
|
51 | nwrite: IN std_logic; |
52 | full: OUT std_logic; |
53 | din: IN std_logic_VECTOR(7 downto 0); |
54 | |
55 | --== Output Interface ==--
|
56 | empty: OUT std_logic; |
57 | nread: IN std_logic; |
58 | dout: OUT std_logic_VECTOR(7 downto 0) |
59 | );
|
60 | end component; |
61 | |
62 | |
63 | signal bus_clk : std_logic; |
64 | signal quiesce : std_logic; |
65 | |
66 | signal reset_8 : std_logic; |
67 | |
68 | signal user_r_read_8_rden : std_logic; |
69 | signal user_r_read_8_empty : std_logic; |
70 | signal user_r_read_8_data : std_logic_vector(7 DOWNTO 0); |
71 | signal user_r_read_8_eof : std_logic; |
72 | signal user_r_read_8_open : std_logic; |
73 | |
74 | signal user_w_write_8_wren : std_logic; |
75 | signal user_w_write_8_full : std_logic; |
76 | signal user_w_write_8_data : std_logic_vector(7 DOWNTO 0); |
77 | signal user_w_write_8_open : std_logic; |
78 | |
79 | signal s_dout_din : std_logic_vector(7 DOWNTO 0); |
80 | signal s_nread_full : std_logic; |
81 | signal s_empty_nwrite : std_logic; |
82 | |
83 | begin
|
84 | xillybus_ins : xillybus |
85 | port map ( |
86 | |
87 | |
88 | -- Ports related to /dev/xillybus_read_8
|
89 | -- FPGA to CPU signals:
|
90 | user_r_read_8_rden => user_r_read_8_rden, |
91 | user_r_read_8_empty => user_r_read_8_empty, |
92 | user_r_read_8_data => user_r_read_8_data, |
93 | user_r_read_8_eof => user_r_read_8_eof, |
94 | user_r_read_8_open => user_r_read_8_open, |
95 | |
96 | -- Ports related to /dev/xillybus_write_8
|
97 | -- CPU to FPGA signals:
|
98 | user_w_write_8_wren => user_w_write_8_wren, |
99 | user_w_write_8_full => user_w_write_8_full, |
100 | user_w_write_8_data => user_w_write_8_data, |
101 | user_w_write_8_open => user_w_write_8_open, |
102 | |
103 | -- General signals
|
104 | PCIE_PERST_B_LS => PCIE_PERST_B_LS, |
105 | PCIE_REFCLK_N => PCIE_REFCLK_N, |
106 | PCIE_REFCLK_P => PCIE_REFCLK_P, |
107 | PCIE_RX_N => PCIE_RX_N, |
108 | PCIE_RX_P => PCIE_RX_P, |
109 | GPIO_LED => GPIO_LED, |
110 | PCIE_TX_N => PCIE_TX_N, |
111 | PCIE_TX_P => PCIE_TX_P, |
112 | bus_clk => bus_clk, |
113 | quiesce => quiesce |
114 | );
|
115 | |
116 | |
117 | -- CPU to FPGA FIFO
|
118 | ac_fifo_wrap_write: ac_fifo_wrap |
119 | port map( |
120 | RST => reset_8, |
121 | CLK => bus_clk, |
122 | nwrite => not user_w_write_8_wren, |
123 | full => user_w_write_8_full, |
124 | din => user_w_write_8_data, |
125 | empty => s_empty_nwrite, -- |
126 | nread => s_nread_full, -- |
127 | dout => s_dout_din-- |
128 | );
|
129 | |
130 | -- FPGA to CPU FIFO
|
131 | ac_fifo_wrap_read: ac_fifo_wrap |
132 | port map( |
133 | RST => reset_8, |
134 | CLK => bus_clk, |
135 | nwrite => s_empty_nwrite, -- |
136 | full => s_nread_full, -- |
137 | din => s_dout_din, -- |
138 | empty => user_r_read_8_empty, |
139 | nread => not user_r_read_8_rden, |
140 | dout => user_r_read_8_data |
141 | );
|
142 | |
143 | |
144 | -- these lines must be preserved in the XillyDemo
|
145 | reset_8 <= not (user_w_write_8_open or user_r_read_8_open); |
146 | user_r_read_8_eof <= user_r_read_8_empty and not(user_w_write_8_open); |
147 | |
148 | end sample_arch; |
Problem: Now I have to test my code and I wrote this test but it does not work. Vivado suite says to check in log file but in the log file there are no errors. I think I messed up with signals. Here the code. Any hint?
1 | library ieee; |
2 | use ieee.std_logic_1164.all; |
3 | |
4 | entity my_buffer_tb is |
5 | end my_buffer_tb; |
6 | |
7 | architecture sim of ac_fifo_wrap_tb is |
8 | signal clk : std_logic := '1'; |
9 | signal rst : std_logic; |
10 | signal nwrite : std_logic; |
11 | signal full : std_logic; |
12 | signal din : std_logic_vector(7 DOWNTO 0); |
13 | signal nread : std_logic; |
14 | signal empty : std_logic; |
15 | signal dout : std_logic_vector(7 DOWNTO 0); |
16 | begin
|
17 | -- component instantiation
|
18 | DUT: entity work.ac_fifo_wrap |
19 | port map ( |
20 | clk => bus_clk, |
21 | rst => reset_8, |
22 | nwrite => user_w_write_8_wren, |
23 | full => user_w_write_8_full, |
24 | din => user_w_write_8_data, |
25 | nread => user_r_read_8_rden, |
26 | empty => user_r_read_8_empty, |
27 | dout => user_r_read_8_data); |
28 | |
29 | -- clock generation
|
30 | clk <= not clk after 5 ns; |
31 | |
32 | -- waveform generation
|
33 | WaveGen_Proc: process |
34 | begin
|
35 | rst <= '1'; -- apply reset |
36 | -- other input values don't care during reset
|
37 | wait until rising_edge(clk); |
38 | |
39 | -- Endless idle cycles
|
40 | rst <= '0'; |
41 | nwrite <= '0'; |
42 | din <= (others => '-'); |
43 | nread <= '0'; |
44 | wait; |
45 | end process WaveGen_Proc; |
46 | end sim; |
[link 1]: http://www.deathbylogic.com/2013/07/vhdl-standard-fifo/ [link 2]: http://www.spacewire.co.uk/auto_fifo.html