--------------------------------------------------------------------------------
-- VECTREX
--------------------------------------------------------------------------------
-- Graphic Generator
-- Vector draw to framebuffer image

--------------------------------------------------------------------------------
-- DO 8/2017
--------------------------------------------------------------------------------

-- CACHE
-- 16 bits / pixel
-- Bursts 8 * 32bits = 16 pixels

--  XXXXXXXX XXXXXXXX  
--  XXXXXXXX XXXXXXXX
--  XXXXXXXX XXXXXXXX
--  XXXXXXXX XXXXXXXX
--  XXXXXXXX XXXXXXXX
--  XXXXXXXX XXXXXXXX
--  XXXXXXXX XXXXXXXX
--  XXXXXXXX XXXXXXXX
--  XXXXXXXX XXXXXXXX
--  XXXXXXXX XXXXXXXX
--  XXXXXXXX XXXXXXXX
--  XXXXXXXX XXXXXXXX
--  XXXXXXXX XXXXXXXX
--  XXXXXXXX XXXXXXXX
--  XXXXXXXX XXXXXXXX
--  XXXXXXXX XXXXXXXX

-- Screen 1024x768 : X[9:0], Y[9:0]

-- 9  8  7  6  5  4  3  2  1  0  9  8  7  6  5  4  3  2  1  0
-- [            Y             ] [             X             ]

--20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
--[             Y             ] [             X             ] pix
--[     TAG       ] [ In]  0  0 [   TAG      ] Idx [  Line  ] pix
--+ Valid + Modified

-- TAG :
--  12 11 10  9  8  7  6  5  4  3  2  1  0
--   V  M [    Y[9:4]     ]  [  X[9:5]   ]


LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

USE std.textio.ALL;

LIBRARY work;
USE work.base_pack.ALL;

ENTITY vecgraph IS
  PORT (
    --------------------------
    -- Pixels drawn
    spot_x  : IN  uv16;
    spot_y  : IN  uv16;
    spot_z  : IN  uv8;
    spot_en : IN std_logic;
    
    --------------------------
    -- Cache line to refresh
    fresh_a   : IN unsigned(20 DOWNTO 5);
    fresh_req : IN std_logic;
    
    --------------------------
    date  : IN uv8;

    vpos  : IN uv12;
    vcomp : IN uv8;
    
    over  : IN std_logic;
    lumi  : IN uv3;
    shape : IN uv2;

    efifo_lev : OUT uv16;
    efifofresh_lev : OUT uv16;
    efifoclr_lev : OUT uv16;
    
    --------------------------
    -- Avalon
    avl_waitrequest   : IN  std_logic;
    avl_readdata      : IN  std_logic_vector(31 DOWNTO 0);
    avl_readdatavalid : IN  std_logic;
    avl_burstcount    : OUT std_logic_vector(7 DOWNTO 0);
    avl_writedata     : OUT std_logic_vector(31 DOWNTO 0);
    avl_address       : OUT std_logic_vector(18 DOWNTO 0);
    avl_write         : OUT std_logic;
    avl_read          : OUT std_logic;
    avl_byteenable    : OUT std_logic_vector(3 DOWNTO 0);
    
    --------------------------
    clk      : IN  std_logic;
    reset_na : IN  std_logic
    );
END ENTITY vecgraph;

ARCHITECTURE rtl OF vecgraph IS

  --------------------------------------
  -- Pixels FIFO
  TYPE type_pix IS RECORD
    x : uv16;
    y : uv16;
    z : uv8;
  END RECORD;
  TYPE arr_uv24 IS ARRAY (natural RANGE <>) OF unsigned(39 DOWNTO 0);
  CONSTANT FIFO_SIZE : natural :=512;
  SIGNAL fifopix : arr_uv24(0 TO FIFO_SIZE-1);
  ATTRIBUTE ramstyle : string;
  ATTRIBUTE ramstyle OF fifopix : SIGNAL IS "no_rw_check";
  SIGNAL fifopix_nf,fifopix_wr : std_logic;
  SIGNAL fifo_in,fifo_out : natural RANGE 0 TO FIFO_SIZE-1;
  SIGNAL fifo_ne : std_logic;
  SIGNAL fifo_pop : std_logic;
  SIGNAL pix : type_pix;
  SIGNAL pixi,pixo : unsigned(39 DOWNTO 0);
  SIGNAL px_z2 : uv8;
  SIGNAL fifo_lev : uv16;
  
  --------------------------------------
  -- Fresh FIFO
  CONSTANT FIFOFRESH_SIZE : natural := 2048;
  TYPE arr_adfresh IS ARRAY (natural RANGE <>) OF unsigned(20 DOWNTO 5);
  
  SIGNAL fifofresh : arr_adfresh(0 TO FIFOFRESH_SIZE-1);
  ATTRIBUTE ramstyle OF fifofresh : SIGNAL IS "no_rw_check";
  SIGNAL fifofresh_in,fifofresh_out : natural RANGE 0 TO FIFOFRESH_SIZE-1;
  SIGNAL fifofresh_ne : std_logic;
  SIGNAL fifofresh_pop : std_logic;
  SIGNAL fresh_ra : unsigned(20 DOWNTO 5);
  SIGNAL fifofresh_lev : uv16;
  
  --------------------------------------
  -- CLR FIFO
  SIGNAL fifoclr : arr_adfresh(0 TO FIFOFRESH_SIZE-1);
  ATTRIBUTE ramstyle OF fifoclr : SIGNAL IS "no_rw_check";
  SIGNAL fifoclr_in,fifoclr_out : natural RANGE 0 TO FIFOFRESH_SIZE-1;
  SIGNAL fifoclr_ne : std_logic;
  SIGNAL fifoclr_pop : std_logic;
  SIGNAL clr_ra,clr_a : unsigned(20 DOWNTO 5);
  SIGNAL fifoclr_lev : uv16;
  SIGNAL clr_req : std_logic;
  
  --------------------------------------
  -- Crible
  SIGNAL cri : arr_uv32(0 TO 2047) :=(OTHERS =>x"0000_0000");
  ATTRIBUTE ramstyle OF cri : SIGNAL IS "no_rw_check";
  SIGNAL cri_a,cricpt : unsigned(10 DOWNTO 0);
  SIGNAL cri_wr : std_logic;
  SIGNAL cri_dr,cri_dw : uv32;
  TYPE enum_erastate IS (sIDLE,
                         sSET,sSET2,sCLR,sCLR2,
                         sCRI,sCRI2,sCRI3
                         );
  SIGNAL erastate : enum_erastate;
  
  SIGNAL crib_req, crib_ack : std_logic;
  SIGNAL crib_ra : unsigned(20 DOWNTO 5);

  SIGNAL avl_address_i : std_logic_vector(18 DOWNTO 0);

  --------------------------------------
  FUNCTION ench(CONSTANT a : unsigned(1 DOWNTO 0)) RETURN unsigned IS
  BEGIN
    CASE a IS
      WHEN "00" => RETURN "10";
      WHEN "01" => RETURN "00";
      WHEN "10" => RETURN "01";
      WHEN OTHERS => RETURN "00";
    END CASE;
  END FUNCTION ench;
  
  FUNCTION czi(
    CONSTANT n : IN natural;
    CONSTANT i : IN unsigned) RETURN unsigned IS
    VARIABLE v : unsigned(i'length-1 DOWNTO 0):=i;  
  BEGIN
    IF v(n-1)='0' THEN
      RETURN (v(2*n-1) AND v(n-1)) & '0' & v(n-2 DOWNTO 0);
    ELSE
      RETURN (v(2*n-1) AND v(n-1)) & NOT v(2*n-1) & v(2*n-2 DOWNTO n);
    END IF;
  END FUNCTION czi;
  
  FUNCTION cpos (CONSTANT v : unsigned(31 DOWNTO 0)) RETURN unsigned IS
    VARIABLE e : unsigned(31 DOWNTO 0);     -- 32
    VARIABLE a : unsigned(8*3-1 DOWNTO 0);  -- 24
    VARIABLE b : unsigned(4*4-1 DOWNTO 0);  -- 16
    VARIABLE c : unsigned(2*5-1 DOWNTO 0);  -- 10
  BEGIN
    FOR i IN 0 TO 15 LOOP
      e(i*2+1 DOWNTO i*2):=ench(v(i*2+1 DOWNTO i*2));  END LOOP;
    FOR i IN 0 TO 7 LOOP
      a(i*3+2 DOWNTO i*3):=czi(2,e(i*4+3 DOWNTO i*4)); END LOOP;
    FOR i IN 0 TO 3 LOOP
      b(i*4+3 DOWNTO i*4):=czi(3,a(i*6+5 DOWNTO i*6)); END LOOP;
    FOR i IN 0 TO 1 LOOP
      c(i*5+4 DOWNTO i*5):=czi(4,b(i*8+7 DOWNTO i*8)); END LOOP;
    RETURN czi(5,c(9 DOWNTO 0));
  END FUNCTION cpos;
  
  --------------------------------------
  -- Cache DATA
  SIGNAL cache0_dh,cache1_dh,cache2_dh,cache3_dh : arr_uv16(0 TO 255);
  SIGNAL cache0_dl,cache1_dl,cache2_dl,cache3_dl : arr_uv16(0 TO 255);
  ATTRIBUTE ramstyle OF cache0_dh : SIGNAL IS "no_rw_check";
  ATTRIBUTE ramstyle OF cache1_dh : SIGNAL IS "no_rw_check";
  ATTRIBUTE ramstyle OF cache2_dh : SIGNAL IS "no_rw_check";
  ATTRIBUTE ramstyle OF cache3_dh : SIGNAL IS "no_rw_check";
  ATTRIBUTE ramstyle OF cache0_dl : SIGNAL IS "no_rw_check";
  ATTRIBUTE ramstyle OF cache1_dl : SIGNAL IS "no_rw_check";
  ATTRIBUTE ramstyle OF cache2_dl : SIGNAL IS "no_rw_check";
  ATTRIBUTE ramstyle OF cache3_dl : SIGNAL IS "no_rw_check";
  
  -- Cache TAGS
  TYPE arr_uv13 IS ARRAY(natural RANGE <>) OF uv13;
  SIGNAL cache0_t,cache1_t,cache2_t,cache3_t : arr_uv13(0 TO 31) :=(OTHERS =>"0000000000000");
  
  SIGNAL cache0_d_dw,cache0_d_dr  : uv32;
  SIGNAL cache1_d_dw,cache1_d_dr  : uv32;
  SIGNAL cache2_d_dw,cache2_d_dr  : uv32;
  SIGNAL cache3_d_dw,cache3_d_dr  : uv32;
  SIGNAL cache0_d_dr2  : uv32;
  SIGNAL cache1_d_dr2  : uv32;
  SIGNAL cache2_d_dr2  : uv32;
  SIGNAL cache3_d_dr2  : uv32;
  SIGNAL cache_d_dr2x : uv32;
  
  SIGNAL cache0_t_dr,cache0_t_dw : uv13; -- V M [ Y ] [ X ]
  SIGNAL cache1_t_dr,cache1_t_dw : uv13; -- V M [ Y ] [ X ]
  SIGNAL cache2_t_dr,cache2_t_dw : uv13; -- V M [ Y ] [ X ]
  SIGNAL cache3_t_dr,cache3_t_dw : uv13; -- V M [ Y ] [ X ]
  
  SIGNAL cache0_d_wrh,cache0_d_wrl,cache0_t_wr : std_logic;
  SIGNAL cache1_d_wrh,cache1_d_wrl,cache1_t_wr : std_logic;
  SIGNAL cache2_d_wrh,cache2_d_wrl,cache2_t_wr : std_logic;
  SIGNAL cache3_d_wrh,cache3_d_wrl,cache3_t_wr : std_logic;
  
  SIGNAL cache0_d_ra,cache1_d_ra,cache2_d_ra,cache3_d_ra : uv8;
  SIGNAL cache0_d_wa,cache0_d_wam : uv8;
  SIGNAL cache1_d_wa,cache1_d_wam : uv8;
  SIGNAL cache2_d_wa,cache2_d_wam : uv8;
  SIGNAL cache3_d_wa,cache3_d_wam : uv8;
  SIGNAL cache0_t_ra,cache0_t_wa,cache0_t_wam : uv5;
  SIGNAL cache1_t_ra,cache1_t_wa,cache1_t_wam : uv5;
  SIGNAL cache2_t_ra,cache2_t_wa,cache2_t_wam : uv5;
  SIGNAL cache3_t_ra,cache3_t_wa,cache3_t_wam : uv5;
  
  SIGNAL cache0_t_dwa,cache0_t_dwa_c : uv11;
  SIGNAL cache1_t_dwa,cache1_t_dwa_c : uv11;
  SIGNAL cache2_t_dwa,cache2_t_dwa_c : uv11;
  SIGNAL cache3_t_dwa,cache3_t_dwa_c : uv11;
  
  SIGNAL mem_x,mem_x_c : uv10;
  SIGNAL mem0_y,mem0_y_c : uv10;
  SIGNAL mem1_y,mem1_y_c : uv10;
  SIGNAL mem2_y,mem2_y_c : uv10;
  SIGNAL mem3_y,mem3_y_c : uv10;
  
  TYPE enum_state IS (sIDLE,sIM0,sIM1,
                      sWBACK,sWBACK2,sWBACK3,sWBACK_PRE,
                      sLOAD,sLOAD2,sLOAD_PRE,
                      sFRESH);
  SIGNAL state,state_c : enum_state;
  
  SIGNAL way,way_c : natural RANGE 0 TO 3;
  
  --------------------------------------
  -- Oversampling 2x -> 4 patterns
  CONSTANT pat : arr_uv8(0 TO 64*4-1) :=
    (x"00",x"00",x"00",x"00",
     x"00",x"28",x"1F",x"00",
     x"00",x"1F",x"18",x"00",
     x"00",x"00",x"00",x"00",

     x"00",x"00",x"00",x"00",
     x"00",x"00",x"48",x"00",
     x"00",x"00",x"37",x"00",
     x"00",x"00",x"00",x"00",

     x"00",x"00",x"00",x"00",
     x"00",x"00",x"00",x"00",
     x"00",x"48",x"37",x"00",
     x"00",x"00",x"00",x"00",

     x"00",x"00",x"00",x"00",
     x"00",x"00",x"00",x"00",
     x"00",x"00",x"7F",x"00",
     x"00",x"00",x"00",x"00",
     -----------------------------------
     x"80",x"00",x"00",x"00",
     x"00",x"80",x"00",x"00",
     x"00",x"00",x"80",x"00",
     x"00",x"00",x"00",x"80",
     
     x"80",x"00",x"00",x"00",
     x"00",x"80",x"00",x"00",
     x"00",x"00",x"80",x"00",
     x"00",x"00",x"00",x"80",
     
     x"80",x"00",x"00",x"00",
     x"00",x"80",x"00",x"00",
     x"00",x"00",x"80",x"00",
     x"00",x"00",x"00",x"80",
     
     x"80",x"00",x"00",x"00",
     x"00",x"80",x"00",x"00",
     x"00",x"00",x"80",x"00",
     x"00",x"00",x"00",x"80",
     
     -----------------------------------
     x"04",x"08",x"08",x"04",
     x"08",x"28",x"1F",x"08",
     x"08",x"1F",x"18",x"08",
     x"04",x"08",x"08",x"04",

     x"04",x"08",x"08",x"04",
     x"08",x"08",x"48",x"08",
     x"08",x"08",x"37",x"08",
     x"04",x"08",x"08",x"04",

     x"04",x"08",x"08",x"04",
     x"08",x"08",x"08",x"08",
     x"08",x"48",x"37",x"08",
     x"04",x"08",x"08",x"04",

     x"04",x"08",x"08",x"04",
     x"08",x"08",x"08",x"08",
     x"08",x"08",x"7F",x"08",
     x"04",x"08",x"08",x"04",
     
     -----------------------------------
     x"10",x"20",x"20",x"10",
     x"20",x"70",x"70",x"20",
     x"20",x"70",x"70",x"20",
     x"10",x"20",x"20",x"10",
     
     x"10",x"20",x"20",x"10",
     x"20",x"70",x"70",x"20",
     x"20",x"70",x"70",x"20",
     x"10",x"20",x"20",x"10",
     
     x"10",x"20",x"20",x"10",
     x"20",x"70",x"70",x"20",
     x"20",x"70",x"70",x"20",
     x"10",x"20",x"20",x"10",
     
     x"10",x"20",x"20",x"10",
     x"20",x"70",x"70",x"20",
     x"20",x"70",x"70",x"20",
     x"10",x"20",x"20",x"10"
     );
  
  CONSTANT pat0,pat1,pat2,pat3 : arr_uv8 :=pat;
  
  SIGNAL pix_cpt,pix_cpt_c : uv2;
  SIGNAL pat0_dr,pat1_dr,pat2_dr,pat3_dr  : uv8;
  SIGNAL pat0_a,pat1_a,pat2_a,pat3_a   : uv6;
  
  --------------------------------------
  SIGNAL cptburst,cptburst_c : uv3;
  SIGNAL wei,wei_c : std_logic;
  TYPE enum_ori IS (ORI_FRESH,ORI_IM);
  -- FRESH : [WBACK si mod] + [LOAD addresse à rafraichir] + retour IDLE
  --  l'adresse vient de l'extérieur
  -- IM    : [WBACK si mod] + [LOAD addresse cherchée]     + retour IM0
  --  pas d'adresse à fournir, juste un numéro de ligne
  
  SIGNAL ori,ori_c : enum_ori;
  
  -- 15:8 : Date
  --  7:0 : Intensity

  FUNCTION lum(
    i    : uv16;
    lumi : uv3) RETURN unsigned IS
    VARIABLE m : unsigned(18 DOWNTO 0);
  BEGIN
    CASE lumi IS
      WHEN "000"  => m:=i & "000";
      WHEN "001"  => m:=('0' & i & "00" ) + ("00" & i & '0') + ("000" & i);
      WHEN "010"  => m:=('0' & i & "00" ) + ("00" & i & '0')              ;
      WHEN "011"  => m:=('0' & i & "00" )                    + ("000" & i);
      WHEN "100"  => m:=('0' & i & "00" )                                 ;
      WHEN "101"  => m:=                    ("00" & i & '0') + ("000" & i);
      WHEN "110"  => m:=                    ("00" & i & '0')              ;
      WHEN OTHERS => m:=                                       ("000" & i);
    END CASE;
    RETURN m(18 DOWNTO 3);
  END FUNCTION lum;
  
  FUNCTION calc(
    pi  : uv16; -- PIX_IN
    z   : uv8;  -- Intensity spot
    pat : uv8;  -- Weigth in the pattern
    date: uv8;
    lumi: uv3) RETURN unsigned IS -- Current Datecode
    VARIABLE po : uv16;
    VARIABLE delay : uv8;
    VARIABLE zi,zr : uv8; -- Intensity before, after
    VARIABLE sum,d2 : uv9;
  BEGIN
    
    po:=z*pat; -- New Intensity
    po:=lum(po,lumi);
    
    zi:=po(15 DOWNTO 8);
    
    delay:=date-pi(15 DOWNTO 8); -- Time since last update

    d2:=delay & '0';
    IF delay>=x"80" THEN
      zr:=x"00";
    ELSE
      IF (delay & '0')>('0' & pi(7 DOWNTO 0)) THEN -- Linear decay
        zr:=x"00";
      ELSE
        zr:=pi(7 DOWNTO 0)-(delay(6 DOWNTO 0) & '0');
      END IF;
    END IF;
    
    -- Add new intensity to previous decayed value.
    sum:=('0' & zi) + ('0' & zr);
    IF sum(8)='1' THEN
      sum(7 DOWNTO 0):=x"FF";
    END IF;

    po:=date & sum(7 DOWNTO 0);
    RETURN po;
  END FUNCTION calc;
  
  -- Scrub old pixels
  FUNCTION fixold16(v    : uv16;
                    date : uv8) RETURN unsigned IS
    VARIABLE delay : uv8;
  BEGIN
    delay:=date-v(15 DOWNTO 8);
    IF delay>=x"C0" THEN
      RETURN x"0000";
    ELSE
      RETURN v;
    END IF;
  END FUNCTION;

  FUNCTION fixold32(v    : uv32;
                    date : uv8) RETURN unsigned IS
  BEGIN
    RETURN fixold16(v(31 DOWNTO 16),date) & fixold16(v(15 DOWNTO 0) ,date);
  END FUNCTION;
  
BEGIN
  
  ------------------------------------------------------------------------------
  -- PIXELS FIFOs : Pixels to draw
  MEMFIFOPIX:PROCESS(clk) IS
  BEGIN
    IF rising_edge(clk) THEN
      IF fifopix_wr='1' THEN
        fifopix(fifo_in)<=pixi;
      END IF;
    END IF;
  END PROCESS MEMFIFOPIX;

  pixo<=fifopix(fifo_out);
  pix<=type_pix'(x=>pixo(15 DOWNTO 0),y=>pixo(31 DOWNTO 16),
                 z=>pixo(39 DOWNTO 32));
  pixi<=spot_z & spot_y & spot_x;
  fifopix_wr<=spot_en AND fifopix_nf;
  
  FIFO:PROCESS(clk,reset_na) IS
    VARIABLE inc,dec : std_logic;
  BEGIN
    IF reset_na='0' THEN
      fifo_in<=0;
      fifo_out<=0;
      fifo_ne<='0';
      fifo_lev<=x"0000";
      
    ELSIF rising_edge(clk) THEN
      inc:='0';
      dec:='0';
      fifopix_nf<=to_std_logic(fifo_lev<FIFO_SIZE-2);
      
      IF fifopix_wr='1' THEN
        fifo_in<=(fifo_in+1) MOD FIFO_SIZE;
        fifo_ne<='1';
        inc:='1';
      END IF;
      IF fifo_pop='1' THEN
        fifo_out<=(fifo_out+1) MOD FIFO_SIZE;
        IF ((fifo_out+1) MOD FIFO_SIZE=fifo_in) AND spot_en='0' THEN
          fifo_ne<='0';
        END IF;
        dec:='1';
      END IF;
      
      IF inc='1' AND dec='0' THEN
        fifo_lev<=fifo_lev+1;
      ELSIF inc='0' AND dec='1' THEN
        fifo_lev<=fifo_lev-1;
      END IF;
    END IF;
  END PROCESS FIFO;
  
  ------------------------------------------------------------------------------
  -- FIFO for pending refresh commands.
  FIFOLU:PROCESS(clk,reset_na) IS
    VARIABLE inc,dec : std_logic;
  BEGIN
    IF reset_na='0' THEN
      fifofresh_in<=0;
      fifofresh_out<=0;
      fifofresh_ne<='0';
      fifofresh_lev<=x"0000";
    ELSIF rising_edge(clk) THEN
      inc:='0';
      dec:='0';
      IF fresh_req='1' THEN --AND ((fifofresh_in+1) MOD FIFOFRESH_SIZE/=fifofresh_out) THEN
        fifofresh(fifofresh_in)<=fresh_a;
        fifofresh_in<=(fifofresh_in+1) MOD FIFOFRESH_SIZE;
        fifofresh_ne<='1';
        inc:='1';
      END IF;
      IF fifofresh_pop='1' THEN
        fifofresh_out<=(fifofresh_out+1) MOD FIFOFRESH_SIZE;
        IF ((fifofresh_out+1) MOD FIFOFRESH_SIZE=fifofresh_in) AND fresh_req='0'
        THEN
          fifofresh_ne<='0';
        END IF;
        dec:='1';
      END IF;
      IF inc='1' AND dec='0' THEN
        fifofresh_lev<=fifofresh_lev+1;
      ELSIF inc='0' AND dec='1' THEN
        fifofresh_lev<=fifofresh_lev-1;
      END IF;
      
    END IF;
  END PROCESS FIFOLU;

  fresh_ra<=fifofresh(fifofresh_out);
  
  ------------------------------------------------------------------------------
  -- FIFO for pending clr commands
  FIFOCLRP:PROCESS(clk,reset_na) IS
    VARIABLE inc,dec : std_logic;
  BEGIN
    IF reset_na='0' THEN
      fifoclr_in<=0;
      fifoclr_out<=0;
      fifoclr_ne<='0';
      fifoclr_lev<=x"0000";
    ELSIF rising_edge(clk) THEN
      inc:='0';
      dec:='0';
      IF clr_req='1' THEN --AND ((fifofresh_in+1) MOD FIFOFRESH_SIZE/=fifofresh_out) THEN
        fifoclr(fifoclr_in)<=clr_a;
        fifoclr_in<=(fifoclr_in+1) MOD FIFOFRESH_SIZE;
        fifoclr_ne<='1';
        inc:='1';
      END IF;
      IF fifoclr_pop='1' THEN
        fifoclr_out<=(fifoclr_out+1) MOD FIFOFRESH_SIZE;
        IF ((fifoclr_out+1) MOD FIFOFRESH_SIZE=fifoclr_in) AND clr_req='0'
        THEN
          fifoclr_ne<='0';
        END IF;
        dec:='1';
      END IF;
      IF inc='1' AND dec='0' THEN
        fifoclr_lev<=fifoclr_lev+1;
      ELSIF inc='0' AND dec='1' THEN
        fifoclr_lev<=fifoclr_lev-1;
      END IF;
      
    END IF;
  END PROCESS FIFOCLRP;

  clr_ra<=fifoclr(fifoclr_out);

  ------------------------------------------------------------------------------
  -- Crible
  MEMCrible:PROCESS(clk) IS
  BEGIN
    IF rising_edge(clk) THEN
      IF cri_wr='1' THEN
        cri(to_integer(cri_a))<=cri_dw;
      END IF;
    END IF;
  END PROCESS MEMCrible;

  cri_dr<=cri(to_integer(cri_a));

  -- FRESH_A [20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5] 4  3  2  1  0
  --   CRI_A [10  9  8  7  6  5  4  3  2  1  0] [ Bit number ] [ CacheLine ]
  
  Erato:PROCESS(clk,reset_na) IS
    VARIABLE dv : unsigned(5 DOWNTO 0);
  BEGIN
    IF reset_na='0' THEN
      cricpt<=(OTHERS =>'0');
      
    ELSIF rising_edge(clk) THEN
      cri_wr<='0';
      fifofresh_pop<='0';
      fifoclr_pop<='0';
      crib_req<='0';
      
      CASE erastate IS
        ------------------------------
        WHEN sIDLE =>
          IF fifofresh_ne='1' AND fifofresh_pop='0' THEN
            cri_a<=fresh_ra(20 DOWNTO 10);
            erastate<=sSET;
            
          ELSIF fifoclr_ne='1' AND fifoclr_pop='0' THEN
            cri_a<=clr_ra(20 DOWNTO 10);
            erastate<=sCLR;
            
          ELSIF crib_req='0' AND fifo_ne='0' THEN
            cri_a<=cricpt;
            erastate<=sCRI;
          END IF;
          
        ------------------------------
        WHEN sSET =>
          erastate<=sSET2;
          
        WHEN sSET2 =>
          cri_dw<=cri_dr;
          cri_dw(to_integer(fresh_ra(9 DOWNTO 5)))<='1';
          cri_wr<='1';
          erastate<=sIDLE;
          fifofresh_pop<='1';

        ------------------------------
        WHEN sCLR =>
          erastate<=sCLR2;
          
        WHEN sCLR2 =>
          cri_dw<=cri_dr;
          cri_dw(to_integer(clr_ra(9 DOWNTO 5)))<='0';
          cri_wr<='1';
          erastate<=sIDLE;
          fifoclr_pop<='1';
          
        ------------------------------
        WHEN sCRI =>
          erastate<=sCRI2;
          
        WHEN sCRI2 =>
          IF cri_dr/=x"0000_0000" THEN
            erastate<=sCRI3;
          ELSE
            erastate<=sIDLE;
            cricpt<=cricpt+1;
            IF cricpt>"10111111111" THEN
              cricpt<="00000000000";
            END IF;
          END IF;

        WHEN sCRI3 =>
          dv:=cpos(cri_dr);
          crib_ra<=cricpt & dv(4 DOWNTO 0);
          crib_req<='1';
          cri_dw<=cri_dr;
          cri_dw(to_integer(dv(4 DOWNTO 0)))<='0';
          IF crib_ack='1' AND crib_req='1' THEN
            cri_wr<='1';
            crib_req<='0';
            erastate<=sIDLE;
          END IF;
        ------------------------------
      END CASE;
    END IF;
  END PROCESS Erato;
  
  clr_a<=unsigned(avl_address_i(18 DOWNTO 3));
  
  ------------------------------------------------------------------------------
  Mems:PROCESS (clk) IS
  BEGIN
    IF rising_edge(clk) THEN
      ----------------------------------
      -- DATA
      cache0_d_dr(31 DOWNTO 16)<=cache0_dh(to_integer(cache0_d_ra));
      cache0_d_dr(15 DOWNTO  0)<=cache0_dl(to_integer(cache0_d_ra));

      IF cache0_d_wrh='1' THEN
        cache0_dh(to_integer(cache0_d_wa))<=cache0_d_dw(31 DOWNTO 16);
      END IF;

      IF cache0_d_wrl='1' THEN
        cache0_dl(to_integer(cache0_d_wa))<=cache0_d_dw(15 DOWNTO 0);
      END IF;
      
      -- TAGS
      cache0_t_dr<=cache0_t(to_integer(cache0_t_ra));
      IF cache0_t_wr='1' THEN
        cache0_t(to_integer(cache0_t_wa))<=cache0_t_dw;
      END IF;

      ----------------------------------
      -- DATA
      cache1_d_dr(31 DOWNTO 16)<=cache1_dh(to_integer(cache1_d_ra));
      cache1_d_dr(15 DOWNTO  0)<=cache1_dl(to_integer(cache1_d_ra));

      IF cache1_d_wrh='1' THEN
        cache1_dh(to_integer(cache1_d_wa))<=cache1_d_dw(31 DOWNTO 16);
      END IF;

      IF cache1_d_wrl='1' THEN
        cache1_dl(to_integer(cache1_d_wa))<=cache1_d_dw(15 DOWNTO 0);
      END IF;
      
      -- TAGS
      cache1_t_dr<=cache1_t(to_integer(cache1_t_ra));
      IF cache1_t_wr='1' THEN
        cache1_t(to_integer(cache1_t_wa))<=cache1_t_dw;
      END IF;

      ----------------------------------
      -- DATA
      cache2_d_dr(31 DOWNTO 16)<=cache2_dh(to_integer(cache2_d_ra));
      cache2_d_dr(15 DOWNTO  0)<=cache2_dl(to_integer(cache2_d_ra));

      IF cache2_d_wrh='1' THEN
        cache2_dh(to_integer(cache2_d_wa))<=cache2_d_dw(31 DOWNTO 16);
      END IF;

      IF cache2_d_wrl='1' THEN
        cache2_dl(to_integer(cache2_d_wa))<=cache2_d_dw(15 DOWNTO 0);
      END IF;
      
      -- TAGS
      cache2_t_dr<=cache2_t(to_integer(cache2_t_ra));
      IF cache2_t_wr='1' THEN
        cache2_t(to_integer(cache2_t_wa))<=cache2_t_dw;
      END IF;

      ----------------------------------
      -- DATA
      cache3_d_dr(31 DOWNTO 16)<=cache3_dh(to_integer(cache3_d_ra));
      cache3_d_dr(15 DOWNTO  0)<=cache3_dl(to_integer(cache3_d_ra));

      IF cache3_d_wrh='1' THEN
        cache3_dh(to_integer(cache3_d_wa))<=cache3_d_dw(31 DOWNTO 16);
      END IF;

      IF cache3_d_wrl='1' THEN
        cache3_dl(to_integer(cache3_d_wa))<=cache3_d_dw(15 DOWNTO 0);
      END IF;
      
      -- TAGS
      cache3_t_dr<=cache3_t(to_integer(cache3_t_ra));
      IF cache3_t_wr='1' THEN
        cache3_t(to_integer(cache3_t_wa))<=cache3_t_dw;
      END IF;
      
      ----------------------------------
      -- Patterns
      pat0_dr<=pat0(to_integer(shape & pat0_a));
      pat1_dr<=pat1(to_integer(shape & pat1_a));
      pat2_dr<=pat2(to_integer(shape & pat2_a));
      pat3_dr<=pat3(to_integer(shape & pat3_a));
      
    END IF;
  END PROCESS Mems;
  
  --------------------------------------
  Comb:PROCESS (state,fifo_ne,date,vpos,vcomp,
                pix_cpt,pix,way,lumi,
                cache0_d_dr,cache1_d_dr,cache2_d_dr,cache3_d_dr,
                cache0_t_dwa,cache1_t_dwa,cache2_t_dwa,cache3_t_dwa,
                wei,ori,over,
                px_z2,pat0_dr,pat1_dr,pat2_dr,pat3_dr,
                cache0_t_dr,cache1_t_dr,cache2_t_dr,cache3_t_dr,
                cache_d_dr2x,cptburst,
                mem_x,mem0_y,mem1_y,mem2_y,mem3_y,
                avl_waitrequest,avl_readdata,avl_readdatavalid,
                cache0_t_wam,cache1_t_wam,cache2_t_wam,cache3_t_wam,
                cache0_d_wam,cache1_d_wam,cache2_d_wam,cache3_d_wam,
                crib_req,avl_address_i,crib_ra) IS
    VARIABLE x_v,y0_v,y1_v,y2_v,y3_v : uv10;
    VARIABLE line0_v,line1_v,line2_v,line3_v : uv5;
    VARIABLE over_v : uv2;
    VARIABLE dr_v : uv32;
    VARIABLE pixin_v,pixout_v : uv16;
    VARIABLE da_v : uv8;
    
  BEGIN
    fifo_pop<='0';
    cache0_d_wrl<='0';
    cache1_d_wrl<='0';
    cache2_d_wrl<='0';
    cache3_d_wrl<='0';
    cache0_d_wrh<='0';
    cache1_d_wrh<='0';
    cache2_d_wrh<='0';
    cache3_d_wrh<='0';
    cache0_t_wr<='0';
    cache1_t_wr<='0';
    cache2_t_wr<='0';
    cache3_t_wr<='0';
    avl_write<='0';
    avl_read<='0';
    
    clr_req<='0';
    state_c<=state;
    way_c<=way;

    x_v:=pix.x(15 DOWNTO 6) + pix_cpt;
    y0_v:=pix.y(15 DOWNTO 6) + "00";
    y1_v:=pix.y(15 DOWNTO 6) + "01";
    y2_v:=pix.y(15 DOWNTO 6) + "10";
    y3_v:=pix.y(15 DOWNTO 6) + "11";

    CASE y0_v(1 DOWNTO 0) IS
      WHEN "00" =>
        line0_v:=y0_v(3 DOWNTO 2) & "00" & x_v(4); -- Cache line number
        line1_v:=y1_v(3 DOWNTO 2) & "00" & x_v(4); -- Cache line number
        line2_v:=y2_v(3 DOWNTO 2) & "00" & x_v(4); -- Cache line number
        line3_v:=y3_v(3 DOWNTO 2) & "00" & x_v(4); -- Cache line number
        cache0_t_dwa_c<=y0_v(9 DOWNTO 4) & x_v(9 DOWNTO 5); -- Tagged adrs
        cache1_t_dwa_c<=y1_v(9 DOWNTO 4) & x_v(9 DOWNTO 5); -- Tagged adrs
        cache2_t_dwa_c<=y2_v(9 DOWNTO 4) & x_v(9 DOWNTO 5); -- Tagged adrs
        cache3_t_dwa_c<=y3_v(9 DOWNTO 4) & x_v(9 DOWNTO 5); -- Tagged adrs
        mem0_y_c<=y0_v;
        mem1_y_c<=y1_v;
        mem2_y_c<=y2_v;
        mem3_y_c<=y3_v;
        pat0_a<=over_v & "00" & pix_cpt; -- Pattern adrs
        pat1_a<=over_v & "01" & pix_cpt; -- Pattern adrs
        pat2_a<=over_v & "10" & pix_cpt; -- Pattern adrs
        pat3_a<=over_v & "11" & pix_cpt; -- Pattern adrs
        
      WHEN "11" =>
        line0_v:=y1_v(3 DOWNTO 2) & "00" & x_v(4); -- Cache line number
        line1_v:=y2_v(3 DOWNTO 2) & "00" & x_v(4); -- Cache line number
        line2_v:=y3_v(3 DOWNTO 2) & "00" & x_v(4); -- Cache line number
        line3_v:=y0_v(3 DOWNTO 2) & "00" & x_v(4); -- Cache line number
        cache0_t_dwa_c<=y1_v(9 DOWNTO 4) & x_v(9 DOWNTO 5); -- Tagged adrs
        cache1_t_dwa_c<=y2_v(9 DOWNTO 4) & x_v(9 DOWNTO 5); -- Tagged adrs
        cache2_t_dwa_c<=y3_v(9 DOWNTO 4) & x_v(9 DOWNTO 5); -- Tagged adrs
        cache3_t_dwa_c<=y0_v(9 DOWNTO 4) & x_v(9 DOWNTO 5); -- Tagged adrs
        mem0_y_c<=y1_v;
        mem1_y_c<=y2_v;
        mem2_y_c<=y3_v;
        mem3_y_c<=y0_v;
        pat0_a<=over_v & "01" & pix_cpt; -- Pattern adrs
        pat1_a<=over_v & "10" & pix_cpt; -- Pattern adrs
        pat2_a<=over_v & "11" & pix_cpt; -- Pattern adrs
        pat3_a<=over_v & "00" & pix_cpt; -- Pattern adrs
        
      WHEN "10" =>
        line0_v:=y2_v(3 DOWNTO 2) & "00" & x_v(4); -- Cache line number
        line1_v:=y3_v(3 DOWNTO 2) & "00" & x_v(4); -- Cache line number
        line2_v:=y0_v(3 DOWNTO 2) & "00" & x_v(4); -- Cache line number
        line3_v:=y1_v(3 DOWNTO 2) & "00" & x_v(4); -- Cache line number
        cache0_t_dwa_c<=y2_v(9 DOWNTO 4) & x_v(9 DOWNTO 5); -- Tagged adrs
        cache1_t_dwa_c<=y3_v(9 DOWNTO 4) & x_v(9 DOWNTO 5); -- Tagged adrs
        cache2_t_dwa_c<=y0_v(9 DOWNTO 4) & x_v(9 DOWNTO 5); -- Tagged adrs
        cache3_t_dwa_c<=y1_v(9 DOWNTO 4) & x_v(9 DOWNTO 5); -- Tagged adrs
        mem0_y_c<=y2_v;
        mem1_y_c<=y3_v;
        mem2_y_c<=y0_v;
        mem3_y_c<=y1_v;
        pat0_a<=over_v & "10" & pix_cpt; -- Pattern adrs
        pat1_a<=over_v & "11" & pix_cpt; -- Pattern adrs
        pat2_a<=over_v & "00" & pix_cpt; -- Pattern adrs
        pat3_a<=over_v & "01" & pix_cpt; -- Pattern adrs
        
      WHEN OTHERS => -- "01"
        line0_v:=y3_v(3 DOWNTO 2) & "00" & x_v(4); -- Cache line number
        line1_v:=y0_v(3 DOWNTO 2) & "00" & x_v(4); -- Cache line number
        line2_v:=y1_v(3 DOWNTO 2) & "00" & x_v(4); -- Cache line number
        line3_v:=y2_v(3 DOWNTO 2) & "00" & x_v(4); -- Cache line number
        cache0_t_dwa_c<=y3_v(9 DOWNTO 4) & x_v(9 DOWNTO 5); -- Tagged adrs
        cache1_t_dwa_c<=y0_v(9 DOWNTO 4) & x_v(9 DOWNTO 5); -- Tagged adrs
        cache2_t_dwa_c<=y1_v(9 DOWNTO 4) & x_v(9 DOWNTO 5); -- Tagged adrs
        cache3_t_dwa_c<=y2_v(9 DOWNTO 4) & x_v(9 DOWNTO 5); -- Tagged adrs
        mem0_y_c<=y3_v;
        mem1_y_c<=y0_v;
        mem2_y_c<=y1_v;
        mem3_y_c<=y2_v;
        pat0_a<=over_v & "11" & pix_cpt; -- Pattern adrs
        pat1_a<=over_v & "00" & pix_cpt; -- Pattern adrs
        pat2_a<=over_v & "01" & pix_cpt; -- Pattern adrs
        pat3_a<=over_v & "10" & pix_cpt; -- Pattern adrs
        
    END CASE;
    
    over_v:=pix.y(5) & pix.x(5); -- Oversampling
    IF over='0' THEN
      over_v:="00";
    END IF;
    
    cache0_t_dw<="11" & cache0_t_dwa;
    cache1_t_dw<="11" & cache1_t_dwa;
    cache2_t_dw<="11" & cache2_t_dwa;
    cache3_t_dw<="11" & cache3_t_dwa;
    
    cache0_d_ra<=line0_v & x_v(3 DOWNTO 1);
    cache1_d_ra<=line1_v & x_v(3 DOWNTO 1);
    cache2_d_ra<=line2_v & x_v(3 DOWNTO 1);
    cache3_d_ra<=line3_v & x_v(3 DOWNTO 1);
    
    cache0_t_ra<=line0_v;
    cache1_t_ra<=line1_v;
    cache2_t_ra<=line2_v;
    cache3_t_ra<=line3_v;
    
    mem_x_c<=x_v; -- MEM_x/y est différent pour refresh.
    
    wei_c<=wei;
    ori_c<=ori;
    
    IF y0_v<vpos THEN da_v:=date-vcomp; ELSE da_v:=date; END IF;
    
    -- Mix old paint with new
    dr_v:=cache0_d_dr;
    cache0_d_dw(31 DOWNTO 16)<=calc(dr_v(31 DOWNTO 16),px_z2,pat0_dr,da_v,lumi);
    cache0_d_dw(15 DOWNTO  0)<=calc(dr_v(15 DOWNTO  0),px_z2,pat0_dr,da_v,lumi);
    dr_v:=cache1_d_dr;
    cache1_d_dw(31 DOWNTO 16)<=calc(dr_v(31 DOWNTO 16),px_z2,pat1_dr,da_v,lumi);
    cache1_d_dw(15 DOWNTO  0)<=calc(dr_v(15 DOWNTO  0),px_z2,pat1_dr,da_v,lumi);
    dr_v:=cache2_d_dr;
    cache2_d_dw(31 DOWNTO 16)<=calc(dr_v(31 DOWNTO 16),px_z2,pat2_dr,da_v,lumi);
    cache2_d_dw(15 DOWNTO  0)<=calc(dr_v(15 DOWNTO  0),px_z2,pat2_dr,da_v,lumi);
    dr_v:=cache3_d_dr;
    cache3_d_dw(31 DOWNTO 16)<=calc(dr_v(31 DOWNTO 16),px_z2,pat3_dr,da_v,lumi);
    cache3_d_dw(15 DOWNTO  0)<=calc(dr_v(15 DOWNTO  0),px_z2,pat3_dr,da_v,lumi);
    
    crib_ack<='0';
    cache0_t_wa<=cache0_t_wam;
    cache1_t_wa<=cache1_t_wam;
    cache2_t_wa<=cache2_t_wam;
    cache3_t_wa<=cache3_t_wam;
    cache0_d_wa<=cache0_d_wam;
    cache1_d_wa<=cache1_d_wam;
    cache2_d_wa<=cache2_d_wam;
    cache3_d_wa<=cache3_d_wam;
    
    avl_address_i<=std_logic_vector(crib_ra) & "000";
    cptburst_c<=cptburst;
    pix_cpt_c <=pix_cpt;
    avl_writedata<=std_logic_vector(cache_d_dr2x);
    
    --------------------------------------------------------
    
    CASE state IS
      ------------------------------------------------------
      WHEN sIDLE =>
        pix_cpt_c<="00";
        cptburst_c<="000";
        ori_c<=ORI_FRESH;
        
        IF crib_req='1' THEN
          state_c<=sFRESH;
        ELSIF fifo_ne='1' THEN
          -- Pixel FIFO is not empty,  let's update 16 pixels !
          state_c<=sIM0;
          ori_c<=ORI_IM;
          
        --IF fifo_ne='1' THEN
        --  -- Pixel FIFO is not empty,  let's update 16 pixels !
        --  state_c<=sIM0;
        --  ori_c<=ORI_IM;
          
        --ELSIF crib_req='1' THEN
        --  state_c<=sFRESH;
          
        END IF;
        
      ------------------------------------------------------
      WHEN sIM0 =>
        pix_cpt_c<=pix_cpt+1;
        state_c<=sIM1;
        IF fifo_ne='0' THEN
          state_c<=sIDLE;
        END IF;
        
      WHEN sIM1 =>
        pix_cpt_c<=pix_cpt+1;
        IF cache0_t_dr(10 DOWNTO 0)/=cache0_t_dwa THEN
          pix_cpt_c<=pix_cpt-1;
          IF cache0_t_dr(12)='0' OR cache0_t_dr(11)='0' THEN -- V=0 or M=0
            state_c<=sLOAD_PRE;
          ELSE -- V=1 & M=1 : Write-back
            state_c<=sWBACK_PRE;
          END IF;
          way_c<=0;
        ELSIF cache1_t_dr(10 DOWNTO 0)/=cache1_t_dwa THEN
          pix_cpt_c<=pix_cpt-1;
          IF cache1_t_dr(12)='0' OR cache1_t_dr(11)='0' THEN -- V=0 or M=0
            state_c<=sLOAD_PRE;
          ELSE -- V=1 & M=1 : Write-back
            state_c<=sWBACK_PRE;
          END IF;
          way_c<=1;
        ELSIF cache2_t_dr(10 DOWNTO 0)/=cache2_t_dwa THEN
          pix_cpt_c<=pix_cpt-1;
          IF cache2_t_dr(12)='0' OR cache2_t_dr(11)='0' THEN -- V=0 or M=0
            state_c<=sLOAD_PRE;
          ELSE -- V=1 & M=1 : Write-back
            state_c<=sWBACK_PRE;
          END IF;
          way_c<=2;
        ELSIF cache3_t_dr(10 DOWNTO 0)/=cache3_t_dwa THEN
          pix_cpt_c<=pix_cpt-1;
          IF cache3_t_dr(12)='0' OR cache3_t_dr(11)='0' THEN -- V=0 or M=0
            state_c<=sLOAD_PRE;
          ELSE -- V=1 & M=1 : Write-back
            state_c<=sWBACK_PRE;
          END IF;
          way_c<=3;
        ELSE
          -- Cache hit, to the next pixel...
          cache0_d_wrl<=mem_x(0);
          cache0_d_wrh<=NOT mem_x(0);
          cache1_d_wrl<=mem_x(0);
          cache1_d_wrh<=NOT mem_x(0);
          cache2_d_wrl<=mem_x(0);
          cache2_d_wrh<=NOT mem_x(0);
          cache3_d_wrl<=mem_x(0);
          cache3_d_wrh<=NOT mem_x(0);
          
          cache0_t_wr<='1';
          cache1_t_wr<='1';
          cache2_t_wr<='1';
          cache3_t_wr<='1';
          IF pix_cpt="11" THEN
            fifo_pop<='1';
            state_c<=sIM0; --IDLE;
          END IF;
          
        END IF;
        
        ------------------------------------------------------
      WHEN sWBACK_PRE =>
        state_c<=sWBACK;
        
      WHEN sWBACK =>
        IF ori=ORI_IM THEN
          cache0_d_ra<=mem0_y(3 DOWNTO 2) & "00" & mem_x(4) & "000";
          cache1_d_ra<=mem1_y(3 DOWNTO 2) & "00" & mem_x(4) & "000";
          cache2_d_ra<=mem2_y(3 DOWNTO 2) & "00" & mem_x(4) & "000";
          cache3_d_ra<=mem3_y(3 DOWNTO 2) & "00" & mem_x(4) & "000";
          cache0_t_ra<=mem0_y(3 DOWNTO 2) & "00" & mem_x(4);
          cache1_t_ra<=mem1_y(3 DOWNTO 2) & "00" & mem_x(4);
          cache2_t_ra<=mem2_y(3 DOWNTO 2) & "00" & mem_x(4);
          cache3_t_ra<=mem3_y(3 DOWNTO 2) & "00" & mem_x(4);
        ELSE -- FRESH
          cache0_d_ra<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5) & "000";
          cache1_d_ra<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5) & "000";
          cache2_d_ra<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5) & "000";
          cache3_d_ra<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5) & "000";
          cache0_t_ra<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5);
          cache1_t_ra<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5);
          cache2_t_ra<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5);
          cache3_t_ra<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5);
        END IF;
        
        state_c<=sWBACK2;
        cptburst_c<="001";
        wei_c<='0';
        
      WHEN sWBACK2 =>
        -- Write back modified entries in the cache
        avl_write<='1';
        
        IF ori=ORI_IM THEN
          CASE way IS
            WHEN 0 =>
              avl_address_i<=std_logic_vector(
                cache0_t_dr(10 DOWNTO 5) & mem0_y(3 DOWNTO 2) & "00" &
                cache0_t_dr(4 DOWNTO 0) & mem_x(4)) & "000";
            WHEN 1 =>
              avl_address_i<=std_logic_vector(
                cache1_t_dr(10 DOWNTO 5) & mem1_y(3 DOWNTO 2) & "01" &
                cache1_t_dr(4 DOWNTO 0) & mem_x(4)) & "000";
            WHEN 2 =>
              avl_address_i<=std_logic_vector(
                cache2_t_dr(10 DOWNTO 5) & mem2_y(3 DOWNTO 2) & "10" &
                cache2_t_dr(4 DOWNTO 0) & mem_x(4)) & "000";
            WHEN 3 =>
              avl_address_i<=std_logic_vector(
                cache3_t_dr(10 DOWNTO 5) & mem3_y(3 DOWNTO 2) & "11" &
                cache3_t_dr(4 DOWNTO 0) & mem_x(4)) & "000";
          END CASE;     
          
          cache0_d_ra<=mem0_y(3 DOWNTO 2) & "00" & mem_x(4) & cptburst;
          cache1_d_ra<=mem1_y(3 DOWNTO 2) & "00" & mem_x(4) & cptburst;
          cache2_d_ra<=mem2_y(3 DOWNTO 2) & "00" & mem_x(4) & cptburst;
          cache3_d_ra<=mem3_y(3 DOWNTO 2) & "00" & mem_x(4) & cptburst;
          cache0_t_ra<=mem0_y(3 DOWNTO 2) & "00" & mem_x(4);
          cache1_t_ra<=mem1_y(3 DOWNTO 2) & "00" & mem_x(4);
          cache2_t_ra<=mem2_y(3 DOWNTO 2) & "00" & mem_x(4);
          cache3_t_ra<=mem3_y(3 DOWNTO 2) & "00" & mem_x(4);
          
        ELSE
          CASE way IS
            WHEN 0 =>
              avl_address_i<=std_logic_vector(
                cache0_t_dr(10 DOWNTO 5) & crib_ra(14 DOWNTO 11)  &
                cache0_t_dr(4 DOWNTO 0) & crib_ra(5)) & "000";
            WHEN 1 =>
              avl_address_i<=std_logic_vector(
                cache1_t_dr(10 DOWNTO 5) & crib_ra(14 DOWNTO 11)  &
                cache1_t_dr(4 DOWNTO 0) & crib_ra(5)) & "000";
            WHEN 2 =>
              avl_address_i<=std_logic_vector(
                cache2_t_dr(10 DOWNTO 5) & crib_ra(14 DOWNTO 11) &
                cache2_t_dr(4 DOWNTO 0) & crib_ra(5)) & "000";
            WHEN 3 =>
              avl_address_i<=std_logic_vector(
                cache3_t_dr(10 DOWNTO 5) & crib_ra(14 DOWNTO 11) &
                cache3_t_dr(4 DOWNTO 0) & crib_ra(5)) & "000";
          END CASE;
          
          cache0_d_ra<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5) & cptburst;
          cache1_d_ra<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5) & cptburst;
          cache2_d_ra<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5) & cptburst;
          cache3_d_ra<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5) & cptburst;
          cache0_t_ra<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5);
          cache1_t_ra<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5);
          cache2_t_ra<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5);
          cache3_t_ra<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5);
          
          IF (cache0_t_dr(12 DOWNTO 11)/="11" AND cptburst="001" AND way=0) OR
             (cache1_t_dr(12 DOWNTO 11)/="11" AND cptburst="001" AND way=1) OR
             (cache2_t_dr(12 DOWNTO 11)/="11" AND cptburst="001" AND way=2) OR
             (cache3_t_dr(12 DOWNTO 11)/="11" AND cptburst="001" AND way=3)
          THEN
            state_c<=sLOAD_PRE;
            avl_write<='0';
          END IF;
        END IF;
        
        IF wei='0' THEN
          CASE way IS
            WHEN 0 => avl_writedata<=std_logic_vector(cache0_d_dr);
            WHEN 1 => avl_writedata<=std_logic_vector(cache1_d_dr);
            WHEN 2 => avl_writedata<=std_logic_vector(cache2_d_dr);
            WHEN 3 => avl_writedata<=std_logic_vector(cache3_d_dr);
          END CASE;
        ELSE
          avl_writedata<=std_logic_vector(cache_d_dr2x);
        END IF;
        wei_c<=avl_waitrequest;
        
        IF avl_waitrequest='0' THEN
          cptburst_c<=cptburst+1;
          IF cptburst="000" THEN
            state_c<=sWBACK3;
          END IF;
        END IF;
        
      WHEN sWBACK3 =>
        avl_writedata<=std_logic_vector(cache_d_dr2x);
        IF wei='1' THEN
          avl_write<='1';
          IF avl_waitrequest='0' THEN
            IF ori/=ORI_FRESH THEN
              clr_req<='1';
            END IF;
            state_c<=sLOAD_PRE;
          END IF;
        ELSE
          IF ori/=ORI_FRESH THEN
            clr_req<='1';
          END IF;
          state_c<=sLOAD_PRE;
        END IF;
        
        ----------------------------------------------------
      WHEN sLOAD_PRE =>
        state_c<=sLOAD;
        
      WHEN sLOAD =>
        avl_read<='1';
        IF ori/=ORI_FRESH THEN
          CASE way IS
            WHEN 0 => avl_address_i<=std_logic_vector(mem0_y) &
                                   std_logic_vector(mem_x(9 DOWNTO 4)) & "000";
            WHEN 1 => avl_address_i<=std_logic_vector(mem1_y) &
                                    std_logic_vector(mem_x(9 DOWNTO 4)) & "000";
            WHEN 2 => avl_address_i<=std_logic_vector(mem2_y) &
                                    std_logic_vector(mem_x(9 DOWNTO 4)) & "000";
            WHEN 3 => avl_address_i<=std_logic_vector(mem3_y) &
                                    std_logic_vector(mem_x(9 DOWNTO 4)) & "000";
          END CASE;
        ELSE
          avl_address_i<=std_logic_vector(crib_ra) & "000";
        END IF;
        IF avl_waitrequest='0' THEN
          state_c<=sLOAD2;
        END IF;
        cptburst_c<="000";

      WHEN sLOAD2 =>
        IF ori/=ORI_FRESH THEN
          cache0_d_wa<=mem0_y(3 DOWNTO 2) & "00" & mem_x(4) & cptburst;
          cache1_d_wa<=mem1_y(3 DOWNTO 2) & "00" & mem_x(4) & cptburst;
          cache2_d_wa<=mem2_y(3 DOWNTO 2) & "00" & mem_x(4) & cptburst;
          cache3_d_wa<=mem3_y(3 DOWNTO 2) & "00" & mem_x(4) & cptburst;
          cache0_t_wa<=mem0_y(3 DOWNTO 2) & "00" & mem_x(4);
          cache1_t_wa<=mem1_y(3 DOWNTO 2) & "00" & mem_x(4);
          cache2_t_wa<=mem2_y(3 DOWNTO 2) & "00" & mem_x(4);
          cache3_t_wa<=mem3_y(3 DOWNTO 2) & "00" & mem_x(4);
          cache0_t_dw<="10" & mem0_y(9 DOWNTO 4) & mem_x(9 DOWNTO 5);
          cache1_t_dw<="10" & mem1_y(9 DOWNTO 4) & mem_x(9 DOWNTO 5);
          cache2_t_dw<="10" & mem2_y(9 DOWNTO 4) & mem_x(9 DOWNTO 5);
          cache3_t_dw<="10" & mem3_y(9 DOWNTO 4) & mem_x(9 DOWNTO 5);
        ELSE
          cache0_d_wa<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5) & cptburst;
          cache1_d_wa<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5) & cptburst;
          cache2_d_wa<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5) & cptburst;
          cache3_d_wa<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5) & cptburst;
          cache0_t_wa<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5);
          cache1_t_wa<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5);
          cache2_t_wa<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5);
          cache3_t_wa<=crib_ra(14 DOWNTO 13) & "00" & crib_ra(5);
          cache0_t_dw<="11" & crib_ra(20 DOWNTO 15) & crib_ra(10 DOWNTO 6);
          cache1_t_dw<="11" & crib_ra(20 DOWNTO 15) & crib_ra(10 DOWNTO 6);
          cache2_t_dw<="11" & crib_ra(20 DOWNTO 15) & crib_ra(10 DOWNTO 6);
          cache3_t_dw<="11" & crib_ra(20 DOWNTO 15) & crib_ra(10 DOWNTO 6);
        END IF;
        
        cache0_d_dw<=fixold32(unsigned(avl_readdata),date);
        cache1_d_dw<=fixold32(unsigned(avl_readdata),date);
        cache2_d_dw<=fixold32(unsigned(avl_readdata),date);
        cache3_d_dw<=fixold32(unsigned(avl_readdata),date);
        
        IF avl_readdatavalid='1' THEN
          CASE way IS
            WHEN 0 =>
              cache0_d_wrl<='1';
              cache0_d_wrh<='1';
              cache0_t_wr<='1';
            WHEN 1 =>
              cache1_d_wrl<='1';
              cache1_d_wrh<='1';
              cache1_t_wr<='1';
            WHEN 2 =>
              cache2_d_wrl<='1';
              cache2_d_wrh<='1';
              cache2_t_wr<='1';
            WHEN 3 =>
              cache3_d_wrl<='1';
              cache3_d_wrh<='1';
              cache3_t_wr<='1';
          END CASE;
          
          cptburst_c<=cptburst+1;
          IF cptburst="111" THEN
            IF ori=ORI_IM THEN
              state_c<=sIM0;
            ELSE
              state_c<=sIDLE;
            END IF;
            IF ori=ORI_FRESH THEN
              crib_ack<='1';
            END IF;
          END IF;
        END IF;
        
    --------------------------------------------------------
      WHEN sFRESH =>
        -- The framebuffer has detected old pixels, refresh memory
        state_c<=sWBACK;
        IF crib_ra(12 DOWNTO 11)="00" THEN
          way_c<=0;
        ELSIF crib_ra(12 DOWNTO 11)="01" THEN
          way_c<=1;
        ELSIF crib_ra(12 DOWNTO 11)="10" THEN
          way_c<=2;
        ELSE
          way_c<=3;
        END IF;
        
    --------------------------------------------------------
    END CASE;
      
  END PROCESS Comb;
  
  ----------------------------------------------------------
  Seq:PROCESS(clk,reset_na) IS
  BEGIN
    IF reset_na='0' THEN
      pix_cpt<="00";
      state<=sIDLE;
      
    ELSIF rising_edge(clk) THEN

      state<=state_c;
      cptburst<=cptburst_c;
      mem_x<=mem_x_c;
      mem0_y<=mem0_y_c;
      mem1_y<=mem1_y_c;
      mem2_y<=mem2_y_c;
      mem3_y<=mem3_y_c;

      ori<=ori_c;
      way<=way_c;
      
      -- Writes are pipelined, 1 cycle after reads
      cache0_t_wam<=cache0_t_ra;
      cache1_t_wam<=cache1_t_ra;
      cache2_t_wam<=cache2_t_ra;
      cache3_t_wam<=cache3_t_ra;
      cache0_d_wam<=cache0_d_ra;
      cache1_d_wam<=cache1_d_ra;
      cache2_d_wam<=cache2_d_ra;
      cache3_d_wam<=cache3_d_ra;
      
      cache0_t_dwa<=cache0_t_dwa_c;
      cache1_t_dwa<=cache1_t_dwa_c;
      cache2_t_dwa<=cache2_t_dwa_c;
      cache3_t_dwa<=cache3_t_dwa_c;
      
      cache0_d_dr2<=cache0_d_dr;
      cache1_d_dr2<=cache1_d_dr;
      cache2_d_dr2<=cache2_d_dr;
      cache3_d_dr2<=cache3_d_dr;

      IF avl_waitrequest='1' THEN
        CASE way IS
          WHEN 0 => cache_d_dr2x<=cache0_d_dr;
          WHEN 1 => cache_d_dr2x<=cache1_d_dr;
          WHEN 2 => cache_d_dr2x<=cache2_d_dr;
          WHEN 3 => cache_d_dr2x<=cache3_d_dr;
        END CASE;
      END IF;
      
      wei<=wei_c;
      px_z2<=pix.z;
      pix_cpt<=pix_cpt_c;
      
    END IF;
  END PROCESS Seq;
  
  avl_burstcount<=x"08";
  avl_byteenable<="1111";
  avl_address<=avl_address_i;
  
  efifofresh_lev<=fifofresh_lev;
  efifoclr_lev  <=fifoclr_lev;
  efifo_lev<=fifo_lev;
  
END ARCHITECTURE rtl;
