一种基于优先级轮询调度负载均衡的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