improve synchonous FIFO implementation (get rid of delays between reads)
Stefan Schuermans

Stefan Schuermans commited on 2012-03-11 18:59:11
Showing 1 changed files, with 54 additions and 50 deletions.

... ...
@@ -36,22 +36,24 @@ ARCHITECTURE a_block_fifo OF e_block_fifo IS
36 36
         );
37 37
     END COMPONENT e_block_rwram;
38 38
 
39
-    SUBTYPE t_addr_n IS natural RANGE 0 TO 2 ** addr_width - 1;
39
+    SUBTYPE t_pos  IS natural RANGE 0 TO 2 ** addr_width - 1;
40 40
     SUBTYPE t_addr IS std_logic_vector(addr_width - 1 DOWNTO 0);
41 41
     SUBTYPE t_data IS std_logic_vector(data_width - 1 DOWNTO 0);
42 42
 
43
-    SIGNAL r_begin:       t_addr_n  := 0;
44
-    SIGNAL r_end:         t_addr_n  := 0;
45
-    SIGNAL r_end_dly1:    t_addr_n  := 0;
46
-    SIGNAL r_end_dly2:    t_addr_n  := 0;
47
-    SIGNAL r_begin_chgd:  std_logic := '0';
48
-    SIGNAL r_ram_wr_addr: t_addr    := (OTHERS => '0');
49
-    SIGNAL r_ram_wr_data: t_data    := (OTHERS => '0');
50
-    SIGNAL r_ram_wr_en:   std_logic := '0';
51
-
52
-    SIGNAL s_ram_rd_addr: t_addr;
43
+    SIGNAL r_begin:         t_pos     := 0;
44
+    SIGNAL n_begin:         t_pos;
45
+    SIGNAL s_begin_addr:    t_addr;
46
+    SIGNAL s_begin_sn_addr: t_addr; -- _sn_ means sometimes next
53 47
     SIGNAL s_rd_rdy:        std_logic;
48
+    SIGNAL s_rd_en:         std_logic;
49
+
50
+    SIGNAL r_end:            t_pos     := 0;
51
+    SIGNAL n_end:            t_pos;
52
+    SIGNAL s_end_addr:       t_addr;
53
+    SIGNAL r_end_addr_delay: t_addr := (OTHERS => '0');
54
+    SIGNAL s_end_an_addr:    t_addr; -- _an_ means always next
54 55
     SIGNAL s_wr_rdy:         std_logic;
56
+    SIGNAL s_wr_en:          std_logic;
55 57
 
56 58
     FUNCTION next_pos (
57 59
         pos: natural RANGE 0 TO 2 ** addr_width - 1
... ...
@@ -66,15 +68,14 @@ ARCHITECTURE a_block_fifo OF e_block_fifo IS
66 68
         RETURN v_next;
67 69
     END FUNCTION next_pos;
68 70
 
71
+    FUNCTION to_addr (
72
+        pos: natural RANGE 0 TO 2 ** addr_width - 1
73
+    ) RETURN std_logic_vector IS
69 74
     BEGIN
75
+        RETURN std_logic_vector(to_unsigned(pos, addr_width));
76
+    END FUNCTION to_addr;
70 77
 
71
-    s_ram_rd_addr <= std_logic_vector(to_unsigned(r_begin, addr_width));
72
-
73
-    s_rd_rdy <= '0' WHEN r_begin = r_end_dly2 OR r_begin_chgd = '1' ELSE '1';
74
-    s_wr_rdy <= '0' WHEN r_begin = next_pos(r_end)                  ELSE '1';
75
-
76
-    o_rd_rdy <= s_rd_rdy;
77
-    o_wr_rdy <= s_wr_rdy;
78
+BEGIN
78 79
 
79 80
     i_rwram: e_block_rwram
80 81
         GENERIC MAP (
... ...
@@ -83,46 +84,49 @@ BEGIN
83 84
         )
84 85
         PORT MAP (
85 86
             clk       => clk,
86
-            i_rd_addr => s_ram_rd_addr,
87
+            i_rd_addr => s_begin_sn_addr,
87 88
             o_rd_data => o_rd_data,
88
-            i_wr_addr => r_ram_wr_addr,
89
-            i_wr_data => r_ram_wr_data,
90
-            i_wr_en   => r_ram_wr_en
89
+            i_wr_addr => s_end_addr,
90
+            i_wr_data => i_wr_data,
91
+            i_wr_en   => s_wr_en
91 92
         );
92 93
 
93
-    p_fifo: PROCESS(rst, clk)
94
+    s_begin_addr    <= to_addr(r_begin);
95
+    s_begin_sn_addr <= to_addr(n_begin);
96
+    s_rd_rdy        <= '1' WHEN s_begin_addr /= r_end_addr_delay ELSE '0';
97
+    s_rd_en         <= s_rd_rdy AND i_rd_en;
98
+
99
+    s_end_addr      <= to_addr(r_end);
100
+    s_end_an_addr   <= to_addr(next_pos(r_end));
101
+    s_wr_rdy        <= '1' WHEN s_end_an_addr /= s_begin_addr ELSE '0';
102
+    s_wr_en         <= s_wr_rdy AND i_wr_en;
103
+
104
+    o_wr_rdy        <= s_wr_rdy;
105
+    o_rd_rdy        <= s_rd_rdy;
106
+
107
+    p_next: PROCESS(r_begin, r_end, s_rd_en, s_wr_en)
108
+    BEGIN
109
+        n_begin <= r_begin;
110
+        n_end <= r_end;
111
+        IF s_rd_en = '1' THEN
112
+            n_begin <= next_pos(r_begin);
113
+        END IF;
114
+        IF s_wr_en = '1' THEN
115
+            n_end <= next_pos(r_end);
116
+        END IF;
117
+    END PROCESS p_next;
118
+
119
+    p_sync: PROCESS(rst, clk)
94 120
     BEGIN
95 121
         IF rst = '1' THEN
96 122
             r_begin          <= 0;
97 123
             r_end            <= 0;
98
-            r_end_dly1    <= 0;
99
-            r_end_dly2    <= 0;
100
-            r_begin_chgd  <= '0';
101
-            r_ram_wr_addr <= (OTHERS => '0');
102
-            r_ram_wr_data <= (OTHERS => '0');
103
-            r_ram_wr_en   <= '0';
124
+            r_end_addr_delay <= (OTHERS => '0');
104 125
         ELSIF rising_edge(clk) THEN
105
-            -- read
106
-            IF i_rd_en = '1' AND s_rd_rdy = '1' THEN
107
-                r_begin      <= next_pos(r_begin);
108
-                r_begin_chgd <= '1';
109
-            ELSE
110
-                r_begin_chgd <= '0';
111
-            END IF;
112
-            -- write
113
-            IF i_wr_en = '1' AND s_wr_rdy = '1' THEN
114
-                r_ram_wr_addr <= std_logic_vector(to_unsigned(r_end, addr_width));
115
-                r_ram_wr_data <= i_wr_data;
116
-                r_ram_wr_en   <= '1';
117
-                r_end         <= next_pos(r_end);
118
-            ELSE
119
-                r_ram_wr_en  <= '0';
126
+            r_begin          <= n_begin;
127
+            r_end            <= n_end;
128
+            r_end_addr_delay <= s_end_addr;
120 129
         END IF;
121
-            -- delay r_end 2 cycles: 1 for writing to RAM, 1 to read RAM
122
-            r_end_dly1 <= r_end;
123
-            r_end_dly2 <= r_end_dly1;
124
-        END IF;
125
-    END PROCESS p_fifo;
130
+    END PROCESS p_sync;
126 131
 
127 132
 END ARCHITECTURE a_block_fifo;
128
-
129 133