Andr2I 0 March 6, 2007 Posted March 6, 2007 · Report post Перехожу с AHDL на Verilog. Почитал, сделал проект D-триггера в Квартусе. Все работает. Далее возник концептуальный вопрос. В AHDL постоянно использовал примитивы (в основном DFFE) - сразу понятно как проект ложится в ячейки. В Verilog тоже можно использовать примитивы, но можно и использовать поведенческие модели. И то и другое обладают примерно одинаковым геммороем - для примитивов надо всю схему продумывать детально, для поведенческой модели должны (по идее - пока не делал) запарить цепи сброса и установки - все надо прописывать и довольно подробно. Поскольку своего опыта нет, хотелось бы услышать мнения по поводу использования примитивов. Прекрасно понимаю, что примитивы затруднят миграцию на другие кристаллы. Но поскольку все равно работаю с встроенной памятью, PLL и умножителями через мегафункции (по сути те же примитивы) большого вреда от этого не вижу. Второй вопрос еще глупее - чем отличается module и task? И для чего нужен task - ведь я могу вызывать другие модули из своего модуля с помощью module_instance (нужно ли текст вызываемых модулей приводить в основном модуле и в каком месте?). С уважением, Андрей Quote Share this post Link to post Share on other sites More sharing options...
klop 0 March 6, 2007 Posted March 6, 2007 · Report post Второй вопрос еще глупее - чем отличается module и task? И для чего нужен task - ведь я могу вызывать другие модули из своего модуля с помощью module_instance (нужно ли текст вызываемых модулей приводить в основном модуле и в каком месте?). С уважением, Андрей Я думаю Вам надо больше почитать по книжек по HDL. И понять что AHDL предназначен только для синтеза а Verilog/VHDL покрывают еще и моделирование. Quote Share this post Link to post Share on other sites More sharing options...
dxp 213 March 6, 2007 Posted March 6, 2007 · Report post Почитал, сделал проект D-триггера в Квартусе. Все работает. Далее возник концептуальный вопрос. В AHDL постоянно использовал примитивы (в основном DFFE) - сразу понятно как проект ложится в ячейки. В Verilog тоже можно использовать примитивы, но можно и использовать поведенческие модели. И то и другое обладают примерно одинаковым геммороем - для примитивов надо всю схему продумывать детально, для поведенческой модели должны (по идее - пока не делал) запарить цепи сброса и установки - все надо прописывать и довольно подробно. Ничего там подробно прописывать не надо. Сигнал сброса может так же описываеться в списке чувствительностей (если надо асинхронный сброс): ... reg a; reg [N-1:0] b; ...2 always @(posedge clk, posedge rst) begin if(rst) begin a <= 0; b <= 0; end else begin if(...) a <= 1; else a <= 0; if(b < 100) b <= b + 1; else b <= 0; ... ... end end Если убрать из списка чувствительностей "posedge rst", то сброс будет синхронным. Описанный объект "а" будет синтезирован в D-триггер, а "b" - в счетчик, который считает до 100 и затем обнуляется. Из таких always-блоков и лепится весь синхронный дизайн. Обратите внимание, что присваивание делается неблокирующее "<=". Комбинационную логику можно лепить тоже из always-блоков, но в списке чувствительностей не должно быть всяких posedge/negedge, Верилог-2001 вообще допускает "пустой" вариант: always @(*) (или always @* ) - его и надо использовать. Такой блок будет синтезирован в комбинационную логику. Тут нужно использовать блокиующие присваивания "=". Поскольку своего опыта нет, хотелось бы услышать мнения по поводу использования примитивов. Прекрасно понимаю, что примитивы затруднят миграцию на другие кристаллы. Но поскольку все равно работаю с встроенной памятью, PLL и умножителями через мегафункции (по сути те же примитивы) большого вреда от этого не вижу. Второй вопрос еще глупее - чем отличается module и task? И для чего нужен task - ведь я могу вызывать другие модули из своего модуля с помощью module_instance (нужно ли текст вызываемых модулей приводить в основном модуле и в каком месте?). Примитивы не нужны - это лишние сущности (артефакты). Все прекрасно описывается поведенчески. Сам тоже с AHDL переползал на Верилог, тоже пытался работать так же, но быстро понял, что выходит как-то некузяво. Тут другой язык, другая идеология. Никаких триггеров, счетчиков, регистров сдвига и прочего не нужно - это лишние сущности, которые отягощают дизайн. Подобные сущности, которые имеет смысл использовать - это то, что представляет собой аппаратные особенности ПЛИС - ФАПЧ, блоки памяти, умножители (хотя по поводу памяти мнения расходятся - синтезаторы умеют инферить память, т.е. сами соображают, что то или иное описание можно запихать в блок памяти и некоторые люди предпочитают этим пользоваться; лично я предпочитаю описывать блок явно, т.к. это дает однозначный и предсказуемый результат всегда). Все остальное прекрасно и без проблем описывается поведенчески и эффективно синтезируется. Quote Share this post Link to post Share on other sites More sharing options...
Andr2I 0 March 6, 2007 Posted March 6, 2007 · Report post Большое спасибо за ответы! dxp Комбинационную логику можно лепить тоже из always-блоков, но в списке чувствительностей не должно быть всяких posedge/negedge, Верилог-2001 вообще допускает "пустой" вариант: always @(*) (или always @* ) - его и надо использовать. Такой блок будет синтезирован в комбинационную логику. Тут нужно использовать блокиующие присваивания "=". Комбинационную логику саму по себе редко использую - все равно приходится буферить триггерами, что бы быстродействие обеспечить - конвеер. Означает ли это, что блокирующее присвоение не актуально или надо сначала wire присвоить логическую конструкцию блокирующим присвоением, а затем этот wire завести на вход reg неблокирующим присвоением? klop И понять что AHDL предназначен только для синтеза а Verilog/VHDL покрывают еще и моделирование. Можно ли расценить Ваш ответ, как то что module для синтеза, а task для моделирования? Я пока синтезирую и моделирую в Квартусе и поэтому мне module вполне хватает. С уважением, Андрей Quote Share this post Link to post Share on other sites More sharing options...
CaPpuCcino 0 March 6, 2007 Posted March 6, 2007 · Report post Верилог-2001 вообще допускает "пустой" вариант: always @(*) (или always @* ). а SystemVerilog идёт ещё дальше и вот этот always@* пазделяет на always_comb и always_latch чтобы исключить на этапе компиляции появление нежелательных защёлок в комбинаторике или простой комбинаторики там где должна быть защёлка (соответственно для проверки на чистую синхронность используется always_ff @(xedge some_clock_signal)) Второй вопрос еще глупее - чем отличается module и task? И для чего нужен task - ведь я могу вызывать другие модули из своего модуля с помощью module_instance (нужно ли текст вызываемых модулей приводить в основном модуле и в каком месте?). таски как и любые субпрограмы нужны для локализации функциональности и повторного использования кодa. обсуждение различий может занять много времени и вызвать жаркую дискуссию в данной ветке поэтому я попробую обяснить когда в основном пользуются тасками (а вы уж дальше по книжкам): при синтезе таски как и функции используют в качестве описалова сложной комбинаторики которая повторяется часто в коде при этом в теле подпрограммы присваивания только блокирующие и никакого событийного управления (типа @ или wait - ну в общем как я и сказал чистая комбинаторика) по своей сути таски и функции при синтезе выполняют роль макросов при верификации/моделирование подпрограммы используются как и в любом другом программерном языке. в этом случае таск может реализовывать ту же функциональность (правда другими языковыми конструкциями) как и модуль с единственной разницей что таск не может быть корнем иерархии (при синтезе также - но при синтезе он еще и не может быть вызван вне процессов) Quote Share this post Link to post Share on other sites More sharing options...
sazh 11 March 6, 2007 Posted March 6, 2007 · Report post Просто для иллюстрации. Не знаю, чье. module task_v (a,b,c); input [7:0] a,b; output [7:0] c; reg [7:0] c; task adder; input [7:0] a,b; output [7:0] adder; reg c; integer i; begin c = 0; for (i = 0; i <= 7; i = i+1) begin adder = a ^ b ^ c; c = (a & b) | (a & c) | (b & c); end end endtask always adder (a,b,c); //c is a reg endmodule Quote Share this post Link to post Share on other sites More sharing options...
Andr2I 0 March 6, 2007 Posted March 6, 2007 · Report post CaPpuCcino Большое спасибо! С таксами и функциями все стало понятно. Quote Share this post Link to post Share on other sites More sharing options...
dxp 213 March 7, 2007 Posted March 7, 2007 · Report post Означает ли это, что блокирующее присвоение не актуально или надо сначала wire присвоить логическую конструкцию блокирующим присвоением, а затем этот wire завести на вход reg неблокирующим присвоением? Семантика блокирующего присваивания не соответствует логике работы триггров, которые работают по фронту - для них четко подходит неблокирующее присваивание. Зато блокирующее хорошо подходит для описания комбинаторных выражений, т.к. поддерживает заданную последовательность - все присваивания делаются в том порядке, как они описаны. Поэтому если не хотите сюрпризов при синтезе (да и при моделировании), то следуйте правилу: в синхронных блоках - неблокирующие, в комбинационных - блокирующие. Quote Share this post Link to post Share on other sites More sharing options...
Andr2I 0 March 7, 2007 Posted March 7, 2007 · Report post dxp Зато блокирующее хорошо подходит для описания комбинаторных выражений, т.к. поддерживает заданную последовательность - все присваивания делаются в том порядке, как они описаны. Т.е. если я напишу a = b&c; r = ~a; то компилятор порядок не изменит - сначала И между b и с, а затем отрицание? Не могли бы Вы еще пояснить - нашел в книге пример 4'b1011 && 4b'0010 результат 1b'1. Я делаю поразрядное И - (0010), а затем И всех разрядов - получается 1b'0. Может опечатка в книге? Quote Share this post Link to post Share on other sites More sharing options...
dxp 213 March 7, 2007 Posted March 7, 2007 · Report post Зато блокирующее хорошо подходит для описания комбинаторных выражений, т.к. поддерживает заданную последовательность - все присваивания делаются в том порядке, как они описаны. Т.е. если я напишу a = b&c; r = ~a; то компилятор порядок не изменит - сначала И между b и с, а затем отрицание? Да, именно так. Но это приемлемо для блока always @* и в этом случае эквивалентно выражению assign r = ~(b&c); Правда, в случае с always-блоком a и r должны быть объявлены как reg, а в последнем случае r - wire. А вот в последовательностных (синхронных) блоках такие присваивания лучше не использовать. Например, пропробуйте написать так (типа, схема, которая обменивает значениями два триггера): reg a; reg b; always @(posedge clk) begin a = b; b = a; end Будете удивлены результатом синтеза - обратите внимание на сообщения синтезатора. Зато, если напишите: reg a; reg b; always @(posedge clk) begin a <= b; b <= a; end то будет полная икэбана. :) Это хороший пример, на котором видна разница между двумя видами присваивания. Почитайте внимательно про блокирующие и неблокирующие присваивания - это весьма важный момент в Верилоге. Верилог, вообще, язык довольно простой, но в нем есть несколько "нюансов". Вот эти присваивания - как раз такой "нюанс". Не могли бы Вы еще пояснить - нашел в книге пример 4'b1011 && 4b'0010 результат 1b'1. Я делаю поразрядное И - (0010), а затем И всех разрядов - получается 1b'0. Может опечатка в книге? Операция && - это не побитовое И, а логическое. Результат у Вас правильный - 1, то есть "истина", не "ложь", которая кодируется нулем. Побитовая операция - это &. Quote Share this post Link to post Share on other sites More sharing options...
Andr2I 0 March 7, 2007 Posted March 7, 2007 · Report post dxp Да, именно так. Но это приемлемо для блока always @* и в этом случае эквивалентно выражению assign r = ~(b&c); Правда, в случае с always-блоком a и r должны быть объявлены как reg, а в последнем случае r - wire. Как то мне не нравится использовать reg для комбинаторной логики: когда я ставлю reg - занимаю ячейку, когда wire - при несложной логике даром. Интересно, а компилятор разве не упрощает выражения со скобками? По поводу Вашего примера с обменом данных между регистрами все понятно, но все равно остается вопрос - у меня вся комбинаторная логика (рано или поздно) поступает а вход reg тактируемого клоком, следовательно я могу обойтись (в принципе) только неблокирующим присвоением? Т.е. блокирующее присвоение только для удобства записи и при этом лучше пользоваться assign вне процесса? Операция && - это не побитовое И, а логическое. Результат у Вас правильный - 1, то есть "истина", не "ложь", которая кодируется нулем. Рискну испытать Ваше терпение, но можно ли по подробнее про логическое И двух 4 битных чисел? Quote Share this post Link to post Share on other sites More sharing options...
dxp 213 March 7, 2007 Posted March 7, 2007 · Report post Да, именно так. Но это приемлемо для блока always @* и в этом случае эквивалентно выражению assign r = ~(b&c); Правда, в случае с always-блоком a и r должны быть объявлены как reg, а в последнем случае r - wire. Как то мне не нравится использовать reg для комбинаторной логики: когда я ставлю reg - занимаю ячейку, когда wire - при несложной логике даром. Интересно, а компилятор разве не упрощает выражения со скобками? reg - это не триггер в железе. Это тип переменной, используемой в поведенческом описании. Он реально может синтезироваться в триггер - это в случае синхронного блока или в обычный сигнал - wire/node, который может и не присутствовать внутри ПЛИС в явном виде - это в случае комбинационных блоков. Это еще один "нюанс" Верилога. По поводу Вашего примера с обменом данных между регистрами все понятно, но все равно остается вопрос - у меня вся комбинаторная логика (рано или поздно) поступает а вход reg тактируемого клоком, следовательно я могу обойтись (в принципе) только неблокирующим присвоением? Т.е. блокирующее присвоение только для удобства записи и при этом лучше пользоваться assign вне процесса? Еще раз. Внутри синхронных блоков - неблокирующее. Для описания комбинационной логики - присваивания assign (объекты присваивания - имеют тип wire) либо комбинационные блоки с блокирующими присваиваниями (объекты присваивания - имеют тип reg). Операция && - это не побитовое И, а логическое. Результат у Вас правильный - 1, то есть "истина", не "ложь", которая кодируется нулем. Рискну испытать Ваше терпение, но можно ли по подробнее про логическое И двух 4 битных чисел? Все просто. Логическое - это когда проверяется на "истина/ложь". Ложь - нулевое значение, истина - ненулевое. В Вашем случае если число не ноль - то это истина и будет на выходе 1. Если число 0, то это ложь и на выходе будет 0. В случае двух чисел - сначала одно число приводится к логическому значению истина/ложь, затем второе, потом оба эти полученные логические значения сравниваются по И. Если хотя бы одно имеет значение ложь, то все выражение является ложным. Понятно? Quote Share this post Link to post Share on other sites More sharing options...
CaPpuCcino 0 March 7, 2007 Posted March 7, 2007 · Report post Как то мне не нравится использовать reg для комбинаторной логики: когда я ставлю reg - занимаю ячейку, когда wire - при несложной логике даром. SystemVerilog-e reg wire bit logic чтоб не путать новичков с этими reg и wire в SystemVerilog-e ввели тип bit он является синонимом reg но название типа уже не запутает (это не всегда регистр - это только тот тип который можно присвоить в любом always блоке) ЗЫ: от assign сейчас вообще пытаются избавиться (в стандартах он указан как устаревший и выводимый из обращения) и заменить его на комбинаторный always- я последнее время намеренно не пользуюсь assign - а пишу alwyas_comb Quote Share this post Link to post Share on other sites More sharing options...
Andr2I 0 March 7, 2007 Posted March 7, 2007 · Report post dxp В Вашем случае если число не ноль - то это истина и будет на выходе 1. Если число 0, то это ложь и на выходе будет 0. В случае двух чисел - сначала одно число приводится к логическому значению истина/ложь, затем второе, потом оба эти полученные логические значения сравниваются по И. Если хотя бы одно имеет значение ложь, то все выражение является ложным. Понятно? Вроде понял! Спасибо большое! Получается что операция && даст ноль только когда хотя бы одно из чисел равно нулю (4'b1011 && 4b'0000 например) . CaPpuCcino от assign сейчас вообще пытаются избавиться (в стандартах он указан как устаревший и выводимый из обращения) и заменить его на комбинаторный always- я последнее время намеренно не пользуюсь assign - а пишу alwyas_comb А Квартус поймет always_comb и always_latch ? Надо будет попробовать. Вообще мне такие процессы больше нравятся - понятно что получится. Quote Share this post Link to post Share on other sites More sharing options...
klop 0 March 7, 2007 Posted March 7, 2007 · Report post Верилог, вообще, язык довольно простой, но в нем есть несколько "нюансов". Вот эти присваивания - как раз такой "нюанс". В Verilogе (точнее в той его части которая предназначена для тесбенчеей) еще довольно много таких "нюансов"(и гемороя с ними предостаточно). Quote Share this post Link to post Share on other sites More sharing options...