下冰雹 · 2022年03月08日

【安路 EG4S20 版本】组合逻辑基础实验

组合逻辑基础

在之前的文章中已经介绍过了安路EG4S20 FPGA开发板以及TD工具的使用,从这篇文章开始,我们将介绍和分享一系列的基础实例,期望能帮助大家逐步走近FPGA。数字逻辑电路分为组合逻辑电路和时序逻辑电路,组合逻辑电路的输出仅取决于当前的输入,其逻辑功能的实现不需要时钟的参与,因此弄清楚组合逻辑电路的输入输出关系尤为重要。这次的文章将通过几个基础的实例介绍FPGA开发板上组合逻辑电路的实现,这些实例包括在数字逻辑设计课程中所熟知的部分中规模集成电路:优先编码器、多路复用器以及加法器,最后还将介绍算术逻辑单元ALU的实现。

实验1 优先编码器

实验原理

在数字系统中,有时候需要将输入的数据信息变换为某种特定的编码输出,编码器便是实现这一编码功能的逻辑电路。编码器的逻辑功能是将输入的高低电平信号转换为二进制编码输出,通常是将多比特的输入数据转换为少比特的二进制编码输出。而另一个常用的组合逻辑电路有译码的功能,即译码器,其逻辑功能是编码的逆过程,通常是将少比特的输入编码翻译为多比特的数据信息输出。由于两者的实现方式非常类似,这里仅以编码器中的优先编码器为例介绍一下其在FPGA开发板上的实现过程。
image.png
编码器与译码器
如之前的文章已经提到,FPGA开发流程中的第一步是编写RTL代码进行电路描述,对于简单的组合逻辑电路来说,只要弄清楚了输入输出关系,RTL代码的编写就变得相对轻松。这里将通过一个4-2优先编码器的真值表来回顾一下该组合逻辑电路的输入输出关系。该优先编码器有4个比特的高电平有效的数据输入,2个比特的编码输出以及一个用于标识输入是否有效的输出信号GS。该优先编码器的功能是根据优先级最高的有效输入位,将输入转换为对应的二进制编码输出,而当所有输入位都无效时,GS信号会输出为0,表示无有效输入。
优先编码器真值表
image.png

代码解读

在硬件描述语言Verilog HDL中,多路分支语句case可以很好的对应真值表来对组合逻辑电路进行描述。如下的参考代码为对应该真值表的优先编码器的一种描述方式,这里使用了casex语句,在该语句中,若分支表达式的某些值为z或不定值x,将忽略对这些位的比较。

module priority_encoder(Data,GS,Code,LED);
    input [3:0] Data;
    output reg [1:0] Code;
    output GS;    
    output [4:0] LED;
    //EG4S20 IO默认弱上拉,因此需要输出低电平熄灭LED7-3
    assign LED = 5'b0;
    assign GS = Data ? 1'b1 : 1'b0;
    always@(Data)
        casex(Data)
            4'b1xxx : Code = 2'b11;
            4'b01xx : Code = 2'b10;
            4'b001x : Code = 2'b01;
            4'b0001 : Code = 2'b00;
            default : Code = 2'b00;
        endcase            
endmodule

当然,也可以使用嵌套的条件语句if-else来对优先编码器进行描述,其参考代码如下。


module priority_encoder(Data,Code,GS,LED);
    input [3:0] Data;
    output reg [1:0] Code;
output GS;
output [4:0] LED;
    //EG4S20 IO默认弱上拉,因此需要输出低电平熄灭LED7-3
    assign LED = 5'b0;
    assign GS = Data ? 1'b1 : 1'b0;
    always@(Data) begin
        if(Data[3]) Code = 2'b11;
        else if(Data[2]) Code = 2'b10;
        else if(Data[1]) Code = 2'b01;
        else if(Data[0]) Code = 2'b00;
        else Code = 2'b00;
    end      
endmodule

仿真

在编写好RTL代码后就需要进行功能验证,即编写好testbench并使用仿真工具进行仿真。对于简单的组合逻辑电路,编写testbench时只需要将输入的所有组合方式枚举一遍,然后观察各种输入组合下的输出情况即可。以下是testbench的参考代码。通过每20ns对输入Data加1(输入数据Data将周期性地按照 0000 0001 0010 … 1111序列进行变化),就可以观察仿真波形得到所有输入组合方式下的输出情况。


`timescale 1ns / 1ps
module priority_encoder_tb;
    reg [3:0] Data;
    wire [1:0] Code;
    wire GS;
    priority_encoder uut(
        .Data(Data),
        .Code(Code),
        .GS(GS)
    );
    initial Data = 0;
    always #20 Data = Data + 1;
endmodule

下图是在Modelsim软件中的得到的部分仿真波形,可以观察到不同输入组合方式下的输出与真值表完全一致。
image.png
优先编码器仿真波形

上板验证

仿真完成后,可参考下表进行管脚约束,具体约束方法都在之前的文章详细讲述过,这里不再赘述。
优先编码器的管脚约束
image.png
按照流程,之后将通过TD进行综合、布局布线并最后生成可下载到FPGA上的比特流,将比特流下载到FPGA开发板上以后,便可以观察上板的现象。上板时已按照上文中的表格进行了管脚约束,将数据输入约束到了拨码开关的SW0至SW3,编码输出由LED5和LED6显示,GS信号由LED7显示。

实验2:多路复用器

实验原理

多路复用器也叫数据选择器,如下图所示,是根据选择信号Sel的值从多个数据输入中选择其中一个进行输出,是数字系统中应用非常广泛的一种逻辑电路。
image.png
多路复用器
如下是一个典型的四选一多路复用器的真值表,其逻辑功能是从四个输入中选择一个输出,因此选择信号需要两个比特。
四选一多路复用器真值表
image.png

代码解读

和之前的优先编码器类似,有了真值表便清楚了多路复用器的输入输出关系,编写RTL代码进行电路描述时只需要用硬件描述语言翻译该真值表即可,如下为四选一多路复用器的参考代码,使用了case语句在过程块中描述多路复用器的逻辑功能,代码中的过程块使用了always@(*)这种写法,该语句的always块中任一输入信号发生改变都将触发该过程块的执行,当敏感信号较多的时候推荐使用这种方便的写法。

module mux4(data_in,sel,data_out);
    input [3:0] data_in;
    input [1:0] sel;
    output reg data_out;
    always@(*)
        case(sel)
            2'b11 : data_out = data_in[3];
            2'b10 : data_out = data_in[2];
            2'b01 : data_out = data_in[1];
            2'b00 : data_out = data_in[0];
        endcase
endmodule

这里还提供了另一种RTL代码的参考写法,没有使用多路分支语句,而是使用连续赋值语句assign和条件操作符?:来描述多路复用器的功能,虽然看似有点花里胡哨但也是可行的。

module mux4(data_in,sel,data_out);
    input [3:0] data_in;
    input [1:0] sel;
    output data_out;
    assign data_out = sel[1]?(sel[0]?data_in[3]:data_in[2]):(sel[0]?data_in[1]:data_in[0]);
endmodule

仿真结果

testbench的写法也和前文所说的类似,列举出所有的输入组合即可,这里将四路输入data_in和选择信号sel拼接起来并周期性地加1便可得到所有的输入组合。

`timescale 1ns / 1ps
module mux4_tb;
    reg [3:0] data_in;
    reg [1:0] sel;
    wire data_out;
    mux4 uut(
        .data_in(data_in),
        .sel(sel),
        .data_out(data_out)
    );
    initial begin
        data_in = 4'b0000;
        sel = 2'b00; 
    end 
    always #20 {data_in,sel} = {data_in,sel} + 1;
endmodule

下图是在modelsim中得到的四选一多路复用器的部分仿真波形,观察波形时可以右键sel信号,点击radix,之后选择unsigned类型便于更直观的观察。可以看到输出信号的无符号按照选择信号sel正确地选择了对应的输入数据进行输出。
image.png
四选一多路复用器仿真波形

上板验证

使用TD软件绑定管脚、综合、布局布线以及生成比特流文件并下载至FPGA开发板,便可观察上板现象。下表给出了该实例具体的管脚约束。
四选一多路复用器的管脚约束
端口名 管脚名 管脚编号
image.png
上板时按照上表将数据输入约束到了拨码开关的SW0至SW3,选择信号sel约束到了拨码开关的SW6至SW7,数据输出由LED7显示。

END

文章来源:
https://www.yuque.com/yingmuketang/01/az5zg7
https://www.yuque.com/yingmuketang/01/ggkiy7

推荐内容

更多内容请关注走进FPGA专栏
推荐阅读
关注数
1615
内容数
27
本专栏将以【安路EG4S开发板】为例,从基础板卡信息及使用教程,基础实验设计与实现及综合性实验设计与实现带大家学习FPGA。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息