[VHDL]

玩转VHDL008-格雷计数器

[复制链接]
939|1
手机看帖
扫描二维码
随时随地手机跟帖
ucx|  楼主 | 2017-10-10 08:04 | 显示全部楼层 |阅读模式
本帖最后由 ucx 于 2017-10-10 08:11 编辑

格雷计数
格雷码的任意两相邻码字之间只有一个比特不相同,这一特点使格雷码在一些高速或跨时钟域的场合常被用到。然而格雷码是无权码,不适合运算,顾格雷码与二进制码之间的转换在所难免。介绍格雷码与二进制码之间转换的**俯拾皆是,然而讨论格雷计数问题的却难得一见。本文主要是在FPGA实现上讨论一下格雷计数。
举一个4比特格雷码与二进制码之间转换的规则实例:
二进码BV=B3B2B1B0,格雷码GV=G3G2G1G0
G3 = B3
G2 = B3 B2
G1 = B2B1
G0 = B1B0

B3 = G3
B2 =B3G2
B1 = B2G1
B0 = B1G0

由实例很容易写出格雷码到二进制码的转换函数Gray_Bin
         function Gray_Bin(gv       : std_vector) return std_vector is
                   subtype T          is std_vector(0 to gv'length-1);
                   variable bv                                             :T;
                   alias v                                                      :T is gv;
          begin     
                   bv(0) :=v(0);
                   for i in 1to bv'right loop
                            bv(i):= v(i) xor bv(i-1);
                   end loop;
                   return bv;
         end;

以及二进制码到格雷码的转换函数Bin_Gray

         function Bin_Gray(bv       : std_vector) return std_vector is
                   subtype T          is std_vector(0 to bv'length-1);
                   variable gv                                             :T;
                   alias v                                                      :T is bv;
          begin

                   gv(0) :=v(0);
                   for i in 1to gv'right loop
                            gv(i):= v(i) xor v(i-1);
                   end loop;
                   return gv;
         end;

那么格雷计数如何实现呢?很容易想到的是把格雷码转化成二进制码,然后把二进制码加1再转为格雷码,这就实现了格雷计数。精确用语句描述如下:
Process(clock) begin
         if rising_edge(clock)then
                   cnt <=Bin_Gray(Gray_Bin(cnt) + 1);
         end if;
End process;
那么计数器cnt就是格雷计数器。
还有其他方法实现格雷计数吗?如果有会和上述方法有不同吗?下面我从硬件综合和软件仿真两个方面来展示一下这个问题。对于一个n+1位的格雷码G[n..0],列举n=2,3,4情况下的个格雷码组,我们不难发现Gi=3,4...,n-1)总是在G[i-1..0]=100..0情况下发生跳变,再找一下G[n]G[1]G[0]的变化规律。根据格雷码每个比特的变化规律,可以直接写出从当前格雷码产生下一格雷码的函数GrayInc(gv)

         function GrayInc(gv : std_vector) return std_vector is
                   constant N                          : integer :=gv'length-1;
                   variable v,q                : std_vector(N downto 0);
                   variablebH,bL          : std_logic;
          begin
                   v := gv;
                   if N = 0 then
                            return not v;
                   elsif N=1then
                            q(0):= not v(1);
                            q(1):= v(0);
                            returnq;
                   end if;
                   q(0) := '1';
                   for i in 1to N loop
                            q(0):= q(0) xor v(i);
                   end loop;
                   q(1) := '1';
                   for i in 2to N loop
                            q(1):= q(1) xor v(i);
                   end loop;
                   q(1) :=(q(1) and v(0)) or (not v(0) and v(1));
                   for i in 2to N loop
                            bL:= v(i-1) xor (v(i) and i=N);
                            forj in 0 to i-2 loop
                                     bL:= bL and not v(j);
                            endloop;
                            bH:= not v(i) or i=N;
                            forj in i to N loop
                                     bH:= bH xor v(j);
                            endloop;
                            ifbH='1' and bL= '1' then
                                     q(i):= '1';
                            elsifbH='0' and bL='1' then
                                     q(i):= '0';
                            else
                                     q(i):= v(i);
                            endif;
                   end loop;     
                   return q;
         end;

我们称通过二进制码计数的算法为间接格雷计数法,通过GrayInc(gv)产生格雷计数的方法为直接格雷计数法。直接格雷计数法可用进程表示为

Process(clock) begin
         if rising_edge(clock)then
                   cnt <=GrayInc(cnt);
         end if;
End process;

算法对比分析
直接法语间接法有和相同和不同之处呢?先看仿真图
格雷计数器.png

图中一并给出了仿真文件Gray_sim.vht的全部代码和仿真结果,为清晰器件图中把三个函数的具体内容折叠起来了,其详细内容文档前面已给出。
行70指明仿真选取9比特格雷码情况。
行75/76表明clock为100M时钟,对于9比特情况,一个格雷计数周期是5120ns。
行80:x1n为间接格雷计数
行81:x2n为直接格雷计数
行82:dif=x1nx2n。仿真图中dif恒0表明x1n与x2n始终相同,意味着间接格雷计数与直接格雷计数在功能上完全相同。
行83:验证x1n是格雷码。prv是x1n前一组格雷码,也即prv与x1n相邻。
行84:b_sum(v)是把矢量v的每一个比特带进位相加的结果,也即b_sum(v)反应矢量v中比特为1的个数。仿真结果中num1s恒为1表明prv与x1n只有一个比特不同,即x1n是格雷计数。
行85:过程NotRst(b,en, rst)的作用是当rst时b复位为0,否则当en时b值翻转。仿真图表明pul的翻转周期是5120ns,意味着x1n每512个时钟周期回到0一次。这表明格雷计数周期为512,对于9比特x1n的全部512个码字全部参与循环,无无效码字。
仿真结果表明直接法与间接法全部实现格雷计数,且功能相同。
再看综合结果。
间接格雷计数.png

综合时,先选用cnt为3个比特的情况,对应行72的信号定义。行77被注释掉,那么此计数器为间接格雷计数器。综合后,查看寄存器视图,我们发现里面有一个Add0加法器逻辑。这个加法器是我们不期望的,综合器完全按照代码的书写格式产生了逻辑,而并没有把加1逻辑和格雷与二进制转换逻辑合并优化。读者可以把72行改为8比特及以上综合后分别查看直接法与间接法资源消耗和时钟最高速率报告。对比表明直接法消耗资源更少,速率提高明显。这更适合格雷码的告诉应用场合。
结论
直接格雷计数法与间接格雷计数**能完全相同,而前者消耗更少的资源拥有更高的速率,即直接法具有更高的性能。

相关帖子

ucx|  楼主 | 2017-10-11 12:27 | 显示全部楼层
这个GrayInc(gv)可以把G[1],G[0]一并写在循环里,代码看起来更简洁。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

ucx

28

主题

85

帖子

5

粉丝