Часть 4 Выражения в языке Verilog

4.1 Операнды в выражениях языка Verilog

   Этот раздел описывает операторы и операнды, доступные в Verilog HDL, а также как использовать их в формальных выражениях. Выражения представляют собой конструкции, которые комбинируют операнды с операторами для получения результата, который представляет собой функцию от значений операндов и семантического смысла операторов. Кроме того, выражением может быть любой разрешенный операнд – допустим, группа битов регистра. Существуют некоторые ограничения при написании константных выражений – константные выражения могут содержать только константы или предварительно определенные параметры, но могут содержать любые операторы, приведенные в табл. 4-1. При использовании в выражениях переменных типа integer и time, они воспринимаются, так же как и переменные типа reg.

В языке Verilog можно использовать операнды следующих типов:

-  числа (включающие и вещественные);

-  цепи;

-  регистры, integer и time-переменные;

-  одиночные биты цепи;

-  одиночные биты регистров;

-  группу битов цепи;

-  группу битов регистра;

-  элементы памяти (массива);

-  результат конкатенации;

-  вызовы пользовательских или системных функций, возвращающих любое из

перечисленных выше значений.

 

4.2 Операторы языка Verilog

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

Список операторов приведен в табл. 3.

 

Табл. 3 Список операторов Verilog HDL

Символ

Назначение

Использование с типом real

{}

Конкатенация (concatenation)

Не допустимо

+ - * /

Арифметические (arithmetic)

Допустимо

%

Модуль (modulus)

Не допустимо

> >= < <=

Отношения (relational)

Допустимо

!

Логическое отрицание (logical negation)

Допустимо

&&

Логическое И (logical and)

Допустимо

||

Логическое ИЛИ (logical or)

Допустимо

==

Логическое равенство (logical equality)

Допустимо

!=

Логическое неравенство (logical inequality)

Допустимо

===

Идентичность (case equality)

Не допустимо

!===

Не идентичность (case inecuality)

Не допустимо

~

Побитовая инверсия (bit-wise negation)

Не допустимо

&

Побитовое И (bit-wise and)

Не допустимо

|

Побитовое ИЛИ (bit-wise or)

Не допустимо

^

Побитовое исключающее ИЛИ(bit-wise exclusive or, xor)

Не допустимо

^~ ~^

Побитовая эквивалентность (bit-wise equivalence, xnor)

Не допустимо

&

Редукционное И (reduction and)

Не допустимо

~&

Редукционное НЕ-И (reduction nand)

Не допустимо

|

Редукционное ИЛИ (reduction or)

Не допустимо

~|

Редукционное НЕ-ИЛИ (reduction nor)

Не допустимо

^

Редукционное исключающее ИЛИ (reduction xor)

Не допустимо

~^ ^~

Редукционное НЕ исключающее ИЛИ (reduction xnor)

Не допустимо

<< 

Сдвиг влево (left shift)

Не допустимо

>> 

Сдвиг вправо (right shift)

Не допустимо

<<<2

Циклический сдвиг влево (arithmetic left shift)

Не допустимо

>>> 

Циклический сдвиг вправо (arithmetic right shift)

Не допустимо

?:

Условный оператор (conditional)

Допустимо

 

4.2.1. Приоритет бинарных операций

   Приоритет бинарных операций (а также оператора «?:») подчиняется тем же правилам, что и приоритет аналогичных операций в языке С. Verilog HDL содержит также несколько операций, не представленных в языке С. Ниже представлен список операторов Verilog, упорядоченных по их приоритету.

 

Наивысший приоритет

+ - ! ~ (унарные)

* / %

+ - (бинарные)

<< >> <<< >>>

< <= > >=

== != === !===

& ~&

^ ^~ ~^

| ~|

&&

||

?:

Нижайший приоритет

 

   Операторы, находящиеся в одной строке имеют равный приоритет, строки упорядочены от наивысшего приоритета к наименьшему. Все операторы с равным приоритетом выполняются в порядке слева-направо, исключение составляет операторы «?:» которые выполняются справа-налево.

   В этом примере значение «В» прибавляется к «А», затем «С» вычитается из результата. Когда операторы имеют различный приоритет, сначала выполняются операторы с наивысшим приоритетом, а затем с меньшим.

 

   В этом примере значение «В» будет поделено на значение «С» и результат будет добавлен к «А». Приоритет выполнения операций может быть изменен с помощью круглых скобок.

   Результат будет совершенно другой в отличие от предыдущего примера. Сначала будет вычислена сумма «А» и «В» и лишь затем результат будет поделен на значение «С».

 

 

4.2.2 Знаковые и беззнаковые числа в выражениях.

 

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

 

   В выражениях Verilog интерпретирует числа в виде sss’f nnn (размерные числа, sss – размер числа в битах) как без знаковые. Запись в такую переменную числа со знаком приведет к тому, что в выражении будет использовано не отрицательное число, а дополнительный код, представленный уже как целое положительное число (см. пример в п. 3.5). Еще один пример приведен ниже, он показывает, что аналогичная ситуация может возникнуть и в случае использования переменной типа integer.

   Не будем забывать, что по умолчанию целое число имеет 32 разряда.

 

4.2.3 Арифметические операции

   К бинарным арифметическим операциям относятся: «+», «-», «*», «/», «%». Операция деления отсекает от целого числа дробную часть. Для получения остатка используется операция %. Эта операция воспринимает знак первого операнда. В следующих примерах представлены различные результаты этой операции.

 

   Унарные арифметические операции (+, -) имеют приоритет перед бинарными. Если один из операндов в арифметических операциях имеет неопределенное значение, то и результат операции будет не определён (х).

4.2.4 Операции отношения

   Следующие примеры иллюстрируют операторы отношения:

   Все эти выражения возвращают лог.0 если приведенное отношение ложно (false) или лог.1 если отношение истинно (true). Если один из операндов имеет неопределенное значение, то и результат будет не определен. Все операторы отношения имеют одинаковый приоритет и более низкий, чем приоритет арифметических операторов. Следующий пример иллюстрирует смысл этого правила:

   Заметим, что в конструкции size – (1 < a) операция отношения вычисляется первой, а затем результат (0 или 1) вычитается из переменной size. В следующем же выражении сначала size уменьшается на 1, а затем результат сравнивается с а.

 

4.2.5 Операторы сравнения

   Операторы сравнения имеют более низкий приоритет, чем операторы сравнения. В следующем примере иллюстрируются операторы сравнения.

   Все четыре оператора имеют одинаковый приоритет. Они сравнивают операнды бит в бит, заполнением нулями, в случае если операнды имеют различную разрядность. Так же как и операторы отношения, они возвращают 0 если false и 1 если true. Если хотя бы один операнд содержит «x» или «z», то операции «==» и «!=» возвращают неопределенное значение. Операции «===» и «!==» сравнивают операнды с учетом x и z, поэтому всегда возвращают либо 0, либо 1.

________________________________________________________________________

Замечание:

Некоторые системы синтеза могут выдавать ошибку на операции «===» и «!==».

________________________________________________________________________

 

4.2.6 Логические операции

            Операторы логического «И» (&&) и логического «ИЛИ» (||) тесно связаны между собой. Результат логического сравнения может принимать значение «истинно» (true, 1) или «ложно» (false, 0), или если один из операндов имеет неопределенное значение, то и результат будет не определён. Допустим, один из операндов имеет значение равное 10, а второй равен нулю. Результат логического «И» будет равен 0, так как второй операнд равен нулю. Результат логического «ИЛИ», однако будет равен 1, так как первый операнд отличен от нуля. Verilog HDL воспринимает операнд равный 0 как «ложный», в то же время если операнд не равен нулю (не обязательно равен 1, например 10), то он воспринимается как «истинный». Именно это и произошло в приведенном примере: операция (true && false) привела к результату false, а операция (true || false) привела к результату true.

   Приоритет операции «&&» больше чем приоритет «||», но оба они меньше, чем приоритет операций отношения и сравнения. Рассмотрим следующий пример:

 

24 a < size – 1 && b != c && index != lastone.

 

   Три субвыражения объединены по логическому «И» без использования круглых скобок. Хотя такая конструкция вполне допустима, применять ее не следует из-за ухудшения читабельности кода. Следующий пример читается гораздо легче:

 

(a < size – 1) && (b != c) && (index != lastone)

 

   Третьим логическим оператором является унарный оператор логического отрицания! Оператор логического отрицания преобразует ненулевое («истинное») значение в 0 («ложно»), а нулевое («ложное») в 1(«истинно»). Неопределенное значение приведет к неопределенному результату. Наиболее часто этот оператор используется в следующей конструкции: if (!inword) эта запись эквивалентна записи if (inword == 0).

 

4.2.7 Побитовые логические операции

             Побитовые операции выполняют манипуляции с операндами бит в бит, т.е. например 0-й бит первого операнда взаимодействует с 0-м битом второго; 1-й бит с 1-м и т.д. Если один из операндов имеет меньшую разрядность, то недостающие биты заполняются нулями. В следующих таблицах представлены результаты побитовых операций – значения результирующих битов в зависимости от битов операндов.

 

Таблица 4. Побитовое отрицание (~ - унарная операция)

0

1

1

0

X

 x

Табл. 5. Побитовое И (&)

 

0

1

x

0

0

0

0

1

0

1

x

x

0

x

x

Табл. 6. Побитовое ИЛИ (|)

 

0

 1

 x

0

0

 1

 x

1

1

 1

 1

x

x

 1

 x

Табл. 7. Побитовое исключающее ИЛИ (^)

 

0

 1

 x

0

0

 1

 x

1

1

 0

 x

x

x

 x

 x

Табл. 8. Побитовое исключающее НЕ ИЛИ (~^ ^~)

 

0

 1

 x

0

1

 0

 x

1

0

 1

 x

x

x

 x

 x

   Следует обратить внимание, что операторы & и &&; | и || различаются принципиально. Операторы && и || обычно используются в конструкциях с условиями (if, например), а & и | для маскирования отдельных битов переменной.

 

4.2.8 Операторы редукции

    Все операторы редукции являются унарными, и результатом всех операций является одноразрядное значение – 0, 1 или х. Алгоритм работы всех операторов следующий: на первом шаге вычисляется значение результата операции между 0-м и 1-м битом операнда, на следующем шаге вычисляется результат между предыдущим результатом и 2-м битом операнда и т.д. пока не будет вычислен результат по всем битам. На каждом шаге результат определяется по таблицам истинности 4 – 8. Необходимо заметить, что унарные операторы редукции NAND и NOR вычисляются точно также как операторы AND и OR, а полученный результат инвертируется. В таблице 9 приведены результаты унарных операций &, |, ~& и ~| различных комбинаций битов операнда. В таблице 10 приведены результаты операций ^ и ~^.

 

Таблица 9. Результаты унарных операций &, |, ~& и ~|

 

Разряды операнда

&

|

~&

~|

Все в лог.0

0

0

1

1

Все в лог.1

1

1

0

0

Часть в лог.0, часть в

лог.1

0

1

1

0

 

Таблица 10. Результаты унарных операций ^ и ~^

                                              

Разряды операнда

^

~^

Нечетное число бит в

лог.1

1

0

Четное число бит в

лог.1 (или ни одного)

0

1

 

4.2.9 Синтаксические ограничения

             В языке Verilog накладываются два ограничения для того чтобы защитить файлы описания от типографской ошибки, которые крайне тяжелы для обнаружения. Ошибка заключается в вставке ошибочного пробела. В следующем примере первая строка не соответствует второй:

 

1. a & &b; a | |b;

2. a && b; a || b;

 

   В первой строке введен дополнительный символ пробела между символами & и |. Это может быть замысел разработчика, а может ошибочный ввод пробела. Для того, чтобы предотвратить подобную неоднозначность Verilog требует разделить бинарную и унарную операцию круглыми скобками. В силу этого требования первая строка примера является ошибочной. Поэтому правильно надо записывать так:

 

a & (&b); a | (|b);

 

4.2.10 Операторы сдвига

            К операторам сдвига относятся операторы <<, >>, <<< и >>>. Первые два оператора выполняют простой сдвиг влево или вправо на количество позиций указанных операндом в правой части выражения, два других выполняют циклический или иначе арифметический сдвиг. В следующем примере иллюстрируется механизм действия этих операторов.

                                                                                   Выражение             Результат

     8’b01001111 << 3   8’b01111000

     8’b01001111 <<< 3 8’b01111010

     8’b01001111 >> 3   8’b00001001

     8’b01001111 >>> 3 8’b11101001

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

 

4.2.11 Условный оператор

            Условный оператор имеет три операнда, разделенные двумя операторами в следующем формате:

 

cond_expr ? true_expr : false_expr;

 

            Если условие (cond_expr) вычисляется как «ложное» (false), то в качестве результата будет использовано выражение false_expr. Если условие «истинно» (true), то будет использовано выражение true_expr. В случае если условие неопределенно, то оба выражения false_expr и true_expr сравниваются бит в бит, по правилам указанным в табл. 11, для того, чтобы вычислить окончательный результат. Если разрядность операндов различна, то наименьший из двух приводится к разрядности большего, при этом недостающие биты добавляются слева и заполняются нулями.

 

Таблице 11. Результат неопределенного условия

?:

 0

 1

 x

 z

0

 0

x

 x

 x

1

 x

1

 x

 x

x

x

x

 x

 x

z

x

x

 x

 x

 

            Следующий пример иллюстрирует типичное применение условного оператора для реализации шины с тремя состояниями:

 

wire [15:0] busa = drive_busa ? data : 16’bz;

 

            Если drive_busa равен лог.1 то на шине busa устанавливается значение data. Если drive_busa неизвестен, то неизвестное значение устанавливается и на шине busa. В случае если drive_busa находится в состоянии лог.0, то шина busa находится в состоянии высокого импеданса.

 

4.2.12 Конкатенация

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

            Синтаксис операции приведен ниже:

 

{<expr_1>, <expr_2>, … <expr_n>};

 

            Операция может содержать несколько повторяющихся элементов, для сокращения записи используется множитель, который указывает сколько раз повторяется данный элемент:

 

{4{w}} эквивалентно {w, w, w, w}

 

            Множитель может быть целой, неотрицательной константой или константным выражением.

            Также в операции могут использоваться внутренние объединения:

 

{{a, b, c}, {3{d, e}}} эквивалентно {a, b, c, d, e, d, e, d, e}

 

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