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语句有文件顺序
文章评论(0条评论)
登录后参与讨论