Основы Verilog: использование casex и full_case, parallel_case

 Статьи по Теме

Основы Verilog: определение битовой ширины выражения (расширение битовой ширины)        

Основы Verilog: определение символов выражения

Основы Verilog: типы данных

Основы Verilog: связь между расширением разрядности и знаковой арифметикой

Основы Verilog: операторы case, casex, casez

Основы Verilog: использование задачи и функции (1)

Основы Verilog: использование задачи и функции (2)

Основы Verilog: целочисленные константы (целые числа) в выражениях

Основы Verilog: иерархические ссылки на имена для идентификаторов

Основы Verilog: восходящие и нисходящие иерархические ссылки на имена для идентификаторов


Оглавление

1. Неправильное использование казекса

2. Неправильное использование casez

3.full_case и параллельный_case

3.1 полный_кейс       

3.2 Неполное описание дела

3.3 - это полное описание случая

3.4 Использование инструкций синтеза full_case

3.5 Недостатки инструкций синтеза full_case

3.6 После использования full_case защелка все еще синтезируется

3.7 параллельный_кейс 

3.8 Оператор case, отличный от parallel_case 

3.9 — это оператор параллельного случая.       

3.9 — это оператор параллельного случая.

3.10 Недостатки инструкции синтеза parallel_case

3.11 Нет необходимости в parallel_case

4. Принцип кодирования оператора case


1. Неправильное использование казекса

        Casex вызовет проблемы с дизайном, потому что casex рассматривает x как «неважно» (то же верно и для z), независимо от того, появляется ли x в выражении case или элементе case в casex. Когда x появляется в выражении case, в это время возникает проблема, потому что оператор caseex не заботится о x в выражении case во время предварительного моделирования, а это означает, что биты с x не участвуют в сопоставлении с выражением case. case, и в это время совпадают только биты, отличные от x. Тогда во время моделирования в модели на уровне ворот нет неопределенного значения x, и результат должен быть одним из 1 или 0, что может привести к неожиданному ответвлению.

        Приведенный ниже модуль code6 представляет собой адресный декодер с разрешающим сигналом. Во время предварительного моделирования иногда инициализация не переходит в допустимое состояние, и ошибка проектирования внешнего интерфейса приводит к тому, что сигнал разрешения изменяется на значение x. Когда enable равно x, casex будет ошибочно соответствовать элементу case в соответствии со значением addr. Если вы невнимательно отнесетесь к значению enable, вы можете подумать, что схема в норме, в настоящее время enable действует, и вывод также правильный. До постсимуляции enable в это время принимает значение x, затем x будет распространяться в цепи уровня затвора, и выходной сигнал будет меняться, что приводит к неопределенности переднего и заднего моделирования.

Пример 1  casex вызвал несоответствие симуляции до и после

module code6 (memce0, memce1, cs, enable, addr);
    output reg memce0, memce1, cs;
    input enable;
    input [31:30]addr;
    
    always@(*)begin
        {memce0, memce1, cs} = 3'b0;
        casex({addr, enable})
            3'b101: memce0 = 1'b1;
            3'b111: memce1 = 1'b1;
            3'b0?1: cs     = 1'b1;
        endcase
    end
endmodule

        Например, если во время предварительной симуляции по какой-то причине enable равно 1, а addr равен 2'bx0, в это время будет установлен memce0, но если вы не посмотрите внимательно, вы примете адрес как должное на основе вывода At на этот раз это 2'b10, или входной адрес также должен быть 2'b10 в это время, и будут проблемы в постсимуляции. При пост-симуляции x будут распространяться через модель уровня ворот, возможно, даже приводя к тому, что на выходе будут все x.

2. Неправильное использование casez

        Casez также вызовет проблемы, аналогичные casex, то есть, когда z появляется в выражении case, поскольку предварительное моделирование вычисляет значение z как «неважно» в операторе casez, такого рода проблемы обычно не игнорируются. во время проверки. При разработке некоторой эффективной логики casez можно использовать для написания более лаконичного кода, такого как кодировщик приоритетов и декодер адресов, поэтому, когда инженеры разрабатывают полезный код, casez не следует отменять.

        Следующий пример аналогичен code6, за исключением того, что здесь используется casez. Когда некоторые сигналы в выражении case изменяются на z, в соответствии с другими входными данными могут возникать ложные совпадения. Но по сравнению с casex (z, x не имеет значения), casez (не имеет значения z) с меньшей вероятностью вызовет ложное совпадение. Поэтому будьте осторожны с casez, чтобы избежать ошибок при сопоставлении z.

Пример 2  с использованием оператора casez

module code7 (memce0, memce1, cs, enable, addr);
    output reg memce0, memce1, cs;
    input enable;
    input [31:30]addr;
    
    always@(*)begin
        {memce0, memce1, cs} = 3'b0;
        casez({addr, enable})
            3'b101: memce0 = 1'b1;
            3'b111: memce1 = 1'b1;
            3'b0?1: cs     = 1'b1;
        endcase
    end
endmodule

 

3.full_case и параллельный_case

        В Verilog есть две часто используемые и критикуемые инструкции синтеза: //synopsys full_case и //synopsys parallel_case. У них есть миф о том, что эти две инструкции сделают дизайн меньше и быстрее, не создавая защелки. Это совсем не так, на самом деле они могут никак не влиять на дизайн, они могут даже сделать дизайн больше и медленнее, сделать дизайн непонятным и синтезировать защелки. Эти две инструкции также вызывают несоответствия между передним и задним моделированием, которые, если они не будут обнаружены во время моделирования на уровне ворот, могут привести к проблемным кристаллам ASIC.

        Поэтому опасно использовать эти две инструкции и избегать их использования. Определения full_case и parallel_case подробно обсуждаются ниже и их влияние на код синтеза.

3.1 полный_кейс       

       full_case означает, что каждое возможное значение выражения case имеет элемент case или значение по умолчанию, соответствующее ему. Даже если оператор case не содержит значения по умолчанию, если каждое выражение case может найти соответствующий элемент case, то оно все равно будет full_case.

3.2 Неполное описание дела

        Для следующего селектора данных с тремя вариантами оператор case здесь неполный, потому что, когда sel=2'b11, нет соответствующего выходного назначения y. Во время моделирования, когда sel=2'b11, y зафиксирует данные, оно сохранит последнее значение, присвоенное y, а инструмент синтеза синтезирует защелку.

  Пример 3 не является полным оператором case

module mux3a(y, a, b, c, sel);
    output reg y;
    input [1:0]sel;
    input a, b, c;
    always@(*) 
        case (sel)
            2'b00: y = a;
            2'b01: y = b;
            2'b10: y = c;  
        endcase  
endmodule

        Примечание: неполный оператор case не обязательно синтезирует защелку.Если существуют ограничения на сигнал case_expression, если неполный оператор case охватывает все возможные значения, это не приведет к созданию защелки.

        Как устранить эту защелку? Вы можете задать начальное значение или использовать оператор по умолчанию .

3.3 - это полное описание случая

        Verilog не требует, чтобы оператор case был заполнен во время синтеза или моделирования, но его можно сделать полным, добавив default. Для следующего селектора данных с тремя вариантами, поскольку используется случай по умолчанию, оператор case становится полным. В моделировании, когда sel равно 2'b11, y приводится к x, но в синтезе назначение x не имеет значения (результат синтеза может быть 0, или 1, или даже связан с определенным сигналом, инструмент синтеза будет использовать любую логику сохранения), что приводит к несоответствию между предварительным моделированием и пост-моделированием. Чтобы обеспечить согласованность, постоянное значение может быть присвоено y в случае значения по умолчанию.

        Но когда мы разрабатываем FSM, присваиваем next_state значение x в случае по умолчанию, что может помочь отладить поддельные переходы между состояниями, так что в случае неправильного перехода next_state останется x, а состояние станет x, что очень удобно в форме сигнала. См. на картинке.

Пример 4 — это полный оператор случая, но между передней и задней симуляциями будут несоответствия.

module mux3b(y, a, b, c, sel);
    output reg y;
    input [1:0]sel;
    input a,b,c;
    always@(*) 
        case (sel)
            2'b00:     y = a;
            2'b01:     y = b;
            2'b10:     y = c;  
            default:   y = 1'bx;
            //2'b11:   y = 1'bx; 另一种方法,同样的效果
            //default: y = 1'b0; 这样前后仿真一致
        endcase   
endmodule

        Если начальное значение присваивается выходу перед оператором case, даже если оператор case неполный или неполный, защелка все равно не будет синтезирована. 

В Примере 5 начальное значение присваивается перед корпусом, и не будет несоответствия между симуляцией до и после.           

module mux3c(y, a, b, c, sel);
    output reg y;
    input [1:0]sel;
    input a,b,c;
    always@(*)
        y = 1'b0; 
        case (sel)
            2'b00: y = a;
            2'b01: y = b;
            2'b10: y = c;  
        endcase  
endmodule

3.4 Использование инструкций синтеза full_case

        Когда «//synopsys full_case» добавляется к заголовку оператора case, это не действует во время симуляции Verilog, поскольку «//synopsys full_case» рассматривается только как комментарий. Но Synopsys Design Complier интерпретирует все комментарии, начинающиеся с «//synopsys», как инструкции по синтезу. Функция full_case заключается в том, что если оператор case не заполнен, то для всех элементов case, которые не появляются, вывод будет рассматриваться как «безразлично».Если оператор case включает элемент по умолчанию, то инструкция full_case будет игнорироваться.

        Для следующих трех селекторов оператор case внутри не является полным, но если в заголовок оператора case добавить инструкцию «full_case», инструмент синтеза расценит ее как заполненную и не будет синтезировать защелку, как если бы добавлялся оператор case. предложение по умолчанию: y=1'bx имеет тот же эффект. При моделировании до Verilog, когда sel=2'b11, вывод y представляется как защелка, но при синтезе инструмент синтеза рассматривает вывод, когда Sel=2'b11, как "неважно", а вывод при этом время состоит из 6 решений инструментов (см., как сохранить логику), что может привести к несоответствиям между симуляциями до и после.

Пример 6. Использование инструкции синтеза full_case

module mux3d(y, a, b, c, sel);
output reg y;
input [1:0]sel;
input a, b, c;
always@(*)
    case(sel) //synopsys full_case
        2'b00 : y = a;
        2'b01 : y = b;
        2'b10 : y = c;
    endcase
endmodule

        На следующих двух рисунках показаны результаты синтеза без и с инструкциями синтеза full_case.

 Нет директивы синтеза full_case

 Существуют директивы синтеза full_case

3.5 Недостатки инструкций синтеза full_case

        Инструкция синтеза "//synopsys full_case" используется только для инструментов синтеза, но не для инструментов моделирования. Эта специальная директива используется, чтобы сообщить инструменту синтеза, что операторы case завершены и не заботятся о бесполезных назначениях вывода case. Если используется эта инструкция, функции до и после синтеза могут отличаться. Кроме того, хотя эта инструкция говорит синтезатору не заботиться об этих бесполезных состояниях, эта инструкция иногда делает проект больше и медленнее, чем без инструкции full_case.

        В code4a в операторе case не используются какие-либо инструкции синтеза, а конечная выходная логика представляет собой декодер, состоящий из логического элемента И с 3 входами и инвертора, а моделирование до и после согласовано. В code4b оператор case использует инструкцию full_case, поэтому ввод en оптимизируется во время синтеза и становится оборванным (висячим) вводом. Предварительная эмуляция code4a и code4b согласована, но предварительная и постэмуляция code4b несовместимы. Обратите внимание, что когда все сигналы, появляющиеся в выражении элемента case, не учитываются при неопределенном вводе, если появляется переменный индекс вектора, такой как y[a], то все сигналы y не учитываются; наличие эти биты не имеют значения, если присутствуют только постоянные индексы.

Пример 7 не использует full_case, симуляция согласована до и после

module code4a(y, a, en);
    output reg [3:0]y;
    input [1:0]a;
    input en;
    always@(*)begin
        y=4'h0;
        case({en, a})
            3'b100: y[a] = 1'b1;
            3'b101: y[a] = 1'b1;
            3'b110: y[a] = 1'b1;
            3'b111: y[a] = 1'b1;
        endcase
    end
endmodule

 В примере 8  используется full_case, симуляция до и после несовместима

module code4b(y, a, en);
    output reg [3:0]y;
    input [1:0]a;
    input en;
    always@(*)begin
        y=4'h0;
        case({en, a}) //synopsys full_case
            3'b100: y[a] = 1'b1;
            3'b101: y[a] = 1'b1;
            3'b110: y[a] = 1'b1;
            3'b111: y[a] = 1'b1;
        endcase
    end
endmodule

3.6 После использования full_case защелка все еще синтезируется

        Существует такой миф, что ''//synopsys full_case" может устранить все защелки в операторе case. Если оператор case не добавляет full_case, синтез будет генерировать защелки, затем после использования full_case их можно будет устранить.

        На самом деле, на этот раз оно было неправильным или неполным. Если в операторе case есть назначения для нескольких выходов, и назначение не завершено после некоторых элементов case, даже если оператор case заполнен или имеет оператор по умолчанию в это время, защелка будет синтезирована, даже если добавлен full_case. инструкции.

        Например, приведенный ниже простой декодер адресов будет генерировать защелки для mce0_n, mce1_n и rce_n. Хотя в этом операторе используется full_case, поскольку не все выходы назначаются в каждом case_item, защелка будет синтезирована для всех выходов. Способ устранения этой защелки тоже очень прост, выполнить назначение всех выходов или присвоить начальные значения всем выходам в начале блока always.

Пример 9. Даже если есть full_case, защелка все равно синтезируется

module addrDecode1a(mce0_n, mce1_n, rce_n, addr);
    output    reg    mce0_n, mce1_n, rce_n;
    input [31:30]    addr;
    always@(*)
        //{mce1_n, mce0_n,rce_n} = 3'b0;
        casez(addr) //synopsys full_case
            2'b10: {mce1_n, mce0_n} = 2'b10;
            2'b11: {mce1_n, mce0_n} = 2'b01;
            2'b0?: rce_n = 1'b0;
        endcase
endmodule

Комплексные результаты

 Комплексный результат присвоения начального значения после блока always

3.7 параллельный_кейс 

        Оператор parallel_case относится к оператору, в котором выражение case может соответствовать только одному элементу case. Если обнаруживается, что выражение case может соответствовать более чем одному элементу case, то эти совпадающие элементы case называются перекрывающимися элементами case, и этот оператор case не является параллельным.

3.8 Оператор case, отличный от parallel_case 

        Следующий пример с использованием casez не является параллельным оператором case, потому что если irq=3'b111, 3'b101, 3'b110 или 3'b111, будет более одного элемента case, соответствующего irq. Это действует как кодировщик приоритета в симуляции, irq[2] имеет наивысший приоритет и больше, чем irq[1], который больше, чем irq[0]. Этот пример также получает кодировщик приоритета при синтезе.

Пример 10 Оператор Case, который не является параллельным

module intctl1a(int2, int1, int0, irq);
    output   reg   int2, int1, int0;
    input    [2:0] irq;
    always@(*)begin
        {int2, int1, int0} = 3'b0;
        casez(irq)
            3'b1??: int2=1'b1;
            3'b?1?: int1=1'b1;
            3'b??1: int0=1'b1;
        endcase
    end
endmodule

Общий результат выглядит следующим образом: он сглажен, поэтому структура приоритета не видна, но если int1 хочет быть 1, irq[2] должен быть 0, а если int0 хочет быть 1, то оба irq[2] и irq [1] должен быть равен 0.

3.9 — это оператор параллельного случая.       

        После изменения приведенного выше примера мы получаем следующий код, в котором каждый элемент case независим, поэтому он параллелен.

Пример 11 — оператор case для параллельного

module intctl2a(int2, int1, int0, irq);
    output reg     int2, int1, int0;
    input [2:0]    irq;
    always@(*)begin
        {int2, int1, int0} = 3'b0;
        casez(irq)
            3'b1??: int2 = 1'b1;
            3'b01?: int1 = 1'b1;
            3'b001: int0 = 1'b1;
        endcase
    end
endmodule

 Общий результат такой же, как и в предыдущем примере.

3.9 — это оператор параллельного случая.

        В следующем примере инструкция «synopsys parallel _case» добавляется в заголовок оператора case. Этот пример моделируется как кодер с приоритетом во время моделирования, но кодер без приоритета выводится во время синтеза. Хотя инструкция parallel_case действует во время синтеза, симуляция несовместима до и после этого времени.

В примере 12 используется инструкция синтеза parallel_case, что приводит к несогласованности между прямым и обратным моделированием.

module intctl1b(int2, int1, int0, irq);
    output reg     int2, int1, int0;
    input [2:0]    irq;
    always@(*)begin
        {int2, int1, int0} = 3'b0;
        casez(irq) //synopsys parallel_case
            3'b1??: int2 = 1'b1;
            3'b?1?: int1 = 1'b1;
            3'b??1: int0 = 1'b1;
        endcase
    end
endmodule

Комплексный результат показывает, что в настоящее время вход и выход напрямую связаны, как показано в коде Verilog на рисунке ниже.

 

         Результатом этого является то, что оператор case теряет возможность проверять элемент case сверху вниз, но проверяет все элементы case параллельно.Пока они совпадают, операторы, стоящие за этими элементами case, выполняются параллельно.

3.10 Недостатки инструкции синтеза parallel_case

        Инструкция синтеза "//synopsys parallel_case" используется только в инструменте синтеза и не влияет на инструмент моделирования. Эта специальная инструкция используется, чтобы сообщить инструменту синтеза, что все элементы case проверяются параллельно, даже если есть кодировщик приоритета, который может быть получен, и есть перекрытие. Эта директива иногда может сделать дизайн большим и медленным.

        Предварительное моделирование модулей code5a и code5b, предварительное и последующее моделирование code5a согласованы, и все они работают в соответствии с приоритетным кодером, то есть только тогда, когда a и b не равны 1 одновременно, y может быть 1. Но исчерпывающим результатом code5b являются два вентиля И, то есть, пока a и b равны 1 одновременно, z равно 1; пока c и d одновременно равны 1, y равно 1. Эта параллельная структура приводит к несогласованности моделирования до и после.

Пример 13 Без команды parallel_case моделирование до и после согласовано

module code5a(y, z, a, b, c, d);
    output reg y, z;
    input a, b, c, d;
    always@(*)begin
        {y, z} = 2'b0;
        casez ({a, b, c, d})
            4'b11??: z = 1;
            4'b??11: y = 1;
        endcase
    end
endmodule

Комплексные результаты

Пример 14. Использование команды parallel_case приводит к несоответствиям между передним и задним моделированием.

module code5b(y, z, a, b, c, d);
    output reg y, z;
    input a, b, c, d;
    always@(*)begin
        {y, z} = 2'b0;
        casez ({a, b, c, d}) //synopsys parallel_case
            4'b11??: z = 1;
            4'b??11: y = 1;
        endcase
    end
endmodule

Комплексные результаты

15

3.11 Нет необходимости в parallel_case

        Следующий пример casez изначально является параллельным Добавление инструкции parallel_case в начало оператора case на самом деле не имеет большого смысла, потому что логика, синтезированная с использованием parallel_case, такая же, как и логика, синтезированная без использования parallel.

Пример 15. Нет необходимой директивы parallel_case

module intctl2b(int2, int1, int0, irq);
    output reg     int2, int1, int0;
    input [2:0]    irq;
    always@(*)begin
        {int2, int1, int0} = 3'b0;
        casez(irq) //synopsys parallel_case
            3'b1??: int2 = 1'b1;
            3'b01?: int1 = 1'b1;
            3'b001: int0 = 1'b1;
        endcase
    end
endmodule

        Так что parallel_case опасен, когда работает parallel_case. Когда parallel_case не работает, это просто лишний символ в заголовке оператора case.

4. Принцип кодирования оператора case

        Ниже приведены некоторые рекомендации по использованию операторов case, директив full_case и parallel_case.

        1. Для параллельной разработки написания выражений оператор case является хорошим выбором, а код получается более кратким и понятным.

        2. При разработке синтезируемого кода будьте осторожны и используйте операторы casez вместо операторов casex.

        3. Будьте осторожны при использовании обратного оператора case, лучше всего использовать его только для параллельных операторов case.

        4. Будьте осторожны при использовании оператора casez для разработки структуры приоритета, и вы также можете использовать оператор if else if для реализации структуры приоритета, чтобы намерение было более очевидным.

        5. При использовании оператора casez используйте «?» для обозначения битов, которые вам не нужны, и лучше не использовать «z».

        6. Лучше всего добавить значение по умолчанию в оператор case и не назначать выход «x». Конечно, также возможно присвоить начальные значения всем выходам в начале блока always.

        7. Обычно не используйте "//synopsys full_case и parallel_case". Поскольку эти две инструкции предоставляют конкретную информацию только инструменту синтеза, но не инструменту моделирования, это, вероятно, вызовет несоответствие между передним и задним моделированием.

        8. Если вы хорошо понимаете механизм работы этих двух инструкций и знаете свои намерения, то можете использовать эти две инструкции.

        9. Лучше всего использовать "//synopsys full_case" только для одного горячего FSM.

        10. Проверьте отчет об операторе case, выведенном инструментом синтеза. При обнаружении исключения соответствующий оператор case должен быть изменен.

        Окончательный вывод: когда работают директивы синтеза full_case и parallel_case, они на самом деле самые опасные. Лучший способ — не использовать эти две инструкции, а напрямую написать оператор case о полном и параллельном. Также будьте осторожны с операторами casez и casex.

Вышеприведенный контент взят из «Verilog Programming Art» с удалениями и изменениями.

Supongo que te gusta

Origin blog.csdn.net/weixin_45791458/article/details/130138239
Recomendado
Clasificación