--------------------------------------------------------------------------------
-- TEM : Cyclone V
-- Interface PLOMB -> Avalon_MM
--------------------------------------------------------------------------------
-- DO 4/2015
--------------------------------------------------------------------------------

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

LIBRARY work;
USE work.base_pack.ALL;
USE work.plomb_pack.ALL;

ENTITY plomb_avalon IS
  GENERIC (
    N  : natural); -- Adresses
  PORT (
    -- PLOMB
    pw : IN  type_plomb_w;
    pr : OUT type_plomb_r;
    
    -- 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(N-3 DOWNTO 0);
    avl_write          : OUT   std_logic;
    avl_read           : OUT   std_logic;
    avl_byteenable     : OUT   std_logic_vector(3 DOWNTO 0);
    
    -- Global
    clk      : IN std_logic;
    reset_na : IN std_logic
    );
END ENTITY plomb_avalon;

--##############################################################################

ARCHITECTURE rtl OF plomb_avalon IS

  SIGNAL pr_i : type_plomb_r;
  SIGNAL prem,deja : std_logic;
  SIGNAL ack : std_logic;
  
  ---------------------------------
  CONSTANT PROF : natural := 32;
  
  SIGNAL fifo_cmd         : unsigned(0 TO PROF-1);
  SIGNAL fifo_cmd_lev     : natural RANGE 0 TO PROF-1;
  SIGNAL fifo_cmd_push_c  : std_logic;
  SIGNAL fifo_cmd_pop_c   : std_logic;
  SIGNAL fifo_cmdo        : std_logic;
  SIGNAL fifo_data        : arr_uv32(0 TO PROF-1);
  SIGNAL fifo_data_lev    : natural RANGE 0 TO PROF-1;
  SIGNAL fifo_data_push_c : std_logic;
  SIGNAL fifo_data_pop_c  : std_logic;
  SIGNAL fifo_dato        : uv32;
  
  ---------------------------------
  SIGNAL avl_address_i,avl_address_mem : std_logic_vector(N-3 DOWNTO 0);
  SIGNAL avl_writedata_i       : std_logic_vector(31 DOWNTO 0);
  SIGNAL avl_byteenable_i          : std_logic_vector(3 DOWNTO 0);
  SIGNAL avl_read_i                : std_logic;
  SIGNAL avl_write_i,avl_write_mem : std_logic;
  SIGNAL avl_burstcount_i,avl_burstcount_mem : std_logic_vector(7 DOWNTO 0);

  SIGNAL rdy,burst : std_logic;
  SIGNAL burstcpt : natural RANGE 0 TO 15;
BEGIN

  pr<=pr_i;
  avl_burstcount<=avl_burstcount_i;
  avl_address   <=avl_address_i;
  avl_read      <=avl_read_i;
  avl_write     <=avl_write_i;

  -- prem : first cycle of a Avalon transfer
  -- deja : The first cycle of a burst read was accepted on the Avalon side.
  --        Remaining accesses can be directly accepted on the PLOMB side.
  ------------------------------------------------------------------
  CombWrite:PROCESS(pw,prem,deja,avl_waitrequest,
                    avl_burstcount_mem,avl_address_mem,avl_write_mem)
  BEGIN
    IF prem='1' THEN
      -- Premier cycle
      avl_burstcount_i <=std_logic_vector(to_unsigned(pb_blen(pw),8));
      avl_address_i    <=std_logic_vector(pw.a(N-1 DOWNTO 2));
      avl_read_i       <=to_std_logic(is_read(pw)) AND pw.req;
      avl_write_i      <=to_std_logic(is_write(pw)) AND pw.req;
      fifo_cmd_push_c  <=to_std_logic(pw.mode=PB_MODE_RD OR
                                      pw.mode=PB_MODE_WR_ACK) AND
                          pw.req AND NOT avl_waitrequest;
      ack<=NOT avl_waitrequest;
    ELSE
      -- Wait states ou, suite burst.
      avl_burstcount_i <=avl_burstcount_mem;
      avl_address_i    <=avl_address_mem;
      avl_read_i       <='0';
      avl_write_i      <=avl_write_mem;
      IF is_read(pw) THEN
        fifo_cmd_push_c<=pw.req;
        ack<='1';
      ELSE
        fifo_cmd_push_c<=to_std_logic(pw.mode=PB_MODE_WR_ACK) AND
                        pw.req AND NOT avl_waitrequest;
        ack<=NOT avl_waitrequest;
      END IF;
    END IF;
    avl_writedata <=std_logic_vector(pw.d);
    avl_byteenable<=std_logic_vector(pw.be);
    
  END PROCESS CombWrite;
  
  ------------------------------------------------------------------
  SyncWrite: PROCESS (clk,reset_na) IS
    VARIABLE burst_v : std_logic;
  BEGIN
    IF reset_na='0' THEN
      prem<='1';
      deja<='0';
      burst<='0';
    ELSIF rising_edge(clk) THEN
      -------------------------------------------------
      burst_v:=burst;
      IF pw.req='1' AND ack='1' THEN
        IF burst_v='0' THEN
          burstcpt<=pb_blen(pw)-1;
          burst_v:=to_std_logic(is_burst(pw));
        ELSE
          burstcpt<=burstcpt-1;
          IF burstcpt=1 THEN
            burst_v:='0';
          END IF;
        END IF;
      END IF;
      burst<=burst_v;
      
      -------------------------------------------------
      IF pw.req='1' AND ack='1' AND burst_v='0' THEN
        prem<='1';
      ELSIF pw.req='1' AND prem='1' AND avl_waitrequest='0' THEN
        prem<='0';
      END IF;
      
      -------------------------------------------------
      IF prem='1' THEN
        deja<=pw.req AND NOT avl_waitrequest;
      ELSIF deja='1' AND burst_v='0' THEN
        deja<='0';
      END IF;
      
      -------------------------------------------------
      IF prem='1' THEN
        avl_burstcount_mem<=avl_burstcount_i;
        avl_address_mem<=avl_address_i;
        avl_write_mem<=avl_write_i;
      END IF;
      
      -------------------------------------------------
      IF fifo_cmd_push_c='1' THEN
        fifo_cmd<=to_std_logic(is_write(pw)) & fifo_cmd(0 TO PROF-2);
      END IF;
      IF fifo_cmd_push_c='1' AND fifo_cmd_pop_c='0' THEN
        fifo_cmd_lev<=fifo_cmd_lev+1;
      ELSIF fifo_cmd_push_c='0' AND fifo_cmd_pop_c='1' THEN
        fifo_cmd_lev<=fifo_cmd_lev-1;
      END IF;
      
      -------------------------------------------------
      IF fifo_data_push_c='1' THEN
        fifo_data<=unsigned(avl_readdata) & fifo_data(0 TO PROF-2);
      END IF;
      IF fifo_data_push_c='1' AND fifo_data_pop_c='0' THEN
        fifo_data_lev<=fifo_data_lev+1;
      ELSIF fifo_data_push_c='0' AND fifo_data_pop_c='1' THEN
        fifo_data_lev<=fifo_data_lev-1;
      END IF;
      
    END IF;
  END PROCESS SyncWrite;
  
  fifo_cmdo<=fifo_cmd(fifo_cmd_lev-1)
--pragma synthesis_off
              WHEN fifo_cmd_lev>0 ELSE '0'
--pragma synthesis_on
              ;
  
  fifo_dato<=fifo_data(fifo_data_lev-1)
--pragma synthesis_off
              WHEN fifo_data_lev>0 ELSE x"00000000"
--pragma synthesis_on
              ;
  ------------------------------------------------------------------
  CombRead:PROCESS(fifo_data_lev,fifo_dato,ack,
                   avl_readdata,avl_readdatavalid,
                   fifo_cmdo,pw,fifo_cmd_lev)
  BEGIN
    IF fifo_data_lev=0 THEN
      pr_i.d<=unsigned(avl_readdata);
      pr_i.dreq<=avl_readdatavalid;
    ELSE
      pr_i.d<=fifo_dato;
      pr_i.dreq<='1';
    END IF;
    pr_i.code<=PB_OK;
    pr_i.ack<=ack;

    IF fifo_cmdo='0' THEN
      -- READ
      fifo_cmd_pop_c  <=pw.dack AND to_std_logic(fifo_cmd_lev>0) AND
                        (to_std_logic(fifo_cmd_lev>0) OR avl_readdatavalid);
      fifo_data_pop_c <=pw.dack AND to_std_logic(fifo_data_lev>0);
      fifo_data_push_c<=avl_readdatavalid AND
                         (NOT pw.dack OR to_std_logic(fifo_data_lev>0));
    ELSE
      -- WRITE_ACK
      fifo_cmd_pop_c  <=pw.dack AND to_std_logic(fifo_cmd_lev>0);
      fifo_data_pop_c <='0';
      fifo_data_push_c<=avl_readdatavalid;
    END IF;
    
  END PROCESS CombRead;

END ARCHITECTURE rtl;
