1. 前言
本文的主题是介绍 arbiter(仲裁器) 的数字电路设计。主要分享的是 fixed priority arbiter(也被称为 specific priority arbiter) 以及 Round Robin arbiter(下文简称为 arb_rr).
2. 正文
由于一是 fixed priority arbiter 会更简单,二是 arb_rr 的可以由 fixed priority arbiter 来构成,所以首先来分析 fixed priority arbiter.
首先需要知道无论是哪种 arbiter, 它的任务只有一个:find-first-one(FF1)。从这个唯一的目标我们其实可知:arbiter 的输入是一个多比特的信号,而arbiter 的输出则是一个 one-hot(独热码),而所输出的 one-hot 中的这个”1″指示的就是所找到的“1”的位置。对应的实际意义也是把此时唯一的 grant 给到哪个 req.
不同的 arbiter 只是找”1″的规则不同罢了,而我们首先讲的 fixed priority arbiter 的找一规则就是:固定从 LSB 往 MSB 找第一个”1″在哪个位置,或者从 MSB 往 LSB 找。并且是每次的找寻规则都是固定一样的。
2.1 fixed priority arbiter
我们这儿假设 fixed priority arbiter 的找一规则是:固定从 LSB 往 MSB 找第一个“1”在哪个位置,即:信号 a[MSB-1: 0] 中的 a[0] 的优先级最高,每次都先判断 a[0] 这一比特是否为1,如果为1,则说明我们找到想要的第一个”1″,否则就接着往 MSB 的方向一路找过去,直到去判断 a[MSB] 是否为”1″。
从上面的找一规则论述可知:如果我找到了 a[m] 是第一个”1″, 则意味着 a[m-1:0] 全都是0,否则这就不是第一个”1″了。There is no higher priority reqs before we find the first req which is going to be granted.
根据这个想法,我们可以设计如下的电路图。
在上图中的 fixed priority arbiter 电路中存在三个重要的信号,一是 exist_higher_pri_reqs[MSB-1:0],二是 req[MSB-1:0], 三是 grant[MSB-1:0]. 其中 exist_higher_pri_reqs[m] 的含义是: 在 req 的前 m 比特(req[m-1:0]) 里是否存在”1″. 如果存在”1″,则说明是在 req 的前 m 比特中存在更高优先级的 req 的。而 req[MSB-1] 就是需要进行 “仲裁“ 的请求。grant[MSB-1:0] 是一个独热码,其中的”1″就是 ”仲裁“得到的结果 grant(可以把 grant 理解为 permission)。
在 fixed priority arbiter 电路中的红色虚线框里是在此电路中重复出现的电路结构,并且可以看到该电路结构的输出 exist_higher_pri_reqs[m] 是由上个相同电路结构单元 exist_higher_pri_reqs[m-1] 所推导得出的。这样的电路结构很适合用 for 循环去实现。如果不用 for 循环,也可以直接如下的用三段 assign 表达式去实现该 fixed priority arbiter 电路功能,本质上是一样的。所以这里可以强记着:fixed priority arbiter 就是用三段 assign 来实现的。
assign exist_higher_pri_reqs[WIDTH-1:1] = exist_higher_pri_reqs[WIDTH-2: 0] | req[WIDTH-2:0];assign exist_higher_pri_reqs[0] = 1'b0;assign grant[WIDTH-1:0] = req[WIDTH-1:0] & ~exist_higher_pri_reqs[WIDTH-1:0]; //no higher priority reqs before we find the first granted req.
2.2 arb_rr
上述的三段 assign 实现了基本的 fixed priority arbiter. 接下来需要分析 arb_rr 的实现方式。arb_rr 的背景说明以及实现思想见下文“参考”部分。
本文中的 arb_rr 实现方式是采用了:不去改变 requesters 的优先级,而是去改动输入给到 arbiter 的 requesters 来入手的,即:如果调度出去了一路 requester, 则就将这路 requester 给“屏蔽”掉,使得下一次再进行调度时,参与调度的 requester 中已经没有了之前调度出去的那路 requster 了。当所有的 requster 都被调度出去了之后,则重新更新参与调度的 requsters,再一次重复 “调度一路,屏蔽一路” 的做法。
具体的实现电路如下所示:
上图所展示的就是 arb_rr 的电路图,这张电路图里用到了两个 fix priority arbiter(fp_arb) 并行的去处理 reqs. 其中一个 fp_arb 被称为 mask_fp_arb, 是专门用来对“屏蔽”过后的 req 来进行调度的 arb,另外一个是 unmask_fp_arb, 这个 arb 就是用来对未经过“屏蔽”的 req 进行调度的 arb.
该电路框图中还有个信号 mask_pointer_reg 很关键,这个信号的含义是:用来“屏蔽”(清零)已经调度出去的那比特以及该比特之前的那些比特位。mask_pointer_reg 复位的初值是全1,代表一开始是不去屏蔽任何一比特的,知道将优先级最高的那比特请求通过 mask_fp_arb 调度出去后,得到了 grant_masked, 并且也得到了 mask_exist_higher_pri_reqs. 使用 exist_higher_pri_reqs 来更新 mask_pointer_reg 的值,就能将刚刚调度出去的那比特给清零。以此类推,直到 mask_exist_higher_pri_reqs 为全0,则意味着把所有的比特都已经调度出去了,以及没有更高优先级的请求了,此时 req_masked 也是全0。则此时应该重新按照所输入的 req 的原始值来进行调度,并且此时更新 mask_pointer_reg 也是使用了 unmask_higher_pri_reqs 这一路的值,此处如果再使用 mask_pointer_reg 的全1初值,会发生时序功能问题,可以自行尝试画波形。
接下来又是重复 “调度出去一路,屏蔽一路” 这样的做法来进行 “轮询调度” 了,这就是“不去改变输入 reqs 的优先级,而是直接去改变输入给到 fp_arb 的 reqs”。
上述 arb_rr 还可以进一步尝试使用 clock_gating 去做时钟优化。
3. 结语
本文主要是讲述了 arbiter 的设计方式,也主要是对“参考”中的文献阐述了自己的理解,通过对 arbiter 的分享,自己知道了 fp_arb 的重要性和基础性,以及 arb_rr 设计起来的核心点就是“调度出去一路,屏蔽这一路,然后接着输入给 fp_arb 进行调度。”
4.参考
- 仲裁器设计(一) — Fixed Priority Arbiter
- 仲裁器设计(二)– Round Robin Arbiter – 极术社区 – 连接开发者与智能计算生态 (aijishu.com)
- [1] Weber M , Weber@Ieee M D ,Org.Arbiters: design ideas and coding styles[J].data, 2008.