FPGA - 仲裁器的设计实现

一,为什么做仲裁

在多主单从的设计中,当多个源端同时发起传输请求时,这个时候就需要仲裁器来根据优先级来判断响应哪一个源端,向其传输数据。比如:以太网仲裁,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 / 1ps

module 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) begin
	ch0_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};    
end

always @(posedge clk) begin
	ch0_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) begin
    if (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;
end

always @(posedge clk) begin
    if (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) begin
	if (reset) 
		cur_status <= IDLE;
	else 
		cur_status <= nxt_status;
end

always @(*) begin
	if (reset) begin
		nxt_status <= IDLE;		
	end
	else begin
		case(cur_status)
			IDLE : begin
				nxt_status <= CH0_SEND;
			end
			CH0_SEND : begin
				if (~ch0_busy && ch0_frame_rdempty)
					nxt_status <= CH1_SEND;
				else if (send_data_last)
					nxt_status <= CH1_SEND;
				else 
					nxt_status <= cur_status;
			end
			CH1_SEND : begin
				if (~ch1_busy && ch1_frame_rdempty)
					nxt_status <= CH0_SEND;
				else if (send_data_last)
					nxt_status <= CH0_SEND;
				else 
					nxt_status <= cur_status;
			end
			default : nxt_status <= IDLE;
		endcase	
	end
end

always @(posedge clk) begin
	if (reset) begin
		send_type      <= 0;
		send_length    <= 0;
        send_data_vld  <= 0;
        send_data_last <= 0;
        send_data      <= 0;
	end
	else begin
		case(cur_status)
			IDLE : begin
				send_type      <= 0;
				send_length    <= 0;
                send_data_vld  <= 0;
                send_data_last <= 0;
                send_data      <= 0;
			end
			CH0_SEND : begin
				if (ch0_frame_rden) begin
					send_type   <= ch0_frame_dout[31:16];
					send_length <= ch0_frame_dout[15:0];
				end
				else begin
					send_type   <= send_type;
					send_length <= send_length;
				end

				if (ch0_data_rden) begin
					send_data_vld  <= 1'b1;
					send_data_last <= ch0_data_dout[8];
					send_data      <= ch0_data_dout[7:0];
				end
				else begin
					send_data_vld  <= 0;
					send_data_last <= 0;
					send_data      <= 0;
				end

			end
			CH1_SEND : begin
				if (ch1_frame_rden) begin
					send_type   <= ch1_frame_dout[31:16];
					send_length <= ch1_frame_dout[15:0];
				end
				else begin
					send_type   <= send_type;
					send_length <= send_length;
				end

				if (ch1_data_rden) begin
					send_data_vld  <= 1'b1;
					send_data_last <= ch1_data_dout[8];
					send_data      <= ch1_data_dout[7:0];
				end
				else begin
					send_data_vld  <= 0;
					send_data_last <= 0;
					send_data      <= 0;
				end		
			end
			default : ;
		endcase
	end
end

/*--------------------------------------------------*\
	                FIFO读使能设计
\*--------------------------------------------------*/
always @(posedge clk) begin
    if (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;
end

always @(posedge clk) begin
    if (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;
end

always @(posedge clk) begin
    if (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;
end

always @(posedge clk) begin
    if (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) begin
    if (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;
end

always @(posedge clk) begin
    if (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;
end

always @(posedge clk) begin
    if (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;
end

always @(posedge clk) begin
    if (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 / 1ps

module 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 begin
		clk = 0;
		forever #(10) 
		clk = ~clk;
	end

	initial begin
		reset = 1;
		#(2000) 
		reset = 0;
	end


	data_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

仿真波形

相关推荐

  1. 基于FPGAUDP协议栈设计第六章_仲裁模块设计

    2024-04-23 02:44:01       44 阅读
  2. 什么是仲裁(Arbiter)?

    2024-04-23 02:44:01       85 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-23 02:44:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-23 02:44:01       101 阅读
  3. 在Django里面运行非项目文件

    2024-04-23 02:44:01       82 阅读
  4. Python语言-面向对象

    2024-04-23 02:44:01       91 阅读

热门阅读

  1. Elasticsearch克隆索引

    2024-04-23 02:44:01       41 阅读
  2. 什么是掩码补丁位置?

    2024-04-23 02:44:01       54 阅读
  3. 图标字体库——Font Awesome

    2024-04-23 02:44:01       37 阅读
  4. MySQL用户和权限管理深入指南

    2024-04-23 02:44:01       30 阅读
  5. 机器学习——逻辑回归

    2024-04-23 02:44:01       36 阅读
  6. 如何使用React.js从头开始构建TODO应用

    2024-04-23 02:44:01       31 阅读
  7. hbase基础(三)

    2024-04-23 02:44:01       35 阅读
  8. FreeLearning PHP 译文集翻译完成

    2024-04-23 02:44:01       37 阅读
  9. ELB 后端主机异常

    2024-04-23 02:44:01       33 阅读
  10. JVM面试题

    2024-04-23 02:44:01       36 阅读