2024年寒假练 - 基于小脚丫FPGA套件STEP BaseBoard V4.0 实现两位十进制加、减、乘、除计算器
该项目使用了WebIDE平台以及小脚丫FPGA套件STEP BaseBoard V4.0,实现了两位十进制加、减、乘、除计算器的设计,它的主要功能为:通过读取矩阵键盘的得到操作数和运算符,实现两位十进制加、减、乘、除计算。。
标签
FPGA
计算器
参加活动/培训
WebIDE
Remo
更新2024-03-29
电子科技大学
227

电子森林2024寒假一起练项目报告

两位十进制加、减、乘、除计算器

一、项目需求

实现一个两位十进制数加、减、乘、除运算的计算器,运算数和运算符(加、减、乘、除)由4×4矩阵键盘来控制。其中每个运算数使用两个数码管显示,左侧显示十位数,右侧显示个位数。输入两位十进制数时,最高位先在右侧显示,然后其跳变到左侧的数码管上,低位在刚才高位占据的数码管上显示。


二、需求分析

本项目需要实现两位十进制数的加、减、乘、除运算,以4×4矩阵键盘作为输入,数码管作为显示输出。矩阵键盘的按键值读取通过行扫描的方式实现,四则运算中的加、减、乘可以通过’+’、’-‘、‘*’运算符对读取到的两个运算数进行运算,只有除法部分需要单独编写一个除法模块实现除法运算。对于两位十进制数的显示,可以通过对运算数移位后再赋值的方式实现,即定义一个8位信号用于读取按键值,每次按下数字键后,先将该信号左移4位,再对低4位进行赋值,即可实现右侧显示个位、左侧显示十位的效果。


三、实现方式

首先对该设计进行模块划分,根据设计需求初步划分为:①矩阵键盘驱动模块、②按键消抖模块、③状态转换模块、④输入运算数寄存模块、⑤除法模块、⑥四则运算模块、⑦根据当前状态和运算数得出显示数据的模块、⑧二进制码转BCD码模块、⑨hc595驱动模块、⑩数码管动态显示模块。最后用顶层模块将各模块连接起来。

其中①、②、⑧、⑨、⑩属于常用模块,这里不做过多讲解。

③状态转换模块:对处理过程中的不同状态进行划分,并根据按键输入进行状态跳转。比如读取第一个运算数时是一个状态,读取第二个运算数时是一个状态,如果输入第二个操作数之后按下’=’按键,则进入运算结果显示状态,如果输入第二个操作数之后再次按下’+’、’-’、’*’、‘/’按键,则先计算出当前两个操作数的运算结果赋值给操作数1,然后再重新进入读取操作数2的状态,若输入操作数2后仍按下运算符按键则重复上述过程,直至按下‘=’输出最终运算结果。

④输入运算数寄存模块:根据按键输入和当前状态,分别对操作数1、操作数2和运算符寄存器进行赋值并将其输出到后续模块进行处理。

⑤除法模块:采用‘恢复余数法’进行除法运算,以生成可综合的除法运算电路。该方法采用移位后比较大小的方式进行商0或商1,总共移位除数位宽次数后得到操作数1/操作数2向下取整的除法运算结果。

⑥四则运算模块:根据当前状态值、操作数1、操作数2以及运算符寄存值,在适当的状态时计算出当前运算结果的数值,其中减法运算部分还要对操作数大小进行比较以确定是否需要生成负号标志位。

⑦根据当前状态和运算数得出显示数据的模块:该模块根据当前状态、操作数值等参数确定最终输出给数码管的显示数值。首先将输入的二进制码操作数和运算结果值通过模块⑧转换为BCD码形式,然后根据状态值和负号标志位是否有效来确定输出给数码管的32位bcd码,其中4’he用作显示负号,4’hf用作隐去目前没用到的数码管。


四、功能框图

完整RTL结构图如下图所示,左侧不完整部分均为按键消抖模块例化,图中保留三个作为示意。


五、代码及说明

这里只给出部分关键代码块及其说明,完整代码见后续附件部分。

always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        operand1<=8'd0;
    else if(state==S1 && key_operation)
        operand1<=8'd0;
    else if(state==S1 || state==S6)
    begin
        case(key_value)
            10'b10_0000_0000:begin operand1<={operand1[3:0] , 4'd9};  end
            10'b01_0000_0000:begin operand1<={operand1[3:0] , 4'd8};  end
            10'b00_1000_0000:begin operand1<={operand1[3:0] , 4'd7};  end
            10'b00_0100_0000:begin operand1<={operand1[3:0] , 4'd6};  end
            10'b00_0010_0000:begin operand1<={operand1[3:0] , 4'd5};  end
            10'b00_0001_0000:begin operand1<={operand1[3:0] , 4'd4};  end
            10'b00_0000_1000:begin operand1<={operand1[3:0] , 4'd3};  end
            10'b00_0000_0100:begin operand1<={operand1[3:0] , 4'd2};  end
            10'b00_0000_0010:begin operand1<={operand1[3:0] , 4'd1};  end
            10'b00_0000_0001:begin operand1<={operand1[3:0] , 4'd0};  end
            default:operand1<=operand1;
        endcase
    end
end

上述代码块主要用于实现,输入十位数字时,该数字显示在右侧数码管,接着输入个位数字后,十位数字跳转到左侧数码管,个位数字显示在右侧数码管。该功能主要通过先移位后赋值的方式实现,定义一个8位的变量,每4位代表一个数字,每次读取按键并赋值之前先将该变量左移4位,再对其低4位进行赋值,以实现上述功能。

always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        result<='d0;
        negative_flag<=1'b0;
    end
    else if(state==S1)
    begin
        result<='d0;
        negative_flag<=1'b0;
    end
    else if(state==S3||state==S4)
    begin
        case(operation_d1)
            2'd0:
            begin
                if(negative_flag)
                    begin
                        if(i_operand1>i_operand2)
                        begin
                            result <= i_operand1 - i_operand2;
                            negative_flag<=1'b1;
                        end
                        else
                        begin
                            result <= i_operand2 - i_operand1;
                            negative_flag<=1'b0;
                        end
                    end
                else
                    begin
                        result <= i_operand1 + i_operand2;
                        negative_flag<=1'b0;
                    end
            end
            2'd1:
            begin
                if(negative_flag)
                    begin
                        result <= i_operand1 + i_operand2;
                        negative_flag<=1'b1;
                    end
                else
                    begin
                        if(i_operand1<i_operand2)
                        begin
                            result <= i_operand2 - i_operand1;
                            negative_flag<=1'b1;
                        end
                        else
                        begin
                            result <= i_operand1 - i_operand2;
                            negative_flag<=1'b0;
                        end
                    end
            end
            2'd2:
            begin
                result <= i_operand1 * i_operand2;
                negative_flag <= negative_flag;
            end
            2'd3:
            begin
                result <= yshang;
                negative_flag <= negative_flag;
            end
            default:result <= result;
        endcase
    end
end

上述代码块用于实现计算功能,其中operation_d1的2'd0为加法、2'd1为减法、2'd2为乘法、2'd3为除法。可以看到,该设计中考虑了负数参与运算的情况,同时加减乘三种运算均通过运算符实现,只有除法运算有专门的除法模块。

module div(
    input   wire                 sys_clk,
    input   wire                 rst_n  ,
    input   wire [26:0]              A,
    input   wire [26:0]              B,
    input   wire                ready,
   
    output  reg  [26:0]          shang,
    output  reg  [26:0]          yushu,
    output  reg                    valid
   
   
    );
 
reg work_flag;
reg [26:0] yushu_qian;
reg [53:0] chushu;
reg [4:0] cnt;
reg [26:0]  shang_qian;
 
always@(posedge sys_clk,negedge rst_n)
    if(!rst_n)
        work_flag <= 1'd0;
    else    if(cnt == 'd27)
        work_flag <= 1'd0;
    else    if(ready == 1'd1)
        work_flag <= 1'd1;
 
always@(posedge sys_clk,negedge rst_n)
    if(!rst_n)
        yushu_qian <= 27'd0;
    else    if(work_flag == 1'd0)
        yushu_qian <= A;
    else    if(work_flag == 1'd1)
        begin
            if(yushu_qian >= chushu)
                yushu_qian <= yushu_qian - chushu;
            else    
                yushu_qian <= yushu_qian;
        end        
       
 
always@(posedge sys_clk,negedge rst_n)
    if(!rst_n)
        chushu <= 54'd0;
    else    if(work_flag == 1'd0)
        chushu <= {B,27'd0};
    else    if(work_flag == 1'd1)
        chushu <= chushu>>1;
 
always@(posedge sys_clk,negedge rst_n)
    if(!rst_n)
        cnt <= 'd0;
    else    if(work_flag == 1'd0)
        cnt <= 'd0;
    else
        cnt <= cnt + 'd1;
 
always@(posedge sys_clk,negedge rst_n)
    if(!rst_n)
        shang_qian <= 27'd0;
    else    if(work_flag == 1'd0)
        shang_qian <= 27'd0;
    else    if(work_flag == 1'd1)
        begin
            if(yushu_qian >= chushu)
                shang_qian[27-cnt] <= 1'd1;
            else    
                shang_qian[27-cnt] <= 1'd0;
        end        
       
always@(posedge sys_clk,negedge rst_n)
    if(!rst_n)
        shang <= 28'd0;
    else    if(cnt == 'd28)
        shang = shang_qian;    
 
always@(posedge sys_clk,negedge rst_n)
    if(!rst_n)
        yushu <= 28'd0;
    else    if(cnt == 'd28)
        yushu <= yushu_qian[26:0];    
 
always@(posedge sys_clk,negedge rst_n)
    if(!rst_n)
        valid <= 'd0;
    else    if(cnt == 'd28)
        valid <= 'd1;
    else
        valid <= 'd0;
       
endmodule

以上为除法运算模块,采用‘恢复余数法’进行除法运算,以生成可综合的除法运算电路。该方法采用移位后比较大小的方式进行商0或商1,总共移位除数位宽次数后得到操作数1/操作数2向下取整的除法运算结果


六、仿真波形图

这里采用modelsim进行仿真测试,各模块完整testbench见后续附件。

③state_transfer_tb:

image.png

image.png

④data_read_tb:该模块需要state_transfer模块的输出信号state作为输入,所以在testbench中将例化这两个模块一起进行仿真测试;

image.png

⑤div_tb:该除法模块输出为商数和余数,这里只用到商数,即除法运算结果向下取整。

image.png

⑥calculate_tb:由于该模块的输入需要用到前面的输出,于是将③④⑤⑥全部例化进行仿真。

image.png

⑦data_to_disp_tb:根据当前state,将二进制操作数转为bcd码并在合适的时机赋值给data_disp信号以便于传递给数码管进行显示,其中4’he用于显示负号,4’hf用于隐去未使用的数码管。

image.png

image.png


七、FPGA资源利用情况

在WebIDE中的run.log日志文件中可以得到资源利用说明:

可以看出该设计使用了大约一半的LUT资源和20%的寄存器资源,其中大部分资源消耗在除法运算和二进制码转bcd码部分。

image.png


八、演示视频

演示视频上传至以下bilibili平台链接:

【电子森林2024年寒假在家一起练,平台二任务一】 https://www.bilibili.com/video/BV1wx421179K/?share_source=copy_web&vd_source=c6992e78df10d9d4074e9b13c476b65c

image.png

image.png






附件下载
rtl_code.rar
该项目的设计源文件
testbench.rar
上述仿真波形部分所使用的testbench源文件
jed_file.rar
jed格式输出文件
团队介绍
本人成电大四微电子专业
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号