【数集项目之 MCDF】(三) 仲裁器 arbiter

news2024/10/7 12:26:00

  接下来进行仲裁器 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_islave1_FIFO发送请求信号slv1_req_islave2_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_i4+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)begin
        if(ch1_prio_syn>ch2_prio_syn)
            channel_prio<=6'b10_01_00;
        else begin
            if(ch0_prio_syn>ch2_prio_syn)
                channel_prio<=6'b01_10_00;
            else
                channel_prio<=6'b01_00_10;
        end
    end
    else begin
        if(ch1_prio_syn<ch2_prio_syn)
            channel_prio<=6'b00_01_10;
        else begin
            if(ch0_prio_syn<ch2_prio_syn)
                channel_prio<=6'b00_10_01;
            else
                channel_prio<=6'b10_00_01;
        end        
    end
end

  有了综合优先级生成和比较,这样我们就能找出优先级最高的通道了,每次arbiter或者更高级请求发送数据包时,我们只要比较一下当前优先级最高的通道(刷新综合优先级),然后直接选通对应通道,将各种信号按照文档中给的对应关系进行wire连接就可以了。
  下面介绍结构设计,可以参考设计文档中的端口声明。


第二节 arbiter结构设计

在这里插入图片描述
  正如结构图所示,只有仲裁信号产生部分是时序电路,其余都是组合逻辑。因此当选通某一通道时,相当于formatterslave_FIFO直连,而此时arbiter是透明的。
  仲裁在formatter发来请求发送信号时进行运算,刷新出当前最优通道,在下一时钟周期的上升沿刷新选择器分配器的使能端,完成选通任务。
  值得一提的是,由于设计只有3个通道,分别用000110表示,而考虑到复位情况不能选择任何一个通道(因为可能3个通道都没接收足够数据发送),并且对于这么多arbiter输出信号复位赋值语句较多,因此这里设置一个虚拟通道(图中未画出),编号是11。提前设定好虚拟通道各信号的值等于复位信号,当复位时,只需要把formatter和虚拟通道接通即可。


第三节 arbiter代码设计

  根据上一节的结构图,可以很容易写出代码。
  文件名称:arbiter.v

/*************************<MCDF仲裁器>*********************/
`timescale 1ns/100ps
/*************************<端口声明>*********************/
module arbiter
(
//Input
    input   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_i
                            a2s1_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_i
    output  reg     [2:0]   a2f_pkglen_sel_o,    //[-slv]slvx_pkglen_i

    output  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)begin
        if(ch1_prio_syn>ch2_prio_syn)
            channel_prio<=6'b10_01_00;
        else begin
            if(ch0_prio_syn>ch2_prio_syn)
                channel_prio<=6'b01_10_00;
            else
                channel_prio<=6'b01_00_10;
        end
    end
    else begin
        if(ch1_prio_syn<ch2_prio_syn)
            channel_prio<=6'b00_01_10;
        else begin
            if(ch0_prio_syn<ch2_prio_syn)
                channel_prio<=6'b00_10_01;
            else
                channel_prio<=6'b10_00_01;
        end        
    end
end
/*****************<时序电路>*********************/
//用于产生仲裁信号 a2f_id_o !!!如果都没准备号,就发送11
always @(posedge clk_i or negedge rstn_i) begin
    if(~rstn_i)begin//输出全部置0
        a2f_id_o<=2'b11;//进入default间接置0
    end
    else 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];
        else
            a2f_id_o<=2'b11;
    end
    else
        a2f_id_o<=a2f_id_o;
end

/*****************<多路选择器部分>*********************/
always @(*) begin
    case(a2f_id_o)
    2'b00:begin
        a2f_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;
    end

    2'b01:begin
        a2f_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;
    end

    2'b10:begin
        a2f_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;
    end

    2'b11:begin//default
        a2f_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;
    end
    endcase
end
endmodule


第四节 arbitertestbench实现

  文件名称: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_i
                a2s1_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;//数据长8
    slv2_pkglen_i<=2'b00;//数据长4

    slv0_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)begin
    f2a_id_req_i<=1;//两个短时信号
end

@(posedge clk_i)begin
    f2a_id_req_i<=0;
    f2a_ack_i<=1;     
end

@(posedge clk_i)begin
    f2a_ack_i<=0;     
end
 
        repeat(8)begin
            @(posedge clk_i)begin
                slv0_data_i<=$random;
                slv1_data_i<=$random;
                slv2_data_i<=$random;
                slv0_val_i<=0;
                slv1_val_i<=1;
                slv2_val_i<=0;                
            end
        end
        slv0_end_i<=1;
        slv1_end_i<=1;
        slv2_end_i<=1; 
@(posedge clk_i)begin
    slv0_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最后的波形仿真中进行分析


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/83922.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FineReport可视化数据分析-图表对象属性

1.概述 1.1 单个系列对象属性 属性 类型 说明 this.points Array 当前系列的所有数据点 this.name String 当前系列的名字&#xff0c;跟图例显示的系列名一致 this.type String 当前系列的图表类型&#xff0c;目前包括的类型如下图所示&#xff1a; 1.2 单个数…

图解TCP_IP 第5版

图解TCP_IP 第5版1.7.1 面向有连接型与面向无连接型1.7.2 电路交换与分组交换1.7.3 单播、广播、多播和任播1.9.1 通信媒介1.9.1 传输速率、带宽和吞吐量1.9.2 网卡1.9.3 中继器与集线器1.9.4 网桥/2 层交换机1.9.5 路由器/3层交换机1.9.6 4~7 层交换机1.9.7 网关2.2.1 TCP/IP …

matplotlib安装及使用

目录 1、Matplotlib简介 2、Matplotlib安装 3、Matplotlib导入 4、Matplotlib基本应用 5、画图种类 5.1、Scatter散点图 5.2、条形图 5.3、等高线图 5.4、Image图片 5.5、3D图像 6、多图合并显示 6.1、Subplot多合一显示 6.2、SubPlot分格显示 6.3、图中图 6.4、…

保护大数据安全的十大行为准则

大数据安全是指在存储、处理和分析过于庞大和复杂的数据集时&#xff0c;采用任何措施来保护数据免受恶意活动的侵害&#xff0c;传统数据库应用程序无法处理这些数据集。大数据可以混合结构化格式(组织成包含数字、日期等的行和列)或非结构化格式(社交媒体数据、PDF 文件、电子…

YourKit Java Profiler 命令行工具自动弹出

YourKit Java Profiler 命令行工具自动弹出 识别处理器和内存从来都不容易。 YourKit为程序开发了两个阶段的开发和开发革命。 YourKit Java Profiler软件的功能和特点&#xff1a; 以任何方式为团队和公司在开发、测试和生产中&#xff0c;以不同的操作系统、本地和远程方式指…

Python多项分布随机数的生成

文章目录二项分布多项分布函数概率密度函数(PDF)备注binomial(n, p)P(k)(nk)pk(1−p)n−kP(k) \binom{n}{k}p^k(1-p)^{n-k}P(k)(kn​)pk(1−p)n−k二项分布poisson([lam])f(k)λke−λk!f(k)\frac{\lambda^ke^{-\lambda}}{k!}f(k)k!λke−λ​泊松分布multinomial(n, pvals)多…

解放双手!推荐一款阿里开源的低代码工具,YYDS!

之前分享过一些低代码相关的文章&#xff0c;发现大家还是比较感兴趣的。之前在我印象中低代码就是通过图形化界面来生成代码而已&#xff0c;其实真正的低代码不仅要负责生成代码&#xff0c;还要负责代码的维护&#xff0c;把它当做一站式开发平台也不为过&#xff01;最近体…

AIOps是什么?为什么用它?

由于快速的数字化转型给 IT 企业组织带来了很大的压力&#xff0c;要求他们更加主动和敏捷&#xff0c;DevOps 原则和实践一直是宝贵的资源。但是&#xff0c;为了保持领先地位&#xff0c;企业需要更强大的解决方案。那么&#xff0c;答案是什么&#xff1f;当然是 AIOps&…

现在ChatGPT可以使用谷歌插件进行快速交互访问了!

文章目录前言效果原理部署过程获得ChatGPT session token克隆代码库设置ChatGPT session token项目安装启动项目谷歌浏览器安装插件报错问题前言 这个ChatGPT虽然功能很强大&#xff0c;但是使用的时候每次都得去打开对应的网站&#xff0c;把自己想问的问题复制过去&#xff…

简易Qt图片查看器

本篇使用Qt来实现一个可以查看任意目录下图片的图片查看器&#xff0c;可以电脑中任意目录下图片的查看&#xff0c;并且可以通过鼠标滚轮以及鼠标移动来实现图片的灵活放大、缩小&#xff0c;此外&#xff0c;在打开一个图片后&#xff0c;若该目录下还有其它图片&#xff0c;…

SpringBoot+Vue实现前后端分离的电影院管理系统

文末获取源码 开发语言&#xff1a;Java 使用框架&#xff1a;spring boot 前端技术&#xff1a;JavaScript、Vue.js 、css3 开发工具&#xff1a;IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库&#xff1a;MySQL 5.7/8.0 数据库管理工具&#xff1a;phpstudy/Navicat JD…

004:搭建常规项目框架「Window、TabBar、NavigationController、ViewController」

常见App页面结构分析&#xff1a; 单页面展示&#xff1a; 列表页面的展示「UITableView」。滚动页面的展示「UIScrollow」。 多页面展示&#xff1a; 通过底部标签栏「TabBar」。通过Push栈的方式进行页面的切换。UITabBarController&#xff1a; 介绍&#xff1a;通过底部…

打响跨域/中央计算「攻坚」战,这些头部企业已经抢先布局

从域控架构到中央集成式架构&#xff0c;跨域融合已经加速到来&#xff0c;从单一域控制器&#xff0c;到多域融合中央计算&#xff0c;市场门槛进一步抬升&#xff0c;市场也进入新一轮「攻坚」阶段。 高工智能汽车研究院发布《2023-2025年智能网联产业趋势报告》显示&#x…

Flink Checkpoint 问题排查实用指南

在 Flink 中,状态可靠性保证由 Checkpoint 支持,当作业出现 failover 的情况下, Flink 会从最近成功的 Checkpoint 恢复。在实际情况中,我们可能会遇到 Checkpoint 失败,或者 Checkpoint 慢的情况,本文会统一聊一聊 Flink 中 Checkpoint 异常的情况(包括失败和慢),以及…

【单片机】串口通信/LED点阵

目录 一、串口介绍 1、双向串口通信 2、电平标准 3、常用通信协议 4、时序图 二、串口收发数据&#xff08;模式1&#xff09; 1、串行控制&#xff08;模式选择&#xff09;寄存器SCON&#xff08;可位寻址&#xff09; 2、串行口数据缓冲寄存器SBUF 3、电源控制&…

引擎入门 | Unity UI简介–第2部分(7)

本期我们继续为大家进行Unity UI简介&#xff08;第二部分&#xff09;的后续教程 本篇内容 12.在菜单场景中添加音乐 13.开启和关闭音乐 文章末尾可免费获取教程源代码 本篇本篇Unity UI简介&#xff08;第二部分&#xff09;篇幅较长&#xff0c;分为八篇&#xff0c;本…

对称加密算法(三)(DES)

文章目录DES EncryptionDES DecryptionExampleThe Avalanche EffectThe Strength of DESThe Use of 56-Bit KeysThe Nature of the DES AlgorithmReferences在 2001 年引入 AEC&#xff08;Advanced Encryption Standard&#xff09;之前&#xff0c;最为普遍使用的加密机制就是…

Python里面的xlrd模块详解

那我就一下面积个问题对xlrd模块进行学习一下&#xff1a; 1.什么是xlrd模块&#xff1f; 2.为什么使用xlrd模块&#xff1f; 3.怎样使用xlrd模块&#xff1f; 1.什么是xlrd模块&#xff1f; ♦python操作excel主要用到xlrd和xlwt这两个库&#xff0c;即xlrd是读excel&…

SQL 入门篇之什么是别名?

SQL 入门篇之什么是别名&#xff1f; &#x1f4d2;博客主页&#xff1a; ​​开心档博客主页​​ &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐留言&#x1f4dd; &#x1f4cc;本文由开心档原创&#xff01; &#x1f4c6;51CTO首发时间&#xff1a;&#x1…

计算机研究生就业方向之考公

我一直跟学生们说你考计算机的研究生之前一定要想好你想干什么&#xff0c;如果你只是转码&#xff0c;那么你不一定要考研&#xff0c;至少以下几个职位研究生是没有啥优势的&#xff1a; 1&#xff0c;软件测试工程师&#xff08;培训一下就行&#xff09; 2&#xff0c;前…