9. If, case for, while и repeat Verilog HDL

Описание конструкций объявления в Verilog HDL: for, repeat, while, forever, if-else, if-else-if. Часть 2 главы 9. Поведенческое моделирование.
Содержание

9.4 Условное оператор if-else

Условный оператор (или оператор if-else) используется для принятия решения о том, будет ли выполняться оператор. Формально синтаксис приведен в Синтаксисе 9-4.

conditional_statement ::= if ( expression ) statement_or_null [ else statement_or_null ] | if_else_if_statement
Синтаксис 9-4-Синтаксис для оператора if

Если выражение оценивается как true (то есть имеет ненулевое известное значение), то выполняется первый оператор. Если выражение равно false (то есть имеет нулевое значение или значение равно x или z), то первый оператор не выполняется. Если есть оператор else и выражение равно false, то выполняется оператор else.

Поскольку числовое значение выражения if проверяется на равенство нулю, возможны некоторые сокращения. Например, следующие два выражения выражают одну и ту же логику:
if (expression) if (expression != 0)
Поскольку часть else в if-else является необязательной, может возникнуть путаница, когда else опущена во вложенной последовательности if. Это решается тем, что else всегда ассоциируется с ближайшим предыдущим if, в котором отсутствует else. В приведенном ниже примере else идет вместе с внутренним if, как показано отступом.
if (index > 0) if (rega > regb) result = rega; else // else applies to preceding if result = regb;
Если такое объединение нежелательно, то для принудительного объединения следует использовать оператор блока begin-end, как показано ниже.
if (index > 0) begin if (rega > regb) result = rega; end else result = regb;

9.4.1 Конструкция if-else-if

Конструкция в синтаксисе 9-5 встречается настолько часто, что заслуживает отдельного краткого обсуждения:

if_else_if_statement ::= (From A.6.6) if ( expression ) statement_or_null { else if ( expression ) statement_or_null } [ else statement_or_null ]
Синтаксис 9-5-Синтаксис для конструкции if-else-if

Эта последовательность выражений if (известная как конструкция if-else-if) является наиболее общим способом написания многоходового решения. Выражения оцениваются по порядку. Если какое-либо выражение истинно, выполняется связанный с ним оператор, и на этом вся цепочка завершается. Каждое объявление — это либо одно объявление, либо блок объявлений.

Последняя else-часть конструкции if-else-if обрабатывает случай, когда ни одно из вышеперечисленных условий не было выполнено. Иногда для случая по умолчанию нет явного действия. В этом случае оператор else можно опустить, или использовать его для проверки ошибок, чтобы поймать невозможное условие.

Например:

Следующий фрагмент модуля использует оператор if-else для проверки переменной index, чтобы решить, нужно ли добавить к адресу памяти один из трех regs modify_segn и какой инкремент должен быть добавлен к index reg. В первых десяти строках объявляются регистры и параметры.
// объявление регистров и параметров reg [31:0] instruction, segment_area[255:0]; reg [7:0] index; reg [5:0] modify_seg1, modify_seg2, modify_seg3; parameter segment1 = 0, inc_seg1 = 1, segment2 = 20, inc_seg2 = 2, segment3 = 64, inc_seg3 = 4, data = 128; // проверка индексной переменной if (index < segment2) begin instruction = segment_area [index + modify_seg1]; index = index + inc_seg1; end else if (index < segment3) begin instruction = segment_area [index + modify_seg2]; index = index + inc_seg2; end else if (index < data) begin instruction = segment_area [index + modify_seg3]; index = index + inc_seg3; end else instruction = segment_area [index];

9.5 Оператор case

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

Синтаксис оператора case показан в Синтаксисе 9-6.

case_statement ::= case ( expression ) case_item { case_item } endcase | casez ( expression ) case_item { case_item } endcase | casex ( expression ) case_item { case_item } endcase case_item ::= expression { , expression } : statement_or_null | default [ : ] statement_or_null
Синтаксис 9-6-Синтаксис для оператора case

Объявление default должно быть необязательным. Использование нескольких объявлений по default в одном объявлении case должно быть незаконным.

Выражение case и выражение элемента case могут быть вычислены во время выполнения. Ни одно из них не должно быть константным выражением.

Например:

Простым примером использования оператора case является расшифровка reg rega для получения значения для результат следующий:
reg [15:0] rega; reg [9:0] result; case (rega) 16'd0: result = 10'b0111111111; 16'd1: result = 10'b1011111111; 16'd2: result = 10'b1101111111; 16'd3: result = 10'b1110111111; 16'd4: result = 10'b1111011111; 16'd5: result = 10'b1111101111; 16'd6: result = 10'b1111110111; 16'd7: result = 10'b1111111011; 16'd8: result = 10'b1111111101; 16'd9: result = 10'b1111111110; default result = 'bx; endcase

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

Помимо синтаксиса, оператор case отличается от многоходовой конструкции if-else-if двумя важными моментами:

1) Условные выражения в конструкции if-else-if являются более общими, чем сравнение одного выражения с несколькими другими, как в операторе case.

2) Оператор case дает окончательный результат, когда в выражении есть значения x и z.

При сравнении выражений case сравнение будет успешным только тогда, когда каждый бит точно совпадает со значениями 0, 1, x и z. Как следствие, необходимо тщательно подходить к определению выражений в выражении case. Длина битов всех выражений должна быть одинаковой, чтобы можно было выполнить точное побитовое сравнение. Длина всех выражений элементов case, а также выражения в круглых скобках должна быть равна длине самого длинного выражения case и выражения элемента case. Если любое из этих выражений является беззнаковым, то все они должны рассматриваться как беззнаковые. Если все эти выражения являются знаковыми, то все они должны рассматриваться как знаковые.

Причина предоставления сравнения выражения случая, которое обрабатывает значения x и z, заключается в том, что оно обеспечивает механизм для обнаружения таких значений и уменьшения нежелательных случаев, который может быть порожден их присутствием.

Например:

Пример 1 Следующий пример иллюстрирует использование оператора case для правильной обработки значений x и z:
case (select[1:2]) 2'b00: result = 0; 2'b01: result = flaga; 2'b0x, 2'b0z: result = flaga ? 'bx : 0; 2'b10: result = flagb; 2'bx0, 2'bz0: result = flagb ? 'bx : 0; default result = 'bx; endcase

В этом примере, если select[1] равен 0 и flaga равен 0, то даже если значение select[2] равно x или z, результат должно быть равно 0, что решается третьим случаем.

Пример 2-В следующем примере показан другой способ использования оператора case для определения значений x и z:
case (sig) 1'bz: $display("signal is floating"); 1'bx: $display("signal is unknown"); default: $display("signal is %b", sig); endcase

9.5.1 Объявление case с условием обработки «не заботиться»

Два других типа объявлений case предусмотрены для обработки условий «не заботиться» в сравнениях case. Один из них рассматривает высокоимпедансные значения (z) как условия «не беспокоить», а другой рассматривает как высокоимпедансные, так и неизвестные (x) значения как условия «не беспокоить».

Объявление этих case можно использовать так же, как и традиционные объявление case, но они начинаются с ключевых слов casez и casex, соответственно.

Значения «не заботиться» (значения z для casez, значения z и x для casex) в любом бите либо выражения case, либо элементов case должны рассматриваться как условия «не заботиться» во время сравнения, и эта позиция бита должна не учитываются. Условия do-not-care в выражении case можно использовать для динамического управления тем, какие биты должны сравниваться в любой момент времени.

Синтаксис литеральных чисел позволяет использовать вопросительный знак (?) вместо z в объявлении случаев. Это обеспечивает удобный формат для указания битов «не беспокоить» в объявленных случая.

Например:

Пример 1— Ниже приведен пример оператора casez. Он демонстрирует декодирование инструкции, где значения старших битов определяют, какая задача должна быть вызвана. Если старший бит ir равен 1, то вызывается инструкция задачи1, независимо от значений остальных битов ir.
reg [7:0] ir; casez (ir) 8'b1???????: instruction1(ir); 8'b01??????: instruction2(ir); 8'b00010???: instruction3(ir); 8'b000001??: instruction4(ir); endcase
Пример 2 Ниже приведен пример оператора casex. Он демонстрирует крайний случай того, как можно динамически управлять условиями do-not-care во время моделирования. В этом случае, если r = 8’b01100110, то вызывается задача stat2.
reg [7:0] r, mask; mask = 8'bx0x0x0x0; casex (r ^ mask) 8'b001100xx: stat1; 8'b1100xx00: stat2; 8'b00xx0011: stat3; 8'bxx010100: stat4; endcase

9.5.2 Константные выражения в операторе case

Константное выражение может быть использовано для выражения регистра. Значение постоянного выражения должно сравниваться с выражениями элементов регистра.

Например:

Следующий пример демонстрирует использование на примере моделирования 3-битного приоритетного кодера:
reg [2:0] encode ; case (1) encode[2] : $display("Select Line 2") ; encode[1] : $display("Select Line 1") ; encode[0] : $display("Select Line 0") ; default $display("Error: One of the bits expected ON"); endcase

В данном примере выражение case — это постоянное выражение (1). Элементы case являются выражениями (битовыми выборами) и сравниваются с постоянным выражением на предмет совпадения.

9.6 Циклические операторы

Существует четыре типа циклических операторов. Эти операторы позволяют управлять выполнением оператора ноль, один или несколько раз.

forever — Непрерывное выполнение оператора.

repeat — Выполняет оператор фиксированное количество раз. Если выражение оценивается как неизвестный или высокий импеданс, оно рассматривается как ноль, и оператор не выполняется.

while -Выполняет оператор до тех пор, пока выражение не станет ложным. Если выражение становится ложным, оператор не выполняется вообще.

for — Контролирует выполнение связанного с ним объявлений с помощью следующего трехэтапного процесса:

1) Выполняет назначение, обычно используемое для инициализации переменной, которая управляет количеством выполняемых циклов.

2) Оценивает выражение. Если результат равен нулю, цикл for завершается. Если результат не равен нулю, цикл for должен выполнить связанный с ним оператор(ы), а затем выполнить шаг c). Если выражение оценивается в неизвестное или высокоимпедансное значение, оно должно рассматриваться как ноль.

3) Выполняет назначение, обычно используемое для изменения значения переменной управления циклом, затем повторяет шаг b).

Синтаксис 9-7 показывает синтаксис для различных операторов цикла.

loop_statement ::= forever statement | repeat ( expression ) statement | while ( expression ) statement | for ( variable_assignment ; expression ; variable_assignment ) statement
Синтаксис 9-7 — Синтаксис для циклических операторов

В остальной части этого подраздела представлены примеры трех операторов цикла. Цикл forever должен использоваться только в сочетании с управлением синхронизацией или оператором disable. Поэтому этот пример представлен в разделе 9.7.2.

Например:

Пример 1- repeat: В следующем примере цикла повторения операторы add и shift реализуют множитель:
parameter size = 8, longsize = 16; reg [size:1] opa, opb; reg [longsize:1] result; begin : mult reg [longsize:1] shift_opa, shift_opb; shift_opa = opa; shift_opb = opb; result = 0; repeat (size) begin if (shift_opb[1]) result = result + shift_opa; shift_opa = shift_opa << 1; shift_opb = shift_opb >> 1; end end
Пример 2- Оператор While: В следующем примере подсчитывается количество значений логической 1 в rega:
begin : count1s reg [7:0] tempreg; count = 0; tempreg = rega; while (tempreg) begin if (tempreg[0]) count = count + 1; tempreg = tempreg >> 1; end end
Пример 3 — Оператор for: Оператор for достигает тех же результатов, что и следующий псевдокод, основанный на цикле while:
begin initial_assignment; while (condition) begin statement step_assignment; end end
Цикл for реализует эту логику, используя всего две строки, как показано в приведенном ниже псевдокоде:
for (initial_assignment; condition; step_assignment) statement