Рассмотрим приведенный ниже пример:
module test;
reg a;
initial begin
a = 1'b0;
a <= 1'b1;
$display(a);
end
endmodule
В приведенном выше примере отображается 0. Моя причина в том, что неблокирующее назначение будет назначено на шаге 3 «Стратифицированной очереди событий», а назначение блокировки и отображение $ выполняются на шаге 1. Если я изменю пример следующим образом:
module test;
reg a;
initial begin
a = 1'b0;
a <= 1'b1;
$display(a);
$monitor(a);
end
endmodule
Затем печатаются 0 и 1, потому что я предполагаю, что $monitor выполняется на шаге 4 очереди событий (?). Но если я изменю пример дальше:
module test;
reg a;
initial begin
a = 1'b0;
a <= 1'b1;
$monitor(a);
$display(a);
end
endmodule
Снова вывод: 0 и 1 - чего я не ожидал. Я ожидал, что 1 и 1 будут напечатаны, потому что $monitor будет оцениваться на шаге 4 очереди событий, когда «a» уже равно 1. После этого у нас есть $display, который должен напечатать 1.
Ссылки Я мог найти разговоры о "текущем времени симуляции" и "стратифицированной очереди событий", но я не уверен, как это работает.
Я ценю ваше объяснение! Спасибо
Цикл моделирования Verilog более сложен, чем описывает ваше текущее объяснение. Краткий ответ на ваш вопрос заключается в том, что $monitor
не ждет конца текущего цикла, показывает свое сообщение, затем продолжает выполнение процесса (и, таким образом, запускает $display
впоследствии), а вместо этого просто планирует отображение сообщения в конце любого цикл моделирования, в котором изменяется любая из зависимых переменных (в данном случае просто a
); это очень специальный (и довольно устаревший) способ отслеживания изменений сигналов во время симуляции. $display
однако выполняется немедленно, таким образом печатая то, что a
есть в данный момент. Таким образом, другой способ думать об этом похож на неблокирующее присваивание (<=
), $monitor
просто настраивает что-то, что произойдет позже, и выполнение продолжается до следующего оператора, а не происходит внутри.
Вам следует рассмотреть возможность изучения имитационной модели systemverilogs, принимая во внимание активные, nba и отложенные регионы, поскольку они используются при выполнении блокирующих назначений (=
), неблокирующих назначений (<=
) и $monitor
соответственно.
Моделирование Verilog управляется событиями. Событие — это изменение значения переменной Verilog (или именованного события). Моделирование выполняется поэтапно.
Шаг начинается с ввода событий, помещенных в очередь событий. Каждое новое изменение значений из-за оценки создает новые события, которые добавляются в очередь. Моделирование завершается, когда очередь становится пустой (активных событий больше нет). Каждый такой шаг увеличивает время моделирования.
Сам шаг разделен на несколько зон, которые выполняются с использованием алгоритма, определенного в стандарте.
Для Verilog 2K существует примерно 3 основные зоны:
блокировка зоны назначения. Verilog выполняет все процедурные блоки, запланированные очередью событий, и реагирует на новые события назначения блокировки. Он просто планирует выполнение событий nbas позже. Когда все блокирующие события выполнены, он попадает в следующую зону.
неблокирующая зона назначения. Здесь он выполняет все блоки, которые реагируют на события расписания nba. Это поставит в очередь как событие ba, так и событие nba. Когда все nba будет выполнено, он может вернуться в зону «1», если есть событие ba, и все повторится.
зона монитора/строба -- это зона, в которой работают $monitor (и $strob). Он выполняется после завершения обеих зон ba и nba (больше никаких событий).
В вашем случае a = 1
выполняется в зоне назначения блокировки. это значение сохраняется до конца этой зоны. $display
также будет выполняться в этой зоне. Таким образом, он увидит значение «a == 0».
a <= 1
будет график выполнения в неблокирующей зоне, после выполнения $dislpay.
$monitor
выберет события в зоне монитора после того, как будет снята блокировка. Таким образом, он покажет вам значение 1
.
Ваши утверждения выполняются в блоке initial
. В результате нет распространения событий. Только события выбираются операторами always
и assign
. Если вы поместите свой $display
в блок «всегда», вы увидите более интересные результаты. always @* $display(a);
Вы должны прочитать о стандартной семантике моделирования в verilog, чтобы получить больше информации.