一、前言
本系列旨在提供100%准确的数字IC设计/验证手撕代码环节的题目,原理,RTL设计,Testbench和参考仿真波形,每篇文章的内容都经过仿真核对。快速导航链接如下:
1.奇数分频
2.偶数分频
3.半整数分批
4.小数/分数分频
5.序列检测器
6.模三检测器
7.饮料机
8.异步复位,同步释放
9.边沿检测(上升沿,下降沿,双边沿)
10.全加器,半加器
11.格雷码转二进制
12.单bit跨时钟域(打两拍,边沿同步,脉冲同步)
13.奇偶校验
14.伪随机数生成器[线性反馈移位寄存器]
15.同步FIFO
16.无毛刺时钟切换电路
17.固定优先级仲裁器
18.轮询仲裁器
应当说,手撕代码环节是面试流程中既重要又简单的一个环节,跟软件类的岗位相比起来,数字IC的手撕代码题目固定,数量有限,属于整个面试中必得分的一个环节,在这个系列以外,笔者同样推荐数字IC求职者使用“HdlBits”进行代码的训练
链接如下
HDLBits — Verilog Practice
二、题目
数字IC工程师在使用多主设备的总线过程中,需要考虑到不同主设备申请总线控制权的优先级问题,请使用Verilog语言,考虑四个主设备,设计固定优先级仲裁器,该仲裁器默认时的总线控制的优先级永远保持为为A>B>C>D。
三、原理
默认情况下的优先级排序为A>B>C>D,input 请求情况request 的四位二进制,从高到低也分别代表主设备A、B、C、D的总线控制请求,output的grant输出one hot编码,即“1000,0100,0010,0001”四种情况中的一种,给出的案例如下,按照四个周期依次输入控制请求,仲裁器在按照固定优先级算法的条件下会依次响应设备A,D,A,B
需要注意的是,虽然我们在上面的例子中提出周期的概念,但对于仲裁器来讲,它是一个纯组合逻辑电路。
3.1 case/if语句法
我们有很多种方法来实现固定优先级仲裁器,第一种介绍的方法为if/case法:
说起来其实非常简单,使用if语句先判断request的最高位,假如为1,输出1000,假如不为1,再判断request的次高位是否唯一,去输出0100,以此类推进行设计即可。
需要注意的是,上述的语句除了可以使用if来完成外,也可以使用case来完成。初学者常常用if语句是串行的,有判断优先级,而case语句是并行的,没有判断优先级的角度去理解verilog语言对于if语句和case语句的综合过程,在这个思路下,if语句对应综合出来的逻辑具有优先级,靠前的逻辑少,路径短,靠后的逻辑多,路径长,而case语句的综合是一个parallel的结构,这个说法对于if语句是正确的,而对于case语句来说对也不对
一个正确的说法是,case语句,即可以实现parallel结构,也可以实现优先级编码。
具体内容可参见case语句的综合结果,你究竟会了吗?
因此,我们可以使用case语句代替if语句去判断固定优先级的仲裁器应该输出什么grant值,RTL代码参见下文即可。
3.2 for循环法
除此以外,for语句也可以用来设计固定优先级仲裁器,对于固定主设备数量的固定优先级仲裁器而言,固定循环次数的for语句,可以综合成实际电路,这个原则是我们为什么可以使用for语句进行固定优先级仲裁器的基础,但是受限于篇幅有限,我们不给出具体的for循环rtl代码了。
3.3 补码相与法
这是一个很巧妙的方法,而我们使用到了2进制的补码的一个特性,即一个数和它的补码相与,得到的结果是一个独热码,独热码为1的那一位是这个数最低的1,这个特性和我们想要寻找,四位二进制的1,在什么时候第一次出现的想法,不谋而合。
需要注意的是,我们这里把现在给出的request当作补码,去求它的原码,再相与,以下会给处详细解释:
我们可以这么去思考这个问题,一个二进制4bit的数,减去1,会向这个数第一个非零的位置借位,改变这一位的值,假如与减1后的数进行与操作,那么只有产生进位的这一位在取反后依旧为1,二者相与,得到一个独热码
举例:(注意这里的request是[0:3]而非[3:0])
四、RTL设计
4.1 case语句法固定优先级仲裁器
module fixed_arb(request,grant); input [3:0] request; output [3:0] grant; reg [3:0] grant_reg; always@(*) case(1'b1) request[3] : grant_reg = 4'b1000; request[2] : grant_reg = 4'b0100; request[1] : grant_reg = 4'b0010; request[0] : grant_reg = 4'b0001; default: grant_reg = 4'b0000; endcase assign grant = grant_reg; endmodule
根据原理可知,这种写法的case语句实际上是一个串行结构,以上的内容当然也可以使用if嵌套的形式进行替代,if先判断最高位,依次判断至第零位,default条件下,grant输出4‘b0000,这里就不再赘述了
4.2 加法器法固定优先级仲裁器
我们之所以在下文的rtl设计中去颠倒grant的高低位,是跟A>B>C>D还是A<B<C<D相关,其中{A,B,C,D}分别代表grant[3:0]从高到低的四位,若为A<B<C<D的优先级,则其实不需要高低位颠倒,而对于前者来说则需要,这里请读者注意,为了考虑4’b0000的情况,我们还做了一个位扩展,当然,assign的等式左边与等式右边位宽不相等,lint肯定会有error,但我们这里忽略,并按照舍弃高位,保留低位的方式来进行默认操作。
module fixed_arb_2(request,grant); input [3:0] request; output [3:0] grant; assign {grant[0],grant[1],grant[2],grant[3]}= {1'b1,request[0],request[1],request[2],request[3]} & ~({1'b1,request[0],request[1],request[2],request[3]}-1'b1); endmodule
五、仿真
5.1 case法仿真文件
`timescale 1ns / 1ps module fixed_arb_tb(); reg [3:0] request; wire [3:0] grant; fixed_arb u1(request,grant); always #5 request = $random; initial begin request = 4'b0000; #200; $stop; end endmodule
5.2 补码相与法仿真文件
`timescale 1ns / 1ps module fixed_arb_tb_2(); reg [3:0] request; wire [3:0] grant; fixed_arb_2 u1(request,grant); always #5 request = $random; initial begin request = 4'b0000; #200; $stop; end endmodule
六、仿真结果分析
6.1 case法结果分析
可以发现,第一个输出1的request对应的位置,为grant信号输出唯一的1的位置,设计成立。
6.2 补码相与法结果分析
效果与6.1一样,即从左到右判断第一个出现1的位置,grant输出对应位置的信号。