ARCHITECTURE behavioral OF fifo_generator_v2_2_bhv_preload0 IS

  constant USE_ALTERNATE_EMPTY_FLAGS : integer := 1;
  
  SIGNAL preloadstage1     : std_logic := '0';
  SIGNAL preloadstage2     : std_logic := '0';
  SIGNAL ram_valid_i       : std_logic := '0';
  SIGNAL read_data_valid_i : std_logic := '0';
  SIGNAL ram_regout_en     : std_logic := '0';
  SIGNAL ram_rd_en         : std_logic := '0';
  SIGNAL empty_i           : std_logic := '1';
  SIGNAL empty_q           : std_logic := '1';
  SIGNAL almost_empty_i           : std_logic := '1';
  SIGNAL almost_empty_q           : std_logic := '1';


  
BEGIN  -- behavioral


p0g: if USE_ALTERNATE_EMPTY_FLAGS=0 generate
  
--------------------------------------------------------------------------------
--  preloadstage2 indicates that stage2 needs to be updated. This is true
--  whenever read_data_valid is false, and RAM_valid is true.
--------------------------------------------------------------------------------  
  preloadstage2 < = ram_valid_i AND (NOT read_data_valid_i or RD_EN);

--------------------------------------------------------------------------------
--  preloadstage1 indicates that stage1 needs to be updated. This is true
--  whenever the RAM has data (RAM_EMPTY is false), and either RAM_Valid is
--  false (indicating that Stage1 needs updating), or preloadstage2 is active
--  (indicating that Stage2 is going to update, so Stage1, therefore, must
--  also be updated to keep it valid.  
--------------------------------------------------------------------------------  
  preloadstage1 < = (((NOT ram_valid_i) OR preloadstage2) AND (NOT FIFOEMPTY));

--------------------------------------------------------------------------------
-- Calculate RAM_REGOUT_EN
--  The output registers are controlled by the ram_regout_en signal.
--  These registers should be updated either when the output in Stage2 is
--  invalid (preloadstage2), OR when the user is reading, in which case the
--  Stage2 value will go invalid unless it is replenished.
--------------------------------------------------------------------------------
  ram_regout_en < = preloadstage2;

--------------------------------------------------------------------------------
-- Calculate RAM_RD_EN
--   RAM_RD_EN will be asserted whenever the RAM needs to be read in order to 
--  update the value in Stage1.
--   One case when this happens is when preloadstage1=true, which indicates
--  that the data in Stage1 or Stage2 is invalid, and needs to automatically
--  be updated.
--   The other case is when the user is reading from the FIFO, which guarantees
--  that Stage1 or Stage2 will be invalid on the next clock cycle, unless it is
--  replinished by data from the memory. So, as long as the RAM has data in it,
--  a read of the RAM should occur. 
--------------------------------------------------------------------------------  
  ram_rd_en     < = (RD_EN AND NOT FIFOEMPTY) OR preloadstage1;

--------------------------------------------------------------------------------
-- Calculate ram_valid
--   ram_valid indicates that the data in Stage1 is valid.
--
--   If the RAM is being read from on this clock cycle (ram_rd_en=1), then
--   ram_valid is certainly going to be true.
--   If the RAM is not being read from, but the output registers are being
--   updated to fill Stage2 (ram_regout_en=1), then Stage1 will be emptying,
--   therefore causing ram_valid to be false.
--   Otherwise, ram_valid will remain unchanged.
--------------------------------------------------------------------------------  
  regout_valid: PROCESS (RD_CLK, RD_RST)
  BEGIN  -- PROCESS regout_valid
    IF RD_RST = '1' THEN                -- asynchronous reset (active high)
      ram_valid_i < = '0';
    ELSIF RD_CLK'event AND RD_CLK = '1' THEN  -- rising clock edge
      IF ram_rd_en = '1' THEN
        ram_valid_i < = '1';
      ELSE
        IF ram_regout_en = '1' THEN
          ram_valid_i < = '0';
        ELSE
          ram_valid_i < = ram_valid_i;
        END IF;          
      END IF;      
    END IF;
  END PROCESS regout_valid;

--------------------------------------------------------------------------------
-- Calculate READ_DATA_VALID
--  READ_DATA_VALID indicates whether the value in Stage2 is valid or not.
--  Stage2 has valid data whenever Stage1 had valid data and ram_regout_en_i=1,
--  such that the data in Stage1 is propogated into Stage2.
--------------------------------------------------------------------------------  
  regout_dvalid : PROCESS (RD_CLK, RD_RST)
  BEGIN
    IF (RD_RST='1') THEN
      read_data_valid_i < = '0';
    ELSIF (RD_CLK'event AND RD_CLK='1') THEN
      read_data_valid_i < = ram_valid_i or (read_data_valid_i and not RD_EN);
    END IF; --RD_CLK
  END PROCESS regout_dvalid;

  regout_empty: PROCESS (RD_CLK, RD_RST)
  BEGIN  -- PROCESS regout_empty
    IF RD_RST = '1' THEN                -- asynchronous reset (active high)
      empty_i < = '1';
      empty_q < = '1';
    ELSIF RD_CLK'event AND RD_CLK = '1' THEN  -- rising clock edge
      IF ((ram_regout_en = '1') OR (FIFOEMPTY = '0' AND read_data_valid_i = '1' AND  RD_EN='0')) THEN
        empty_i < = FIFOEMPTY;
      END IF;
      empty_q   < = empty_i;
    END IF;
  END PROCESS regout_empty;

  USEREMPTY < = empty_i;
  FIFORDEN  < = ram_rd_en;
  RAMVALID  < = ram_valid_i;

  guvh: if C_USERVALID_LOW=0 generate
    USERVALID < = read_data_valid_i;
  end generate guvh;
  guvl: if C_USERVALID_LOW=1 generate
    USERVALID < = not read_data_valid_i;
  end generate guvl;
  
  gufh: if C_USERUNDERFLOW_LOW=0 generate
    USERUNDERFLOW < = empty_q AND RD_EN;    
  end generate gufh;
  gufl: if C_USERUNDERFLOW_LOW=1 generate
    USERUNDERFLOW < = not (empty_q AND RD_EN);    
  end generate gufl;

  regout_lat0: PROCESS (RD_CLK, RD_RST)
  BEGIN  -- PROCESS regout_lat0
    IF RD_RST = '1' THEN              -- asynchronous reset (active high)
      USERDATA < = hexstr_to_std_logic_vec(C_DOUT_RST_VAL, C_DOUT_WIDTH);
    ELSIF RD_CLK'event AND RD_CLK = '1' THEN  -- rising clock edge
      IF (ram_regout_en = '1') THEN
        USERDATA < = FIFODATA;
      END IF;         
    END IF;
  END PROCESS regout_lat0;  




end generate p0g;

p0ga: if USE_ALTERNATE_EMPTY_FLAGS=1 generate
  
--------------------------------------------------------------------------------
--  preloadstage2 indicates that stage2 needs to be updated. This is true
--  whenever read_data_valid is false, and RAM_valid is true.
--------------------------------------------------------------------------------  
  preloadstage2 < = ram_valid_i AND (NOT read_data_valid_i or RD_EN);

--------------------------------------------------------------------------------
--  preloadstage1 indicates that stage1 needs to be updated. This is true
--  whenever the RAM has data (RAM_EMPTY is false), and either RAM_Valid is
--  false (indicating that Stage1 needs updating), or preloadstage2 is active
--  (indicating that Stage2 is going to update, so Stage1, therefore, must
--  also be updated to keep it valid.  
--------------------------------------------------------------------------------  
  preloadstage1 < = (((NOT ram_valid_i) OR preloadstage2) AND (NOT FIFOEMPTY));

--------------------------------------------------------------------------------
-- Calculate RAM_REGOUT_EN
--  The output registers are controlled by the ram_regout_en signal.
--  These registers should be updated either when the output in Stage2 is
--  invalid (preloadstage2), OR when the user is reading, in which case the
--  Stage2 value will go invalid unless it is replenished.
--------------------------------------------------------------------------------
  ram_regout_en < = preloadstage2;

--------------------------------------------------------------------------------
-- Calculate RAM_RD_EN
--   RAM_RD_EN will be asserted whenever the RAM needs to be read in order to 
--  update the value in Stage1.
--   One case when this happens is when preloadstage1=true, which indicates
--  that the data in Stage1 or Stage2 is invalid, and needs to automatically
--  be updated.
--   The other case is when the user is reading from the FIFO, which guarantees
--  that Stage1 or Stage2 will be invalid on the next clock cycle, unless it is
--  replinished by data from the memory. So, as long as the RAM has data in it,
--  a read of the RAM should occur. 
--------------------------------------------------------------------------------  
  ram_rd_en     < = (RD_EN AND NOT FIFOEMPTY) OR preloadstage1;

--------------------------------------------------------------------------------
-- Calculate ram_valid
--   ram_valid indicates that the data in Stage1 is valid.
--
--   If the RAM is being read from on this clock cycle (ram_rd_en=1), then
--   ram_valid is certainly going to be true.
--   If the RAM is not being read from, but the output registers are being
--   updated to fill Stage2 (ram_regout_en=1), then Stage1 will be emptying,
--   therefore causing ram_valid to be false.
--   Otherwise, ram_valid will remain unchanged.
--------------------------------------------------------------------------------  
  regout_valid: PROCESS (RD_CLK, RD_RST)
  BEGIN  -- PROCESS regout_valid
    IF RD_RST = '1' THEN                -- asynchronous reset (active high)
      ram_valid_i < = '0';
    ELSIF RD_CLK'event AND RD_CLK = '1' THEN  -- rising clock edge
      IF ram_rd_en = '1' THEN
        ram_valid_i < = '1';
      ELSE
        IF ram_regout_en = '1' THEN
          ram_valid_i < = '0';
        ELSE
          ram_valid_i < = ram_valid_i;
        END IF;          
      END IF;      
    END IF;
  END PROCESS regout_valid;

--------------------------------------------------------------------------------
-- Calculate READ_DATA_VALID
--  READ_DATA_VALID indicates whether the value in Stage2 is valid or not.
--  Stage2 has valid data whenever Stage1 had valid data and ram_regout_en_i=1,
--  such that the data in Stage1 is propogated into Stage2.
--------------------------------------------------------------------------------  
  regout_dvalid : PROCESS (RD_CLK, RD_RST)
  BEGIN
    IF (RD_RST='1') THEN
      read_data_valid_i < = '0';
    ELSIF (RD_CLK'event AND RD_CLK='1') THEN
      read_data_valid_i < = ram_valid_i or (read_data_valid_i and not RD_EN);
    END IF; --RD_CLK
  END PROCESS regout_dvalid;

-------------------------------------------------------------------------------
-- Calculate EMPTY
--  Defined as the inverse of READ_DATA_VALID
--
-- Description:
--
--  If read_data_valid_i indicates that the output is not valid,
-- and there is no valid data on the output of the ram to preload it
-- with, then we will report empty.
--
--  If there is no valid data on the output of the ram and we are
-- reading, then the FIFO will go empty. 
--
  
-------------------------------------------------------------------------------
  regout_empty :  PROCESS (RD_CLK, RD_RST)       --This is equivalent to (NOT read_data_valid_i)
  BEGIN
    IF (RD_RST='1') THEN
      empty_i < = '1';
      empty_q < = '1';
    ELSIF (RD_CLK'event AND RD_CLK='1') THEN
      --empty_i  < = not (ram_valid_i or (read_data_valid_i and not RD_EN));
      empty_i  < = (not ram_valid_i and not read_data_valid_i) or (not ram_valid_i and RD_EN);      
      empty_q  < = empty_i;    
    END IF; --RD_CLK
  END PROCESS regout_empty;

-------------------------------------------------------------------------------
-- Calculate user_almost_empty
--  user_almost_empty is defined such that, unless more words are written
--  to the FIFO, the next read will cause the FIFO to go EMPTY.
--
--  In most cases, whenever the output registers are updated (due to a user
-- read or a preload condition), then user_almost_empty will update to
-- whatever RAM_EMPTY is.
--
--  The exception is when the output is valid, the user is not reading, and
-- Stage1 is not empty. In this condition, Stage1 will be preloaded from the
-- memory, so we need to make sure user_almost_empty deasserts properly under
-- this condition.
-------------------------------------------------------------------------------
  regout_aempty: PROCESS (RD_CLK, RD_RST)
  BEGIN  -- PROCESS regout_empty
    IF RD_RST = '1' THEN                -- asynchronous reset (active high)
      almost_empty_i < = '1';
      almost_empty_q < = '1';
    ELSIF RD_CLK'event AND RD_CLK = '1' THEN  -- rising clock edge
      IF ((ram_regout_en = '1') OR (FIFOEMPTY = '0' AND read_data_valid_i = '1' AND  RD_EN='0')) THEN
        almost_empty_i < = FIFOEMPTY;
      END IF;
      almost_empty_q   < = almost_empty_i;
    END IF;
  END PROCESS regout_aempty;

  USEREMPTY < = empty_i;
  USERALMOSTEMPTY < = almost_empty_i;
  FIFORDEN  < = ram_rd_en;
  RAMVALID  < = ram_valid_i;

  guvh: if C_USERVALID_LOW=0 generate
    USERVALID < = read_data_valid_i;
  end generate guvh;
  guvl: if C_USERVALID_LOW=1 generate
    USERVALID < = not read_data_valid_i;
  end generate guvl;
  
  gufh: if C_USERUNDERFLOW_LOW=0 generate
    USERUNDERFLOW < = empty_q AND RD_EN;    
  end generate gufh;
  gufl: if C_USERUNDERFLOW_LOW=1 generate
    USERUNDERFLOW < = not (empty_q AND RD_EN);    
  end generate gufl;

  regout_lat0: PROCESS (RD_CLK, RD_RST)
  BEGIN  -- PROCESS regout_lat0
    IF RD_RST = '1' THEN              -- asynchronous reset (active high)
      USERDATA < = hexstr_to_std_logic_vec(C_DOUT_RST_VAL, C_DOUT_WIDTH);
    ELSIF RD_CLK'event AND RD_CLK = '1' THEN  -- rising clock edge
      IF (ram_regout_en = '1') THEN
        USERDATA < = FIFODATA;
      END IF;         
    END IF;
  END PROCESS regout_lat0;  



  

end generate p0ga;



  
END behavioral;