crazybird

【原创】“参数化”的编码器

2
阅读(3308)

    当你看到这个题目的时候,也许你会觉得它非常的简单。好吧,算你猜对了。但是,我想通过该题目向大家介绍可以实现该设计的方法以及几个不常见或不常用的知识点。

    首先,在开始我们的设计之前,介绍一下设计中会用到的两个知识点。

    <1>由于该设计是可参数化的,所谓“参数化”就是通过设置输入数据的位宽就能实现相应数据位宽的编码器。假设编码器的输入数据位宽为A,输出数据位宽为B,由我们所学的数电知识可知其关系为B = log2(A),其中log2(x)是以2为底的对数函数。而Verilog HDL中有与其对应的系统函数:$clog2(x)。它在参数定义中的一个例子如下所示:

parameter  C_DIN_WIDTH = 8;
parameter  C_DOUT_WIDTH = $clog2(C_DIN_WIDTH);

    <2>这里我要介绍的是关键字wor,相信大家都很少用到它。首先,它是可综合的;其次,它拥有线或的功能;最后,由assign对其进行赋值。例如,一个或门的功能模块如下所示:

/*****************************版权申明**********************************
**                    电子技术应用网站, CrazyBird
**     http://www.chinaaet.com, http://blog.chinaaet.com/crazybird
**
**----------------------------文件信息----------------------------------
** 文件名:          or_gate.v
** 创建者:          CrazyBird
** 创建日期:        2016-1-24
** 版本号:           v1.0
** 功能描述:        或门功能
**                   
***********************************************************************/
// synopsys translate_off
`timescale 1 ns / 1 ps
// synopsys translate_on
module or_gate (
    dina,
    dinb,
    dout
    );
    //******************************************************************
    //  端口定义
    //******************************************************************
    input       dina;
    input       dinb;
    output wor  dout;
    
    //******************************************************************
    //  或门实现
    //******************************************************************
    assign dout = dina;
    assign dout = dinb;
    
endmodule

    对应的综合结果如图1所示。

综合之或门.png

图1  综合结果

    接下来介绍实现该编码器的方法,我想到的有两种:第一,通过遍历数据位的方法;第二,通过推导公式的方法。

    <1>通过遍历数据位的方法有两种,都是借助for循环来实现的。第一种方法是从输入数据的低位向高位遍历,并判断遍历到的数据位是否为1,若为1,则其对应的二进制码就是编码器的输出。对应的Verilog HDL实现如下(下面所有的设计都已验证过,在本博文中就不给出仿真结果了):

/*****************************版权申明**********************************
**                    电子技术应用网站, CrazyBird
**     http://www.chinaaet.com, http://blog.chinaaet.com/crazybird
**
**----------------------------文件信息----------------------------------
** 文件名:          priority_encode.v
** 创建者:          CrazyBird
** 创建日期:        2016-1-24
** 版本号:           v1.0
** 功能描述:        基于遍历法的参数化编码器
**                   
***********************************************************************/
// synopsys translate_off
`timescale 1 ns / 1 ps
// synopsys translate_on
module priority_encode(
    din,
    dout
    );
    // ******************************************************************
    // 参数定义
    // ******************************************************************
    parameter   C_DIN_WIDTH  = 8;
    parameter   C_DOUT_WIDTH = $clog2(C_DIN_WIDTH);
    
    // ******************************************************************
    // 端口定义
    // ******************************************************************
    input       [C_DIN_WIDTH-1:0]       din;
    output reg  [C_DOUT_WIDTH-1:0]      dout;
    
    // ******************************************************************
    // 内部变量定义
    // ******************************************************************
    reg     [C_DOUT_WIDTH:0]        bit_cnt;
    reg     [C_DOUT_WIDTH-1:0]      dout_r;
    
    // ******************************************************************
    // 编码器实现
    // ******************************************************************
    always @(*)
    begin
        dout_r = {(C_DOUT_WIDTH){1'b0}};
        for(bit_cnt = 0;bit_cnt < C_DIN_WIDTH;bit_cnt = bit_cnt + 1)
        begin
            if(din[bit_cnt] == 1'b1)
                dout_r = bit_cnt[C_DOUT_WIDTH-1:0];
        end
        dout = dout_r;
    end
    
endmodule

    另一种方法是从输入数据的高位向低位遍历,并判断遍历到的数据位是否为1,若为1,则其对应的二进制码就是编码器的输出。

    <2>通过推导公式的方法。下面是8-3编码器的输入输出对应关系:

   din         dout
0000_0000       000 
0000_0001       000
0000_0010       001
0000_0100       010
0000_1000       011
0001_0000       100
0010_0000       101
0100_0000       110
1000_0000       111

    根据以上关系可推出以下公式:

dout[0] = din[2'b001] ^ din[2'b011] ^ din[2'b101] ^ din[2'b111];
dout[1] = din[2'b010] ^ din[2'b011] ^ din[2'b110] ^ din[2'b111];
dout[2] = din[2'b100] ^ din[2'b101] ^ din[2'b110] ^ din[2'b111];

    再总结下上述公式,编码器输出的某个位可由可能导致该位为1的输入位进行或运算的结果决定,如编码器输入din中所有二进制索引号第0位为1的位进行或运算,便得到编码器输出第0位dout[0];编码器输入din中所有二进制索引号第1位为1的位进行或运算,便得到编码器输出第1位dout[1];依次类推。

    在设计中,利用两个for循环实现,一个for用于对编码器输入的索引号进行计数,另一个for用于对编码器输出的索引号进行计数。同时还要判断输入二进制索引号对应位以进行相应的或运算。基于公式的参数化编码器,其Verilog HDL实现如下所示:

/*****************************版权申明**********************************
**                    电子技术应用网站, CrazyBird
**     http://www.chinaaet.com, http://blog.chinaaet.com/crazybird
**
**----------------------------文件信息----------------------------------
** 文件名:          priority_encode.v
** 创建者:          CrazyBird
** 创建日期:        2016-1-24
** 版本号:           v1.0
** 功能描述:        基于公式法的参数化编码器
**                   
***********************************************************************/
// synopsys translate_off
`timescale 1 ns / 1 ps
// synopsys translate_on
module priority_encode(
    din,
    dout
    );
    //******************************************************************
    //  参数定义
    //******************************************************************
    parameter   C_DIN_WIDTH  = 8;
    parameter   C_DOUT_WIDTH = $clog2(C_DIN_WIDTH);
    
    //******************************************************************
    //  端口定义
    //******************************************************************
    input       [C_DIN_WIDTH-1:0]       din;
    output wor  [C_DOUT_WIDTH-1:0]      dout;
    
    //******************************************************************
    //  内部变量定义
    //******************************************************************
    genvar          i;
    genvar          j;
    
    //******************************************************************
    //  编码器实现
    //******************************************************************
    generate
        for(i = 0;i < C_DIN_WIDTH;i = i+1)
        begin : din_traversal
            for(j = 0;j < C_DOUT_WIDTH;j = j+1)
            begin : dout_traversal
                if(i[j] == 1'b1)
                    assign dout[j] = din[i];
            end
        end
    endgenerate
    
endmodule