当前位置:   article > 正文

基于FPGA的电子计算器设计(下)_设计一个基于 fpga 的简单运算器,使之能提供以下功能1.完成-7到+7的简单的加、减

设计一个基于 fpga 的简单运算器,使之能提供以下功能1.完成-7到+7的简单的加、减

今天给大侠带来基于FPGA的电子计算器设计,由于篇幅较长,分三篇。今天带来第三篇,下篇,话不多说,上货。

 

 

 

 

 

导读 

 

 

本篇介绍了一个简单计算器的设计,基于 FPGA 硬件描述语言 Verilog HDL,系统设计由计算部分、显示部分和输入部分四个部分组成,计算以及存储主要用状态机来实现。显示部分由六个七段译码管组成,分别来显示输入数字,输入部分采用4*4矩阵键盘,由0-9一共十个数字按键,加减乘除四个运算符按键,一个等号按键组成的。通过外部的按键可以完成加、减、乘、除四种功能运算,其结构简单,易于实现。本篇为本人毕业设计部分整理,各位大侠可依据自己的需要进行阅读,参考学习。

第三篇内容摘要:仿真测试验证部分以及结论,包括ModelSim简介、模块仿真验证分析、矩阵按键模块、计算仿真举例等相关内容。

 

六、仿真验证设计

 

6.1  ModelSim简介

在仿真设计时,用到了Mentor公司的Modelsim,这是一款硬件描述语言仿真软件,该款软件不单单能提供十分友好的仿真环境,而且它也是我们业界第一个也是仅此一个的单内核支持VHDL和Verilog语言混合仿真的软件。它采用直接优化的编译技术、Tcl/Tk技术、和单一内核仿真技术,从而达到令人编译仿真速度快的效果,而且编译代码和整个平台没有关系,这样就更容易保护IP核,它是FPGA/ASIC设计的首选仿真软件。

Modelsim有不同版本,例如:SE、PE、LE和OEM,其中最高级的版本是SE,而集成在 Actel、Atmel以及Lattice等FPGA厂商设计工具中的都是其OEM版本。

Modelsim SE支持PC、UNIX和LINUX的混合平台;能给出十分全面到位以及高性能的验证功能;全面支持业界设定的广泛标准;同时Mentor Graphics公司提供了整个行业最出色的技术支持与服务。

Modelsim的主要特点有:

1)支持单内核的VHDL和Verilog混合在一起进行仿真处理;

2)具有源代码模版、助手以及项目管理功能;

3)汇聚了性能考核、波形参考、代码覆盖、数据流Chase X、Signal Spy、虚拟对象Virtual Object、Assertion窗口、Memory窗口、源码窗口显示信号值、信号条件断点等众多调试功能;

4)C和Tcl/Tk接口,C调试;

5)能够实现对System C的直接支持功能,同时可以和HDL任意混合使用;

6)能够实现System Verilog的设计功能;

7)可以做到对系统级描述语言进行最全面的支持;

8)可以单独或同时进行行为(behavioral)、RTL级、和门级(gate-level)的代码。

9)能够实现RTL和门级优化,编译仿真速率非常快,跨平台跨版本的仿真。

 

 

6.2  模块仿真验证分析

FPGA设计流程包括设计输入,仿真,综合,生成,板级验证等很多阶段。在整个设计流程中,完成设计输入并成功进行编译仅仅能说明设计符合一定的语法规范,并不能说明设计功能的正确性,这时,我们就需要通过仿真对设计进行验证。我们主要进行的是功能仿真,又叫逻辑仿真,是指在不考虑器件延时和布线延时的理想情况下对源代码进行逻辑功能验证;而时序仿真是在布局布线后进行。我们仿真是为了保证设计的正确性。

 

6.2.1  矩阵按键模块

矩阵键盘测试程序流程框图如下:

图6-1 按键测试程序流程图

Figure 6-1 key testing program flow chart

 

首先,我们要先进行按键检测,判断是否有按键闭合,如果没有说明没有按键键入,那么返回就是我们常说的消抖,重新进行按键检测,直到有按键闭合。接下来会有10ms的延迟,保存键值;再继续判断按键是否松开,如果是则又会产生10ms的延迟,否则返回判断直到按键有松开为止,最后返回键值。

我们需要编译一个模拟键盘定义data0-15,然后模拟输入给FPGA一个行信号,FPGA接收行信号,同时输出给模拟键盘一个列信号,如果输出的列信号不存在低电平,那么行信号为4‘b1111,代表输入的按键不在本列上,继续扫描下一列直到找到相应的行信号为止。部分代码如图所示。

图6-2 键盘扫描部分代码

Figure 6-2 keyboard scan code

 

图6-3为键盘扫描仿真图,当我们按下1时,数据显示1,按下10显示10,按下2显示的是2,按下15显示15,仿真结果有效,程序编译正确。

 

图6-3 键盘扫描仿真

Figure 6-3 keyboard scanning simulation

 

6.2.2  计算仿真举例

加法计算举例,首先pnumber输入1,data_in输入也为1,扫描结果为1;然后输入10;pnumber输入为2,data_in输入为2,扫描结果为2;最后按键“=”,显示结果即为3。仿真显示结果正确,说明我们的编译代码没有问题,计算有效,计算器结果可信。

 

图6-4 1+2=3程序仿真图

Figure 6-4 1+2=3 process simulation diagram

 

七、结论

 

 

本次电子计算器的设计是基于FPGA设计的,计算器基本上可以实现的加减乘除的功能。系统的计算部分、存储部分、显示部分和输入部分四个部分都可以完成设计要求,输入部分采用键盘矩阵原理,存储部分用状态机来实现,并进行了仿真。实现了防消抖的要求,计算结果较精确。达到了预期的要求目标。

 

附录:设计主体源代码

 

 

二进制转BCD代码:

module bin2bcd_12bit(bin, bcd);  input [19:0] bin;  output reg [23:0] bcd;    always @ (*)    begin      bcd[3:0] = bin%10;      bcd[7:4] = bin/10%10;      bcd[11:8] = bin/100%10;      bcd [15:12] = bin/1000%10;      bcd[19:16] = bin/10000%10;      bcd[23:20] = bin/100000%10;    endendmodule

 

计算模块代码:

module calculator (clk, rst_n, flag, key_data, bin_data);  input clk;  input rst_n;  input flag;  input [3:0] key_data;    output reg [19:0] bin_data;  reg [1:0] state;  reg [19:0] num1;  reg [3:0] opcode;    always @ (posedge clk or negedge rst_n)    begin      if (!rst_n)        begin          state <= 0;          num1 <= 0;          bin_data <= 0;          opcode <= 0;        end      else        begin          case (state)            0 : begin                if (flag)                  begin                    if (key_data < 10)                      begin                        bin_data <= bin_data * 10 + key_data;                      end                    else                      begin                        if (key_data == 14)                          begin                            state <= 0;                          end                        else                          begin                            opcode <= key_data;                            state <= 1;                            num1 <= bin_data;                            bin_data <= 0;                          end                      end                  end                else                  begin                    state <= 0;                  end              end                        1 : begin                if (flag)                  begin                    if (key_data < 10)                      begin                        bin_data <= bin_data * 10 + key_data;                      end                    else                      begin                        if (key_data == 14)                          begin                            case (opcode)                              10 :  begin bin_data <= num1 + bin_data; state <= 2; end                              11 :  begin bin_data <= num1 - bin_data; state <= 2; end                              12 :  begin bin_data <= num1 * bin_data; state <= 2; end                              13 :   begin bin_data <= num1 / bin_data; state <= 2; end                              default : bin_data <= 0;                            endcase                           end                        else                          begin                            state <= 1;                          end                      end                  end                else                  begin                    state <= 1;                  end              end                      2 : begin                if (flag)                  begin                    if (key_data < 10)                      begin                        bin_data <= {16'd0,key_data};                        state <= 0;                      end                    else                      begin                        if (key_data == 14)                          begin                            state <= 2;                          end                        else                          begin                            num1 <= bin_data;                            opcode <= key_data;                            bin_data <= 0;                            state <=1;                          end                      end                  end                else                  begin                    state <= 2;                  end              end          endcase        end    endendmodule

 

输入部分代码:

module key_board (clk, rst_n, row, col, data, valid, clk_1k);  input clk;  input rst_n;  input [3:0] row;    output reg [3:0] col;  output reg [3:0] data;  output reg valid;  output reg clk_1k;  reg [14:0] cnt;    parameter T1ms = 24999;    always @ (posedge clk or negedge rst_n)    begin      if (!rst_n)        begin          clk_1k <= 1'b1;          cnt <= 15'd0;        end      else        begin          if (cnt < T1ms)            begin              cnt <= cnt + 15'd1;            end          else            begin              cnt <= 15'd0;              clk_1k <= ~clk_1k;            end        end      end  reg [7:0] row_col;  reg [1:0] state;  reg [4:0] count;    always @ (posedge clk_1k or negedge rst_n)    begin      if (!rst_n)        begin          col <= 4'b0000;          row_col <= 8'd0;          state <= 0;          valid <= 0;          count <= 0;        end      else        begin          case (state)            0 : begin                if (row == 4'b1111)                  begin                    col <= 4'b0000;                  end                else                  begin                    state <= 1;                  end              end                        1 : begin                if (row == 4'b1111)                  begin                    state <= 0;                    count <= 0;                  end                else                  begin                    if (count < 19)                      begin                        count <= count + 1;                      end                    else                      begin                        count <= 0;                        state <= 2;                        col <= 4'b0111;                      end                  end                end                          2 : begin                if (row == 4'b1111)                  begin                    col <= {col[2:0],col[3]};                    state <= 2;                  end                else                  begin                    row_col <= {row,col};                    state <= 3;                    valid <= 1;                  end              end                          3 : begin                if (row == 4'b1111)                  begin                    state <= 0;                    valid <= 0;                  end                else                  begin                    valid <= 0;                    state <= 3;                  end              end                                      default : state <= 0;                      endcase        end    end    always @ (*)    begin      case (row_col)        8'b0111_0111 : data = 4'hf;        8'b0111_1011 : data = 4'he;        8'b0111_1101 : data = 4'hd;        8'b0111_1110 : data = 4'hc;                8'b1011_0111 : data = 4'hb;        8'b1011_1011 : data = 4'ha;        8'b1011_1101 : data = 4'h9;        8'b1011_1110 : data = 4'h8;                8'b1101_0111 : data = 4'h7;        8'b1101_1011 : data = 4'h6;        8'b1101_1101 : data = 4'h5;        8'b1101_1110 : data = 4'h4;                8'b1110_0111 : data = 4'h3;        8'b1110_1011 : data = 4'h2;        8'b1110_1101 : data = 4'h1;        8'b1110_1110 : data = 4'h0;                default : data = 4'h0;      endcase    endendmodule

 

数码管顶层代码:

module seven_seg (clk, rst_n, data_in, sel, seg);  input clk;  input rst_n;  input [23:0] data_in;    output [2:0] sel;  output [7:0] seg;  wire clk_1k;    freq freq_dut(      .clk(clk),       .rst_n(rst_n),      .clk_1k(clk_1k)    );  sel_seg_encode sel_seg_encode_dut(      .clk(clk_1k),       .rst_n(rst_n),       .data_in(data_in),       .sel(sel),       .seg(seg)    );        endmodule

 

分频部分代码:

module freq (clk, rst_n, clk_1k);  input clk;  input rst_n;    output reg clk_1k;  reg [14:0] cnt;    always @ (posedge clk or negedge rst_n)    begin      if (!rst_n)        begin          clk_1k <= 1;          cnt <= 0;        end      else        begin          if (cnt < 24_999)            begin              cnt <= cnt + 1;            end          else            begin              cnt <= 0;              clk_1k <= ~clk_1k;            end        end    end    endmodule

 

位选段选连接代码:

module sel_seg_encode (clk, rst_n, data_in, sel, seg);    input clk;  input rst_n;  input [23:0] data_in;    output [2:0] sel;  output [7:0] seg;  wire [3:0] num;    seg_encode seg_encode_dut(        .rst_n(rst_n),        .num(num),        .seg(seg)      );    sel_encode sel_encode_dut(        .clk(clk),        .rst_n(rst_n),        .data_in(data_in),        .num(num),        .sel(sel)      );endmodule

 

 

段选部分代码:

module seg_encode (rst_n, num, seg);  input rst_n;  input [3:0] num;    output reg [7:0] seg;  always @ (*)    begin      if (!rst_n)        begin          seg = 8'b0000_0000;        end      else        begin          case (num)            0 : seg = 8'b1100_0000;            1 : seg = 8'b1111_1001;            2 : seg = 8'b1010_0100;            3 : seg = 8'b1011_0000;            4 : seg = 8'b1001_1001;            5 : seg = 8'b1001_0010;            6 : seg = 8'b1000_0010;            7 : seg = 8'b1111_1000;            8 : seg = 8'b1000_0000;            9 : seg = 8'b1001_0000;            default : seg = 8'b0000_0000;          endcase        end    endendmodule

 

位选部分代码:

module sel_encode (clk, rst_n, data_in, num, sel);  input clk;  input rst_n;  input [23:0] data_in;    output reg [3:0] num;  output reg [2:0] sel;  always @ (posedge clk or negedge rst_n)    begin      if (!rst_n)        begin          sel <= 0;        end      else        begin          if (sel < 5)            begin              sel <= sel + 1;            end          else            begin              sel <= 0;            end        end    end  always @ (*)    begin      if (!rst_n)        begin          num = 0;        end      else        begin          case (sel)            0 : num = data_in[23:20];            1 : num = data_in[19:16];            2 : num = data_in[15:12];            3 : num = data_in[11:8];            4 : num = data_in[7:4];            5 : num = data_in[3:0];            default : num = 0;          endcase        end    endendmodule

 

 

 

本篇到此结束,各位大侠,有缘再见!

 

 

END

 

后续会持续更新,带来Vivado、 ISE、Quartus II 、candence等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。

大侠们,江湖偌大,继续闯荡,愿一切安好,有缘再见!

 

 

 

 

 

精彩推荐

 

 

 

 

直接扩频通信(下)仿真

Signal tap 逻辑分析仪使用教程

基于FPGA的实时图像边缘检测系统设计(下)

“FPGA产品设计与研发 ” 零基础入门及就业

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/秋刀鱼在做梦/article/detail/762402
推荐阅读
相关标签
  

闽ICP备14008679号