Verilog学习心得Word下载.docx

上传人:b****5 文档编号:21201253 上传时间:2023-01-28 格式:DOCX 页数:9 大小:22.67KB
下载 相关 举报
Verilog学习心得Word下载.docx_第1页
第1页 / 共9页
Verilog学习心得Word下载.docx_第2页
第2页 / 共9页
Verilog学习心得Word下载.docx_第3页
第3页 / 共9页
Verilog学习心得Word下载.docx_第4页
第4页 / 共9页
Verilog学习心得Word下载.docx_第5页
第5页 / 共9页
点击查看更多>>
下载资源
资源描述

Verilog学习心得Word下载.docx

《Verilog学习心得Word下载.docx》由会员分享,可在线阅读,更多相关《Verilog学习心得Word下载.docx(9页珍藏版)》请在冰豆网上搜索。

Verilog学习心得Word下载.docx

inputa,b,cin;

outputsum,cout;

 

assign{cout,sum}=a+b+cin;

endmodule 

然后在执行8-bit补码加减运算的ALUmodule中实例化8个FullAdder,表示ALU用到了8个FullAdder。

moduleALU(a,b,result,cout,is_add);

input[7:

0] 

a,b;

input 

is_add;

output[7:

0]result;

output 

cout;

wire[7:

0]b_not=~b;

0]b_in=is_add?

b:

b_not;

0]carry;

assigncarry[0]=is_add?

1'

b0:

b1;

//module实例化 

//8-bitrippleadder 

FullAdderfa0(a[0],b_in[0],carry[0],result[0],carry[1]);

FullAdderfa1(a[1],b_in[1],carry[1],result[1],carry[2]);

FullAdderfa2(a[2],b_in[2],carry[2],result[2],carry[3]);

FullAdderfa3(a[3],b_in[3],carry[3],result[3],carry[4]);

FullAdderfa4(a[4],b_in[4],carry[4],result[4],carry[5]);

FullAdderfa5(a[5],b_in[5],carry[5],result[5],carry[6]);

FullAdderfa6(a[6],b_in[6],carry[6],result[6],carry[7]);

FullAdderfa7(a[7],b_in[7],carry[7],result[7],cout);

对应在C++中先写FullAdderclass,然后在ALUclass中以FullAdder作为datamember。

classFullAdder 

};

classALU 

FullAdderfa[8];

另外一点,moudle声明port的方式,像是从早期C语言的函数定义中学来的:

char*strcpy(dst,src)

char*dst;

char*src;

{

//...

}

2.Verilog中的模块调用时,指定端口可以使用名称绑定。

C++在调用函数时,参数只能按顺序书写。

例如memset()的原型是:

void*memset(void*s,intc,size_tn);

如果你想将某个buf清零,应该这么写:

charbuf[256];

memset(buf,0,sizeof(buf));

但是如果你不小心写成了:

memset(buf,sizeof(buf),0);

编译器不会报错,但运行的实际效果是根本没有对buf清零。

(记得RichardStevens的书里提到过这一点。

) 

在Verilog中,如果要写一个测试ALU的module,那么其中对ALU实例化的指令可以这么写:

modulealu_test;

reg[8:

0]a_in,b_in;

reg 

op_in;

wire[7:

0]result_out;

wire 

carry_out;

ALUalu0(.a(a_in[7:

0]),.b(b_in[7:

0]),.is_add(op_in), 

.result(result_out),.cout(carry_out));

//... 

endmodule 

这样就比较容易检查接线错误。

另外,在C++中,如果所有参数类型不同,而且之间没有隐式类型转换,那么可以利用C++的强类型机制在编译期检查出这种调用错误。

3.Verilog中把大括弧{}用作bit的并置,因此语句块要用begin/end标示。

Verilog中小括号()和中括号[]的作用与C++中类似,前者用于函数或模块调用,后者用于下标索引。

我想如果Verilog把尖括号<

>

用作bit并置的话,就能把大括号{}解放出来,用作标示语句块,这样写起来更舒服一些。

4. 

Verilog本质上是测试驱动开发的。

对于每个module都应该有对应的testbench(或称testfixture)。

比较好的情况是,一个工程师写module,另一个工程师写对应的testbench,这样很容易检查出对电路功能需求理解不一致的地方。

因此还可以说Verilog主张结对编程(pairprogramming)。

例如对前面的ALUmodule的testbench可以写成:

`timescale1ns/1ns 

reg[9:

0]get,expected;

has_error;

initialbegin 

has_error=1'

b0;

op_in=1'

//testaddition 

for(a_in=9'

a_in!

=256;

a_in=a_in+1) 

for(b_in=9'

b_in!

b_in=b_in+1)begin 

#1;

get={carry_out,result_out};

expected=a_in+b_in;

if(get!

==expected)begin 

$display("

a_in=%d,b_in=%d,expected%d,get%d"

 

a_in,b_in,expected,get);

end 

end 

//testsubtraction 

//... 

if(has_error===1'

b0)begin 

ALLTESTSPASSED!

"

);

$finish;

5.Verilog比起VHDL的不足之处在于,它只能定义concreteclass,不能定义abstractclass。

也就是说interface和implementation不能分离。

这在设计大型电路时就显得表现力不足。

不过这关系不大,因为可以在编译时选择同一模块的不同实现版本,间接实现了接口与实现的分离。

在VHDL中,强制将接口与实现分离。

对每个模块,你都得先写接口(定义输入输出信号),即ENTITY;

然后至少写一份实现,即ARCHITECTURE。

每个ENTITY可以有不止一份实现,例如可以有行为描述的,也有数据流描述的。

然后在配置文件中选择该ENTITY到底用哪一份实现。

举例来说(选自《VHDL入门·

解惑·

经典实例·

经验总结》一书),分频器模块可以这么写,先定义其接口FreqDevider,然后定义两份实现Behavior和Dataflow:

LIBRARYIEEE;

USEIEEE.Std_Logic_1164.All;

ENTITYFreqDeviderIS 

PORT 

(Clock 

:

IN 

Std_Logic;

Clkout:

OUTStd_Logic 

END;

ARCHITECTUREBehaviorOFFreqDeviderIS 

SIGNALClk:

BEGIN 

PROCESS(Clock) 

BEGIN 

IFrising_edge(Clock)THEN 

Clk<

=NOTClk;

ENDIF;

ENDPROCESS;

Clkout<

=Clk;

ARCHITECTUREDataflowOFFreqDeviderIS 

--signaldeclarations 

--processes 

在C++中,既可以写concreteclass,也可以写abstractclass。

比Verilog和VHDL都方便。

6.Verilog和VHDL都有模板的概念,Verilog称为参数(parameter),VHDL称为类属(generic)。

不过好像都只能用整数作为模板参数,不能像C++那样用类型作为模板参数。

7.目前来看,Verilog是硬件描述语言,不是硬件设计语言。

在用Verilog设计电路的时候,我们是把脑子中想好的电路用Verilog“描述”出来:

哪里是寄存器、哪里是组合逻辑、数据通路是怎样、流水线如何运作等等都要在脑子里有清晰的映象。

然后用RTL代码写出来,经过综合器综合出的电路与大脑中的设想相比八九不离十。

这就像说C语言是可移植的汇编语言,以前好的C程序员在写代码的时候,能够知道每条语句背后对应的汇编代码是什么。

verilog设计经验点滴

1,敏感变量的描述完备性

Verilog中,用always块设计组合逻辑电路时,在赋值表达式右端参与赋值的所有信号都必须在always@(敏感电平列表)中列出,always中if语句的判断表达式必须在敏感电平列表中列出。

如果在赋值表达式右端引用了敏感电平列表中没有列出的信号,在综合时将会为没有列出的信号隐含地产生一个透明锁存器。

这是因为该信号的变化不会立刻引起所赋值的变化,而必须等到敏感电平列表中的某一个信号变化时,它的作用才表现出来,即相当于存在一个透明锁存器,把该信号的变化暂存起来,待敏感电平列表中的某一个信号变化时再起作用,纯组合逻辑电路不可能作到这一点。

综合器会发出警告。

Example1:

inputa,b,c;

rege,d;

always@(aorborc)

begin

e=d&

a&

b;

/*d没有在敏感电平列表中,d变化时e不会立刻变化,直到a,b,c中某一个变化*/

d=e|c;

end

Example2:

always@(aorborcord)

/*d在敏感电平列表中,d变化时e立刻变化*/

2,条件的描述完备性

如果if语句和case语句的条件描述不完备,也会造成不必要的锁存器。

if(a==1'

b1)q=1'

//如果a==1'

b0,q=?

q将保持原值不变,生成锁存器!

else 

q=1'

//q有明确的值。

不会生成锁存器!

Example3:

reg[1:

0]a,q;

....

case(a)

2'

b00:

q=2'

b00;

b01:

b11;

//如果a==2'

b10或a==2'

b11,q=?

q将保持原值不变,锁存器!

endcase

Example4:

default:

Verilog中端口的描述

1,端口的位宽最好定义在I/O说明中,不要放在数据类型定义中;

moduletest(addr,read,write,datain,dataout)

input[7:

datain;

input[15:

0]addr;

input 

read,write;

output[7:

0]dataout;

//要这样定义端口的位宽!

wireaddr,read,write,datain;

reg 

dataout;

datain,addr,read,write;

outputdataout;

wire[15:

reg[7:

//不要这样定义端口的位宽!

2,端口的I/O与数据类型的关系:

端口的I/O 

端口的数据类型

module内部 

module外部

wire或reg

output 

wire或reg 

wire

inout 

3,assign语句的左端变量必须是wire;

直接用"

="

给变量赋值时左端变量必须是reg!

Example:

assigna=b;

//a必须被定义为wire!

********

begin

a=b;

//a必须被定义为reg!

end

VHDL中STD_LOGIC_VECTOR和INTEGER的区别

例如A是INTEGER型,范围从0到255;

B是STD_LOGIC_VECTOR,定义为8位。

A累加到255时,再加1就一直保持255不变,不会自动反转到0,除非令其为0;

而B累加到255时,再加1就会自动反转到0。

所以在使用时要特别注意!

以触发器为例说明描述的规范性

1,无置位/清零的时序逻辑

always@(posedgeCLK)

Q<

=D;

2,有异步置位/清零的时序逻辑

异步置位/清零是与时钟无关的,当异步置位/清零信号到来时,触发器的输出立即被置为1或0,不需要等到时钟沿到来才置位/清零。

所以,必须要把置位/清零信号列入always块的事件控制表达式。

always@(posedgeCLKornegedgeRESET)

if(!

RESET)

Q=0;

else

3,有同步置位/清零的时序逻辑

同步置位/清零是指只有在时钟的有效跳变时刻置位/清零,才能使触发器的输出分别转换为1或0。

所以,不要把置位/清零信号列入always块的事件控制表达式。

但是必须在always块中首先检查置位/清零信号的电平。

always@(posedgeCLK)

结构规范性

在整个芯片设计项目中,行为设计和结构设计的编码是最重要的一个步骤。

它对逻辑综合和布线结果、时序测定、校验能力、测试能力甚至产品支持都有重要的影响。

考虑到仿真器和真实的逻辑电路之间的差异,为了有效的进行仿真测试:

1,避免使用内部生成的时钟

内部生成的时钟称为门生时钟(gatedclock)。

如果外部输入时钟和门生时钟同时驱动,则不可避免的两者的步调不一致,造成逻辑混乱。

而且,门生时钟将会增加测试的难度和时间。

2,绝对避免使用内部生成的异步置位/清零信号

内部生成的置位/清零信号会引起测试问题。

使某些输出信号被置位或清零,无法正常测试。

3,避免使用锁存器

锁存器可能引起测试问题。

对于测试向量自动生成(ATPG),

为了使扫描进行,锁存器需要置为透明模式(transparentmode),

反过来,测试锁存器需要构造特定的向量,这可非同一般。

4,时序过程要有明确的复位值

使触发器带有复位端,在制造测试、ATPG以及模拟初始化时,可以对整个电路进行快速复位。

5,避免模块内的三态/双向

内部三态信号在制造测试和逻辑综合过程中难于处理.

补充不知你看了verilog2001版本吗?

现在的verilog在尽量往C语言的风格上靠拢。

1。

敏感变量的描述完备性,我现在用always实现组合逻辑时,都是写成always@(*),这样很很好,自动把所有右端赋值信号加入。

2。

module编写时这样更好:

module( 

input[23:

rx_data 

//CRC_chkinterface 

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 科学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1