module plic_granu_arb(
  //input
  int_in_prio,
  int_in_req, 
  int_in_id,

  //output
  int_out_req,
  int_out_id,
  int_out_prio

);
parameter    SEL_NUM        = 4;
parameter    SEL_BIT        = 2;
parameter    ID_NUM         = 10;
parameter    PRIO_BIT       = 5;
localparam   PRIO_NUM       = 1<<<PRIO_BIT;
localparam   INT_INFO       = ID_NUM + PRIO_BIT;

input   [SEL_NUM*PRIO_BIT-1:0]  int_in_prio;
input   [SEL_NUM-1:0]           int_in_req;
input   [SEL_NUM*ID_NUM-1:0]    int_in_id;

  //output
output                          int_out_req;
output  [ID_NUM-1:0]            int_out_id;
output  [PRIO_BIT-1:0]          int_out_prio;

// wire definition
wire    [PRIO_NUM-1:0]          int_valid_prio;
wire    [SEL_NUM-1:0]           high_prio_pos;
wire    [ID_NUM*SEL_NUM-1:0]    int_id_1d_bus;
wire    [PRIO_BIT-1:0]          high_prio;
wire    [SEL_NUM-1:0]           sel_pos_rever;
wire    [ID_NUM-1:0]            sel_out_id;

// reg definition
wire     [PRIO_NUM-1:0]          int_in_exp_prio[SEL_NUM-1:0];
wire     [SEL_NUM-1:0]           int_prio_pos_array[PRIO_NUM-1:0];
wire     [PRIO_NUM*SEL_NUM-1:0]  int_prio_pos_1d_bus;

wire    [SEL_BIT-1:0]           tmp_pos;
//**********************************************************************
//  first, get all the expand priority using 2-d array
//
//**********************************************************************
genvar i;
genvar j;
generate 
  for(i=0;i<SEL_NUM;i=i+1)
  begin: INT_EXP_I
    for(j=0;j<PRIO_NUM;j=j+1)
    begin:INT_EXP_J
assign        int_in_exp_prio[i][j] = int_in_req[i] && (int_in_prio[i*PRIO_BIT+:PRIO_BIT] == j);
    end
  end
endgenerate
//**********************************************************************
//  secod, reverse the expand priority array, ognized with priority
//
//**********************************************************************
generate 
  for(i=0;i<SEL_NUM;i=i+1)
  begin:REV_INT_I
    for(j=0;j<PRIO_NUM;j=j+1)
    begin:REV_INT_J
assign        int_prio_pos_array[j][i] = int_in_exp_prio[i][j];
    end
  end
endgenerate
generate 
  for(j=0;j<PRIO_NUM;j=j+1)
  begin:INT_PRI_1D
assign      int_prio_pos_1d_bus[j*SEL_NUM+:SEL_NUM] = int_prio_pos_array[j];
  end
endgenerate
//**********************************************************************
//  third, get the valid priority 
//  and select the highest priority position
//**********************************************************************
genvar k;
generate 
  for(k=0;k<PRIO_NUM;k=k+1)
  begin:VALID_PRIO
  assign int_valid_prio[k] = |int_prio_pos_array[k];
  end
endgenerate

prio_sel #(SEL_NUM,PRIO_NUM,PRIO_BIT) x_priority_select(
  .data_in(int_prio_pos_1d_bus),
  .sel_in(int_valid_prio),
  .data_out(high_prio_pos),
  .pos_out(high_prio)
);


//**********************************************************************
//  fourth, get the selected int information 
//  and select the highest priority position
//**********************************************************************
generate 
genvar m;
  for(m=0;m<SEL_NUM;m=m+1)
    begin:FLAT_INT_INFO
    assign int_id_1d_bus[(SEL_NUM-1-m)*ID_NUM+:ID_NUM] = int_in_id[m*ID_NUM+:ID_NUM];
    assign sel_pos_rever[SEL_NUM-1-m]                  = high_prio_pos[m];
    end
endgenerate

prio_sel #(ID_NUM,SEL_NUM,SEL_BIT) x_id_select(
  .data_in(int_id_1d_bus),
  .sel_in(sel_pos_rever),
  .data_out(sel_out_id),
  .pos_out(tmp_pos)
);

assign int_out_req                 = |int_in_req[SEL_NUM-1:0];
assign int_out_prio[PRIO_BIT-1:0]  = high_prio[PRIO_BIT-1:0];
assign int_out_id[ID_NUM-1:0]      = sel_out_id[ID_NUM-1:0];


endmodule