我的Verilog HDL学习历程(二) 组合逻辑电路的一个实例:基于EGO1板子

题目:

实验一个多功能数字电路模块
具体要求如下:
1) 输入数据为两个一位十进制数A和B,A和B均为8421码表示,其中数据A由拨动开关SW7-SW4输入(SW7为MSB),数据B由SW3-SW0输入(SW3为MSB);
2) 电路的功能包括求和、比较大小、输出最大值和输出最小值四种;分别由如下图所示的按键开关控制,当按键按下时,电路执行相对应的功能并输出结果。
在这里插入图片描述
3) 求和功能描述:当按下求和键时,对A和B两个数相加,相加的结果显示在数码管上,注意相加的结果需要进行BCD码调整,显示模块必须调用实验一中设计的显示译码电路,当十位为0时,需要灭零。
在这里插入图片描述
4) 比较大小模块描述:当比较大小功能键按下时,比较A和B的大小,当A<B时显示01(不灭0),当A>B时显示10,A=B时显示11。
5) 输出最大(小)值功能描述:当按下输出最大(小)值功能键时,将A和B中的最大(小)值显示在数码管上。

(出题:北京理工大学 张延军老师)

1. 设计思路

在做本题之前,已经编写好了LED显示模块,这个模块比较简单,我就不多说了.

module decoder_7led(
    input turn_off,//灭灯信号
    input test,//测灯信号
    input zero,//灭零信号
    input [3:0] number,//输入的四位二进制数
    output reg [7:0] display,//数码管片选
    output reg led,//控制LD2的0号灯
    output reg select=1//段选,恒为1,连接G6管脚。
);
//led变量
always @ *
begin 
    if (turn_off==1'b0)//仍按照优先级顺序判断
        led=1'b0;
    else if (test==1'b0)
        led=1'b0;
    else if ((zero==1'b0)&&(number==4'b0000))//满足灭零条件
        led=1'b1;
    else
        led=1'b0;
        
end
//display变量
always @ *
begin
    if (turn_off==1'b0)//灭灯有效
        display=8'b00000000;
    else if (test==1'b0)//测试有效
        display=8'b11111111;
    else if ((zero==1'b0)&&(number==4'b0000))//满足灭零条件
            display=8'b00000000;
    else
    begin
        case(number)//情况逐个讨论
            4'b0000:display=8'b11111100;
            4'b0001:display=8'b01100000;
            4'b0010:display=8'b11011010;
            4'b0011:display=8'b11110010;
            4'b0100:display=8'b01100110;
            4'b0101:display=8'b10110110;
            4'b0110:display=8'b10111110;
            4'b0111:display=8'b11100000;
            4'b1000:display=8'b11111110;
            4'b1001:display=8'b11100110;
            4'b1010:display=8'b00011010;
            4'b1011:display=8'b00110010;
            4'b1100:display=8'b01000110;
            4'b1101:display=8'b10010110;
            4'b1110:display=8'b00011110;
            4'b1111:display=8'b00000000;
        endcase
    end
end

endmodule // decoder_7led

首先将整个逻辑模块分为四大功能模块:求和、比较、求最大值和求最小值模块和数码管显示模块,以及起到控制作用的选择模块。本题的关键在于如何将这些模块正确地联系起来。首先分别讨论各自模块的实现:
①求和模块
若要对两个8421数进行求和,且求和结果仍为8421数,则非常关键的一步在于判断是否进位如果产生了进位,那么要在加法结果之后再加6(0000_0110).
本模块的输入是两个4位8421数,为了方便地进行加法,首先拓展为8位二进制数。产生进位,即直接相加的结果大于9,否则就是没有产生进位,直接将结果输出。为此创建bcd_adder模块,输入为两个8421数和控制加法功能的按钮信号,输出为十位数结果和个位数结果,需要中间变量来储存加法结果,利用8位寄存器变量。还有需要注意的一点是当十位数结果为0时要清零。因为最终计算的结果要输入到数码管控制的电路里,且在实验一中当数码管模块的输入为4’b1111时数码管的8个LED全灭。因此与其控制数码管模块的灭零信号,不如直接让十位数对应的输出为4’1111更为简便。代码如下:

	module bcd_adder(
    input [3:0] numa1,//输入数字1
    input [3:0] numa2,//输入数字2
    input button_adder,//按钮
    output reg [3:0] resulta1,//结果,十位数
    output reg [3:0] resulta2//结果,个位数
);
reg [7:0] temp;
always @ *
begin
    temp={4'b0000,numa1}+{4'b0000,numa2};//扩充位数
    if(temp>8'b00001001)//产生进位
        begin
            {resulta1,resulta2}=temp+8'b00000110;//加6
        end

   
 else
        begin
        resulta1=4'b1111;//十位数为0时要清零
        resulta2=temp[3:0];
        end
end

endmodule // 加法模块

②比较大小模块
比较大小模块的功能比较简单,主体就是if语句,让对应的输入情形对应正确的输出即可。为此创建compare模块,输入为两个8421数和控制比较功能的按钮信号,输出为十位数结果和个位数结果。代码如下:

	module compare(
    input [3:0] numc1,
    input [3:0] numc2,
    input button_compare,
    output reg [3:0] resultc1,
    output reg [3:0] resultc2
);
//resultc1
always @ *
begin
    if (numc1<numc2)
            resultc1=4'b0000;
    else if (numc1>numc2)
            resultc1=4'b0001;
    else
            resultc1=4'b0001;
end
//resultc2
always @ *
begin
    if (numc1<numc2)
        resultc2=4'b0001;
    else if (numc1>numc2)
        resultc2=4'b0000;
    else
        resultc2=4'b0001; 
end
endmodule // 比较模块

③输出最大/最小值模块
这两个模块在功能上是相似的。由于输入的是两个8421数,二者中的较大/较小者一定是个位数,因此显示十位数的数码管(或说一个数码管)就不需要显示了,如前所述,可以直接用4’b1111来灭灯。为此创建export_max和export_min模块,代码如下:

	module export_max(
    input [3:0] num_max1,
    input [3:0] num_max2,
    input button_max,
    output reg [3:0] result_max1=4'b1111, //十位是0
    output reg [3:0] result_max2
);
always @ *
begin
    if(num_max1>num_max2)
            result_max2=num_max1;
    else
            result_max2=num_max2;
end

endmodule // 输出最大值模块
module export_min(
    input [3:0] num_min1,
    input [3:0] num_min2,
    input button_min,
    output reg [3:0] result_min1=4'b1111,//十位是0
    output reg [3:0] result_min2
);
always @ *
begin
    if(num_min1<num_min2)
            result_min2=num_min1;
    else
            result_min2=num_min2;
end
endmodule // 输出最小值模块

④选择模块
至此实现四个功能的模块已经设计完了,为了避免混乱,四个模块最好独立,不要管脚复用。这时候就需要一个选择器,来选择究竟将哪个模块的输出连接到数码管模块的输入。控制究竟发送哪个数据的信号当然是四个按钮,此外,应将四个模块的输出作为这个模块的输入。为此创建mux模块,输入为四个按钮信号和四个模块的对应输出,输出为控制两个数码管的信号,即显示的第一位数和第二位数对应的信号。代码如下:

	module mux(
	//四个模块的八个输出
    input [3:0] add_output_1,
    input [3:0] add_output_2,
    input [3:0] cmp_output_1,
    input [3:0] cmp_output_2,
    input [3:0] max_output_1,
    input [3:0] max_output_2,
    input [3:0] min_output_1,
input [3:0] min_output_2,
//四个按钮
    input button_a,
    input button_c,
    input button_x,
input button_n,
//输出:第一位数和第二位数
    output reg [3:0] result_1,
    output reg [3:0] result_2
);
always @ *
begin
    if (button_a==1)//如果是加法功能
        {result_1,result_2}={add_output_1,add_output_2};
    else if (button_c==1)//如果是比较功能
        {result_1,result_2}={cmp_output_1,cmp_output_2};
    else if (button_x==1)//如果是求最大值功能
        {result_1,result_2}={max_output_1,max_output_2};
    else if(button_n==1)//如果是求最小值功能
        {result_1,result_2}={min_output_1,min_output_2};
    else //如果都不是(没有按钮被摁下),就输出两个0.
        {result_1,result_2}={4'b0000,4'b0000};
end
endmodule // 选择器 对输出信号进行选择送到LED模块

⑤顶层模块
顶层模块的设计是本题的关键。整个电路的架构应当是:有六个输入,分别是两个8421数和4个按钮。有两个数码管,因此有六个输出,每个数码管对应三个输出:片选、位选和LED灯。这里直接利用实验一的数码管模块。六个输入是并行的,同时输入到四个功能模块中。四个模块和选择器的连接关系前面已述,选择器的两个输出直接送给对应的两个数码管模块。数码管的三个信号:灭灯、灭零和测试信号由于用不到,可以直接赋值为无效。代码如下:

//顶层模块
module multiply_top(
    input [3:0] num1,
    input [3:0] num2,
    input B_add,
    input B_cmp,
    input B_max,
    input B_min,
    output [7:0] display1,
    output [7:0] display2,
    output select1,
    output select2,
    output led1,
    output led2
);
//中间连线
wire [3:0] led_number_a_1;
wire [3:0] led_number_a_2;
wire [3:0] led_number_c_1;
wire [3:0] led_number_c_2;
wire [3:0] led_number_max_1;
wire [3:0] led_number_max_2;
wire [3:0] led_number_min_1;
wire [3:0] led_number_min_2;

wire [3:0] to_led_1;
wire [3:0] to_led_2;
//将四个功能模块实例化
bcd_adder BCD_ADDER
(.numa1(num1),.numa2(num2),.button_adder(B_add),.resulta1(led_number_a_1),.resulta2(led_number_a_2));
compare CMP
(.numc1(num1),.numc2(num2),.button_compare(B_cmp),.resultc1(led_number_c_1),.resultc2(led_number_c_2));
export_max EPMAX
(.num_max1(num1),.num_max2(num2),.button_max(B_max),.result_max1(led_number_max_1),.result_max2(led_number_max_2));
export_min EPMIN
(.num_min1(num1),.num_min2(num2),.button_min(B_min),.result_min1(led_number_min_1),.result_min2(led_number_min_2));

//将选择器实例化
mux MUX1 (
    .add_output_1(led_number_a_1),.add_output_2(led_number_a_2),//加法输出
    .cmp_output_1(led_number_c_1),.cmp_output_2(led_number_c_2),//比较输出
    .max_output_1(led_number_max_1),.max_output_2(led_number_max_2),//最大值输出
    .min_output_1(led_number_min_1),.min_output_2(led_number_min_2),//最小值输出
    .button_a(B_add),.button_c(B_cmp),.button_x(B_max),.button_n(B_min),//四个按钮
    .result_1(to_led_1),.result_2(to_led_2));//输出,传给LED模块

//LED模块实例化
decoder_7led LED1
(.turn_off(1'b1),.test(1'b1),.zero(1'b1),.number(to_led_1),.display(display1),.led(led1),.select(select1));
decoder_7led LED2
(.turn_off(1'b1),.test(1'b1),.zero(1'b1),.number(to_led_2),.display(display2),.led(led2),.select(select2));
endmodule

2. 仿真与测试

编写testbench模块,分别测试四个功能。代码如下:

module testbench;
reg [3:0] NUM1;
reg [3:0] NUM2;
reg B_ADD;
reg B_CMP;
reg B_MAX;
reg B_MIN;
wire [7:0] DISPLAY1;
wire [7:0] DISPLAY2;
wire SELECT1;
wire SELECT2;
wire LED1;
wire LED2;
multiply_top TEST (.num1(NUM1),.num2(NUM2),
                .B_add(B_ADD),.B_cmp(B_CMP),
                .B_max(B_MAX),.B_min(B_MIN),
                .display1(DISPLAY1),.display2(DISPLAY2),
                .select1(SELECT1),.select2(SELECT2),
                .led1(LED1),.led2(LED2));

initial
begin
    NUM1=4'b0000;
    NUM2=4'b0000;
    B_ADD=0;
    B_CMP=0;
    B_MAX=0;
    B_MIN=0;

end

always
begin
    #20 NUM1=4'b0100;NUM2=4'b0001;
    #20 B_ADD=1;
    #10 B_ADD=0;
    #20 B_CMP=1;
    #10 B_CMP=0;
    #20 B_MAX=1;
    #10 B_MAX=0;
    #20 B_MIN=1;
    #20 B_MIN=0;

    #20 NUM1=4'b1000;NUM2=4'b1001;
    #20 B_ADD=1;
    #10 B_ADD=0;
    #20 B_CMP=1;
    #10 B_CMP=0;
    #20 B_MAX=1;
    #10 B_MAX=0;
    #20 B_MIN=1;
    #20 B_MIN=0;
end
initial 
    #300 $finish;
endmodule // testbench

仿真结果:

在这里插入图片描述经过验证,输出正确,满足设计要求。

  • 17
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值