原创 Verilog HDL学习笔记(1)

2010-4-17 13:19 2022 0 分类: FPGA/CPLD

Verilog HDL学习笔记(1


基本语法


************************************


? 系统级(system):用高级语言结构实现设计模块的外部性能的模型。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


? 算法级(algorithm):用高级语言结构实现设计算法的模型。


? RTL级(Register Transfer Level):描述数据在寄存器之间流动和如何处理这些数据的模型。


? 门级(gate-level):描述逻辑门以及逻辑门之间的连接的模型。


? 开关级(switch-level):描述器件中三极管和储存节点以及它们之间连接的模型。


************************************


模块:


模块名与文件名同名;


原则上一个模块一个文件;


尽量考虑参数化,提高重用;


除了endmodule语句外,每个语句和数据定义的最后必须有分号。


*******************************************


模块的内容:


包括IO说明、内部信号声明和功能定义。


IO说明:module 模块名(in1,in2,out1,out2);


                     input in1,in2;


                     output out1,out2;


             


              module 模块名(input in1,input in2,output out1,output out2);


内部信号声明:wire 和 reg


功能定义:用“assign”声明


            用实例元件


            always


    * 并行执行 顺序执行


****************************


数据类型


       基本数据类型:reg型、wire型、integer型、parameter型


**********************


变量


       数字:


8'b10101100 //位宽为8的数的二进制表示, 'b表示二进制


8'ha2 //位宽为8的数的十六进制,'h表示十六进制。


4'b10x0 //位宽为4的二进制数从低位数起第二位为不定值


4'b101z //位宽为4的二进制数从低位数起第一位为高阻值


12'dz //位宽为12的十进制数其值为高阻值(第一种表达方式)


12'd? //位宽为12的十进制数其值为高阻值(第二种表达方式)


8'h4x //位宽为8的十六进制数其低四位值为不定值


-8'd5 //这个表达式代表5的补数(用八位二进制数表示)


8'd-5 //非法格式


16'b1010_1011_1111_1010 //下划线仅仅为了提高可读性


    参数:


parameter msb="7"; //定义参数msb为常量7


parameter e="25", f="29"; //定义二个常数参数


parameter r="5".7; //声明r为一个实型参数


parameter byte_size=8, byte_msb=byte_size-1; //用常数表达式赋值


parameter average_delay = (r+f)/2; //用常数表达式赋值


 


[例1]:在引用Decode实例时,D1,D2的Width将采用不同的值4和5,且D1的Polarity将为0。可用例


子中所用的方法来改变参数,即用 #(4,0)向D1中传递 Width="4",Polarity=0; 用#(5)向D2中传递


Width=5,Polarity仍为1。


module Decode(A,F);


parameter Width="1", Polarity="1";


……………


endmodule


 


module Top;


wire[3:0] A4;


wire[4:0] A5;


wire[15:0] F16;


wire[31:0] F32;


Decode #(4,0) D1(A4,F16);


Decode #(5) D2(A5,F32);


Endmodule


[例2]:一个多层次模块构成的电路,在一个模块中改变另一个模块的参数时,需要使用


defparam命令


Module Test;


wire W;


Top T ( );


emdmodule


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 [7:0] b; //定义了一个八位的wire型数据


reg [3:0] regb; //定义了一个四位的名为regb的reg型数据


reg [7:0] mema [n-1:0]; //一个由n个8位寄存器构成的存储器组


***************************************


运算符及表达式


1) 算术运算符(+,-,×,/,%)


2) 赋值运算符(=,<=)


3) 关系运算符(>,<,>=,<=)


4) 逻辑运算符(&&,||,!)


5) 条件运算符(?


6) 位运算符(~,|,^,&,^~)


7) 移位运算符(<<,>>)


8) 拼接运算符({ })


9) 其它


<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />


**************************************


赋值语句


(1).非阻塞(Non_Blocking)赋值方式( 如 b <= a; )


1) 块结束后才完成赋值操作。


2) b的值并不是立刻就改变的。


3) 这是一种比较常用的赋值方法。(特别在编写可综合模块时)


(2).阻塞(Blocking)赋值方式( 如 b = a; )


1) 赋值语句执行完后,块才结束。


2) b的值在赋值语句执行完后立刻就改变的。


3) 可能会产生意想不到的结果。


非阻塞赋值方式和阻塞赋值方式的区别常给设计人员带来问题。问题主要是给"always"块内的reg型


信号的赋值方式不易把握。到目前为止,前面所举的例子中的"always"模块内的reg型信号都是采用下面的这种赋值方式:


b <= a;


这种方式的赋值并不是马上执行的,也就是说"always"块内的下一条语句执行后,b并不等于a,而是保持原来的值。"always"块结束后,才进行赋值。而另一种赋值方式阻塞赋值方式,如下所示:


b = a;


这种赋值方式是马上执行的。也就是说执行下一条语句时,b已等于a。尽管这种方式看起来很直观,


但是可能引起麻烦。下面举例说明:


[例1]:always @( posedge clk )


begin


b<=a;


c<=b;


end


[例1] 中的"always"块中用了非阻塞赋值方式,定义了两个reg型信号b和c,clk信号的上升沿到来时,b就等于a,c就等于b,这里应该用到了两个触发器。请注意:赋值是在"always"块结束后执行的,c应为原来b的值。



[例2]: always @(posedge clk)


begin


b=a;


c=b;


end


[例2]中的 "always"块用了阻塞赋值方式。clk信号的上升沿到来时,将发生如下的变化:b马上取a的值,c马上取b的值(即等于a),生成的电路图如下所示只用了一个触发器来寄存器a的值,又输出给b和c。这大概不是设计者的初衷,如果采用[例1]所示的非阻塞赋值方式就可以避免这种错误。



********************************


块语句


[例1]:


begin


areg = breg;


creg = areg; //creg的值为breg的值。


end


[例2]:


fork               //fork为并行块,语句没有顺序关系,同时执行


#50 r = 'h35;


#100 r = 'hE2;


#150 r = 'h00;


#200 r = 'hF7;


#250 -> end_wave; //触发事件end_wave.


join


*****************************************************


if语句


case语句


forever语句


repeat语句


while语句


for语句


4种结构说明语句


Verilog语言中的任何过程模块都从属于以下四种结构的说明语句。


1) initial说明语句


2) always说明语句


3) task说明语句下面的例子说明怎样定义任务和调用任务:


任务定义:


task my_task;


input a, b;


inout c;


output d, e;



<语句> //执行任务工作相应的语句



c = foo1; //赋初始值


d = foo2; //对任务的输出变量赋值t


e = foo3;


endtask


任务调用:


my_task(v,w,x,y,z);


任务调用变量(v,w,x,y,z)和任务定义的I/O变量(a,b,c,d,e)之间是一一对应的。当任务启动时,由v,w,和x.传入的变量赋给了a,b,和c,而当任务完成后的输出又通过c,d和e赋给了x,y和z。下面是一个具体的例子用来说明怎样在模块的设计中使用任务,使程序容易读懂:


module traffic_lights;


reg clock, red, amber, green;


parameter on="1", off="0", red_tics=350,


amber_tics=30,green_tics=200;


//交通灯初始化


initial red="off";


initial amber="off";


initial green="off";


//交通灯控制时序


always


begin


red=on; //开红灯


light(red,red_tics); //调用等待任务


green=on; //开绿灯


light(green,green_tics); //等待


amber=on; //开黄灯


light(amber,amber_tics); //等待


end


//定义交通灯开启时间的任务


task light(color,tics);


output color;


input[31:0] tics;


begin


repeat(tics) @(posedge clock);//等待tics个时钟的上升沿


color=off;//关灯


end


endtask


//产生时钟脉冲的always块


always


begin


#100 clock="0";


#100 clock="1";


end


endmodule


这个例子描述了一个简单的交通灯的时序控制,并且该交通灯有它自己的时钟产生器。


 


4) function说明语句


下面的例子中定义了一个可进行阶乘运算的名为factorial的函数,该函数返回一个32位的寄存器类型的值,该函数可后向调用自身,并且打印出部分结果值。


module tryfact;


//函数的定义-------------------------------


function[31:0]factorial;


input[3:0]operand;


reg[3:0]index;


begin


factorial = operand? 1 : 0;


for(index=2;index<=operand;index=index+1)


factorial = index * factorial;


end


endfunction


//函数的测试-------------------------------------


reg[31:0]result;


reg[3:0]n;


initial


begin


result=1;


for(n=2;n<=9;n=n+1)


begin


$display("Partial result n= %d result= %d", n, result);


result = n * factorial(n)/((n*2)+1);


end


$display("Finalresult=%d",result);


end


endmodule//模块结束


************************************************


系统函数和任务


$bitstoreal, $rtoi, $display, $setup, $finish, $skew, $hold,


$setuphold, $itor, $strobe, $period, $time, $printtimescale,


$timefoemat, $realtime, $width, $realtime$random,$stop,$readmemb,


$readmemh,$write, $recovery,


***********************************************************


编译预处理


`accelerate,`autoexpand_vectornets,`celldefine,`default_nettype,`define,`else,`endcelldefine,`endif,`endprotect,`endprotected,`expand_vectornets,`ifdef,`include,`noaccelerate,`noexpand_vectornets , `noremove_gatenames , `noremove_netnames ,`nounconnected_drive , `protect , `protecte , `remove_gatenames , `remove_netnames ,`reset,`timescale,`unconnected_drive


 


‘include语句有文件顺序


 


 


 


 

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
0
关闭 站长推荐上一条 /3 下一条