alman 0 15 февраля, 2014 Опубликовано 15 февраля, 2014 (изменено) · Жалоба Будьте добры, объясните как привильно добавлять новые возможности в проект. К примеру есть базовый модуль module Child ( input wire i_clk, input wire [7:0] i_cmd, output reg [7:0] o_result ); // Вместо этого примитивного примера здесь может быть сложный код always @( posedge i_clk ) o_result = (i_cmd >>> 4) + 4; endmodule Нужно перехватить вызов и обработать его на уровне выше. При этом желательно чтобы отключалась синхронизация в случае перехвата команды родительским модулем и включалась обратно, если команда не перехватывается. Получился вот такой код: module Parent( input wire i_clk, input wire i_rst, input wire [7:0] i_cmd, output reg [7:0] o_result ); reg enable_child; wire i_cild_clk; wire o_chd_result; assign i_cild_clk = i_clk & enable_child; Child child_0( .i_clk(i_cild_clk), .i_rst(i_rst), .i_cmd(i_cmd), .o_result(o_chd_result) ); always @( posedge i_clk ) begin casex (i_cmd) 8'b01110xxx: begin enable_child = 0; o_result = 8'b01010101; end default: begin enable_child = 1; o_result = o_chd_result; end endcase end endmodule А как это же самое сделать правильно или лучше? Изменено 15 февраля, 2014 пользователем alman Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Timmy 1 15 февраля, 2014 Опубликовано 15 февраля, 2014 · Жалоба Правильно enable_child заводить в child отдельным проводом(clk_en) и в child писать always @(posedge clk) begin if(clk_en) begin //работаем только тут end end Сам клок нельзя прерывать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
iosifk 3 15 февраля, 2014 Опубликовано 15 февраля, 2014 · Жалоба Нужно перехватить вызов и обработать его на уровне выше. При этом желательно чтобы отключалась синхронизация в случае перехвата команды родительским модулем и включалась обратно, если команда не перехватывается. А как это же самое сделать правильно или лучше? В самой постановке вопроса - ошибка... Когда работаете с ПЛИС, то надо помнить, что это не программа. И тут нет "перехватов". Это описание железа и не более. Если Вы представляете себе, как устроен Ваш вычислитель, то вот так и описывайте. Посмотрите у меня на сайте, "Краткий Курс", главу об автоматах. Там описано, как осуществлять взаимодействие автоматов. А синхронизация, как Вам уже написали должна быть общей.. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SM 0 15 февраля, 2014 Опубликовано 15 февраля, 2014 · Жалоба А как это же самое сделать правильно или лучше? Правильно - в самом модуле ввести сигнал разрешения его работы, как это посоветовал Timmy, и завести его на разрешение записи в нужные регистры: module Child ( input wire i_clk, input wire i_ena, input wire [7:0] i_cmd, output reg [7:0] o_result ); // Вместо этого примитивного примера здесь может быть сложный код always @( posedge i_clk ) if (i_ena) o_result = (i_cmd >>> 4) + 4; endmodule Ну а дальше, я думаю понятно. Касаемо Вашей реализации с clock gating, она тоже вполне имеет право на жизнь, но для FPGA такую схему применять нежелательно (исходя из структуры ее клоковых деревьев). Кстати, отдельно взятые синтезаторы умеют clock gating конвертировать в сигналы enable. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 15 февраля, 2014 Опубликовано 15 февраля, 2014 · Жалоба Вороторизирование клока иногда применяют для снижения энергопотребления и в FPGA тоже. Недостаток я так понимаю некий сдвиг фронта клока после ворот относительно исходного клока, так? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SM 0 15 февраля, 2014 Опубликовано 15 февраля, 2014 · Жалоба Вороторизирование клока Ух какой термин! Откуда взяли? Первый раз слышу что-то русскоязычное, кроме "клок, пропущенный через вентиль". В ASIC никакого сдвига это не вносит, так как дерево клоков балансируется с учетом задержек этих вентилей, просто оказывается, что в каком-то месте дерева вместо буфера втыкается какой нибудь там AND/NAND/OR/NOR. В FPGA, да, некая задержка и доп. джиттер добавляется обязательно. И надо быть очень внимательным, чтобы сигнал, коммутирующий клок, с учетом логики, которая коммутирует, не давал иголок на выходе, если, конечно, не спецблок-коммутатор используется. Например, если управление клоком делается элементом И, от триггера, управляемого положительным перепадом, то при выключении клока пройдет глитч, если не добавить задержки между И и вентилем-клокогейтилкой достаточной. Или гейтить элементом ИЛИ. И наоборот, для отрицательного перепада. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 15 февраля, 2014 Опубликовано 15 февраля, 2014 · Жалоба термин - не термин, просто дословный перевод gated%)... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alman 0 15 февраля, 2014 Опубликовано 15 февраля, 2014 (изменено) · Жалоба Огромное спасибо всем ответившим! Как перехватывать сигнал стало понятно. Да, я хотел отключить клок для экономии энергии, но судя по сложности устранения побочных эффектов, от этого придётся отказаться. А вот как быть если появилась необходимость подсунуть свою "команду" субмодулю? Немного изменил пример. Все команды константы взяты случайно просто для примера. module Parent( input wire i_clk, input wire [7:0] i_cmd, output reg [7:0] o_result ); reg enable_child; reg sub_cmd; wire o_chd_result; Child child_0( .i_clk( i_clk), .i_ena(enable_child), .i_cmd(sub_cmd), // Подстановка команд .o_result(o_chd_result) ); always @( posedge i_clk ) begin casex (i_cmd) 8'b01110xxx: begin enable_child = 0; o_result = 8'b01010101; end 8'b11001100: // Новая команда, требующая подстановки begin sub_cmd = 8'b00110011; enable_child = 1; o_result = o_chd_result + 8'b00000101; end default: begin sub_cmd = i_cmd; enable_child = 1; o_result = o_chd_result; end endcase end endmodule Можно ли так делать? Конечные автоматы это хорошо, но хочется всё поместить в один такт. Могут ли тут быть проблемы? Изменено 15 февраля, 2014 пользователем alman Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SM 0 15 февраля, 2014 Опубликовано 15 февраля, 2014 · Жалоба Можно ли так делать? Конечные автоматы это хорошо, но хочется всё поместить в один такт. Могут ли тут быть проблемы? Можно, и нужно. Только, чтобы все это "поместить в 1 такт", надо мультиплексор sub_cmd описать в отдельном always@*, а так получается конвейер на два такта, на первом защелкивается cmd, так как из-за того, что он внутри always @(posedge...), он получается с регистром на выходе, а на втором такте уже защелкнется result, полученный от этого cmd. И вообще, когда каждая сущность (мультиплексор, дешифратор, арифметический блок, и т.п.) описана в отдельном своем always, то, как правило, описание схемы устройства читается и понимается лучше. Ну, разумеется, именно "как правило", а вовсе не всегда. По крайней мере при таком подходе к описанию устройства всегда наглядно понятно, на выходе какого блока есть регистр, а на выходе какого - нет. И не ставьте блокирующие присваивания там, где они совершенно не нужны. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alman 0 15 февраля, 2014 Опубликовано 15 февраля, 2014 (изменено) · Жалоба Можно, и нужно. Только, чтобы все это "поместить в 1 такт", надо мультиплексор sub_cmd описать в отдельном always@*, а так получается конвейер на два такта, на первом защелкивается cmd, так как из-за того, что он внутри always @(posedge...), он получается с регистром на выходе, а на втором такте уже защелкнется result, полученный от этого cmd. Простите за назойливость. Хочется понять раз и навсегда. Сделал отдельный always. И не ставьте блокирующие присваивания там, где они совершенно не нужны. Заменил все блокирующие прерывания на неблокирующие. Догадываюсь, что поступил глупо, поэтому вся надежда на указание, где и почему в этом примере понадобятся блокирующие присваивания. module Parent( input wire i_clk, input wire i_rst, input wire [7:0] i_cmd, output reg [7:0] o_result ); reg enable_child; reg sub_cmd; wire o_chd_result; Child child_0( .i_clk( i_clk), .i_rst( i_rst), .i_ena(enable_child), .i_cmd(sub_cmd), .o_result(o_chd_result) ); always @ * begin casex (i_cmd) 8'b01110xxx: begin enable_child <= 0; end 8'b11001100: begin sub_cmd <= 8'b00110011; enable_child <= 1; end default: begin sub_cmd <= i_cmd; enable_child <= 1; end endcase end always @( posedge i_clk ) begin casex (i_cmd) 8'b01110xxx: begin o_result <= 8'b01010101; end 8'b11001100: begin o_result <= o_chd_result + 8'b00000101; end default: begin o_result <= o_chd_result; end endcase end endmodule И вообще, когда каждая сущность (мультиплексор, дешифратор, арифметический блок, и т.п.) описана в отдельном своем always, то, как правило, описание схемы устройства читается и понимается лучше. Ну, разумеется, именно "как правило", а вовсе не всегда. По крайней мере при таком подходе к описанию устройства всегда наглядно понятно, на выходе какого блока есть регистр, а на выходе какого - нет. Будьте добры, скажите что неправильно в последнем примере. Очень хочется понять, как заставить пример работать за один такт. И ещё вопрос - на что повлияет тип присваивания в субмодуле? Как он относится к возможности запустить схему за такт? Спасибо. Изменено 15 февраля, 2014 пользователем alman Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SM 0 15 февраля, 2014 Опубликовано 15 февраля, 2014 · Жалоба Будьте добры, скажите что неправильно в последнем примере. Очень хочется понять, как заставить пример работать за один такт. Неправильно то, что в первом always Вы поставили always @( posedge i_clk ) вместо того, что я советовал - always @*, таким образом Вы получили тот же мультиплексор с регистром на выходе, как и в предыдушем коде, вместо комбинаторного мультиплексора и комбинаторной логики. Тут работает простейшее правило - хотите на выходе блока поставить триггер (синхронный регистр), пишите always @(posedge clock), не хотите - пишите always @* (внимательно следя, чтобы во всех case были default или атрибут full_case, и все ветки IF что-то присваивали, иначе асинхронный регистр-защелка получится). И ещё вопрос - на что повлияет тип присваивания в субмодуле? Как он относится к возможности запустить схему за такт? В данном контексте ни на что не повлияет, а к количеству тактов, так вообще никак не относится. Блокирующее присваивание нужно довольно редко, когда для следующего присваивания внутри одного блока нужно значение переменной, полученное в предыдущем присваивании, то есть, в основном, в каких-то сложных комбинаторных итерационных алгоритмах. А в остальных случаях может привести к некорректной симуляции при корректной работе в железе. В общем, грубо говоря, суть блокирующего присваивания при синтезе в том, что для вычисления правой части выражения берется текущее значение переменной, после последней, предыдущей операции. А неблокирующего - всегда для правой части берется то значение, которое было на момент начала блока, что бы Вы там с ним не делали до этого. А при моделировании может принести много интересных сюрпризов, особенно, если результат от блокирующего присваивания используется в неблокирующем в другом always, и не задана транспортная задержка... вот простой пример: reg [7:0] i,j; always @(posedge clk) begin i <= i+2'd3; i <= i+2'd2; i <= i+2'd1; j = j+2'd3; j = j+2'd2; j = j+2'd1; end в этом коде результатом для i будет i=i+1, так как оно было последним в блоке, а +3 и +2 будут проигнорированы, а для j - будет j=j+6, так как будет сформировано подряд три последовательных сумматора, +3, +2 и +1 Почему я не рекомендую ставить блокирующие "=" где попало, лишь потому, что они могут привести к неоднозначности между моделированием и железом, других причин нет. Но есть такие варианты, когда неблокирующие присваивания очень даже помогают сократить количество писанины, например, при описании комбинаторного умножителя или делителя чисел, или быстрого сдвигателя (barrel shifter, честно, я не знаю, почему он barrel - или это фамилия такая, или от слова "бочка" :) :) - буду должен :beer: , если кто подскажет историю этого барреля), ну а для переменных цикла, так они вообще незаменимы. Чтобы понять, откуда берется неоднозначность моделирование и железа - тут уже глубоко копать надо, изучать стандарт, как он предписывает их моделировать, и в рамках этого ответа оно будет лишним. В общем и целом, применяйте везде, где можно, неблокирующие присваивания потому, что это так принято (кошерно, халяльно, круто, по понятиям, и т.п., кому как нравится)... Вот как-то так... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 15 февраля, 2014 Опубликовано 15 февраля, 2014 · Жалоба блокирующее и не блокирующее это как пост и пред инкремент к примеру always @(posedge clk) begin i = i + 1; if (i == 2) done <= 1; end сработает на 2 клоке на первом клоке i перейдет из 0 в 1, и проверится условие что 1 не равно 2 на втором клоке i перейдет из 1 в 2, и проверится условие что 2 == 2 и сигнал done выставиться always @(posedge clk) begin j <= j + 1; if (j == 2) done <= 1; end а тут сработает на 3 клоке на 1 клоке j перейдет из 0 в 1, и одновременно проверится условие что 0 не равен 2 на 2 клоке j перейдет из 1 в 2, и одновременно проверится условие что 1 не равно 2 на 3 клоке j перейдет из 2 в 3, и одновременно проверится условие что 2 == 2, и сигнал выставится... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alman 0 15 февраля, 2014 Опубликовано 15 февраля, 2014 · Жалоба Уважаемые SM, Golikov A. и все ответившие в теме. Большое спасибо за исчерпывающую информацию - буду испольлзовать эту тему как справочник. Разрешите уточнить ещё вопрос относительно сигнала сброса. Можно ли все блоки always поместить в ветку else? Т.е. как-то так: if( i_rst ) begin // Код инициализации end else begin always @ * // что-то делаем always @ posedge clk // заканчиваем что-то делать end SM, c Вашего позволения исправлю always в последнем примере, чтобы не сбивать с толку случайных посетителей темы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 15 февраля, 2014 Опубликовано 15 февраля, 2014 · Жалоба мне кажется (SM любит это слово:)) так не выйдет... нельзя просто ставить if(rst) - в какой момент? Всегда? а как это реализовать? Надо понимать что если вы хотите что-то делать то оно должно быть под always то есть можно always @(posedge clk) begin if(reset) begin //действия при ресете end else begin //что то по программе end end без always идут только присвоения assign out = (reset) ? 0 : signal; типа если ресет, то выдать 0, иначе выдавать сигнал еще есть always который выполняется всегда без клоков, но там надо указывать по "изменению" каких сигналов always (rst, signal, signal_b) begin if(rst) signal <= 1; else signal <= (signal & signal_b); end в остальных случает, кажется, даже синтезатор вас обругает.... кстати есть хитрость в верилоге, я не очень ее люблю мне кажется она снижает понимаемость, но SM сказал - это определено стандартом, и все должны уважать конструкции вида always.... if(condition) signal <= A; else signal <=B могут быть записаны в виде always.... signal <=B if(condition) signal <= A; то есть как бы вы избавляетесь от else begin - end, меньше отступов, компактнее код. Меня правда интуитивно от этой конструкции плющит, и придерживаюсь по старинке if - else, но читаемость, надо признать, возрастает. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SM 0 16 февраля, 2014 Опубликовано 16 февраля, 2014 · Жалоба Можно ли все блоки always поместить в ветку else? Т.е. как-то так: Нельзя. Так как получится, как минимум, что функциональность одного и того же регистра описана в двух разных always, что недопустимо, да и вообще использовать if/case вне процедурных блоков нельзя. И вообще, никогда не надо пытаться разбивать один функциональный блок на несколько always. Вот Ваш пример, он состоит из: - логического блока формирования сигнала enable_child - мультиплексора, переключающего на шину sub_cmd разные варианты сигналов. - модуля, который что-то делает с sub_cmd и enable, и формирует свой выходной сигнал. - мультиплексора с регистром, который коммутирует в регистр выход модуля, или другие сигналы. Вот и описывайте каждую из этих сущностей ОТДЕЛЬНО в своем always, пока Вы начинающий. И для каждого always ставьте комментарий - тут мультиплексор sub_cmd, он делает это, тут - логика формирования сигнала enable_child, она такая, а тут мультиплексор выходного сигнала с регистром. Так будет лучше всего. Не надо мешать мух с котлетами, у вас очень понятная схема устройства, зачем ее запутывать какими то перемешиваниями always-ов с if-ами? Чтобы враг не догадался? у вас там еще элементарных глюков хватает, хотя бы то, что sub_cmd и o_chd_result объявлены однобитными. А Вы еще какую-то мегапутаницу хотите в описание ввести. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться