Разработка светодиодных систем отображения информации

Системы передачи по волоконно-оптическим линиям связи

 

Светодиодные экраны

Бегущие строки

НПП “Цифровые решения”

Контрактная разработка радиоэлектронных устройств

Цифровая обработка сигналов и изображений

Поставка высокотехнологичных изделий

 

ПЛИС фирмы Altera: проектирование устройств обработки сигналов.

Стешенко В.Б.

 

Глава 3. Язык описания аппаратуры AHDL

3.3. Комбинационная логика

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

3.3.1. Реализация булевых выражений и уравнений

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

В качестве примера приведен файл boole1.tdf, в котором даны два простых булевых выражения, представляющих два логических элемента.

SUBDESIGN boole1

(

a0, a1, b : INPUT;

out1, out2 : OUTPUT;

)

BEGIN

out1 = a1 & !a0;

out2 = out1 # b;

END;

Здесь выход out1 получается в результате логической операции И, примененной ко входу а1 и инвертированному входу а0, а выход out2 получается в результате применения логической операции ИЛИ к выходу out1 и входу b. Поскольку эти уравнения обрабатываются одновременно, последовательность их следования в файле не важна.

3.3.2. Объявление NODE (узел)

Узел, который объявляется в секции переменных VARIABLE в объявлении NODE, можно использовать для хранения промежуточных выражений. Это полезно делать, если булево выражение повторяется несколько раз и его целесообразно заменить именем узла. Приведенный выше файл boole1.tdf можно переписать по-другому:

SUBDESIGN boole2

(

a0, a1, b : INPUT;

out : OUTPUT;

)

VARIABLE

a_equals_2 : NODE;

BEGIN

a_equals_2 = a1 & !a0;

out = a_equals_2 # b;

END;

Здесь объявляется узел a_equals_2 и ему присваивается значение выражения a1 & !a0. Использование узлов помогает экономить ресурсы устройств, если узел используется в нескольких выражениях.

3.3.3. Определение групп

Группа может включать в себя до 256 элементов (бит), рассматривается как совокупность узлов и участвует в различных действиях как единое целое. В булевых уравнениях группа может быть приравнена булевому выражению, другой группе, одному узлу, VCC, GND,1 или 0. В каждом случае значения группы разные.

Если группа определена, для краткого указания всего диапазона ставят две квадратные скобки [ ]. Например, группу а[4..1] можно кратко записать как а[ ].

Примеры определения групп:

При присваивании двух групп обе должны иметь одинаковое число бит. В приводимом ниже примере каждый бит первой группы соединяется с соответствующим битом второй групп, а именно, d2 соединяется с q8, d1 с q7 и d0 с q6:

d[2..0] = q[8..6]

При присваивании группы одному узлу все биты группы присоединяются к узлу. В приводимом ниже примере d1, d2 и d0 присоединяются все вместе к n:

d[2..0] = n

При присваивании группы значению VCC или GND все биты группы присоединяются к этому значению. В приводимом ниже примере d1, d2 и d0 присоединяются все вместе к VCC:

d[2..0] = VCC

При присваивании группы к 1 младший бит группы присоединяется к VCC, а все другие биты - к значению GND. В приводимом ниже примере только d0 присоединяется к VCC, значение 1 расширяется до представления B”001”.

d[2..0] = 1

3.3.4. Реализация условной логики

Условная логика делает выбор между режимами в зависимости от логических входов. Для реализации условной логики используются операторы IF или CASE:

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

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

3.3.4.1. Логика оператора IF

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

SUBDESIGN priority

(

low, middle, high : INPUT;

highest_level[1..0] : OUTPUT;

)

BEGIN

IF high THEN

highest_level[] = 3;

ELSIF middle THEN

highest_level[] = 2;

ELSIF low THEN

highest_level[] = 1;

ELSE

highest_level[] = 0;

END IF;

END;

Здесь оцениваются входы low, middle и high, чтобы определить, запущены ли они VCC. На выходе получится код, соответствующий приоритету того входа, который был запущен VCC. Если ни один вход не запущен, значение кода станет 0.

3.3.4.2. Логика оператора CASE

В качестве примера рассмотрим файл decoder.tdf, реализующий функции Дешифратора, преобразующего код из двухразрядного в четырехразрядный. В результате его работы два двухразрядных двоичных входа преобразуются в один “горячий код”, который так называется потому, что четыре его допустимых значения содержат по одной единице: 0001, 0010, 0100, 1000.

SUBDESIGN decoder

(

code[1..0] : INPUT;

out[3..0] : OUTPUT;

)

BEGIN

CASE code[] IS

WHEN 0 => out[] = B"0001";

WHEN 1 => out[] = B"0010";

WHEN 2 => out[] = B"0100";

WHEN 3 => out[] = B"1000";

END CASE;

END;

Здесь группа входа code [1..2] может принимать значения 0, 1, 2, 3. В зависимости от реального кода активизируется соответствующая ветвь оператора и только она одна в данный момент времени. Например, если на входе code [] равен 1, на выходе out устанавливается значение В”0010”.

3.3.4.3. Сравнение операторов IF и CASE

Операторы IF и CASE похожи. Иногда использование любого из них приводит к одним и тем же результатам:

If Then

Case

 

IF a[] == 0 THEN

y = c & d;

ELSIF a[] == 1 THEN

y = e & f;

ELSIF a[] == 2 THEN

y = g & h;

ELSIF a[] == 3 THEN

y = i;

ELSE

y = GND;

END IF;

 

 

CASE a[] IS

WHEN 0 =>

y = c & d;

WHEN 1 =>

y = e & f;

WHEN 2 =>

y = g & h;

WHEN 3 =>

y = i;

WHEN OTHERS =>

y = GND;

END CASE;

 

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

  • В операторе IF можно использовать любое булево выражение. Каждое выражение, записываемое в предложении, следующем за IF или ELSEIF, может не быть связанным с другими выражениями в операторе. В операторе CASE одно единственное выражение сравнивается с проверяемым значением.
  • В результате интерпретации оператора IF может быть сгенерирована логика, слишком сложная для компилятора системы MAX+PLUS II. В приведенном ниже примере показано, как компилятор интерпретирует оператор IF. Если а и b - сложные выражения, то инверсия каждого из них даст еще более сложное выражение.

IF a THEN IF a THEN

c = d; c = d;

END IF;

ELSIF b THEN IF !a & b THEN

c = e; c = e;

END IF;

ELSE IF !a & !b THEN

c = f; c = f;

END IF; END IF;

3.3.5. Описание дешифраторов

Дешифратор содержит комбинаторную логику, которая преобразует входные схемы в выходные значения или задает выходные значения для входных схем. Для создания дешифратора в языке AHDL используется объявление таблицы истинности TABLE.

Ниже приведен файл 7segment.tdf, представляющий собой Дешифратор, который задает логику схемы светодиодов. Светодиоды светятся на семисегментном дисплее для индикации шестнадцатеричной цифры (от 0 до 9 и буквы от A до F).

% -a- %

% f| |b %

% -g- %

% e| |c %

% -d- %

% %

% 0 1 2 3 4 5 6 7 8 9 A b C d E F %

% %

SUBDESIGN 7segment

(

i[3..0] : INPUT;

a, b, c, d, e, f, g : OUTPUT;

)

BEGIN

TABLE

i[3..0] => a, b, c, d, e, f, g;

H"0" => 1, 1, 1, 1, 1, 1, 0;

H"1" => 0, 1, 1, 0, 0, 0, 0;

H"2" => 1, 1, 0, 1, 1, 0, 1;

H"3" => 1, 1, 1, 1, 0, 0, 1;

H"4" => 0, 1, 1, 0, 0, 1, 1;

H"5" => 1, 0, 1, 1, 0, 1, 1;

H"6" => 1, 0, 1, 1, 1, 1, 1;

H"7" => 1, 1, 1, 0, 0, 0, 0;

H"8" => 1, 1, 1, 1, 1, 1, 1;

H"9" => 1, 1, 1, 1, 0, 1, 1;

H"A" => 1, 1, 1, 0, 1, 1, 1;

H"B" => 0, 0, 1, 1, 1, 1, 1;

H"C" => 1, 0, 0, 1, 1, 1, 0;

H"D" => 0, 1, 1, 1, 1, 0, 1;

H"E" => 1, 0, 0, 1, 1, 1, 1;

H"F" => 1, 0, 0, 0, 1, 1, 1;

END TABLE;

END;

В этом примере все возможные шестнадцатиричные цифры (i[3..0]) и соответствующие состояния светодиодов (a, b, c, d, e, f, g), которые обеспечивают “начертание” цифры на дисплее. Изображение светодиодов на дисплее дано в виде комментария перед файлом.

Ниже приведен файл дешифратора адреса decode3.tdf для шестнадцатиразрядной микропроцессорной системы.

SUBDESIGN decode3

(

addr[15..0], m/io : INPUT;

rom, ram, print, sp[2..1] : OUTPUT;

)

BEGIN

TABLE

m/io, addr[15..0] => rom, ram, print, sp[];

1, B"00XXXXXXXXXXXXXX" => 1, 0, 0, B"00";

1, B"100XXXXXXXXXXXXX" => 0, 1, 0, B"00";

0, B"0000001010101110" => 0, 0, 1, B"00";

0, B"0000001011011110" => 0, 0, 0, B"01";

0, B"0000001101110000" => 0, 0, 0, B"10";

END TABLE;

END;

В данном примере существуют тысячи возможных вариантов входа (адреса), поэтому было бы непрактично сводить их все в таблицу. Вместо этого, можно пометить символом “Х” несущественные, не влияющие на выход, разряды. Например, выходной сигнал rom (ПЗУ) будет высоким для всех 16384 вариантов адреса addr[15..0], которые начинаются с 00. Поэтому вам нужно только указать общую для всех вариантов часть кода, т.е. 00, а в остальных разрядах кода поставить “Х”. Такой прием позволит сделать проект, требующий меньше устройств и ресурсов.

Приведенный ниже пример decode4.tdf показывает использование стандартной параметризируемой функции lpm_decode в задаче разработки дешифратора, аналогичной примеру decode1.tdf.

INCLUDE "lpm_decode.inc";

SUBDESIGN decode4

(

address[15..0] : INPUT;

chip_enable : OUTPUT;

)

BEGIN

chip_enable = lpm_decode(.data[]=address[])

WITH (LPM_width=16, LPM_DECODES=2^10)

RETURNS (.eq[H"0370"]);

END;

3.3.6. Использование для переменных значений по умолчанию

Можно определить значения по умолчанию для узла или группы, которые будут автоматически использоваться для них, если в файле их значения не будут заданы. Язык AHDL позволяет присваивать значение узлу или группе в файле неоднократно. Если при этом произойдет конфликт, система автоматически будет использовать значения по умолчанию. Если значения по умолчанию не были заданы, используется значение GND.

Объявление значений по умолчанию DEFAULTS можно использовать для задания переменных в таблице истинности, операторах IF и CASE.

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

Ниже приводится файл default1.tdf, в котором происходит оценка входов и выбор соответствующего ASCII кода.

SUBDESIGN default1

(

i[3..0] : INPUT;

ascii_code[7..0] : OUTPUT;

)

BEGIN

DEFAULTS

ascii_code[] = B"00111111";% ASCII question mark"?" % END DEFAULTS;

TABLE

i[3..0] => ascii_code[];

B"1000" => B"01100001"; % "a" %

B"0100" => B"01100010"; % "b" %

B"0010" => B"01100011"; % "c" %

B"0001" => B"01100100"; % "d" %

END TABLE;

END;

Если значение входа совпадает с одним из значений в левой части таблицы, код на выходе приобретает соответствующее значение ASCII кода в правой части таблицы. Если входное значение не совпадает ни с одним из (левых) табличных, выходу будет присвоено значение по умолчанию B”00111111” (вопросительный знак).

В приведенном ниже файле default2.tdf показано, как при многократном присваивании узлу разных значений возникает конфликт и как он разрешается средствами AHDL.

SUBDESIGN default2

(

a, b, c : INPUT;

select_a, select_b, select_c : INPUT;

wire_or, wire_and : OUTPUT;

)

BEGIN

DEFAULTS

wire_or = GND;

wire_and = VCC;

END DEFAULTS;

IF select_a THEN

wire_or = a;

wire_and = a;

END IF;

IF select_b THEN

wire_or = b;

wire_and = b;

END IF;

IF select_c THEN

wire_or = c;

wire_and = c;

END IF;

END;

В данном примере выход wire_or устанавливается равным a, b или с в зависимости от входных сигналов select_a, select_b и select_c. Если ни один из них не равен VCC, то выход wire_or принимает значение по умолчанию, равное GND.

Если более одного сигнала (select_a, select_b или select_c) равны VCC, то wire_or равно результату логической операции ИЛИ над соответствующими входными сигналами. Например, если select_a и select_b равны VCC, то wire_or равно a ИЛИ b.

С сигналом wire_and производятся аналогичные действия, но он становится равным VCC, когда входные сигналы select равны VCC, и равен логическому И от соответствующих входных сигналов, если более, чем один из них равен VCC.

3.3.7. Реализация логики с активным низким уровнем

Значение сигнала с низким активным уровнем равно GND. Сигналы с низким активным уровнем могут быть использованы для управления памятью, периферийными устройствами и микропроцессорными чипами.

Ниже приводится файл daisy.tdf, который представляет модуль арбитражной схемы для соединения гирляндой (daisy chain). Данный модуль делает запрос на доступ к шине для предыдущего (в гирлянде) модуля. Он получает запрос на доступ к шине от самого себя и от следующего (в цепочке) модуля. Доступ к шине предоставляется тому модулю, у которого приоритет выше.

SUBDESIGN daisy

(

/local_request : INPUT;

/local_grant : OUTPUT;

/request_in : INPUT; % from lower priority % /request_out : OUTPUT; % to higher priority % /grant_in : INPUT; % from higher priority % /grant_out : OUTPUT; % to lower priority %

)

BEGIN

DEFAULTS

/local_grant = VCC; % active-low output % /request_out = VCC; % signals should default % /grant_out = VCC; % to VCC %

END DEFAULTS;

IF /request_in == GND # /local_request == GND THEN

/request_out = GND;

END IF;

IF /grant_in == GND THEN

IF /local_request == GND THEN

/local_grant = GND;

ELSIF /request_in == GND THEN

/grant_out = GND;

END IF;

END IF;

END;

Все сигналы в данном файлы имеют активный низкий уровень. Фирма Altera рекомендует помечать как-нибудь имена сигналов с низким активным уровнем, например, первым символом в имени ставить символ “/”, который не является оператором, и использовать его постоянно.

В операторе IF проверяется, является ли модуль активным, т.е. равен ли он GND. Если модуль оказывается активным, реализуются действия, записанные в операторе IF.

В объявлении по умолчанию DEFAULTS считается, что сигналу присваивается значение VCC, если он не активен.

3.3.8. Реализация двунаправленных выводов

Система MAX+PLUS II позволяет конфигурировать порты ввода/вывода (I/O) в устройствах Altera как двунаправленные порты. Двунаправленный вывод задается как порт BIDIR, который подсоединяется к выходу примитива TRI. Сигнал между этим выводом и буфером с тремя состояниями является двунаправленным, и его можно использовать в проекте для запуска других логических схем.

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

SUBDESIGN bus_reg2

(

clk : INPUT;

oe : INPUT;

io : BIDIR;

)

BEGIN

io = TRI(DFF(io, clk,, ), oe);

END;

Двунаправленный сигнал io, запускаемый примитивом TRI, используется в качестве входа d для D-триггера (DFF). Запятые в конце списка параметров отделяют места для сигналов триггера clrn и prn. Эти сигналы по умолчанию установлены в неактивное состояние.

Двунаправленный вывод можно также использовать для подсоединения TDF-ФАЙЛа более низкого уровня к выводу с высоким уровнем. Прототип функции для TDF-ФАЙЛа более низкого уровня должен содержать двунаправленный вывод в предложении RETURNS. В приведенном ниже файле bidir1.tdf даны четыре примера использования макрофункции bus_reg2.

FUNCTION bus_reg2 (clk, oe) RETURNS (io);

SUBDESIGN bidir1

(

clk, oe : INPUT;

io[3..0] : BIDIR;

)

BEGIN

io0 = bus_reg2(clk, oe);

io1 = bus_reg2(clk, oe);

io2 = bus_reg2(clk, oe);

io3 = bus_reg2(clk, oe);

END;

 

- Наверх -

 

Координаты:

   г. Москва, пр. Мира, 102

Для писем:

   105066, Россия, г. Москва, а/я 18

Тел.: (495) 778-97-04

e-mail: mail@dsol.ru, info@dsol.ru

 

© НПП “Цифровые решения” 2003 — 2006

Разработка светодиодных экранов | Разработка бегущих строк | Проектирование ПЛИС и СБИС | Разработка законченных устройств и модулей | Синтез алгоритмов |

Rambler's Top100 Rambler's Top100