一,为什么做仲裁
在多主单从的设计中,当多个源端同时发起传输请求时,这个时候就需要仲裁器来根据优先级来判断响应哪一个源端,向其传输数据。比如:以太网仲裁,DDR仲裁,光纤传图仲裁.....
二,仲裁类别
仲裁器分为轮询仲裁(Round-Robiin)与固定优先级仲裁(Fixed-Priority),轮询仲裁,各个源端优先级相同,当同时发起请求时,依次进行响应,而固定优先级仲裁就是根据优先级顺序依次进行响应。
轮询仲裁:每一路数据的优先级都是一样的
中断仲裁:有一路或者多路的优先级是最高的
用的比较多的方法就是轮询仲裁
三,轮询仲裁
在实际项目中,如果需要用到仲裁,可以以2路数据作为分析:
① :缓存每一路的数据
使用两个FIFO,
数据FIFO缓存:data+last(last信号的作用指示每一帧数据的边界)
控制FIFO缓存:缓存数据对应的信息:类型、地址、长度……
② :设计状态机(轮询跳变)
复位状态机处于IDLE,复位结束调到发送通道0的状态
发送通道0状态:开始判断通道0的数据有没有来(询问),如果通道0没有来数据,则调到通道1。
如果通道0有数据来,则把通道0的数据从FIFO里面读出来,发送出去,然后跳到通道1。
发送通道1状态:开始判断通道1的数据有没有来(询问),如果通道1没有来数据,则调到通道2。
如果通道1有数据来,则把通道1的数据从FIFO里面读出来,发送出去,然后跳到通道2。
…….
四,轮询仲裁逻辑设计
以2通道设计为例:
`timescale 1ns / 1psmodule mux2_arbit(input clk ,input reset ,input [15:0] ch0_type , //默认所有通道传来的信号都是reg型,所以进行无需打拍input [15:0] ch0_length ,input ch0_data_vld ,input ch0_data_last ,input [7:0] ch0_data ,input [15:0] ch1_type ,input [15:0] ch1_length ,input ch1_data_vld ,input ch1_data_last ,input [7:0] ch1_data ,output reg [15:0] send_type ,output reg [15:0] send_length ,output reg send_data_vld ,output reg send_data_last ,output reg [7:0] send_data );
/*--------------------------------------------------*\状态机信号定义
\*--------------------------------------------------*/
reg [2:0] cur_status;
reg [2:0] nxt_status;
localparam IDLE = 2'b00;
localparam CH0_SEND = 2'b01;
localparam CH1_SEND = 2'b10;
/*--------------------------------------------------*\FIFO端口信号
\*--------------------------------------------------*/
reg [31:0] ch0_frame_din ;
reg ch0_frame_wren ;
wire [31:0] ch0_frame_dout ;
reg ch0_frame_rden ;
wire ch0_frame_wrfull ;
wire ch0_frame_rdempty;
wire [4:0] ch0_frame_count ;reg [31:0] ch1_frame_din ;
reg ch1_frame_wren ;
wire [31:0] ch1_frame_dout ;
reg ch1_frame_rden ;
wire ch1_frame_wrfull ;
wire ch1_frame_rdempty;
wire [4:0] ch1_frame_count ;reg [8:0] ch0_data_din ;
reg ch0_data_wren ;
wire [8:0] ch0_data_dout ;
reg ch0_data_rden ;
wire ch0_data_wrfull ;
wire ch0_data_rdempty;
wire [11:0] ch0_data_count ;reg [8:0] ch1_data_din ;
reg ch1_data_wren ;
wire [8:0] ch1_data_dout ;
reg ch1_data_rden ;
wire ch1_data_wrfull ;
wire ch1_data_rdempty;
wire [11:0] ch1_data_count ;/*--------------------------------------------------*\其他端口信号
\*--------------------------------------------------*/
reg ch0_busy;
reg ch1_busy;reg ch0_frame_fifo_err;
reg ch1_frame_fifo_err;
reg ch0_data_fifo_err ;
reg ch1_data_fifo_err ;/*--------------------------------------------------*\通道0、通道1的数据写入FIFO
\*--------------------------------------------------*/
always @(posedge clk) beginch0_frame_wren <= ch0_data_last;ch0_frame_din <= {ch0_type,ch0_length};ch1_frame_wren <= ch1_data_last;ch1_frame_din <= {ch1_type,ch1_length};
endalways @(posedge clk) beginch0_data_wren <= ch0_data_vld;ch0_data_din <= {ch0_data_last,ch0_data}; ch1_data_wren <= ch1_data_vld;ch1_data_din <= {ch1_data_last,ch1_data};
end/*--------------------------------------------------*\busy信号
\*--------------------------------------------------*/
always @(posedge clk) beginif (reset) ch0_busy <= 0;else if (cur_status == CH0_SEND && send_data_last) ch0_busy <= 0;else if (cur_status == CH0_SEND && ~ch0_frame_rdempty)ch0_busy <= 1;
endalways @(posedge clk) beginif (reset) ch1_busy <= 0;else if (cur_status == CH1_SEND && send_data_last) ch1_busy <= 0;else if (cur_status == CH1_SEND && ~ch1_frame_rdempty)ch1_busy <= 1;
end/*--------------------------------------------------*\状态机设计
\*--------------------------------------------------*/
always @(posedge clk) beginif (reset) cur_status <= IDLE;else cur_status <= nxt_status;
endalways @(*) beginif (reset) beginnxt_status <= IDLE; endelse begincase(cur_status)IDLE : beginnxt_status <= CH0_SEND;endCH0_SEND : beginif (~ch0_busy && ch0_frame_rdempty)nxt_status <= CH1_SEND;else if (send_data_last)nxt_status <= CH1_SEND;else nxt_status <= cur_status;endCH1_SEND : beginif (~ch1_busy && ch1_frame_rdempty)nxt_status <= CH0_SEND;else if (send_data_last)nxt_status <= CH0_SEND;else nxt_status <= cur_status;enddefault : nxt_status <= IDLE;endcase end
endalways @(posedge clk) beginif (reset) beginsend_type <= 0;send_length <= 0;send_data_vld <= 0;send_data_last <= 0;send_data <= 0;endelse begincase(cur_status)IDLE : beginsend_type <= 0;send_length <= 0;send_data_vld <= 0;send_data_last <= 0;send_data <= 0;endCH0_SEND : beginif (ch0_frame_rden) beginsend_type <= ch0_frame_dout[31:16];send_length <= ch0_frame_dout[15:0];endelse beginsend_type <= send_type;send_length <= send_length;endif (ch0_data_rden) beginsend_data_vld <= 1'b1;send_data_last <= ch0_data_dout[8];send_data <= ch0_data_dout[7:0];endelse beginsend_data_vld <= 0;send_data_last <= 0;send_data <= 0;endendCH1_SEND : beginif (ch1_frame_rden) beginsend_type <= ch1_frame_dout[31:16];send_length <= ch1_frame_dout[15:0];endelse beginsend_type <= send_type;send_length <= send_length;endif (ch1_data_rden) beginsend_data_vld <= 1'b1;send_data_last <= ch1_data_dout[8];send_data <= ch1_data_dout[7:0];endelse beginsend_data_vld <= 0;send_data_last <= 0;send_data <= 0;end enddefault : ;endcaseend
end/*--------------------------------------------------*\FIFO读使能设计
\*--------------------------------------------------*/
always @(posedge clk) beginif (reset) ch0_frame_rden <= 0;else if (cur_status == CH0_SEND && ~ch0_frame_rdempty && ~ch0_busy) ch0_frame_rden <= 1'b1;else ch0_frame_rden <= 0;
endalways @(posedge clk) beginif (reset) ch1_frame_rden <= 0;else if (cur_status == CH1_SEND && ~ch1_frame_rdempty && ~ch1_busy) ch1_frame_rden <= 1'b1;else ch1_frame_rden <= 0;
endalways @(posedge clk) beginif (reset) ch0_data_rden <= 0;else if (ch0_data_rden && ch0_data_dout[8]) ch0_data_rden <= 0;else if (ch0_frame_rden)ch0_data_rden <= 1'b1;else ch0_data_rden <= ch0_data_rden;
endalways @(posedge clk) beginif (reset) ch1_data_rden <= 0;else if (ch1_data_rden && ch1_data_dout[8]) ch1_data_rden <= 0;else if (ch1_frame_rden)ch1_data_rden <= 1'b1;else ch1_data_rden <= ch1_data_rden;
end/*--------------------------------------------------*\调试信号
\*--------------------------------------------------*/
always @(posedge clk) beginif (reset) ch0_frame_fifo_err <= 0;else if (ch0_frame_wren && ch0_frame_wrfull) ch0_frame_fifo_err <= 1;else ch0_frame_fifo_err <= ch0_frame_fifo_err;
endalways @(posedge clk) beginif (reset) ch1_frame_fifo_err <= 0;else if (ch1_frame_wren && ch1_frame_wrfull) ch1_frame_fifo_err <= 1;else ch1_frame_fifo_err <= ch1_frame_fifo_err;
endalways @(posedge clk) beginif (reset) ch0_data_fifo_err <= 0;else if (ch0_data_wren && ch0_data_wrfull) ch0_data_fifo_err <= 1;else ch0_data_fifo_err <= ch0_data_fifo_err;
endalways @(posedge clk) beginif (reset) ch1_data_fifo_err <= 0;else if (ch1_data_wren && ch1_data_wrfull) ch1_data_fifo_err <= 1;else ch1_data_fifo_err <= ch1_data_fifo_err;
end/*--------------------------------------------------*\例化
\*--------------------------------------------------*/
fifo_w9xd2048 ch0_data_fifo (.clk (clk), // input wire clk.srst (reset), // input wire srst.din (ch0_data_din), // input wire [8 : 0] din.wr_en (ch0_data_wren), // input wire wr_en.rd_en (ch0_data_rden), // input wire rd_en.dout (ch0_data_dout), // output wire [8 : 0] dout.full (ch0_data_wrfull), // output wire full.empty (ch0_data_rdempty), // output wire empty.data_count(ch0_data_count) // output wire [11 : 0] data_count
);fifo_w9xd2048 ch1_data_fifo (.clk (clk), // input wire clk.srst (reset), // input wire srst.din (ch1_data_din), // input wire [8 : 0] din.wr_en (ch1_data_wren), // input wire wr_en.rd_en (ch1_data_rden), // input wire rd_en.dout (ch1_data_dout), // output wire [8 : 0] dout.full (ch1_data_wrfull), // output wire full.empty (ch1_data_rdempty), // output wire empty.data_count(ch1_data_count) // output wire [11 : 0] data_count
);fifo_w32xd16 ch0_frame_fifo (.clk (clk), // input wire clk.srst (reset), // input wire srst.din (ch0_frame_din), // input wire [31 : 0] din.wr_en (ch0_frame_wren), // input wire wr_en.rd_en (ch0_frame_rden), // input wire rd_en.dout (ch0_frame_dout), // output wire [31 : 0] dout.full (ch0_frame_wrfull), // output wire full.empty (ch0_frame_rdempty), // output wire empty.data_count(ch0_frame_count) // output wire [4 : 0] data_count
);fifo_w32xd16 ch1_frame_fifo (.clk (clk), // input wire clk.srst (reset), // input wire srst.din (ch1_frame_din), // input wire [31 : 0] din.wr_en (ch1_frame_wren), // input wire wr_en.rd_en (ch1_frame_rden), // input wire rd_en.dout (ch1_frame_dout), // output wire [31 : 0] dout.full (ch1_frame_wrfull), // output wire full.empty (ch1_frame_rdempty), // output wire empty.data_count(ch1_frame_count) // output wire [4 : 0] data_count
);endmodule
编写测试:
`timescale 1ns / 1psmodule tb();parameter CH0_LENGTH = 256 ;parameter CH0_PERIOD = 300 ; parameter CH1_LENGTH = 256 ;parameter CH1_PERIOD = 300 ;reg clk;reg reset;wire ch0_data_vld;wire ch0_data_last;wire [7:0] ch0_data;wire ch1_data_vld;wire ch1_data_last;wire [7:0] ch1_data;wire [15:0] send_type;wire [15:0] send_length;wire send_data_vld;wire send_data_last;wire [7:0] send_data ;initial beginclk = 0;forever #(10) clk = ~clk;endinitial beginreset = 1;#(2000) reset = 0;enddata_generate #(.LENGTH(CH0_LENGTH),.PERIOD(CH0_PERIOD)) data_generate_ch0 (.clk (clk),.reset (reset),.send_data_vld (ch0_data_vld),.send_data_last (ch0_data_last),.send_data (ch0_data));data_generate #(.LENGTH(CH1_LENGTH),.PERIOD(CH1_PERIOD)) data_generate_ch1 (.clk (clk),.reset (reset),.send_data_vld (ch1_data_vld),.send_data_last (ch1_data_last),.send_data (ch1_data));mux2_arbit mux2_arbit(.clk (clk),.reset (reset),.ch0_type (16'h0001),.ch0_length (CH0_LENGTH),.ch0_data_vld (ch0_data_vld),.ch0_data_last (ch0_data_last),.ch0_data (ch0_data),.ch1_type (16'h0002),.ch1_length (CH1_LENGTH),.ch1_data_vld (ch1_data_vld),.ch1_data_last (ch1_data_last),.ch1_data (ch1_data),.send_type (send_type),.send_length (send_length),.send_data_vld (send_data_vld),.send_data_last (send_data_last),.send_data (send_data));endmodule
仿真波形