module_en_cnt <= module_en_cnt;
end

reg double_buf_change_signal;
always @ (posedge clk)     
begin
  if(rst)
    double_buf_change_signal <=0;
  else if((module_en_cnt == 32'b0) && (module_en) )
    double_buf_change_signal <=1;
  else
    double_buf_change_signal <=0;
end 
 
//generate pre_load
reg blob_din_en_tmp;
always @ (posedge clk)
begin
  if(rst)
    blob_din_en_tmp <= 1'b0;
  else if(blob_din_en)
    blob_din_en_tmp <= 1'b1;
  else
    blob_din_en_tmp <= blob_din_en_tmp;
end

reg blob_din_en_tmp_d1;
always @ (posedge clk)
begin
  if(rst)
    blob_din_en_tmp_d1 <= 1'b0;
  else
    blob_din_en_tmp_d1 <= blob_din_en_tmp;
end
 
reg pre_load;
always @ (posedge clk)
begin
  if(rst)
    pre_load <= 1'b0;
  else if ((blob_din_en_tmp) & (~blob_din_en_tmp_d1))
    pre_load <= 1'b1;
  else
    pre_load <= 1'b0;
end

// generate dma_engineer_req;
wire dma_engineer_req_pulse = double_buf_change_signal | pre_load ;

reg dma_engineer_req;
always @ (posedge clk)
begin
  if(rst)
    dma_engineer_req <= 1'b0;
  else if(dma_engineer_req_pulse)
    dma_engineer_req <= 1'b1;
  else if(dma_engineer_ack)
    dma_engineer_req <= 1'b0;
  else
    dma_engineer_req <= dma_engineer_req;
end

// generate dma_engineer_length;
assign dma_engineer_length = LENGTH;

reg wr_ack;
always @ (posedge clk)
begin
  if(rst)
    wr_ack <= 1'b0;
  else if(dma_engineer_ack)
    wr_ack <= 1'b1;
  else if (dma_engineer_dout_eop)
    wr_ack <= 1'b0;
  else
    wr_ack <= wr_ack;
end

reg [15:0] dma_engineer_req_cnt;
always @ (posedge clk)
begin
  if(rst)
    dma_engineer_req_cnt <= 16'b0;
  else if(dma_engineer_req_pulse)
    begin 
	  if(dma_engineer_req_cnt == KG*GROUP-1)
	    dma_engineer_req_cnt <= 16'b0;
	  else
	    dma_engineer_req_cnt <= dma_engineer_req_cnt + 1'b1;
	end
  else
    dma_engineer_req_cnt <= dma_engineer_req_cnt;
end

// generate dma_engineer_start_addr;
always @ (posedge clk)
begin
  if(rst)
    dma_engineer_start_addr <= START_ADDR;
  else if ( (dma_engineer_req_cnt == 0) && dma_engineer_req_pulse)
    dma_engineer_start_addr <= START_ADDR;
  else if(dma_engineer_req_pulse)
    dma_engineer_start_addr <= dma_engineer_start_addr + LENGTH;
  else
    dma_engineer_start_addr <= dma_engineer_start_addr;
end


//============================================
//generate  ping_wr_en    and pong_wr_en   ; 
//generate  double_buf_wr_addr 
//generate  ping_buf_rdy  and pong_buf_rdy  =>  weight_blob_rdy    
//============================================

//generate ping/pong_wr_en
reg double_buf_wr_addr_sel;
always @ (posedge clk)
begin
  if(rst)
    double_buf_wr_addr_sel <= 1'b0;
  else if(double_buf_change_signal == 1'b1)
    double_buf_wr_addr_sel <= ~double_buf_wr_addr_sel;
  else
    double_buf_wr_addr_sel <= double_buf_wr_addr_sel;
end

assign double_buf_wr_en = dma_engineer_dout_en & wr_ack;

//generate double_buf_wr_addr
reg double_buf_rdy_sel;
reg [31:0] double_buf_wr_addr_tmp;
always @ (posedge clk)
begin
  if(rst | dma_engineer_ack)
    double_buf_wr_addr_tmp <= 32'b0;
  else if(dma_engineer_dout_en & wr_ack)
    begin
	  if(double_buf_wr_addr_tmp == LENGTH -1)
	    double_buf_wr_addr_tmp <= 32'b0;
	  else
	    double_buf_wr_addr_tmp <= double_buf_wr_addr_tmp + 1'b1;
	end
  else
    double_buf_wr_addr_tmp <= double_buf_wr_addr_tmp;
end
wire [DOUBLE_BUF_WR_ADDR_WIDTH-1:0] double_buf_wr_offset = (double_buf_wr_addr_sel==1'b0) ? 0 : DOUBLE_BUF_WR_DEPTH/2;
assign double_buf_wr_addr = double_buf_wr_addr_tmp[DOUBLE_BUF_WR_ADDR_WIDTH-1:0] + double_buf_wr_offset;

//generate ping_buf_rdy
reg ping_buf_rdy;
always @ (posedge clk)
begin
  if(rst)
    ping_buf_rdy <= 1'b0;
  else if((double_buf_wr_addr_sel==1'b0) & (dma_engineer_dout_eop & wr_ack))
    ping_buf_rdy <= 1'b1;
  else if((double_buf_rdy_sel==1'b1) & (double_buf_change_signal))
    ping_buf_rdy <= 1'b0;
  else
    ping_buf_rdy <= ping_buf_rdy;
end

//generate pong_buf_rdy
reg pong_buf_rdy;
always @ (posedge clk)
begin
  if(rst)
    pong_buf_rdy <= 1'b0;
  else if((double_buf_wr_addr_sel==1'b1) & (dma_engineer_dout_eop & wr_ack))
    pong_buf_rdy <= 1'b1;
  else if((double_buf_rdy_sel==1'b0) & (double_buf_change_signal))
    pong_buf_rdy <= 1'b0;
  else
    pong_buf_rdy <= pong_buf_rdy;
end

//generate weight_blob_rdy
always @ (posedge clk)
begin
  if (rst)
    double_buf_rdy_sel <= 1'b0;
  else if(module_en && (h_c == (DB_H_OUT*WB_W*WB_H*CG-1)))
    double_buf_rdy_sel <= ~double_buf_rdy_sel;
  else
    double_buf_rdy_sel <= double_buf_rdy_sel;
end

assign weight_blob_rdy = double_buf_rdy_sel ? pong_buf_rdy : ping_buf_rdy;

//========================================
//generate double_buf_rd_addr 
//generate op_weight       
//======================================== 

wire [31:0] wm_h;
wire [31:0] wm_w;

mul16_unsigned u_mul16_unsigned_4 (
  .CLK(clk), 
  .A(h_w_count),
  .B(CG),  
  .P(wm_h)  
);

mul16_unsigned u_mul16_unsigned_5 (
  .CLK(clk),  
  .A(w_w_count),  
  .B(CG * WB_H),  
  .P(wm_w)  
);

wire double_buf_rd_sel;
delay #(2) u_delay_5(
  .clk(clk),
  .rst(rst),
  .in(double_buf_rdy_sel),
  .out(double_buf_rd_sel)
);

reg [31:0] double_buf_rd_addr_tmp;
always @(posedge clk) 
begin
  if(rst)
    double_buf_rd_addr_tmp <= 32'b0;
  else
    double_buf_rd_addr_tmp <= c_d + wm_h + wm_w;
end

//add 1 clock delay to keep the same data access delay for reshape memory
wire [DOUBLE_BUF_RD_ADDR_WIDTH-1:0] double_buf_rd_offset = (double_buf_rd_sel == 1'b0) ? 0 : DOUBLE_BUF_RD_DEPTH / 2;

always @ (posedge clk)
begin
    double_buf_rd_addr <= double_buf_rd_addr_tmp[DOUBLE_BUF_RD_ADDR_WIDTH-1:0] + double_buf_rd_offset;
end

endmodule