Почему «назначить a = a/2» (внутри задачи) вызывает изменение только одного значения?

Сегодня я столкнулся с очень необычным фрагментом тестового кода, и все были в недоумении, почему он работает именно так. Упрощенная версия будет выглядеть примерно так (обратите внимание, что тест написан внутри task):

task TEST();
    logic [9:0] a;

    assign a = 10'd512;
    #10ns;
    assign a = a/2;
    #100ns;

endtask

Мои вопросы:

  1. Ожидалось, что a будет продолжать делиться на 2 каждую единицу дельты времени, пока его значение не достигнет 0. Но вместо этого при моделировании (с использованием Xcelium) оно делится только один раз, и конечный результат равен a = 256. Почему это? Коллега подтвердил с помощью небольшого теста, что assign работает нормально в задаче, если RHS не содержит переменную LHS. Поэтому я предполагаю, что это как-то связано с тем, что по сути это блок Always@(...), где единственной переменной в списке чувствительности является также переменная LHS, но я нигде не могу найти описание того, что происходит в этом конкретном случае. .

  2. Я был озадачен тем, почему код компилируется успешно и даже без каких-либо предупреждений, имея 2 оператора assign для одной и той же переменной. В поисках ответа я обнаружил, что в разделе 10.6.1 версии LRM 1800-2017 говорится:

Если ключевое слово Assign применяется к переменной, для которой уже существует процедурное непрерывное присваивание, то это новое процедурное непрерывное присвоение должно отменить назначение переменной перед выполнением нового процедурного непрерывного присвоения.

И теперь я еще больше запутался: почему LRM говорит это, если наличие двух операторов assign для одной и той же переменной обычно приводит к ошибкам компиляции (несколько драйверов) в модуле вместо сохранения последнего оператора assign и игнорирования остальных?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
  1. Семантика планирования непрерывных назначений четко не определена в LRM. Между оценкой RHS и обновлением LHS нет разницы во времени — они оба происходят в одной и той же активной области. Обратите внимание, что обновление может произойти немедленно или быть помещено в очередь. LRM не определяет порядок событий внутри региона, хотя используется термин «очередь». Это дает инструментам свободу выполнять обновление перед планированием чувствительности RHS.

  2. Вы путаете структурные непрерывные задания с процедурными непрерывными заданиями. Это обычное явление, поскольку обе конструкции используют одно и то же ключевое слово assign.

В сети может быть несколько непрерывных присвоений (драйверов), но только одно непрерывное присвоение переменной.

Процедурное непрерывное присвоение переопределяет все процедурные присвоения переменной и заменяет любое предыдущее процедурное непрерывное присвоение этой переменной.

Процедурные непрерывные присваивания изначально предназначались для моделирования асинхронного поведения отдельного процесса от синхронного поведения триггера. Однако большинство инструментов синтеза решили ограничить моделирование триггера одним (always) процессом. Эта конструкция сейчас используется редко.

Операторы процедурного назначения и операторы deassign считаются устаревшими, IEEE1800-2023 C.4.2. Но его считали устаревшим, начиная с IEEE1800-2005 25.4, так что кто знает, сколько времени пройдет, прежде чем он фактически устареет.

Greg 16.07.2024 20:52

Спасибо, Дэйв. Я чувствую, что это отвечает на мой второй вопрос, но я не уверен насчет первого. Процедурный непрерывный оператор по-прежнему является «непрерывным», так почему же assign a = a/2 не вызывает бесконечный цикл обновления значения? Я предполагаю, что такой код является плохой практикой, и удивлен, что он не вызывает ошибки/предупреждения (есть ли что-то специально запрещающее такой код?). Должен ли результат, который я описал в своем вопросе, быть записан как реакция конкретного инструмента на плохую практику кодирования, или есть какое-то связанное с SV объяснение того, что значение обновляется только один раз?

DeFalco 17.07.2024 01:21

Другие вопросы по теме