verilog实例代码2Word文件下载.docx
《verilog实例代码2Word文件下载.docx》由会员分享,可在线阅读,更多相关《verilog实例代码2Word文件下载.docx(36页珍藏版)》请在冰点文库上搜索。
//---------------compare.v-----------------
modulecompare(equal,a,b);
outputequal;
assignequal=(a==b)?
0;
//a等于b时,equal输出为1;
a不等于b时,
//equal输出为0。
测试模块用于检测模块设计得正确与否,它给出模块的输入信号,观察模块的内部信号和输出信号,如果发现结果与预期的有所偏差,则要对设计模块进行修改。
测试模块源代码:
`timescale1ns/1ns//定义时间单位。
modulecomparetest;
rega,b;
wireequal;
initial//initial常用于仿真时信号的给出。
begina=0;
b=0;
#100a=0;
b=1;
#100a=1;
#100$stop;
//系统任务,暂停仿真以便观察仿真波形。
end
comparecompare1(.equal(equal),.a(a),.b(b));
//调用模块。
Endmodule
【例3.1】4位全加器
moduleadder4(cout,sum,ina,inb,cin);
output[3:
0]sum;
outputcout;
input[3:
0]ina,inb;
inputcin;
assign{cout,sum}=ina+inb+cin;
endmodule
【例3.2】4位计数器
modulecount4(out,reset,clk);
0]out;
inputreset,clk;
reg[3:
always@(posedgeclk)
begin
if(reset)out<
=0;
//同步复位
elseout<
=out+1;
//计数
end
09.04.07
【例5.11】模为60的BCD码加法计数器
modulecount60(qout,cout,data,load,cin,reset,clk);
output[7:
0]qout;
input[7:
0]data;
inputload,cin,clk,reset;
reg[7:
always@(posedgeclk)//clk上升沿时刻计数
if(reset)qout<
elseif(load)qout<
=data;
//同步置数
elseif(cin)
if(qout[3:
0]==9)//低位是否为9,是则
qout[3:
0]<
//回0,并判断高位是否为5
if(qout[7:
4]==5)qout[7:
4]<
else
qout[7:
=qout[7:
4]+1;
//高位不为5,则加1
else//低位不为9,则加1
=qout[3:
0]+1;
assigncout=((qout==8'
h59)&
cin)?
//产生进位输出信号
【例9.10】奇偶校验位产生器
moduleparity(even_bit,odd_bit,input_bus);
outputeven_bit,odd_bit;
0]input_bus;
assignodd_bit=^input_bus;
//产生奇校验位
assigneven_bit=~odd_bit;
//产生偶校验位
∙VerilogHDL实例
(二)
练习二.简单时序逻辑电路的设计
目的:
掌握基本时序逻辑电路的实现。
在VerilogHDL中,相对于组合逻辑电路,时序逻辑电路也有规定的表述方式。
在可综合的VerilogHDL模型,我们通常使用always块和@(posedgeclk)(上升沿)或@(negedgeclk)(下降沿)的结构来表述时序逻辑。
下面是一个1/2分频器的可综合模型。
//half_clk.v:
modulehalf_clk(reset,clk_in,clk_out);
inputclk_in,reset;
outputclk_out;
regclk_out;
always@(posedgeclk_in)
begin
if(!
reset)
clk_out=0;
else
clk_out=~clk_out;
在always块中,被赋值的信号都必须定义为reg型,这是由时序逻辑电路的特点所决定的。
对于reg型数据,如果未对它进行赋值,仿真工具会认为它是不定态。
为了能正确地观察到仿真结果,在可综合风格的模块中我们通常定义一个复位信号reset,当reset为低电平时,对电路中的寄存器进行复位。
测试模块的源代码:
//-------------------
clk_Top.v-----------------------------
`timescale1ns/100ps
`defineclk_cycle50
moduleclk_Top.v;
regclk,reset;
wireclk_out;
always
#`clk_cycle
clk=~clk;
initial
clk=0;
reset=1;
#100reset=0;
#100reset=1;
#10000$stop;
half_clkhalf_clk(.reset(reset),.clk_in(clk),.clk_out(clk_out));
∙VerilogHDL实例(三)
练习三.利用条件语句实现较复杂的时序逻辑电路
掌握条件语句在VerilogHDL中的使用。
与常用的高级程序语言一样,为了描述较为复杂的时序关系,VerilogHDL提供了条件语句供分支判断时使用。
在可综合风格的VerilogHDL模型中常用的条件语句有if…else和case…endcase两种结构,用法和C程序语言中类似。
两者相较,if…else用于不很复杂的分支关系,实际编写可综合风格的模块、特别是用状态机构成的模块时,更常用的是case…endcase风格的代码。
这一节我们给的是有关if…else的范例,有关case…endcase结构的代码已后会经常用到。
下面给出的范例也是一个可综合风格的分频器,是将10M的时钟分频为500K的时钟。
基本原理与1/2分频器是一样的,但是需要定义一个计数器,以便准确获得1/20分频
模块源代码:
//---------------fdivision.v-----------------------------
modulefdivision(reset,f10m,f500k);
inputf10m,reset;
outputf500k;
regf500k;
reg[7:
0]j;
always@(posedgef10m)
RESET)//低电平复位。
f500k<
=0;
j<
else
if(j==19)//对计数器进行判断,以确定F500K信号是否反转。
=~f500k;
else
=j+1;
endmodule测试模块源代码:
//---------------
fdivision_Top.v------------------------
moduledivision_Top;
regf10m=0,reset;
wiref500k;
always#`clk_cyclef10m=~f10m;
begin
reset=1;
#100reset=0;
#100reset=1;
#10000$stop;
fdivisionfdivision(.reset(reset),.f10m(f10m),.f500k(f500k));
endmodule
∙VerilogHDL实例(四)
练习四.设计时序逻辑时采用阻塞赋值与非阻塞赋值的区别
1.明确掌握阻塞赋值与非阻塞赋值的概念和区别;
2.了解阻塞赋值的使用情况。
阻塞赋值与非阻塞赋值,在教材中我们已经了解了它们之间在语法上的区别以及综合后所得到的电路结构上的区别。
在always块中,阻塞赋值可以理解为赋值语句是顺序执行的,而非阻塞赋值可以理解为赋值语句是并发执行的。
实际的时序逻辑设计中,一般的情况下非阻塞赋值语句被更多地使用,有时为了在同一周期实现相互关联的操作,也使用了阻塞赋值语句。
(注意:
在实现组合逻辑的assign结构中,无一例外地都必须采用阻塞赋值语句。
下例通过分别采用阻塞赋值语句和非阻塞赋值语句的两个看上去非常相似的两个模块blocking.v和non_blocking.v来阐明两者之间的区别。
//-------------
blocking.v---------------
moduleblocking(clk,a,b,c);
output[3:
0]b,c;
input
[3:
0]a;
clk;
reg
always@(posedgeclk)
b=a;
c=b;
end
//-------------
non_blocking.v-------------------
modulenon_blocking(clk,a,b,c);
b<
=a;
c<
=b;
测试模块源代码:
compareTop.v-----------------------------
`include"
./blocking.v"
./non_blocking.v"
modulecompareTop;
wire[3:
0]b1,c1,b2,c2;
initial
forever#50clk=~clk;
a=4'
h3;
$display("
____________________________"
);
#100a=4'
h7;
hf;
ha;
h2;
#100
$stop;
non_blocking
non_blocking(clk,a,b2,c2);
blocking
blocking(clk,a,b1,c1);
VerilogHDL实例(五)
练习五.用always块实现较复杂的组合逻辑电路
1.掌握用always实现组合逻辑电路的方法;
2.了解assign与always两种组合逻辑电路实现方法之间的区别。
仅使用assign结构来实现组合逻辑电路,在设计中会发现很多地方会显得冗长且效率低下。
而适当地采用always来设计组合逻辑,往往会更具实效。
已进行的范例和练习中,我们仅在实现时序逻辑电路时使用always块。
从现在开始,我们对它的看法要稍稍改变。
下面是一个简单的指令译码电路的设计示例。
该电路通过对指令的判断,对输入数据执行相应的操作,包括加、减、与、或和求反,并且无论是指令作用的数据还是指令本身发生变化,结果都要作出及时的反应。
显然,这是一个较为复杂的组合逻辑电路,如果采用assign
语句,表达起来非常复杂。
示例中使用了电平敏感的always块,所谓电平敏感的触发条件是指在@后的括号内电平列表中的任何一个电平发生变化,(与时序逻辑不同,它在@后的括号内没有沿敏感关键词,如posedge或negedge)就能触发always块的动作,并且运用了case结构来进行分支判断,不但设计思想得到直观的体现,而且代码看起来非常整齐、便于理解。
alu.v--------------------------
`defineplus
3'
d0
`defineminus
d1
`defineband
d2
`definebor
d3
`defineunegate3'
d4
module
alu(out,opcode,a,b);
0]
out;
input[2:
0]opcode;
0]a,b;
//操作数。
always@(opcodeoraorb)
//电平敏感的always块
case(opcode)
`plus:
out=a+b;
//加操作。
`minus:
out=a-b;
//减操作。
`band:
out=a&
b;
//求与。
`bor:
out=a|b;
//求或。
`unegate:
out=~a;
//求反。
default:
out=8'
hx;
//未收到指令时,输出任意态。
endcase
end
同一组合逻辑电路分别用always块和连续赋值语句assign描述时,代码的形式大相径庭,但是在always中适当运用default(在case结构中)和else(在if…else结构中),通常可以综合为纯组合逻辑,尽管被赋值的变量一定要定义为reg型。
不过,如果不使用default或else对缺省项进行说明,则易生成意想不到的锁存器,这一点一定要加以注意。
指令译码器的测试模块源代码:
//-------------alu_Top.v-----------------
`timescale1ns/1ns
alutest;
wire[7:
reg[7:
a,b;
reg[2:
opcode;
parameter
times=5;
begin
a={$random}%256;
//Givearadomnumberblongsto[0,255].
b={$random}%256;
//Givearadomnumberblongsto[0,255].
opcode=3'
h0;
repeat(times)
#100
//Givearadomnumber.
opcode=opcode+1;
end
alu
alu1(out,opcode,a,b);
VerilogHDL实例(六)
练习六.在VerilogHDL中使用函数
掌握函数在模块设计中的使用。
与一般的程序设计语言一样,VeirlogHDL也可使用函数以适应对不同变量采取同一运算的操作。
VeirlogHDL函数在综合时被理解成具有独立运算功能的电路,每调用一次函数相当于改变这部分电路的输入以得到相应的计算结果。
下例是函数调用的一个简单示范,采用同步时钟触发运算的执行,每个clk时钟周期都会执行一次运算。
并且在测试模块中,通过调用系统任务$display在时钟的下降沿显示每次计算的结果。
moduletryfunct(clk,n,result,reset);
output[31:
0]result;
input[3:
0]n;
inputreset,clk;
reg[31:
always@(posedgeclk)//clk的上沿触发同步运算。
reset)//reset为低时复位。
result<
result<
=factorial(n);
function[31:
0]factorial;
//函数定义。
input[3:
0]operand;
reg[3:
0]index;
factorial=1;
for(index=1;
index<
=operand;
index=index+1)
factorial=index*factorial;
endfunction
moduletryfuctTop;
0]n,i;
regreset,clk;
wire[31:
n=0;
reset=1;
clk=0;
#10reset=0;
#10reset=1;
for(i=0;
i<
=15;
i=i+1)
#20n=i;
#10$stop;
always#5clk=~clk;
tryfuncttryfunct(.clk(clk),.n(n),.result(result),.reset(reset));
上例中函数factorial(n)实际上就是阶乘运算。
必须提醒大家注意的是,在实际的设计中,我们不希望设计中的运算过于复杂,以免在综合后带来不可预测的后果。
经常的情况是,我们把复杂的运算分成几个步骤,分别在不同的时钟周期完成。
VerilogHDL实例(七)
练习七.在VerilogHDL中使用任务(task)
掌握任务在结构化VerilogHDL设计中的应用。
仅有函数并不能完全满足VeirlogHDL中的运算需求。
当我们希望能够将一些信号进行运算并输出多个结果时,采用函数结构就显得非常不方便,而任务结构在这方面的优势则十分突出。
任务本身并不返回计算值,但是它通过类似C语言中形参与实参的数据交换,非常快捷地实现运算结果的调用。
此外,我们还常常利用任务来帮助我们实现结构化的模块设计,将批量的操作以任务的形式独立出来,这样设计的目的通常一眼看过去就很明了。
下面是一个利用task和电平敏感的alway