FPGA - 仲裁器的设计实现

2024-04-16 06:20
文章标签 实现 设计 fpga 仲裁

本文主要是介绍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 / 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

仿真波形

这篇关于FPGA - 仲裁器的设计实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/908010

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

使用Python快速实现链接转word文档

《使用Python快速实现链接转word文档》这篇文章主要为大家详细介绍了如何使用Python快速实现链接转word文档功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 演示代码展示from newspaper import Articlefrom docx import