Verilog 学习笔记
1、 Verilog语法的基本概念
(1) Verilog模块的基本概念
下面是一个2路选择器的模块
Module muxtwo (out,a,b,s1);
Input a,b,s1;
Output out;
Reg out;
If (!s1) out=a;
Else out=b;
Endmodule
Module muxtwo (out ,a,b,s1)
Input a,b,s1;
Output out;
Not u1(ns1,s1);
And #1 u2(sela,a,ns1);
And #1 u3(selb,b,s1);
Or #2 u4(out,sela,selb);
endmodule
在编写模块时,不但符合语法,还符合一些基本规则,就可以将左边的行为级描述转化为右边的门级描述,这个过程叫作综合。
Verilog语法最重要的几个特性是:并行性、层次结构性、可综合性、测试平台。
一个简单的三位加法器
Module adder(cout,sum,cin,a,b);
Input [2:0]a,b;
Input cin;
Output [2:0]sum;
Output cout;
Assign{cout,sum}=a+b+cin;
Endmodule
一个2位比较器
Module cmp(out,a,b);
Input [1:0]a,b;
Output out;
Assign out=(a==b)?1:0;
endmodule
三态驱动器的几种实现
Module trist2(out,in,enable);
Input in,enable;
Output out;
Bufifl myfifl(out,in,enable);
Endmodule
本模块通过调用库中的三态驱动元件来实现逻辑功能
Module trist1(sout,sin,ena);
Input sin,ena;
Output sout;
Mytri tri_inst(.out(sout),.in(sin)..enable(ena));
Endmodule
Module mytri(out,in,enable);
Input in,enable;
Output out;
Assign out=enable? in: ‘bz;
Endmodule
//通过调用已经定义的mytri模块来实例化tri_inst模块。
(2) 模块的测试
Verilog还可以用于描述变化的测试信号,描述测试信号的变化和测试的过程的模块叫做测试平台。
下面来做一个针对2路选择器的测试平台
include”muxtwo.v”
module t;
reg ain,bin,select;
reg clock;
wire outw;
initial //把寄存器变量初始化为一确定值
begin
ain=0;
bin=0;
select=0;
clock=0;
end
always #50 clock=~clock;//产生一个周期为100个单位时间的信号
always@(posedge clock)
begin
ain={$random}%2;
#3 bin={$random}%2;// {$random}为系统任务
end
always #1000 select=~select;
muxtwo m(.out(outw),.a(ain),.b(bin).s1(select));
endmodule
2、 常用Verilog的语法
(1) 模块的结构、数据类型和变量、基本的运算符号
模块的由两部分组成,一部分描述接口,另一部分描述逻辑。在Verilog模块中所有的过程块是(如:initial块、always块)、连续赋值语句、实例引用都是并行的;在同一模块中这三者出现的先后顺序没有关系;只有连续赋值语句assign和实例引用语句可以独立于过程快而存在于模块的功能定义部分。许多与C语言类似的语句只能出现在过程快中(initial和always块),而不能随意出现在功能定义的范围内。
数字的表示方法<位宽><进制><数字>8’b10101010、12’dz、12’d?(高阻)、8’h4x、-8’d5、8’b1010_1010,当常量不说明位数时,默认为32位。
参数parameter型,在Verilog中用parameter来定义常量,即用parameter来定义一个标识符号代表一个常量,成为符号常量,在赋值语句的右边必须是一个常数型的数,也就是说表达式只能包含数字和已经定义的参数。例如:parameter e=12,f=29; parameter r=5.7; parameter byte_size=8,byte_msb=byte_size-1;
参数型常数常用与定义延迟时间和变量宽度,在模块或实例引用时,可以通过参数传递改变在被引用模块或是实例中已定义的参数。参数在多层次模块中的运用。
Module Test;
Wire W;
Top T();
Endmodule
Module Top;
Wire W;
Block B1();
Block B2();
Endmodule
Module Block;
Parameter P=0;
Endmodule
Module Annotate
Defparam;//在一个模块中改变另一个模块的参数命令
Test.T.B1.P=2;//在多层次模块中,用点号来表示不同的模块层次
Test.T.B2.P=3;
Endmodule
变量,网络类型的变量不能存储值,而且必须受到驱动器的驱动,如果没有驱动器连接到网络上,其值为高阻态,常用的网络类型包括wire型和tri型。Wire型变量通常是用来表示单个门驱动或连续赋值语句驱动的网络型数据,tri型变量通常是用来表示多驱动器驱动的网络型数据。如果wire或tri型变量没有定义强度,在多驱动源的情况下,逻辑值会发生冲突。
Verilog程序模块中输入输出信号类型默认时自动定义成wire型,wire型信号可以做任何方程式的输入也可以做assign语句或实例元件的输出。Reg型数据常用来表示“always”模块内的指定信号,在“always”块内被赋值的每一个信号都必须定义成reg型,reg型默认初始值为不定值,reg型的数据可以赋正值也可以赋负值,但当一个reg型数据是一个表达式中的操作数时,它的值被当做是一个无符号值。Memory型数据是通过扩展reg型数据的地址范围来生成的,例如:reg[7:0] mema[255:0];表示存储器有256个8位的存储器,对存储器进行地址索引的表达式必须是常数表达式。
(2) 各种运算符、赋值语句、结构说明语句
逻辑运算的级别低于关系运算的级别,算术运算的级别高于关系运算的级别;===是严格意义上的相等,==则不是。移位运算的例子:
Module shift;
Reg[3:0] start,result;
Initial;
begin
start=1;
result=(start<<2);
end
endmodule
位拼接符的用法{a,b[3:0],w,3’b101,4{e}}
赋值分非阻塞赋值和阻塞赋值两种方式。非阻塞赋值b<=a:块结束后才完成赋值操作,b的值并不是立刻就变的,这是一种比较常用的赋值方法;阻塞赋值b=a:赋值语句执行完后,块才结束,b的值在赋值语句执行完后立即就变,在沿触发的always块中使用时可能会产生意想不到的结果。
块分顺序快和并行块,顺序快内的语句是顺序执行的,每条语句的延迟时间是相对与前一条语句的仿真时间而言的;并行块内的语句是并行执行的,每条语句的延迟时间是相对于程序
流程
快递问题件怎么处理流程河南自建厂房流程下载关于规范招聘需求审批流程制作流程表下载邮件下载流程设计
控制进入到块内的仿真时间的。块的使用有以下几个特点:可以允许在块内定义局部变量,可以允许被其他语句调用,在Verilog语言里所有的变量都是静态的,既所有的变量都只有一个唯一的存储地址,因此进入或是跳出块并不影响存储在变量内的值。
(3) 条件语句和循环语句
系统对表达式的值进行判断时,若为0,x,z,按假处理,If else语句经典模板。
If()
begin
if()语句1(内嵌if)
end
else
语句2
Case括号内的表达式称为控制表达式,case分支项中的表达式称为分支表达式,case语句的所有表达式的位宽必须相等,case的经典模板:
case()
2’b00: 语句1;
2’b01: 语句2;
Encase
在Verilog中存在4种循环语句:foever:连续的执行语句;repeat:连续执行一条语句n次,与always块不同之处在于不能独立写在程序中,必须写在initial模块中;while:执行一条语句直到某个条件不满足;for:通过给循环次数变量赋初值,判定控制循环变量的值,修改次数,继续判断。
用repeat语句实现一个8位的乘法器:
parameter size=8,longsize=16;
reg[size:1] opa,opb;
reg[longsize:1] result;
begin: mult
reg[longsize:1] shift_opa,shift_opb;
shift_opa=opa;
shift_opb=opb;
result=0;
repeat(size)
begin
if(shift_opb[1])
result=resut+shift_opa;
shift_opa=shift_opa<<1;
shift_opb=shift_opb>>1;
end
end
用for语句来实现一个8位乘法器:
parameter size=8,longsize=16;
reg[size:1] opa,opb;
reg[longsize:1] result;
begin: mult
integer bindex;
result=0;
for(bindex=1; bindex<=size; bindex= bindex+1)
if(opb[bindex])
result=result+(opa<<(bindex-1));
end
(4) 结构语句、系统任务、函数语句、显示系统任务
Verilog语言中的任何过程模块都从属于以下4种结构的说明语句:initial说明语句、always说明语句u、task说明语句、function说明语句。一个模块可以有多个initial和always模块,每个initial和always说明语句在仿真的一开始同时立即开始执行,initial只执行一次,always则持续到仿真结束。一个模块可以有多个always块,他们是并行运行的,若果这些always块是可以综合的,则表示的是某种结构,如果不可以综合,则是电路结构行为。
Task和function有以下不同:函数只能与主模块公用同一个仿真时间单位,而任务可以定义自己的仿真时间单位;函数不能启动任务,而任务可以启动其他任务和函数;函数至少有一个输入变量,而任务可以没有或有多个任何类型的变量;函数返回一个值,而任务则不返回值。在使用函数时,把它当做表达式中的操作符,这个操作的结果就是这个函数的返回值。
如果传给任务的变量值和任务完成后接受结果的变量已经定义,就可以用一条语句启动任务。举一个交通灯时间的任务例子:
module traffic_lights;
………
always
begin
light(red,red_tics);//调用等待任务
………….
end
task light;
output color;
input[31:0];
begin
repeat(tics)
@(posedge clock);
color=off;
end
endtask
//产生时钟脉冲的always模块
always
begin
#100 clock=0;
#100 clock=1;
end
enmodule
函数的定义蕴含声明了与函数同名的、函数内部的寄存器。函数的定义把函数返回值所赋值寄存器的名称初始化为与函数同名的内部变量。
function[7:0]getbyte;
input[15:0]address;
begin
<说明语句>
Getbyte=result_expression;
end
endfunction
函数的使用限制:函数的定义不能包含有任何的时间控制语句,即任何用#、@或wait来标示的语句;函数不能启动任务;函数必须至少有一个输入变量;在函数的定义中必须有一条赋值语句给函数中的一个内部变量赋以函数的结果值,该内部变量具有和函数名字相同的变量。
(5) 调用系统任务和常用编译预处理语句
常用系统任务:$monitor($time,”rxd=%btxd=%b”,rxd,txd),用来监视和输出参数列表中的表达式或变量值;$finish(n),用来退出仿真器,返回主操作系统;$stop(),用来把仿真工具置成暂停模式,在仿真环境下给出一个交互式的命令提示符;$random,用于产生一个随机的带符号的整数
Verilog编译系统通常先对特殊的命令进行“预处理”,然后将预处理的结果和源程序仪器进行通常的编译处理。
`define WORKSIZE 8
Module
Reg[1:`WORKSIZE] data;在引用已定义的宏名时,必须在宏名的前面加`,宏定义不是Verilog语句,不必在行末加分号宏名和宏内容必须在同一行中声明。
如果文件1包含文件2,而文件2要用到文件3,则可以在文件1用2个`include命令分别包含文件2和文件3,而且文件3应该出现在文件2之前。
3、 中级篇
(1) Verilog模型的不同抽象级别
抽象的级别和他们对应的模块的类型可以分为以下5种:系统级(system);算法级(algorithmic);RTL级(register-transfer-level);门级(gate-level);开关级(switch-level);系统级、算法级、RTL级是属于行为级的,门级的属于结构级。
#time –>(事件名)//表示等待time个时间单位后,立即触发事件。
(2) 如何编写和验证简单的纯组合逻辑模块
(3) 复杂数字系统的构成
组合逻辑:组成逻辑是由与、或、非门组成的网络。时序逻辑:时序逻辑是由多个触发器和多个组合逻辑块组成的网络,常用的有计数器、复杂的数据流动控制逻辑运算控制逻辑、指令
分析
定性数据统计分析pdf销售业绩分析模板建筑结构震害分析销售进度分析表京东商城竞争战略分析
和操作控制逻辑。
同步时序逻辑是指表示状态的寄存器组的值只可能在唯一确定的触发条件发生时刻改变,只能由时钟的正跳沿或是负跳沿触发的状态机就是一例。异步时序逻辑是指触发条件由多个控制因素组成,任何一个因素的跳变都可以引起触发。采用同步时序逻辑时为确保下一个状态所使用的组合电路的延迟小于一个时钟周期的宽度,应注意以下2点:全局时钟网络布线时尽量使各分支的时钟一致;采用平衡树结构,在每一级加入缓冲器,使到达每个触发器时钟端得时钟同步。
(4) 同步状态机的原理、结构和设计
如果时序逻辑的输出不仅取决于状态还取决于输出,这样的状态机为Mealy状态机;如果输出只取决于当前状态,跟输入没有关系,则这样的状态机为Moore状态机。
对于用FPGA实现的有限状态机建议采用独热码,因为虽然独热码对用了2个触发器,但所有组合电路可省一些,因而是电路的速度和可靠性有显著提高,而总的单元数并无显著增加,采用独热码后出现多余的状态,为此在case语句的最后需增加default分支项。
把状态码的指定与状态机控制的输出联系起来,把状态的变化直接用作输出,这样做可以提高输出信号的开关速度并节省电路器件,这种设计方法常用于高速状态机中。
在比较复杂的状态机设计过程中,我们往往把状态的变化与输出开关的控制分成2部分来考虑,为调试的方便,还常常把每个输出开关写成一个个独立的always模块。
有限状态机设计的一般步骤:逻辑抽象,得出状态转换图;状态简化;状态分配;选定触发器的类型;按照方程得出逻辑图。
逻辑抽象,得出转换图就是把给出的一个实际逻辑关系表示为时序逻辑函数,可以用状态转换表来描述,也可以用状态转换图来描述这就需要分析给定的逻辑问题,确定输入变量、输出变量以及电路的状态数,通常是取原因(或是条件)作为输入变量,取结果作为输出变量;定义输入、输出逻辑状态的含义,并将电路状态顺序编号。
(5) 设计可综合的状态机的指导原则
因为现在绝大多数的FPGA内部的触发器比较多,设计时往往蚕蛹独热码状态机,建议采用case、casex或casez来建立状态机模型,不要忘记 写上case语句的最后一个分支default,并将状态变量设为‘bx,这就等于告知综合器:case语句已经制定了所有的状态,使得生成的电路简介。如果不将default分支设为‘bx,而是设为某一确定的状态,会使模型综合后和综合前的仿真结果不一致,但可以避免死锁现象。
状态机应该有一个异步或是同步复位端,以便在通电时将硬件电路复位到有效状态,也可以在操作中将硬件电路复位。目前大多数综合器不支持在一个always模块中由多个事件触发的状态机,为了能综合出有效的电路,状态机应该由唯一的时钟触发。如果设计必须有不同的时钟触发的状态机,可以编写另一个模块,在那个模块中采用另外一个时钟,然后用实例引用的方法在另外一个模块中把他们连接起来为了调试比较容易,应该尽量使这两个状态机的时钟有一定的关系。
异步状态机是没有确定时钟的状态机,它的状态转移不是由唯一的时钟跳变沿所触发。千万不要使用综合工具来设计异步状态机,因为目前大多数的综合工具在对异步状态机进行逻辑优化时会胡乱地简化逻辑,使综合后的异步状态机不能正常工作,如果一定要设计异步状态机,建议采用电路图输入的方法,或用实例引用的写法把几个引用 的实例用异步时钟连接起来,而不要直接用VerilogRTL级别的描述方法通过综合产生。
综合的一般原则:综合之前一定要做仿真这是因为仿真会暴漏逻辑错误,在每一次布局布线后都要进行仿真,异步状态机避免用综合器来设计,如果要为电平敏感的锁存器建模,使用连续的赋值语句是最简单的方法。
每个always块只能有一个事件控制,而且要紧跟在always后面;always块可以表示时序逻辑或者是组合逻辑,也可以用always块既表示电平敏感的透明锁存器又同时表示组合逻辑,但是不推荐使用这种描述方法,因为这容易产生错误和多余的电平敏感的透明锁存器;每个表示时序的always模块只能由一个时钟跳变沿触发,职位或复位最好也由该时钟跳变沿触发;每个always块中赋值的信号都必须定义成reg型或整型;always模块中应该避免组合反馈回路,每次执行always块时,在生成组合逻辑的always块中赋值的所有信号必须有明确的值,否则,需要设计者在设计中加入电平敏感的锁存器来保持赋值前的最后一个值,只有这样,综合器才能正常生成电路,如果不这样,综合器会发出警告,提示设计中插入了锁存器,如果设计中当综合器认为不是电平敏感锁存器的组合回路时,综合器会发出错误信息。
input a,b,c;
reg e,d;
always @(a or b or c)
begin
e=d&a&b;/*d没有在敏感电平列表中,所以d变化时,e不能立即变化,要等到a或b或c变化时才体现出来。这就是说,实际上相当于存在一个电平敏感的透明锁存器在起作用,把d信号的变化所存其中*/
d=e|c;
end
对一个寄存器型和整型变量给定位的赋值,只允许在一个always块内进行,如在另一个always块中也对其赋值,这是非法的。把某一信号赋值为‘bx,综合器就把它解释成无关状态,因而综合器为其生成的硬件电路最简洁。
状态机的同步置位和复位只有在时钟的有效跳变沿时刻,为避免每次置位和复位都能有效的完成,置位和复位的电平维持时间必须大于时钟沿的间隔时间。
(6) 深入理解阻塞和非阻塞赋值的不同
RHS-方程式右手方向的表达式或变量可分别缩写为RHS表达式或RHS变量
LHS-方程式左手方向的表达式或变量可分别缩写为LHS表达式或LHS变量
IEEE-Verilog
标准
excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载
定义了有些语句有明确的执行时间,有些语句没有确定的执行时间。若有两条或两条以上语句准备在同一时刻执行,但由于语句的排列顺序不同(而这两种不同是IEEE-Verilog标准允许的),却产生了不同的输出结果,这就是造成Verilog模块冒险和竞争现象的原因。
阻塞赋值的执行可以认为是只有一个步骤的操作,即计算RHS并更新LHS,且不能允许有来自任何其他Verilog语句的干扰,所谓阻塞的概念是指在同一个always块中,其后面的赋值语句从概念上(即使不设定延时)是在前一句赋值语句结束后再开始赋值。一般可综合的阻塞赋值操作在RHS不能设定有延时(即使是零延时也是不允许的)。如果在一个过程中阻塞赋值的RHS变量正好是另一个过程块中阻塞赋值的LHS变量,这两个过程块又用同一个时钟沿触发,这时阻塞赋值操作会出现问题。
非阻塞赋值操作只能用于对寄存器类型变量进行赋值,因此只能用在“initial”块和“always”块等过程块中,而非阻塞赋值不能允许用于连续赋值。
Verilog模块编程要点:时序电路建模,用非阻塞赋值;锁存器电路建模时,用非阻塞赋值;用always块建立组合逻辑模型时,用阻塞赋值;在同一个always块建立时序和组合逻辑电路时,用非阻塞赋值;在同一个always块中不要既用非阻塞赋值又用阻塞赋值;不要在一个以上的always模块中为同一个变量赋值;用$strobe系统任务来显示用非阻塞赋值的变量值;在赋值时不要使用#0延迟。
层次化事件队列在逻辑上分为用于当前仿真时间的4个不同的队列,和用于下一段仿真时间的若干个附件队列。(1)动态事件队列:阻塞赋值,计算非阻塞赋值语句右边的表达式,连续赋值,执行$display命令,计算原语的输入和输出的变化。(2)停止运行的事件队列:#0延时阻塞赋值。(3)非阻塞事件队列:更新非阻塞赋值语句LHS的值(4)监控事件队列:执行$monitor命令,执行$strobe命令。(5)其他指定的PLI命令队列。
采用#0延时的赋值时因为对Verilog理解不够深入的设计人员希望在两个不同的程序块中给同一个变量赋值,他们企图在同一个仿真时刻,通过稍加延时赋值来消除Verilog可能产生的竞争冒险,这样做实际上会产生问题,因为给Verilog模型附加完全不必要的#0延时赋值,使得定时时间的分析变得很复杂。Verilog 标准定义了在同一个always块中,可以对同一变量进行多次非阻塞赋值,却在多次赋值中,只有最后一次赋值对该变量其作用。
(7) 较复杂时序逻辑电路设计实践
一个简单的状态机-序列检测器。