【数集项目之 MCDF】(三) 仲裁器 arbiter
接下来进行仲裁器 arbiter
的设计。根据设计文档,我们知道从输入总共有3个通道,而这三个通道很有可能都接收到数据可以进行发送。而arbiter
就是综合优先级、是否有包可以发送等因素,选择一个通道来进行发送。形象的可以将arbiter
比喻成“一个多选1开关”,它来负责控制最后的整形模块formatter
和哪个slave_FIFO
接在一起,因此力求在设计时,如果arbiter
选择了一个通道后,arbiter
就是透明的,尽量不产生始终延迟,使选通的通道直接和formatter
联通。
基于以上想法,结合arbiter
的多选1开关结构,我先设计arbiter结构示意图,主要采用组合逻辑,只有优先级产生模块使用时序电路,最后用verilog参考结构示意图完成设计。
第一节 arbiter
文档理解
文档相关内容部分引用如下
如果
formatter
的发送数据请求信号f2a_id_req_i为高,则arbiter
根据slave0_FIFO
的发送请求信号slv0_req_i
、slave1_FIFO
发送请求信号slv1_req_i
、slave2_FIFO
发送请求信号slv2_req_i
,按优先级确定响应通道的发送请求,并根据通道的编号(id=0, 1, 2)X产生以下信号送到formatter
:
a2f_id_o = X(通道编号)
a2f_data_o = slvX_data_i
a2f_pkglen_sel_o = slvX_pkglen_i
a2f_val_o = slvX_val_i
将formatter的响应信号送往对应的slave通道:
a2sX_ack_o = f2a_ack_i
如果各通道的优先级相同,则按通道编号从低到高轮流发送。
综合优先级产生:
我们发现文档中优先级描述是文字化的,参考微机原理中学到“人工优先级”、“自然优先级”的相关知识,迁移到本模块中。文档中的意思是:控制寄存器为通道配置的寄存器占优先级中的dominant地位,而自然优先级处于优先级比较中的minimal地位。我们将这两者优先级结合的优先级暂时称之为综合优先级。
为了将综合优先级用表达式表达出来以便直接比较,这里采用直接按位组合的方法,因为二进制数高位自然地处于dominant地位。
c h x _ p r i o _ s y n = s l v x _ p r i o _ i ∗ 4 + s l v x _ p r i o _ n a t u r e chx\_prio\_syn=slvx\_prio\_i*4+slvx\_prio\_nature chx_prio_syn=slvx_prio_i∗4+slvx_prio_nature 将该表达式转换为verilog语言如下
assign ch0_prio_syn=({2'b0,slv0_prio_i}<<2)+'d0;//[3:2是设置prio][1:0是自然prio,3:2相等时才起作用]
assign ch1_prio_syn=({2'b0,slv1_prio_i}<<2)+'d1;
assign ch2_prio_syn=({2'b0,slv2_prio_i}<<2)+'d2;
有了自然优先级之后,我们便可以据此来判断选择哪个通道了。
综合优先级判断:
根据文档中的描述,优先级数值越小,优先级越高。综合优先级继承了这样的特性。但是对于3个优先级,不同于2个数值之间直接比较那么简单,这里采用的是嵌套if-else
的方法实现最小值寻找。
//根据综合优先级得出最优先通道(数值最小)
always @(*) begin//综合优先级生成电路保证不可能相等if(ch0_prio_syn>ch1_prio_syn)beginif(ch1_prio_syn>ch2_prio_syn)channel_prio<=6'b10_01_00;else beginif(ch0_prio_syn>ch2_prio_syn)channel_prio<=6'b01_10_00;elsechannel_prio<=6'b01_00_10;endendelse beginif(ch1_prio_syn<ch2_prio_syn)channel_prio<=6'b00_01_10;else beginif(ch0_prio_syn<ch2_prio_syn)channel_prio<=6'b00_10_01;elsechannel_prio<=6'b10_00_01;end end
end
有了综合优先级生成和比较,这样我们就能找出优先级最高的通道了,每次arbiter或者更高级请求发送数据包时,我们只要比较一下当前优先级最高的通道(刷新综合优先级),然后直接选通对应通道,将各种信号按照文档中给的对应关系进行wire连接就可以了。
下面介绍结构设计,可以参考设计文档中的端口声明。
第二节 arbiter
结构设计
正如结构图所示,只有仲裁信号产生部分是时序电路,其余都是组合逻辑。因此当选通某一通道时,相当于formatter
和slave_FIFO
直连,而此时arbiter
是透明的。
仲裁在formatter发来请求发送信号时进行运算,刷新出当前最优通道,在下一时钟周期的上升沿刷新选择器和分配器的使能端,完成选通任务。
值得一提的是,由于设计只有3个通道,分别用00
、01
、10
表示,而考虑到复位情况不能选择任何一个通道(因为可能3个通道都没接收足够数据发送),并且对于这么多arbiter输出信号复位赋值语句较多,因此这里设置一个虚拟通道(图中未画出),编号是11
。提前设定好虚拟通道各信号的值等于复位信号,当复位时,只需要把formatter
和虚拟通道接通即可。
第三节 arbiter
代码设计
根据上一节的结构图,可以很容易写出代码。
文件名称:arbiter.v
/*************************<MCDF仲裁器>*********************/
`timescale 1ns/100ps
/*************************<端口声明>*********************/
module arbiter
(
//Inputinput wire clk_i,rstn_i,
/*******************<control register 接口>*******/input wire [1:0] slv0_prio_i,slv1_prio_i,slv2_prio_i,input wire [2:0] slv0_pkglen_i,slv1_pkglen_i,slv2_pkglen_i,
/*******************<slave 接口>*********************/input wire [31:0] slv0_data_i,slv1_data_i,slv2_data_i,input wire slv0_req_i,slv1_req_i,slv2_req_i, slv0_val_i,slv1_val_i,slv2_val_i,input wire slv0_end_i, //!!!增加的信号input wire slv1_end_i, //!!!增加的信号input wire slv2_end_i, //!!!增加的信号
/*******************<formatter 接口>*********************/ input wire f2a_id_req_i, //formatter请求接收f2a_ack_i,
//Output
/*******************<slave 接口>*********************/ output reg a2s0_ack_o, //[-slv]f2a_ack_ia2s1_ack_o,a2s2_ack_o,
/*******************<formatter 接口>*********************/a2f_val_o, //[-slv]slvx_val_i,包有效包络信号output reg [1:0] a2f_id_o, //通道编号output reg [31:0] a2f_data_o, //[-slv]slvx_data_ioutput reg [2:0] a2f_pkglen_sel_o, //[-slv]slvx_pkglen_ioutput reg a2f_end_o //!!!增加的信号
);
/*****************<中间信号>*********************/
wire [3:0] ch0_prio_syn,//各通道综合优先级,计算方法见下ch1_prio_syn,ch2_prio_syn;
reg [5:0] channel_prio;//通道优先级综合排序寄存器[5:4最高优先级通道序号][3:2次高优先级通道序号][1:0最低优先级通道序号]
wire [2:0] slvx_req;//输入请求集中,!!!写成向量比数组更好,向量可以查看值,防止出错
assign slvx_req[0]=slv0_req_i;
assign slvx_req[1]=slv1_req_i;
assign slvx_req[2]=slv2_req_i;
/*****************<综合优先级生成电路:组合逻辑>*********************/
assign ch0_prio_syn=({2'b0,slv0_prio_i}<<2)+'d0;//[3:2是设置prio][1:0是自有prio,3:2相等时才起作用]
assign ch1_prio_syn=({2'b0,slv1_prio_i}<<2)+'d1;
assign ch2_prio_syn=({2'b0,slv2_prio_i}<<2)+'d2;
/*****************<优先级整合逻辑>*********************/
//根据综合优先级得出最优先通道(数值最小)
always @(*) begin//综合优先级生成电路保证不可能相等if(ch0_prio_syn>ch1_prio_syn)beginif(ch1_prio_syn>ch2_prio_syn)channel_prio<=6'b10_01_00;else beginif(ch0_prio_syn>ch2_prio_syn)channel_prio<=6'b01_10_00;elsechannel_prio<=6'b01_00_10;endendelse beginif(ch1_prio_syn<ch2_prio_syn)channel_prio<=6'b00_01_10;else beginif(ch0_prio_syn<ch2_prio_syn)channel_prio<=6'b00_10_01;elsechannel_prio<=6'b10_00_01;end end
end
/*****************<时序电路>*********************/
//用于产生仲裁信号 a2f_id_o !!!如果都没准备号,就发送11
always @(posedge clk_i or negedge rstn_i) beginif(~rstn_i)begin//输出全部置0a2f_id_o<=2'b11;//进入default间接置0endelse if(f2a_id_req_i)begin//当上级(formatter)命令可以发送包!!!f2a_id_req_i应当时单周期信号,不能持续if(slvx_req[channel_prio[5:4]])//先查看优先级最高的slave是否请求发送a2f_id_o<=channel_prio[5:4];else if(slvx_req[channel_prio[3:2]])a2f_id_o<=channel_prio[3:2];else if(slvx_req[channel_prio[1:0]])a2f_id_o<=channel_prio[1:0];elsea2f_id_o<=2'b11;endelsea2f_id_o<=a2f_id_o;
end/*****************<多路选择器部分>*********************/
always @(*) begincase(a2f_id_o)2'b00:begina2f_val_o=slv0_val_i;a2f_data_o=slv0_data_i; a2f_pkglen_sel_o=slv0_pkglen_i;a2s0_ack_o=f2a_ack_i;a2s1_ack_o=0;a2s2_ack_o=0;a2f_end_o=slv0_end_i;end2'b01:begina2f_val_o=slv1_val_i;a2f_data_o=slv1_data_i; a2f_pkglen_sel_o=slv1_pkglen_i; a2s0_ack_o=0;a2s1_ack_o=f2a_ack_i;a2s2_ack_o=0;a2f_end_o=slv1_end_i;end2'b10:begina2f_val_o=slv2_val_i;a2f_data_o=slv2_data_i; a2f_pkglen_sel_o=slv2_pkglen_i;a2s0_ack_o=0;a2s1_ack_o=0;a2s2_ack_o=f2a_ack_i;a2f_end_o=slv2_end_i;end2'b11:begin//defaulta2f_val_o=0;a2f_data_o=0; a2f_pkglen_sel_o=0;a2s0_ack_o=0;a2s1_ack_o=0;a2s2_ack_o=0;a2f_end_o=0;endendcase
end
endmodule
第四节 arbiter
testbench实现
文件名称:arbiter_tb.v
`timescale 1ns/1ns
`include "arbiter.v"
/*************************<端口声明>*********************/
module arbiter_tb;
reg clk_i,rstn_i;
/********<control register 接口>*******/
reg [1:0] slv0_prio_i,slv1_prio_i,slv2_prio_i;
reg [2:0] slv0_pkglen_i,slv1_pkglen_i,slv2_pkglen_i;
/********<slave 接口>*********************/
reg [31:0] slv0_data_i,slv1_data_i,slv2_data_i;
reg slv0_req_i,slv1_req_i,slv2_req_i, slv0_val_i,slv1_val_i,slv2_val_i,slv0_end_i,slv1_end_i,slv2_end_i;/********<formatter 接口>*********************/
reg f2a_id_req_i, //formatter请求接收f2a_ack_i;
/********<slave 接口>*********************/
wire a2s0_ack_o, //[-slv]f2a_ack_ia2s1_ack_o,a2s2_ack_o,
/********<formatter 接口>*********************/a2f_val_o; //[-slv]slvx_val_i,包有效包络信号
wire [1:0] a2f_id_o; //通道编号
wire [31:0] a2f_data_o; //[-slv]slvx_data_i
wire [2:0] a2f_pkglen_sel_o; //[-slv]slvx_pkglen_i/********************<实例化arbiter>*********************/
arbiter ar1(clk_i,rstn_i,slv0_prio_i,slv1_prio_i,slv2_prio_i,slv0_pkglen_i,slv1_pkglen_i,slv2_pkglen_i,slv0_data_i,slv1_data_i,slv2_data_i,slv0_req_i,slv1_req_i,slv2_req_i, slv0_val_i,slv1_val_i,slv2_val_i,slv0_end_i,slv1_end_i,slv2_end_i,f2a_id_req_i, f2a_ack_i,a2s0_ack_o, a2s1_ack_o,a2s2_ack_o,a2f_val_o, a2f_id_o, a2f_data_o, a2f_pkglen_sel_o,a2f_end_o
);
initial begin
/*********<初始化>**********/clk_i<=0;rstn_i<=0;//slv0_end_i<=0;slv1_end_i<=0;slv2_end_i<=0;slv0_prio_i<=2'b11;//slv1_prio_i<=2'b01;//这个是最优先通道slv2_prio_i<=2'b01;//次优先通道slv0_pkglen_i<=2'b10;//slv1_pkglen_i<=2'b01;//数据长8slv2_pkglen_i<=2'b00;//数据长4slv0_data_i<=$random;slv1_data_i<=$random;slv2_data_i<=$random;slv0_req_i<=0;slv1_req_i<=0;slv2_req_i<=0; slv0_val_i<=0;slv1_val_i<=0;slv2_val_i<=0;f2a_id_req_i<=0;//短时信号,在slvx_req_i就绪之后 f2a_ack_i<=0;//在slvx_req_i就绪之后$dumpfile("arbiter.vcd");$dumpvars;
/*********<生成波形>**********/
#25 rstn_i<=1;
#20 slv0_req_i<=1;slv1_req_i<=1;slv2_req_i<=1;
@(posedge clk_i)beginf2a_id_req_i<=1;//两个短时信号
end@(posedge clk_i)beginf2a_id_req_i<=0;f2a_ack_i<=1;
end@(posedge clk_i)beginf2a_ack_i<=0;
endrepeat(8)begin@(posedge clk_i)beginslv0_data_i<=$random;slv1_data_i<=$random;slv2_data_i<=$random;slv0_val_i<=0;slv1_val_i<=1;slv2_val_i<=0; endendslv0_end_i<=1;slv1_end_i<=1;slv2_end_i<=1;
@(posedge clk_i)beginslv0_data_i<=$random;slv1_data_i<=$random;slv2_data_i<=$random;slv0_end_i<=0;slv1_end_i<=0;slv2_end_i<=0; slv0_val_i<=0;slv1_val_i<=0;slv2_val_i<=0;slv0_req_i<=0;slv1_req_i<=0;slv2_req_i<=0;
end
#2000 $finish;
end
always #10 clk_i<=~clk_i;
endmodule
波形如图
本例中由于存在一些握手机制,统一在MCDF最后的波形仿真中进行分析
【数集项目之 MCDF】(三) 仲裁器 arbiter相关推荐
- 【数集项目之 MCDF】(五) 最终整合:MCDF顶层文件
根据前面几章的介绍,我们已经大致完成了MCDF的子模块设计和波形测试,分别是control_regisyer.slave_FIFO.arbiter.formatter. 当然,由于握手机制等一 ...
- 【数集项目之 MCDF】(一) 控制寄存器 control_register
写在前面 本项目为MCDF数据整形器设计,所有的参考代码见我的github https://github.com/SuperiorLQF/verilog_ALL/tree/master/MCDF ...
- 【数集项目之 MCDF】(四) 整形器 formatter
根据上一章的arbiter结构图,结合设计文档中MCDF的整体结构图,可以发现formatter整形器模块是arbiter的上级,负责最终的数据输出,与外界数据接收端相连. 第一节 fromatt ...
- round robin arbiter 轮询仲裁器设计
前言 仲裁器Arbiter是数字设计中非常常见的模块,应用也非常广泛.定义就是当有两个或两个以上的模块需要占用同一个资源的时候,我们需要由仲裁器arbiter来决定哪一个模块来占有这个资源.一般来说, ...
- 仲裁器设计(1)固定优先级仲裁器
仲裁器Arbiter是数字设计中非常常见的模块,应用也非常广泛.定义就是当有两个或两个以上的模块需要占用同一个资源的时候,我们需要由仲裁器arbiter来决定哪一个模块来占有这个资源.类比一下,老师上 ...
- Verilog——一个简单仲裁器的实现
Verilog--一个简单仲裁器的实现 仲裁器基本功能 仲裁器(arbiter) 的主要功能是,多个source源同时发出请求时,根据当前的优先级来判断应响应哪一个source. 仲裁器分为轮询优先级 ...
- 仲裁器设计(二)-- Round Robin Arbiter 轮询调度算法
作者:李虹江 原文:https://mp.weixin.qq.com/s/r-nckE5nGz9mc5KqjPXKYg 本文授权转自IC加油站微信号,未经作者授权,严禁二次转载. 上一篇老李讲了固定优 ...
- 【数字IC/FPGA】仲裁器进阶--Round Robin Arbiter
Round Robin Arbiter 固定优先级的缺点是:每个模块的优先级自始至终是固定不变的,这在某种程度上来说是不公平的,Round Robin就是考虑到公平性的一种仲裁算法.其基本思路是,当一 ...
- Verilog权重轮询仲裁器设计——Weighted Round Robin Arbiter
前两篇讲了固定优先级仲裁器的设计.轮询仲裁器的设计 Verilog固定优先级仲裁器--Fixed Priority Arbiter_weixin_42330305的博客-CSDN博客 Verilog轮 ...
最新文章
- 高可用 Redis 服务架构分析与搭建
- python持久化存储文件操作
- 不学无数——SpringBoot入门Ⅷ
- CRC32算法详细推导(2)
- 鸿蒙手机是个噱头,华为鸿蒙不是谈判噱头 必要时会应用手机当中!
- PAT 1017 Queueing at Bank[一般]
- mysql5.7下载及详细安装教程_MySQL 5.7 下载及安装教程(详细)
- 大数据爆炸改变企业的决策
- SqlServer 2008R2修改表结构提示“不允许保存更改”解决方案
- javascript服务器端验证_Blazor对打JavaScript:谁会成为前端应用程序的首选框架?...
- android下载文件下载不完全解决方案
- 【专升本计算机】计算机文化基础练习题(选择题300道附答案)
- 路由器就能赚钱? 揭秘京东云无线宝背后的黑科技
- 最短路径问题——Dijkstra算法详解(单源最短路径)
- 我的2021秋招 | 互联网、银行、选调 经验分享
- Deepin Linux设置环境变量时出现【Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=gasp】的解决方法
- java 做日历_java编程实现日历
- 匹兹堡大学申请条件计算机科学,美国匹兹堡大学计算机科学专业好不好?
- VM ware 启动时坏掉了的解决方法:Runtime error opening,big_linux.vbox' for reading: -102 (File not found.).
- SAP 银行存款设为 外币户 USD