Операторы параллельного присваивания сигналов в VHDL: с помощью выбора варианта и по условию

Добавлено 31 октября 2018 в 18:41

В данной статье будут рассмотрены операторы параллельного присваивания сигналов в VHDL.

В данной статье будет рассмотрена концепция параллелизма в языках описания аппаратного обеспечения. Затем мы обсудим два оператора параллельного присваивания сигнала в VHDL: присваивание сигнала с помощью выбора варианта (selected signal assignment) и присваивание сигнала по условию (conditional signal assignment). После нескольких примеров мы кратко рассмотрим эти два типа операторов присваивания сигнала.

Если вы не знакомы с концепцией VHDL, то смотрите первую статью о введении в VHDL.

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

Чтобы понять разницу между параллельными и последовательными операциями, рассмотрим простую комбинационную схему, показанную на рисунке 1.

Рисунок 1 – Комбинационная схема
Рисунок 1 – Комбинационная схема

Если мы рассмотрим работу этих трех логических элементов на рисунке, то заметим, что каждый логический элемент обрабатывает свой текущий входной сигнал(ы) независимо от других логических элементов. Эти физические компоненты работают одновременно. В тот момент, когда на них подано питание, они будут «одновременно» выполнять свои функции. Обратите внимание, что, хотя на практике логический элемент И имеет задержку выдачи корректного выходного сигнала, это не означает, что логический элемент ИЛИ остановит свою работу и дождется выходного сигнала элемента И. Элемент ИЛИ будет работать всё время; однако его выходной сигнал будет некорректным, пока не установятся его входные сигналы.

Теперь давайте рассмотрим описание VHDL для рисунка 1. Оно показано ниже:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;


entity comb1 is
    Port ( a : in  STD_LOGIC;
           b : in  STD_LOGIC;
           c : in  STD_LOGIC;
           d : in  STD_LOGIC;
           out1 : out  STD_LOGIC;
           out2 : out  STD_LOGIC);
end comb1;

architecture Behavioral of comb1 is
    signal sig1: std_logic;
begin
    sig1 <= ( a and b );
    out1 <= ( sig1 or c );
    out2 <= (not d);

end Behavioral;

Основное, что нам здесь интересно, – это определение этих трех логических элементов:

sig1 <= ( a and b );
out1 <= ( sig1 or c );
out2 <= (not d);

Каждая из этих строк описывает физический компонент на рисунке 1. Например, вторая строка, которая описывает логический элемент ИЛИ, принимает значения sig1 и c как входы и выдает результат операции ИЛИ этих двух значений. Мы видели, что физические компоненты на рисунке 1 работают одновременно. Следовательно, разумно ожидать, что описание VHDL этих элементов должно определяться параллельным способом. Другими словами, три вышеуказанные строки кода выполняются одновременно, и нет никакого значения для порядка этих операторов. В результате мы можем переписать секцию architecture приведенного выше кода следующим образом:

architecture Behavioral of comb1 is
	signal sig1: std_logic;
begin
	
	out1 <= ( sig1 or c );
	out2 <= (not d);
	sig1 <= ( a and b );

end Behavioral;

Поскольку эти операторы оцениваются одновременно, мы называем их параллельными операторами. Этот тип кода сильно отличается от того, что мы узнали в базовом компьютерном программировании, где строки кода выполняются одна за другой. Например, рассмотрим следующий код MATLAB:

clear all;
a=1;
b=0;
c=1;
d=0;
sig1=and(a, b);
out1=or(sig1, c)
out2=not(d)

Данный код выдает out1=1 и out2=1. Однако, если мы изменим порядок операторов на следующий, программа перестанет работать, потому что мы пытаемся использовать sig1 до его создания

out1=or(sig1, c)
out2=not(d)
sig1=and(a, b);

Хотя код VHDL, описывающий рисунок 1, выполнялся одновременно, показанный выше код MATLAB рассматривается последовательно (то есть одна строка за другой). VHDL поддерживает как параллельные операторы, так и последовательные. Понятно, что параллельные операторы VHDL позволят нам легко описать схему, такую как схема, показанная на рисунке 1 выше. В следующей статье мы увидим, что последовательные инструкции VHDL позволяют нам иметь более безопасное описание последовательных схем. Кроме того, используя последовательный VHDL, мы можем легко описать цифровую схему поведенческим образом. Эта возможность может значительно облегчить проектирование цифрового аппаратного обеспечения.

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

Рисунок 2 – Разница между параллельными и последовательными операторами
Рисунок 2 – Разница между параллельными и последовательными операторами

Теперь давайте рассмотрим два параллельных оператора присваивания сигнала в VHDL: «оператор присваивания сигнала с помощью выбора варианта» (selected signal assignment statement) и «оператор присваивания сигнала по условию» (conditional signal assignment statement).

Присваивание сигнала с помощью выбора варианта или оператор “with/select

Рассмотрим мультиплексор «n к 1», как показано на рисунке 3. Этот блок должен выбрать один из своих n входов и передать значение этого входа на выходной вывод, т.е. output_signal.

Рисунок 3 – Мультиплексор выбирает один из своих n входов, основываясь на значении управляющего выражения control_expression.
Рисунок 3 – Мультиплексор выбирает один из своих n входов, основываясь на значении управляющего выражения control_expression.

Присваивание сигнала с помощью выбора варианта позволяет нам реализовать функциональность мультиплексора. Например, VHDL код, описывающий мультиплексор, будет следующим:

with control_expression select
    output_signal <= value_1    when    option_1,
                     value_2    when    option_2,
                     ...
                     value_n	when	option_n; 

Здесь значение control_expression будет сравниваться с n возможных вариантов, т.е. option_1, option_2, …, option_n. Когда совпадение будет найдено, значение, соответствующее этому конкретному варианту, будет присвоено выходному сигналу, т.е. output_signal. Например, если control_expression совпадает с вариантом option_2, то значение value_2 будет присвоено output_signal.

Обратите внимание, что варианты оператора “with/select” должны быть взаимоисключающими, т.е. один вариант нельзя использовать более одного раза. Более того, все возможные значения control_expression должны быть включены в набор вариантов. Следующий пример разъясняет эти моменты.

Пример 1. Используйте оператор "with/select" для описания одноразрядного мультиплексора «4-к-1». Предположим, что необходимо выбирать входы a, b, c и d. А двухбитовый сигнал sel используется для выбора нужного входа и его присваивания выходу out1.

Код для этого мультиплексора приведен ниже:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity Mux1 is
    Port ( a : in  STD_LOGIC;
           b : in  STD_LOGIC;
           c : in  STD_LOGIC;
           d : in  STD_LOGIC;
           sel : in  STD_LOGIC_VECTOR (1 downto 0);
           out1 : out  STD_LOGIC);
end Mux1;

architecture Behavioral of Mux1 is

begin
    with sel select
            out1 <= a when "00",
                    b when "01",
                    c when "10",
                    d when others;

end Behavioral;

Обратите внимание: поскольку тип данных std_logic может принимать значения, отличные от "0" и "1", в последней строке оператора “with/select” должно использоваться ключевое слово “others”, чтобы учитывать все возможные значения sel.

На следующем рисунке показано моделирование данного кода с помощью симулятора Xilinx ISE. Как показано на этом рисунке, от 0 наносекунд до 300 наносекунд вход выбора, sel, равен 00, и, следовательно, out1 принимает такое же значение как на входе a. Аналогично вы можете проверить предсказуемую работу на оставшемся времени моделирования.

Рисунок 4 – ISE моделирование мультиплексора из примера 1
Рисунок 4 – ISE моделирование мультиплексора из примера 1

Пример 2. Используйте оператор “with/select” для описания приоритетного шифратора 4-к-2 с таблицей истинности, показанной ниже:

Таблица истинности приоритетного шифратора
ВходыВыходы
x(3)x(2)x(1)x(0)y(1)y(0)v
1не важенне важенне важен111
01не важенне важен101
001не важен011
0001001
0000000

Для описания приведенной выше таблицы истинности может быть использован следующий VHDL код:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity prio_encoder1 is
    Port ( x : in  STD_LOGIC_Vector(3 downto 0);
           y : out  STD_LOGIC_Vector(1 downto 0);
           v : out  STD_LOGIC);
end prio_encoder1;

architecture Behavioral of prio_encoder1 is

begin
    with x select
        y <= "11" when "1000" | "1001" | "1010" | "1011" | "1100" | "1101" | "1110" | "1111",
             "10" when "0100" | "0101" | "0110" | "0111",
             "01" when "0010" | "0011",
             "00" when others;
        v <= ( x(3) or x(2) or x(1) or x(0) );

end Behavioral;

Результаты ISE моделирования показаны на рисунке 5.

Рисунок 5 – ISE моделирование приоритетного шифратора из примера 2
Рисунок 5 – ISE моделирование приоритетного шифратора из примера 2

Присваивание сигнала по условию или оператор "when/else"

Оператор “when/else” – это еще один способ описать параллельные присваивания сигналов, подобные тем, что были приведены в примерах 1 и 2. Поскольку синтаксис этого типа присваивания сигнала довольно нагляден, давайте сначала рассмотрим VHDL код для одноразрядного мультиплексора 4-к-1, используя оператор “when/else”, а затем обсудим некоторые детали.

Пример 3. Используйте оператор “when/else” для описания одноразрядного мультиплексора 4-к-1. Предположим, что необходимо выбирать входы a, b, c и d. А двухбитовый сигнал sel используется для выбора нужного входа и его присваивания выходу out1.

Код будет следующим:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity Mux2 is
    Port ( a : in  STD_LOGIC;
           b : in  STD_LOGIC;
           c : in  STD_LOGIC;
           d : in  STD_LOGIC;
           sel : in  STD_LOGIC_VECTOR (1 downto 0);
           out1 : out  STD_LOGIC);
end Mux2;

architecture Behavioral of Mux2 is

begin
    out1 <= a when sel="00" else
            b when sel="01" else
            c when sel="10" else
            d;

end Behavioral;

В данном случае выражения после "when" последовательно оцениваются до тех пор, пока не будет найдено истинное выражение. Затем будет выполнено присваивание, соответствующее этому истинному выражению. Если ни одно из этих выражений не является истинным, будет выполнено последнее присваивание. В общем случае синтаксис оператора “when/else” будет следующим:

output_signal <= value_1    when    expression_1 else
                 value_2    when    expression_2 else
                 ...
                 value_n;

Следует подчеркнуть, что выражения после “when” оцениваются последовательно. В результате выражения, приведенные ранее, имеют более высокий приоритет по сравнению с последующими. Учитывая это, мы можем получить наглядную диаграмму этого присваивания, показанную на рисунке 6. Этот рисунок иллюстрирует присваивание сигнала по условию с тремя условиями “when”.

Рисунок 6 – Наглядная реализация оператора “when/else” с тремя условиями “when”
Рисунок 6 – Наглядная реализация оператора “when/else” с тремя условиями “when

Давайте рассмотрим основные особенности присваивания сигнала с помощью выбора варианта и присваивания сигнала по условию.

Присваивания: “with/select” против “when/else

Как упоминалось выше, варианты присваивания “with/select” должны быть взаимоисключающими, т.е. один вариант не может использоваться более одного раза. Более того, все возможные значения управляющего выражения control_expression должны быть включены в набор вариантов. В то время как присваивание “with/select” имеет общее управляющее выражение, присваивание “when/else” может работать с выражениями с разными аргументами. Например, рассмотрим следующие строки кода

out1 <= ‘0’ when reset1=’0’ else
         d  when clk=’1’;

В этом случае выражения оценивают два разных сигнала, то есть reset1 и clk.

Для присваивания “when/else” мы можем включать (а можем и не включать) все возможные значения выражений, которые должны быть оценены. Например, мультиплексор из примера 3 охватывает все возможные значения sel; однако приведенный выше код этого не делает. Приведенный выше код предполагает, что out1 должен сохранять свое предыдущее значение, если ни одно из выражений не является истинным. Это приводит к предположению о запирании в синтезированной схеме.

Другое важное различие между присваиваниями “with/select” и “when/else” можно увидеть, сравнив наглядную реализацию этих двух операторов. Приоритетная сеть на рисунке 6 включает в себя каскад из нескольких логических элементов. Однако присваивание “with/select” позволяет избежать этой цепочечной структуры и имеет сбалансированную структуру. В результате теоретически оператор “with/select” может иметь лучшую производительность с точки зрения задержки и пространства.

На практике мы обычно не видим этого различия потому, что многие пакеты программного обеспечения для синтеза, такие как Xilinx XST, стараются не выводить логику с приоритетным шифрованием. Хотя мы можем использовать в XST ограничение PRIORITY_EXTRACT для принудительного вывода приоритетного шифрования, Xilinx настоятельно предлагает использовать это ограничение по принципу «сигнал за сигналом»; в противном случае это ограничение может привести нас к неоптимальным результатам.

Резюме

  • Параллельные операторы выполняются одновременно, и нет никакого значения для порядка следования этих операторов. Этот тип кода сильно отличается от того, что мы узнали в базовом компьютерном программировании, где строки выполняются одна за другой.
  • Присваивание сигнала с помощью выбора варианта или присваивание “with/select” позволяет нам реализовать функционал мультиплексора.
  • Варианты присваивания “with/select” должны быть взаимоисключающими, т.е. один вариант не может использоваться более одного раза. Более того, все возможные значения управляющего выражения control_expression должны быть включены в набор вариантов.
  • Для оператора “when/else”, выражения после “when” оцениваются последовательно. В результате выражения, приведенные ранее, имеют более высокий приоритет по сравнению с последующими.
  • Одно важное различие между присваиваниями “with/select” и “when/else” можно увидеть, сравнив наглядную реализацию этих двух операторов. Оператор “when/else” имеет приоритетную сеть; однако присваивание “with/select” позволяет избежать этой цепочечной структуры и имеет сбалансированную структуру.

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.


Сообщить об ошибке