进阶之路——二进制与格雷码的相互转换模块设计
来源:互联网 发布:hbase快速清空表数据 编辑:程序博客网 时间:2024/05/16 15:16
最近在研究异步fifo的同步化设计,里面需要格雷码与二进制码的转换,因此研究了下实现的代码。说起来这次的代码体验真的是很有意思,简单的几行代码,先后提高了自己三次认识,收益匪浅啊。
先看下两种码的转化原理:格雷码的特点就是相邻两个数之间只有一位不同,就不细说了,主要看转换。二进制与格雷码的对照关系如下:
二进制格雷码二进制格雷码00000000100011000001000110011101001000111010111100110010101111100100011011001010010101111101101101100101111010010111010011111000二者之间的转换关系各种资料中也说的很多了,简单而言就是:
二进制转格雷码,二进制最高位为格雷码最高位,二进制最高位与二进制次高位相亦或为格雷码次高位,以后二进制各位均如此得到(或者简单的记为二进制最高位前补一个0,然后依次与后面二进制求亦或得到格雷码)。
格雷码转二进制,二进制最高位为格雷码最高位,二进制最高位与格雷码次高位相亦或为二进制次高位,以后格雷码各位均如此得到(或者简单的记为二进制最高位前补一个0,然后依次与后面格雷码求亦或得到二进制)。
用图表示如下:
1.第一次代码
第一次写我想就写一个8位的吧,毕竟8位的数一般也够用了,所以依照上图我就把东西直接铺开了写的,后来一看惨不忍睹。依照此图首先进行了8位输入输出的设计,二进制转格雷码
module B2G(clk,rst,data_in_B,data_out_G);input clk, rst;input [7:0]data_in_B;output [7:0]data_out_G;wire [7:0]data_out_G_n;wire [8:0]data_in_B_exp;assign data_in_B_exp = {1'b0, data_in_B};assign data_out_G_n[0] = data_in_B_exp[0] ^ data_in_B_exp[1];assign data_out_G_n[1] = data_in_B_exp[1] ^ data_in_B_exp[2];assign data_out_G_n[2] = data_in_B_exp[2] ^ data_in_B_exp[3];assign data_out_G_n[3] = data_in_B_exp[3] ^ data_in_B_exp[4];assign data_out_G_n[4] = data_in_B_exp[4] ^ data_in_B_exp[5];assign data_out_G_n[5] = data_in_B_exp[5] ^ data_in_B_exp[6];assign data_out_G_n[6] = data_in_B_exp[6] ^ data_in_B_exp[7];assign data_out_G_n[7] = data_in_B_exp[7] ^ data_in_B_exp[8];reg [7:0]data_out_G;always @(posedge clk or posedge rst) beginif (rst) begin// resetdata_out_G <= 0;endelse begindata_out_G <= data_out_G_n;endendendmodule
格雷码转二进制
module G2B(clk,rst,data_in_G,data_out_B);input clk, rst;input [7:0]data_in_G;output [7:0]data_out_B;wire [7:0]data_out_B_n;wire [8:0]data_in_B_exp;assign data_in_B_exp = {1'b0, data_out_B_n};assign data_out_B_n[0] = data_in_G[0] ^ data_in_B_exp[1];assign data_out_B_n[1] = data_in_G[1] ^ data_in_B_exp[2];assign data_out_B_n[2] = data_in_G[2] ^ data_in_B_exp[3];assign data_out_B_n[3] = data_in_G[3] ^ data_in_B_exp[4];assign data_out_B_n[4] = data_in_G[4] ^ data_in_B_exp[5];assign data_out_B_n[5] = data_in_G[5] ^ data_in_B_exp[6];assign data_out_B_n[6] = data_in_G[6] ^ data_in_B_exp[7];assign data_out_B_n[7] = data_in_G[7] ^ data_in_B_exp[8];reg [7:0]data_out_B;always @(posedge clk or posedge rst) beginif (rst) begin// resetdata_out_B <= 0;endelse begindata_out_B <= data_out_B_n;endendendmodule
怎么样是不是肯定没出错,那是必然的,这么铺开了写咋能出错。
2.第二次代码
后来一想这样不行,我这个设计输入大于8位或者是任意位的话会出错,不具有通用性。而且这样铺开了写肯定不是办法,要用for循环来展开就对了。所以又查了下资料,写了第二版代码。任意小于32位宽的输入输出设计(integer型是32位),二进制转格雷码:
module B2G_new #(parameter width = 8)(clk,rst,data_in_B,data_out_G);input clk, rst;input [width-1:0]data_in_B;output [width-1:0]data_out_G;reg [width-1:0]data_out_G_n;wire [width:0]data_in_B_exp;assign data_in_B_exp = {1'b0, data_in_B};integer i;always @(data_in_B) begin for(i=0; i<width; i=i+1) data_out_G_n[i] = data_in_B_exp[i] ^ data_in_B_exp[i+1];endreg [width-1:0]data_out_G;always @(posedge clk or posedge rst) beginif (rst) begin// resetdata_out_G <= 0;endelse begindata_out_G <= data_out_G_n;endendendmodule
格雷码转二进制:
module G2B_new #(parameter width = 8)(clk,rst,data_in_G,data_out_B);input clk, rst;input [width-1:0]data_in_G;output [width-1:0]data_out_B;reg [width-1:0]data_out_B_n;integer i;always @(data_in_G or posedge rst) begindata_out_B_n[width-1] = data_in_G[width-1];for(i=width-1; i>0; i=i-1)data_out_B_n[i-1] = data_in_G[i-1] ^ data_out_B_n[i];endreg [width-1:0]data_out_B;always @(posedge clk or posedge rst) beginif (rst) begin// resetdata_out_B <= 0;endelse begindata_out_B <= data_out_B_n;endendendmodule
写晚这个时候觉得还行,然后我手残的打开了书,看到了书上的写法,意识到了自己的差距。。。
3.第三次代码
书上的代码太简单了,而且里面还有思维转换的过程。
二进制转格雷码:
module B2G_Conv #(parameter size = 4)( output [size-1:0] gray, input [size-1:0] binary ); assign gray = (binary >> 1) ^ binary;endmodule
module G2B_Conv #(parameter size = 4)( output reg [size-1:0] binary, input [size-1:0] gray ); integer k; always @(gray) begin for (k = 0; k < size; k = k + 1) binary[k] = ^(gray >> k); endendmodule
也就是说二进制转格雷码就是把二进制错位下然后按位亦或(果然如此),格雷码转二进制就是就是把当前位(包括当前的第k位)以前的所有格雷码按位亦或就好了,一观察果然是,厉害了。
我们再把转换那个图拿来看看,一看果然是对的。后面异步FIFO的设计就是用的这个代码。附:
顶层模块如下(没有第三次代码的加入):
module work(clk,rst);input clk, rst;reg [7:0]data_in_B;always @(posedge clk or posedge rst) beginif (rst) begin// resetdata_in_B <= 0;endelse begindata_in_B <= data_in_B + 1;endendwire [7:0]data_out_G1, data_out_G2, data_out_B1, data_out_B2;B2G u_b2g(.clk(clk),.rst(rst),.data_in_B(data_in_B),.data_out_G(data_out_G1));B2G_new u_b2g_new(.clk(clk),.rst(rst),.data_in_B(data_in_B),.data_out_G(data_out_G2));G2B u_g2b(.clk(clk),.rst(rst),.data_in_G(data_out_G1),.data_out_B(data_out_B1));G2B_new u_g2b_new(.clk(clk),.rst(rst),.data_in_G(data_out_G2),.data_out_B(data_out_B2));endmodule
testbench如下:
module tb();reg clk;reg rst;initial begin clk = 1'b0; forever #5 clk = ~clk; end initial beginrst = 1;#24 rst = 0;endwork u(.clk(clk),.rst(rst));endmodule
- 进阶之路——二进制与格雷码的相互转换模块设计
- 二进制与格雷码的转换
- 二进制与格雷码之间的转换
- 二进制与格雷码之间的转换---矩阵表示
- FPGA Verilog HDL 系列实例--------二进制与格雷码的转换
- 二进制码与格雷码互相转换
- 二进制与整数的相互转换
- 二进制 八进制 十六进制 之间的相互转换
- 十进制与二进制的相互转换
- 十进制和二进制的相互转换
- 二进制和十进制之间的相互转换
- 十进制小数与二进制的相互转换
- 十进制,二进制,八进制的相互转换
- 十进制和二进制的相互转换
- 二进制和十进制的相互转换
- 二进制十进制相互转换
- 二进制八进制相互转换
- 二进制十六进制相互转换
- 欢迎使用CSDN-markdown编辑器
- ZooKeeper_4_Java操作ZK_创建会话
- 数据库-sql语句
- table的默认宽度之变化
- MySql中的数据类型
- 进阶之路——二进制与格雷码的相互转换模块设计
- Java技术图谱
- NLP深度学习 —— CS224学习笔记12
- HDU 3861 The King’s Problem(tarjan缩点+最小路径覆盖ISAP)
- html的meta标记大全
- js中的常用Math函数
- JavaScript异步和单线程经典的例子setTimeout
- 线程
- Ubuntu录制视频转GIF