1
0
mirror of https://github.com/antonblanchard/microwatt.git synced 2026-01-11 23:43:15 +00:00
Benjamin Herrenschmidt bd42580a42 pp_fifo: Fix full fifo losing all data on simultaneous push & pop
The pp_fifo decides whether top = bottom means empty or full based
on whether the previous operation was a push or a pop.

If the fifo performs both in one cycle, it sets the previous op to
pop. That means that a full fifo being added a character and removed
one at the same time becomes empty.

Instead, just leave the previous op alone. If the fifo was empty, it
remains so, if it was full ditto.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
2020-05-15 20:49:09 +10:00

92 lines
2.5 KiB
VHDL

-- The Potato Processor - A simple processor for FPGAs
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net>
library ieee;
use ieee.std_logic_1164.all;
--! @brief A generic FIFO module.
--! Adopted from the FIFO module in <https://github.com/skordal/smallthings>.
entity pp_fifo is
generic(
DEPTH : natural := 64;
WIDTH : natural := 32
);
port(
-- Control lines:
clk : in std_logic;
reset : in std_logic;
-- Status lines:
full : out std_logic;
empty : out std_logic;
-- Data in:
data_in : in std_logic_vector(WIDTH - 1 downto 0);
data_out : out std_logic_vector(WIDTH - 1 downto 0);
push, pop : in std_logic
);
end entity pp_fifo;
architecture behaviour of pp_fifo is
type memory_array is array(0 to DEPTH - 1) of std_logic_vector(WIDTH - 1 downto 0);
signal memory : memory_array := (others => (others => '0'));
subtype index_type is integer range 0 to DEPTH - 1;
signal top, bottom : index_type;
type fifo_op is (FIFO_POP, FIFO_PUSH);
signal prev_op : fifo_op := FIFO_POP;
begin
empty <= '1' when top = bottom and prev_op = FIFO_POP else '0';
full <= '1' when top = bottom and prev_op = FIFO_PUSH else '0';
read: process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
bottom <= 0;
else
if pop = '1' then
data_out <= memory(bottom);
bottom <= (bottom + 1) mod DEPTH;
end if;
end if;
end if;
end process read;
write: process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
top <= 0;
else
if push = '1' then
memory(top) <= data_in;
top <= (top + 1) mod DEPTH;
end if;
end if;
end if;
end process write;
set_prev_op: process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
prev_op <= FIFO_POP;
else
if push = '1' and pop = '1' then
-- Keep the same value for prev_op
elsif push = '1' then
prev_op <= FIFO_PUSH;
elsif pop = '1' then
prev_op <= FIFO_POP;
end if;
end if;
end if;
end process set_prev_op;
end architecture behaviour;