• 实验目的
  1. 实现74LS283全加器IP核的编写。
  2. 实现四位二进制加法器的功能。
  3. 实现四位二进制减法器的功能。
  4. 实现四位二进制乘法器的功能。
  5. 将二进制数转换为BCD码。
  6. 将BCD码通过7段数码管进行显示。
  • 各模块原理及功能
  1. Adder模块

原理:采用矢量拼接并赋值的算法,获得两个二进制数之和。

功能:实现两个四位二进制数输入[3:0]A, [3:0]B,一个8位二进制输出两者之和[7:0]sum。

  1. Multiplier 模块

原理:将[3:0]A作为被乘数,[3:0]B作为乘数,采用4次循环的方式,每次循环对A进行向左的移位,若B的右边第i位为1则将其加到中间结果中去,循环结束,中间结果即为最终结果。

功能:实现两个四位二进制数输入[3:0]A, [3:0]B,一个8位二进制输出两者之积[7:0]product。

  1. Subtraction模块

原理:采用书本P105利用全加器实现全减器的原理。对减数取反再加1作为补码,将被减数和减数的补码相加,得到5位二进制数,当第一位为1表示结果为正,后四位为运算的结果,当第一位为0表示结果为负,若为负数则需要变换为补码才是结果。

功能:实现两个四位二进制数输入[3:0]A, [3:0]B,一个8位二进制输出两者之差[7:0]sub,输出一位二进制数代表结果正负p_or_n(1代表正数0代表负数)。

  1. Transferbcd模块

原理:采用移位加三的算法,实现的过程:(1)把二进制数左移一位(2)如果共移了8位,那么BCD码就在百位、十位和个位列,转换完成(3)如果再BCD列中,任何一个二进制数是5或比5更大,那么就再BCD列的数值加三(4)返回步骤1。实例如下图所示。

操作

百位

十位

个位

二进制数

十六进制数

F

F

开始

1111

1111

左移1

1

1111

111

左移2

11

1111

11

左移3

111

1111

1

加3

1010

1111

1

左移4

1

0101

1111

加3

1

1000

1111

左移5

11

0001

111

左移6

110

0011

11

加3

1001

0011

11

左移7

1

0010

0111

1

加3

1

0010

1010

1

左移8

10

0101

0101

BCD码

2

5

5

功能:实现8位二进制数输入,10位BCD码[9:0]p输出

  1. hex7seg模块

原理:对于每一片数码管都是共阴极的,因此是低电平有效,需要对其进行动态扫描。由于公用一个段码,因此一个时刻只能显示一片。

功能:输入选择显示的结果(加减乘中间的一位),输入100M时钟信号,以及加减乘的运算结果(都已经在主函数中调用完成产生了结果),输出七段数码管的片选[3:0]an,以及段选[6:0]a_to_g。

  1. calculate主模块

原理:调用前面的函数完成计算器的功能。

功能:输入自带的时钟信号,输入数据选择的向量[2:0]choice,输入两个四位二进制数[3:0]A、[3:0]B,输出四片七段数码管的片选以及段选,还有减法时的正负符号p_or_n。

  • 实现过程以及代码
  1. 创建全加器IP核

为更好的实现代码复用,因此建立74LS283的IP核,IP核代码如下:

module adder(

input [3:0] A,

input [3:0] B,

input C0,

output [3:0] S,

output C4

);

assign {C4, S}={1'b0, A}+{1'b0, B}+C0;

endmodule

其中C0为来自上一位的进位,C4为对下一位的进位,采用了拼接的方式实现S以及C4的赋值。

并通过仿真程序对74LS283进行验证。

module adder_sim;

reg [3:0] A;

reg [3:0] B;

reg C0;

wire [3:0] S;

wire C4;

adder u1(A, B, C0, S, C4);

initial                     //从仿真开始时刻开始执行下面语句

begin

A=4'b0;

B=4'b0;

C0=0;

#100;

A=4'b0001; B=4'b0000; C0=0;

#100;

A=4'b0011; B=4'b0011; C0=0;

#100;

A=4'b1111; B=4'b1111; C0=1;

#100;

A=4'b1100; B=4'b0011; C0=1;

#100;

A=4'b0000; B=4'b0000; C0=0;

end

endmodule

并创建IP核所示。

  1. 创建加法模块

欲通过IP核的调用实现全加器,由于单纯实现四位二进制数的加法直接实现的代码长度较于调用74LS283而言更短,因此采用直接实现的方式。代码如下。

module adder(

input wire [3:0]A,

input wire [3:0]B,

output wire [7:0]sum

);

wire C4;

wire [3:0]S;

assign {C4, S}={1'b0, A}+{1'b0, B}; //采用拼接再赋值的方式确定和以及进位

assign sum = {3'b000,C4, S}; //将进位作为第五位二进制数拼接成8位二进制数

endmodule

由于中间变量不需要通过条件语句更改值,因此只需要作为网表类型即可,最后由于用不到进位,也没有来自上一位的进位,因此不需要加上C0。由于要求输出的位数满足计算器的最多位数的要求,因此输出为8位二进制数。

  1. 创建减法模块

采用补码的运算实现减法,具体实现代码如下。

module subtraction(

input wire [3:0]A,

input wire [3:0]B,

output reg [7:0]sub,

output reg p_or_n      //正负 1为正0为负

);

reg C4;                //因为要采用if语句对其进行更改因此定义为reg

reg C0;

reg [3:0]S;

reg [4:0]q;

always@(*)

begin

C0=1;

q={1'b0, A}+{1'b0, ~B}+1;   //被减数与补码的和(补码为反码加一)

C4=q[4];                //最高位(代表结果的符号)

S=q[3:0];                //后四位

if (C4==1)               //最高位为1,表示结果为正,结果为后四位

begin

p_or_n = 1;

sub = {4'b0000,S};

end

if (C4==0)                  //最高位为0,结果为负,为后四位的补码

begin

p_or_n = 0;

sub = {4'b0000, !S[3],  !S[2], !S[1], !S[0]}+1;

end

end

endmodule

由于需要在条件语句中修改输出的值,因此将输出和中间变量定义位reg型,能在always中修改,在此时在通过p_or_n输出减法运算结果的正负情况,为正时输出1,为负时输出0。

并对减法模块进行仿真程序的编写,编写的仿真程序如下所示。

module subsim;

reg [3:0] A;

reg [3:0] B;

wire [7:0] sub;

wire p_or_n;

subtraction u1(.A(A),.B(B),.sub(sub),.p_or_n(p_or_n));

initial                     //从仿真开始时刻开始执行下面语句

begin

A=4'b0;

B=4'b0;

#100;

A=4'b0001; B=4'b0000;

#100;

A=4'b0011; B=4'b0011;

#100;

A=4'b1111; B=4'b1111;

#100;

A=4'b1000; B=4'b1100;

#100;

A=4'b0000; B=4'b0000;

end

endmodule

  1. 创建乘法模块

将A作为被乘数,每次向左移动一位,与此同时向左遍历B,若此时B为1,则将此时的A加入到中间结果中,遍历一边(即四次)之后则中间变量为最终的输出。其实例如下图所示。

最终实现的代码如下。

module multer(

input [3:0] A,

input [3:0] B,

output reg [7:0] product        //乘积

);

reg[7:0]pv;                     //每次相加产生的中间变量

reg[7:0]ap;                     //A的每次移位

integer i;

always@(*)

begin

pv=8'b00000000;

ap={4'b0000,A};             //被乘数

for(i=0;i<=3;i=i+1)

begin

if(B[i]==1)             //如果乘数是1则将此时的ap加到中间结果中

pv=pv+ap;

ap={ap[6:0],1'b0};      //左移1位

end

product=pv;      //结果,因为四位二进制数乘法最高为225,只要8位二进制就能完全表示

end

endmodule

由于也需要在always语句块中执行,因此也要定义成寄存器型。由于1111*1111为最大的结果225为8位。因此限定了其他函数运行结果的位数,以便后续转BCD码使用。

  1. 建立二进制数转BCD码模块

原理为移位加三算法,由于8位二进制数最多位255,因此需要的最多的BCD码位数位10位,因此输出为10为用二进制表示的10进制数。代码如下。

module transferbcd(

input wire [7:0] b,

output reg [9:0] p                            //10位二进制数一定够用了

);

reg [17:0] z;                                  // 中间变量

integer i;

always @ ( * )

begin

for (i = 0; i <=17; i = i + 1)

z[i] = 0;

z[10:3] = b;                             // 向左移3位

repeat (5)                              // 重复5次

begin

if (z[11:8] > 4)                     // 如果个位大于4

z[11:8] = z[11:8] +3;              // 加3

if (z[15:12] > 4)                    // 如果十位大于4

z[15:12] = z[15:12] +3;            // 加3

z[17:1] = z[16:0];                   // 左移一位

end

p = z[17:8];                    // BCD(用二进制表示的十进制数前四位表示个位......)

end

endmodule

先进行了初始化,令每一位都为0(for语句在这里没有end)。因为刚开始只有左移三位之后才有可能大于4,因此刚开始时都会左移三位。重复5次一共相当于左移了8位,将输入的二进制全部转换为BCD码了。最后输出位中间变量的左边10位。

  1. 创建七段数码管显示模块

代码如下所示。

module hex7seg(

inout wire [2:0]choice,

input wire clk_100M,

input wire clr,

input wire [15:0]x1,             //要显示的BCD(减法)

input wire [15:0]x2,             //(乘法结果)

input wire [15:0]x3,             //(加法结果)

output reg [6:0]a_to_g,          //段选

output reg [3:0]an               //片选

);

wire [1:0]s;

reg [15:0]x;

reg [3:0]digit;

reg [20:0]clkdiv;

always@(*)

begin

if (choice == 3'b001)           //按动减法按钮

x =x1[15:0];

else if (choice == 3'b010)      //按动乘法按钮

x=x2[15:0];

else if (choice == 3'b100)      //按动加法按钮

x=x3[15:0];

else

x=16'b0;                     //不按动或者其他情况

end

always @(posedge clk_100M or posedge clr)  //相当于一个分频

begin

if(clr==1)                                    //清零只是刷新频率为0

clkdiv<=0;

else

clkdiv<=clkdiv+1;              //时钟上升沿加一非阻塞赋值,直接赋值不需要等待)

end

assign s=clkdiv[20:19];                       //只取20 19两位

always@(*)

begin

an=4'b0000;  //位选,显示那个数码管

an[s]=1;      //因为clkdiv只有00 01 10 11四位,因此是四个数码管轮流显示

end

always @(*)

case(s)

0:digit=x[3:0];         //显示第一个数码管(最右边)

1:digit=x[7:4];         //显示第二个数码管

2:digit=x[11:8];        //显示第三个数码管

3:digit=x[15:12];       //显示第四个数码管

default:;

endcase

always@(*)

case(digit)

0:a_to_g=7'b1111110;        //每个数字的显示

1:a_to_g=7'b0110000;

2:a_to_g=7'b1101101;

3:a_to_g=7'b1111001;

4:a_to_g=7'b0110011;

5:a_to_g=7'b1011011;

6:a_to_g=7'b1011111;

7:a_to_g=7'b1110000;

8:a_to_g=7'b1111111;

9:a_to_g=7'b1111011;

'hA:a_to_g=7'b1110111;

'hB:a_to_g=7'b0011111;

'hC:a_to_g=7'b1001110;

'hD:a_to_g=7'b0111101;

'hE:a_to_g=7'b1001111;

'hF:a_to_g=7'b1000111;

default:;

endcase

endmodule

将每个模块的输出值作为此模块的输入,最后通过控制信号choice实现对于输出结果的显示。并采用分频电路实现数码管的动态扫描,其中分频电路采用自带时钟信号出发的计数电路,并且分频之后的信号为计数电路的最高两位信号,实现了2位二进制的定周期循环。并用分频之后的2位二进制(00, 01, 10, 11)的循环控制四段数码管的显示。

  1. 建立顶层模块

顶层模块通过调用加减乘法子模块,并采用BCD转换和数码管显示模块实现。代码如下所示,

module calculate(

input wire clk,

input wire clr,

input wire [2:0]choice,

input wire [3:0]A,

input wire [3:0]B,

output wire [6:0]a_to_g,  //段选

output wire [3:0]an,  //片选

output wire p_or_n

);

wire [15:0]x1;

wire [15:0]x2;

wire [15:0]x3;

wire [9:0]p1;

wire [9:0]p2;

wire [9:0]p3;

wire [7:0] mid1;

wire [7:0] mid2;

wire [7:0] mid3;

assign x3={6'b000000,p3};

assign x2={6'b000000,p2};

assign x1={6'b000000,p1};                                      //都是并行的除非有begin end

subtraction mux_zero(.A(A),.B(B),.sub(mid1),.p_or_n(p_or_n));   //1代表减法

multer mux_first(.A(A),.B(B),.product(mid2));                   //2代表乘法

adder mux_two(.A(A),.B(B),.sum(mid3));                          //3代表加法

transferbcd mux_three1(.b(mid1),.p(p1));

transferbcd mux_three2(.b(mid2),.p(p2));

transferbcd mux_three3(.b(mid3),.p(p3));

hex7seg mux_four (.choice(choice),.clk_100M(clk),.clr(clr),.x1(x1),.x2(x2),.x3(x3),.a_to_g(a_to_g),.an(an));

endmodule

采用了分别调用计算模块,并将计算结果都作为输入,并通过按键进行选择输出的结果。

  1. 编写管教约束文件

整体代码如下图所示。

set_property -dict {PACKAGE_PIN P5 IOSTANDARD LVCMOS33} [get_ports {A[3]}]

set_property -dict {PACKAGE_PIN P4 IOSTANDARD LVCMOS33} [get_ports {A[2]}]

set_property -dict {PACKAGE_PIN P3 IOSTANDARD LVCMOS33} [get_ports {A[1]}]

set_property -dict {PACKAGE_PIN P2 IOSTANDARD LVCMOS33} [get_ports {A[0]}]

set_property -dict {PACKAGE_PIN R2 IOSTANDARD LVCMOS33} [get_ports {B[3]}]

set_property -dict {PACKAGE_PIN M4 IOSTANDARD LVCMOS33} [get_ports {B[2]}]

set_property -dict {PACKAGE_PIN N4 IOSTANDARD LVCMOS33} [get_ports {B[1]}]

set_property -dict {PACKAGE_PIN R1 IOSTANDARD LVCMOS33} [get_ports {B[0]}]

set_property -dict {PACKAGE_PIN P17 IOSTANDARD LVCMOS33} [get_ports {clk}]

set_property -dict {PACKAGE_PIN R15 IOSTANDARD LVCMOS33} [get_ports {clr}]

set_property -dict {PACKAGE_PIN U4 IOSTANDARD LVCMOS33}  [get_ports {choice[2]}]

set_property -dict {PACKAGE_PIN R11 IOSTANDARD LVCMOS33} [get_ports {choice[0]}]

set_property -dict {PACKAGE_PIN R17 IOSTANDARD LVCMOS33} [get_ports {choice[1]}]

set_property -dict {PACKAGE_PIN F6 IOSTANDARD LVCMOS33} [get_ports {p_or_n}]

set_property -dict {PACKAGE_PIN G1 IOSTANDARD LVCMOS33} [get_ports {an[3]}]

set_property -dict {PACKAGE_PIN F1 IOSTANDARD LVCMOS33} [get_ports {an[2]}]

set_property -dict {PACKAGE_PIN E1 IOSTANDARD LVCMOS33} [get_ports {an[1]}]

set_property -dict {PACKAGE_PIN G6 IOSTANDARD LVCMOS33} [get_ports {an[0]}]

set_property -dict {PACKAGE_PIN D4 IOSTANDARD LVCMOS33} [get_ports {a_to_g[6]}]

set_property -dict {PACKAGE_PIN E3 IOSTANDARD LVCMOS33} [get_ports {a_to_g[5]}]

set_property -dict {PACKAGE_PIN D3 IOSTANDARD LVCMOS33} [get_ports {a_to_g[4]}]

set_property -dict {PACKAGE_PIN F4 IOSTANDARD LVCMOS33} [get_ports {a_to_g[3]}]

set_property -dict {PACKAGE_PIN F3 IOSTANDARD LVCMOS33} [get_ports {a_to_g[2]}]

set_property -dict {PACKAGE_PIN E2 IOSTANDARD LVCMOS33} [get_ports {a_to_g[1]}]

set_property -dict {PACKAGE_PIN D2 IOSTANDARD LVCMOS33} [get_ports {a_to_g[0]}]

其中正负号通过F6 LED灯进行显示,量代表减法结果为正,灭代表减法结果为负。输入A、B通过8位拨码开关实现输入。

  • 结论与总结

在对不同情况赋不同的值的情况下,需要对除去直接赋值的语句外还需要对情况之外的可能进行赋值,使系统更加稳定。在实验过程中对于不同的choice而言要输出不同的结果,在除去其中有一个为1 的情况下还可能有多个1或者没有1的情况,一次代码要如下所示。

always@(*)

begin

if (choice == 3'b001)           //按动减法按钮

x =x1[15:0];

else if (choice == 3'b010)      //按动乘法按钮

x=x2[15:0];

else if (choice == 3'b100)      //按动加法按钮

x=x3[15:0];

else

x=16'b0;                     //不按动或者其他情况

end

要加一个else不然出现不同的结果,因此在同时按动两个以上按钮的时候不会出现错误结果。

对于一个矢量进行取反,既可以通过 ~B直接各位取反,也可以通过!S[3],  !S[2],  !S[1],  !S[0]的形式进行取反。

  • 程序的不足
  1. 没有想到除法如何显示如何计算,因此计算器的最简单的功能加减乘除只实现了前三者。
  2. 减法的符号显示较为笨拙,如果需要在数码管中显示符号需要对另一半的数码管进行扫描,不太好显示以及程序编写。
  3. 计算器的出发方式较为机械,需要一直按在按键上才会显示,因为在输出时如果需要用上升沿和下降沿触发的话,数码管显示模块的代码将会存在更多的重复,因此在实现中采用折衷的方式,降低代码复杂度。

verilog语言实现简易二进制计算器相关推荐

  1. c语言计算器程序代码 链栈,【C语言】简易科学计算器源代码(链栈应用)(原创).doc...

    [C语言]简易科学计算器源代码(链栈应用)(原创) 用到的是算符优先法的思想,现摘自严蔚敏的数据结构(C语言版)的3.2.5章来详细说明算符优先法的思想: (摘抄结束) 我给出的计算器功能有:支持欧拉 ...

  2. c语言编程实现二进制计算器,本程序是用纯C语言编的一个基于命令行的四则运算计算器。主要用于计算四则运算表达式的值,同时可以实现四...

    本程序是用纯C语言编的一个基于命令行的四则运算计算器.主要用于计算四则运算表达式的值,同时可以实现四 2016-08-22 0 0 0 暂无评分 其他 1 积分下载 如何获取积分? 本程序是用纯C语言 ...

  3. c语言用栈编写计算器程序,用c语言实现简易的计算器四则运算的代码最好用栈方法实现,该怎么解决...

    C/C++ code/*--------------------------------------- 函数型计算器(VC++6.0,Win32 Console)程序由 yu_hua 于2007-07 ...

  4. 计算器怎么用c语言编程,如何用C语言编写简易的计算器

    表达式计算建议看一下<数据结构>,先转换为逆波兰表达式,然后再计算. 当然用字符串匹配也是可以的,但是这样复杂度会比较高, 匹配最里面的括号有一个方法就是寻找第一个右括号,和这个右括号对应 ...

  5. C语言二位十进制计算器模数,十进制转二进制计算器

    win10系统之家今天精心准备的是<十进制转二进制计算器>,下面是详解! 怎样用电脑计算器计算二进制 用电脑计算器计算二进制的具体操作步骤如下: 1.首先在电脑桌面上点击左下角的" ...

  6. GO语言基础----简易计算器

    GO语言基础----简易计算器 该计算器可以执行两个数字和一个计算符号的计算. 例如,1+1,3*5,9/2- 代码实现: package mainimport("fmt")fun ...

  7. c语言计算器开题报告,基于单片机的简易电子计算器设计开题报告.doc

    第 PAGE 3页 授人以渔能力为本 毕业设计开题报告 学生姓名 学生学号 毕业设计题目 基于单片机的简易电子计算器设计 1.选题背景(含国内外相关研究综述及评价)与意义 随着社会的发展,科学的进步, ...

  8. 简易计时闹钟设计verilog语言实现

    简易计时闹钟设计verilog语言实现 任务描述: 用电路或verilog语言实现以下功能 简易计时闹钟: 有四位数码管,前两位计分钟,表示00~99分钟, 后面两位记秒,值为00~59秒. 有三个按 ...

  9. Android开发:kotlin语言实现简易计算器

    Android开发:kotlin语言实现简易计算器 1. 实现效果 2. 主要文件代码: 界面布局:activity_main.xml文件代码 字符定义:string.xml文件代码 逻辑实现:Mai ...

最新文章

  1. mysql 子查询多个字段_MySql基础
  2. log4j配置文件详解---转
  3. 30岁转行测试工程师_30岁一无所长,转行UI设计还合适吗?
  4. python读取文件的常用方法
  5. 统计学习方法第二章作业:感知机模型原始形式与对偶形式代码实现
  6. 浅谈SQL注入风险 - 一个Login拿下Server(转)
  7. MSSQL → 02:数据库结构
  8. python开发环境推荐_推荐一款Python开发环境管理神器
  9. log功能ASP.NET MVC能实现
  10. python实现汉诺塔(递归)
  11. FlasCC例子研究之bitmapdata
  12. 记一次被200G流量 DDOS攻击的处理经验
  13. 秀动app抢票脚本_GitHub标星2.5万的quot;Python抢票教程”!
  14. 经典SQL学习笔记 (二)-单行函数
  15. 算法笔记习题 2-9小节
  16. j1_8。实现打折功能关键算法。编写程序计算购买图书的总金额。
  17. android通过webview调起支付宝app支付
  18. 手机显示器云服务器,不想买台式机,手机加显示器组成云电脑是否可行?
  19. 为什么说OKRS-E是适合的OKR框架
  20. [转]高精度乘法计算

热门文章

  1. ng2 绑定输出html,Angular2的数据绑定
  2. 你愿意给应届生200万年薪吗?
  3. 干货 | 训练AI模型找不到数据?20个精选开源社区收藏好!
  4. Python文本分析-常用中文停用词表(Chinese Stop Words)
  5. 运放的参数详解及应用电路
  6. [2021]Linux下C语言qrencode二维码生成库的基本使用和ARM开发板移植
  7. 直播美颜SDK代码浅析:直播平台接入美颜SDK是怎样实现美颜的?
  8. 计算机毕业设计JavaVue框架电商后台管理系统(源码+系统+mysql数据库+lw文档)
  9. 产品概念之4/4:产品包 —— 升维思考,降维打击
  10. p值>0.05,统计意义上不显著?