跳转至

实验1:编码器与译码器

提示

在查阅本文档进行实验时,verilog的基础知识可查阅普通班lab1,vivado的基本使用方法可查阅提高班预备知识-vivado的使用

在本次实验中,我们将学习编码器和译码器的原理。通过设计几个常见的编码器和译码器,我们将了解这种元件在数字电路中的广泛应用。

1 编码器

编码器是一种\(n\)位独热码转换为其他编码格式(例如\(log_2n\)位二进制编码)的组合电路元件。根据其对输入格式的接受能力不同,我们将其分为普通编码器优先编码器。在本次实验中,我们将实现10线-4线BCD编码器

1.1 普通编码器

普通编码器只能接受独热码(有且仅有一位为1)的输入,并输出对应的编码。对于其他类型的输入,普通编码器的输出可以被设计为任意值。为了区分输出是否有效,我们还需要另外一个单位宽输出使能信号e,来表示其输出是否有效

在很多情况下,我们希望能够通过输入来告知编码器当前输入是否有效,因此我们会再设置一个使能位。当使能位为0时,编码器的输出可以定义为任意值,但输出使能应当为0,当使能位为1时,编码器应当按照上述逻辑执行输出。

1.2 优先编码器

优先编码器可以接受任意类型的输出,但是当输入中有多个位为1时,优先编码器只会输出最高位为1的编码

对于具备输入使能控制位的优先编码器,当使能位为0时,输出可以被定义为任意值,此时其输出使能应当为0;当使能位为1时,优先编码器应当按照上述逻辑执行输出。

1.3 可选模式的编码器

在本次实验中,我们将实现一个10线-4线BCD编码器。BCD编码器可以将10位输入码转换为4位二进制编码,同时我们可以使用一个选择位t来控制其编码的模式。当t为0时,BCD编码器将按照普通编码器的逻辑执行,当t为1时,BCD编码器将按照优先编码器的逻辑执行。

image-20230923131758352

我们推荐使用行为级描述(always+case)来实现编码器。这里我们给出一种实现可选模式编码器的思路:

  • 实现一个带输入、输出使能的普通编码器
  • 实现一个带输入、输出使能的优先编码器
  • 根据选择位t,使用一个多路选择器来选择普通编码器和优先编码器的输出作为最终输出。
示例代码
ECD
module encoder10_4(
input e,//使能
input t,//类型
input [9:0] a,//待编码信号
output reg f,//标志
output reg[3:0] y//BCD码
);
always @(e,t,a)begin
f=1;
if(e==0) begin y=4'd0;f=0;end   //输入使能信号指示当前不进行编码
else begin      //输入使能信号指示当前进行编码
    case(t)     //根据类型信号选择普通或优先编码类型
        1'b0:begin//普通编码器
            case(a)
            10'b10_0000_0000:y=4'd9;
            10'b01_0000_0000:y=4'd8;
            10'b00_1000_0000:y=4'd7;
            10'b00_0100_0000:y=4'd6;
            10'b00_0010_0000:y=4'd5;
            10'b00_0001_0000:y=4'd4;
            10'b00_0000_1000:y=4'd3;
            10'b00_0000_0100:y=4'd2;
            10'b00_0000_0010:y=4'd1;
            10'b00_0000_0001:y=4'd0;
            default:begin y=4'd0;f=0;end//输出使能指示当前编码无效
            endcase
        end
        1'b1:begin//优先编码器
            casex(a)
            10'b1x_xxxx_xxxx:y=4'd9;
            10'b01_xxxx_xxxx:y=4'd8;
            10'b00_1xxx_xxxx:y=4'd7;
            10'b00_01xx_xxxx:y=4'd6;
            10'b00_001x_xxxx:y=4'd5;
            10'b00_0001_xxxx:y=4'd4;
            10'b00_0000_1xxx:y=4'd3;
            10'b00_0000_01xx:y=4'd2;
            10'b00_0000_001x:y=4'd1;
            10'b00_0000_0001:y=4'd0;
            default:begin y=4'd0;f=0;end//输出使能指示当前编码无效
            endcase
        end
        default:begin y=4'd0;f=0;end
    endcase
end
end
endmodule
复用数据通路

你是否觉得上述实现会浪费电路中一半的计算资源(当使用优先编码器时,普通编码器的计算结果被浪费)?。仔细思考,你是否真的需要实现两个编码器?优先编码器的输出能否作为普通编码器的输出?如果你有这样的想法,那么你可以尝试使用复用数据通路来实现可选模式编码器。当然,当你复用了数据通路后,你还需要仔细考虑输出使能的生成逻辑。

硬件设计和软件设计不同,但也有相似之处。仔细思考,当你写C语言程序的时候,对于不同分支语句中的输出,如果它们有相同的部分,你是否也会直接把这个输出提前到分支外面?例如如下语句:

C
if (a == 1) {
    b = 1;
    printf("a is 1\n");
} else {
    b = 1;
    printf("a is not 1\n");
}
这里对于b的赋值,就真的可以提前到分支外面,这样就可以减少重复的代码。而对于硬件设计而言,这样的设计对于设计的优化是非常显著的,因为它可以大幅度减少硬件资源的使用。

在你以后的设计中,你也可以尝试多求同存异,尽量多地复用数据通路,这样可以大幅度减少硬件资源的使用。

复用数据通路 优化版示例代码
module encoder10_4_optimize(
    input e,//使能
    input t,//类型
    input [9:0] a,//待编码信号
    output reg f,//标志输出是否有效
    output reg[3:0] y//BCD码
);
always @(e,t,a)begin
    f=1;//无效情况都排除时认为编码有效
    if(e==0) begin y=4'd0;f=0;end   //输入使能指示当前不进行编码
    else begin      //输入使能信号指示当前进行编码
        if(a[9]) y=4'd9;else
        if(a[8]) y=4'd8;else 
        if(a[7]) y=4'd7;else
        if(a[6]) y=4'd6;else
        if(a[5]) y=4'd5;else
        if(a[4]) y=4'd4;else
        if(a[3]) y=4'd3;else
        if(a[2]) y=4'd2;else
        if(a[1]) y=4'd1;else
                 y=4'd0;
        if(t==0)//普通编码模式,有多位1时,指示编码无效
            if((a&(a-1))!=10'b00_0000_0000)//多位1
                f=0;
        if(a==0)//普通或优先编码模式,全为0时,指示编码无效
            f=0;
    end
end
endmodule

2 译码器

译码器是一种将其他编码格式(例如\(log_2n\)位二进制编码)转换为 \(n\)位独热码或其他类型信号的组合电路元件。在本次实验中,我们将实现4线-10线BCD译码器七段数码管译码器

2.1 4线-10线BCD译码器

4线-10线BCD译码器可以将4位BCD编码转换为10位独热码。这种输出有且仅有一位为1。

若输入的BCD码不合法(如输入为4'b1010),则输出可以定义为任意值。

image-20230923194824612

这里我们推荐使用行为级描述来进行实现,但你也可以尝试使用assign + 左移运算来完成这个设计。

2.2 七段数码管译码器

七段数码管译码器可以将4位BCD编码转换为七段数码管的控制信号。这里我们使用共阳极七段数码管,因此输出信号为低电平有效信号。

七段数码管由两个控制信号构成,分别为段选信号(ca-cg)位选信号(an),均为低电平有效。段选信号用于控制七段数码管的哪一段被点亮,位选信号用于控制哪一位的七段数码管被点亮。译码器只负责将输入的BCD码转换为段选信号。在本次实验中,我们希望最低位的七段数码管被点亮,因此位选信号an恒为8'b11111110。

image-20230923195526721

七段数码管的段选信号和物理上的七段数码管的对应关系如下图所示:

image-20230923195758785

其中,ca-cg也就对应了图中a-g的位置,你只需要将ca-cg对应的位置置为0,就可以点亮对应的段。

3 总体电路设计

image-20230923200121860

我们需要实现的电路如上所示。

  • 需要编码的独热码由0-9号开关提供,10-13号开关是一组编码信号,可以直接作为译码器的输入,编码器模式选择由14号开关提供,编码器的输入使能由15号开关提供。

  • 编码器会将输入的独热码进行编码,编码后的输出接入到11-14号led指示灯中,而其输出使能则接入到15号led指示灯中。

  • 如果编码器的输出有效,则两个译码器会对其进行译码,译码后的独热码输出到0-9号led指示灯中,同时七段数码管会显示对应的数字;如果编码器的输出无效,则两个译码器会对10-13号开关的输入进行译码。

  • 对于译码对象的选择,我们使用译码器的输出信号作为控制信号,对两种源头不同的编码进行二路选择。

vivado项目内的设计资源结构示例:

仿真测试文件

本次实验助教为大家提供了一个仿真测试文件的框架,请点击这里下载。

请注意,这个仿真测试文件的后缀为.sv,也就是system verilog文件,sv在一些语法要求相比v更宽松(尤其是可以使用logic来自动判断reg和wire类型)。在这个仿真测试文件中,模块输出段接的信号是reg类型,这在sv中是可以的,而在v中则会报错"concurrent assignment to a non-net out is not permitted"。这是因为v中输出端口模块例化时,output 端口必须连接 wire 型变量。

你可以参考「预备知识-vivado的使用-step4:对设计进行仿真」或者「普通班2023年lab2-编写测试文件」来学习仿真测试文件的编写。

限制文件

本次实验的顶层模块如果是这样的,那么你的限制文件应该是这样的。请结合这个例子,学习提高班文档-预备知识-实现电路,来理解限制文件的使用。