Jump to content
    

Переход с AHDL на Verilog

Перехожу с AHDL на Verilog.

Почитал, сделал проект D-триггера в Квартусе. Все работает.

Далее возник концептуальный вопрос. В AHDL постоянно использовал примитивы (в основном DFFE) - сразу понятно как проект ложится в ячейки. В Verilog тоже можно использовать примитивы, но можно и использовать поведенческие модели. И то и другое обладают примерно одинаковым геммороем - для примитивов надо всю схему продумывать детально, для поведенческой модели должны (по идее - пока не делал) запарить цепи сброса и установки - все надо прописывать и довольно подробно.

Поскольку своего опыта нет, хотелось бы услышать мнения по поводу использования примитивов.

Прекрасно понимаю, что примитивы затруднят миграцию на другие кристаллы. Но поскольку все равно работаю с встроенной памятью, PLL и умножителями через мегафункции (по сути те же примитивы) большого вреда от этого не вижу.

Второй вопрос еще глупее - чем отличается module и task? И для чего нужен task - ведь я могу вызывать другие модули из своего модуля с помощью module_instance (нужно ли текст вызываемых модулей приводить в основном модуле и в каком месте?).

 

С уважением, Андрей

Share this post


Link to post
Share on other sites

Второй вопрос еще глупее - чем отличается module и task? И для чего нужен task - ведь я могу вызывать другие модули из своего модуля с помощью module_instance (нужно ли текст вызываемых модулей приводить в основном модуле и в каком месте?).

 

С уважением, Андрей

Я думаю Вам надо больше почитать по книжек по HDL. И понять что AHDL предназначен только для синтеза а Verilog/VHDL покрывают еще и моделирование.

Share this post


Link to post
Share on other sites

Почитал, сделал проект 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 переползал на Верилог, тоже пытался работать так же, но быстро понял, что выходит как-то некузяво. Тут другой язык, другая идеология. Никаких триггеров, счетчиков, регистров сдвига и прочего не нужно - это лишние сущности, которые отягощают дизайн. Подобные сущности, которые имеет смысл использовать - это то, что представляет собой аппаратные особенности ПЛИС - ФАПЧ, блоки памяти, умножители (хотя по поводу памяти мнения расходятся - синтезаторы умеют инферить память, т.е. сами соображают, что то или иное описание можно запихать в блок памяти и некоторые люди предпочитают этим пользоваться; лично я предпочитаю описывать блок явно, т.к. это дает однозначный и предсказуемый результат всегда). Все остальное прекрасно и без проблем описывается поведенчески и эффективно синтезируется.

Share this post


Link to post
Share on other sites

Большое спасибо за ответы!

 

dxp

 

Комбинационную логику можно лепить тоже из always-блоков, но в списке чувствительностей не должно быть всяких posedge/negedge, Верилог-2001 вообще допускает "пустой" вариант: always @(*) (или always @* ) - его и надо использовать. Такой блок будет синтезирован в комбинационную логику. Тут нужно использовать блокиующие присваивания "=".

 

Комбинационную логику саму по себе редко использую - все равно приходится буферить триггерами, что бы быстродействие обеспечить - конвеер. Означает ли это, что блокирующее присвоение не актуально или надо сначала wire присвоить логическую конструкцию блокирующим присвоением, а затем этот wire завести на вход reg неблокирующим присвоением?

 

klop

 

И понять что AHDL предназначен только для синтеза а Verilog/VHDL покрывают еще и моделирование.

 

Можно ли расценить Ваш ответ, как то что module для синтеза, а task для моделирования? Я пока синтезирую и моделирую в Квартусе и поэтому мне module вполне хватает.

 

С уважением, Андрей

Share this post


Link to post
Share on other sites

Верилог-2001 вообще допускает "пустой" вариант: always @(*) (или always @* ).

а SystemVerilog идёт ещё дальше и вот этот always@* пазделяет на always_comb и always_latch чтобы исключить на этапе компиляции появление нежелательных защёлок в комбинаторике или простой комбинаторики там где должна быть защёлка (соответственно для проверки на чистую синхронность используется always_ff @(xedge some_clock_signal))

 

Второй вопрос еще глупее - чем отличается module и task? И для чего нужен task - ведь я могу вызывать другие модули из своего модуля с помощью module_instance (нужно ли текст вызываемых модулей приводить в основном модуле и в каком месте?).

таски как и любые субпрограмы нужны для локализации функциональности и повторного использования кодa.

обсуждение различий может занять много времени и вызвать жаркую дискуссию в данной ветке поэтому я попробую обяснить когда в основном пользуются тасками (а вы уж дальше по книжкам):

 

при синтезе таски как и функции используют в качестве описалова сложной комбинаторики которая повторяется часто в коде при этом в теле подпрограммы присваивания только блокирующие и никакого событийного управления (типа @ или wait - ну в общем как я и сказал чистая комбинаторика) по своей сути таски и функции при синтезе выполняют роль макросов

 

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

Share this post


Link to post
Share on other sites

Просто для иллюстрации. Не знаю, чье.

 

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

Share this post


Link to post
Share on other sites

CaPpuCcino

Большое спасибо! С таксами и функциями все стало понятно.

Share this post


Link to post
Share on other sites

Означает ли это, что блокирующее присвоение не актуально или надо сначала wire присвоить логическую конструкцию блокирующим присвоением, а затем этот wire завести на вход reg неблокирующим присвоением?

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

Share this post


Link to post
Share on other sites

dxp

Зато блокирующее хорошо подходит для описания комбинаторных выражений, т.к. поддерживает заданную последовательность - все присваивания делаются в том порядке, как они описаны.

 

Т.е. если я напишу

a = b&c;

r = ~a;

то компилятор порядок не изменит - сначала И между b и с, а затем отрицание?

Не могли бы Вы еще пояснить - нашел в книге пример

4'b1011 && 4b'0010 результат 1b'1. Я делаю поразрядное И - (0010), а затем И всех разрядов - получается 1b'0. Может опечатка в книге?

Share this post


Link to post
Share on other sites

Зато блокирующее хорошо подходит для описания комбинаторных выражений, т.к. поддерживает заданную последовательность - все присваивания делаются в том порядке, как они описаны.

 

Т.е. если я напишу

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, то есть "истина", не "ложь", которая кодируется нулем. Побитовая операция - это &.

Share this post


Link to post
Share on other sites

dxp

Да, именно так. Но это приемлемо для блока always @* и в этом случае эквивалентно выражению

 

assign r = ~(b&c);

 

Правда, в случае с always-блоком a и r должны быть объявлены как reg, а в последнем случае r - wire.

 

Как то мне не нравится использовать reg для комбинаторной логики: когда я ставлю reg - занимаю ячейку, когда wire - при несложной логике даром. Интересно, а компилятор разве не упрощает выражения со скобками?

По поводу Вашего примера с обменом данных между регистрами все понятно, но все равно остается вопрос - у меня вся комбинаторная логика (рано или поздно) поступает а вход reg тактируемого клоком, следовательно я могу обойтись (в принципе) только неблокирующим присвоением? Т.е. блокирующее присвоение только для удобства записи и при этом лучше пользоваться assign вне процесса?

 

Операция && - это не побитовое И, а логическое. Результат у Вас правильный - 1, то есть "истина", не "ложь", которая кодируется нулем.

 

Рискну испытать Ваше терпение, но можно ли по подробнее про логическое И двух 4 битных чисел?

Share this post


Link to post
Share on other sites

Да, именно так. Но это приемлемо для блока 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. В случае двух чисел - сначала одно число приводится к логическому значению истина/ложь, затем второе, потом оба эти полученные логические значения сравниваются по И. Если хотя бы одно имеет значение ложь, то все выражение является ложным. Понятно?

Share this post


Link to post
Share on other sites

Как то мне не нравится использовать reg для комбинаторной логики: когда я ставлю reg - занимаю ячейку, когда wire - при несложной логике даром.

SystemVerilog-e reg wire bit logic

чтоб не путать новичков с этими reg и wire в SystemVerilog-e ввели тип bit он является синонимом reg но название типа уже не запутает (это не всегда регистр - это только тот тип который можно присвоить в любом always блоке)

ЗЫ: от assign сейчас вообще пытаются избавиться (в стандартах он указан как устаревший и выводимый из обращения) и заменить его на комбинаторный always- я последнее время намеренно не пользуюсь assign - а пишу alwyas_comb

Share this post


Link to post
Share on other sites

dxp

В Вашем случае если число не ноль - то это истина и будет на выходе 1. Если число 0, то это ложь и на выходе будет 0. В случае двух чисел - сначала одно число приводится к логическому значению истина/ложь, затем второе, потом оба эти полученные логические значения сравниваются по И. Если хотя бы одно имеет значение ложь, то все выражение является ложным. Понятно?

 

Вроде понял! Спасибо большое! Получается что операция && даст ноль только когда хотя бы одно из чисел равно нулю (4'b1011 && 4b'0000 например) .

 

 

CaPpuCcino

от assign сейчас вообще пытаются избавиться (в стандартах он указан как устаревший и выводимый из обращения) и заменить его на комбинаторный always- я последнее время намеренно не пользуюсь assign - а пишу alwyas_comb

 

А Квартус поймет always_comb и always_latch ? Надо будет попробовать. Вообще мне такие процессы больше нравятся - понятно что получится.

Share this post


Link to post
Share on other sites

Верилог, вообще, язык довольно простой, но в нем есть несколько "нюансов". Вот эти присваивания - как раз такой "нюанс".

 

В Verilogе (точнее в той его части которая предназначена для тесбенчеей) еще довольно много таких

"нюансов"(и гемороя с ними предостаточно).

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...