Перейти к содержанию
    

Блокирующее присваивание - симуляция отличается от синтеза

1 minute ago, pavlovconst said:

По каким правилам он "адаптирует"? :shok: И как разработчик должен быть уверен, что при очередной перекомпиляции эта адаптация не приведет к другому результату?

А нет этих правил, можно интерпретировать как баг синтеза. Бывали случаи когда синтезатор даже неправильно интерпретировал имена регистров, только для одной версии.

Для FPGA можно и так посмотреть, в случае с ASIC есть Formality.

В последнем проекте: ncsim, vivado, dc и Formality, как один пакет (по чипу потом все сошлось) выдавали одно, а вот результат Zebu отличался. Причем это был как SystemVerilog (в чем я еще могу согласится), но и чистый Verilog.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 hours ago, dxp said:

Синтез имеет другую исполнительную модель - "тру параллел", там гонок в этом смысле нет.

Пока что получается, что синтезатор имплементирует код именно так, как задумал разработчик. А симуляторы, для того, чтобы воспроизвести тот же результат, что и в реальности - требуют переписать код и соблюсти много дополнительных условий. Видите ли, у них там "сложная временная модель"... =)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

1 hour ago, pavlovconst said:

Пока что получается, что синтезатор имплементирует код именно так, как задумал разработчик.

Синтезатор и симулятор выполняют разные задачи. Синтез физической структуры обработки дизайна и симуляция поведения во времени. Отсюда и возможные разные результаты при одном и том же входном коде.  Ну и опять же - чтобы симулятор  правильно отображал реальную действительность модель симуляции должна быть полной. А чисто функциональная симуляция грешит  упрощениями (0 задержки) для ускорения этого процесса. Вот сим и не понял что задумал разработчик. 

 

1 hour ago, lexx said:

По каким правилам он "адаптирует"? :shok: И как разработчик должен быть уверен, что при очередной перекомпиляции эта адаптация не приведет к другому результату?

Как обычно - разработчик делает pots-synthesis/post-P&R симуляцию и сравнивает поведение с функциональной golden reference моделью. Да еще и формальная верификация добавляется. И если вдруг будут разные результаты - то начинает копать, чтобы понять где именно  (в синтезаторе или в симе) он нако... был неправильно понят :unknw:.

Удачи! Rob.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, pavlovconst said:

По каким правилам он "адаптирует"?

Насколько мне известно изначально происходит распознавание синтаксических структур и прагм. потом на основе этих данных происходит синтезирование примитивов и элементов, ну а дальше map, place&route.

Чтобы быть уверенным в каждом проходе компиляции достаточно выдерживать одни и те же правила описания (которые описаны в стандарте) и никаких проблем не должно возникнуть (если только вы не перешли на другой, свежий и новый синтезатор - старые игроки обычно не грешат изменением поддержки стандартов)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

56 minutes ago, RobFPGA said:

Как обычно - разработчик делает pots-synthesis/post-P&R симуляцию и сравнивает поведение с функциональной golden reference моделью.

Симуляция не покрывает, только формальная верификация.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 hours ago, dxp said:

почитайте про планировщик виртуальной машины симулятора (по ссылкам выше про это тоже есть), например, тут

Почитал, и мне даже удалось заставить симулятор сделать задержку в два такта.

Но такой код, с перемешанными блокирующими и неблокирующими присваиваниями, оставлять в проекте мне было бы стыдно. =(

module main(

  input clk,
  input nrst,
  input [7:0] in_data,
  output [7:0] out_data
);

reg [3:0] brd_err2 = 0;
reg [7:0] brd_err2_cntr = 0;

always @(posedge clk) begin
  if( ~nrst ) begin
    brd_err2_cntr[7:0] <= 0;
    brd_err2[3:0] = 0;
  end else begin
    brd_err2_cntr[7:0] <= brd_err2_cntr[7:0] + brd_err2[3] +
                                               brd_err2[2] +
                                               brd_err2[1] +
                                               brd_err2[0];
    brd_err2[3] = in_data[3] || in_data[2] || in_data[1] || in_data[0];
    brd_err2[2] = in_data[4] || in_data[2] || in_data[1] || in_data[0];
    brd_err2[1] = in_data[5] || in_data[2] || in_data[1] || in_data[0];
    brd_err2[0] = in_data[3] || in_data[1];
  end
end

assign out_data[7:0] = brd_err2_cntr[7:0];

endmodule

 

2019-09-30 12 34 25.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

18 minutes ago, pavlovconst said:

Почитал, и мне даже удалось заставить симулятор сделать задержку в два такта.

Но такой код, с перемешанными блокирующими и неблокирующими присваиваниями, оставлять в проекте мне было бы стыдно. =(

уберите блокирующие. они,  в вашем случае роли не играют абсолютно. так будет не стыдно?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 минут назад, pavlovconst сказал:

Почитал, и мне даже удалось заставить симулятор сделать задержку в два такта.

А почему сразу не сделать это в явном виде.

Ведь Вам дали ссылку на Клиффа:

Guideline: Use blocking assignments in always blocks that are written to generate
combinational logic [1]. 
Guideline: Use nonblocking assignments in always blocks that are written to generate
sequential logic [1]. 

Но Вы это игнорируете...

И еще. Вам действительно надо сделать что-то вроде этого: 

brd_err2[3] = in_data[3] || in_data[2] || in_data[1] || in_data[0];

только за один такт? С какой скоростью в проект "прибывают" данные и какая частота у "clk"? Может быть можно успеть все эти вычисления сделать и по-другому?

А главный вопрос вот какой: какой смысл делать вот так: " Намеренно использую при этом блокирующее присваивание, так код получается коротким и хорошо читаемым."? Если потом приходится более 20-то часов выяснять как преодолеть проблему данного кода. И проблема еще не решена. Потому как если даже Вы заставите программные инструменты сделать "как надо" сегодня, то через полгода-год появится новая версия софта и возможно проблемы выплывет снова. IMXO, за 20 часов можно переделать проект так, чтобы наверняка не было никаких проблем... 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

25 minutes ago, iosifk said:

А почему сразу не сделать это в явном виде.

ну лень ему писать красиво

always @(posedge clk) begin
  if( ~nrst ) begin
    brd_err2      <= '0;
    brd_err2_cntr <= '0;
  end else begin
    brd_err2[3] <= |{            in_data[3 : 0]};
    brd_err2[2] <= |{in_data[4], in_data[2 : 0]};
    brd_err2[1] <= |{in_data[5], in_data[2 : 0]};
    brd_err2[0] <= |{in_data[3], in_data[1]};
    //
    brd_err2_cntr <= brd_err2_cntr + brd_err2[3] + brd_err2[2] + brd_err2[1] + brd_err2[0];
  end
end

да и обычный декодер флагов это, со счетчиком событий

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Попробуйте еще добавить задержки в неблокирующие присваивания. Так проще смотреть значения выходов при движении курсора по фронту клока.

Например, так:

`timescale 1ns/100ps

...

 brd_err2_cntr[7:0] <= #1 brd_err2_cntr[7:0] + ...

 

Пишут что это не всегда хорошо. За и против взвешены в этой статье:

http://www.sunburst-design.com/papers/CummingsSNUG2002Boston_NBAwithDelays.pdf

Я пока не сталкивался со случаями, когда бы это вредило.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

49 minutes ago, des00 said:

ну лень ему писать красиво

des00, Спасибо за "красивый" вариант, но в целевом проекте все несколько сложнее устроено. Поэтому я и пытаюсь дожать вариант с блокирующими.

1 hour ago, iosifk said:

если даже Вы заставите программные инструменты сделать "как надо" сегодня, то через полгода-год появится новая версия софта и возможно проблемы выплывет снова

Порядок обработки событий планировщиком симулятора, описанный в стандарте, поменяется наврядли =)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

19 minutes ago, pavlovconst said:

des00, Спасибо за "красивый" вариант, но в целевом проекте все несколько сложнее устроено. Поэтому я и пытаюсь дожать вариант с блокирующими.

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

Точнее не так, что там такое, что непременно требует блокирующее присваивание, без возможности реализации на внутренних, для процесса, переменных?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 минуты назад, des00 сказал:

Точнее не так, что там такое, что непременно требует блокирующее присваивание, без возможности реализации на внутренних, для процесса, переменных?

Я дополню... Хотя бы даже не код, а словесное описание или блок-схему алгоритма...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 hours ago, des00 said:

Точнее не так, что там такое, что непременно требует блокирующее присваивание, без возможности реализации на внутренних, для процесса, переменных?

При синтезе все равно будет как блокируещее,  так что не понимаю упорства.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 30.09.2019 в 14:48, pavlovconst сказал:

Пока что получается, что синтезатор имплементирует код именно так, как задумал разработчик. А симуляторы, для того, чтобы воспроизвести тот же результат, что и в реальности - требуют переписать код и соблюсти много дополнительных условий. Видите ли, у них там "сложная временная модель"... =)

Несколько не так. Исходно HDL (верилог, в частности) разрабатывались как языки для моделирования. Отсюда и возникла концепция исполнительной виртуальной машины, обеспечивающей корректное моделирование параллельно выполняемых процессов, и машина эта работает по определённым правилам - например, те же самые блокирующие и неблокирующие присваивания, которые работают в разных регионах событий и позволяют более гибко описывать процесс моделирования.

 

Идея использовать синтез из верилог-описания возникла позднее, и не все средства языка для этого поддерживаются - существует некое синтезируемое подмножество. Естественно, что синтезированная реализация работает на другой исполнительной платформе, где нет виртуальной машины, соответственно, нет и ограничений, связанных с ней. С другой стороны возникает набор своих требований - например, не всякое даже в принципе синтезируемое описание может быть реализовано на конкретной платформе - например, если вы напишите:

 

always @(posedge clk or negedge clk) ...

 

и попытаетесь скормить это синтезатору практически любой современной ПЛИС, то получите отлуп, т.к. такая конструкция предполагает реализацию в виде флопа, работающего по обоим фронтам, а таких в нынешних ПЛИС просто нет (вроде были в Spartan или Spartan2), в то время как симулятор это съест без проблем.

 

Собственно именно логика работы неблокирующих присваиваний в тактируемых поведенческих блоках и ложится нативно на поведение флопов - по фронту записывается значение, которые было на входе до фронта (на момент его возникновения). А блокирующее присваивание нарушает эту логику - там выстраивается цепочка присваиваний - это как раз хорошо ложится на описание комбинационной логики - там важен порядок следования сигналов по логическим переменным. Отсюда и возникло простое правило: для описания флопов - тактируемые блоки с неблокирующими присваиваниями, для комбинационной - нетактируемые блоки с блокирующими. Это порождает корректное поведение с точки зрения соответствия "виртуальная машина симулятора - аппаратное исполнительной устройство". 

 

Отсюда простой вывод: если хочется иметь в арсенале мощный инструмент для моделирования (симулятор) и иметь от него пользу, надо просто соблюдать пару простых правил. 

 

Блокирующие присваивания, кстати, очень даже применимы в тактируемых блоках, но только для вычисления значений переменных, используемых в правой части неблокирующих присваиваний - нередко это просто удобно и повышает читабельность, когда логика развесистая и нетривиальная. Для симулятора тут всё корректно: сперва вычисляются значения блокирующих (Active Region), причём итеративно (учитывая изменения переменных в других блоках в текущем дельта-цикле), затем они присваиваются через неблокирующие (NBA Region). Синтез тоже понимает эту логику и прекрасно разносит реализацию на комбинационную логику и флопы.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...