dxp 42 1 марта, 2019 Опубликовано 1 марта, 2019 · Жалоба Столкнулся с неприятностью, где не ожидал. Имею сгенерённую корку Independent Clock Block RAM FIFO, упрощена до предела - 8 бит данных на входе, 8 на выходе. На wr_en (порт записи данных) поступает сигнал: assign wr_en = !full && data_valid; // data_valid поступает синхронно с данными с внешнего мира (из тестбенча). Неприятность состоит в том, что данные на выходе не соответствуют входным. Поведение в этом контексте было разным (в зависимости от конфигурации корки в основном зависит - был вариант с downsizing), в текущей простейшей конфигурации последнее слово читается неверно - всегда нули. Эксперименты показали, что поведение зависит от конкретного числа дельтациклов при вычислении сигнала wr_en. Например, если пропустить его через регистр, то ошибки уходят. Или, скажем, если задержать: assign wr_en = #0.1ns !full && data_valid; то тоже начинает показывать правильную временную диаграмму. Исследование показало, что во всех этих случаях, если смотреть в режиме delta cycles (в квесте), то количество дельтациклов разное. Например, в исходном случае их на сигнале wr_en +11, в случае, если его пропустить через регистр, то +8. Получается, там внутри модели какие-то гонки и отсюда и такое поведение. В общем, хочется понять, как быть. Конечно, самое простое оставить транспортную задержку в 100 пс, но это пахнет костылями. А хочется сделать нормально. Прошу высказываться. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
new123 0 1 марта, 2019 Опубликовано 1 марта, 2019 · Жалоба я третий день сижу с этой проблемой. Но в альтере. По аналогии wr_en был очень сложный и не успевал временами (слак). Но мне об этом честно сказал Timing Analyzer сразу. Ну и ширина данных у меня 64 бита. Перелопатил всю логику. Мне кажется у вас нечто похожее, стоит поменять размещение wr_en, поведение меняется. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 42 1 марта, 2019 Опубликовано 1 марта, 2019 · Жалоба Я рассматриваю сугубо функциональную симуляцию, тут нет никаких зависимостей от ширины данных и частот - это логическое моделирование, не временнОе. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
new123 0 1 марта, 2019 Опубликовано 1 марта, 2019 · Жалоба Just now, dxp said: Я рассматриваю сугубо функциональную симуляцию да действительно, не вчитался в название, прошу прощение. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MegaVolt 26 1 марта, 2019 Опубликовано 1 марта, 2019 · Жалоба В 14.7 те же баги? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RobFPGA 27 1 марта, 2019 Опубликовано 1 марта, 2019 · Жалоба Приветствую! Тут интересно бы знать что конкретно глючит? На последнем слове нет записи в память но при этом увеличивает указатель и счетчик? Или вообще нет записи? Или пишет 0, или еще как? FIFO у Xilinx до сих пор на VHDL значит могут быть глюки/гонки в самом симуляторе на стыке verilog/VHDL или в непосредственно в шедулере сима. У меня было похожее (правда довольно давно уже) - поведение сима менялось от порядка расположения always блоков в исходнике. И вроде было (опять же давно и точно не помню) похожая ситуация с при передаче клока в нижний модуль через несколько промежуточных assign. Какая версия сима? Корка из ISE или Vivado? Удачи! Rob. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 42 2 марта, 2019 Опубликовано 2 марта, 2019 · Жалоба Подробности такие. Инструментарий: Vivado 2018.2, Questasim 10.4e. Исходно у меня в проекте используется вариант с даунсайзом 132:66. Поведение было такое: записываю два слова (по 132 бита), на выходе читаю 4 (по 66), первые два нули, вторые два соответствуют второму 132-разрядному входному. Т.е. как будто первое слово по данным (но не по логике прохождения данных) потерялось. Чтение осуществляется, естественно, по признаку !empty. Далее последовало изрядное количество экспериментов. Сначала перегенерил корку с портами wr_data_count, rd_data_count. На wr_data_count всегда присутствует ненулевое значение, т.е. если FIFO пустое, то там торчит 1. На rd_data_count при этом честный 0. Запись и чтение показывают, что значения этих сигналов корректны (если считать, что 1 на wr_data_count верна, а это скорее всего так - у правильно работающих вариантов (см. ниже) это всё точно так же). Логика работы full/empty флагов тоже правильная. Затем я просто клонировал FIFO - создал ещё инстанс этой же корки и подал туда сигналы с простого генератора (счётчика). Вижу, то работает правильно. Дальше стал выяснять, по какому же сигналу возникает проблема. Менял местами данные между боевой и тестовой коркой, логика работы не поменялась (т.е. боевая работала так же неправильно, а тестовая - правильно), значит дело не в данных. Потом поменял местами сигналы wr_en. И вот тут оно и проявилось. Т.е. проблема именно в wr_en. Разница между этими сигналами для корок в том, что в боевом варианте этот сигнал формируется на комбинаторной логике (пробовал assign и always_comb, разницы между ними, в общем, нет, что логично), а для тестовой - на флопе. Когда я пропустил тот комбинаторный сигнал через флоп, то правильность работы FIFO восстановилось (естественно, логика работы при этом нарушается из-за сдвига на такт, но в данном случае это не важно). Всё это выглядит странным - ведь что сигнал с комбинаторной логики, что с флопа поступают одновременно, т.е. при функциональном логическом моделировании все сигналы вычисляются за модельное время 0, и на симуляторе они рисуются в один и тот же момент времени. Очевидно, что несмотря на модельное время 0 в реальности там сигналы вычисляются не одновременно, а в зависимости от сложности логики - это можно увидеть в режиме просмотра дельтациклов. И действительно, например, сигнал с флопа появлялся в том случае после фронта клока через +8 дельтациклов, а с комбинаторной логики через +11. Потом я пробовал менять логику вычисления wr_en, это приводило к изменению результатов по данным на выходе - например, был вариант, когда первое слово выходит правильно, второе - половина текущего, половина следующего, третье - ноль. При этом, опять же, логика работы full/empty (и wr/rd_data_count) всегда правильные, т.е. портятся только данные. Отличия порождаются, полагаю, из-за того, что при изменении логики вычисления wr_en меняется и количество дельтациклов. В процессе экспериментов упростил FIFO до варианта без даунсайза и ширины данных в 8 бит, а логику wr_en до простейшего !full && data_valid (куда уж проще - это минимальная логика работы с FIFO по записи - простой хендшейк), и эффект порчи данных не ушёл. Просто в этом конкретном случае ломается последнее слово - это частный случай всего бесконечного разнообразия вариантов, возникающих при наложении сигналов с разными дельтациклами. Ведь действительно - не может же FIFO "знать", что слово в потоке последнее, значит, это последнее слово чем-то отличается от остальных. И действительно, анализ дельтациклов показал, что у всех слов wr_en имеет +10, а у последнего +5. Причина в том, что в последнем слове меняется условие формирования data_valid (оно становится не valid). Такова общая картина. Резюме: во всех случаях портятся только данные, логика работы FIFO правильная - количество слов и флаги full/empty правильные. Обратил внимание, что, например, сигнал empty вываливается наружу с задержкой 0.1 нс относительно своего клока. Оную задержку я увидел внутри файла модели fifo_generator_vlog_beh.v (https://github.com/Digilent/Genesys-2-HDMI/blob/master/src/bd/system/ipshared/564d/simulation/fifo_generator_vlog_beh.v) в виде макроса TCQ 100ps. Там внутри куча сигналов, задержанных на эту величину. Зачем они это сделали, не очень ясно, похоже, что какой-то древний легаси код тащат с лохматых времён. Интернет полон возмущённых криков по этому поводу. Ведь в самом деле, зачем на функциональной модели, которая и так должна работать правильно в логике симуляторов, ещё добавлять задержки, имитирующие Tco флопов. Да, модель, кстати, на верилоге, т.е. тут вряд ли проблема на стыке VHDL<->Verilog. А по поведению с ошибкой данных это похоже как бы на нарушения по холду - и лечится соответственно - введением задержки. Собственно, меня интересуют ответы на следующие вопросы: 1. Это ошибка в модели или это я что-то делаю не так? 2. Как такое вообще получается, ведь это не какой-то уникальный случай или эксклюзивный код - тут же простейшая логика работы с очень распространённым элементом цифрового дизайна - FIFO, ведь это по идее используется тысячами (если не десятками тысяч) инженеров в сотнях тысяч проектов, неужели мало кто из них на это налетает? Или они в массе не моделируют свои дизайны с двухклоковыми FIFO? 3. Как поступить? Хочется сделать правильно. Пока вижу путь добавить задержку в логику формирования wr_en, но это похоже на костыли, а костылей не хочется. К тому же, вот тут я могу пофиксить проблему, но где гарантия, что аналогичное не вылезет на других сигналах корки? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 42 3 марта, 2019 Опубликовано 3 марта, 2019 · Жалоба В 01.03.2019 в 22:31, RobFPGA сказал: FIFO у Xilinx до сих пор на VHDL значит могут быть глюки/гонки в самом симуляторе на стыке verilog/VHDL или в непосредственно в шедулере сима. Кстати, да, в директории synth исходников корки таки лежит VHDL'ный файл. Но связи с поведенческим моделированием не просматривается на первый взгляд. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alexPec 3 3 марта, 2019 Опубликовано 3 марта, 2019 · Жалоба Странно... В vivado 2017.4 использовал этот блок у себя, симулировал, правда в вивадовом симуляторе, - все сходу взлетело, никаких проблем не было. Скомпилировал в железе - ведет себя точь-в-точь как в симуляторе, все нормально. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flip-fl0p 4 3 марта, 2019 Опубликовано 3 марта, 2019 · Жалоба 4 часа назад, dxp сказал: Если не сложно скиньте мини-проект. Попробую запустить симуляцю в Modelsim с библиотеками, скопмилированными Vivado 17.4. Может разработчики в библиотеках накосячили для Vivado 18.2 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
BSACPLD 12 3 марта, 2019 Опубликовано 3 марта, 2019 · Жалоба Был печальный опыт с FIFO в Vivado 2017.3. По сигналу ресет, при наличии определенной комбинации на других входах, FIFO зависал. Все время показывал переполнение. До этого с готовыми FIFO не было проблем ни в Quartus, ни в ISE. После двухдневных мучений написал свой FIFO и забил на использование готового. С тех пор готовым коркам от Xilinx я не доверяю. Стараюсь использовать сторонние или полностью свои. d_c_fifo.sv d_p_ram_rw.sv Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Gorby 6 3 марта, 2019 Опубликовано 3 марта, 2019 · Жалоба On 3/2/2019 at 6:44 AM, dxp said: 1. Это ошибка в модели или это я что-то делаю не так? 2. Как такое вообще получается, ведь это не какой-то уникальный случай или эксклюзивный код - тут же простейшая логика работы с очень распространённым элементом цифрового дизайна - FIFO, ведь это по идее используется тысячами неужели мало кто из них на это налетает? Или они в массе не моделируют свои дизайны с двухклоковыми FIFO? 3. Как поступить? Хочется сделать правильно. Пока вижу путь добавить задержку в логику формирования wr_en, но это похоже на костыли, а костылей не хочется. К тому же, вот тут я могу пофиксить проблему, но где гарантия, что аналогичное не вылезет на других сигналах корки? 1. Не всё так просто. Ошибок в модели нет. И Вы делаете всё правильно. 2. Кто виноват ? На этот эффект натыкаются все, кто делает более-менее сложный проект. То, что Вам кажется одновременными событиями, для симулятора оказываются разными во времени. Причем это не баг или прихоть языка, а особенность вычислительного ядра. То есть на разных симуляторах один и тот же код будет выдавать РАЗНЫЕ результаты. Например меня в свое время потрясло различие Моделсим и Альдек Актив ХДЛ в моделировании одинакового "чистого" кода (без "костылей") Яркий пример - простробировать некие данные непосредственно клоком и его копией после двух инверторов. А самая жесть - тот же клок, но через поворитель-буфер. По идее никакой разницы - а в реале второй клок сдвинут на несколько тех дельта-циклов (фемтосекунды?) и выход уже не тот. 3.Что делать? Выкручиваются, кто как умеет. Я например, моделирую только временную (пост-лейаут) модель. Там уже все реальные задержки присутствуют и описанный эффект не проявляется. Если таки-надо промоделировать модуль до разводки, руками ставлю костыли в виде after 1nS после каждого присваивания. 4. Охи и ахи "да Вы не понимаете VHDL", "это костыли!" пропадают после первого серьезного фэйла "на модели всё работало, а в железе - фигвам". 5. Полное отрезвление наступает, когда проведешь достаточно много времени во временном моделировании - до тебя вдруг доходит, что система построена так, что все триггеры в проекте АВТОМАТОМ подстраиваются на соблюдение условий setup-hold и что это достигается только при WrEn <= !full && data_valid after 10 nS если тактовая 100 МГц. Природу не обманешь. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RobFPGA 27 3 марта, 2019 Опубликовано 3 марта, 2019 · Жалоба Приветствую! On 3/2/2019 at 8:44 AM, dxp said: Далее последовало изрядное количество экспериментов. Сначала перегенерил корку с портами wr_data_count, rd_data_count. На wr_data_count всегда присутствует ненулевое значение, т.е. если FIFO пустое, то там торчит 1 ... Это уже подозрительно - вы reset правильно делаете для FIFO? (вроде reset должен быть активный не менее 4-х тактов и wr_en не должен быть активным при reset) On 3/2/2019 at 8:44 AM, dxp said: ... Т.е. проблема именно в wr_en. Разница между этими сигналами для корок в том, что в боевом варианте этот сигнал формируется на комбинаторной логике (пробовал assign и always_comb, разницы между ними, в общем, нет, что логично), а для тестовой - на флопе. Когда я пропустил тот комбинаторный сигнал через флоп, то правильность работы FIFO восстановилось (естественно, логика работы при этом нарушается из-за сдвига на такт, но в данном случае это не важно). ... Потом я пробовал менять логику вычисления wr_en, это приводило к изменению результатов по данным на выходе - например, был вариант, когда первое слово выходит правильно, второе - половина текущего, половина следующего, третье - ноль. При этом, опять же, логика работы full/empty (и wr/rd_data_count) всегда правильные, т.е. портятся только данные. Отличия порождаются, полагаю, из-за того, что при изменении логики вычисления wr_en меняется и количество дельтациклов. Но при этом - сама модель FIFO не меняется! - а это, IMHO, на 99% говорит о том что проблемы скорее с вашей логикой формирования wr_en или генерацией данных на входе FIFO. Тут конечно желательно бы тестовый сим проект посмотреть с воспроизводством проблемы. Чтобы не гадать на FIFOшной гуще. On 3/2/2019 at 8:44 AM, dxp said: Ведь в самом деле, зачем на функциональной модели, которая и так должна работать правильно в логике симуляторов, ещё добавлять задержки, имитирующие Tco флопов. Это давняя проблема симуляторов - так как параллельные события в модели симулируются последовательно. Отсюда иногда возникают неоднозначности (особенно при 0-вом времени задержек при функ. симуляции) в очередности добавлении событий в очередь исполнения. В старых версиях симов это встречалось довольно часто поэтому и боролись с этим 1ps ... 1ns задержками при присвоении. Удачи! Rob. P.S. К то муже если вы посмотрите в саму модель fifo_generator_vlog_beh.v то увидите внутри все ту же комбинаторику по входу: assign ram_wr_en = WR_EN & !FULL; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 42 4 марта, 2019 Опубликовано 4 марта, 2019 · Жалоба Выражаю благодарность всем участникам этой темы. И мнения всегда интересны, и предложения наталкивают на новые "ветки" поиска. 10 часов назад, RobFPGA сказал: Но при этом - сама модель FIFO не меняется! - а это, IMHO, на 99% говорит о том что проблемы скорее с вашей логикой формирования wr_en или генерацией данных на входе FIFO. Вы как всегда правы! Нашёл причину, похоже! Как обычно, "сам дурак". Таки дело в формировании сигнала wr_en (да и самых данных тоже). А дело было так. Внутри проекта у меня образовался непростой кусок (модуль), который было неудобно моделировать в общем окружении, поэтому я вытащил его в отдельный тестбенч. На модуль приходит AXI4 транзакция, и данные этой транзакции обрабатываются и упаковываются в буфер - то самое FIFO. В боевом проекте данные формируются синтезируемой частью (и там, кстати, такой пакости замечено не было, что теперь вполне понятно), а в тестовом проекте я написал другой генератор транзакций с использованием несинтезируемых конструкций, т.к. это проще и быстрее (а иначе зачем они вообще). И вот тут-то "собака и порылась". Транзакция генерится с помощью task: Спойлер task automatic axi_transaction(input logic [AXI_ADDR_W-1:0] addr, input int len); logic [AXI_BYTES_W-1:0] offset = addr[AXI_BYTES_W-1:0]; int count = 0; logic [ AXI_ADDR_W-1:0] base_addr = addr & '1 << AXI_BYTES_W; wdata_t wdata = 0; // addr channel forever begin @(posedge clk) begin axi4_wr.AWADDR <= addr; axi4_wr.AWLEN <= get_axi_word_count(addr, len); axi4_wr.AWID <= 1; axi4_wr.AWVALID <= 1; if(axi4_wr.AWREADY) begin break; end end end @(posedge clk) begin axi4_wr.AWVALID <= 0; axi_active <= 1; end fork begin // data while(count < axi4_wr.AWLEN) begin @(posedge clk) begin if(enable && axi4_wr.WREADY) begin count++; end end end end begin forever begin wdata = get_wdata(base_addr + count*AXI_BYTES, refmem); axi4_wr.WDATA <= wdata; if(count == 0) begin // the first beat axi4_wr.WSTRB <= get_wstrb_first(addr, len); end else if(count == axi4_wr.AWLEN-1) begin // the last beat axi4_wr.WSTRB <= get_wstrb_last(addr, len); axi4_wr.WLAST <= 1; end else begin axi4_wr.WSTRB <= '1; axi4_wr.WLAST <= 0; end @(posedge clk) ; end end join_any axi_active <= 0; endtask В этом коде уже всё правильно. А было то же самое, но присваивания были блокирующими. А т.к. синхронизация идёт по событиям @(posedge ...), то и логику присваиваний нужно использовать соответствующую. С блокирующими присваиваниями происходили в полный рост гонки с комбинаторной логикой тестируемого модуля, что и выливалось в описанные глюки. Причину можно легко понять из алгоритма обработки событий виртуальной машиной симуляторе, который упрощено показан на картинке: Тут видно, что блокирующие присваивания обрабатываются как Active Events, а порядок их обработки не определён. Вот тут и гонки. Я же подогнался из-за стереотипного мышления - привязывал логику обработки к типам always блоков, а тут вроде их и нет. Но дело-то не в том, есть такие блоки или нет, а в том, как компилятор симулятора обрабатывает код и строит очереди событий. И если есть привязка к фронту клока, то и всё зависимые от него данные должны обрабатываться соответствующим образом вне зависимости от того, always блок там, task или что-то ещё. Надеюсь, этот эпизод поможет кому-нибудь (послужит уроком или освежит знания по теме). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться