ZED 0 10 октября, 2009 Опубликовано 10 октября, 2009 · Жалоба Да, давайте, а то я уже путаться начинаю. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Sefo 0 12 октября, 2009 Опубликовано 12 октября, 2009 · Жалоба А как насчет статейки про wait until? Любопытно все же... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ZED 0 13 октября, 2009 Опубликовано 13 октября, 2009 · Жалоба Суворова Е.А. Шейнин Ю.Е. Проектирование цифровых систем на VHDL. Стр. 248. Но я, по-видимому, несколько ошибся, там это для сопоставления результатов моделирования и синтеза. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Sefo 0 21 октября, 2009 Опубликовано 21 октября, 2009 · Жалоба Извиняюсь за долгое молчание. Совсем не было времени. Я написал небольшую заметку о том, как формировать задержанные копии сигналов. How_Make_Delayed_Copy_of_Signals.pdf Надеюсь, теперь будет понятно, как реализовать блок управления БПФ. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ZED 0 22 октября, 2009 Опубликовано 22 октября, 2009 · Жалоба Я так понял, что сигналы для записи в память мы будем задерживать, основываясь на функциональной связи, т.е. вычитаем 5 из исходного значения счетчика бабочек. А как быть с сигналами для чтения коэффициентов? Там нужно вычитать 3*MODULE_ROM или их будем делать на FIFO? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Sefo 0 23 октября, 2009 Опубликовано 23 октября, 2009 · Жалоба Я так понял, что сигналы для записи в память мы будем задерживать, основываясь на функциональной связи, т.е. вычитаем 5 из исходного значения счетчика бабочек. А как быть с сигналами для чтения коэффициентов? Там нужно вычитать 3*MODULE_ROM или их будем делать на FIFO? Что касается адресов на запись, то так действительно можно сделать. Хорошее упражнение. Вопрос-подсказка: до скольки должен считать счетчик бабочек в этом случае? Что касается остальных сигналов, то выгоднее использовать регистры задержи, вопрос только в том, чтобы поставить их с "правильной стороны". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ZED 0 28 октября, 2009 Опубликовано 28 октября, 2009 · Жалоба Простите с ответом немного потяну, работы много надеюсь за неделю разрулю. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ZED 0 30 октября, 2009 Опубликовано 30 октября, 2009 · Жалоба Вопрос-подсказка: до скольки должен считать счетчик бабочек в этом случае? Счетчик бабочек по-моему должен по-прежнему считать от 0 до 511, а функциональную связь организовать следующим образом: ADDR_WR <= std_logic_vector(BUTTERFLY_COUNTER - 5); . Или я чего-то не так понял. Кстати у меня еще появился вопрос по заметке. Если проанализировать схему на рис. 8. Там написано, что адрес записи WR_ADDR прекратит обновляться за 3 такта до окончания вычислений. Но ведь сигнал Enable запрещающий вычисления дойдет также за 3 такта, так что все компенсируется. Вот еще у меня какая мысль увеличить счетчик бабочек на один разряд, чтоб он считал от 0 до 516 и вот по его значениям уже управлять. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Sefo 0 1 ноября, 2009 Опубликовано 1 ноября, 2009 · Жалоба Счетчик бабочек по-моему должен по-прежнему считать от 0 до 511, а функциональную связь организовать следующим образом: ADDR_WR <= std_logic_vector(BUTTERFLY_COUNTER - 5); . Или я чего-то не так понял. При использовании функциональной связи, если счетчик бабочек будет считать до 511, то ничего не получится по тем же причинам, что и на рис. 8. Поэтому, объяснения см. ниже. Кстати у меня еще появился вопрос по заметке. Если проанализировать схему на рис. 8. Там написано, что адрес записи WR_ADDR прекратит обновляться за 3 такта до окончания вычислений. Но ведь сигнал Enable запрещающий вычисления дойдет также за 3 такта, так что все компенсируется. WR_ADDR прекратит обновляться за 3 такта до окончания записи (т.е. 3 такта адрес будет один и тот же), а Enable (к тому же не запрещающий, а разрешающий вычисления и запись) дойдет до памяти за 4 такта, в смысле через 4 такта после начала Enable на входе. Одна и та же схема может работать в разных режимах. Это определяется управляющими сигналами. Поэтому 2 по-разному реализованные схемы (блока) в одном режиме могут давать эквивалентные результаты, а в другом режиме совершенно разные. Эквивалентные результаты не всегда означает одинаковые - нередко на временной диаграмме есть интервалы времени, на которых все равно какие значения будут принимать сигналы. В этих интервалах два по-разному реализованных блока, могут выдавать совершенно разные значения сигналов и это ни сколько не помешает работе устройства. Но зато, в те интервалы времени, где сигналы должны иметь строго определенное значение их выходы будут строго совпадать. В заметке описано, при каких условиях и в каких случаях работу схемы управления на рисунках 7, 8 и 9 можно считать эквивалентной, а в каких нет. Соответственно, в каких случаях можно использовать функциональную связь (или как правильно ее реализовать), а в каких это не получится. Возьмем схемы на рисунках 7 и 8 и посмотрим, что получится, если подать на них одно и то же управление. Начнем со схемы на рис. 7, когда адрес записи формирует клон счетчика формирующего адрес чтения. Enable_n обозначены выходы соответствующих триггеров задержки. Enable_4 - выход последнего триггера, подается непосредственно на WE. Как видно из диаграммы, за время активности входного Enable читаются данные по адресам 0...9. Через 4 такта эти обработанные данные появятся на входе памяти. Вместе с ними на память придет задержанная на 4 такта копия сигнала Enable (на диаграмме Enable_4) и пока этот Enable_4 активен счетчик-клон сформирует такую же последовательность адресов записи 0...9, что и счетчик, формирующий адреса чтения. Теперь посмотрим, какая диаграмма получится у схемы на рис. 8 при таком же сигнале Enable на входе. Когда RD_ADDR станет равен 3, в этом же такте станет активен сигнал Enable_3. Вычитатель начнет работать - вычислять выражение "RD_ADDR - 3". Т.к вычитатель имеет регистр на выходе, то результат будет появляться с задержкой на 1 такт. Таким образом, когда на выходе вычитателя появится первый правильный адрес на память одновременно придут первые данные и разрешение записи (Enable_4). Но вот входной Enable закончился и RD_ADDR перестал обновляться - остановился на значении 10. Но Enable_3 будет активен еще 3 такта и вычитатель еще три такта будет вычислять выражение "RD_ADDR - 3". Но т.к. RD_ADDR больше не обновляется, то и WD_ADDR будет иметь одно и то же значение: 10 - 3 = 7. Т.е. 3 последних такта поступающие данные будут записаны по одному и тому же адресу памяти - 7. Такая же ситуация произойдет и в БПФ, если счетчик бабочек остановится на 511, а адрес записи будет реализован на основе функциональной связи. Вот еще у меня какая мысль увеличить счетчик бабочек на один разряд, чтоб он считал от 0 до 516 и вот по его значениям уже управлять. Мысль хорошая. Если бы Вы высказали только ее одну, то я бы ошибочно подумал, что Вы правильно поняли как реализовать адрес записи, опираясь на функциональную связь. :) Чтобы правильно реализовать адрес записи, опираясь на функциональную связь, нужно чтобы счетчик бабочек не останавливался на 511 и считал дальше. Разумеется, что нет необходимости вводить еще один счетчик для отсчета тактов паузы, если у нас и так уже есть счетчик, по которому мы можем определить и начало и конец паузы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ZED 0 2 ноября, 2009 Опубликовано 2 ноября, 2009 · Жалоба Вот моя очередная попытка, жду Ваших замечаний... Driver.rar Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Sefo 0 3 ноября, 2009 Опубликовано 3 ноября, 2009 · Жалоба Внимательно разбираться в коде и диаграмме времени, к сожалению, не было. Поэтому пока скажу о том, что бросилось в глаза сразу. БПФ получился одноразовый - включили питание, сбросили ресетом все в исходное состояние, загрузили данные, подали старт, провели вычисления, выгрузили данные и все... Больше БПФ запустить нельзя... Нужно опять подавать ресет. Схема управления не восстанавливает своего начального значения к следующему запуску. Либо все должно приходить в исходное состояние по сигналу Start, либо самостоятельно, после окончания вычислений. Еще Вы явно не справились с расстановкой задерживающих триггеров для формирования ADDR_ROM и SWITCH_ROTATE_OUT. Ввиду малой разрядности SWITCH_ROTATE_OUT потери в логике получились пренебрежимо малы, а вот для ADDR_ROM, ввиду большой разрядности, уже неоправданно высоки. Продолжение следует... :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ZED 0 5 ноября, 2009 Опубликовано 5 ноября, 2009 · Жалоба Еще один вариант Driver.rar Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Sefo 0 6 ноября, 2009 Опубликовано 6 ноября, 2009 · Жалоба Так гораздо лучше. Продолжим анализ кода. Вы, судя по всему, необоснованно используете обособленные операторы if в которых одному и тому же сигналу присваиваются значения. Возьмем первый же process. process begin wait until (rising_edge(CLK)); if (RST = '1') then STATE <= '1'; elsif (START = '1') then STATE <= '0'; end if; if (COUNT_ETAP = 5) and (BUTTERFLY_COUNTER = 516) then STATE <= '1'; end if; end process; Сделали бы что-нибудь подобное за пределами process получили бы от синтезатора сообщение об ошибке, что сигнал имеет несколько драйверов. Но поскольку в теле process операторы "исполняются" последовательно, синтезатор опираясь на это преобразует ваш код в один единственный if ... elsif ... elsif ... end if, а условия и соответствующие им действия расставит в таком порядке приоритетов, который соответствует по поведению вашему коду. Для наглядности поменяем значения, присваиваемые STATE при сбросе и при старте. process begin wait until (rising_edge(CLK)); if (RST = '1') then STATE <= '0'; --было '1' elsif (START = '1') then STATE <= '1'; --было '0' end if; if (COUNT_ETAP = 5) and (BUTTERFLY_COUNTER = 516) then STATE <= '1'; end if; end process; Предположим, что случился фронт CLK и все условные выражения истинны. Начинаем "исполнять" код. В первом if сигнал RST имеет высший приоритет по сравнению со START. Значит STATE получит значение '0'. Идем дальше, "исполняем" второй if. Т.к. условие истинно, то STATE получит значение '1' и, поскольку на этом "исполнение" приостанавливается до следующего фронта CLK, STATE будет хранить '1'. Синтезатор должен поставить триггер, работающие именно таким образом. Поэтому получается, что наибольшим приоритетом обладает самый последний if, а наименьшим - самый первый. Эквивалентный код, которым синтезатор заменит ваш получается следующий: process begin wait until (rising_edge(CLK)); if (COUNT_ETAP = 5) and (BUTTERFLY_COUNTER = 516) then STATE <= '1'; elsif (RST = '1') then STATE <= '0'; --было '1' elsif (START = '1') then STATE <= '1'; --было '0' end if; end if; end process; Получается, что сигнал сброса RST не самый приоритетный! Сброс, поданный одновременно с истинным выражением "(COUNT_ETAP = 5) and (BUTTERFLY_COUNTER = 516)" будет проигнорирован. В вашем коде по условиям "(COUNT_ETAP = 5) and (BUTTERFLY_COUNTER = 516)" и "(RST = '1')" STATE получает одно и тоже значение. Поэтому, в конечном счете, код будет работать правильно, но такие удачные совпадения будут далеко не всегда. В каком-нибудь проекте получите трудно обнаруживаемую ошибку, которая будет давать сбои редко и не стабильно. Такая же ситуация у Вас с BANK_COUNTER_WR. Я советую задавать приоритеты условий в явном виде. Еще я обратил внимание, что у Вас довольно часто в разных process встречается условие "(STATE = '0' and BUTTERFLY_COUNTER = 516)". Я, обычно, в таких случаях добавляю еще один комбинаторный signal, который отражает истинность данного условия и имеет, по возможности, имя отражающее суть этого условия. Так же это удобно, если условие потребуется изменить - не придется выискивать все его экземпляры в коде. Например: END_OF_STAGE <= '1' when (STATE = '0' and BUTTERFLY_COUNTER = 516) else '0'; process begin wait until (rising_edge(CLK)); if END_OF_STAGE = '1' then ... end if; end process; ... process begin wait until (rising_edge(CLK)); if END_OF_STAGE = '1' then ... end if; end process; Формирование ADDR_ROM_COUNTER теперь, кажется, сделано так как я имел ввиду. Но это я еще посмотрю по-внимательнее. Диаграмму пока тоже еще не проверил, хотя выглядит правдоподобно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ZED 0 9 ноября, 2009 Опубликовано 9 ноября, 2009 · Жалоба Вот подправленный вариант. Driver.rar Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Sefo 0 10 ноября, 2009 Опубликовано 10 ноября, 2009 · Жалоба Пока я анализирую более детально что получилось с управлением, предлагаю написать код блока памяти. С управлением если какие-то ошибки и обнаружатся, то явно не серьезные. По стилю и избыточности вашего кодирования у меня еще остаются замечания, но уже не столь существенные. Их можно обсудить в фоновом режиме. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться