//-------------------------------------------------------------------
//
//  Filename      : proc_axi_if.v
//  Author        : Huang Lei Lei
//  Created       : 2015-09-09
//  Description   : if between proc and axi
//
//-------------------------------------------------------------------

`include "GFP_defines.v"

module proc_axi_if(
  // global
  axi_clk         ,
  axi_rstn        ,
  proc_clk        ,
  proc_rstn       ,
  // control
  proc_en         ,
  // gm
  gm_maddr        ,
  gm_mburst       ,
  gm_mcache       ,
  gm_mdata        ,
  gm_mid          ,
  gm_mlen         ,
  gm_mlock        ,
  gm_mprot        ,
  gm_mread        ,
  gm_mready       ,
  gm_msize        ,
  gm_mwrite       ,
  gm_mwstrb       ,
  gm_saccept      ,
  gm_sdata        ,
  gm_sid          ,
  gm_slast        ,
  gm_sresp        ,
  gm_svalid       ,
  // proc
  proc_val        ,
  proc_dat        ,
  // fifo error
  proc_fifo_err
  );


//*** PARAMETER DECLARATION ****************************************************

  parameter    AXI_DW             = 64            ,
               AXI_AW             = 32            ,
               AXI_WID            = 1             ;
               
  parameter    BST_LEN            = 16            ;
               
  parameter    IDLE_WRITE         = 0             ,
               RUN_WRITE          = 1             ;

  parameter    RGB_ADR            = 640*480*4     ,
               HON_LEN            = 640*4         ,
               VER_LEN            = 480           ;


  parameter    PROC_WR_DEPTH      = 256*8         ,
               PROC_RD_DEPTH      = 256           ;


//*** INPUT/OUTPUT DECLARATION *************************************************

  // global
  input                           axi_clk         ;
  input                           axi_rstn        ;
  input                           proc_clk        ;
  input                           proc_rstn       ;

  // control
  input                           proc_en         ;

  // gm
  input                           gm_saccept      ;
  input       [AXI_DW-1   : 0]    gm_sdata        ;
  input       [3          : 0]    gm_sid          ;
  input                           gm_slast        ;
  input       [2          : 0]    gm_sresp        ;
  input                           gm_svalid       ;

  output      [AXI_AW-1   : 0]    gm_maddr        ;
  output      [1          : 0]    gm_mburst       ;
  output      [3          : 0]    gm_mcache       ;
  output      [AXI_DW-1   : 0]    gm_mdata        ;
  output      [3          : 0]    gm_mid          ;
  output      [3          : 0]    gm_mlen         ;
  output                          gm_mlock        ;
  output      [2          : 0]    gm_mprot        ;
  output                          gm_mread        ;
  output                          gm_mready       ;
  output      [2          : 0]    gm_msize        ;
  output reg                      gm_mwrite       ;
  output      [AXI_DW/8-1 : 0]    gm_mwstrb       ;

  // proc
  input                           proc_val        ;
  input       [7          : 0]    proc_dat        ;

  // fifo error
  output reg  [1          : 0]    proc_fifo_err   ;


//*** WIRE/REG DECLARATION *****************************************************

  // global
  reg                             stop_axi_r      ;
  reg                             stop_proc_r     ;

  // state_write
  reg                             state_write     ;
  wire                            burst_finish    ;
  reg         [3          : 0]    counter_rgb     ;
  reg         [31         : 0]    addr_offset     ;

  // fifo
  wire                            fifo_rst        ;

  wire                            wr_clk          ;
  wire                            wr_req          ;
  wire        [7          : 0]    wr_dat          ;
  wire        [11         : 0]    wr_cnt          ;
  wire                            wr_full         ;

  wire                            rd_clk          ;
  wire                            rd_req          ;
  wire        [AXI_DW-1   : 0]    rd_dat          ;
  wire        [8          : 0]    rd_cnt          ;
  wire                            rd_empty        ;

  wire                            rd_start        ;
  wire                            rd_wait         ;


//*** MAIN BODY ****************************************************************

//*** GLOBAL *************************************

  // stop_axi_r
  always @(posedge axi_clk or negedge axi_rstn ) begin
    if( !axi_rstn )
      stop_axi_r <= 1 ;
    else begin
      stop_axi_r <= !proc_en ;
    end
  end

  // stop_proc_r
  always @(posedge proc_clk or negedge proc_rstn ) begin
    if( !proc_rstn )
      stop_proc_r <= 1 ;
    else begin
      stop_proc_r <= !proc_en ;
    end
  end


//*** GM *****************************************

  assign gm_mburst  = 2'b01     ;
  assign gm_mcache  = 4'b0000   ;
  assign gm_mdata   = rd_dat    ;
  assign gm_mid     = AXI_WID   ;
  assign gm_mlen    = BST_LEN-1 ;
  assign gm_mlock   = 0         ;
  assign gm_mprot   = 3'b000    ;
  assign gm_mready  = 1         ;
  assign gm_msize   = 3'b011    ; // 64 bits
  assign gm_mwstrb  = 8'hff     ; // 8 bytes
  assign gm_mread   = 0         ;

  // state_write
  always @(posedge axi_clk or negedge axi_rstn) begin
    if( !axi_rstn )
      state_write <= IDLE_WRITE ;
    else if( stop_axi_r )
      state_write <= IDLE_WRITE ;
    else if( rd_start )
      state_write <= RUN_WRITE ;
    else if( rd_wait ) begin
      state_write <= IDLE_WRITE ;
    end
  end

  // gm_mwrite
  always @(posedge axi_clk or negedge axi_rstn) begin
    if( !axi_rstn )
      gm_mwrite <= 0 ;
    else if( stop_axi_r )
      gm_mwrite <= 0 ;
    else if( burst_finish )
      gm_mwrite <= 0 ;
    else if( state_write == RUN_WRITE ) begin
      gm_mwrite <= 1 ;
    end
  end

  // burst_finish
  assign burst_finish = (counter_rgb == BST_LEN-1) && gm_saccept && gm_mwrite ;

  // counter_rgb
  always @(posedge axi_clk or negedge axi_rstn) begin
    if( !axi_rstn )
      counter_rgb <= 0 ;
    else if( !gm_mwrite )
      counter_rgb <= 0 ;
    else if( gm_saccept & gm_mwrite ) begin
      if( counter_rgb == BST_LEN-1 )
        counter_rgb <= 0 ;
      else begin
        counter_rgb <= counter_rgb + 1 ;
      end
    end
  end

  // gm_maddr
  assign gm_maddr = RGB_ADR + addr_offset ;

  // addr_offset
  always @(posedge axi_clk or negedge axi_rstn) begin
    if( !axi_rstn )
      addr_offset <= 0 ;
    else if( stop_axi_r )
      addr_offset <= 0 ;
    else if( rd_req ) begin
      if( addr_offset == ( HON_LEN * VER_LEN - 8 ) )
        addr_offset <= 0 ;
      else begin
        addr_offset <= addr_offset + 8 ;
      end
    end
  end


//*** FIFO ***************************************

  fifo_proc fifo_proc0 (
    // global
    .aclr       ( fifo_rst      ),
    // wr_side
    .wrclk      ( wr_clk        ),
    .wrreq      ( wr_req        ),
    .data       ( wr_dat        ),
    .wrusedw    ( wr_cnt        ),
    .wrfull     ( wr_full       ),
    // rd_size
    .rdclk      ( rd_clk        ),
    .rdreq      ( rd_req        ),
    .q          ( rd_dat        ),
    .rdusedw    ( rd_cnt        ),
    .rdempty    ( rd_empty      )
    );

  assign wr_clk = proc_clk ;
  assign wr_req = proc_val ;
  assign wr_dat = proc_dat ;

  assign rd_clk = axi_clk ;
  assign rd_req = gm_mwrite & gm_saccept ;

  assign rd_start = ( rd_cnt >= PROC_RD_DEPTH>>2 );
  assign rd_wait  = ( rd_cnt <  PROC_RD_DEPTH>>2 );

  // fifo rst
  assign fifo_rst = ! ( axi_rstn & proc_en );

  // proc_fifo_err[0]: wr
  always @(posedge axi_clk or negedge axi_rstn) begin
    if( !axi_rstn )
      proc_fifo_err[0] <= 0 ;
    else if( wr_full & wr_req ) begin
      proc_fifo_err[0] <= 1 ;
    end
  end

  // proc_fifo_err[1]: rd
  always @(posedge proc_clk or negedge proc_rstn) begin
    if( !proc_rstn )
      proc_fifo_err[1] <= 0 ;
    else if( rd_empty & rd_req ) begin
      proc_fifo_err[1] <= 1 ;
    end
  end

endmodule
