«Бог не меняет того, что (происходит) с людьми, пока они сами не изменят своих помыслов.» Коран, Сура 12:13

Проектирование цифровых систем на языках описания аппаратуры/Лекция 4

Материал из Wiki
Перейти к: навигация, поиск
Лекции ПЦСЯОА

Лекции

Практические

Доп. материалы

Заголовок
Основы языка VHDL. часть 3. Последовательные операторы.
Автор
Ланкевич Ю.Ю.
Нижний колонтитул
Проектирование цифровых систем на языках описания аппаратуры/Лекция 4
Дополнительный нижний колонтитул
Ланкевич Ю.Ю., 19:30, 6 января 2021


Содержание

Слайд:Последовательные операторы

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

На рисунке приведена общая структура VHDL-описания, из которой следует, что последовательные операторы (sequential statement) могут появляться внутри операторов процесса или внутри тел подпрограмм (функций, процедур).

Перечислим последовательные операторы:

  1. оператор присвоения значения переменной;
  2. оператор назначения сигнала, т.е. присвоения значения сигналу;
  3. оператор if (если);
  4. оператор case (случай);
  5. оператор loop (цикл);
  6. оператор next (следующий);
  7. оператор exit (выход);
  8. оператор null (нуль, пустой);
  9. оператор вызова процедуры;
  10. оператор return (возврат);
  11. оператор assert (сообщение);
  12. оператор wait (ожидать).
Структура VHDL описания

Слайд:Оператор присваивания значения переменной

Определение

variable_assignment_statement::=[label] target := expression ;

Данный оператор заменяет текущее значение (target) переменной новым значением, которое определяется выражением (expression). Переменная и выражение должны быть того же базового типа. Еще раз напомним, что присваивание значения переменным не есть то же самое, что сигналам. Присваивание значений сигналам мы обсудим в следующем разделе. В VHDL локальные переменные могут быть только декларированы в области операторов процессов и подпрограмм (функций или процедур). В следующем VHDL-коде приведены примеры присваивания значений переменным. Слева указаны номера строк, не относящиеся к тексту на языке VHDL.

 1  entity VAR is
 2  end VAR;
 3
 4  architecture functional of VAR is
 5      signal A, B, J : bit_vector(1 downto 0);
 6      signal E, F, G : bit;
 7      begin
 8          p0 : process (A, B, E, F, G, J)
 9          variable C, D, H, Y : bit_vector(1 downto 0);
 10         variable W, Q : bit_vector(3 downto 0);
 11         variable Z : bit_vector(0 to 7);
 12         variable X : bit;
 13         variable DATA : bit_vector(31 downto 0);
 14         begin
 15             C := "11";
 16             X := E and F;
 17             Y := H nand J;
 18             Z(0 to 3) := C & D; -- конкатенация
 19             Z(4 to 7) := (not A) & (A nor B); -- конкатенация
 20             D := ('0', '0'); -- агрегат
 21             W := (2 downto 1 => G, 3 => '1', others => '0');
 22             DATA := (others => '1'); -- агрегат
 23         end process;
 24     end functional;

В строке 15 переменная C получает константное значение. Выражения в строке 16, 17 используют логические операторы.
В строке 18 в выражении употребляется оператор & конкатенации, чтобы присвоить значения первым четырем битам переменной Z.
В строке 19 употреблена комбинация логических операторов и конкатенация.
Строка 20 показывает агрегат, в котором употребляется позиционное отображение (соответствие). Запись ('0', '0') называется агрегатом. Агрегат заключается в круглые скобки, входящие в агрегат элементы разделяются запятой.
В строке 21 употребляется позиционное отображение и ключевое слово others.
В строке 22 всем компонентам битового вектора – переменной DATA – присваивается значение единица.
Заметим, что локальные переменные "видны" только внутри процессов или подпрограмм, которые декларированы. VHDL‘93 определяет другой класс переменных, называемых shared (совместно используемые, общие), которые могут совместно использоваться (видны) с процессами и подпрограммами. Подробнее об области видимости смотрите в книге А. Полякова "Языки VHDL и VERILOG в проектировании цифровой аппаратуры" (раздел 1.2.6)
Агрегаты и конкатенация могут использоваться не только при присвоении значений переменным, но и при назначении сигналов для таких типов данных, как массивы.

Рассмотрим пример агрегата.

Variable z_bus : bit_vector (3 downto 0 );
Variable A,B,C,D : bit;
z_bus := (A,B,C,D); -- агрегат

Запись (A,B,C,D) является агрегатом.

Слайд:Присваивание значений сигналам (назначение сигналов)/ Инцерционная и транспортная задержка

В языке VHDL в операторах назначения сигналов, т. е. в операторах присваивания значений сигналам используются два вида задержек:

  • инерционная задержка;
  • транспортная задержка;

Ключевое слово inertial определяет инерционную задержку, ключевое слово transport определяет транспортную задержку.
Пример

X<= inertial Y after 3 ns; -- инерционная задержка
X<= transport Y after 3 ns; -- транспортная задержка.

В случае инерционной задержки передача сигнала будет иметь место, если и только если входной сигнал будет сохранять соответствующий уровень в течение заданного отрезка времени. В языке VHDL этот заданный отрезок времени и есть задержка, указываемая во фразе after. Таким образом, в первом примере изменение значения Y подействует на значение X только в случае, если новый уровень Y будет сохраняться в течение 3ns и более. Во втором примере (транспортная задержка) все изменения Y будут передаваться в X независимо от того, сколько времени будет сохраняться новое значение Y.
! Если не используется ключевое слово transport, то подразумевается инерционная задержка.
Пример

X<= Y after 3 ns; -- инерционная задержка

Механизм инерционной задержки позволяет отфильтровывать входные сигналы, которые меняются слишком быстро, т. е. если длительность сигнала Y меньше 3 ns, то его значение не будет передано сигналу X. Данный механизм по существу имитирует работу реальной схемы. Уровень напряжения определяет значение логического сигнала. Ввиду наличия электрических емкостей напряжения узлов не могут изменяться мгновенно, необходимо, чтобы определенное количество энергии подавалось в течение определенного отрезка времени, – только в этом случае напряжение узла изменится настолько, чтобы вызвать переключение схемы, управляемой этим напряжением. Поэтому при моделировании реальных логических схем используется инерционная задержка. Транспортная задержка чаще используется на этапе алгоритмического проектирования.

Слайд:Присваивание значений сигналам (назначение сигналов)/ Сигналы и переменные

Порты, декларируемые в entity, являются сигналами. Аргументы подпрограмм могут быть сигналами или переменными.
Пример. ( Различие между локальной переменной и сигналом).
Данный VHDL-код

Y<= A+(B*C+D*E*F+G);
Z<= A-(B*C+D*E*F+G);

эквивалентен следующему VHDL-коду

V := (B*C+D*E*F+G);
Y <= A+V;
Y <= A- V;

однако не эквивалентен приведенному ниже VHDL-коду

V <= (B*C+D*E*F+G);
Y <= A+V;
Z <= A - V;

Замечание. Запись x <= y <= z понимается не как "конвейерное" назначение сигналов. Правильное понимание: сигналу x присваивается значение, равное значению выражения y<=z (у меньше либо равно z).

Слайд:Присваивание значений сигналам (назначение сигналов)/ Сигналы и переменные

Назначение сигналов в случае массивов, например битовых векторов, является позиционным.
Пример.

Signal z_bus : bit_vector (3 downto 0);
Signal c_bus : bit_vector (1 to 4);
 z_bus <= c_bus;

эквивалентно

 z_bus(3) <=c_bus(1);
 z_bus(2) <=c_bus(2);
 z_bus(1) <=c_bus(3);
 z_bus(0) <=c_bus(4);

При назначении сигналов должно указываться то направление диапазона (возрастающий диапазон – to, убывающий диапазон – downto), которое было при декларации массива. Для предыдущего примера

z_bus (3 downto 2) <= ''00''; -- правильно
c_bus (2 to 4) <= z_bus (3 downto 1); -- правильно
z_bus (0 to 1) <= ''11''; -- неправильно, так как z_bus декларирован с убывающим диапазоном

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

Signal z_bus : bit_vector (3 downto 0 );
Signal A,B,C,D : bit;
z_bus <= (3 => '1', 1 downto 0 => '1', 2 => B); -- агрегат

Слайд:Оператор if (если)

Общий вид оператора if

if условие then
    упорядоченное множество последовательных операторов
{elsif условие then
    упорядоченное множество последовательных операторов}
[else
    упорядоченное множество последовательных операторов]
end if;

Оператор if языка VHDL подобен операторам if в других языках программирования. Выражение, представляющее собой “условие” должно иметь тип BOOLEAN. В одном if операторе может быть одна (ни одной) либо более частей elsif. Ключевое слово elsif следует отличать от слов else if. Часть else может быть только одна (или ни одной). Должен быть разделитель между ключевыми словами в заключительной фразе end if;
Следующая модель 5-битового счетчика употребляет if операторы.

entity IFSTMT is
    port ( RSTn, CLK, EN, PL : in bit;
           DATA              : in integer range 0 to 31;
           COUNT             : out integer range 0 to 31);
end IFSTMT;
architecture RTL of IFSTMT is
    signal COUNT_VALUE : integer range 0 to 31;
    begin
        p0 : process (RSTn, CLK)
        begin
            if (RSTn = '0') then
                COUNT_VALUE <= 0;
            elsif (CLK'event and CLK = '1') then
                if (PL = '1') then
                    COUNT_VALUE <= DATA;
                elsif (EN = '1') then
                    if (COUNT_VALUE = 31) then
                        COUNT_VALUE <= 0;
                    else
                        COUNT_VALUE <= COUNT_VALUE + 1;
                    end if;
                end if;
            end if;
        end process;
        COUNT <= COUNT_VALUE;
    end RTL;

Как показано в разделе деклараций, 5-битовый счетчик имеет порты RSTn, CLK, EN, PL, DATA. Выходной порт COUNT получает значение счетчика, RSTn – асинхронная установка (в нуль), CLK – входной сигнал синхронизации, PL – параллельное считывание, DATA – порт данных.

Слайд:Оператор case (случай)

Общий вид оператора case

case выражение is
    when выбор => упорядоченное множество
        последовательных операторов
    {when выбор => упорядоченное множество 
        последовательных операторов}
end case;

Оператор case выбирает одну из альтернатив, избранная альтернатива (случай) определяется значением выражения. Выражение должно быть дискретного типа или типа одноразмерного массива символов, значения которых могут быть представлены как строки или строка битов. Выбор должен быть такого же типа, как выражение. Все возможные выборы (случаи) должны быть перебраны. Для случая "others" (другие) должно быть такое значение, которое не соответствует предыдущим альтернативам. Оператор case является подходящим для моделирования конечных автоматов и программ микропроцессора. Используя оператор case, приведем пример VHDL-кода для вычисления числа дней в каждом месяце.

package PACK is
    type month_type is (JAN, FEB, MAR, APR, MAY, JUN,
                        JUL, AUG, SEP, OCT, NOV, DEC);
end PACK;
use work.PACK.all;
entity CASESTMT is
    port ( MONTH : in month_type;
           LEAP : in boolean;
           DAYS : out integer);
end CASESTMT;
architecture RTL of CASESTMT is
begin
    p0 : process (LEAP, MONTH)
    begin
        case MONTH is
            when FEB =>
                if LEAP then
                    DAYS <= 29;
                else
                    DAYS <= 28;
                end if;
            when APR | JUN | SEP | NOV =>
                DAYS <= 30;
            when JUL to AUG =>
                DAYS <= 31;
            when others =>
                DAYS <= 31;
        end case;
    end process;
end RTL;

Слайд:Оператор loop (цикл)

Общий вид оператора loop

[метка цикла:][while условие | for идентификатор in диапазон дискретного типа] loop
    упорядоченное множество последовательных операторов
end loop [метка цикла];

Когда в записи цикла используется ключевое слово while, то сначала вычисляется условие (condition). Если условие есть TRUE, выполняется последовательность последовательных операторов, иначе оператор цикла завершается. Когда в записи цикла используется ключевое слово for, то идентификатор определяет цикловой параметр с базовым дискретным типом. Параметр цикла употребляется как константа внутри действия оператора цикла и он не может быть целью оператора присваивания.
! Общая ошибка: употребление параметра цикла снаружи оператора цикла.
Пример

loop1: for i in 0 to 9 loop
    exit loop1 when A(i)>20;
    next when A(i)>10;
    sum:=sum +A(i);
end loop loop1;
if i=20 then -- ошибка! Параметр цикла снаружи цикла.

Оператор next (следующий)

Общий вид оператора next

next [метка цикла ][when условие];

Пример дан выше. Оператор next употребляется для завершения итераций цикла.

Оператор exit (выход)

Общий вид оператора exit

exit [метка цикла ] [when условие];

Оператор EXIT употребляется, чтобы завершить выполнение и закрыть оператор цикла. Если условие (condition) есть TRUE, то осуществляется выход из цикла.

Оператор null (пустой)

Общий вид оператора null (нуль, пустой)

null;

Оператор null не представляет действий. Он употребляется, чтобы точно специфицировать, что нет действий. Типичное применение – в операторе case, чтобы определить действия во всех случаях.

Слайд:Оператор вызова процедуры

Оператор вызова процедуры состоит из имени процедуры с аргументами (если они есть) в скобках. Приведем пример определения и вызова функции и процедуры.

entity CALL_PRO is
end CALL_PRO;
architecture RTL of CALL_PRO is
    function bit_bool (inp_bit : in bit) return boolean is
    begin
        if (inp_bit = '1') then
            return true;
        else
            return false;
        end if;
    end bit_bool;
    procedure left_one ( signal DATA  : in bit_vector (1 to 8);
                         signal l_bit : out integer) is
    variable temp : integer;
    begin
        temp := 0;
        for i in 1 to 8 loop
            if (DATA(i) = '1') then
                temp := i;
            end if;
            if (temp /= 0) then exit;
            end if;
        end loop;
        l_bit <= temp;
    end left_one;
    signal DIN    : bit_vector (1 to 8);
    signal bit_1  : bit;
    signal bool_1 : boolean;
    signal DOUT   : integer;
    begin
        p0: process (bit_1,DIN)
        begin
            bool_1 <= bit_bool(bit_1); -- вызов функции
            LEFT_ONE(DIN, DOUT); -- вызов процедуры
        end process;
        p1: process
        begin
            bit_1 <= '1' after 20 ns, '0' after 40 ns;
            DIN <= "01010000" after 20 ns,
                   "00000000" after 40 ns,
                   "00001100" after 60 ns,
                   "00000001" after 80 ns;
            wait for 100 ns;
        end process;
    end RTL;

Функция bit_bool преобразует тип BIT в тип BOOLEAN. Предлагаем читателю провести моделирование, проанализировать временную диаграмму и определить функциональное назначение процедуры left_one.

Слайд:Оператор return (возврат)

Общий вид оператора return

return [выражение];

Употребляется, чтобы завершить выполнение самой внутренней функции или процедуры. Он используется только внутри тела функции или процедуры. Оператор return не требуется в теле процедуры, поэтому в архитектурном теле RTL (entity RETURNSTMT) соответствующая строка может быть удалена. Оператор return может быть употреблен с другими последовательными операторами, такими как if, case для управления возвратом функции или процедуры.

Слайд:Оператор assert (сообщение)

Общий вид оператора assert

assert условие [report выражение ] [severity выражение ];

Операторы сообщений проверяют, является ли условие истинным (TRUE), и сообщают об ошибке, если условие является ложным. По умолчанию сообщенное выражение есть "Assertion violation" (нарушение). Выражение с ключевым словом severity (severity – степень серьезности) имеет перечислимый тип: NOTE, WARNING, ERROR, FAILURE. Примеры.

assert (CLK'event and CLK='0') report "D hold error" severity WARNING;
assert (CLK'last_event > HOLD) report "D hold error" severity ERROR;

В данных примерах атрибут CLK'last_event имеет тип TIME и возвращает время, пройденное с момента последнего изменения сигнала CLK, HOLD – имеет тип TIME. Условие CLK'last_event>HOLD может быть либо истинным, либо ложным. Следующие два оператора (две строки) эквивалентны:

report "NEW YEAR 3003" severity ERROR;
assert FALSE report "NEW YEAR 3003" severity ERROR;

также, как и следующие:

report "NEW YEAR 2002";
assert FALSE report "NEW YEAR 2002" severity NOTE;

Так как FALSE всегда является ложным, то данные сообщения всегда выдаются – это примеры безусловно выдаваемых сообщений.

Слайд:Оператор wait (ожидать)

Общий вид оператора wait

wait on список чувствительности until условие for тайм-аут ;

Оператор wait является причиной временного прекращения оператора процесса или процедуры. Оператор ожидания wait приостанавливает процесс до момента, пока не изменится некоторый сигнал в списке чувствительности процесса, в это время будет произведено вычисление условия. Фраза “условие” есть выражение типа BOOLEAN. Если получается истинное значение, выполнение процесса возобновляется. Фраза “тайм-аут” устанавливает максимальное время ожидания, после которого процесс возобновит свое выполнение. Пример.

WAIT on A, B until (C=0) for 50 ns;

Этот оператор приостановит процесс до момента изменения A или B, после чего будет проверено выражение C=0 и, если результатом проверки будет истина, процесс возобновится. Но независимо от этих условий возобновление процесса произойдет через 50ns. Допустимо записывать одно или более условий в операторе ожидания, например,

Условие 1. WAIT on A, B;
Условие 2. WAIT until (C=0);
Условие 3. WAIT for 50 ns;

В условии 1 процесс будет возобновляться, когда изменится A или B. В условии 2 нет списка сигналов запуска, поэтому процесс возобновится, когда C изменит свое значение из 1 в 0. В условии 3 процесс возобновится через 50ns независимо от любых других условий.
! Для оператора процесса мы можем иметь либо список чувствительности после ключевого слова процесс, либо оператор wait, но не оба вместе. Может быть более одного оператора wait внутри оператора процесса.

Слайд:Оператор wait (ожидать)/ Примеры

Примеры оператора wait
1. Оператор wait типа for
 wait for 10ns;
 wait for CLK_Period/2;
2. Оператор wait типа until
 wait until CLK='1';
 wait until CE and (not RST);
 wait until IntData>16;
3. Оператор wait типа on
 wait on CLK;
 wait on Enable, Data;
 Wait until
 Enable ='1';

эквивалентно

 loop
 wait on Enable;
 exit when Enable = '1';
 end loop;
4. Комбинированный оператор wait (комбинация двух или трех предыдущих)
 wait on Data until CLK='1';
 wait until CLK='1' for 10ns;