FPGA小白学习笔记(一)--Verilog语法学习(1)
一、组合电路的verilog 描述
1.模块表达
module 模块名(模块端口名)
模块端口和模块功能描述。
endmodule
//注意 module和endmodule旁边都不加标点;所有的关键字都必须小写
2 .端口语句、端口信号名和端口模式
端口定义关键字:input、output、inout(从端口的内部看,可以对端口进行赋值或者通过此端口读出外部的数据信息;从端口的外部看,信号既可以从端口流出也可以想此端口输入信号,如RaM的数据口、单片机的i/o口等)
input 端口名1,端口2,-----;
若描述一个多信号端口或者总线端口
output [3:0] c,d;//表示一个四个位宽的输出信号
3 .赋值语句和条件操作符
关键词assign 可以引导不同的幅值语句
assign y = a;//将信号a赋给y
assign y = a & b;
4 .关键字 (module,input,output等)
5 . 标识符(identifier)
设计者在程序中自定义的,用以标志不同的名称
6.文件的存取和读盘
一般情况下,文件名可由用户任意指定,但文件的后缀扩展名必须是 .v
,考虑到调用的方便性,建议程序的文件名与模块名相同。
二、几种简单的语法分析
举例:
a,b,cd 为四个输入端口,y为输出端口;
当s1和s0取值为00、01、10、11时,输出端y分别是来自a,b,c,d的数据
图一 四选一多路选择器
1 、程序:
module MUX41a(a,b,c,d.s0.s1,y)
input a,b,c,d;
intput s0,s1;
output y; //3行为电路模块端口说明和定义段
reg y;//信号类型定义段
always @(a or b or c or d or s1 or s0)//任何一个信号变化都会起动过程语句的执行
begin :MUX41//MUX41为块名,不参与编译,故可省略
case({s1,s0})
2’b00:y<=a;
2’b01:y<=b;
2’b10:y<=c;
2’b11:y<=d;
default: y<=a;
endcase
end //电路模块功能描述段
endmodule
补充说明:
1)module 、endmodule 引出完整的电路描述
2)intput 、output 引出对模块的外部端口描述
3)以 reg等关键词定义模块内将出现的相关信号的特性和数据类型
4)[email protected]等关键词引导对模块的对模块逻辑功能的语句
2、代码语法详解
1) reg型变量定义
reg是定义寄存器类型变量的关键字,如:reg 变量1,变量2,---;
reg [msb:lsb]变量1,变量2,---;
注意:verilog中常用变量为寄存器变量(用reg定义)和网线型变量(用wire定义),默认情况为NET型,但是[email protected]引导的顺序语句必须规定为reg型变量。
2)过程语句
[email protected](敏感信号及敏感信号列表或表达式)包括块语句和各类顺序语句
//注意通常要求所有的敏感信号都写在括号内,但是不写也只会报警告信息,所以试图选择性的列入敏感信号来改变逻辑设计是无效的。
3)块语句begin_end
相当于一个括号,仅限于[email protected]引导的过程语句之中使用,通常用它来组合顺序语句,故称其为顺序块。常用格式为:
begin:[:块名]
语句1;语句二;.....;语句n;
end
4)case 条件语句和四种逻辑状态
条件语句的条件值和标识符数据类型必须匹配;‚允许出现多个分支取值同时满足case表达式的情况,这种情况先处理最先满足表达式的分支项,随后跳出case语句;ƒ如果条件选择取值能覆盖所有的case语句表达式的值,必须使用default语句。
备注:四种逻辑状态的取值
.0 含义四个 : 二进制 0、低电平、逻辑 0、事件为伪;
.1 含义四个 : 二进制 1、高电平、逻辑 1、事件为真;
.z或Z 高阻态 或 高阻值;
. X 或 x 不确定或未知的逻辑状态
//casez、casex 对应以上的后两种状态
5)并位操作和数字表达
{a1,b1,2{a2,b2}} = {a1,b1,{a2,b2},{a2,b2}}={a1,b1,a2,b2,a2,b2}
例如,表示一个二进制的一般格式如下:
<位宽>´<进制><数字>
2. 4四选1 多路选择器及其数据流描述方式
源代码:
module MUX41a(a,b,c,d,s1,s0,y)
input a,b,c,d,s1,s0;
out put y;
wire [1:0] SEL;
wire AT,BT,CT,DT;
assign SEL = {s1,s0}; //assign 定义的变量必须是网线型的
assign AT = {SEL = = 2’D0};
assign BT = {SEL = = 2’D1};
assign CT = {SEL = = 2’D2};
assign DT = {SEL = = 2’D3};
assign y =(a & AT) | (b & BT) |(c & CT) | (d & DT);
endmodule
源码语法分析:
1)按位逻辑操作符
如:A = 1’b0 , B = 1’b0 => A ~ ^B = 1’b0//其中~^为同或信号
2)等式操作符
=s = = //全等 != =//不全等
3)assign 连续赋值语句
上例中采用的是并行语句加纯布尔函数的表达式实现模块的功能,属于所谓的数据流描述方式,通常使用连续赋值语句来描述输入与输出之间的逻辑关系。
连续赋值语句的基本格式如下:
assign 目标变量名 = 驱动表达式;
assign DOUT = a & b;//a,b为显示的敏感信号,此语句被执行一次的唯一条件是此语句右边的变量发生变化。
注意一个wire变量不允许有多个时钟源,如下描述是不允许 的,如:
assign DOUT = a & b | c; assign DOUT = a & b | f;
4)wire 定义网线型变量
用wire定义的网线型变量可以在任何类型的表达式或赋值语句中(包括连续赋值或者过程赋值)用作输入信号,也可在连续赋值语句或试题元件例化中用作输出信号。
此外还可以用wire语句代替assign语句:
module MUX41a(A,B,C,D,s1,s0,y)
input A,B,C,D,s1,s0,y;
output y;
wire AT = s0 ? D : C ;
wire BT = s0 ? B : A ;
wire Y = (s1 ? AT : BT );
endmodule
3 选一 及if 语句描述方式
module MUX41a (A,B,C,D,s1,s0,y)
input A,B,C,D,s1,s0;
output y;
reg[1 :0] SEL;
reg y;
always @(A,B,C,D,SEL) begin //快语句开始
SEL = {s1,s0};
if(SEL = = 0) y = A ;
else if (SEl = = 1) y = B;
else if (SEL = = 2) y = C ;
else y = D ;
end //快语句结束
endmodule
源码分析:
1)if _ else 语句
和C语言类似这里不做强调
2)过程赋值语句
阻塞式赋值
“=” 如果在一个块语句中有多条阻塞式赋值语句时,当执行到其中某条赋值语句时,其他语句被顺序执行。assign 语句和always 语句出现的等号理论上是不同的,因为前者属于连续类赋值语句,具有并行执行赋值特性;后者属于过程赋值中的顺序赋值语句。但从综合效果的角度看其结果是相同点,因为assign语句不能使用块语句,故只允许引导一条含有“=”符号的赋值语句;而assign语句作为并行语句的限制下,即使其中的语句具有顺序执行功能,也无从发挥。
‚非阻塞式赋值
“<=”,必须在快语句执行结束后才整完成赋值。
3)数据表示方式
数据的自动匹配:
例如:wire Y = 9 ; Y<= 9;//不报错,verilog会截掉高位赋给Y,
故Y的值为 2’b01
注意:verlog 的语法比VHDL更宽松适合初学者入门,但正因为如此,程序设计更要小心,其排错查错时可能要花费更多的力气。