verliog hdl语法要点
一、常用的数据类型
1.四种常用的数据类型
reg,wire,integer,parameter
2.常量
(1)数字
A.整数
1)B或b--二进制整数
2)D或d--十进制
3)H或h--十六进制
4)O或o--八进制
例子:
11'b00000000000
注意:*位宽可省略,位宽由机器指定
*进制也可省略,<数字>---默认是十进制
parameter READFLAG =11'b00100000000; //
parameter WRITERAM =11'b01000000000; //写RAM
parameter READRAM =11'b10000000000; //读RAM
parameter cur_inc =1;
parameter cur_dec =0;
parameter cur_shift =1;
SETMODE :begin lcd_rs<=0;lcd_rw<=0;data[7:2]<=6'b000001;data[1]<=cur_inc;data[0]<=cur_noshift;
B.x和z值,x--不定值,z-高阻值
data<=8'bzzzz_zzzz;
C.负值的写法
-8'd5 (正确)
8'd-5 (错误)
D.下划线
8'b0100_1100
8'b01001100
上面的两个值一样,加下划线为增加可读性
8'b_0100_1100 (错误)
(2)参数
parameter 参数名1=表达式1,参数名2=表达式3;
4.变量
reg[3:0] dataout_buf[3:0];
reg[3:0] dataout_code;
integer i;
wire[7:0] cal;
assign cal[0]=(dataout_buf[0]==9)?1:0; //个位向十位进位标志
assign cal[1]=(cal[0]&&dataout_buf[1]==9)?1:0;//十位向百位进位标志
assign cal[2]=(cal[1]&&dataout_buf[2]==9)?1:0;//百位向千位进位标志
assign cal[3]=(cal[2]&&dataout_buf[3]==9)?1:0;//千位向万位进位标志
(1)存储器型变量
reg[3:0] dataout_buf[5:0]; //dataout_buf--存储器名,[5:0]--存储器的个数,[3:0]--每个存储器的位宽
注意存储器可单个使用。
(2)网络型变量:
常用的有两种:wire,tri(三态)
(3)寄存器变量
寄存器是数据存储单元的抽象。寄存器变量,通过赋值语句可以改变寄存器存储的值。
二、常用的运算符
1.重点:
(1)三目运算
r=s?t:u;//可形成一个条件语句
(2)取反
3'b001: begin //发“来”
cnt<=cnt+1;
if(cnt==22'h3fffff)
state<=3'b010;
if(clk_div2!=lai)
clk_div2<=clk_div2+1;
else begin
clk_div2<=0;
out<=~out;
end
(3)位拼接运算符--{}
1)可以把两个或多个信号的某些位拼接起来进行运算操作。
2)格式:
{信号1的某几位,信号2的某几位,...,信号n某几位}
dial[7:0]={led[7],led[6],....,led[0]};
dial[7]=led[7];
dial[6]=led[6];
..........
dial[0]=led[0];
dial[7:0]={led[7:4],....,led[0]};
3)具有重要参考价值的拼接方式:
{a,b[3:0],w,3'b101};//不同位宽的变量和整数值一起可以拼接成一个新的变量
{a,b[3],b[2],b[1],b[0],w,1'b1,1'b0,1'b1};
注意:
A.dial[7:0]=led[7:0] //注意的做不到每个控制每个led灯
B.{4{w}}={w,w,w,w}
C.{b,{3(a,b)}}={b,a,b,a,b,a,b}
(4)缩减运算符---是单目运算,与、或、非运算
1)先将操作数的第一位与第二位进行与或非运行
2)将运算结果与第三位进行与、或、非运算,直至最后一位。
使用方法:
reg [3:0] B;
reg C;
C= &B;
相当于:
C=((B[0]&B[1])&B[2])&B[3];
三、块语句
1.常用的是两种语句块:
begin ...end--顺序块
fork....join---并行块
2.顺序块
(1)语句按顺序执行
(2)每条语句的延迟时间是相对与前一条语句的仿真时间而言。
(3)顺序块里加延时
例子:
begin:块名
areg=breg;
#10 creg=areg;
areg=dreg;
end
注意:在顺序执行的begin...end,非阻塞赋值,可以把顺序执行改变成近于并发执行。
3.并行块
(1)块内的语句同时执行
(2)块内每条语句的延迟时间是相对于程序控制进入到块内的仿真时间。
fork
#50 r ='h35;
#100 r='hE2;
join
注意:通过上面的方式,变成顺序执行。
四、条件语句
(一)if语句的形式
(1)无分支--if
if (a>b)
out1<=int1;
(2)单级分支--if...else
if(a>b)
out1<=int2;
else
out1<=int1;
(3)多级分支
if (表达式1) 语句1;
else if (表达式2) 语句2;
else if (表达式3) 语句3;
else 语句n;
(二)注意:
1.当表示条件的表达式的值为1时,按真处理;
表达式的值为0,x,z按假处理
if(a) out1<=int2;
2.if语句的嵌套
if(expression)
begin
if(expression2) 语句1 (内嵌if)
else 语句2
end
else if (expression3) 语句3 (内嵌if)
else 语句4
注意:if和离它最近的else配对,为防止混乱和增加可读性,
可以用begin_end来区隔。
若begin_end使用不当可改变逻辑关系:
例子:
if(index>0)
for(scani=0;scani<index;scani=scani+1)
if(memory[scani]>0) begin
$display("...");
memory[scani]=0;
end
else
$display("error");
五、Case语句
(一)状态机
1.parameter state0=3'b000,
state1=3'b001, //mealy状态机,其参数的位数非常灵活
state2=3'b010,
state3=3'b011,
state4=3'b100,
state5=3'b101,
state6=3'b110,
state7=3'b111;
注意:状态机需要声明上面的连续的数值
2.和case语句配合使用
always@(state)
begin
case(state)
state0:
c=8'b0000_0011;
state1:
c=8'b1001_1111;
state2:
c=8'b0010_0101;
state3:
c=8'b0000_1101;
state4:
c=8'b1001_1001;
state5:
c=8'b0100_1001;
state6:
c=8'b0100_0001;
state7:
c=8'b0001_1111;
endcase
end
3.也可以选择的执行
CLEAR :begin lcd_rs<=0;lcd_rw<=0;data<=8'b0000_0001;
state<=SETMODE;end
SETMODE :begin lcd_rs<=0;lcd_rw<=0;data[7:2]<=6'b000001;data[1]<=cur_inc;data[0]<=cur_noshift;
state<=SETDDRAM1;end
RETURNCURSOR :begin lcd_rs<=0;lcd_rw<=0;data<=8'b00000010;
state<=WRITERAM;end
SWITCHMODE :begin lcd_rs<=0;lcd_rw<=0;data[7:3]<=5'b00001;data[2]<=open_display;data[1]<=open_cur;data[0]<=blank_cur;
state<=CLEAR;end
SHIFT :begin lcd_rs<=0;lcd_rw<=0;data[7:4]<=4'b0001;data[3]<=shift_display;data[2]<=left_shift;data[1:0]<=2'b00;
state<=IDLE;end
SETFUNCTION :begin lcd_rs<=0;lcd_rw<=0;data[7:5]<=3'b001;data[4]<=datawidth8;data[3]<=twoline;data[2]<=font5x10;data[1:0]<=2'b00;
state<=SWITCHMODE;end
SETCGRAM :begin lcd_rs<=0;lcd_rw<=0;data<=8'b01000000;state<=IDLE;end
SETDDRAM1 :begin
lcd_rs<=0;
lcd_rw<=0;
state<=WRITERAM;
if(counter==0)
data<=8'b1000_0000;
else
data<=8'b1100_0000;
end
SETDDRAM2 :begin lcd_rs<=0;lcd_rw<=0;data<=8'b10000000;state<=WRITERAM;end//0x80显示在第一行
4.简化程序,调用语句块更加简洁
always@(count)
begin
case (count)
0: state=4'b1111; //低音“3”
1: state=4'b1111; //持续4 个时钟节拍
2: state=4'b1111;
3: state=4'b1111;
4: state=4'b0000; //低音“5”
5: state=4'b0000; //发3 个时钟节拍
6: state=4'b0000;
7: state=4'b0001; //低音“6”
8: state=4'b0011; //中音“1”
9: state=4'b0011; //发3 个时钟节拍
10: state=4'b0011;
end
(二)一般有3种形式
(1)case (表达式) <case 分支项> default <表达式> endcase
(2)casez (表达式) <case 分支项> endcase
(3)casex (表达式) <case 分支项> endcase
注意:
1..每个分支表达式的值必须互不相同,否则出错
2..在用case语句进行比较时,只有信号的值明确才能比较。
3..case语句所有表达式的值的位宽必须相等,一个经常犯的错误是,用'bx,'bz来代替n'bx,n'bz
4.当分支表达式中存在不定值x和高阻值z时,处理方法如下:
5.两种特殊case语句的处理方法:
例子一:
六、循环语句
(一)循环语句的类型
(1)forever:连续的执行语句
(2)repeat:连续执行一条语句n次
(3)while:执行一条语句直到条件不满足
(4)for:执行一条语句直到条件不满足
(二)分别介绍:
1. forever语句:
格式:
forever begin
end
2.repeat:
格式:
repeat (表达式) begin
end
3.while:
格式:
while(表达式) 语句
或
while(表达式) begin
多条语句;
end
4.for:
for(表达式1--给循环的变量赋初值;表达式2--结束条件;表达式3--变量的增加方式) 语句
例子:
for(scani=0;scani<index;scani=scani+1)
begin
语句;
end
函数和任务
一、函数:
(一)格式
function [位宽] <函数名称>
<函数参数声明>--一般是声明输入
........
语句区
endfunction
例子:
function [7:0] ddram;
input [5:0] n;
begin
case(n)
6'b000_000:ddram=8'b01001100; //L
6'b000_001:ddram=8'b0110_1001; //i
6'b000_010:ddram=8'b0110_0011; //c
6'b000_011:ddram=8'b0110_1000; //h
6'b000_100:ddram=8'b0110_0101; //e
6'b000_101:ddram=8'b0110_1110; //n
6'b000_110:ddram=8'b0100_1100; //L
6'b000_111:ddram=8'b0110_1001; //i
6'b001_000:ddram=8'b0110_0011; //c
6'b001_001:ddram=8'b0110_1000; //h
6'b001_010:ddram=8'b0110_0101; //e
6'b001_011:ddram=8'b0110_1110; //n
endcase
end
endfunction
调用函数:
data<=ddram(address);
address<=address+1;
注意:
1。函数的输出一般是函数名,要指定位宽
2.参数声明部分parameter,input,reg,integer,real,time等声明
二、任务
1。格式
task <任务名称>
<参数声明>
.........
语句区
endtask
2.注意:
(1)任务允许多个输出,函数只允许一个输出
(2)任务可以调用函数,函数不能调用任务
三、任务和函数,任务和任务间的调用
1.任务和函数,任务和任务间的调用
2.函数之间的调用
例子:
系统函数和任务
一、系统函数和任务所用的关键字
二、与实数有关的系统函数与任务
(1)$bitstoreal--将位数据转成实数,与$realtobits互为反函数
格式:
$bitstoreal(b);//b为位数据
(2)$itor--将整数数据转成实数,与$rtoi互为反函数
$itor(I) //I为整数
(3)$realtobits--将实数数据转成64位的位数据
(4)$rtoi--以截尾方式将实数数据转成整数
$rtoi(r);//r为实数数据
三、显示与写入任务
显示函数的格式:
$display(<系统函数>,“字符串与格式”,<输入/输出端口的名称>)
$write(<系统函数>,“字符串与格式”,<输入/输出端口的名称>)
四、驱动器计数系统函数
作用:为设计者提供计算某特定线路上有多少驱动器。
格式:
$countdriver(net,net_is_forced,number_of_01x_drivers,number_of_0_drivers,
number_of_1_drivers,number_of_x_drivers);
参数解释:
net_is_forced--若线路被驱动,则回复为1;否则回复为0
number_of_0_drivers--回复一整数以指示在线路上状态为0态的驱动器个数
number_of_01x_drivers--回复一整数以指示状态为0,1,及x的驱动器个数
number_of_1_drivers--回复一整数以指示状态为1的驱动器个数
number_of_x_drivers--回复一整数以指示状态为x的驱动器个数
五、文件输出系统任务
作用:文件的输出
$fopen"<文件名称>");
$close<多信道叙述器>);
$fdisplay<多信道叙述器>,<字符串显示格式>,<变量名称>);
$fwrite<多信道叙述器>,<字符串显示格式>,<变量名称>);
$fstrobe<多信道叙述器>,<字符串显示格式>,<变量名称>);
$fmonitor<多信道叙述器>,<字符串显示格式>,<变量名称>);
六、结束执行系统任务
(1)$finish;
(2)$finish(n);
n=0 ---不打印信息
n=1 ---打印仿真时间及位置
n=2 ---打印仿真时间及位置,并且统计在仿真过程中的内存及CPU使用时间
n没有被赋值 ---默认n=1处理
七、时序检查系统任务
作用:可以让设计者在设定的区块中,验证电路的时间效能。
格式:
$setup(<数据事件>,<参考事件>,<限制范围>,<通告>);
$hold(<参考事件>,<数据事件>,<限制范围>,<限制范围>,<通告>);
$width(<参考事件>,<数据事件>,<限制范围>,<阈值>,<通告>);
$period(<参考事件>,<限制范围>,<通告>);
$skew(<参考事件>,<数据事件>,<限制范围>,<通告>);
$recovery(<参考事件>,<数据事件>,<限制范围>,<通告>);
$setuphold(<参考事件>,<数据事件>,<设定范围>,<保持限制>,<通告>);
$nochange(<参考事件>,<数据事件>,<起始边缘补偿>,<终止边缘补偿>);
数据事件--激活时序检查,且为了追踪时序违例用于被检查的信号。
参考事件--在数据事件中为了追踪时序违例所建立的参考时序。
限制范围--就设定的任务而言,在数据事件中用于检测时序违例的时间限制。
保持限制--在数事件中用于检测时序违例的时间限制。
通告------用于在时序违例发送时,通知仿真器。
起始边缘补偿---补偿值用来修正"参考事件"的起始时间,用于扩充或缩减时序违例的区间。
终止边缘补偿---补偿值用来修正"参考事件"的终止时间,用于扩充或缩减时序违例的区间
八、测试信号系统任务
作用:快速处理测试信号
$getpattern(<内存指针>);
九、加载内存系统任务
$readmemb("<文件名称>",<内存地址名称>)
十、时间刻度系统函数和任务
注意:上面的代码以编译指引语句'timescale设定时间单位为10ns,准度1/10ns,
在连续监视语句中以'timescale返回实数型时间单位。
文章评论(0条评论)
登录后参与讨论