// ================================================================
// NVDLA Open Source Project
//
// Copyright(c) 2016 - 2017 NVIDIA Corporation. Licensed under the
// NVDLA Open Hardware License; Check "LICENSE" which comes with
// this distribution for more information.
// ================================================================
// File Name: NV_NVDLA_PDP_nan.v
// ================================================================
// NVDLA Open Source Project
// 
// Copyright(c) 2016 - 2017 NVIDIA Corporation.  Licensed under the
// NVDLA Open Hardware License; Check "LICENSE" which comes with 
// this distribution for more information.
// ================================================================
// File Name: NV_NVDLA_PDP_define.h
/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
//#ifdef NVDLA_FEATURE_DATA_TYPE_INT8
//#if ( NVDLA_PDP_THROUGHPUT  ==  8 )
//    #define LARGE_FIFO_RAM
//#endif
//#if ( NVDLA_PDP_THROUGHPUT == 1 )
//    #define SMALL_FIFO_RAM
//#endif
//#endif
module NV_NVDLA_PDP_nan (
   nvdla_core_clk
  ,nvdla_core_rstn
  ,dp2reg_done
  ,nan_preproc_prdy
  ,pdp_rdma2dp_pd
  ,pdp_rdma2dp_valid
  ,reg2dp_flying_mode
// ,reg2dp_input_data
  ,reg2dp_nan_to_zero
  ,reg2dp_op_en
  ,dp2reg_inf_input_num
  ,dp2reg_nan_input_num
  ,nan_preproc_pd
  ,nan_preproc_pvld
  ,pdp_rdma2dp_ready
  );
///////////////////////////////////////////////////////////////////
input nvdla_core_clk;
input nvdla_core_rstn;
input dp2reg_done;
input nan_preproc_prdy;
input [8*1 +13:0] pdp_rdma2dp_pd;
input pdp_rdma2dp_valid;
input reg2dp_flying_mode;
//input [1:0] reg2dp_input_data;
input reg2dp_nan_to_zero;
input reg2dp_op_en;
output [31:0] dp2reg_inf_input_num;
output [31:0] dp2reg_nan_input_num;
output [8*1 +13:0] nan_preproc_pd;
output nan_preproc_pvld;
output pdp_rdma2dp_ready;
///////////////////////////////////////////////////////////////////
reg [8*1 +13:0] datin_d;
reg cube_end_d1;
//reg [11:0] datin_info_d;
reg din_pvld_d1;
wire [31:0] dp2reg_inf_input_num=0;
wire [31:0] dp2reg_nan_input_num=0;
//reg [31:0] inf_in_count;
//reg [31:0] inf_in_num0;
//reg [31:0] inf_in_num1;
//reg [2:0] inf_num_in_8byte_d1;
reg layer_flag;
//reg mon_inf_in_count;
//reg mon_nan_in_count;
//reg [31:0] nan_in_count;
//reg [31:0] nan_in_num0;
//reg [31:0] nan_in_num1;
//reg [2:0] nan_num_in_8byte_d1;
//reg [15:0] nan_preproc_pd0;
//reg [15:0] nan_preproc_pd1;
//reg [15:0] nan_preproc_pd2;
//reg [15:0] nan_preproc_pd3;
reg op_en_d1;
reg waiting_for_op_en;
reg wdma_layer_flag;
wire cube_end;
//wire [3:0] dat_is_inf;
//wire [3:0] dat_is_nan;
wire din_prdy_d1;
//wire fp16_en;
//wire [15:0] fp16_in_pd_0;
//wire [15:0] fp16_in_pd_1;
//wire [15:0] fp16_in_pd_2;
//wire [15:0] fp16_in_pd_3;
//wire [2:0] inf_num_in_8byte;
//wire [1:0] inf_num_in_8byte_0;
//wire [1:0] inf_num_in_8byte_1;
wire layer_end;
wire load_din;
wire load_din_d1;
//wire [2:0] nan_num_in_8byte;
//wire [1:0] nan_num_in_8byte_0;
//wire [1:0] nan_num_in_8byte_1;
wire onfly_en;
wire op_en_load;
wire pdp_rdma2dp_ready_f;
//wire tozero_en;
wire wdma_done;
//==========================================
//DP input side
//==========================================
//----------------------------------------
assign pdp_rdma2dp_ready = pdp_rdma2dp_ready_f;
assign pdp_rdma2dp_ready_f = (~din_pvld_d1 | din_prdy_d1) & (~waiting_for_op_en);
assign load_din = pdp_rdma2dp_valid & pdp_rdma2dp_ready_f;
//----------------------------------------
// assign tozero_en = reg2dp_nan_to_zero == 1'h1 ;
// assign fp16_en = (reg2dp_input_data[1:0]== 2'h2 );
assign onfly_en = (reg2dp_flying_mode == 1'h0 );
//----------------------------------------
// assign fp16_in_pd_0 = pdp_rdma2dp_pd[15:0] ;
// assign fp16_in_pd_1 = pdp_rdma2dp_pd[31:16] ;
// assign fp16_in_pd_2 = pdp_rdma2dp_pd[47:32] ;
// assign fp16_in_pd_3 = pdp_rdma2dp_pd[63:48] ;
//
// assign dat_is_nan[0] = fp16_en & (&fp16_in_pd_0[14:10]) & (|fp16_in_pd_0[9:0]);
// assign dat_is_nan[1] = fp16_en & (&fp16_in_pd_1[14:10]) & (|fp16_in_pd_1[9:0]);
// assign dat_is_nan[2] = fp16_en & (&fp16_in_pd_2[14:10]) & (|fp16_in_pd_2[9:0]);
// assign dat_is_nan[3] = fp16_en & (&fp16_in_pd_3[14:10]) & (|fp16_in_pd_3[9:0]);
//
// assign dat_is_inf[0] = fp16_en & (&fp16_in_pd_0[14:10]) & (~(|fp16_in_pd_0[9:0]));
// assign dat_is_inf[1] = fp16_en & (&fp16_in_pd_1[14:10]) & (~(|fp16_in_pd_1[9:0]));
// assign dat_is_inf[2] = fp16_en & (&fp16_in_pd_2[14:10]) & (~(|fp16_in_pd_2[9:0]));
// assign dat_is_inf[3] = fp16_en & (&fp16_in_pd_3[14:10]) & (~(|fp16_in_pd_3[9:0]));
//////////////////////////////////////////////////////////////////////
//waiting for op_en
//////////////////////////////////////////////////////////////////////
always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
  if (!nvdla_core_rstn) begin
    op_en_d1 <= 1'b0;
  end else begin
  op_en_d1 <= reg2dp_op_en;
  end
end
assign op_en_load = reg2dp_op_en & (~op_en_d1);
assign layer_end = &{pdp_rdma2dp_pd[8*1 +13],pdp_rdma2dp_pd[8*1 +9]} & load_din;
always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
  if (!nvdla_core_rstn) begin
    waiting_for_op_en <= 1'b1;
  end else begin
    if(layer_end & (~onfly_en))
        waiting_for_op_en <= 1'b1;
    else if(op_en_load) begin
        if(onfly_en)
            waiting_for_op_en <= 1'b1;
        else if(~onfly_en)
            waiting_for_op_en <= 1'b0;
    end
  end
end
//VCS coverage off
`ifndef DISABLE_FUNCPOINT
  `ifdef ENABLE_FUNCPOINT
    reg funcpoint_cover_off;
    initial begin
        if ( $test$plusargs( "cover_off" ) ) begin
            funcpoint_cover_off = 1'b1;
        end else begin
            funcpoint_cover_off = 1'b0;
        end
    end
    property RDMA_NewLayer_out_req_And_core_CurLayer_not_finish__0_cov;
        disable iff((nvdla_core_rstn !== 1) || funcpoint_cover_off)
        @(posedge nvdla_core_clk)
        waiting_for_op_en & (~pdp_rdma2dp_ready_f) & pdp_rdma2dp_valid;
    endproperty
// Cover 0 : "waiting_for_op_en & (~pdp_rdma2dp_ready_f) & pdp_rdma2dp_valid"
    FUNCPOINT_RDMA_NewLayer_out_req_And_core_CurLayer_not_finish__0_COV : cover property (RDMA_NewLayer_out_req_And_core_CurLayer_not_finish__0_cov);
  `endif
`endif
//VCS coverage on
/////////////////////////////////////
//NaN process mode control
/////////////////////////////////////
// always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
// if (!nvdla_core_rstn) begin
// nan_preproc_pd0 <= {16{1'b0}};
// nan_preproc_pd1 <= {16{1'b0}};
// nan_preproc_pd2 <= {16{1'b0}};
// nan_preproc_pd3 <= {16{1'b0}};
// datin_info_d <= {12{1'b0}};
// end else begin
// if(load_din) begin
// nan_preproc_pd0 <= (dat_is_nan[0] & tozero_en) ? 16'd0 : fp16_in_pd_0;
// nan_preproc_pd1 <= (dat_is_nan[1] & tozero_en) ? 16'd0 : fp16_in_pd_1;
// nan_preproc_pd2 <= (dat_is_nan[2] & tozero_en) ? 16'd0 : fp16_in_pd_2;
// nan_preproc_pd3 <= (dat_is_nan[3] & tozero_en) ? 16'd0 : fp16_in_pd_3;
// datin_info_d <= pdp_rdma2dp_pd[75:64];
// end
// end
// end
always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
  if (!nvdla_core_rstn) begin
    datin_d <= 0;
  end else begin
    if(load_din) begin
        datin_d <= pdp_rdma2dp_pd;
    end
  end
end
always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
  if (!nvdla_core_rstn) begin
    din_pvld_d1 <= 1'b0;
  end else begin
    if(pdp_rdma2dp_valid & (~waiting_for_op_en))
        din_pvld_d1 <= 1'b1;
    else if(din_prdy_d1)
        din_pvld_d1 <= 1'b0;
  end
end
assign din_prdy_d1 = nan_preproc_prdy;
//-------------output data -----------------
//assign nan_preproc_pd = {datin_info_d,nan_preproc_pd3,nan_preproc_pd2,nan_preproc_pd1,nan_preproc_pd0};
assign nan_preproc_pd = datin_d;
assign nan_preproc_pvld = din_pvld_d1;
//
// /////////////////////////////////////
// //input NaN element count
// /////////////////////////////////////
// assign cube_end = pdp_rdma2dp_pd[75];
//
// assign nan_num_in_8byte_0[1:0] = dat_is_nan[0] + dat_is_nan[1];
// assign nan_num_in_8byte_1[1:0] = dat_is_nan[2] + dat_is_nan[3];
// assign nan_num_in_8byte[2:0] = nan_num_in_8byte_0 + nan_num_in_8byte_1;
//
// always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
// if (!nvdla_core_rstn) begin
// cube_end_d1 <= 1'b0;
// end else begin
// if ((load_din) == 1'b1) begin
// cube_end_d1 <= cube_end;
// end
// end
// end
// always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
// if (!nvdla_core_rstn) begin
// nan_num_in_8byte_d1 <= {3{1'b0}};
// end else begin
// if ((load_din) == 1'b1) begin
// nan_num_in_8byte_d1 <= nan_num_in_8byte[2:0];
// end
// end
// end
// always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
// if (!nvdla_core_rstn) begin
// inf_num_in_8byte_d1 <= {3{1'b0}};
// end else begin
// if ((load_din) == 1'b1) begin
// inf_num_in_8byte_d1 <= inf_num_in_8byte[2:0];
// end
// end
// end
//
// assign load_din_d1 = din_pvld_d1 & din_prdy_d1;
// always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
// if (!nvdla_core_rstn) begin
// {mon_nan_in_count,nan_in_count[31:0]} <= {33{1'b0}};
// end else begin
// if(load_din_d1) begin
// if(cube_end_d1)
// {mon_nan_in_count,nan_in_count[31:0]} <= 33'd0;
// else
// {mon_nan_in_count,nan_in_count[31:0]} <= nan_in_count + nan_num_in_8byte_d1;
// end
// end
// end
//
// assign inf_num_in_8byte_0[1:0] = dat_is_inf[0] + dat_is_inf[1];
// assign inf_num_in_8byte_1[1:0] = dat_is_inf[2] + dat_is_inf[3];
// assign inf_num_in_8byte[2:0] = inf_num_in_8byte_0 + inf_num_in_8byte_1;
// always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
// if (!nvdla_core_rstn) begin
// {mon_inf_in_count,inf_in_count[31:0]} <= {33{1'b0}};
// end else begin
// if(load_din_d1) begin
// if(cube_end_d1)
// {mon_inf_in_count,inf_in_count[31:0]} <= 33'd0;
// else
// {mon_inf_in_count,inf_in_count[31:0]} <= inf_in_count + inf_num_in_8byte_d1;
// end
// end
// end
//
// always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
// if (!nvdla_core_rstn) begin
// layer_flag <= 1'b0;
// nan_in_num1 <= {32{1'b0}};
// inf_in_num1 <= {32{1'b0}};
// nan_in_num0 <= {32{1'b0}};
// inf_in_num0 <= {32{1'b0}};
// end else begin
// if(load_din_d1 & cube_end_d1) begin
// layer_flag <= ~layer_flag;
// if(layer_flag) begin
// nan_in_num1 <= nan_in_count;
// inf_in_num1 <= inf_in_count;
// end else begin
// nan_in_num0 <= nan_in_count;
// inf_in_num0 <= inf_in_count;
// end
// end
// end
// end
//
// //adding dp2reg_done to latch the num and output a sigle one for each
// assign wdma_done = dp2reg_done;
// always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
// if (!nvdla_core_rstn) begin
// wdma_layer_flag <= 1'b0;
// dp2reg_nan_input_num <= {32{1'b0}};
// dp2reg_inf_input_num <= {32{1'b0}};
// end else begin
// if(wdma_done) begin
// wdma_layer_flag <= ~wdma_layer_flag;
// if(wdma_layer_flag) begin
// dp2reg_nan_input_num <= nan_in_num1;
// dp2reg_inf_input_num <= inf_in_num1;
// end else begin
// dp2reg_nan_input_num <= nan_in_num0;
// dp2reg_inf_input_num <= inf_in_num0;
// end
// end
// end
// end
//==============
//function points
//==============
//VCS coverage off
`ifndef DISABLE_FUNCPOINT
  `ifdef ENABLE_FUNCPOINT
    property PDP_RDMA2CORE__rdma_layerDone_stall__1_cov;
        disable iff((nvdla_core_rstn !== 1) || funcpoint_cover_off)
        @(posedge nvdla_core_clk)
        waiting_for_op_en & (~pdp_rdma2dp_ready_f);
    endproperty
// Cover 1 : "waiting_for_op_en & (~pdp_rdma2dp_ready_f)"
    FUNCPOINT_PDP_RDMA2CORE__rdma_layerDone_stall__1_COV : cover property (PDP_RDMA2CORE__rdma_layerDone_stall__1_cov);
  `endif
`endif
//VCS coverage on
//////////////////////////////////////////////////////////////////////
endmodule // NV_NVDLA_PDP_nan