导引
一个简单的.v程序(与非门的实现):
module nand2_ex1(A,B,F); //定义2输入与非门电路模块nand2_ex1
input A,b; //A、B为输入端口
output F; //F为输出端口
nand inst1(F, A, B);//调用Verilog内部预定义的门级源语nand
endmodule
计算机语言的是本着与计算机交流、让计算机完成工作,而Verilog语言的功能使用常量、变量、运算符、语句、模块、功能等来描述数字电路。
Verilog的特点:
- 逻辑控制+时间控制
- 与电路紧密结合
- 标识清晰(xxx.v文件;以module为基本单位)
编写Verilog |
Verilog文件 |
做电路仿真 | 仿真命令脚本、仿真结果报告 |
编写Verilog = Module的声明 + Module的定义,其中Module的定义是主要的工作。
一、关于Module
Module的角色:
1、电路描述的基本完整单元(完整性、唯一性)。唯一性,即一个项目必须有且只能有一个顶层module。
2、电路的蓝图(重用性),module可以生成instance到其它的module当中。
Module的声明
-
关键字module+名字
module name;
Module的定义
-
位于声明之后
-
以endmodule结束
module name;
......
endmodule
二、基本语法
1、标识符
标识符用于表示电路系统中的模块、寄存器、输入\输出端口、连线等物理对象的名字。
标识符构成:一组字母、数字以及符号“$”和下划线“_”的组合。
关键字不能用作标识符,
例如:if,always,input,output,or....…,但是,IF(大写的关键词)是合法标识符
空格,制表符(table),换行符(enter),操作符:+,-,*,/,~!0等等
PS:首字母必须是字母或下划线 !!!
标识符区分大小写:ab、AB是两个标识符
标识符可以以“\”开头,以空白符结尾的任何字符组成的转义标识符。
\8_data”定义了一个转义标识符,
“\reg_out”和“reg_out”是一样的标识符
三、常量:整数型、实数型、字符串数据
1.整数型数据
表示:+/- <位宽> ' <进制符号> <数值>
8'b010110
4hE(十六进制a到f不区分大小写)、8'Hz
5'D25、6′070
8’B1x_00001//下划线本身无意义
PS:可以在位宽与’之间、进制与数值之间出现空格,但’和进制、数值之间不能出现空格
2、实数型数据
- 实数型数据可以用十进制方式表示,如2.55、4.23、10.0等。小数点后的数字不能省略;
- 实数型数据可以用科学计数法表示:如1.0E4
3、字符串数据
- 用双引号引出的字符序列,如"HELLO!WORLD!"
4、parameter型
- 用来定义一个标识符表示常量
- 格式:parameter 参数名1=表达式, 参数名2=表达式…
例:parameter sb=500/2; (注意,sb必须为合法的标识符)
四、变量表示
变量类型:wire、reg、memory。
1、Wire型变量
Wire型变量相当于组合逻辑电路中的各种连线,输出的值紧随输入值的变化而变化,不能暂存。
一般的,输入/输出信号类型默认为wire型。模块中引用实例原件的输出信号变量以及用“assign”语句赋值的变量,也都定义为wire型。
wire型变量定义格式:
- wire 信号名1,信号名2,…;口多位数据线(地址总线,数据总线等):
- wire[n-1:0] 信号名1,信号名2,…;
例如:
wire[7:0] data; /*说明一个8位数据总线data为wire型*/
wire[31:0] adder; /*说明一个32位地址总线adder为wire型*/
2、reg寄存器型变量
格式:
reg 信号名1, 信号名2 … ;
reg[n-1:0] 信号名1, 信号名2,… ;
PS:reg型初值默认为不定值x。reg数据类型定义的信号必须放在过程块(如always,initial)中,通过过程赋值语句赋值。
3、memory型变量
- 格式:reg[n-1:0] 存储器名 [m-1:0] ;
例如:reg[7:0] memory1 [255:0];
要对memory1中的存储器单元进行读写操作,必须指定地址:memory1[10]=168;
一个变量赋值例子
module test;
wire clk;
reg [7:0] result;
wire [31:0] temp;
endmodule
4、Verilog赋值语句
- assign(连续赋值)
assign连续赋值语句一般用来描述组合逻辑电路,用于给网线型wire变量赋值。
assign连续赋值语句用右端表达式所推导出来的逻辑来驱动赋值语句左端的连接线变量。
语法:assign wire型变量=表达式;
例如:
assign f=~(a&b); //f=a·b
assign f=~s&p0ls&~p1; //f=s-pO+s-p1
5、"?:"条件操作符
语句口使用条件操作符的语法格式如下:口条件表达式?表达式1:表达式2口条件操作符的运算过程如下:如果条件表达式的值为1(即为真),则运算后的结果取表达式1的值,否则取表达式2的值。
例:aassign F = (S==1'b0) ? P0 : P1
五、Verilog的数据运算
(1)算术运算符(+、一、×、/、%)
(2)关系运算符(<、>)
(3)等式运算符(==、!=)(4)逻辑运算符(&&、|、!)
(5)位运算符(~、&、|)
(6)缩位运算符
(7)移位运算符(>>、<<)
(8)条件运算符(?:)
位运算符号
“~^”、 “^~” 即:按位同或。不同长度的数据进行位运算时,会自动地将两个操作数在右端对齐,位数少的操作数会在高位用0补齐。
缩位运算符
变量A=8'10010001
&A=0;//1和0相与=0、0和0相与=1、0和1相与=0、···,只有A缩位运算后的所有位都为1时,缩位与运算的结果才为1
|A=1;//只有A的所有位都为0时,缩位或运算的结果才为0
^A=1;
左移”<<”与右移”>>”
例:
A=4'b1101,则“A>>2”运算后A=4'b0011(将A右移2位,用0补全移出的位)
A=4'b1010,则”A<<2”运算后A=4'b1000(将A左移2位,用0补全移出的位)
位拼接运算符“{}”
{信号1的某几位,信号2的某几位,…,信号n的某几位}
output[3:0] sum;
output cout;
input[3:0] ina, inb;
input cin;
assign {cout,sum} = ina+inb+cin;
位拼接可以嵌套使用:
{3{a, b}} = {a, b}, {a,b}, {a,b} = {a,b,a,b,a,b};
六、2选1数据选择器的实现
方案①:
assign f=~s&p0|s&~p1;
方案②:
wire not_s,andcntrl1,andcntrl2;
not U1(not_s,s);
and U2(andcntrl1,PO,not_s), U3(andcntrl2,P1,s);
or U4(f,andcntrl1,andcntrl2);
方案③:
reg f;
always@(p0 or p1 or s)
begin
if(s==1'b0)
f<=po;
else
f<=p1;
end
1、条件语句
if条件语句分为:基本if语句、if-else语句、if-else-if语句、嵌套if-else语句
case条件语句,有三种表示方式:case、casez 和 casex
1.case语句
2、casez和 casex 语句
首先,casez和casex,是case语句的变种。
- casez:表达式的值出现z,那么对这些位的比较不予考虑,只需关注其它位的比较结果。
- casex:表达式的值出现x或z,那么对这些位的比较都不予考虑。
2、 四种循环语句
- 1、for语句
for(循环变量赋初值; 循环条件; 修改循环变量)
循环语句
PS:只在复制电路的时候才使用for循环
- 2、repeat语句
repeat(循环次数表达式)
begin
语句组;
end
reg[8*11:1] f;
parameter time1=520;
repeat(time1)
begin
f="I LOVE YOU!";
end
- 3、while语句
//while语句模板
while(循环执行条件表达式)
begin
循环体语句组;
end
一个有趣的例子,请欣赏:
while(money>0)
begin
if(day==11)
begin
wallet=salary-500;
end
- 4、forever 语句
forever
begin
循环语句;
end
forever循环语句连续不断地执行后面的语句或语句块,常用来产生周期性的波形,作为仿真测试信号。
3、 Verilog过程及译码电路
Verilog过程语句有always过程语句以及initial过程语句这两种。
1、always语句
always语句定义的过程块是一个电路,电路从上电开始就会一直执行;(类似于我们的while(1))
"电路从上电开始就会一直执行",从代码一开始就执行,执行完了再回到过程块的最初来执行,周而复始,不会停止,直到代码执行完毕
2、initial语句
initial块从仿真0时刻开始执行,在整个仿真过程中只执行一次。如果一个模块中包括了若干个initial块,则这些initial块从仿真0时刻开始并发执行,且每个块的执行是各自独立的。
如果有任何错误的地方,还望评论区下指正!谢谢!