学习笔记——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…else、case…default…endcase。

  • 个人理解:与C语言中的比较判断一致,使用频率高
  • 使用示例:
// if 判断语句
if(<判断条件>) 
begin 
// 具体逻辑
end
// if…else 判断语句
if(<判断条件>)
begin 
// 具体逻辑 1
end
else 
begin
// 具体逻辑 2
end
// if…else if…else 判断语句
if(<判断条件 1>)
begin 
// 具体逻辑 1
end
else if(<判断条件 2>)
  • 代码解读:
    if后面加判断条件这个和C语言中一致。然后begin…end相当于C语言中的“{}”其中罗列具体的逻辑语句。达到条件需要执行的语句就是在这里执行的。然后加if…else没有达到条件执行的语句在这个之后加。case与C语言中的使用也是一样的。下面有几个取值。case后面的变量与下面的取值作比较,达到要求则执行后面的具体逻辑如果没有达到要求就一直比较,如果都没有则执行default语句后面的逻辑语句。最后的结束语endcase。

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…else语句,更多是用在组合逻辑函数中。
  • 使用示例:
(判断条件) ? (判断条件为真时的逻辑处理) : (判断条件为假时的逻辑处理)

10、always模块:可分为组合逻辑和时序逻辑两种(always有很多用法)

(1)组合逻辑:敏感表为电平、沿信号posedge/negedge;通常用@连用。使用示例如下所示:

always@(*)
begin
// 具体逻辑
end

(2)时序逻辑:always后若有沿信号(上升沿posedge,下降沿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)关键词、各类名称或变量、操作符相互间都尽量保留一个空格以作隔离。

  • 有些规则通过汉字的书写是无法真正的理解其操作的。只有在代码编写的过程中才可以真正的体会其含义。所以这里我也就只是了解,有许多与C语言相似的地方就理解了,其他地方就通过之后的实例一一感受吧。
    3、注释:Verilog 的注释有“/* /”以及“//”两种方式。“/”左侧和“*/”右侧之间的部分为注释内容,此注释可以用在行前、行间、行末或多行中;“//”后面的内容为注释,该注释只可用在行末(当然了,它也可以顶个,那么意味着整行都是注释)我在写代码的时候不太经常写注释,其实注释也是帮助别人更好的读懂自己代码的一个方式。通过注释可以清晰的体现每个模块的作用实现的功能等。注释有以下几小点的讲究,其实在C语言中依然如此。
    (1)每个独立的功能模块都要有简单的功能描述,对输入输出信号功能进行描述。
    (2)无论习惯在代码末注释还是代码上面注释,同一个模块或工程中尽量保持一致。
    (3)注释内容简明扼要,不要过于冗长或写废话(例如:add = add+1;//add 自增)。
  • 5
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: FPGA是一种可编程逻辑器件,可以通过编程实现各种功能。而Verilog是一种硬件描述语言,用于描述FPGA中的电路。Verilog基础语法包括模块定义、端口定义、信号定义、赋值语句、条件语句、循环语句等。模块定义是Verilog中最基本的语法,用于定义一个电路模块。端口定义用于定义模块的输入输出端口。信号定义用于定义模块内部的信号。赋值语句用于给信号赋值。条件语句用于根据条件执行不同的代码。循环语句用于重复执行一段代码。掌握Verilog基础语法学习FPGA编程的基础。 ### 回答2: FPGA是一种可编程逻辑器件,它可以通过硬件描述语言来编写自定义的逻辑电路来实现各种功能。其中,Verilog是一种常用的硬件描述语言,有助于实现FPGA的功能。 Verilog语言主要由模块、端口、信号、语句和运算符五个基本部分组成。模块是Verilog中的最基本的语法单元,类似于传统程序语言中的函数,模块之间可以通过实例化进行连接。端口则是与外部世界进行通信的接口,可以分为输入端口(input)和输出端口(output)两种类型。信号是Verilog中表示数字信号的基本单元,可以是位向量、整数或实数。语句则是Verilog中描述操作和行为的语言,常用的语句包括赋值语句、分支语句和循环语句。运算符则是Verilog中用于进行操作的符号,包括算数运算符、逻辑运算符和位运算符。 在Verilog语言中,还有一些常用的结构体和命令可以帮助我们更方便地实现FPGA的功能。其中,常用的结构体包括always语句、case语句和module归档,常用的命令包括initial语句、wire语句和reg语句。always语句可以在指定的触发条件下执行某一段代码,case语句可以根据不同的条件执行不同的代码段,module归档则可以将多个模块合并为一个模块。initial语句可用于在仿真开始前初始化某些信号,wire语句则用于声明并连接信号,reg语句则用于声明并存储信号。 总体而言,了解FPGA和Verilog基础语法可以帮助我们更好地理解FPGA技术的应用和实现。然而,理论知识只有结合实际操作和实验才能更好地掌握。所以,我们还需要结合实际项目来进行练习和实践,从而更好地掌握FPGA和Verilog基础语法。 ### 回答3: FPGA(可编程门阵列)是一种可编程逻辑器件,可以用来创建定制的数字电路。Verilog是一种硬件描述语言,用于描述数字电路的结构和行为。 Verilog基础语法有以下几个部分: 1.模块定义:Verilog代码以模块的形式进行组织,每个模块都有一个名称和端口列表。模块定义以module关键字开始,以endmodule关键字结束。 2.端口声明:模块的端口是输入和输出连接到其他模块或FPGA芯片的引脚。端口可以是输入(input)、输出(output)或双向(inout)。端口声明在模块定义中。 3.信号声明:信号是描述数字电路中状态的变量。可以是单个位(wire)或多位(reg),在模块中声明。 4.赋值语句:用来为信号赋值,包括非阻塞赋值(<=)、阻塞赋值(=)和连续赋值(assign)。 5.条件分支语句:if, else if和else语句是用来控制程序流程,实现条件判断。 6.循环语句:Verilog支持for、while、do while和forever等类型的循环语句,可以在程序中实现迭代操作。 7.模块实例化:用来将其他模块作为子模块嵌入到当前模块中,从而实现复杂的数字电路。 除上述基本语法外,Verilog还有其他常用语法,如always块、initial块和function定义等。需要深入了解和使用Verilog,可以参考相关资料和教程。掌握了Verilog语法,可以使用FPGA搭建各种个性化的数字电路,用于嵌入式系统、数字信号处理、计算机网络等各种应用领域。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

热爱生活的fuyao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值