// ================================================================
// 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_RUBIK_wr_req.v
module NV_NVDLA_RUBIK_wr_req (
   nvdla_core_clk //|< i
  ,nvdla_core_rstn //|< i
  ,dma_wr_cmd_pd //|< i
  ,dma_wr_cmd_vld //|< i
  ,dma_wr_data_pd //|< i
  ,dma_wr_data_vld //|< i
  ,dp2reg_consumer //|< i
  ,pwrbus_ram_pd //|< i
  ,reg2dp_dataout_ram_type //|< i
  ,reg2dp_perf_en //|< i
  ,wr_req_rdy //|< i
  ,dma_wr_cmd_rdy //|> o
  ,dma_wr_data_rdy //|> o
  ,dp2reg_d0_wr_stall_cnt //|> o
  ,dp2reg_d1_wr_stall_cnt //|> o
  ,dp2reg_done //|> o
  ,wr_req_pd //|> o
  ,wr_req_type //|> o
  ,wr_req_vld //|> o
  );
input nvdla_core_clk;
input nvdla_core_rstn;
input dp2reg_consumer;
input [31:0] pwrbus_ram_pd;
input reg2dp_dataout_ram_type;
input reg2dp_perf_en;
output [31:0] dp2reg_d0_wr_stall_cnt;
output [31:0] dp2reg_d1_wr_stall_cnt;
output wr_req_type;
output wr_req_vld;
output [514:0] wr_req_pd;
input wr_req_rdy;
input dma_wr_cmd_vld;
input [77:0] dma_wr_cmd_pd;
output dma_wr_cmd_rdy;
input dma_wr_data_vld;
input [513:0] dma_wr_data_pd;
output dma_wr_data_rdy;
output dp2reg_done;
reg [3:0] dbuf_remain;
reg [31:0] dp2reg_d0_wr_stall_cnt;
reg [31:0] dp2reg_d1_wr_stall_cnt;
reg dp2reg_done_d;
reg fill_half;
reg last_wr_cmd;
reg mon_dbuf_remain;
reg mon_wr_dcnt_c;
reg send_cmd;
reg send_cmd_open;
reg send_data;
reg [13:0] send_data_size;
reg send_half;
reg stl_adv;
reg [31:0] stl_cnt_cur;
reg [33:0] stl_cnt_dec;
reg [33:0] stl_cnt_ext;
reg [33:0] stl_cnt_inc;
reg [33:0] stl_cnt_mod;
reg [33:0] stl_cnt_new;
reg [33:0] stl_cnt_nxt;
reg [12:0] wr_data_cnt;
reg wr_req_stall_inc_d;
reg [31:0] wr_stall_cnt;
wire dbuf_nempty;
wire [513:78] dma_wr_cmd_hpd;
wire [77:0] dma_wr_cmd_opd;
wire [72:0] dma_wr_cmd_opdt;
wire dma_wr_cmd_ordy;
wire dma_wr_cmd_ovld;
wire dma_wr_cmd_pop;
wire dma_wr_cmd_req_vld;
wire [511:0] dma_wr_data_opd;
wire dma_wr_data_ordy;
wire dma_wr_data_pop;
wire dma_wr_data_push;
wire dma_wr_data_req_vld;
wire [255:0] dma_wr_datah_opd;
wire dma_wr_datah_ordy;
wire dma_wr_datah_ovld;
wire [255:0] dma_wr_datah_pd;
wire dma_wr_datah_pop;
wire dma_wr_datah_rdy;
wire dma_wr_datah_vld;
wire [255:0] dma_wr_datal_opd;
wire dma_wr_datal_ordy;
wire dma_wr_datal_ovld;
wire [255:0] dma_wr_datal_pd;
wire dma_wr_datal_pop;
wire dma_wr_datal_rdy;
wire dma_wr_datal_vld;
wire [1:0] fifo_mask;
wire [1:0] fifo_omask;
wire mon_remain_dsize;
wire [1:0] pop_size;
wire [1:0] push_size;
wire [13:0] remain_data_size;
wire send_data_done;
wire [13:0] wr_data_cnt_inc;
wire wr_req_stall_inc;
wire wr_stall_cnt_dec;
// synoff nets
// monitor nets
// debug nets
// tie high nets
// tie low nets
// no connect nets
// not all bits used nets
// todo nets
assign dp2reg_done = send_data_done & last_wr_cmd;
assign wr_req_type = reg2dp_dataout_ram_type;
assign wr_req_vld = dma_wr_cmd_req_vld || dma_wr_data_req_vld;
assign wr_req_pd[514:514] = dma_wr_cmd_pop ? 1'd0 /* PKT_nvdla_dma_wr_req_dma_write_cmd_ID  */ : 1'd1 /* PKT_nvdla_dma_wr_req_dma_write_data_ID  */ ;
assign wr_req_pd[513:0] = dma_wr_cmd_pop ? {dma_wr_cmd_hpd,dma_wr_cmd_opd} : {fifo_omask,dma_wr_data_opd};
assign dma_wr_cmd_hpd[513:78] = {436{1'b0}};
assign dma_wr_cmd_ordy = send_cmd & wr_req_rdy;
assign dma_wr_cmd_pop = dma_wr_cmd_ordy & dma_wr_cmd_ovld;
assign dma_wr_cmd_req_vld = send_cmd & dma_wr_cmd_ovld;
always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
  if (!nvdla_core_rstn) begin
    send_cmd <= 1'b0;
  end else begin
    if (dma_wr_cmd_pop)
        send_cmd <= 1'b0;
    else if((send_cmd_open | send_data_done) & dbuf_nempty)
        send_cmd <= 1'b1;
  end
end
always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
  if (!nvdla_core_rstn) begin
    send_cmd_open <= 1'b1;
  end else begin
    if (send_cmd_open & dbuf_nempty)
        send_cmd_open <= 1'b0;
    else if (send_data_done & ~dbuf_nempty)
        send_cmd_open <= 1'b1;
  end
end
always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
  if (!nvdla_core_rstn) begin
    send_data <= 1'b0;
  end else begin
    if (send_data_done)
        send_data <= 1'b0;
    else if (dma_wr_cmd_pop)
        send_data <= 1'b1;
  end
end
always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
  if (!nvdla_core_rstn) begin
    last_wr_cmd <= 1'b0;
    send_data_size <= {14{1'b0}};
  end else begin
    if (dma_wr_cmd_pop) begin
        last_wr_cmd <= dma_wr_cmd_opd[77:77];
        send_data_size <= dma_wr_cmd_opd[76:64]+1;
    end
  end
end
//push data
assign fifo_mask[1:0] = dma_wr_data_pd[513:512];
assign dma_wr_data_rdy = ~fifo_mask[1] ? (fill_half ? dma_wr_datah_rdy : dma_wr_datal_rdy) : dma_wr_datah_rdy & dma_wr_datal_rdy;
assign dma_wr_data_push = dma_wr_data_vld & dma_wr_data_rdy;
assign dma_wr_datah_vld = dma_wr_data_push & (&fifo_mask[1:0] || fill_half & ~fifo_mask[1]);
assign dma_wr_datal_vld = dma_wr_data_push & (&fifo_mask[1:0] || !fill_half & ~fifo_mask[1]);
assign dma_wr_datah_pd[255:0]= fill_half ? dma_wr_data_pd[255:0] : dma_wr_data_pd[511:256] ;
assign dma_wr_datal_pd[255:0]= fill_half ? dma_wr_data_pd[511:256] : dma_wr_data_pd[255:0] ;
assign push_size[1:0] = fifo_mask[1] + fifo_mask[0];
always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
  if (!nvdla_core_rstn) begin
    fill_half <= 1'b0;
  end else begin
    if (dp2reg_done)
        fill_half <= 1'b0;
    else if (dma_wr_data_push & ~fifo_mask[1])
        fill_half <= ~fill_half;
  end
end
//pop data
assign dma_wr_data_ordy = send_data & wr_req_rdy;
assign dma_wr_datah_ordy = (~fifo_omask[1] ? !send_half ? 1'b0 : dma_wr_datah_ovld : dma_wr_datah_ovld & dma_wr_datal_ovld) & dma_wr_data_ordy;
assign dma_wr_datal_ordy = (~fifo_omask[1] ? send_half ? 1'b0 : dma_wr_datal_ovld : dma_wr_datah_ovld & dma_wr_datal_ovld) & dma_wr_data_ordy;
assign dma_wr_data_opd[511:0] = send_half ? {dma_wr_datal_opd[255:0],dma_wr_datah_opd[255:0]} : {dma_wr_datah_opd[255:0],dma_wr_datal_opd[255:0]};
assign dma_wr_data_req_vld = send_data & (~fifo_omask[1] ? !send_half ? dma_wr_datal_ovld : dma_wr_datah_ovld : dma_wr_datah_ovld & dma_wr_datal_ovld);
assign dma_wr_datah_pop = dma_wr_datah_ordy & dma_wr_datah_ovld;
assign dma_wr_datal_pop = dma_wr_datal_ordy & dma_wr_datal_ovld;
assign dma_wr_data_pop = dma_wr_datah_pop | dma_wr_datal_pop;
assign pop_size[1:0] = dma_wr_datah_pop + dma_wr_datal_pop;
always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
  if (!nvdla_core_rstn) begin
    send_half <= 1'b0;
  end else begin
    if (dp2reg_done)
        send_half <= 1'b0;
    else if (dma_wr_data_pop & ~fifo_omask[1])
        send_half <= ~send_half;
  end
end
assign {mon_remain_dsize,remain_data_size} = send_data_size - wr_data_cnt;
assign fifo_omask[1:0] = remain_data_size == 1'b1 ? 2'b01 : 2'b11;
assign wr_data_cnt_inc = wr_data_cnt + pop_size;
assign send_data_done = dma_wr_data_pop & (wr_data_cnt_inc >= send_data_size);
always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
  if (!nvdla_core_rstn) begin
    wr_data_cnt <= {13{1'b0}};
    {mon_wr_dcnt_c,wr_data_cnt} <= {14{1'b0}};
  end else begin
    if (send_data_done)
        wr_data_cnt <= {13'b0};
    else if(dma_wr_data_pop)
        {mon_wr_dcnt_c,wr_data_cnt} <= wr_data_cnt_inc;
  end
end
always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
  if (!nvdla_core_rstn) begin
    {mon_dbuf_remain,dbuf_remain[3:0]} <= {5{1'b0}};
  end else begin
    if (dma_wr_data_push & dma_wr_data_pop)
        {mon_dbuf_remain,dbuf_remain[3:0]} <= dbuf_remain+push_size-pop_size;
    else if (dma_wr_data_push)
        {mon_dbuf_remain,dbuf_remain[3:0]} <= dbuf_remain+push_size;
    else if (dma_wr_data_pop)
        {mon_dbuf_remain,dbuf_remain[3:0]} <= dbuf_remain-pop_size;
  end
end
assign dbuf_nempty = |dbuf_remain[3:0];
assign dma_wr_cmd_opd[77:0] = {dma_wr_cmd_opdt[72:0],5'h0};
NV_NVDLA_RUBIK_wrdma_cmd rbk_dma_wr_cmd_fifo (
   .nvdla_core_clk (nvdla_core_clk) //|< i
  ,.nvdla_core_rstn (nvdla_core_rstn) //|< i
  ,.idata_prdy (dma_wr_cmd_rdy) //|> o
  ,.idata_pvld (dma_wr_cmd_vld) //|< i
  ,.idata_pd (dma_wr_cmd_pd[77:5]) //|< i
  ,.odata_prdy (dma_wr_cmd_ordy) //|< w
  ,.odata_pvld (dma_wr_cmd_ovld) //|> w
  ,.odata_pd (dma_wr_cmd_opdt[72:0]) //|> w
  ,.pwrbus_ram_pd (pwrbus_ram_pd[31:0]) //|< i
  );
NV_NVDLA_RUBIK_wrdma_data rbk_dma_wr_datah_fifo (
   .nvdla_core_clk (nvdla_core_clk) //|< i
  ,.nvdla_core_rstn (nvdla_core_rstn) //|< i
  ,.idata_prdy (dma_wr_datah_rdy) //|> w
  ,.idata_pvld (dma_wr_datah_vld) //|< w
  ,.idata_pd (dma_wr_datah_pd[255:0]) //|< w
  ,.odata_prdy (dma_wr_datah_ordy) //|< w
  ,.odata_pvld (dma_wr_datah_ovld) //|> w
  ,.odata_pd (dma_wr_datah_opd[255:0]) //|> w
  ,.pwrbus_ram_pd (pwrbus_ram_pd[31:0]) //|< i
  );
NV_NVDLA_RUBIK_wrdma_data rbk_dma_wr_datal_fifo (
   .nvdla_core_clk (nvdla_core_clk) //|< i
  ,.nvdla_core_rstn (nvdla_core_rstn) //|< i
  ,.idata_prdy (dma_wr_datal_rdy) //|> w
  ,.idata_pvld (dma_wr_datal_vld) //|< w
  ,.idata_pd (dma_wr_datal_pd[255:0]) //|< w
  ,.odata_prdy (dma_wr_datal_ordy) //|< w
  ,.odata_pvld (dma_wr_datal_ovld) //|> w
  ,.odata_pd (dma_wr_datal_opd[255:0]) //|> w
  ,.pwrbus_ram_pd (pwrbus_ram_pd[31:0]) //|< i
  );
assign wr_req_stall_inc = wr_req_vld & !wr_req_rdy;
always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
  if (!nvdla_core_rstn) begin
    wr_req_stall_inc_d <= 1'b0;
  end else begin
  wr_req_stall_inc_d <= wr_req_stall_inc;
  end
end
always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
  if (!nvdla_core_rstn) begin
    dp2reg_done_d <= 1'b0;
  end else begin
  dp2reg_done_d <= dp2reg_done;
  end
end
    assign wr_stall_cnt_dec = 1'b0;
// stl adv logic
    always @(
      wr_req_stall_inc_d
      or wr_stall_cnt_dec
      ) begin
      stl_adv = wr_req_stall_inc_d ^ wr_stall_cnt_dec;
    end
// stl cnt logic
    always @(
      stl_cnt_cur
      or wr_req_stall_inc_d
      or wr_stall_cnt_dec
      or stl_adv
      or dp2reg_done_d
      ) begin
// VCS sop_coverage_off start
      stl_cnt_ext[33:0] = {1'b0, 1'b0, stl_cnt_cur};
      stl_cnt_inc[33:0] = stl_cnt_cur + 1'b1; // spyglass disable W164b
      stl_cnt_dec[33:0] = stl_cnt_cur - 1'b1; // spyglass disable W164b
      stl_cnt_mod[33:0] = (wr_req_stall_inc_d && !wr_stall_cnt_dec)? stl_cnt_inc : (!wr_req_stall_inc_d && wr_stall_cnt_dec)? stl_cnt_dec : stl_cnt_ext;
      stl_cnt_new[33:0] = (stl_adv)? stl_cnt_mod[33:0] : stl_cnt_ext[33:0];
      stl_cnt_nxt[33:0] = (dp2reg_done_d)? 34'd0 : stl_cnt_new[33:0];
// VCS sop_coverage_off end
    end
// stl flops
    always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
      if (!nvdla_core_rstn) begin
        stl_cnt_cur[31:0] <= 0;
      end else begin
      if (reg2dp_perf_en) begin
      stl_cnt_cur[31:0] <= stl_cnt_nxt[31:0];
      end
      end
    end
// stl output logic
    always @(
      stl_cnt_cur
      ) begin
      wr_stall_cnt[31:0] = stl_cnt_cur[31:0];
    end
always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
  if (!nvdla_core_rstn) begin
    dp2reg_d0_wr_stall_cnt <= {32{1'b0}};
  end else begin
   if (dp2reg_done & ~dp2reg_consumer)
       dp2reg_d0_wr_stall_cnt <= wr_stall_cnt;
  end
end
always @(posedge nvdla_core_clk or negedge nvdla_core_rstn) begin
  if (!nvdla_core_rstn) begin
    dp2reg_d1_wr_stall_cnt <= {32{1'b0}};
  end else begin
   if (dp2reg_done & dp2reg_consumer)
       dp2reg_d1_wr_stall_cnt <= wr_stall_cnt;
  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 rubik_wr_req__wr_request_block__0_cov;
        disable iff((nvdla_core_rstn !== 1) || funcpoint_cover_off)
        @(posedge nvdla_core_clk)
        wr_req_vld & ~wr_req_rdy;
    endproperty
// Cover 0 : "wr_req_vld & ~wr_req_rdy"
    FUNCPOINT_rubik_wr_req__wr_request_block__0_COV : cover property (rubik_wr_req__wr_request_block__0_cov);
  `endif
`endif
//VCS coverage on
//VCS coverage off
`ifndef DISABLE_FUNCPOINT
  `ifdef ENABLE_FUNCPOINT
    property rubik_wr_req__wr_req_cmd_after_rf_nempty__1_cov;
        disable iff((nvdla_core_rstn !== 1) || funcpoint_cover_off)
        @(posedge nvdla_core_clk)
        send_data_done & ~dbuf_nempty;
    endproperty
// Cover 1 : "send_data_done & ~dbuf_nempty"
    FUNCPOINT_rubik_wr_req__wr_req_cmd_after_rf_nempty__1_COV : cover property (rubik_wr_req__wr_req_cmd_after_rf_nempty__1_cov);
  `endif
`endif
//VCS coverage on
//VCS coverage off
`ifndef DISABLE_FUNCPOINT
  `ifdef ENABLE_FUNCPOINT
    property rubik_wr_req__dma_wr_dbuf_fill_half__2_cov;
        disable iff((nvdla_core_rstn !== 1) || funcpoint_cover_off)
        @(posedge nvdla_core_clk)
        dma_wr_data_push & fill_half;
    endproperty
// Cover 2 : "dma_wr_data_push & fill_half"
    FUNCPOINT_rubik_wr_req__dma_wr_dbuf_fill_half__2_COV : cover property (rubik_wr_req__dma_wr_dbuf_fill_half__2_cov);
  `endif
`endif
//VCS coverage on
//VCS coverage off
`ifndef DISABLE_FUNCPOINT
  `ifdef ENABLE_FUNCPOINT
    property rubik_wr_req__dma_wr_dbuf_send_half__3_cov;
        disable iff((nvdla_core_rstn !== 1) || funcpoint_cover_off)
        @(posedge nvdla_core_clk)
        dma_wr_data_pop & send_half;
    endproperty
// Cover 3 : "dma_wr_data_pop & send_half"
    FUNCPOINT_rubik_wr_req__dma_wr_dbuf_send_half__3_COV : cover property (rubik_wr_req__dma_wr_dbuf_send_half__3_cov);
  `endif
`endif
//VCS coverage on
endmodule // NV_NVDLA_RUBIK_wr_req