相关阅读
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: keepreg 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: innerwavereg hold;joinend
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 beginstim1 = 1'b0; // 编译错误,引用位置在定义位置前stim2 = 1'b1; // 编译错误,引用位置在定义位置前endreg stim1, stim2;
endmodule
任务名和函数名则没有这个要求,如例4所示。
// 例4
module example;initial begin$display("Sum is: %d", add(2, 3)); endfunction integer add;input integer a, b;beginadd = a + b;endendfunction
endmodule
如果使用层次化标识符,则所有对象都没有这个要求,如例5所示,因为层次名解析是在elaboration阶段进行而不是在编译阶段进行。
// 例5
module example;initial beginexample.stim1 = 1'b0; // 没有问题example.stim2 = 1'b1; // 没有问题endreg stim1, stim2;
endmodule
五、不完整的层次化标识符
使用完整的层次化标识符简单直观,但当层次结构复杂起来时,完整的层次化标识符便显得十分臃肿,此时可以使用不完整的层次化标识符,即层次化标识符不从顶层(根)模块名开始写起。
不完整的层次化标识符的语法和图1所示的一样,但是此时不要求最左边的普通标识符是顶层(根)模块名,它可以是模块(实例)名、任务名、函数名、命名块名和生成块名。
不完整的层次化标识符解析遵循一定的规则,如下所示:
1、首先在层次化标识符引用位置的命名空间中尝试匹配层次化标识符,匹配指的是从层次化标识符最左边的普通标识符开始依次匹配后续的所有普通标识符,如果匹配失败且当前命名空间不是模块命名空间,则在上层命名空间中尝试匹配层次化标识符,以此类推直到匹配成功或到达模块命名空间。例6展示展示了不完整的层次化标识符的使用方式。
// 例6
module example;initial begin: block1reg x, y;x = 1;y = 0;begin: block1reg x;x = 0;$display("x = %b", block1.x); // 输出:x = 0$display("y = %b", block1.y); // 输出:y = 0endend
endmodule
2、在规则1中在到达模块命名空间后,如果匹配仍然失败,则会在父模块的模块命名空间(最外层)尝试匹配层次化标识符。
在父模块的模块命名空间内匹配时会有一个例外,那就是首先将层次化标识符最左边的普通标识符与模块名匹配,如果成功则将其视为子模块实例名(指直接或间接包含的子模块实例);如果匹配失败再尝试匹配其他名字(用于实例化的模块名可以与模块命名空间中的名字重名),如例7所示。
// 例7
module top;example example_1(1); // 对于实例example_1中的$display,它输出1example example_2(0); // 对于实例example_2中的$display,它输出0initial begin: examplereg x;x = 1'bx; // 优先搜索模块名,因此这个x没有被引用end
endmodulemodule 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直到顶层(根)模块,如果顶层(根)模块的模块命名空间也是失败的,则它会被视为一个完整的层次化标识符。
没错,其实完整的层次化标识符的解析也可以认为是遵守这个规则的,可以视为一层一层向上匹配但全部匹配失败,直到最后在假象的顶层(根)模块的父模块中匹配成功。
善于思考的你可能会提出问题,那岂不是会出现拦截问题,比如顶层(根)模块的模块命名空间中的一个名字可能会因为在向上匹配的过程中被提前匹配而无法被引用到,这是对的!如例8所示。
// 例8
module top;reg x = 0;example example_0();initial begin: topreg x;x = 1;end
endmodulemodule example();initial begin#1 $display("x = %b", top.x); // 输出:x = 1,这种情况下,此处无法引用到顶层(根)模块命名空间中的xend
endmodule
为了克服这个问题,后面的SystemVerilog标准提出了$root,本文就不对此进行详述了。