12.5 Иерархические имена
Каждый идентификатор в описании Verilog HDL должен иметь уникальное имя иерархического пути. Иерархия модулей и определение элементов, таких как задачи и именованные блоки внутри модулей, должны определять эти имена. Иерархия имен может рассматриваться как древовидная структура, где каждый экземпляр модуля, экземпляр блока генерации(generate), задачи(task), функции(function) или именованный блок begin-end или fork-join определяет новый иерархический уровень, или область видимости, в определенной ветви дерева.
Описание конструкции содержит один или несколько модулей верхнего уровня (см. 12.1.1). Каждый такой модуль образует вершину иерархии имен. Этот корневой (модуля верхнего уровня) или эти параллельные корневые модули составляют одну или несколько иерархий в описании конструкции или описании. Внутри любого модуля каждый экземпляр модуля(module) (включая массив экземпляров), экземпляр блока генерации(generate), объявление задачи(task), объявление функции(function) и именованный блок «begin-end» или «fork-join» определяют новую ветвь иерархии. Именованные блоки внутри именованных блоков, а также внутри задач и функций должны создавать новые ветви.
Исключением являются неименованные блоки generate. Они создают ветви, которые видны только внутри блока и внутри любой иерархии, объявленном экземпляре блока. Обсуждение неименованных генерирующих блоков см. в разделе 12.4.3.
Каждый узел в иерархическом дереве имен должен быть отдельной областью действия по отношению к идентификаторам. Определенный идентификатор может быть объявлен не более одного раза в любой области видимости. См. раздел 12.7 для обсуждения правил области видимости и раздел 4.11 для обсуждения пространств имен.
На любой именованный объект Verilog или иерархическую ссылку на имя можно однозначно ссылаться в полной форме путем конкатенации имен модулей(module), имен экземпляров модулей(module, macromodule), блоков генерации(generate), задач(task), функций(function) или именованных блоков, которые его содержат. Символ точки должен использоваться для разделения каждого имени в иерархии, за исключением экранированных идентификаторов, встроенных в иерархическую ссылку на имя, за которыми следуют разделители, состоящие из пробела и символа точки. Полное имя пути к любому объекту должно начинаться с модуля верхнего уровня (корневого). Это имя пути может быть использовано с любого уровня иерархии или из параллельной иерархии. Имя первого узла в имени пути также может быть вершиной иерархии, которая начинается с уровня, на котором используется путь (что позволяет и дает возможность ссылаться на объекты по нисходящей). Объекты, объявленные в автоматических задачах и функциях, являются исключениями и не могут быть доступны по иерархическим ссылкам имен. Объекты, объявленные в неименованных генерирующих блоках, также являются исключениями. На них можно ссылаться по иерархическим именам только внутри блока и внутри любой иерархии, объявленном экземпляре блока.
За именами в имени иерархического пути, которые ссылаются на массивы экземпляров или циклов блока generate, может сразу следовать константное выражение в квадратных скобках. Это выражение выбирает конкретный экземпляр массива и поэтому называется выбором экземпляра. Выражение должно соответствовать одному из законных значений индекса массива. Если имя массива не является последним элементом пути в иерархическом имени, то выражение instance select является обязательным.
Синтаксис для имен иерархических путей приведен в Синтаксисе 12-6.
escaped_identifier ::=
\ {Any_ASCII_character_except_white_space} white_space
hierarchical_identifier ::=
{ identifier [ [ constant_expression ] ] . } identifier
identifier ::=
simple_identifier
| escaped_identifier
simple_identifier ::= [ a-zA-Z_ ] { [ a-zA-Z0-9_$ ] }
white_space ::=
space | tab | newline | eof
Например:
module mod(in);
input in;
always @(posedge in) begin : keep
reg hold;
hold = in;
end
endmodule
module cct(stim1, stim2);
input stim1, stim2;
//экземпляр mod
mod amod(stim1), bmod(stim2);
endmodule
module wave;
reg stim1, stim2;
cct a(stim1, stim2); // экземпляр cct
initial begin :wave1
#100 fork :innerwave
reg hold;
join
#150 begin
stim1 = 0;
end
end
endmodule
Рисунок 12-1 иллюстрирует иерархию, подразумеваемую в этом коде Verilog.

Рисунок 12-1 Иерархия в модели
wave
wave.stim1
wave.stim2
wave.a
wave.a.stim1
wave.a.stim2
wave.a.amod
wave.a.amod.in
wave.a.amod.keep
wave.a.amod.keep.hold
wave.a.bmod
wave.a.bmod.in
wave.a.bmod.keep
wave.a.bmod.keep.hold
wave.wave1
wave.wave1.innerwave
wave.wave1.innerwave.hold
Рисунок 12-2 Иерархические имена путей в модели
Иерархическая ссылка на имя позволяет свободно обращаться к данным любого объекта с любого уровня иерархии. Если известно уникальное имя иерархического пути элемента, его значение может быть отобрано или изменено из любой точки описания.
begin
fork :mod_1
reg x;
mod_2.x = 1;
join
fork :mod_2
reg x;
mod_1.x = 0;
join
end
12.6 Ссылка на имя верхней области
Имена модуля или экземпляра модуля достаточно для идентификации модуля и его местоположения в иерархии. Модуль нижнего уровня может ссылаться на элементы модуля, находящегося выше него в иерархии. На переменные могут ссылаться, если известно имя модуля более высокого уровня или имя его экземпляра. Для задач(task), функций(function), именованных блоков и блоков генерации(generate) Verilog должен искать имя в объемлющем модуле, пока оно не будет найдено или пока не будет достигнут корень иерархии(модуля верхнего уровня). Он должен искать имя только в более высоких объемлющих модулях, но не в экземплярах.
Синтаксис для ссылки на верхние области приведен в Синтаксисе 12-7.
upward_name_reference ::=
module_identifier.item_name
item_name ::=
function_identifier
| block_identifier
| net_identifier
| parameter_identifier
| port_identifier
| task_identifier
| variable_identifier
Возрастающем ссылки на имена также могут быть сделаны с именами вида имяобласти.имяэлемента(scope_name.item_name), где имя области является либо именем экземпляра модуля, либо именем блока generate. Имя такой формы должно быть передаваться следующим образом:
- Поиск в текущей области видимости область видимости с именем области. Если она не найдена и текущая область видимости не является областью видимости модуля, ищите имя в верхней области видимости, повторяя при необходимости, пока имя не будет найдено или не будет достигнута область видимости модуля. Если имя все еще не найдено, перейдите к шагу 2). В противном случае эта ссылка на имя должна рассматриваться как нисходящая ссылка из области видимости, в которой найдено имя.
- Ищите в самой внешней области видимости родительского модуля области видимости с scope_name видимости. Если он найден, имя элемента будет передаваться из этой области видимости.
- Повторите шаг 2), поднимаясь вверх по иерархии.
Существует исключение из этих правил для иерархических имен в левой части объявления defparam. Подробности см. в разделе 12.8.
Например:
module a;
integer i;
b a_b1();
endmodule
module b;
integer i;
c b_c1(), b_c2();
initial // нисходящий путь ссылается на 2 копии i:
#10 b_c1.i = 2; // a.a_b1.b_c1.i, d.d_b1.b_c1.i
endmodule
module c;
integer i;
initial begin // локальное имя ссылается на 4 копии i:
i = 1; // a.a_b1.b_c1.i, a.a_b1.b_c2.i,
// d.d_b1.b_c1.i, d.d_b1.b_c2.i
b.i = 1; // Возрастающем пути ссылается на 2 копии i:
// a.a_b1.i, d.d_b1.i
end
endmodule
module d;
integer i;
b d_b1();
initial begin // полное имя пути ссылается на каждую копию i
a.i = 1; d.i = 5;
a.a_b1.i = 2; d.d_b1.i = 6;
a.a_b1.b_c1.i = 3; d.d_b1.b_c1.i = 7;
a.a_b1.b_c2.i = 4; d.d_b1.b_c2.i = 8;
end
endmodule
12.7 Правила области
Следующие элементы определяют новую область видимости в Verilog:
- module
- task
- function
- Именованные блоки
- Блоки generate
Идентификатор должен использоваться для объявления только одного элемента в пределах области видимости. Это правило означает, что объявлять две или более переменных с одинаковым именем, или называть задачу так же, как переменную в том же модуле, или давать экземпляру вентиля то же имя, что и имя сети, подключенной к его выходу, запрещено. Для блоков generate это правило применяется независимо от того, инстанцирован ли блок generate. Исключение сделано для блоков generate в условной конструкции generate. Обсуждение именования условных блоков генерации см. в разделе 12.4.3.
Если на идентификатор ссылаются непосредственно (без иерархического пути) внутри task, function, именованного блока или блока generate, то он должен быть объявлен либо внутри task, function, именованного блока или блока generate локально, либо внутри module, task, function, именованного блока или блока generate, который находится выше в той же ветви дерева имен, которая содержит task, function, именованный блок или блок generate. Если элемент объявлен локально, то используется локальный элемент. Если нет, то поиск продолжается вверх, пока не будет найден элемент с таким именем или пока не будет встречена граница модуля. Если элемент является переменной, то поиск останавливается на границе модуля. Если элемент является task, function, именованным блоком или блоком generate, то поиск продолжается в модулях более высокого уровня до тех пор, пока он не будет найден. Этот факт означает, что task и function могут использовать и изменять переменные внутри содержащего модуля по имени, не проходя через его порты.
Если на идентификатор ссылается иерархическое имя, путь может начинаться с имени модуля, имени экземпляра, задачи(task), функции(function), именованного блока или именованного блока generate. Имена должны искаться сначала на текущем уровне, а затем в модулях более высокого уровня, пока не будут найдены. Поскольку могут использоваться как имена модулей, так и имена экземпляров, приоритет отдается именам экземпляров, если существует модуль с тем же именем, что и имя экземпляра.
Из-за восходящего поиска можно использовать имена путей, которые не находятся строго на нисходящем пути. Например:
Пример 1 — На рисунке 12-3 каждый прямоугольник представляет локальную область поиска. Область видимости, доступная для восходящего поиска, распространяется на все содержащие прямоугольники — с границей модуля A в качестве внешней границы. Таким образом, блок G может напрямую ссылаться на идентификаторы в F, E и A. Он не может напрямую ссылаться на идентификаторы в H, B, C и D.

Рисунок 12-3 Области, доступные для ссылки на имя
task t;
reg s;
begin : b
reg r;
t.b.r = 0;// Эти три строки обращаются к одной и той же переменной r
b.r = 0;
r = 0;
t.s = 0;/ Эти две строки обращаются к одной и той же
s = 0;
end
endtask
12.8 Элаборация
Элаборация — это процесс, который происходит между разбором и моделированием. Он связывает модули с экземплярами модулей, строит иерархию модели, вычисляет значения параметров, передает иерархические имена, устанавливает сетевые связи и готовит все это к моделированию. С добавлением конструкций generate порядок выполнения этих задач становится важным.
12.8.1 Порядок Элаборации
Из-за конструкций generate иерархия модели может зависеть от значений параметров. Поскольку операторы defparam могут изменять значения параметров практически из любой точки иерархии, результат элаборации может быть неоднозначным, когда задействованы конструкции generate.
Окончательная иерархия модели может зависеть от порядка, в котором оцениваются конструкции defparam и generate.
Следующий алгоритм определяет порядок, который создает правильную иерархию:
- Список начальных точек инициализируется списком модулей верхнего уровня.
- Иерархия под каждой начальной точкой расширяется настолько, насколько это возможно без детализации общих конструкций. Все параметры, встречающиеся во время этого расширения, получают свои окончательные значения путем применения начальных значений, переопределения параметров и объявление defparam. Другими словами, любое объявление defparam, цель которого может быть определена в иерархии, элаборации до сих пор, должно иметь свою цель и свое значение. Объявление defparam, цель которых не может быть определена, откладываются до следующей итерации этого шага. Поскольку ни один defparam в иерархии ниже конструкции generate не может ссылаться на параметр вне конструкции generate, возможно, что параметры получат свои окончательные значения до перехода к шагу 2).
- Каждая конструкция generate, встреченная на шаге 2), просматривается, и схема generate оценивается. Полученные экземпляры блока generate составляют новый список начальных точек. Если новый список начальных точек не пуст, перейдите к шагу 2).
12.8.2 Раннее передача иерархических имен
module m;
m1 n();
endmodule
module m1;
parameter p = 2;
defparam m.n.p = 1;
initial $display(m.n.p);
generate
if (p == 1) begin : m
m2 n();
end
endgenerate
endmodule
module m2;
parameter p = 3;
endmodule
В этом примере defparam должен быть оценен до того, как будет элаборация условной конструкции generate. На этом этапе элаборации имя передается в parameter p в модуле m1, и этот параметр используется в схеме generate. Результатом действия defparam является присвоение этого параметра в 1. Следовательно, условие generate истинно. После элаборации иерархии под конструкцией generate правила передач иерархического имени диктуют, что имя должно было передаваться в parameter p в модуле m2. На самом деле, идентичное имя в операторе $display будет передаваться на этот другой параметр.
Будет ошибкой, если иерархическое имя в defparam будет начинать передачу до того, как иерархия будет полностью проработана, и это имя будет трактоваться по-другому после того, как модель будет полностью проработана.
Такая ситуация возникает очень редко. Чтобы вызвать ошибку, должен существовать именованный блок generate, который имеет то же имя, что и одна из областей видимости в ее полном иерархическом имени. Кроме того, должны существовать два экземпляра с одинаковым именем, один в блоке generate, а другой в другой области видимости с тем же именем, что и блок generate. Затем внутри этих экземпляров должны быть параметры с тем же именем. Если такая проблема возникла, ее можно легко устранить, изменив имя блока generate.