sync_fifo.vhdl 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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. library work;
  19. use work.utils.all;
  20. entity sync_fifo is
  21. generic(
  22. -- Fifo depth in entries
  23. DEPTH : natural := 64;
  24. -- Fifo width in bits
  25. WIDTH : natural := 32;
  26. -- When INIT_ZERO is set, the memory is pre-initialized to 0's
  27. INIT_ZERO : boolean := false
  28. );
  29. port(
  30. -- Control lines:
  31. clk : in std_ulogic;
  32. reset : in std_ulogic;
  33. -- Write port
  34. wr_ready : out std_ulogic;
  35. wr_valid : in std_ulogic;
  36. wr_data : in std_ulogic_vector(WIDTH - 1 downto 0);
  37. -- Read port
  38. rd_ready : in std_ulogic;
  39. rd_valid : out std_ulogic;
  40. rd_data : out std_ulogic_vector(WIDTH - 1 downto 0)
  41. );
  42. end entity sync_fifo;
  43. architecture behaviour of sync_fifo is
  44. subtype data_t is std_ulogic_vector(WIDTH - 1 downto 0);
  45. type memory_t is array(0 to DEPTH - 1) of data_t;
  46. function init_mem return memory_t is
  47. variable m : memory_t;
  48. begin
  49. if INIT_ZERO then
  50. for i in 0 to DEPTH - 1 loop
  51. m(i) := (others => '0');
  52. end loop;
  53. end if;
  54. return m;
  55. end function;
  56. signal memory : memory_t := init_mem;
  57. subtype index_t is integer range 0 to DEPTH - 1;
  58. signal rd_idx : index_t;
  59. signal rd_next : index_t;
  60. signal wr_idx : index_t;
  61. signal wr_next : index_t;
  62. function next_index(idx : index_t) return index_t is
  63. variable r : index_t;
  64. begin
  65. if ispow2(DEPTH) then
  66. r := (idx + 1) mod DEPTH;
  67. else
  68. r := idx + 1;
  69. if r = DEPTH then
  70. r := 0;
  71. end if;
  72. end if;
  73. return r;
  74. end function;
  75. type op_t is (OP_POP, OP_PUSH);
  76. signal op_prev : op_t := OP_POP;
  77. signal op_next : op_t;
  78. signal full, empty : std_ulogic;
  79. signal push, pop : std_ulogic;
  80. begin
  81. -- Current state at last clock edge
  82. empty <= '1' when rd_idx = wr_idx and op_prev = OP_POP else '0';
  83. full <= '1' when rd_idx = wr_idx and op_prev = OP_PUSH else '0';
  84. -- We can accept new data if we aren't full or we are but
  85. -- the read port is going to accept data this cycle
  86. wr_ready <= rd_ready or not full;
  87. -- We can provide data if we aren't empty or we are but
  88. -- the write port is going to provide data this cycle
  89. rd_valid <= wr_valid or not empty;
  90. -- Internal control signals
  91. push <= wr_ready and wr_valid;
  92. pop <= rd_ready and rd_valid;
  93. -- Next state
  94. rd_next <= next_index(rd_idx) when pop = '1' else rd_idx;
  95. wr_next <= next_index(wr_idx) when push = '1' else wr_idx;
  96. with push & pop select op_next <=
  97. OP_PUSH when "10",
  98. OP_POP when "01",
  99. op_prev when others;
  100. -- Read port output
  101. rd_data <= memory(rd_idx) when empty = '0' else wr_data;
  102. -- Read counter
  103. reader: process(clk)
  104. begin
  105. if rising_edge(clk) then
  106. if reset = '1' then
  107. rd_idx <= 0;
  108. else
  109. rd_idx <= rd_next;
  110. end if;
  111. end if;
  112. end process;
  113. -- Write counter and memory write
  114. producer: process(clk)
  115. begin
  116. if rising_edge(clk) then
  117. if reset = '1' then
  118. wr_idx <= 0;
  119. else
  120. wr_idx <= wr_next;
  121. if push = '1' then
  122. memory(wr_idx) <= wr_data;
  123. end if;
  124. end if;
  125. end if;
  126. end process;
  127. -- Previous op latch used for generating empty/full
  128. op: process(clk)
  129. begin
  130. if rising_edge(clk) then
  131. if reset = '1' then
  132. op_prev <= OP_POP;
  133. else
  134. op_prev <= op_next;
  135. end if;
  136. end if;
  137. end process;
  138. end architecture behaviour;