首页 > 其他分享 >verilog-1| 仲裁器

verilog-1| 仲裁器

时间:2024-09-14 09:52:29浏览次数:12  
标签:req 优先级 grant REQ WIDTH verilog reg 仲裁

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

目录

前言

一、固定优先级仲裁器(Fixed Priority Arbiter)

1、case/if语句实现

2、for循环语句实现参数化

3、展开for循环的变体 

4、补码相与法

二、轮询仲裁器(Round Robin Arbiter)

1、优先级仲裁器+优先级更新

2、固定优先级仲裁器+MASK Request

三、权重循轮询仲裁器(Weighted Round Robin Arbiter)

1、基于grant进行轮询

2、基于request进行轮询

总结


前言

常用仲裁器的简单总结,方便自己后续查询和复习


一、固定优先级仲裁器(Fixed Priority Arbiter)

当有多个主设备发起请求时,需要对多个请求进行仲裁,一般同一时刻只有一个主设备可以控制总线。

固定优先级:优先级是固定的,多个主设备同时发起请求,每次都会响应优先级最高的那个主设备。例:A>B>C或者A<B<C

1、case/if语句实现

信号固定位宽,最高位的优先级最高代码如下:

高位优先级最高

module fixed_pri_arb(
  input   [3:0] request,
  output  [3:0] grant_reg
);

//case语句会被综合成串行结构
always@(*) begin
  case(1'b1)
    request[0]: grant_reg = 4'b1000;
    request[1]: grant_reg = 4'b0100;
    request[2]: grant_req = 4'b0010;
    request[3]: grant_req = 4'b0001;
    default: grant_req = 4'b0000;
  endcase
end

//casez语句实现
always@(*) begin
  casez(request)
    4'b1???: grant_reg = 4'b1000;
    4'b01??: grant_reg = 4'b0100;
    4'b001?: grant_req = 4'b0010;
    4'b0001: grant_req = 4'b0001;
    default: grant_req = 4'b0000;
  endcase
end

//此处也可以使用if-else语句
always@(*) begin
  if(request[3])
    grant_reg = 4'b1000;
  else if(request[2])
    grant_reg = 4'b0100;
  else if(request[1])
    grant_reg = 4'b0010;
  else if(request[0])
    grant_reg = 4'b0001;
  else 
    grant_reg = 4'b0000;
end

endmodule

2、for循环语句实现参数化

信号位宽参数化,代码如下:

低位优先级最高

module fixed_pri_arb #(
  parameter REQ_WIDTH = 16
)(
  input  [REQ_WIDTH-1:0] req,
  output [REQ_WIDTH-1:0] grant
);
 

  //记录低位是否已经有了request
  reg [REQ_WIDTH-1:0] pre_req; 
  //实现低位优先级最高
  always@(*) begin
    grant[0]   = req[0];
    pre_req[0] = req[0];
    for(genvar i=1; i<REQ_WIDTH; i=i+1) begin
      grant[i]   = req[i] & ~pre_req[i-1];
      pre_req[i] = req[i] | pre_req[i-1];
     end 
  end
 
endmodule

要实现高位优先级最高,把req和grant重新排布一下即可,代码如下:

reg [REQ_WIDTH-1:0] req_inverse;
reg [REQ_WIDTH-1:0] grant_inverse;

always(*) begin
for(genvar i=0; i<REQ_WIDTH; i=i+1) begin
  req_inverse[i]   = req[REQ_WIDTH-1-i];
  grant[i]         = grant_inverse[REQ_WIDTH-1-i];
end
end

3、展开for循环的变体 

低位优先级最高,代码如下:

module fixed_pri_arb #(
  paramter REQ_WIDTH= 4
)(
  input  [REQ_WIDTH-1:0] req,
  output [REQ_WIDTH-1:0] grant
);

  wire [REQ_WIDTH-1:0] pre_req;
  //pre_req[i+1]由req[i] | pre[i]决定
  //效果是pre_req保存的是req第一个1位置以后的高位都为1
  assign pre_req[0] = 0;
  assign pre_req[REQ_WIDTH-1:1] = req[REQ_WIDTH-2:0] | pre_req[REQ_WIDTH-2:0];

  assign grant = req & ~pre_req;

endmodule

4、补码相与法

低位优先级最高,即从低位到高位找出第一个1出现的req请求被grant。

保留一个数中最低位的1,其他置0,可以用原码&补码的方式实现。

原理如下:补码为原码取反+1得到。只有第一个1的位置,补码有进位变1,相与后不为零。

原码0001001000110100
补码1111111011011100

 reqeust当成原码,求补码,后相与,代码如下:

module fixed_pri_arb #(
  parameter REQ_WIDTH = 4
)(
  input  [REQ_WIDTH-1:0]  req;
  output [REQ_WIDTH-1:0]  grant
);

  assign grant = req & (~req + 1'b1);

endmodule

request 当成补码,求原码,后相与;(低位优先级最高)

可以通过重排request和grant信号的方式(同上),实现高位最高优先级

代码如下:

module fixed_pri_arb #(
 parameter REQ_WIDTH = 4
)(
  input   [REQ_WIDTH-1:0] req,
  output  [REQ_WIDTH-1:0] grant
);

  assign grant = req & (~(req - 1'b1));

endmodule

二、轮询仲裁器(Round Robin Arbiter)

轮询机制:当一个req获得grant后,优先级在接下来的仲裁中变得最低。每一响应完一个设备,都会对优先级进行更新。

有以下两种实现方式:

1、优先级仲裁器+优先级更新

A & ~(A-base)的结果是保留base对应位的A左边第一个1,其中base为onehot;每次仲裁后,base权重最高位左移进行更新。

module round_robin_arb #(
  parameter REQ_WIDTH = 4
)(
  input                  clk,
  input                  rst_n,
  input  [REQ_WIDTH-1:0] req,
  output [REQ_WIDTH-1:0] grant
);
 
//signals 
  reg  [REG_WIDTH-1:0]   base;
  wire [2*REG_WIDTH-1:0] double_grant;

assign double_grant = {req, req} & (~({req, req} - base));
assign grant = double_grant[2*REQ_WIDTH-1:REQ_WIDTH] | double_grant[REQ_WIDTH-1:0];

always@(posedge clk or negedge rst_n) begin
  if (!rst_n)
     base <= {{REQ_WIDTH-1{1'b0}}, 1'b1};  //默认最低位最高优先级
  else if (|req)
     base <= {grant[REQ_WIDTH-2:0], grant[REQ_WIDTH-1]};
end

endmodule

2、固定优先级仲裁器+MASK Request

思路:如果某一个req被grant,就把该req请求mask掉,仲裁剩下req,并且权重保持不变;当所有的req都被仲裁完了,再载入新的mask。

展开for循环的固定优先级仲裁器中,pre_req信号实现:如果req的第i位为1,那么pre_req从第i+1位开始都是1,从第0位到第i位都是0。即pre_req就是所需要的mask。只需要把当前的req和上一拍的pre_req 与起来,得到mask后的req。

module round_robin_arb #(
  parameter REQ_WIDTH = 4
)(
  input                   clk,
  input                   rst_n,
  input  [REQ_WIDTH-1:0]  req,
  output [REQ_WIDTH-1:0]  grant
);

  wire  [REQ_WIDTH-1:0]  req_masked;
  wire  [REQ_WIDTH-1:0]  mask_higher_pri_reqs;
  wire  [REQ_WIDTH-1:0]  grant_masked;

  wire  [REQ_WIDTH-1:0]  unmask_higher_pri_reqs;
  wire  [REQ_WIDTH-1:0]  grant_unmasked;

  wire  no_req_masked;
  reg   [REQ_WIDTH-1:0]  pointer_reg;
  
  //simple priority arbitration for masked portion
  assign req_masked = req & pointer_reg;
  assign mask_higher_pri_reqs[0] = 1'b1;
  assign mask_higher_pri_reqs[REQ_WIDTH-1:1] = req_masked[REQ_WIDTH-2:0] | 
                                               mask_higher_reqs[REQ_WIDTH-2:0];
  assign grant_masked = req_masked & (~mask_higher_pri_reqs);
  
  //simple priority arbitration for unmasked portion
  assign unmask_higher_pri_reqs[0] = 1'b0;
  assign unmask_higher_pri_reqs[REQ_WIDTH-1:1] = req[REQ_WIDTH-2:0] | 
                                                 unmask_higher_pri_reqs[REQ_WIDTH-2:0];
  assign garnt_unmasked = req & (~unmask_higher_pri_reqs);

  //use grant_masked if there is any there, otherwise use grant_unmasked.
  assign no_req_masked = ~(|req_masked);
  assign grant = ({REQ_WIDTH{no_req_masked}} & grant_unmasked) | grant_masked;

  //pointer update
  always@(posedge clk or negedge rst_n) begin 
    if (!rst_n)
      pointer_reg <= {REQ_WIDTH{1'b1}};
    else if (|req_masked)
      pointer_reg <= mask_higher_pri_reqs;
    else begin
      if (|req) //only update if there's a req
        pointer_reg <= unmask_higher_reqs;
    end
  end

endmodule

思路:把mask和unmask仲裁器分别实现出来,然后利用req_masked等于0条件进行grant信号的mux。 

问题记录:直接先把reg_masked和req先mux出来,再送进仲裁器,可以减少一个仲裁器数量?

三、权重循轮询仲裁器(Weighted Round Robin Arbiter)

在轮询仲裁基础上,不同权重的req会得到不同的访问次数,非公平的轮询机制

有两种解决思路:

1、基于grant进行轮询

  考虑权重,一般做法是给每个用户固定的仲裁次数,然后每个用户每仲裁一次计数一次。

因此,完成一次仲裁后,不能立即对grant进行循环左移,而是判断当前用户可仲裁次数是否已经用完,若已经用完,则grant_base进行跳转;反之,如果当前请求停止仲裁,并且其他请求到来,依然跳转,否则保持不变。

module weight_rr_arb #(
  parameter  REQ_WIDTH    = 4,
  parameter  CNT_WIDTH    = 5,
  parameter  INIT_GRANT   = {{REQ_WIDTH-1{1'b0}}, 1'b1},
  parameter  WEIGHT_WIDTH = CNT_WIDTH*REQ_WIDTH 
)(
  input                     clk,
  input                     rst_n,
  input  [REQ_WIDTH-1:0]    req,
  input  [WEIGHT_WIDTH-1:0] weight,
  output [REQ_WIDTH-1:0]    grant
);


reg   [REQ_WIDTH-1:0]    grant_base;
wire  [REQ_WIDTH*2-1:0]  double_req;
wire  [REQ_WIDTH*2-1:0]  double_grant;

reg   [CNT_WIDTH-1:0]    priority_cnt [REQ_WIDTH-1:0];
wire  [REQ_WIDTH-1:0]    cnt_over;
wire  [REQ_WIDTH-1:0]    round_en;

wire                     req_flag;

assign req_flag = |req;

generate
  for(genvar i=0; i<REQ_WIDTH; i=i+1) begin
    assign cnt_over[i] = priority_cnt[i] == weight[CNT_WIDTH*(i+1)-1-:CNT_WIDTH];
    assign round_en[i] = cnt_over[i] | ((priority_cnt[i] != 0) & (~req[i]));

    always@(posedge clk or negedge rst_n) begin
      if (!rst_n)
        priority_cnt[i] <= {CNT_WIDTH{1'b0}};
      else if (grant[i])    //有grant产生:被grant进行计数加1,未被grant清0
        priority_cnt[i] <= priority_cnt[i] + 1'b1;
      else
        priority_cnt[i] <= {CNT_WIDTH{1'b0}};
    end 
  end
endgenerate

always@(posedge clk or negedge rst_n) begin
  if (!rst_n) 
    grant_base <= INIT_GRANT;
  else if (|round_en & req_flag)
    grant_base <= {grant_base[REQ_WIDTH-2:0], grant_base[REQ_WIDTH-1]};
end

assign double_req   = {req, req};
assign double_grant = double_req & (~(double_req - grant_base));
assign grant= double_grant[REQ_WIDTH*2-1:REQ_WIDTH] | double_grant[REQ_WIDTH-1:0];
 
endmodule

2、基于request进行轮询

权重没有改变仲裁的选择方法,仅仅只会改变mask跳转的判断条件。


博主水平有限,内容如有不当之处,还望指教

标签:req,优先级,grant,REQ,WIDTH,verilog,reg,仲裁
From: https://blog.csdn.net/m0_62869075/article/details/142134185

相关文章

  • Github_以太网开源项目verilog-ethernet代码阅读与移植(二)
    实验背景在《Github_以太网开源项目verilog-ethernet代码阅读与移植(一)》中简要介绍了verilog-ethernet开源项目的目录构造等基本信息,下面介绍如何使用与移植步骤。实验内容verilog-ethernet项目的使用与移植准备工作实验步骤打开项目的中README.md文件内容如下:信......
  • verilog vscode 与AI 插件
    Verilog轻量化开发环境背景笔者常用的开发环境VIAVDO,体积巨大,自带编辑器除了linting能用,编辑器几乎不能用,仿真界面很友好,但是速度比较慢。SublimeText,非常好用的编辑器,各种插件使用verilog非常方便,可以自动补全、生成调用、linting等;VSCODE,SublimeText有的插件,VSC......
  • 【劳动仲裁】打工人一定要看这篇文章【收藏篇】
    【劳动仲裁】纯经验干货分享,点个关注防止需要时找不到!当公司决定搞你心态,变相逼退你时,无非就那么些手段,只要你能正确应对,并做好收集证据的准备,就不足为惧。合理利用法律的武器维护自身利益。什么情况是N?2N?N+1?N指的是公司有违法行为(社保未全额缴纳,未足额发放工资,不提......
  • Verilog:【8】基于FPGA实现SD NAND FLASH的SPI协议读写
    Verilog:【8】基于FPGA实现SDNANDFLASH的SPI协议读写在此介绍的是使用FPGA实现SDNANDFLASH的读写操作,以雷龙发展提供的CS创世SDNANDFLASH样品为例,分别讲解电路连接、读写时序与仿真和实验结果。目录1FLASH背景介绍2样品申请3电路结构与接口协议3.1SD......
  • verilog仿真激励
    简介    本章节主要描述verilog激励仿真函数的介绍。initial    主要针对寄存器初始化值,基本所有仿真都会使用到该语句,使用如下:initialbegin sys_clk='d0; sys_rst_n='d0; #2000; sys_rst_n='d1;endrepeat    重复有限次数地执......
  • iverilog+gtkwave搭建轻量级verilog仿真环境
    前言在之前用到的仿真工具只有vivado与modelsim,vivado的笨重不用多说,可能你搭建一个工程的时间比你看波形的时间还要长,modelsim倒是稍微轻一些,但步骤也较为繁琐,虽然我在之前也意外收获了modelsim的仿真脚本模板且屡试不爽,但还是觉得稍微有些麻烦,正好之前在学习tinyrv时安装了iver......
  • Linux 高可用仲裁设备配置
    RedHatEnterpriseLinux7.4完全支持配置作为集群的第三方设备的独立仲裁设备。它的主要用途是允许集群保持比标准仲裁规则允许更多的节点故障。建议在具有偶数节点的集群中使用仲裁设备。对于双节点群集,使用仲裁设备可以更好地决定在脑裂情况下保留哪些节点。在配置仲裁设备,......
  • verilog-UART驱动流程
    目录1.理论介绍       2.verilog代码实现 1.理论介绍               UART(Universalasynchronousreceivers-transmitter,通用异步收发器)数据帧结构如下图,zynq7020-PL侧的时钟频率fclk一般设置为50MHz,假设串口波特率为115200bps,则一个1bit传输需......
  • verilog代码与设计总结
    Verilog编码风格及设计建议相比于case语句,casez语句将z态看做不关心,casex语句将z态和x态看做不关心。并且所有case类型语句均没有优先级。锁存器是组合逻辑产生的,一般没有复位端,所以根据其所存特性,在上电的时候没法确定其初始状态,因此正常情况下要避免使用。组合逻辑环是一种......
  • FPGA开发——verilog的运算符以及相关优先级的介绍
    一、简介        在我们学习任何一门编程语言时,不可避免的都会遇见运算符和相关的运算优先级的问题,只有掌握了各个运算符的优先级关系我们才能进行更好的代码编写。在前面的时候因为我没有遇到因为优先级而导致的工程结果错误,所以没有过多注意,但是遇到之后才发现运算......