学习笔记——Verilog语法(可综合的语法子集)

更新时间:2023-05-09 07:58:38 阅读: 评论:0

学习笔记——Verilog语法(可综合的语法⼦集)
可综合的语法⼦集
1、模块声明类语⾔:module…endmodule
module后加该模块的命名,取名没有任何限制,随后加“()”内罗列出该模块的所有输出/输⼊端⼝信号名。
⽤法描述
module my_first_prj(<;端⼝信号列表> … );
<;逻辑代码> …
endmodule
2、端⼝声明:input(输⼊信号)、output(输出信号)inout(双向)
每个module都有输⼊和输出的信号⽤于和外部器件或其他module进⾏连接。所以要在module后的“()”内声明该模块⽤于与外部接⼝的信号。
⽤法描述
input clk;
input wire rst_n;
input [7:0] data_in;
代码解释:第1个声明表⽰1bit的名称为clk的输⼊信号端⼝;第2个声明表⽰wire类型的1bit的名称为rst_n的输⼊信号;第3个声明表⽰8bit的名称为data_in的输⼊信号。
3、参数定义:parameter
⽤于声明⼀下常量,便于模块的移植或升级时候的修改。对于⼀个⼀般的module来说必定有module…endmodule语句也有input output语句但是不⼀定有parameter语句。不过对于⼀个可读性强的代码来说也是必不可少的。
基本的module如下:
module <;模块命名>(<;端⼝命名 1>, <;端⼝命名 2>, ...);
/
/ 输⼊端⼝申明
input <;端⼝命名 1>;
input wire <;端⼝命名 2>;
input [<;最⾼位>:<;最低位>]<;端⼝命名 3>;
...
// 输出端⼝申明
output <;端⼝命名 4>;
output [<;最⾼位>:<;最低位>]<;端⼝命名 5>;
output reg [<;最⾼位>:<;最低位>]<;端⼝命名 6>;
...
// 双向(输⼊输出)端⼝申明
inout <;端⼝命名 7>;
inout [<;最⾼位>:<;最低位>]<;端⼝命名 8>;
...
// 参数定义
parameter <;参数命名 1>=<;默认值 1>;
parameter [<;最⾼位>:<;最低位>]<;参数命名 2>=<;默认值 2>;
...
// 具体功能逻辑代码
...
endmodule
其中“//”后为注释的内容。“<>”之间是各个参数以及端⼝的名称命名,在实际代码中不需要加“<>”。
4、信号类型:wire、reg等
如图所⽰可以直观的理解两个信号的类型区别。
⾸先是reg。reg代表是寄存器,图中的电路中,分别定义两个寄存器reg锁存当前的输⼊din,每个时钟信号clk上升沿到来时,reg都会锁存到最新的输⼊的数据。
然后是wire,wire由图可知是两个reg之间的连线(直接)。
注意:虽然我们在代码中定义了这些信号的类型,但是在实际电路中换是想要看综合⼯具的表现才能确定,不能⼀概⽽论,可能出现差错。例如reg定义的信号通常会被综合为⼀个寄存器register,但是这个有⼀个前提,就是这个reg信号必须是在某个由特定信号边沿敏感触发的aways语句中被赋值这个例⼦我不是很明⽩,我的理解是,reg定义的这个信号被综合为⼀个寄存器是有条件的,这个条件就是这个信号必须在某个特定信号的边沿敏感触发的aways语句中赋值,否则是不能被综合为这个寄存器的。所以信号的类型还是想要看综合⼯具所表现的形式再来决定。
常见⽤法
// 定义⼀个 wire 信号
wire <wire 变量名>;
// 给⼀个定义的 wire 信号直接连接赋值
// 该定义等同于分别定义⼀个 wire 信号和使⽤ assign 语句进⾏赋值
wire <wire 变量名>=<;常量或变量赋值>;
// 定义⼀个多 bit 的 wire 信号
wire [<;最⾼位>:<;最低位>]<wire 变量名>;
// 定义⼀个 reg 信号
reg <reg 变量名>;
// 定义⼀个赋初值的 reg 信号
reg <reg 变量名>=<;初始值>;
// 定义⼀个多 bit 的 reg 信号
reg [<;最⾼位>:<;最低位>]<reg 变量名>;
// 定义⼀个赋初值的多 bit 的 reg 信号
reg [<;最⾼位>:<;最低位>]<reg 变量名>=<;初始值>;
// 定义⼀个⼆维的多 bit 的 reg 信号
reg [<;最⾼位>:<;最低位>]<reg 变量名>[<;最⾼位>:<;最低位>];
由以上代码可知:
给⼀个定义的信号直接连接赋值就可以直接在后⾯将需要赋值的内容⽤“=”连接即可。
定义⼀个多bit的信号需要在后⾯“【】”中加⼊最⾼位和最低位。
定义⼀个多维度的信号,就需要有⼏个维度在后⾯写⼏个“【】”
5、多语句定义:begin…end
可以理解为C语⾔中的“{}”,⽤于单个语法的多个语句定义
使⽤⽰例
// 含有命名的 begin 语句
begin :<;块名>
// 可选申明部分
// 具体逻辑
end
// 基本的 begin 语句
begin
// 可选申明部分
// 具体逻辑
end
6、⽐较判断:if…el、ca…default…endca。
个⼈理解:与C语⾔中的⽐较判断⼀致,使⽤频率⾼
使⽤⽰例:
// if判断语句
if(<;判断条件>)
begin
// 具体逻辑
end
// if…el 判断语句
if(<;判断条件>)
begin
/
/ 具体逻辑 1
end
el
begin
// 具体逻辑 2
end
// if…el if…el 判断语句
if(<;判断条件 1>)
begin
// 具体逻辑 1
end
el if(<;判断条件 2>)
代码解读:
if后⾯加判断条件这个和C语⾔中⼀致。然后begin…end相当于C语⾔中的“{}”其中罗列具体的逻辑语句。达到条件需要执⾏的语句就是在这⾥执⾏的。然后加if…el没有达到条件执⾏的语句在这个之后加。ca与C语⾔中的使⽤也是⼀样的。下⾯有⼏个取值。
ca后⾯的变量与下⾯的取值作⽐较,达到要求则执⾏后⾯的具体逻辑如果没有达到要求就⼀直⽐较,如果都没有则执⾏default语句后⾯的逻辑语句。最后的结束语endca。
7、循环语句:for
FPGA中使⽤循环语句的时候⽐C语⾔中使⽤循环语句少,但是也会在特定的时候使⽤到。
使⽤⽰例:
// for语句
for(<;变量名>=<;初值>;<;判断表达式>;<;变量名>=<;新值>)
begin
// 具体逻辑
end
由上⽰代码可见即使是循环语句还是离不开begin…end语句的。
8、任务定义:take…endtake
take像是C语⾔的⼦程序,可以⽤于实现⼀个时序的控制,,take中也可以有input和output,inout端⼝作为出⼊⼝参数,take没有返回值所以不能⽤于表达式中。
使⽤⽰例:
task <task 命名>;
// 可选申明部分,如本地变量申明
begin
// 具体逻辑
end
endtask
9、连续赋值:assign和问好表达式(?:)
assign⽤于⾃动互连不同的信号或直接给wire变量赋值。(我理解⾃动互连的意思就是⾃动的相互连接,通过上⾯的语法我们知道两个寄存器之间需要有wire的连线直接连接,通过assign直接⾃动连接不同信号)
使⽤⽰例:
assign <wire 变量名>=<;变量或常量>;
问号表达式(?:)Verilog与C语⾔有许多相似的地⽅这⾥⼜是⼀个体现,C语⾔中也有问号表达式,⽤来判断(由下⾯的⽰例可以看出,这个和C语⾔中的问号表达式⼀样)。其实问号表达式就是简单的if…el语句,更多是⽤在组合逻辑函数中。
使⽤⽰例:
(判断条件) ? (判断条件为真时的逻辑处理):(判断条件为假时的逻辑处理)
10、always模块:可分为组合逻辑和时序逻辑两种(always有很多⽤法)
(1)组合逻辑:敏感表为电平、沿信号podge/negedge;通常⽤@连⽤。使⽤⽰例如下所⽰:
always@(*)
begin
// 具体逻辑
end
(2)时序逻辑:always后若有沿信号(上升沿podge,下降沿negedge)声明,则多为时序逻辑,使⽤⽰例如下所⽰:
// 单个沿触发的时序逻辑
always@(<;沿变化>)
begin
//具体逻辑
End
// 多个沿触发的时序逻辑
always@(<;沿变化 1> or <;沿变化 2>)
begin
//具体逻辑
End
11、运算操作符(简单的来说就是加减乘除与或⾮⼤于⼩于等于)
Verilog中绝⼤多数运算操作符(逻辑操作符、移位操作符、算数操作符)都是可综合的。
运算操作符的列表如下所⽰:
+ // 加 - // 减
! // 逻辑⾮
~
// 取反
& // 与
~& // 与⾮
| // 或
~| // 或⾮
^ // 异或
^~ // 同或
~^ // 同或
* // 乘,是否可综合看综合⼯具
/ // 除,是否可综合看综合⼯具
% // 取模
<< // 逻辑左移
>> // 逻辑右移
< // ⼩于
<= // ⼩等于
> // ⼤于
>= // ⼤等于
== // 逻辑相等
!= // 逻辑不等于
&& // 逻辑与
|| // 逻辑或
由上表可以看出来,这些和C语⾔中的是⼀样的。
12、赋值符号=和<=
赋值的=与C语⾔中的运算⼀直,不同之处在于在Verilog中有阻塞和⾮阻塞赋值。(有待了解,在具体的实例中感受他们之间的不同之从)代码书写规范
在学单⽚机的初始阶段,我写代码就超级乱,超级烂。其实我们在写每个代码程序的时候都应该遵守代码书写的规范。最起码起到便于他⼈阅读的效果。不然代码⼀团乱,即使电脑运⾏的时候不会出错但是也不便与别⼈交流合作。学FPGA也是⼀样的,Verilog也是有代码的书写规范的。我们要从刚开始接触Verilog就养成好的习惯,尽⼒遵从⽐较规范的书写⽅式。下⾯是也写基本的可供遵循的规范。
1、标识符:标识符包括语法保留关键字、模块名称、端⼝名称、信号名称、各种变量或常量名称等(注意后⾯的名称不能和关键字⼀样)
⽤户⾃定义的命名规则:
(1)命名中只能包含字母数字和下划线“_”和符号“$”
(2)命名的第⼀个字符必须是字母
(3)在⼀个模块中的命名必须是唯⼀的。
模块名称、端⼝名称、信号名称、各种变量或常量名称等的命名,有很多推荐的规则可供参考。(不是必须服从的规则,只是建议这样做)
(1)尽可能使⽤能表达名称具体含义的英⽂单词命名,单词名称过长时可以采⽤易于识别的缩写形式替代,多个单词之间可以⽤下划线“_”进⾏分割。
(2)对于出现频率较⾼的相同含义的单词,建议统⼀作为前缀或后缀使⽤。
(3)对于低电平有效的消耗,通常加后缀“_n”表⽰。
(4)在同⼀个设计中,尽可能的统⼀⼤⼩写的书写规范。
建议:如果想要写⼀个⼯整好懂美观的程序,最好的把这些规则做到,在写代码之前先复习⼀下规则,然后带着规则去写代码,这样就会更容易注意到问题的所在了。
2、格式:这⾥的格式主要是指每个代码功能块之间、关键词、名称或操作符之间的间距(⾏间距、字符间距)规范。这⾥只是建议⼤家尽量遵循以下⼀些原则:
(1)每个功能块(如 verilog 的 always 逻辑、VHDL 的 process 逻辑)之间尽量⽤⼀⾏或数⾏空格进⾏隔离。
(2)⼀个语法语句⼀⾏,不要在同⼀⾏写多个语法语句。
(3)单⾏代码不宜过长,所有代码⾏长度尽量控制在⼀个适当的便于查看的范围。
(4)同层次的语法尽量对齐,使⽤ Tab 键(通常⼀个 Tab 对应四个字符宽度)进⾏缩进。
(5)⾏尾不要有多余的空格。
(6)关键词、各类名称或变量、操作符相互间都尽量保留⼀个空格以作隔离。

本文发布于:2023-05-09 07:58:38,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/90/101755.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:代码   逻辑   信号
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图