Школа схемотехнического
проектирования устройств обработки сигналов
„ _ Память человека есть лист белой бумаги:
Занятие 7. - '
иногда напишется хорошо, а иногда дурно.
Реализация вычислительных устройств на ПЛИС.
К. Прутков
В этом занятии мы рассмотрим некоторые примеры реализации цифровых устройств на ПЛИС фирмы Altera с использованием языков описания аппаратуры. Языки описания аппаратуры (Hardware Description Language) являются формальной записью, которая может быть использована на всех этапах разработки цифровых электронных систем. Это возможно вследствие того, что язык легко воспринимается как машиной, так и человеком. Он может использоваться на этапах проектирования, верификации, синтеза и тестирования аппаратуры, так же как и для передачи данных о проекте, модификации и сопровождения.
Владимир Стешенко
Реализация генератора ПСП на ПЛИС
В качестве простого примера реализации цифрового устройства на ПЛИС рассмотрим пример генератора псевдослучайной последовательности (ПСП). Генератор формирования М-последовательностей был написан в виде параметризованной макрофункции, описывающей устройство, упрощенная структура которого показана на рис. 1. Параметрами макрофункции являются длина характеристического многочлена и число, описывающее начальные состояния триггеров.
Ниже приводится листинг описания этой функции на языке описания аппаратуры AHDL [1].
% M - вход многочлена; %
% GENA - разрешение генерации (default=GND); %
% CLK - тактовый вход; %
% LOAD - вход предустановки (default=GND); %
% Выходы: %
% OUT - выход М-последовательности %
% %
% Параметры: %
% M_WIDTH - длина полинома; %
% M_BEGIN - начальное состояние %
% (default=»100000..00»); %
% %
% Версия 1.0 %
%===
INCLUDE «lpm_xor.inc»; INCLUDE «lpm_constant.inc»; PARAMETERS
(
M_WIDTH, M_BEGIN = 0
Функция M_GENERATE:
% Функция M_GENERATE %
% Генерирует М-последовательность, заданную %
% характеристическим многочленом М %
% % % Входы: %
Рис. 1
SUBDESIGN m_generate
(
M[M_WIDTH-1..0]
CLK
GENA
LOAD
OUT
dffs[M_WIDTH-2..0] shift_node[M_WIDTH-2..0] xor_node[M_WIDTH-2..0] shiftin, shiftout
INPUT = GND; INPUT;
INPUT = GND; INPUT = GND; OUTPUT;
DFFE; - триггеры регистра сдвига NODE;
NODE;
NODE; - вход и выход регистра
IF (USED(M_BEGIN)) GENERATE ac : lpm_constant
WITH (LPM_WIDTH = M_WIDTH, LPM_CVAL-
UE = M_BEGIN);
END GENERATE;
BEGIN
ASSERT (M_WIDTH>0)
REPORT «Значение параметра M_WIDTH должно быть больше
нуля»
SEVERITY ERROR;
% -
----------общие выводы триггеров -
dffs[].ena = GENA; dffs[].dk = CLK;
-----------асинхронные операции -IF (USED(M_BEGIN)) GENERATE
-- %
%
%
dffs[].dm = !load # ac.result[M_WIDTH-2..0];
% установка начального состояния %
dffs[].prn = !load # !ac.result[M_WIDTH-2..0];
% триггеров, заданное M_BEGIN %
ELSE GENERATE dffs[M_WIDTH-3..0].dm = !load;
% установка начального состояния %
dffs[M_WIDTH-2].prn = !load;
% триггеров «10000..00 %
END GENERATE;
%----------------обратные связи-----------------%
xor_node[] = dffs[] & M[M_WIDTH-2..0]; shiftin = lpm_xor(xor_node[])
WITH (LPM_SIZE = M_WIDTH-1, LPM_WIDTH=1);
%----------------операции сдвига----------------%
shift_node[] = (shiftin, dffs[M_WIDTH-2..1]); shiftout = dffs[0];
%----------------синхронные операции-----------%
dffs[].d = !load & shift_node[];
%----------------подключим выход----------------%
OUT = shiftout;
END;
Данная функция имеет следующие входы и выходы:
М — шина (группа выводов) с размером M_WIDTH. На этот вход подаются коэффициенты характеристического многочлена; CLK — вход тактового сигнала;
GENA — вход разрешения генерации. При GENA= «0» генерация М-последовательности запрещена;
LOAD — вход предустановки. При LOAD= «1» триггеры регистра сдвига устанавливаются в состояние, определяемое параметром M_BEGIN;
OUT — выход М-последовательности.
Для включения данной функции в другие схемы были также созданы включаемый файл, содержащий описание, и графический символ-элемент (см. рис.2).
Файл «M_GENERATE.INC»:
FUNCTION m_generate (m[(m_width) — (1)..0], clk, gena, load) WITH (M_WIDTH, M_BEGIN)
RETURNS (out);
Для моделирования работы генератора в графическом редакторе пакета МАХ+РЬШ II [1, 4] была создана тестовая схема, показанная на рис. 3. Результаты моделирования приведены на рис. 4 (на вход одного генератора подан характеристический многочлен М1 = 11001, на вход другого — М2 = 10010000001).
Реализация цифровых полиноминальных фильтров
Одним из важных классов нелинейных цифровых устройств являются так называемые полиноминальные цифровые фильтры [5, 6]. В последние годы их все чаще применяют в системах обработки изображений.
В общем случае цифровой полиномиальный фильтр размерности г и порядка М, оп-
ределяется конечным дискретным рядом Вольтерра (функциональным полиномом) вида
яп)=Ао+Х->’"(іі)=Ао+ХХ-"Хм,,і ”.)Пі(|і,-,,<),
—1 _1 п, п. ы
где Ьш(п1, ..., Пщ) — многомерные импульсные характеристики (ядра) фильтра, зависящие от векторных аргументов п = [пі1 ... піг]. Фильтры данного вида часто называются также фильтрами Вольтерра.
Непосредственная реализация цифровых полиномиальных фильтров связана с вычис-
лением произведения векторов. Вычислительные затраты могут быть сокращены за счет использования свойства симметрии изотропных фильтров.
Таким образом, путем последовательного применения процедуры декомпозиции полиномиальный фильтр произвольного порядка может быть представлен в виде параллельной структуры, состоящей из линейных фильтров. Операция линейной фильтрации связана с вычислением двухмерной свертки и допускает высокоэффективную реализацию в виде структур систолического типа, матричных и волновых процессоров. Процесс двух-
Х2,Хі,Х0 „ h0 —► hi ► Ьг
—► ► —► hi A
х5,х^ ^ h3 —► —► ► ► ь, —► У, УтН ——►
х8,х7,х6 kfi*
ьл —► h7 ► h8 —►
Рис. 5. Систолическая реализация двухмерной линейной свертки
:M_WIDTH=: :m_begin=:
m. .generate
H X— H OUT -kout
GENA X GENA
LOADX— LOAD
CLK X— CLK
Рис. 2
мерной свертки изображения с маской N X N в свою очередь, можно свести к вычислению N одномерных сверток, что в конечном итоге позволяет выполнять полиномиальную фильтрацию изображений путем параллельного вычисления обычных одномерных сверток. На рис. 5 представлен один из наиболее простых вариантов реализации двухмерной свертки изображения с маской 3 X 3 в виде систолической структуры, состоящей из 9 идентичных процессорных элементов.
Задача двумерной свертки формулируется следующим образом: даны веса для у=1,2...,к, так что к X к — размер ядра, и входное изображение х^ для у=1,2...,п. Требуется вычислить элементы изображения у^ для у=1,2...,п, определяемые в виде
* к
У и =11И'м^*-1,)+Н'
1=\ А=1
При к=3 двумерная свертка выполняется в виде трех последовательных одномерных сверток (использующих в качестве весов одну и ту же последовательность (■11, ■21,
...,■33)):
1. Вычисление (у11,у12,у13,у14,...) при использовании (х11, х21,х31,х12,х22,х32,х13,х23,х33,... ) в
качестве входной последовательности.
2. Вычисление (у21,у22,у23,у24,...) при использовании (х21,х31,х41,х22,х32,х42,х23,х33,х43,... ) в качестве входной последовательности.
3. Вычисление (у31,у32,у33,у34,...) при использовании (х31,х41,х51,х32,х42,х52,х33,х43,х53,... ) в качестве входной последовательности. Каждую из этих сверток можно выполнить
на одномерном систолическом массиве из девяти ячеек. Отметим, что в любом из этих одномерных массивов ячейка занята вычислениями у^ только 1/3 времени.
Для восстановления ячейка с двумя потоками должна быть 8-разрядной для входных данных и иметь 12 бит для представления весов. Для сетки 32 X 32 пикселей в каждом блоке памяти требуется хранить 1024 различных весовых коэффициента и иметь 10-разрядную адресную шину для указания положения каждой точки. 12-разрядный умножитель и 24разрядный сумматор для получения промежуточных результатов вполне обеспечивают сохранение требуемой точности в процессе вычислений.
Для выполнения многомерной свертки требуется единственная модификация базовой ячейки с двумя потоками — добавление требуемого числа систолических входных потоков и соответствующее увеличение размера мультиплексора для выбора данных.
При решении задач фильтрации изображения с целью удаления шумов, восстановления изображения или улучшения его качества приходится иметь дело с данными, характеризующимися широким динамическим диапазоном. Поэтому в качестве формата данных необходимо использовать числа с плавающей запятой.
Для реализации систолических структур полиноминальных фильтров наиболее пригодны ПЛИС семейства БЬЕХШК, содержа-
щие встроенные блоки памяти (EAB — embedded array blocks), предназначенные для эффективной реализации функций памяти и сложных арифметических и логических устройств (умножителей, конечных автоматов, цифровых фильтров и т. д.). Один такой блок имеет емкость 2 килобита и позволяет сформировать память с организацией 2048 X 1, 1024 X 2, 512 X 4 или 256 X 8, работающую с циклом 12-14 нс. Использование ВБП значительно повышает эффективность и быстродействие создания сложных логических устройств, например, умножителей. Так, каждый ВБП может выполнять функции умножителя 4 X 4, 5 X 3 или 6 X 2.
На рис. 6 приведена реализация структуры на ПЛИС, а на рис. 7 — результаты моделирования систолической структуры в среде MAX PLUS II.
Примеры описания цифровых схем на VHDL
Наиболее универсальным и распространенным языком описания аппаратуры является VHDL. На этом языке возможно как поведенческое, так структурное и потоковое описание цифровых схем.
Язык VHDL используется во многих системах для моделирования цифровых схем, про-
Рис. б. Реализация систолической структуры на ПЛИС
wnrV\*.K\J\24lM«»v - icJ Wnw4iirif> fcdi»m|
Him* 1 1 V|hM 105 On. St
I іЛ|Т fl| nnranm OOOOOQ1B '
1Ш hT n| rmnmnii nQQQQOl1 Ї
riPKTF П] prrmouo amono •
U(7 О] FOnwn ammo
gp§ мр О] В 00000001 irrrrmi
П] nnvmtnn OXDICD
ip г4ф ft] Rmvmn QDDDBTl ;
пі fiononoom лапті
^*1? ПІ p000000ro amnio
W t‘P Q] воікююі nnanoi
lii_L
iT
»<Vc||amw-pi.. n <u
Рис. 7. Результаты моделирования систолической структуры на ПЛИС
QB їм?
ектирования программируемых логических интегральных микросхем, базовых матричных кристаллов, заказных интегральных микросхем.
Рассмотрим некоторые примеры описания цифровых схем на VHDL.
Первый — описание цифрового автомата преобразователя параллельного кода в последовательный. Преобразователь кода представляет собой устройство, на вход которого подается n-битное число в параллельном коде «d», сигнал загрузки «load» и синхроимпульсы «clk». По сигналу загрузки происходит запись входного слова во внутренний регистр и последовательная выдача в течение n тактов этого входного слова в последовательном коде на выходе «о» синхроимпульсами «oclk». После окончания преобразования на выходе «e» появляется высокий уровень сигнала в течение одного такта. Такого рода преобразователи кода часто используются для управления синтезаторами частот 1104ПЛ1 и им подобными.
Описание этого устройства на языке VHDL приведено ниже:
library ieee;
use ieee.std_logic_1164.all; entity Serial is port (
clk : in STD_LOGIC;
load : in STD_LOGIC;
reset: in STD_LOGIC;
d : in STD_LOGIC_vector (3 downto 0);
oclk : out STD_LOGIC;
o : out STD_LOGIC; e : out STD_LOGIC );
end;
architecture behavioral of Serial is type t1 is range 0 to 4;
signal s : STD_LOGIC_vector (2 downto 0);
signal i : t1; begin
process (clk)
begin
if reset = '1' then
i <= 0;
else
if (clk'event and clk=T) then
if (i = 0 and load = '1') then
s(2 downto 0) <= d(3 downto 1);
0 <= d(0);
1 <= 4;
end if;
if (i > 1) then
0 <= s(0);
s(1 downto 0) <= s(2 downto 1);
1 <= i — 1;
end if;
if (i = 1) then
e <= '1';
i <= 0;
else
e <= '0';
end if; end if;
end if; if i>0 then
oclk <= not clk;
else
oclk <= '0';
end if; end process; end behavioral;
По переднему фронту синхроимпульса «clk» при высоком уровне на входе загрузки происходит загрузка трех старших бит входного слова d[3.. 1 ] во временный регистр s[2..0]. Младший бит входного слова d[0] подается на выход «o». На выходе «oclk» появляются синхроимпульсы. На сигнале «i» собран внутренний счетчик, выдающий сигнал окончания преобразования «e». При поступлении
последующих синхроимпульсов происходит выдача на выход «o» остальных бит входного слова, хранящихся в регистре s[2..0].
Моделирование этого устройства было проведено в системе проектирования OrCAD 9.0.
Для тестирования схемы использовался тест:
library ieee;
use ieee.std_logic_1164.aH;
use ieee.numeric_std.all;
entity test_serial is end test_serial;
architecture testbench of test_serial is
component serial
port (
clk : in std_logic; load : in std_logic; reset : in std_logic; d : in std_logic_vector(3 downto 0); oclk : out std_logic; o : out std_logic; e : out std_logic );
end component;
signal clk : std_logic;
signal load : std_logic := '0';
signal reset : std_logic;
signal d : std_logic_vector(3 downto 0);
signal oclk : std_logic;
signal o : std_logic;
signal e : std_logic;
begin
process begin
for i in 0 to 50 loop
clk <= '0'; wait for 5 ns; clk <= '1'; wait for 5 ns;
end loop;
end process;
process begin
reset <= '1'; wait for 10 ns;
reset <= '0' ;
load <= '1';
d <= «1010»; wait for 10 ns;
load <= '0';
d <= «0000»; wait for 500 ns;
end process; dut : serial port map ( clk => clk, load => load, reset => reset, d => d, oclk => oclk, o => o, e => e );
end testbench;
Результаты моделирования представлены на рис. 8.
В качестве примера описания устройства ЦОС рассмотрим цифровой КИХ-фильтр. Работа цифрового КИХ-фильтра описывается разностным уравнением
yn=A0Xn + A1Xn-1 + A2Xn-2 + •••,
где yn — реакция системы в момент времени n, xn — входное воздействие Ai — Весовой коэффициент i-й входной переменной.
На VHDL описание фильтра имеет вид:
library ieee;
use ieee.std_logic_1164.aH; use ieee.std_logic_arith.all; entity f is port (
din: in std_logic_vector(7 downto 0); sout: out std_logic_vector(15 downto 0); r: in std_logic; c: in std_logic );
end f;
architecture behavior of f is constant h00 : std_logic_vector(7 downto 0) := constant h01 : std_logic_vector(7 downto 0) := constant h02 : std_logic_vector(7 downto 0) := constant h03 : std_logic_vector(7 downto 0) := constant h04 : std_logic_vector(7 downto 0) := constant h05 : std_logic_vector(7 downto 0) := constant h06 : std_logic_vector(7 downto 0) := constant h07 : std_logic_vector(7 downto 0) := constant h08 : std_logic_vector(7 downto 0) := constant h09 : std_logic_vector(7 downto 0) := constant h10 : std_logic_vector(7 downto 0) := constant h11 : std_logic_vector(7 downto 0) := constant h12 : std_logic_vector(7 downto 0) := constant h13 : std_logic_vector(7 downto 0) := constant h14 : std_logic_vector(7 downto 0) := constant h15 : std_logic_vector(7 downto 0) := constant h16 : std_logic_vector(7 downto 0) := constant h17 : std_logic_vector(7 downto 0) := constant h18 : std_logic_vector(7 downto 0) := constant h19 : std_logic_vector(7 downto 0) := constant h20 : std_logic_vector(7 downto 0) := constant h21 : std_logic_vector(7 downto 0) := constant h22 : std_logic_vector(7 downto 0) := constant h23 : std_logic_vector(7 downto 0) := signal x00, x01, x02, x03, x04, x05, x06, x07,
x08, x09, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23 : std_logic_vector(7 downto 0);
00000000»;
00000001»;
00000100»;
00001111»
00100100»;
01000010»;
01100100»;
01111100»;
01111111»;
01101010»;
01000010»;
00010011»;
11101100»;
11010110»;
11010101»;
11100011»;
11110111»
00001010»;
00010100»;
00010011»;
00001100»;
00000010»;
11111000»
11110101»;
signal mOO, mO1, mO2, mO3, mO4, mO5, mO6, mO7,
mO8, mO9, m1O, m11, m12, m13, m14, m15,
m16, m17, m18, m19, m2O, m21,
m22, m23 : std_logic_vector(l5 downto 0);
begin
mOO <= mO1 <= mO2 <= mO3 <= mO4 <= mO5 <= mO6 <= mO7 <= mO8 <= mO9 <= m1O <= m11 <= m12 <= m13 <= m14 <= m15 <= m16 <= m17 <= m18 <= m19 <= m2O <= m21 <= m22 <= m23 <= sout <=
signed(xOO
signed(xO1
signed(xO2
signed(xO3
signed(xO4
signed(xO5
signed(xO6
signed(xO7
signed(xO8
signed(xO9
signed(x1O
signed(x11
signed(x12
signed(x13
signed(x14
signed(x15
signed(x16
signed(x17
signed(x18
signed(x19
signed(x2O
signed(x21
signed(x22
signed(x23
signed(hOO
signed(hO1
signed(hO2
signed(hO3
signed(hO4
signed(hO5
signed(hO6
signed(hO7
signed(hO8
signed(hO9
signed(h1O
signed(hll
signed(h12
signed(h13
signed(h14
signed(h15
signed(h16
signed(h17
signed(h18
signed(h19
signed(h2O
signed(h21
signed(h22
signed(h23
signed(mOO)+signed(mO
+signed(mO4)+signed
+signed(mO8)+signed
+signed(m12)+signed
+signed(m16)+signed
process(c,r)
x00 <= others => O')
xOl <= others => O')
x02 <= (others => O')
x03 <= (others => O')
x04 <= (others => O')
x05 <= (others => O')
x06 <= (others => O')
x07 <= (others => O')
x08 <= (others => O')
x09 <= (others => O')
xlO <= (others => O')
xll <= (others => O')
xl2 <= (others => O')
xl3 <= (others => O')
xl4 <= (others => O')
xl5 <= (others => O')
xl6 <= (others => O')
xl7 <= (others => O')
xl8 <= (others => O')
xl9 <= (others => O')
x20 <= (others => O')
x2l <= (others => O')
x22 <= (others => O')
x23 <= (others => O')
elsif (c'event and c='l' then
x00(7 downto 0) <= din(7 downto 0); xO1(7 downto O) <= xOO(7 downto O x02(7 downto 0) <= x0l(7 downto 0); xO3(7 downto O) <= xO2(7 downto O x04(7 downto 0) <= x03(7 downto 0); xO5(7 downto O) <= xO4(7 downto O x06(7 downto 0) <= x05(7 downto 0); xO7(7 downto O) <= xO6(7 downto O x08(7 downto 0) <= x07(7 downto 0); x09(7 downto 0) <= x08(7 downto 0
xl0(7 downto 0) <= xl 1 (7 downto 0) • xl2(7 downto 0) <= xl3(7 downto 0) • xl4(7 downto 0) <= xl5(7 downto 0) • xl6(7 downto 0) <= xl7(7 downto 0) • xl8(7 downto 0) <= xl9(7 downto 0) • x20(7 downto 0) <= x2l(7 downto 0) • x22(7 downto 0) <= x23(7 downto 0) •
x09(7 downto 0);
:= xl0(7 downto 0); xll(7 downto 0);
:= xl2(7 downto 0); xl3(7 downto 0);
:= xl4(7 downto 0); xl5(7 downto 0);
:= xl6(7 downto 0); xl7(7 downto 0);
:= xl8(7 downto 0); xl9(7 downto 0);
:= x20(7 downto 0); x2l(7 downto 0);
:= x22(7 downto 0);
+signed(m02)+signed(m03)
m05)+signed(m06)+signed(m07)
m09)+signed(ml0)+signed(mll)
ml3)+signed(ml4)+signed(ml5)
ml7)+signed(ml8)+signed(ml9)
+signed(m20)+signed(m2l)+signed(m22)+signed(m23));
r)
begin
if r='l' then
end if; end process; end behavior;
Входные данные считываются с входа din[7..0] в дополнительном коде по переднему фронту синхросигнала «с»
На сигналах x0 + x23 построен сдвиговый регистр, обеспечивающий задержку данных на 24 такта. Сигналы с регистров умножаются на весовые коэффициенты h0 + h23 и суммируются.
Для тестирования схемы использован тест:
-- Test bench shell library ieee;
use ieee.std_logic_1164.all; entity test_f is end test_f; architecture testbench of test_f is component f port (
din : in std_logic_vector(7 downto 0); sout : out std_logic_vector(15 downto 0); r : in std_logic; c : in std_logic
end component; gnal din : std_logic_vector(7 downto 0); gnal sout : std_logic_vector(15 downto 0); gnal r : std_logic; gnal c : std_logic; begin
process begin
for i in 0 to 50 loop
c <= '0'; wait for 5 ns; c <= '1'; wait for 5 ns;
end loop;
end process; process begin
r <= '1'; wait for 10 ns; r <= '0' ;
din <= «00000001»; wait for 10 ns; din <= «00000000»; wait for 500 ns;
end process; dut : f port map ( din => din, sout => sout, r => r, c => c );
end testbench;
Тест моделирует подачу на цифровой фильтр аналога 8-функции. На выходе фильтра — его импульсная характеристика.
Результаты моделирования представлены на рис. 9.
В следующем занятии мы продолжим рассмотрение реализации устройств обработки сигналов на ПЛИС. Н
Литература
1. Стешенко В. ПЛИС фирмы ALTERA: проектирование устройств обработки сигналов. М.: Додека, 2000 .
2. Угрюмов Е. П. Цифровая схемотехника. СПб.: БХВ — Санкт-Петербург, 2000.
3. Стешенко В. Б. Школа схемотехнического проектирования устройств обработки сигналов // Компоненты и технологии, № 3-6, 2000 г.
4. Стешенко В. Школа разработки аппаратуры цифровой обработки сигналов на ПЛИС // Chip News, 1999, № 8-10, 2000, № 1, 3-5.
5. Щербаков М. А., Стешенко В. Б., Губанов Д. А. Цифровая полиноминальная фильтрация: алгоритмы и реализация на ПЛИС // Инженерная микроэлектроника, № 1(3), март 1999. С.12-17.
6. Щербаков М. А., Стешенко В. Б., Губанов Д. А. Цифровая полиноминальная фильтрация в реальном масштабе времени: алгоритмы и пути реализации на ПЛИС // Цифровая обработка сигналов, № 1, 2000. С. 19-26.