module fm_axi_monitor_vw (
  clk_core,
  rst_x,
  i_start,
  i_clear,
  i_stop,
  i_alen,
  i_wvalid,
  i_wlast,
  i_wready,
  // result out
  o_set_no_wait,
  o_set_bukets,
  o_set_no_more,
  o_counter,
  o_bukets_no_wait,
  o_bukets_0,
  o_bukets_1,
  o_bukets_2,
  o_bukets_3,
  o_bukets_more,
  o_max_count,
  o_min_count,
  o_bukets_len_0,
  o_bukets_len_1,
  o_bukets_len_2,
  o_bukets_len_3,
  o_total_bytes,
  o_bukets_nrdy_0,
  o_bukets_nrdy_1,
  o_bukets_nrdy_2,
  o_bukets_nrdy_3,
  o_wr_cont,
  o_wr_discont
);
`include "polyphony_axi_def.v"
//////////////////////////////////
// parameter definition
//////////////////////////////////
localparam P_NUM_OF_BUCKETS  = 'd4;
localparam P_BUCKET_RANGE    = 'd1;
localparam P_BUCKET_SIZE     = 'd32;
localparam P_COUNTER_SIZE    = 'd32;

localparam P_IDLE = 1'b0;
localparam P_RUN = 1'b1;
//////////////////////////////////
// I/O port definition
//////////////////////////////////
  input clk_core;
  input rst_x;
  input i_start;
  input i_clear;
  input i_stop;
  input  [P_AXI_M_ARLEN-1:0] i_alen;
  input 		     i_wvalid;
  input 		     i_wlast;
  input 		     i_wready;
  // result out
  output o_set_no_wait;
  output [P_NUM_OF_BUCKETS-1:0] o_set_bukets;
  output o_set_no_more;
  output [P_COUNTER_SIZE-1:0] o_counter;
  output [P_BUCKET_SIZE-1:0] o_bukets_no_wait;
  output [P_BUCKET_SIZE-1:0] o_bukets_0;
  output [P_BUCKET_SIZE-1:0] o_bukets_1;
  output [P_BUCKET_SIZE-1:0] o_bukets_2;
  output [P_BUCKET_SIZE-1:0] o_bukets_3;
  output [P_BUCKET_SIZE-1:0] o_bukets_more;
  output [P_COUNTER_SIZE-1:0] o_max_count;
  output [P_COUNTER_SIZE-1:0] o_min_count;
  output [P_BUCKET_SIZE-1:0] o_bukets_len_0;
  output [P_BUCKET_SIZE-1:0] o_bukets_len_1;
  output [P_BUCKET_SIZE-1:0] o_bukets_len_2;
  output [P_BUCKET_SIZE-1:0] o_bukets_len_3;
  output [P_BUCKET_SIZE-1:0] o_total_bytes;
  output [P_BUCKET_SIZE-1:0] o_wr_cont;
  output [P_BUCKET_SIZE-1:0] o_wr_discont;
  output [P_BUCKET_SIZE-1:0] o_bukets_nrdy_0;
  output [P_BUCKET_SIZE-1:0] o_bukets_nrdy_1;
  output [P_BUCKET_SIZE-1:0] o_bukets_nrdy_2;
  output [P_BUCKET_SIZE-1:0] o_bukets_nrdy_3;

//////////////////////////////////
// reg
//////////////////////////////////
  reg [P_BUCKET_SIZE-1:0]  r_bukets[P_NUM_OF_BUCKETS-1:0];
  reg [P_BUCKET_SIZE-1:0]  r_bukets_len[P_NUM_OF_BUCKETS-1:0];
  reg [P_BUCKET_SIZE-1:0]  r_bukets_no_wait;
  reg [P_BUCKET_SIZE-1:0]  r_bukets_more;
  reg [P_COUNTER_SIZE-1:0]  r_counter;
  reg [P_COUNTER_SIZE-1:0]  r_nrdy_counter;
  reg r_state;
  reg [P_COUNTER_SIZE-1:0] r_max_count;
  reg [P_COUNTER_SIZE-1:0] r_min_count;
  reg r_disc_flag;
  reg [P_BUCKET_SIZE-1:0] r_wr_cont;
  reg [P_BUCKET_SIZE-1:0] r_wr_discont;
  reg [P_BUCKET_SIZE-1:0] r_total_bytes;
   
  reg  [P_BUCKET_SIZE-1:0] r_bukets_nrdy[P_NUM_OF_BUCKETS-1:0];
  reg [P_BUCKET_SIZE-1:0]  r_bukets_nrdy_more;
// wire
//////////////////////////////////
  wire   w_inc;
  wire   [P_NUM_OF_BUCKETS-1:0]
                 w_set;
  wire   [P_NUM_OF_BUCKETS-1:0]
                 w_set_len;
  wire   [P_NUM_OF_BUCKETS-1:0]
                 w_set_nrdy;
  wire   w_set_no_wait;
  wire   w_set_more;
  wire   w_start;
  wire [P_COUNTER_SIZE-1:0]  w_counter_inc;
  wire   w_set_nrdy_more;

  wire   w_set_max_min;
   
//////////////////////////////////
// assign
//////////////////////////////////
  assign w_inc = (r_state == P_RUN);

  assign  w_set_no_wait = (r_state == P_IDLE) & i_start & i_stop;
  assign  w_set_more = (P_BUCKET_RANGE*P_NUM_OF_BUCKETS <= w_counter_inc) &
                        ((r_state == P_RUN) & i_stop);
  assign  w_start = (r_state == P_IDLE) & i_start & (!i_stop);
  assign  w_counter_inc = (r_state == P_IDLE) ? 'd0 : r_counter + 1'b1;

  assign  w_set_max_min = w_set_no_wait | ((r_state == P_RUN) & i_stop);

  assign o_bukets_no_wait = r_bukets_no_wait;
  assign o_bukets_0 = r_bukets[0];
  assign o_bukets_1 = r_bukets[1];
  assign o_bukets_2 = r_bukets[2];
  assign o_bukets_3 = r_bukets[3];
  assign o_bukets_more = r_bukets_more;
  assign o_set_no_wait = w_set_no_wait;
  assign o_set_bukets = w_set;
  assign o_set_no_more = w_set_more;
  assign o_counter = r_counter;
  assign o_max_count = r_max_count;
  assign o_min_count = r_min_count;
  assign o_bukets_len_0 = r_bukets_len[0];
  assign o_bukets_len_1 = r_bukets_len[1];
  assign o_bukets_len_2 = r_bukets_len[2];
  assign o_bukets_len_3 = r_bukets_len[3];
  assign o_wr_cont = r_wr_cont;
  assign o_wr_discont = r_wr_discont;
//  assign o_total_bytes = r_total_bytes;
  assign o_total_bytes = r_bukets_nrdy_more;
  assign o_bukets_nrdy_0 = r_bukets_nrdy[0];
  assign o_bukets_nrdy_1 = r_bukets_nrdy[1];
  assign o_bukets_nrdy_2 = r_bukets_nrdy[2];
  assign o_bukets_nrdy_3 = r_bukets_nrdy[3];
//////////////////////////////////
// always
//////////////////////////////////
  always @(posedge clk_core or negedge rst_x) begin
    if (~rst_x) begin
      r_state <= P_IDLE;
    end else begin
      case (r_state)
        P_IDLE: begin
          if (i_start) begin
            if (!i_stop) r_state <= P_RUN;
          end
        end
        P_RUN: begin
          if (i_stop|i_clear) begin
            r_state <= P_IDLE;
          end
        end
      endcase
    end
  end

  always @(posedge clk_core or negedge rst_x) begin
    if (~rst_x) begin
      r_counter <= {P_COUNTER_SIZE{1'b0}};
    end else begin
      if (w_start) begin
        r_counter <= {P_COUNTER_SIZE{1'b0}};;
      end else begin
        if (w_inc) r_counter <= w_counter_inc;
      end
    end
  end

genvar gi;
generate for (gi=0;gi<P_NUM_OF_BUCKETS;gi=gi+1)begin
  assign w_set[gi] = ((P_BUCKET_RANGE*gi <= w_counter_inc) &
                     (w_counter_inc < P_BUCKET_RANGE*(gi+1))) & 
                     (((r_state == P_IDLE) & i_start & i_stop) |
                      ((r_state == P_RUN) & i_stop));

  always @(posedge clk_core or negedge rst_x) begin
    if (~rst_x) begin
      r_bukets[gi] <= {P_BUCKET_SIZE{1'b0}};
    end else begin
      if (i_clear) begin
        r_bukets[gi] <= {P_BUCKET_SIZE{1'b0}};
      end else begin
        if (w_set[gi]) r_bukets[gi] <= r_bukets[gi] + 1'b1;
      end
    end
  end

end
endgenerate

 // special case
  always @(posedge clk_core or negedge rst_x) begin
    if (~rst_x) begin
      r_bukets_no_wait <= {P_BUCKET_SIZE{1'b0}};
    end else begin
      if (i_clear) begin
        r_bukets_no_wait <= {P_BUCKET_SIZE{1'b0}};
      end else begin
        if (w_set_no_wait) r_bukets_no_wait <= r_bukets_no_wait + 1'b1;
      end
    end
  end

  always @(posedge clk_core or negedge rst_x) begin
    if (~rst_x) begin
      r_bukets_more <= {P_BUCKET_SIZE{1'b0}};
    end else begin
      if (i_clear) begin
        r_bukets_more <= {P_BUCKET_SIZE{1'b0}};
      end else begin
        if (w_set_more) r_bukets_more <= r_bukets_more + 1'b1;
      end
    end
  end
  // max min
  always @(posedge clk_core or negedge rst_x) begin
    if (~rst_x) begin
      r_max_count <= {P_COUNTER_SIZE{1'b0}};
      r_min_count <= {P_COUNTER_SIZE{1'b1}};
    end else begin
      if (i_clear) begin
        r_max_count <= {P_COUNTER_SIZE{1'b0}};
        r_min_count <= {P_COUNTER_SIZE{1'b1}};
      end else begin
      if ( w_set_max_min) begin
	if (!w_set_no_wait)
          if (w_counter_inc > r_max_count) r_max_count <= w_counter_inc;
	if (w_set_no_wait) r_min_count <= 'd0;
        else if (w_counter_inc < r_min_count) r_min_count <= w_counter_inc;
      end
      end
    end
  end

genvar gj;
generate for (gj=0;gj<P_NUM_OF_BUCKETS;gj=gj+1)begin
  assign w_set_len[gj] = ((P_BUCKET_RANGE*gj <= i_alen) &
                     (i_alen < P_BUCKET_RANGE*(gj+1))) & 
                     (((r_state == P_IDLE) & i_start & i_stop) |
                      ((r_state == P_RUN) & i_stop));

  always @(posedge clk_core or negedge rst_x) begin
    if (~rst_x) begin
      r_bukets_len[gj] <= {P_BUCKET_SIZE{1'b0}};
    end else begin
      if (i_clear) begin
        r_bukets_len[gj] <= {P_BUCKET_SIZE{1'b0}};
      end else begin
        if (w_set_len[gj]) r_bukets_len [gj] <= r_bukets_len[gj] + 1'b1;
      end
    end
  end

end
endgenerate


always @(posedge clk_core or negedge rst_x) begin
  if (~rst_x) begin
    r_nrdy_counter <= 1'd0;
  end else begin
    if (i_clear)
      r_nrdy_counter <= 1'd0;
    else if (i_wvalid & i_wready & i_wlast)
      r_nrdy_counter <= 1'd0;
    else if (i_wvalid & !i_wready)
      r_nrdy_counter <= r_nrdy_counter + 1'b1;
  end
end

genvar gk;
generate for (gk=0;gk<P_NUM_OF_BUCKETS;gk=gk+1)begin
  assign w_set_nrdy[gk] = ((P_BUCKET_RANGE*gk <= r_nrdy_counter) &
                           (r_nrdy_counter < P_BUCKET_RANGE*(gk+1))) & 
                           (i_wvalid & i_wready & i_wlast);

  always @(posedge clk_core or negedge rst_x) begin
    if (~rst_x) begin
      r_bukets_nrdy[gk] <= {P_BUCKET_SIZE{1'b0}};
    end else begin
      if (i_clear) begin
        r_bukets_nrdy[gk] <= {P_BUCKET_SIZE{1'b0}};
      end else begin
        if (w_set_nrdy[gk]) r_bukets_nrdy[gk] <= r_bukets_nrdy[gk] + 1'b1;
      end
    end
  end
end
endgenerate

  assign  w_set_nrdy_more = (P_BUCKET_RANGE*P_NUM_OF_BUCKETS <= r_nrdy_counter) &
                             (i_wvalid & i_wready & i_wlast);
  always @(posedge clk_core or negedge rst_x) begin
    if (~rst_x) begin
      r_bukets_nrdy_more <= {P_BUCKET_SIZE{1'b0}};
    end else begin
      if (i_clear) begin
        r_bukets_nrdy_more <= {P_BUCKET_SIZE{1'b0}};
      end else begin
        if (w_set_nrdy_more) r_bukets_nrdy_more <= r_bukets_nrdy_more + 1'b1;
      end
    end
  end

  always @(posedge clk_core or negedge rst_x) begin
    if (~rst_x) begin
      r_disc_flag <= 1'b0;
    end else begin
      if (i_clear)
        r_disc_flag <= 1'b0;
      else if (i_wvalid & i_wready & i_wlast) begin
        r_disc_flag <= 1'b0;
      end else begin
	// awvalid is already accepted
        if (i_wvalid & !i_start & !i_wready ) r_disc_flag <= 1'b1;
      end
    end
  end // always @ (posedge clk_core or negedge rst_x)
   
  always @(posedge clk_core or negedge rst_x) begin
    if (~rst_x) begin
      r_wr_cont <= 'd0;
      r_wr_discont <= 'd0;
    end else begin
      if (i_clear) begin
        r_wr_cont <= 'd0;
        r_wr_discont <= 'd0;
      end else
      if (i_wvalid & i_wready & i_wlast) begin
         if (r_disc_flag) r_wr_discont <= r_wr_discont + 1'b1;
	 else r_wr_cont <= r_wr_cont + 1'b1;
      end
    end
  end

  always @(posedge clk_core or negedge rst_x) begin
    if (~rst_x) begin
      r_total_bytes <= 'd0;
    end else begin
      if (i_clear)
        r_total_bytes <= 'd0;
      else if (i_wvalid&i_wready) r_total_bytes <= r_total_bytes + 1'b1;
    end
  end
endmodule