Существует переменная reg, содержащая огромный массив данных. Эта переменная объявляется и инициализируется внутри модуля.
Я создал функцию внутри модуля Verilog для доступа к этим внешним данным. Удивительно, но я могу сделать это без каких-либо проблем.
Итак, есть ли причина, по которой мне следует передавать значения в качестве входных данных функции, когда она может просто получить доступ к внешним переменным?
Вот пример кода, чтобы показать, что я имею в виду
module TestModule (
input clock,
output Out
);
// Variable declared outside the function
reg [7:0] externalVariable [10:0];
// Function declaration
function [7:0] myFunction;
input arg;
begin
myFunction = externalVariable[arg];
end
endfunction
always @(posedge clock) begin
// Assign a value to the external variable
Out <= myFunction(1);
end
endmodule
Я смоделировал приведенный выше пример, и он работает. Но почему?
Могут ли функции Verilog обращаться к переменным, объявленным вне функционального блока?
Короткий ответ: Да
Почему?:
Каждый модуль создает область действия; переменная externalVariable
находится в области модуля TestModule.
Поэтому externalVariable
доступен конструкциям Verilog в той же области видимости.
Я бы рассмотрел возможность добавления аргументов и переменных по мере необходимости для локализации поведения и объявления хранилища функции как automatic
. Хранилищем по умолчанию для функций является статическое (общие переменные).
Объявление функции automatic
делает ее реентерабельной, вызывает динамическое выделение памяти при каждом ее вызове, а не совместное использование переменных между различными вызовами задачи.
Объявление автоматической функции выглядит так
function automatic [7:0] myFunction;
Дополнительную информацию см. в разделе 10 «Задачи и функции» стандарта IEEE 1364-2005 (последняя спецификация Verilog).
Этот пост может оказаться вам полезным в отношении Область действия модуля переменных Verilog
Я не знаю, какой симулятор вы используете, но ваш код не скомпилировался, когда я использовал коммерческие симуляторы на www.edaplayground.com
Я получаю ошибку
design.sv, 20
Net type cannot be used on the left side of this assignment.
The offending expression is : Out
Source info: Out <= myFunction(1);
То есть часть Out
должна измениться с:
output Out
к
output reg Out
По умолчанию для outputs
используется тип wire
, и wires
нельзя управлять из блока always
в Verilog.
Вы также можете изменить расширение файла на .sv, вызвав таким образом компилятор SystemVerilog. В SystemVerilog используйте команду logic
вместо wire/reg
, и инструмент сделает правильное действие и освободит вас от правил wire/reg
.
@ Dave59 и другие указали на потенциальные недостатки доступа к переменной, определенной вне fn. Я рекомендую вам понять и запомнить их точку зрения, а затем действовать соответствующим образом. Существуют инструменты проверки, которые вы можете запустить в проектах Verilog, которые будут отмечать подобные вещи с разной степенью серьезности. Мнения о ценности инструментов для ворса различаются. Назначение блокировки в функции моделирует комбинационную логику (в данном случае мультиплексор). У вас есть шинный мультиплексор, управляющий однобитовым триггером.
Функция или задача, безусловно, могут ссылаться на сигналы, объявленные вне ее. Но есть одна вещь, с которой вам следует быть осторожным, — это чувствительность к комбинационной логике. Если вместо этого вы попытаетесь использовать непрерывное присваивание, например
assign someWire = myFunction(someIn);
или
always @(*) someReg = myFunction(someIn);
Тогда симуляция вызывает myFunction
только тогда, когда someIn
меняет свое значение, а не когда изменяется externalVariable.
SystemVerilog решает эту проблему с помощью блока alway_comb
. Он встраивает все вызовы функций и делает процесс всегда чувствительным ко всем изменениям внешних переменных.
Если вы говорите о Verilog, правила области действия определены в 1364-2005 12.7. SystemVerilog, возможно, внес некоторые незначительные изменения, но, скорее всего, нет, поскольку это могло бы что-то сломать. В правилах указано, что
Если на идентификатор ссылаются напрямую (без иерархического пути) внутри задачи, функции, именованного блока или блока генерации должно быть объявляется либо внутри задачи, функции, именованного блока, либо генерируется блокировать локально или внутри модуля, задачи, функции, именованного блока или сгенерировать блок, который находится выше в той же ветви дерева имен, что и содержит задачу, функцию, именованный блок или блок генерации.
Таким образом, внутри функции вы можете напрямую ссылаться на что-то, объявленное во включающем модуле.
Стоит ли вам это делать? Вам решать. Если у вас есть опыт программирования, вы, вероятно, предпочли бы умереть первым. Функции предназначены для инкапсуляции функциональности; привлечение произвольных вещей извне нарушает это. Это также делает функцию «нечистой», что не является концепцией в Verilog, но, вероятно, является причиной того, что вы не можете делать причудливые вещи во время компиляции в Verilog (например, такие вещи, как предварительное вычисление коэффициентов фильтра, что распространено среди других ЛПВП и наблюдается на протяжении десятилетий). SystemVerilog добавил концепцию чистых функций, так что, возможно, они это исправили.
Интересно, что если вы используете иерархический идентификатор, вы можете получить доступ ко всему, что захотите, где угодно. Опять же, хорошо это или плохо, решать вам, но не делайте этого в синтезируемом коде. Он может быть фантастически полезен в тестовых стендах, и я широко использую его в коде, который компилируется для создания Verilog. Интересно, что невозможность использовать подобные иерархические идентификаторы в An Other HDL всегда была серьезным недостатком, на исправление которого уходили годы.
Это был всего лишь пример кода, который я быстро написал, чтобы показать, что означает вопрос. Мне не разрешено делиться реальным кодом. Итак, вы говорите, что единственная проблема, связанная с приведенным выше дизайном (кроме оператора блокировки), заключается в том, что пользователь не будет знать, как работает функция. Я прав?