Add Tercel PHY reset synchronization
[microwatt.git] / sync_fifo.vhdl
1 -- Synchronous FIFO with a protocol similar to AXI
2 --
3 -- The outputs are generated combinationally from the inputs
4 -- in order to allow for back-to-back transfers with the type
5 -- of flow control used by busses lite AXI, pipelined WB or
6 -- LiteDRAM native port when the FIFO is full.
7 --
8 -- That means that care needs to be taken by the user not to
9 -- generate the inputs combinationally from the outputs otherwise
10 -- it would create a logic loop.
11 --
12 -- If breaking that loop is required, a stash buffer could be
13 -- added to break the flow control "loop" between the read and
14 -- the write port.
15 --
16 library ieee;
17 use ieee.std_logic_1164.all;
18
19 library work;
20 use work.utils.all;
21
22 entity sync_fifo is
23 generic(
24 -- Fifo depth in entries
25 DEPTH : natural := 64;
26
27 -- Fifo width in bits
28 WIDTH : natural := 32;
29
30 -- When INIT_ZERO is set, the memory is pre-initialized to 0's
31 INIT_ZERO : boolean := false
32 );
33 port(
34 -- Control lines:
35 clk : in std_ulogic;
36 reset : in std_ulogic;
37
38 -- Write port
39 wr_ready : out std_ulogic;
40 wr_valid : in std_ulogic;
41 wr_data : in std_ulogic_vector(WIDTH - 1 downto 0);
42
43 -- Read port
44 rd_ready : in std_ulogic;
45 rd_valid : out std_ulogic;
46 rd_data : out std_ulogic_vector(WIDTH - 1 downto 0)
47 );
48 end entity sync_fifo;
49
50 architecture behaviour of sync_fifo is
51
52 subtype data_t is std_ulogic_vector(WIDTH - 1 downto 0);
53 type memory_t is array(0 to DEPTH - 1) of data_t;
54
55 function init_mem return memory_t is
56 variable m : memory_t;
57 begin
58 if INIT_ZERO then
59 for i in 0 to DEPTH - 1 loop
60 m(i) := (others => '0');
61 end loop;
62 end if;
63 return m;
64 end function;
65
66 signal memory : memory_t := init_mem;
67
68 subtype index_t is integer range 0 to DEPTH - 1;
69 signal rd_idx : index_t;
70 signal rd_next : index_t;
71 signal wr_idx : index_t;
72 signal wr_next : index_t;
73
74 function next_index(idx : index_t) return index_t is
75 variable r : index_t;
76 begin
77 if ispow2(DEPTH) then
78 r := (idx + 1) mod DEPTH;
79 else
80 r := idx + 1;
81 if r = DEPTH then
82 r := 0;
83 end if;
84 end if;
85 return r;
86 end function;
87
88 type op_t is (OP_POP, OP_PUSH);
89 signal op_prev : op_t := OP_POP;
90 signal op_next : op_t;
91
92 signal full, empty : std_ulogic;
93 signal push, pop : std_ulogic;
94 begin
95
96 -- Current state at last clock edge
97 empty <= '1' when rd_idx = wr_idx and op_prev = OP_POP else '0';
98 full <= '1' when rd_idx = wr_idx and op_prev = OP_PUSH else '0';
99
100 -- We can accept new data if we aren't full or we are but
101 -- the read port is going to accept data this cycle
102 wr_ready <= rd_ready or not full;
103
104 -- We can provide data if we aren't empty or we are but
105 -- the write port is going to provide data this cycle
106 rd_valid <= wr_valid or not empty;
107
108 -- Internal control signals
109 push <= wr_ready and wr_valid;
110 pop <= rd_ready and rd_valid;
111
112 -- Next state
113 rd_next <= next_index(rd_idx) when pop = '1' else rd_idx;
114 wr_next <= next_index(wr_idx) when push = '1' else wr_idx;
115 with push & pop select op_next <=
116 OP_PUSH when "10",
117 OP_POP when "01",
118 op_prev when others;
119
120 -- Read port output
121 rd_data <= memory(rd_idx) when empty = '0' else wr_data;
122
123 -- Read counter
124 reader: process(clk)
125 begin
126 if rising_edge(clk) then
127 if reset = '1' then
128 rd_idx <= 0;
129 else
130 rd_idx <= rd_next;
131 end if;
132 end if;
133 end process;
134
135 -- Write counter and memory write
136 producer: process(clk)
137 begin
138 if rising_edge(clk) then
139 if reset = '1' then
140 wr_idx <= 0;
141 else
142 wr_idx <= wr_next;
143
144 if push = '1' then
145 memory(wr_idx) <= wr_data;
146 end if;
147 end if;
148 end if;
149 end process;
150
151 -- Previous op latch used for generating empty/full
152 op: process(clk)
153 begin
154 if rising_edge(clk) then
155 if reset = '1' then
156 op_prev <= OP_POP;
157 else
158 op_prev <= op_next;
159 end if;
160 end if;
161 end process;
162
163 end architecture behaviour;