其他分享
首页 > 其他分享> > 一种基于优先级轮询调度负载均衡的crossbar结构

一种基于优先级轮询调度负载均衡的crossbar结构

作者:互联网

特点:支持群组路由,端口可配置

主体代码

`timescale 1ns / 1ps
//
// Company: nssc
// Engineer: liumeng
// Create Date:    22:49:51 01/11/2022
// Module Name:    lm_rra_sqr_sync
//
module lm_rra_sqr_sync #(
           parameter PORT_NUMBER            = 4,
           parameter ROW_CLOCKED_NUMBER     = 2,
           parameter COLUMN_CLOCKED_NUMBER  = 2
       )(
           input           clk,
           input           reset,

           input[PORT_NUMBER*PORT_NUMBER-1:0]       port_req_vec,
           output[PORT_NUMBER*PORT_NUMBER-1:0]      port_grant_vec,
           output                                   arb_out_strobe
       );
localparam CLOCKED_NUMBER   = ROW_CLOCKED_NUMBER+COLUMN_CLOCKED_NUMBER+1;//row+column+1
localparam st0_idle         = {{(CLOCKED_NUMBER-1){1'b0}},1'b1};

wire[PORT_NUMBER-1:0]   north                   [PORT_NUMBER-1:0];
wire[PORT_NUMBER-1:0]   south                   [PORT_NUMBER-1:0];
wire[PORT_NUMBER-1:0]   east                    [PORT_NUMBER-1:0];
wire[PORT_NUMBER-1:0]   west                    [PORT_NUMBER-1:0];
wire[PORT_NUMBER-1:0]   east_rt                 [PORT_NUMBER-1:0];//east_rotate
wire[PORT_NUMBER-1:0]   west_rt                 [PORT_NUMBER-1:0];//west_rotate

wire[PORT_NUMBER-1:0]   req                     [PORT_NUMBER-1:0];
wire[PORT_NUMBER-1:0]   grant                   [PORT_NUMBER-1:0];
wire[PORT_NUMBER-1:0]   grant_rt                [PORT_NUMBER-1:0];

reg[PORT_NUMBER-1:0]    r_head;
reg[PORT_NUMBER-1:0]    g_head;
wire[PORT_NUMBER-1:0]   r_head_next;
wire[PORT_NUMBER-1:0]   g_head_next;
wire[PORT_NUMBER-1:0]   any_grant_row;
wire[PORT_NUMBER-1:0]   any_grant_column;

reg[PORT_NUMBER-1:0]    row_reg[ROW_CLOCKED_NUMBER-1:0];
reg[PORT_NUMBER-1:0]    column_reg[COLUMN_CLOCKED_NUMBER-1:0];

wire[PORT_NUMBER-1:0]   any_req_row;
wire any_req;
reg[CLOCKED_NUMBER-1:0]    state;

genvar i,j;
generate
    for (i=0; i<PORT_NUMBER; i=i+1) begin :cell_row
        for (j=0; j<PORT_NUMBER; j=j+1) begin :cell_column
            assign east_rt[j][i]    = east[i][j];
            assign west[j][i]       = west_rt[i][j];
            assign req[i][j]        = port_req_vec[PORT_NUMBER*i+j];
            assign port_grant_vec[PORT_NUMBER*i+j] = grant[i][j];
            assign grant_rt[j][i]   = grant[i][j];

            lm_rra_arb_sync_cell
                u_lm_rra_arb_sync_cell(
                    .north  ( north[i][j]  ),
                    .south  ( south[i][j]  ),
                    .west   ( west[i][j]   ),
                    .east   ( east[i][j]   ),
                    .req    ( req[i][j]    ),
                    .grant  ( grant[i][j]  ),
                    .r_head ( r_head[i]    ),
                    .g_head ( g_head[j]    )
                );
        end

        if (i==0) begin
            assign north[i]     = row_reg[0];
        end else if ((i%(PORT_NUMBER/ROW_CLOCKED_NUMBER))==0) begin
            assign north[i]     = row_reg[i/(PORT_NUMBER/ROW_CLOCKED_NUMBER)];
        end else begin
            assign north[i]     = south[i-1];
        end

        if (i==0) begin
            assign west_rt[i]   = column_reg[0];
        end else if ((i%(PORT_NUMBER/COLUMN_CLOCKED_NUMBER))==0) begin
            assign west_rt[i]   = column_reg[i/(PORT_NUMBER/COLUMN_CLOCKED_NUMBER)];;
        end else begin
            assign west_rt[i]   = east_rt[i-1];
        end

        assign any_grant_row[i] = |grant[i];
        assign any_req_row[i]   = |req[i];

    end

    for (i=0; i<ROW_CLOCKED_NUMBER; i=i+1) begin :loop_row_reg
        always @(posedge clk) begin
            if (reset) begin
                row_reg[i]      <= {PORT_NUMBER{1'b0}};
            end else begin
                row_reg[i]      <= south[(((ROW_CLOCKED_NUMBER-1+i)%ROW_CLOCKED_NUMBER))*
                                    (PORT_NUMBER/ROW_CLOCKED_NUMBER)+(PORT_NUMBER/ROW_CLOCKED_NUMBER)-1];
            end
        end
    end

    for (j=0; j<COLUMN_CLOCKED_NUMBER; j=j+1) begin :loop_column_reg
        always @(posedge clk) begin
            if (reset) begin
                column_reg[j]   <= {PORT_NUMBER{1'b0}};
            end else begin
                column_reg[j]   <= east_rt[(((COLUMN_CLOCKED_NUMBER-1+j)%COLUMN_CLOCKED_NUMBER))*
                                    (PORT_NUMBER/COLUMN_CLOCKED_NUMBER)+(PORT_NUMBER/COLUMN_CLOCKED_NUMBER)-1];
            end
        end
    end

endgenerate

generate
    for (j=0; j<PORT_NUMBER; j=j+1) begin :grant_lolumn_loop
        assign any_grant_column[j] = |grant_rt[j];
    end
endgenerate

always @(posedge clk) begin
    if (reset) begin
        r_head  <= {{(PORT_NUMBER-1){1'b0}},1'b1};//init
        g_head  <= {{(PORT_NUMBER-1){1'b0}},1'b1};//init
    end else if (state[CLOCKED_NUMBER-1]) begin
        r_head  <= r_head_next;
        g_head  <= g_head_next;
    end else begin
        r_head  <= r_head;
        g_head  <= g_head;
    end
end

rra_pointer_cal#(
                   .POINTER_WIDTH  ( PORT_NUMBER   )
               )u_r_head_cal(
                   .pointer_pre    ( r_head        ),
                   .gnt_info       ( any_grant_row ),
                   .pointer_next   ( r_head_next   )
               );

rra_pointer_cal#(
                   .POINTER_WIDTH  ( PORT_NUMBER       )
               )u_g_head_cal(
                   .pointer_pre    ( g_head            ),
                   .gnt_info       ( any_grant_column  ),
                   .pointer_next   ( g_head_next       )
               );

always @(posedge clk) begin
    if (reset) begin
        state    <= st0_idle;
    end else if (state[CLOCKED_NUMBER-1] || (st0_idle && ~any_req)) begin
        state    <= st0_idle;
    end else begin
        state    <= state<<1;
    end
end

assign any_req = |any_req_row;
assign arb_out_strobe = state[CLOCKED_NUMBER-1];

endmodule

子模块lm_rra_arb_sync_cell代码:

`timescale 1ns / 1ps
//
// Company: nssc
// Engineer: liumeng
// Create Date:    09:53:03 01/14/2022 
// Module Name:    lm_rra_arb_sync_cell
//
module lm_rra_arb_sync_cell(
           input       north,
           output      south,
           input       west,
           output      east,

           input       req,
           output      grant,

           input       r_head,
           input       g_head
       );

assign south    = (north | r_head) & (~grant);
assign east     = (west | g_head) & (~grant);
assign grant    = (north | r_head) & (west | g_head) & req;

endmodule

子模块rra_pointer_cal代码:

`timescale 1ns / 1ps
//
// Company: nssc
// Engineer: liumeng
// Create Date:    11:59:08 01/16/2022
// Module Name:    rra_pointer_cal
//
module rra_pointer_cal#(
           parameter POINTER_WIDTH = 4
       )(
           input    [POINTER_WIDTH-1:0]pointer_pre,
           input    [POINTER_WIDTH-1:0]gnt_info,
           output   [POINTER_WIDTH-1:0]pointer_next
       );

wire [POINTER_WIDTH*2-1:0] pointer_mask[POINTER_WIDTH-1:0];
wire [POINTER_WIDTH*2-1:0] gnt_shift;
wire [POINTER_WIDTH*2-1:0] thermo_in,thermo_out;
wire [POINTER_WIDTH*2-1:0] thermo_out_edge;
wire [POINTER_WIDTH*2-1:0] thermo_out_edge_shift;
wire [POINTER_WIDTH-1:0]   pointer_update;
wire [POINTER_WIDTH-1:0]   all_gnt_mask;

wire gnt_none,gnt_full;
assign gnt_none     = gnt_info=={POINTER_WIDTH{1'b0}};
assign all_gnt_mask = pointer_pre|({pointer_pre[0],pointer_pre[POINTER_WIDTH-1:1]});
assign gnt_full     = all_gnt_mask==(all_gnt_mask&gnt_info);

genvar i;
generate
    for (i=0; i<POINTER_WIDTH; i=i+1) begin :loop_pointer_mask
        if (i==0) begin
            assign pointer_mask[i]  = {{POINTER_WIDTH{1'b0}},pointer_pre};
        end else begin
            assign pointer_mask[i]  = pointer_mask[i-1] | (pointer_mask[i-1]<<1);
        end
    end
endgenerate

generate
    for (i=0; i<POINTER_WIDTH*2; i=i+1) begin :loop_gnt_shift
        if (i<POINTER_WIDTH ) begin
            assign gnt_shift[i] = gnt_info[i];
        end else begin
            assign gnt_shift[i] = gnt_info[i-POINTER_WIDTH];
        end
    end
endgenerate

assign thermo_in = gnt_shift&pointer_mask[POINTER_WIDTH-1];//全零待处理

inv_thermo_encoder#(
                      .WIDTH        ( POINTER_WIDTH*2   )
                  )u_inv_thermo_encoder(
                      .in           ( thermo_in         ),
                      .thermo_out   ( thermo_out        )
                  );

assign thermo_out_edge          = thermo_out^(thermo_out>>1);
assign thermo_out_edge_shift    = thermo_out_edge<<1;

assign pointer_update   = thermo_out_edge_shift[POINTER_WIDTH-1:0]|thermo_out_edge_shift[POINTER_WIDTH*2-1:POINTER_WIDTH];
assign pointer_next     = gnt_full ? {pointer_pre[POINTER_WIDTH-2:0],pointer_pre[POINTER_WIDTH-1]} :
       gnt_none ? pointer_pre : pointer_update;

endmodule

子模块inv_thermo_encoder代码:

`timescale 1ns / 1ps
//
// Company: nssc
// Engineer: liumeng
// Create Date:    20:13:45 01/11/2022
// Module Name:    inv_thermo_encoder
// Revision 0.01 - File Created
//
module inv_thermo_encoder#(parameter WIDTH = 8)
       (
           input[WIDTH-1 : 0]   in,
           output[WIDTH-1 : 0]  thermo_out
       );

genvar i;
generate
    for(i=WIDTH-1;i>=0;i=i-1)begin :loop
        assign thermo_out[i] = |in[WIDTH-1:i];
    end
endgenerate

endmodule

测试文件代码:

`timescale 1ns / 1ps
//
// Company: nssc
// Engineer: liumeng
// Create Date:    00:15:23 01/12/2022
// Module Name:    sim_lm_rra_sqr_sync
//
module sim_lm_rra_sqr_sync;
parameter PORT_NUMBER               = 4;
parameter ROW_CLOCKED_NUMBER        = 2;
parameter COLUMN_CLOCKED_NUMBER     = 2;

integer seed_dis;
reg clk;
reg reset;
reg enable;
wire [PORT_NUMBER*PORT_NUMBER-1:0] port_req_vec;
wire arb_out_strobe;
wire[1:0]   RG_VEC [PORT_NUMBER*PORT_NUMBER-1:0];

// Outputs
wire [PORT_NUMBER*PORT_NUMBER-1:0] port_grant_vec;
reg[PORT_NUMBER-1:0] port_req [PORT_NUMBER-1:0];
wire[PORT_NUMBER-1:0] port_grant [PORT_NUMBER-1:0];
wire[PORT_NUMBER-1:0] any_grant;
wire[PORT_NUMBER-1:0] any_req;
wire any_port_req;

genvar i,j,k;
generate
    for (i=0; i<PORT_NUMBER; i=i+1) begin
        for (j=0; j<PORT_NUMBER; j=j+1) begin
            assign port_req_vec[PORT_NUMBER*i+j]    = port_req[i][j];
            assign port_grant[i][j] = port_grant_vec[PORT_NUMBER*i+j];

        end

        assign any_grant[i] = |port_grant[i];//i输入被许可
        assign any_req[i]   = |port_req[i];

        always @(posedge clk) begin
            if (reset) begin
                port_req[i]  <= {PORT_NUMBER{1'b0}};
            end else if (enable) begin
                if (arb_out_strobe || (~any_port_req)) begin
                    port_req[i]  <= $dist_uniform(seed_dis, 0, {PORT_NUMBER{1'b1}});
                end else begin
                    port_req[i]  <= port_req[i];
                end
            end else begin
                if (arb_out_strobe) begin
                    port_req[i]  <= {PORT_NUMBER{1'b0}};
                end else begin
                    port_req[i]  <= port_req[i];
                end
            end
        end

    end
endgenerate

generate
    for (k=0; k<PORT_NUMBER*PORT_NUMBER; k=k+1) begin
        assign RG_VEC[k] = {port_req_vec[k],port_grant_vec[k]};
    end
endgenerate

assign any_port_req = |any_req;

initial begin
    clk = 0;
    reset = 0;
    #200;
    reset = 1;
    #500;
    reset = 0;
end
always #15 clk = ~clk;

initial begin
    enable = 0;
    seed_dis = 99;
    #6000;
    enable = 1;
    #30000;
    enable = 0;
    #10000;
    enable = 1;
    #30000;
    enable = 0;

end

lm_rra_sqr_sync#(
    .PORT_NUMBER            ( PORT_NUMBER           ),
    .ROW_CLOCKED_NUMBER     ( ROW_CLOCKED_NUMBER    ),
    .COLUMN_CLOCKED_NUMBER  ( COLUMN_CLOCKED_NUMBER )
)u_lm_rra_sqr_sync(
    .clk                    ( clk                   ),
    .reset                  ( reset                 ),
    .port_req_vec           ( port_req_vec          ),
    .port_grant_vec         ( port_grant_vec        ),
    .arb_out_strobe         ( arb_out_strobe        )
);

endmodule

测试结果:

可见支持群组路由,满足输入请求轮询和输出负载均衡。 

标签:wire,优先级,pointer,轮询,NUMBER,WIDTH,crossbar,POINTER,PORT
来源: https://blog.csdn.net/f601323135/article/details/122535685