FPGA之道(39)HDL的命名规则

举报
李锐博恩 发表于 2021/07/15 03:39:18 2021/07/15
【摘要】 文章目录 前言命名规则命名要有意义简单意义命名复杂意义命名一、下划线分隔法。二、非首单词首字母大写分隔法。 多重相似命名电平敏感命名方向敏感命名命名格式要统一命名格式要区分 前言 VHDL以及Verilog的命令都遵循一定的规则,例如VHDL不允许下划线“-”开头,而Verilog允许。不过,今天不是讨论这个问题的,今天需要讨论的都是VHDL以及Ve...

前言

VHDL以及Verilog的命令都遵循一定的规则,例如VHDL不允许下划线“-”开头,而Verilog允许。不过,今天不是讨论这个问题的,今天需要讨论的都是VHDL以及Verilog通用的,需要遵守的一些有利于提到代码可读性的规则,这是养成良好代码风格的关键一步。
本文节选自《FPGA之道》,一起来看下作者的肺腑之言。

命名规则

古人有云:“赐子千金,不如教子一艺;教子一艺,不如赐子好名。”虽然可能有些夸张,但也足以见证名字的重要性。不仅如此,自古以来,凡是好的文学作品,其中人物的姓名都是栩栩如生,让人过目不忘。而我们写HDL代码,虽然不比写作,但是也请不要太委屈了“剧本”中出场的“各位”。

命名要有意义

有意义的命名能够让人更容易理解它的用途,例如:

	-- VHDL example
	signal AAAA : std_logic; 
	signal BBBB : std_logic_vector(3 downto 0);

// Verilog example
reg abcd; 
reg [3 : 0] efgh;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

我相信,看到这样的定义谁也不知道上面定义的这几个变量的用途,必须要去HDL代码中痛苦的推敲一遍才能得到答案。但若写成下面这样,我相信这几个变量的作用就一目了然了。

-- VHDL example
	signal CLK : std_logic; 
	signal COUNTER : std_logic_vector(3 downto 0);

// Verilog example
reg clk; 
reg [3 : 0] counter;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

从上述代码中,我们可以很容易的猜测出它们应该是用来描述一个计数器的。

简单意义命名

像上例一样,我们一般采用英文单词来作为变量等的标识符,这是因为HDL代码的语法关键字都是英文的单词,所以如果标识符也用英文或英文缩写的话,整个代码的风格才会更加统一。对于像“时钟”、“计数器”这样的可以用一个英文单字或者一个常见的缩写概括其意思的变量,我们称之为简单意义的命名,并可以直接用其所表述功能对应的英文单词或缩写作为其标识符即可。

复杂意义命名

有时候,变量等所表述的功能需要更加详细的描述才能区分开来。例如代码中有两个计数器,一个负责对秒计数,一个负责对分钟计数,那么我们就不能简单的用counter来作为它们的标识符,必须加以更详细的描述符作为区分才行。你也许很容易想到,只要分别命名为“秒计数器”和“分钟计数器”,那么我们就可以很容易的区分开它们。但是这两个命名的含义都不是能够被一个英文单词所简单概括的,因此我们把这种需要用两个及两个以上英文单词才能概括其意义的命名叫做复杂意义的命名。考虑到HDL代码中,标识符是不能包含空格的,因此在这里,我们推荐给大家两种表述复杂意义命名的方法。

一、下划线分隔法。

无论是VHDL还是Verilog,标识符中都允许出现下划线符号——‘_’,唯一不同的是Verilog允许下划线出现在标识符的开头,而VHDL不允许。针对上述“秒计数器”和“分钟计数器”的例子,我们可以写出它们有意义的标识符如下:

	-- VHDL example 
	signal SECOND_COUNTER : std_logic_vector(3 downto 0); 
	signal MINUTE_COUNTER : std_logic_vector(3 downto 0);

// Verilog example
reg [3 : 0] second_counter; 
reg [3 : 0] minute_counter;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

二、非首单词首字母大写分隔法。

该方法是这样的:如果标识符只需要用一个英文单词来描述,那么该英文单词全部小写;如果标识符需要用多个英文单词来描述,那么从第二个英文单词开始,首字母大写,其余字母仍小写。通过这样一个写法,人眼很容易通过大写的英文字母来识别出各个完整的英文单词,从而快速理解其意义。仍以“秒计数器”和“分钟计数器”为例,我们的命名代码如下:

	-- VHDL example 
	signal secondCounter : std_logic_vector(3 downto 0); 
	signal minuteCounter : std_logic_vector(3 downto 0);

// Verilog example
reg [3 : 0] secondCounter; 
reg [3 : 0] minuteCounter;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

多重相似命名

有时候,我们可能会同时用到很多个用途和含义相似的变量,如果要严格按照复杂意义的命名规则将它们区分开来,很可能每个标识符都需要四、五个以上的英文单词才能搞定。虽然这样我们的命名更加有意义了,但是凡事都有个“度”的问题,伴随着越来越长的标识符,代码的阅读也会越来越困难。这个时候,利用数字的多重相似命名往往能取得比较好的效果。例如,程序中需要用到某一个标志位信号及它的1周期延迟、2周期延迟、3周期延迟,如果用复杂意义命名准则,可能得写成这样:

	-- VHDL example 
	signal flagDelayforZeroCycle : std_logic; 
	signal flagDelayforOneCycle : std_logic; 
	signal flagDelayforTwoCycle : std_logic; 
	signal flagDelayforThreeCycle : std_logic;

// Verilog example
reg flagDelayforZeroCycle; 
reg flagDelayforOneCycle; 
reg flagDelayforTwoCycle; 
reg flagDelayforThreeCycle;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

如果利用数字来进行多重相似命名的话,可以写成这样:

-- VHDL example 
	signal flagDelay0, flagDelay1, flagDelay2, flagDelay3: std_logic; 

// Verilog example
reg flagDelay0, flagDelay1, flagDelay2, flagDelay3;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

由此可见,利用数字的多重相似命名规则,很好的缩短了代码的长度,更有利于书写和阅读,并且标识符的意义也没有明显减弱。

电平敏感命名

FPGA的程序设计中,肯定存在很多控制信号,通常我们更愿意称它们为“使能”。而这些使能中,有一些是高电平起作用的,而另一些是低电平器有效的。为了能够更加容易的区分它们,那么我们需要在它们的命名上面做点“手脚”。一般来说,我们认为高电平有效的信号是比较符合逻辑思维习惯的,那么对于这类信号,我们就不做命名修改;而低电平有效的信号,我们通常会通过一些前缀或后缀的方法加以区分。例如,FPGA外围其他芯片的片选信号一般都是低电平有效的,那么我们可以采用类似如下的命名方式进行命名:

-- VHDL example 
	CS_n, nCS in : std_logic; 

// Verilog example
output CS_n, nCS, _CS;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

方向敏感命名

该命名方式一般针对于模块或者实体的端口,当端口的数量比较多时,即使命名有意义,我们也很难分辨出它们到底是当前模块或实体的输入还是输出,因此,为了进一步增加代码的易读性,可以参照电平敏感命名的方法来对这些端口名称做些“手脚”。例如:

-- VHDL example 
clk_in in : std_logic; 
out_clk out : std_logic; 
	busIO inout : std_logic_vector(7 downto 0);

// Verilog example
input clk_in;
output outClk;
inout [7:0] io_bus;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

但是请注意,对于更上一层的模块来说,子模块A的输出端口很可能连接到子模块B的输入端口,这时连线的名字无论是和子模块A还是B一致都会让人觉得别扭。因此,对于这种互连线,我们可以直接用去除它们所连接端口的方向前缀或后缀后的字段来命名即可。例如:

-- VHDL example 
signal data : std_logic_vector(31 downto 0);
m0: xxxx PORT MAP(
		data_in => data,
		……
	);
m1: yyyy PORT MAP(
		data_out => data,
		……
	);

// Verilog example
wire data;
xxxx m0(.dataIn (data),
……); 
yyyy m1(.dataOut (data),
……);

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

命名格式要统一

前面刚刚介绍了一些有意义的命名方法,我们可以看出,有意义的命名方法有很多,但是我们最好在代码中统一命名格式。因为统一的格式看起来更舒服,而且更容易让人看懂。
一般来说,统一的命名方法要求标识符之间的大小写一致,前、后缀格式一致,分隔方法一致等等。如果不遵循这种一致性,例如将代码写成如下这样:

	-- VHDL example 
	signal data0 : std_logic; 
	signal data1 : std_logic; 
	signal DATA2: std_logic; 
	signal DATA3 : std_logic;

// Verilog example
reg DATA0; 
reg DATA1; 
reg data2; 
reg data3;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

我相信经验再丰富的FPGA设计师看到这段代码都会眩晕一阵,本来好端端的4位数据线,第一眼看上去好像就是前两根数据线是一组,后两个是一组一样,而这两组之间到底有没有关系,说老实话,第一眼看上去心里还真是没底!

命名格式要区分

前面讲“统一”,这里又讲“区分”,这难道不是自相矛盾么?其实一点也不矛盾。在我们给标识符命名的时候,该统一的地方就要统一,该区分的地方就要区分!那么什么地方该区分呢?通过【本篇->编程语法】章节的介绍,我们可以知道需要取名字的不仅仅是代码中声明的变量,除此以外像一些常数、参数,模块名称,实体名称,语句端标号等等都是需要我们为之取名的。试想一下,如果能够在命名格式上将不同类型的标识符区分开来,那么肯定会对提高HDL代码易读性有很大帮助。例如:

	-- VHDL example entity PulseDealer is
……
constant MAX_NUMBER : std_logic_vector(7 downto 0) := 100;
		signal pulseCounter : std_logic_vector(7 downto 0); 

// Verilog example
module PulseDealer
	……
	Parameter MAX_NUMBER = 100;
reg [7:0] pulseCounter; 

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

由于上例对不同类型标识符采用了不同的命名形式来区分,因此在后续HDL代码的阅读中,可以非常容易就分辨出标识符的种类,而不需要每次都回到HDL代码的声明部分去查询。

文章来源: reborn.blog.csdn.net,作者:李锐博恩,版权归原作者所有,如需转载,请联系作者。

原文链接:reborn.blog.csdn.net/article/details/104322178

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。