----------------------------------------------------------------------------------------------
--
-- Generated by X-HDL Verilog Translator - Version 4.0.0 Apr. 30, 2006
-- Wed Jun 17 2009 00:53:40
--
--      Input file      : /home/samsonn/SandBox_LBranch_11.2/env/Databases/ip/src2/L/mig_v3_2/data/dlib/virtex6/ddr3_sdram/verilog/rtl/controller/rank_cntrl.v
--      Component name  : rank_cntrl
--      Author          : 
--      Company         : 
--
--      Description     : 
--
--
----------------------------------------------------------------------------------------------

library UNISIM;
library ieee;
   use ieee.std_logic_1164.all;
   use ieee.std_logic_unsigned.all;
   use ieee.std_logic_arith.all;
 --  use UNISIM.VCOMPONENTS.all;


-- This block is responsible for managing various rank level timing
-- parameters.  For now, only Four Activate Window (FAW) and Write
-- To Read delay are implemented here.
--
-- Each rank machine generates its own inhbt_act_faw_r and inhbt_rd_r.
-- These per rank machines are driven into the bank machines.  Each
-- bank machines selects the correct inhibits based on the rank
-- of its current request.

entity rank_cntrl is
   generic (
      TCQ                        : integer := 100;
      BURST_MODE                 : string := "8";
      ID                         : integer := 0;
      nBANK_MACHS                : integer := 4;
      nCK_PER_CLK                : integer := 2;
      CL                         : integer := 5;
      nFAW                       : integer := 30;
      nREFRESH_BANK              : integer := 8;
      nRRD                       : integer := 4;
      nWTR                       : integer := 4;
      PERIODIC_RD_TIMER_DIV      : integer := 20;
      RANK_BM_BV_WIDTH           : integer := 16;
      RANK_WIDTH                 : integer := 2;
      RANKS                      : integer := 4;
      PHASE_DETECT               : string := "OFF"; --Added to control periodic reads
      REFRESH_TIMER_DIV          : integer := 39
   );
   port (
      -- Outputs
      -- Inputs
      
      -- ceiling logb2
      
      inhbt_act_faw_r            : out std_logic;
      
      inhbt_rd_r                 : out std_logic;
      wtr_inhbt_config_r         : out std_logic;
      
      refresh_request            : out std_logic;     
      periodic_rd_request        : out std_logic;
      clk                        : in std_logic;
      rst                        : in std_logic;
      sending_row                : in std_logic_vector(nBANK_MACHS - 1 downto 0);
      act_this_rank_r            : in std_logic_vector(RANK_BM_BV_WIDTH - 1 downto 0);
      sending_col                : in std_logic_vector(nBANK_MACHS - 1 downto 0);
      wr_this_rank_r             : in std_logic_vector(RANK_BM_BV_WIDTH - 1 downto 0);
      app_ref_req                : in std_logic;
      dfi_init_complete          : in std_logic;
      rank_busy_r                : in std_logic_vector((RANKS * nBANK_MACHS) - 1 downto 0);
      refresh_tick               : in std_logic;
      insert_maint_r1            : in std_logic;
      maint_zq_r                 : in std_logic;
      maint_rank_r               : in std_logic_vector(RANK_WIDTH - 1 downto 0);
      app_periodic_rd_req        : in std_logic;
      maint_prescaler_tick_r     : in std_logic;
      clear_periodic_rd_request  : in std_logic;
      rd_this_rank_r             : in std_logic_vector(RANK_BM_BV_WIDTH - 1 downto 0)
   );
end entity rank_cntrl;

architecture trans of rank_cntrl is

component SRLC32E
  generic (
     INIT : bit_vector := X"00000000"
  );
  port (
     Q : out STD_ULOGIC;
     Q31 : out STD_ULOGIC;
     A : in STD_LOGIC_VECTOR (4 downto 0);
     CE : in STD_ULOGIC;
     CLK : in STD_ULOGIC;
     D : in STD_ULOGIC
  );
end component;

function REDUCTION_OR( A: in std_logic_vector) return std_logic is
  variable tmp : std_logic := '0';
begin
  for i in A'range loop
       tmp := tmp or A(i);
  end loop;
  return tmp;
end function REDUCTION_OR;


function REDUCTION_NOR( A: in std_logic_vector) return std_logic is
  variable tmp : std_logic := '0';
begin
  for i in A'range loop
       tmp := tmp or A(i);
  end loop;
  return not tmp;
end function REDUCTION_NOR;


function f_ADD_RRD (nCK_PER_CLK: integer; nRRD : integer )
return integer is
begin

if (nCK_PER_CLK = 1) then
    return (nRRD - 2);
else 
    return ( nRRD - 4);
    
end if ;
end function f_ADD_RRD;


function f_RRD_CLKS(nCK_PER_CLK: integer; nADD_RRD : integer )
return integer is
begin

if (nCK_PER_CLK = 1) then
    return (nADD_RRD);
else 
    return (nADD_RRD/2 + (nADD_RRD mod 2));
    
end if ;
end function f_RRD_CLKS;

function f_FAW_CLKS(nCK_PER_CLK: integer; nFAW : integer )
return integer is
begin

if (nCK_PER_CLK = 1) then
    return (nFAW);
else 
    return (nFAW/2 + (nFAW mod 2));
    
end if ;
end function f_FAW_CLKS;


function clogb2(size: integer) return integer is
   variable tmp : integer range 0 to 24;

begin
  tmp := 0;

  for i in 23 downto 0 loop  
    if( size <= 2** i) then 
    tmp := i; 
    end if;
  end loop;
  return tmp;
end function clogb2;


function f_CASWR2CASRD (nWTR: integer; CL : integer ;BURST_MODE : string)
return integer is
begin

   if (BURST_MODE = "4") then
        return ( 2 + nWTR + CL );
   else
        return (4 + nWTR + CL);
   end if;
    
end function f_CASWR2CASRD;

function f_CASWR2CASRD_CLKS(nCK_PER_CLK: integer; CASWR2CASRD : integer )
return integer is
begin

if (nCK_PER_CLK = 1) then
    return (CASWR2CASRD);
else 
    return (CASWR2CASRD/2 + (CASWR2CASRD mod 2));
    
end if ;
end function f_CASWR2CASRD_CLKS;

function BOOLEAN_TO_STD_LOGIC(A : in BOOLEAN) return std_logic is
begin
   if A = true then
       return '1';
   else
       return '0';
   end if;
end function BOOLEAN_TO_STD_LOGIC;

function CALC_RANK_BUSY (my_rank_busy: std_logic; rank_busy_r : std_logic_vector)
return std_logic is
variable tmp : std_logic;
begin
    tmp := my_rank_busy;
    for i in 0 to  nBANK_MACHS - 1 loop
       tmp := tmp or rank_busy_r((i * RANKS) + ID);
    end loop;
    return tmp;
end function CALC_RANK_BUSY;


   constant nADD_RRD                : integer := f_ADD_RRD(nCK_PER_CLK, nRRD);   
   constant nRRD_CLKS               : integer := f_RRD_CLKS(nCK_PER_CLK,nADD_RRD); 
   constant ADD_RRD_CNTR_WIDTH      : integer := clogb2(nRRD_CLKS + 1);

   constant nFAW_CLKS               : integer := f_FAW_CLKS(nCK_PER_CLK ,nFAW);
   constant ONE                     : integer := 1;
   
   constant CASWR2CASRD             : integer := f_CASWR2CASRD(nWTR,CL,BURST_MODE );
   constant CASWR2CASRD_CLKS        : integer := f_CASWR2CASRD_CLKS(nCK_PER_CLK,CASWR2CASRD);
   
   constant WTR_CNT_WIDTH           : integer := clogb2(CASWR2CASRD_CLKS - 1);
   constant TWO                     : integer := 2;
   constant REFRESH_BANK_WIDTH      : integer := clogb2(nREFRESH_BANK + 1);
   constant PERIODIC_RD_TIMER_WIDTH : integer := clogb2(PERIODIC_RD_TIMER_DIV + 1);



   signal act_this_rank             : std_logic;
   signal i                         : integer;
   signal add_rrd_inhbt             : std_logic := '0';
   signal faw_cnt_ns,faw_cnt_r      : std_logic_vector(2 downto 0);
   signal periodic_rd_timer_r       : std_logic_vector(PERIODIC_RD_TIMER_WIDTH-1 downto 0);
   signal periodic_rd_timer_ns       : std_logic_vector(PERIODIC_RD_TIMER_WIDTH-1 downto 0);
   signal periodic_rd_request_ns       : std_logic;
   signal periodic_rd_request_r       : std_logic;
   
    signal add_rrd_r       : std_logic_vector(ADD_RRD_CNTR_WIDTH-1 downto 0);
    signal add_rrd_ns       : std_logic_vector(ADD_RRD_CNTR_WIDTH-1 downto 0);
   signal shift_depth               : std_logic_vector(4 downto 0);
   signal act_delayed             : std_logic;
   signal inhbt_act_faw_ns          : std_logic;
   signal write_this_rank             : std_logic;
    signal wtr_cnt_r       : std_logic_vector(WTR_CNT_WIDTH-1 downto 0);
    signal wtr_cnt_ns       : std_logic_vector(WTR_CNT_WIDTH-1 downto 0);
   signal inhbt_rd_ns       : std_logic;
   signal wtr_inhbt_config_ns       : std_logic;
   signal read_this_rank            : std_logic;
   signal read_this_rank_tmp        : std_logic;
   signal my_rank_busy              : std_logic;
   signal refresh_bank_r       : std_logic_vector(REFRESH_BANK_WIDTH-1 downto 0);
   signal refresh_bank_ns       : std_logic_vector(REFRESH_BANK_WIDTH-1 downto 0);
   signal my_refresh            : std_logic;
   signal periodic_rd_timer_one : std_logic;
   
   signal int1 : std_logic_vector(2 downto 0);
begin
   process (act_this_rank_r, sending_row)
   variable act_this_rank_tmp : std_logic;
   begin
      act_this_rank_tmp := '0';
      for i in 0 to  nBANK_MACHS - 1 loop
         act_this_rank_tmp := act_this_rank_tmp or (sending_row(i) and act_this_rank_r((i * RANKS) + ID));
      end loop;
      
      act_this_rank <= act_this_rank_tmp;
   end process;
   
   int0 : if (nADD_RRD > 0) generate
      process (act_this_rank, add_rrd_r, rst)
      begin
         add_rrd_ns <= add_rrd_r;
         if (rst = '1') then
            add_rrd_ns <= (others => '0');
         elsif (act_this_rank = '1') then
            add_rrd_ns <= conv_std_logic_vector(nRRD_CLKS, ADD_RRD_CNTR_WIDTH);
         elsif ((REDUCTION_OR(add_rrd_r)) = '1') then
            add_rrd_ns <= add_rrd_r - '1';
         end if;
      end process;
      
      process (clk)
      begin
         if (clk'event and clk = '1') then
            add_rrd_r <= add_rrd_ns after (TCQ)*1 ps;
         end if;
      end process;
      
      process (add_rrd_ns)
      begin
         add_rrd_inhbt <= REDUCTION_OR(add_rrd_ns);
      end process;
      
   end generate;
   shift_depth <= conv_std_logic_vector(nFAW_CLKS, 5) - "00011";
   
   
   SRLC32E0 : SRLC32E
      generic map (
         init  => "00000000000000000000000000000000"
      )
      port map (
         q    => act_delayed,
         q31  => open,
         a    => shift_depth,
         ce   => '1',
         clk  => clk,
         d    => act_this_rank
      );
   process (act_delayed, act_this_rank, add_rrd_inhbt, faw_cnt_r, rst)
   variable faw_cnt_ns_tmp : std_logic_vector(2 downto 0);
   begin
      if (rst = '1') then
         faw_cnt_ns_tmp := "000";
      else
         faw_cnt_ns_tmp := faw_cnt_r;
         if (act_this_rank = '1') then
            faw_cnt_ns_tmp := faw_cnt_r + "001";
         end if;
         if (act_delayed = '1') then
            faw_cnt_ns_tmp := faw_cnt_ns_tmp - "001";
         end if;
      end if;
      
      faw_cnt_ns <= faw_cnt_ns_tmp;
      inhbt_act_faw_ns <= BOOLEAN_TO_STD_LOGIC(faw_cnt_ns_tmp = "100") or add_rrd_inhbt;
   end process;
   
   process (clk)
   begin
      if (clk'event and clk = '1') then
         faw_cnt_r <= faw_cnt_ns after (TCQ)*1 ps;
      end if;
   end process;
   
   process (clk)
   begin
      if (clk'event and clk = '1') then
         inhbt_act_faw_r <= inhbt_act_faw_ns after (TCQ)*1 ps;
      end if;
   end process;
   
   process (sending_col, wr_this_rank_r)
   variable write_this_rank_tmp : std_logic;
   begin
      write_this_rank_tmp := '0';
      for i in 0 to  nBANK_MACHS - 1 loop
         write_this_rank_tmp := write_this_rank_tmp or (sending_col(i) and wr_this_rank_r((i * RANKS) + ID));
      end loop;
      
      write_this_rank <= write_this_rank_tmp;
   end process;
   
   process (rst, write_this_rank, wtr_cnt_r)
    variable wtr_cnt_ns_tmp       : std_logic_vector(WTR_CNT_WIDTH-1 downto 0);
   
   begin
      if (rst = '1') then
         wtr_cnt_ns_tmp := (others => '0');
      else
         wtr_cnt_ns_tmp := wtr_cnt_r;
         if (write_this_rank = '1') then
            wtr_cnt_ns_tmp := conv_std_logic_vector(CASWR2CASRD_CLKS, WTR_CNT_WIDTH) - conv_std_logic_vector(2,WTR_CNT_WIDTH);
         elsif ((REDUCTION_OR(wtr_cnt_r)) = '1') then
            wtr_cnt_ns_tmp := wtr_cnt_r - conv_std_logic_vector(1, WTR_CNT_WIDTH);
         end if;
      end if;
      
      wtr_cnt_ns <= wtr_cnt_ns_tmp;
      
   end process;
   
   inhbt_rd_ns <= REDUCTION_OR(wtr_cnt_ns);
   wtr_inhbt_config_ns <= BOOLEAN_TO_STD_LOGIC(wtr_cnt_ns >= conv_std_logic_vector(2,WTR_CNT_WIDTH));
   process (clk)
   begin
      if (clk'event and clk = '1') then
         wtr_cnt_r <= wtr_cnt_ns after (TCQ)*1 ps;
      end if;
   end process;
   
   process (clk)
   begin
      if (clk'event and clk = '1') then
         inhbt_rd_r <= inhbt_rd_ns after (TCQ)*1 ps;
      end if;
   end process;
   
   process (clk)
   begin
      if (clk'event and clk = '1') then
         wtr_inhbt_config_r <= wtr_inhbt_config_ns after (TCQ)*1 ps;
      end if;
   end process;
   
   process (rank_busy_r)
   begin
      my_rank_busy <= CALC_RANK_BUSY('0',rank_busy_r);
      --my_rank_busy <= '0';
      --for i in 0 to  nBANK_MACHS - 1 loop
      --   my_rank_busy <= my_rank_busy or rank_busy_r((i * RANKS) + ID);
      --end loop;
   end process;
   
   my_refresh <= insert_maint_r1 and not(maint_zq_r) and BOOLEAN_TO_STD_LOGIC(maint_rank_r = conv_std_logic_vector(ID,RANK_WIDTH));
   int1 <= my_refresh & refresh_tick & app_ref_req;
   process (app_ref_req, dfi_init_complete, my_refresh, refresh_bank_r, refresh_tick,int1)
   begin
      if ((not(dfi_init_complete)) = '1') then
         if (REFRESH_TIMER_DIV = 0) then
            refresh_bank_ns <= conv_std_logic_vector(nREFRESH_BANK, REFRESH_BANK_WIDTH);
         else
            refresh_bank_ns <= ( others => '0' );
         end if;
      else
         case int1 is
            when "000" | "110" | "101" | "111" =>
               refresh_bank_ns <= refresh_bank_r;
            when "010" | "001" | "011" =>
               if ( REDUCTION_OR(refresh_bank_r) = '1' ) then
                   refresh_bank_ns <= refresh_bank_r - '1';
               else
                   refresh_bank_ns <= refresh_bank_r;
               end if;
            when "100" =>
               refresh_bank_ns <= refresh_bank_r + '1';
            when others =>
               null;
         end case;
      end if;
   end process;
   
   process (clk)
   begin
      if (clk'event and clk = '1') then
         refresh_bank_r <= refresh_bank_ns after (TCQ)*1 ps;
      end if;
   end process;
   
   refresh_request <= dfi_init_complete and 
                  (REDUCTION_NOR(refresh_bank_r) or 
   (BOOLEAN_TO_STD_LOGIC(refresh_bank_r /= conv_std_logic_vector(nREFRESH_BANK, REFRESH_BANK_WIDTH)) and not(my_rank_busy)));
   
   enable_periodic_reads : if ( not(PHASE_DETECT = "OFF") ) generate

      process (rd_this_rank_r, sending_col)
      variable read_this_rank_tmp : std_logic;
      begin
         read_this_rank_tmp := '0';
         for i in 0 to  nBANK_MACHS - 1 loop
            read_this_rank_tmp := read_this_rank_tmp or (sending_col(i) and rd_this_rank_r((i * RANKS) + ID));
         end loop;
         
         read_this_rank <= read_this_rank_tmp;
      end process;
      
      
      process (dfi_init_complete, maint_prescaler_tick_r, periodic_rd_timer_r, read_this_rank)
      begin
         periodic_rd_timer_ns <= periodic_rd_timer_r;
         if ((not(dfi_init_complete)) = '1') then
            periodic_rd_timer_ns <= (others => '0' );
         elsif (read_this_rank = '1') then
            periodic_rd_timer_ns <= conv_std_logic_vector(PERIODIC_RD_TIMER_DIV, PERIODIC_RD_TIMER_WIDTH);
         elsif ((REDUCTION_OR(periodic_rd_timer_r) and maint_prescaler_tick_r) = '1') then
            periodic_rd_timer_ns <= periodic_rd_timer_r - '1';
         end if;
      end process;
      
      
      process (clk)
      begin
         if (clk'event and clk = '1') then
            
            periodic_rd_timer_r <= periodic_rd_timer_ns after (TCQ)*1 ps;
         end if;
      end process;
      
      periodic_rd_timer_one <= maint_prescaler_tick_r and BOOLEAN_TO_STD_LOGIC((periodic_rd_timer_r = conv_std_logic_vector(1,PERIODIC_RD_TIMER_WIDTH)));
      
      periodic_rd_request_ns <= not(rst) and 
                               ((app_periodic_rd_req and dfi_init_complete) or 
                                (BOOLEAN_TO_STD_LOGIC(PERIODIC_RD_TIMER_DIV /= 0) and not(dfi_init_complete)) or
                                (not(read_this_rank or clear_periodic_rd_request) and 
                                (periodic_rd_request_r or periodic_rd_timer_one)));
      process (clk)
      begin
         if (clk'event and clk = '1') then
            
            periodic_rd_request_r <= periodic_rd_request_ns after (TCQ)*1 ps;
         end if;
      end process;
      
      periodic_rd_request <= dfi_init_complete and periodic_rd_request_r;

   end generate;

   disable_periodic_reads : if ( PHASE_DETECT = "OFF" ) generate
      periodic_rd_request <= '0';
   end generate;
   
   
end architecture trans;


