通信软件设计-第2章 加法器-计数器实例-2011_图文

第2章 加法器/计数器实例 ? 加法器是数字电路中最广泛应用的电路 之一,在CPU的ALU算数运算单元广泛 应用。 ? 在算数运算中,加法器(减法器)是使 用最多的

2.1
?

1位半加器adder设计实例

半加器定义:即是产生数的和的装置。加数和被加 数为输入,和数与进位为输出的装置为半加器。

?

全加器定义:若加数、被加数与低位的进位数为输
入,而和数与进位为输出则为全加器。

1位半加法器的设计
? 数字系统通过0与1来实现复杂的系统工程,最简单的逻辑运算就是两 个1位进行加法的操作。

封装后的1bit半加法器

代码
? ? ? ? ? ? ? module adder(cout,sum,a,b); //模块名 output cout; // 输出端口声明 output sum; //输出端口声明 input a,b; //输入端口声明 wire cout,sum ; // wire变量声明 assign {cout,sum}=a+b; // a+b相加 endmodule // 模块结束语句

2.1.1 模块的结构
Verilog 模块的结构由在module和 endmodule 关键词之间的四个主要部分组 成:
- 端口定义: - I/O说明 : module block1(a, b, c, d ); input a, b, c ; output d ; - 内部信号声明: wire x; - 功能定义: assign d = a | x ; assign x = ( b & ~c ); endmodule

2.1 模块的结构
2.1.1 模块的端口定义
模块的端口声明了模块的输入输出口。其格式如 下: module 模块名(口1,口2,口3,口4, ………); 模块的内容包括I/O说明、内部信号声明、功能 定义。 ? I/O说明的格式 输入口:input[信号位宽-1:0] 端口名1; input[信号位宽-1:0] 端口名2; … input[信号位宽-1:0] 端口名 i; //(共有i个输入口)

2.1 模块的结构
输出口 output[信号位宽-1:0] 端口名1; output[信号位宽-1:0] 端口名2; … output[信号位宽-1:0] 端口名j; //(共有j个输出口) 输入/输出口: inout[信号位宽-1:0] 端口名1; inout[信号位宽-1:0] 端口名2; … inout[信号位宽-1:0] 端口名k; //(共有k个双向总线端口) I/O说明也可以写在端口声明语句里。其格式如下: module module_name(input port1,input port2,… output port1,output port2… );

assign语句
? assign net_type = 表达式; 用它赋值的语言称为连续赋值语句。 ? 连续赋值语句用于组合逻辑的建模。等式 左边是wire 类型的变量。等式右边可以是 常量、由运算符如逻辑运算符、算术运算 符参与的表达。

wire型 wire型数据常用来表示用于以assign关键字 指定的组合逻辑信号。 Verilog程序模块中输入输出信号类型缺省时自 动定义为wire型。其格式 如下: wire [n-1:0] 数据名1,数据名2,……数据名i; //共有i条总线,每条总线内有n条线路,或 wire [n:1] 数据名1,数据名2,……数据名i;

2.1.2 adder Testbench 设计
? 什么是 Testbench

如何编写Testbench

2.1.2 adder Testbench的编写
? ? ? ? ? ? ? ? ? ? ? ? `timescale 1ns/10ps //定义时间精度 `include “adder.v” //引用模块 module adder_testbench; //定义测试模块 reg a,b; //初始化模块中寄存器定义 wire sum,cout; // 定义线网 integer i,j; adder adder_te( .sum ( sum ), .cout ( cout), .a ( a ), .b ( b ) );

2.1.2 adder Testbench的编写
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? initial //initial 语句同时立即执行,不需要时间 begin a=0;b=0; for(i=1;i<16;i=i+1) #20 a=i; end initial begin for(j=1;j<16;j=j+1) #10 b=j; end initial begin $monitor($time,,,"%d + %d ={%b,%d}",a,b,cout,sum); #160 $finish; end endmodule

2.1.3 adder Testbench执行结果与仿真波形

? ? ? ?

# 20 # 30 # 40 # 50

1 + 0 ={0,1} 1 + 1 ={1,0} 0 + 0 ={0,0} 0 + 1 ={0,1}

2.2
? 2.2.1

1bit全加法器full_add设计实例
1bit全加法器full_add 设计

全加器的verilog代码
? ? ? ? ? ? ? ? ? ? ? ? ? ? module full_add (a,b,cin,sum,cout); input a,b,cin; output sum,cout; reg sum,cout; reg m1,m2,m3; always @(a or b or cin) begin sum = (a ^ b) ^ cin;//^按位逻辑异或 m1 = a & b; m2 = b & cin; m3 = a & cin; cout = (m1|m2)|m3; end endmodule

Full_add Testbench代码
? ? ? ? ? ? ? ? ? ? ? ? ? ? `timescale 1ns/10ps `include "full_add.v" module full_add_testbench; reg a,b,cin; wire sum,cout; integer i,j,k; full_add full_adder_te( .sum ( sum ), .cout ( cout), .a ( a ), .b ( b ), .cin ( cin) );

initial //a向量 begin a=0; for(i=1;i<16;i=i+1) #20 a=~a; //a周期为40ns end initial //b向量 begin b=0; for(j=1;j<16;j=j+1) #10 b=~b; // b周期为20ns end Initia // cin向量 begin cin=0; for(k=1;k<16;k=k+1) #5 cin=~cin; // cin周期为10ns end initial begin $monitor($time,,,"%d + %d + %d ={%b,%d}",a,b,cin,cout,sum); #80 $finish; end endmodule

2.2.3 Testbench仿真波形
? ? ? ? ? ? ? ? ? ? ? ? ? ? # # # # # # # # # # # # # # 0 0 + 0 + 0 ={0,0} 5 0 + 0 + 1 ={0,1} 10 0 + 1 + 0 ={0,1} 15 0 + 1 + 1 ={1,0} 20 1 + 0 + 0 ={0,1} 25 1 + 0 + 1 ={1,0} 30 1 + 1 + 0 ={1,0} 35 1 + 1 + 1 ={1,1} 40 0 + 0 + 0 ={0,0} 45 0 + 0 + 1 ={0,1} 50 0 + 1 + 0 ={0,1} 55 0 + 1 + 1 ={1,0} 60 1 + 0 + 0 ={0,1} 65 1 + 0 + 1 ={1,0}

full_add仿真波形

2.3同步4bit全加法器的设计实例

2.3同步4bit全加法器的设计实例
2.3.1 always语句说明 initial和always说明语句在仿真的一开 始即开始执行。initial语句只执行一次。 相反,always语句则是不断地重复执行,

直到仿真过程结束。

2.3.1 always 语句
? always语句在仿真过程中是不断重复执行的。 其声明格式如下: always <时序控制> <语句> always语句由于其不断重复执行的特性,只有 和一定的时序控制结合在一起才有用。如果一个 always语句没有时序控制,则这个always语句将 会发成一个仿真死锁。
always areg = ~areg; 这个always语句将会生成一个0延迟的无限循环跳变

过程,这时会发生仿真死锁。

2.3.1 always 语句
如果加上时序控制,则这个always语句 将变为一条非常有用的描述语句。
always # half_period areg = ~areg; 这个例子生成了一个周期 为:period(=2*half_period) 的无限延续的信号波形,常用这种方法来描 述时钟信号,作为激励信号来测试所设计 的电路。

Adder4的I/O口说明

Adder4的I/O口说明
? ? ? ? ? ? module adder4(cout,sum,ina,inb,cin,clk); output[3:0] sum; output cout; input[3:0] ina,inb; input cin,clk; reg[3:0] tempa,tempb,sum; //tempa,tempb 中间变量说明 ? reg cout; ? reg tempc; //tempc中间变量说明

? ? ? ? ? ? ? ? ? ? ?

always @(posedge clk) begin tempa=ina; tempb=inb; tempc=cin; end always @(posedge clk) begin {cout,sum}=tempa+tempb+tempc; end endmodule

Adder4的testbench设计
? `timescale 1ns/10ps `include "adder4.v" ? module adder4_testbench; ? reg [3:0] ina,inb; ? reg cin; ? reg clk=0; ? wire [3:0] sum; ? wire cout;

? always #10 clk=~clk; ? initial ? begin ? ina=0; ? repeat(20) ? #20 ina =$random; ? end ? initial ? begin ? inb=0; ? repeat(10) ? #40 inb =$random; ? end ?

adder4 testbench的设 计

? initial ? begin ? cin=0; ? repeat(2) ? #200 ? cin ={$random}%16; ? end adder4 adder4_te( ? .clk (clk ), ? .sum ( sum ), ? .cout ( cout), ? .ina ( ina ), ? .inb ( inb ), ? .cin ( cin ) ? ); ? initial ? begin ? $monitor($time,,,"%b + %b + %b ={%b,%b}",ina,inb,cin,cout,sum); ? #400 $finish; ? end ? endmodule

系统任务 $random
这个系统函数提供了一个产生随机数的手段。当函数被 调用时返回一个32bit的随机数。它是一个带符号的整形数。 $ramdom % b ,其中 b>0. 它给出了一个范围在(-b+1):(b-1)中的随机数。 reg[23:0] rand; rand = $random % 60; reg[23:0] rand; rand = {$random} % 60; 给出了一个范围在-59到59 之间的随机数 通过位并接操作产生一个值 在0到59之间的数

系统任务 $monitor
? 格式: $monitor(p1,p2,.....,pn); $monitor; $monitoron; $monitoroff;
任务$monitor提供了监控和输出参数列表中的表达式 或变量值的功能。 每当参数列表中变量或表达式的值发生变化时,整个 参数列表中变量或表达式的值都将输出显示

时间度量系统函数 $time
?系统函数$time。$time可以返回一个64比特的

整数来表示的当前仿真时刻值。该时刻是以模块 的仿真时间尺度为基准的。

? $realtime系统函数。$realtime和$time 的作用是一样的,只是$realtime返回的 时间数字是一个实型数,该数字也是以时 间尺度为基准的。

系统任务 $finish
格式: $finish; $finish(n); 系统任务$finish的作用是退出仿真器,返回主操作系统, 也就是结束仿真过程。任务$finish可以带参数,根据参数的 值输出不同的特征信息。如果不带参数,默认$finish的参数 值为1。

对于不同的参数值,系统输出的特征信息: 0 ——不输出任何信息 1 ——输出当前仿真时刻和位置 2 ——输出当前仿真时刻,位置和在仿真过程中所 用memory及CPU时间的统计

作业
? 调试adder4 testbench ? 要求给出波形及仿真结果。

2.4 4bit计数器count4设计实例

Count 4 的顶层封装

count4 代码
? ? ? ? ? ? ? ? ? ? module count4(qout,reset,clk); output[3:0] qout; input clk,reset; reg[3:0] qout; always @(posedge clk) begin if (reset) qout<=0; else qout<=qout+1; end endmodule

2.4.2 count4 testbench 设计
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? `timescale 1ns/1ns `include "count4.v" module coun4_testbench; reg clk,reset; wire[3:0] out; parameter DELY=100; count4 mycount(out,reset,clk); always #(DELY/2) clk = ~clk; initial begin clk =0; reset=0; #DELY reset=1; #DELY reset=0; #(DELY*20) $finish; end initial $monitor($time,,,"clk=%d reset=%d out=%d", clk, reset,out); endmodule

2.4.3 仿真结果与波形
? ? ? ? ? ? ? ? ? ? ?

# # # # # # # # # # # #

0 clk=0 reset=0 out= x 50 clk=1 reset=0 out= x 100 clk=0 reset=1 out= x 150 clk=1 reset=1 out= 0 200 clk=0 reset=0 out= 0 250 clk=1 reset=0 out= 1 300 clk=0 reset=0 out= 1 350 clk=1 reset=0 out= 2 400 clk=0 reset=0 out= 2 450 clk=1 reset=0 out= 3 500 clk=0 reset=0 out= 3 550 clk=1 reset=0 out= 4

波形

2.5 8bit BCD码计数器 count60
? 用4位二进制数来表示1位十进制数中的 0~9这10个数码,简称BCD码, ? (Binary-Coded Decimal?)码又称8421 码表如下所示

i/o 说明
功能:计数到60(16进制),data是载入计数 初始值,load为载入有效,cin为累加器计数有效, qout为计数输出值,cout为计数值达到60输出。

count60 程序设计代码
? ? ? ? ? ? module count60(qout,cout,data,load,cin,reset,clk); output[7:0] qout; output cout; input[7:0] data; input load,cin,clk,reset; reg[7:0] qout;

? always @(posedge clk) ? begin ? if (reset) qout<=0; ? else if(load) qout<=data; ? else if(cin) ? begin ? if(qout[3:0]==9) ? begin ? qout[3:0]<=0; ? if (qout[7:4]==5) qout[7:4]<=0; ? else ? qout[7:4]<=qout[7:4]+1; ? end ? else ? qout[3:0]<=qout[3:0]+1; ? end ? end ? assign cout=((qout==8'h59)&cin)?1:0; ? endmodule

if_else语句
? if语句是用来判定所给定的条件是否满足, 根据判定的结果(真或假)决定执行给出的 两种操作之一。 ? Verilog HDL语言提供了三种形式的if语句。 ? (1).if(表达式)语句 ? 例如: if ( a > b ) out1 <= int1; ?

? (2).if(表达式) 语句1 ? else 语句2 ? 例如: if(a>b) out1<=int1; ? else out1<=int2; ? (3).if(表达式1) 语句1; ? else if(表达式2) 语句2; ? else if(表达式3) 语句3; ? ........ ? else if(表达式m) 语句m; ? else 语句n; ? 例如: ? if(a>b) out1<=int1; ? else if(a==b) out1<=int2; ? else out1<=int3;

If语句

2.5.2 count60 Testbench设计
计数器测试主要考虑载入的数据,载入是否有效,计 数有效,其testbench代码; `timescale 10ns/1ns `include "count60.v" module count60_testbench; reg clk,reset; reg [7:0] data; reg cin; reg load; wire[7:0] qout; wire count; parameter DELY=100; count60 C1(qout,count,data,load,cin,reset,clk); always #(DELY/2) clk = ~clk;

? ? ? ? ? ? ? ? ? ? ? ? ?

initial begin clk =0; reset=0; data=80; #DELY reset=1; #DELY reset=0;load=1; #DELY reset=0;load=0;cin=1; #(DELY*300) $finish; end always @( posedge clk) begin $display($time,,,"clk=%d reset=%d qout=%d",clk,reset,qout); end endmodule

COUNT60的波形仿真及结果测试
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? # # # # # # # # # # # # # # # # # 50 clk=1 reset=0 qout= x 150 clk=1 reset=1 qout= x 250 clk=1 reset=0 qout= 0 350 clk=1 reset=0 qout= 80 450 clk=1 reset=0 qout= 81 550 clk=1 reset=0 qout= 82 650 clk=1 reset=0 qout= 83 750 clk=1 reset=0 qout= 84 850 clk=1 reset=0 qout= 85 950 clk=1 reset=0 qout= 86 1050 clk=1 reset=0 qout= 87 1150 clk=1 reset=0 qout= 88 1250 clk=1 reset=0 qout= 89 1350 clk=1 reset=0 qout= 0 1450 clk=1 reset=0 qout= 1 1550 clk=1 reset=0 qout= 2 1650 clk=1 reset=0 qout= 3

Count60 testbench的仿真波形


相关文档

通信软件设计-第3章 乘法器除法器设计实例-2011
通信软件设计-第4章 编码器-译码器设计实例-2011
通信软件设计-第5章 状态机实例-2011
数字通信-第2章2011-3
通信概论第2章2011
2011串口通信范例程序
基于VB6_0的串行通信工控软件设计及实例
2011 LX 移动通信_第二章_移动通信电波传播与传播预测模型 ver3.3 part1
软件设计报告—南京邮电大学—mfc—计算器,万年历
通信软件设计-第1章 绪论-软件使用-2011
电脑版