news 2026/10/27 1:16:07

Verilog基础:层次化标识符的使用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Verilog基础:层次化标识符的使用

相关阅读

Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm=1001.2014.3001.5482


一、前言

Verilog HDL中的标识符(identifier)是一个为了引用而给一个Verilog对象起的名字,分为两大类:普通标识符大类和层次化标识符大类。普通标识符大类又可以分为简单标识符和转义标识符,详情见下面的博客。

Verilog基础:简单标识符和转义标识符-CSDN博客文章浏览阅读647次,点赞25次,收藏20次。标识符(identifier)是一个为了引用而给一个对象起的名字。一个标识符可以是一个简单标识符,也可以是一个转义标识符。本文将对两者进行详细阐述。_转义标识符veriloghttps://blog.csdn.net/weixin_45791458/article/details/140436528?ops_request_misc=%257B%2522request%255Fid%2522%253A%25226813B559-9D37-4969-810B-88F9A143E446%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=6813B559-9D37-4969-810B-88F9A143E446&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-140436528-null-null.nonecase&utm_term=%E6%A0%87%E8%AF%86%E7%AC%A6&spm=1018.2226.3001.4450一般情况下我们只会接触到简单标识符,但是有些时候(如验证设计时),层次化标识符也会被使用,本文目的是为需要使用层次化标识符的设计人员提供一定参考。

二、层次化标识符的起源

模块、任务、函数、命名块和生成块的定义引入了命名空间(模块命名空间、块命名空间和生成块命名空间),详情见下面的博客。

Verilog基础:八种命名空间(定义命名空间、文本宏命名空间、模块命名空间,块命名空间、生成块命名空间、端口命名空间、specify块命名空间、属性命名空间)详解(上)-CSDN博客文章浏览阅读1k次,点赞44次,收藏24次。Verilog有八个标识符命名空间:其中两个是全局的(定义命名空间和文本宏命名空间),六个是局部的(模块命名空间,块命名空间、生成块命名空间、端口命名空间、specify块命名空间、属性命名空间)。_verilog 过程块命名https://blog.csdn.net/weixin_45791458/article/details/142132358?spm=1001.2014.3001.5501命名空间的层次化结构可以被视为树结构,其中每个模块(实例)、任务、函数、命名块和生成块在树的特定分支中定义了新的层次,而一个普通标识符在一个层次中最多只能声明一次(需要特别注意的是,层次化标识符不能用来声明)。任何非匿名的对象都可以通过若干直接或间接包含它的模块(实例)名、任务名、函数名、命名块名和生成块名进行引用(在本文中,“**名”和“名字”这种表述指的是普通标识符)。

三、层次化标识符的语法

图1是层次化标识符的BNF范式(语法),有关BNF范式相关内容,可以参考下面的文章。

Verilog基础:巴科斯范式(BNF)-CSDN博客文章浏览阅读556次,点赞14次,收藏40次。最后一个范式定义了variable_lvalue可以是hierarchical_variable_identifier加上可选的[]包围的多个数组表达式索引,以及可选的最后的[]包围的位选或域选表达式,variable_lvalue还可以是使用拼接运算符{}连接起来的多个variable_lvalue(递归定义自己)。第三个范式定义了第一个范式中的delay_or_event_control,为delay_control或event_control或使用repeat语句的event_control。_bnf veriloghttps://blog.csdn.net/weixin_45791458/article/details/132567389?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522F7990A6B-6C1B-4DA7-98FC-0BEFAC7FAAA8%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=F7990A6B-6C1B-4DA7-98FC-0BEFAC7FAAA8&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-132567389-null-null.nonecase&utm_term=BNF&spm=1018.2226.3001.4450

图1 层次化标识符的语法

层次化标识符由若干由句点.分隔的普通标识符组成,其中只有最左边的普通标识符可以是一个模块名,如果层次化标识符中包含实例数组名或循环生成块名,则该名后要有内含常量表达式的方括号组成,这表示选择实例数组或循环生成块的一个特定实例,一个完整的层次化标识符应该从顶层(根)模块名开始写起,因此它对于每个对象而言唯一的。

例1给出了一个层次化设计的Verilog代码,其中包括三个模块:mod、cct和wave,图2给出了这个层次化设计的树形结构。

// 例1 module mod(in); input in; always @(posedge in) begin: keep reg hold; hold = in; end endmodule //*********************************** module cct(stim1, stim2); input stim1, stim2; mod amod(stim1), bmod(stim2); endmodule //*********************************** module wave; reg stim1, stim2; cct a(stim1, stim2); initial begin: wave1 #100 fork: innerwave reg hold; join end endmodule

图2 例1的树形结构

例2给出了这个层次设计中所有对象的完整层次化标识符。

// 例2 wave // 模块的完整层次化标识符 wave.stim1 // reg信号的完整层次化标识符 wave.stim2 // reg信号的完整层次化标识符 wave.a // 模块实例的完整层次化标识符 wave.a.stim1 // reg信号的完整层次化标识符 wave.a.stim2 // reg信号的完整层次化标识符 wave.a.amod // 模块实例的完整层次化标识符 wave.a.amod.in // wire信号的完整层次化标识符 wave.a.amod.keep // 命名块的完整层次化标识符 wave.a.amod.keep.hold // reg信号的完整层次化标识符 wave.a.bmod // 模块实例的完整层次化标识符 wave.a.bmod.in // wire信号的完整层次化标识符 wave.a.bmod.keep // 命名块的完整层次化标识符 wave.a.bmod.keep.hold // reg信号的完整层次化标识符 wave.wave1 // 命名块的完整层次化标识符 wave.wave1.innerwave // 命名块的完整层次化标识符 wave.wave1.innerwave.hold // reg信号的完整层次化标识符

四、普通标识符的引用位置

普通标识符(除任务、函数外)要求引用位置在同一模块中标识符的定义位置后,例3给出了一个错误的引用方式。

// 例3 module example; initial begin stim1 = 1'b0; // 编译错误,引用位置在定义位置前 stim2 = 1'b1; // 编译错误,引用位置在定义位置前 end reg stim1, stim2; endmodule

普通标识符中的任务名和函数名则不要求引用位置在同一模块中标识符的定义位置后,如例4所示,且可以跨层次引用,如例5所示,就像后面谈到的层次化标识符那样。

// 例4 module example; initial begin $display("Sum is: %d", add(2, 3)); end function integer add; input integer a, b; begin add = a + b; end endfunction endmodule
// 例5 module top; example ex1(); function integer add; input integer a, b; begin add = a + b; end endfunction endmodule module example; initial begin $display("Sum is: %d", add(2, 3)); end endmodule

五、层次化标识符的引用位置

如果使用层次化标识符,则所有标识符对定义位置都不要求引用位置在同一模块中标识符的定义位置后,如例6所示,因为层次名解析是在elaboration阶段进行而不是在编译阶段进行。

// 例6 module example; initial begin example.stim1 = 1'b0; // 没有问题 example.stim2 = 1'b1; // 没有问题 end reg stim1, stim2; endmodule

六、不完整的层次化标识符

使用完整的层次化标识符简单直观,但当层次结构复杂起来时,完整的层次化标识符便显得十分臃肿,此时可以使用不完整的层次化标识符,即层次化标识符不从顶层(根)模块名开始写起(不完整的层次化标识符和完整的层次化标识符一样,不要求引用位置在同一模块中标识符的定义位置后)。

不完整的层次化标识符的语法和图1所示的一样,但是此时不要求最左边的普通标识符是顶层(根)模块名,它可以是模块(实例)名、任务名、函数名、命名块名和生成块名。

不完整的层次化标识符解析遵循一定的规则,如下所示:

1、首先在层次化标识符引用位置的命名空间中尝试匹配层次化标识符,匹配指的是从层次化标识符最左边的普通标识符开始依次匹配后续的所有普通标识符,如果匹配失败且当前命名空间不是模块命名空间,则在上层命名空间中尝试匹配层次化标识符,以此类推直到匹配成功或到达模块命名空间。例7展示展示了不完整的层次化标识符的使用方式。

// 例7 module example; initial begin: block1 reg x, y; x = 1; y = 0; begin: block1 reg x; x = 0; $display("x = %b", block1.x); // 输出:x = 0 $display("y = %b", block1.y); // 输出:y = 0 end end endmodule

2、在规则1中在到达模块命名空间后,如果匹配仍然失败,则会在父模块的模块命名空间(即最外层)尝试匹配层次化标识符。

在父模块的模块命名空间内匹配时会有一个例外,那就是首先将层次化标识符最左边的普通标识符与模块名匹配,如果成功则将其视为子模块实例名(指直接或间接包含的子模块实例);如果匹配失败再尝试匹配其他名字(用于实例化的模块名可以与模块命名空间中的名字重名),如例8所示。

// 例8 module top; example example_1(1); // 对于实例example_1中的$display,它输出1 example example_2(0); // 对于实例example_2中的$display,它输出0 initial begin: example reg x; x = 1'bx; // 优先搜索模块名,因此这个x没有被引用 end endmodule module example(input a); reg x; initial begin #1; x = a; $display("x = %b", example.x); // 对于实例example_1中example相当于example_1;对于实例example_2中的example相当于example_2。 end endmodule

3、如果在父模块的模块命名空间中的匹配全部失败了,则重复规则2直到顶层(根)模块,如果顶层(根)模块的模块命名空间也是失败的,则它会被视为一个完整的层次化标识符。

没错,其实完整的层次化标识符的解析也可以认为是遵守这个规则的,可以视为一层一层向上匹配但全部匹配失败,直到最后在假象的顶层(根)模块的父模块中匹配成功。

善于思考的你可能会提出问题,那岂不是会出现拦截问题,比如顶层(根)模块的模块命名空间中的一个名字可能会因为在向上匹配的过程中被提前匹配而无法被引用到,这是对的!如例9所示。

// 例9 module top; reg x = 0; example example_0(); initial begin: top reg x; x = 1; end endmodule module example(); initial begin #1 $display("x = %b", top.x); // 输出:x = 1,这种情况下,此处无法引用到顶层(根)模块命名空间中的x end endmodule

为了克服这个问题,后面的SystemVerilog标准提出了$root,本文就不对此进行详述了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/27 1:15:05

Linux:Bash中的命令介绍(简单命令、管道以及命令列表)

相关阅读 Linuxhttps://blog.csdn.net/weixin_45791458/category_12234591.html?spm1001.2014.3001.5482 在Bash中,命令执行的方式可以分为简单命令、管道和命令列表组成。这些结构提供了强大的工具,允许用户组合命令并精确控制其执行方式。以下是对这…

作者头像 李华
网站建设 2026/10/27 1:14:39

Fast-Retry 高性能百万级任务重试框架介绍及使用

一、Fast-Retry 在本专栏的前面文章中我们介绍了 Spring 家族的 重试框架,本篇文章再给大家介绍一个高性能百万级任务重试框架 Fast-Retry 。它是一个高性能任务重试框架,可以支持百万级别任务的并发重试处理。与 Spring-Retry 不同,Fast-Re…

作者头像 李华
网站建设 2026/10/27 1:13:24

Verilog基础:强度建模与net型信号的多驱动问题(三)

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 四、一般情况下的net型信号的线与组合(线网多驱动) 在Verilog基础:强度建模与net型信号的多驱动问题(二&#xff0…

作者头像 李华
网站建设 2026/10/27 1:12:45

【IC】【DE】数字IC基本设计流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/27 1:12:29

数字IC前端学习笔记:锁存器Latch的综合

相关文章 数字IC前端专栏https://blog.csdn.net/weixin_45791458/category_12173698.html?spm1001.2014.3001.5482 锁存器的生成方式有两种,一种是有意的,而另一种是无意的。无意生成的锁存器会浪费硅片面积,因为在大部分FPGA资源中&#x…

作者头像 李华