Главы из книги «Параллельная обработка данных».

Приложение 3. Основные понятия программистской модели VHDL

Программистская модель языка существует вне зависимости от того, как именно построено разъяснение языка будущим пользователям. Однако изложение программистской модели в явном виде обычно под­разумевает, что рассказ о языке ориентирован на «традиционных» программистов. Но зачем вообще это делать, почему о языке VHDL приходится рассказывать именно программистам?

Из материала, изложенного в подразделе, посвященном проблемам логического проектирования специализированных вычислителей, сле­дуeт простой и, в общем, довольно безрадостный вывод. Такое проек­тирование прекрасно подготовлено развитием как аппаратных, так и программных средств с технической стороны, но должно выполняться специалистами, которых в настоящее время не готовит ни одно учебное заведение России. Речь идет о системных архитекторах специ­ализированных вычислителей, т.е. о тех людях, которым в средне­срочной перспективе придется работать в тесном контакте с приклад­ными программистами, заменяя своим трудом не созданные пока не­обходимые технологии автоматической разработки таких вычислите­лей.

В самом деле, спроектировать схему по готовым функциональным спецификациям могут многие. Сложнее придумать эти спецификации таким образом, чтобы схема действительно соответствовала «духу и букве» вычислительного алгоритма, действительно содержала в себе внутренне присущий алгоритму параллелизм, выражала в своей струк­туре свойственную алгоритму специализированную структуру памя­ти. Более того, из всех имеющихся алгоритмов и численных методов решения поставленой задачи требуется выбрать именно тот, который лучше всего «ложится» именно в схему, а не на универсальный про­цессор.

Словом, системный архитектор специализированных вычислителей должен сочетать в себе профессиональное владение схемотехникой и знание численных методов, достаточное, как минимум, для уверенного общения с математиками-прикладниками. Система профессионального компьютерного образования 60 лет уверенно шла к тому, чтобы макси­мально разделить по разным областям профессиональной подготовки эти две области знаний. В результате сегодня представить себе схемо­техника, способного правильно подобрать разностную схему и итера­ционный алгоритм, так же невозможно, как специалиста по численным методам, способного хотя бы просто представить себе, в чем вообще заключается отличие процессора от вентильной матрицы. Можно, конечно, надеяться, что необходимые специалисты будет подготовлены, когда наступит такая потребность. Проблем здесь всего две.

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

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

С другой стороны, ситуация, когда фундаментальный прорыв в об­ласти вычислительных технологий может быть выполнен целиком «В голове», без каких-либо ссылок на отставание в технологической базе и слабое финансирование строительства новых заводов и технопарков, уникальна. Такое в технике бывает не часто, окно возможностей скоро закроется. Это будет означать, что данную область знаний создадут без нас.

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

Теоретически существует три категории специалистов:

  • схемотехники;
  • системные программисты;
  • прикладные программисты, специалисты в области численных методов математического моделирования.

При рассмотрении проблемы в практической плоскости нетрудно прийти к выводу, что наибольшую надежду на успех дают системные программисты, профессионально наиболее подготовленные к построе­нию новых формализмов, к формулированию новых логических сущ­ностей. При освоении не существующей пока профессии системного архитектора специализированных вычислителей им придется «всего лишь» проявить эту свою способность в новой, непривычной предметной области. Конечно, довольно большое количество схемотехников, само­стоятельно освоивших программирование, также является важнейшим источником «кандидатов в системные архитекторы». Од нако специалисты этого профиля обычно знают о прикладной математике и численных методах еще намного меньше (если такое вообще возможно), чем «системщики», что представляет собой серьезную трудность. Так что задача подготовки будущих системных архитекторов именно из системных программистов остается, как минимум, актуальной.

Ясно, что первым и очень важным шагом в такой подготовке системных архитекторов является изучение языка схемотехнического проектирования, например, VHDL. Ведь именно через программистскую модель языка схемотехнического проектирования системный архитектор получает базовое представление о материале, с которым ему придется работать. В специальной литературе на сегодня накоплен довольно богатый опыт разъяснения основ VHDL схемотехникам, привыкшим к структурному проектированию «в регистрах». Главная методическая трудность здесь состоит в освоении самого алгоритмического подхода, в привыкании к тому, что схема может быть описана не в терминах структуры, а в терминах алгоритма. Казалось бы, при разъяснении основ VHDL программисту эта трудность точно не возникает, но возникают другие сложности.

Всего несколько лет назад автору пришлось побывать в роли системного программиста, осваивающего VHDL. Хотелось бы поделиться опытом того, в чем состоят типичные ошибки и трудности, что остается не прочитанным или не понятым с первого раза, когда к изучению VHDL приступает именно системный программист с характерной именно для этой профессии «картиной мира».

Учебников по основам VHDL достаточно высокого качества существует много, и предлагаемый ниже текст не претендует на то, чтобы быть заменой или кратким конспектом одного из них. Скорее речь может идти о комментариях к типичному учебнику по основам VHDL, написанных с точки зрения системного программиста и для системных программистов.

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

Модель памяти VHDL базируется на двух понятиях — сигнала и переменной. При поверхностном знакомстве с языком может сложиться впечатление, что именно переменные — те самые объекты, в терминах которых в основном и следует записывать алгоритм. Такое представление является глубочайшей ошибкой и верным путем к написанию текстов, не соответствующих вообще никакой схеме. Переменные в реальных текстах на VHDL встречаются крайне редко, и пока не будем о них говорить. Сосредоточимся на сигналах.

Сигнал в VHDL — это абстракция провода, на котором имеется напряжение логического уровня, логический нуль или логическая единица. Таким образом, сигнал — это именованный объект, имеющий двоичное значение, подобно переменной в фоннеймановских языках программирования. В полной аналогии с фоннеймановским программированием сигналы должны быть объявлены в начале программы, до их использования, а использование их состоит, в частности, в присваивании им новых значений. В некоторых языках схемотехнического проектирования предусматриваются специальные виды программных объектов для обозначения, с одной стороны, соединений выходов одних элементов с входами других, т. е. проводов в буквальном смысле этого слова, и, с другой стороны, «проводов», обладающих свойством хранить ранее присвоенное значение и изменять его при новом присваивании, т.е. триггеров. VHDL к таким языкам не относится. В нем для обозначения «проводов» обоих видов применяется один и тот же вид объектов — сигналы, а вопрос о том, стоит ли за тем или иным сигналом триггер, или же это просто провод, решается транслятором автоматически, по тексту программы. С точки зрения человека, обладающего опытом фоннеймановского программирования, такое обобщение очень удобно. Можно смело считать, что сигнал аналогичен переменной в традиционном программировании, и не вдаваться в дальнейшие детали.

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

Примеры объявления сигналов:

signal a: bit;
signal b: bit_vector(31 downto 0);

В первом случае объявлен одноразрядный сигнал под именем “а”, во втором — 32-разрядный сигнал с именем “Ь”, разряды в котором занумерованы по убыванию от 31 до нуля.

Примеры присваивания:

а <= '0';
Ь(18) <= а;
b(31 downto 24) <= "01010101";

Помимо векторов существуют также массивы сигналов (одиночных или векторных). Очень важно понимать, что индексация как векторов, так и массивов может быть только статической. Такая очевидная и привычная для программиста возможность, как, например, «присвоить единицу тому биту сигнала Ь, номер которого хранится в данный момент в сигнале с», в языках схемотехнического проектирования, вообще говоря, не предусмотрена. В модели вентилей и регистров, на которые ориентированы эти языки, эта возможность не является базовой подобно тому, как в С не является базовой возможность присвоить значение полю записи, хранящейся в СУБД. Схемы, реализующие динамическую индексацию, в терминах VHDL можно записать как довольно сложные фрагменты программ, но базовыми конструкциями языка они не являются. Из этого утверждения бывают исключения, которые кратко будут изложены далее.

Наличие в операторе объявления сигнала слова «bit» наверняка уже удивило некоторых внимательных читателей. В самом деле, какой еще тип, кроме типа «бит», можно придумать для сигнала в цифровой схеме? В действительности существуют и очень часто используются другие типы, например тип сигнала «std_logic», способный принимать несколько других значений, помимо нуля и единицы. Речь идет, конечно, не о возможности проектирования схем для троичных и квантовых компьютеров, как быть может подумали некоторые из читателей, а всего лишь о возможности выражения в схемах функциональности таких не вполне логических элементов, как тристабильные формирователи. Например, среди допустимых значений сигнала типа «std_logic» имеется значение «третье состояние», которое соответствует просто «обрыву линии», выполненному путем отключения тристабильного формирователя на выходе этой линии. Обнаружив в программе присваивание сигналу такого значения, транслятор включит в формируемую схему необходимый тристабильный формирователь. Располагая же сигналом типа «bit», автор программы просто не смог бы донести до транслятора необходимую информацию о составе требуемой схемы. Использование сигналов типа «std_logic» для записи схем, полностью выразимых в терминах логических элементов, никак не усложняет итоговую схему по сравнению с использованием сигналов типа «bit».

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

С точки зрения модели выполнения программа распадается на некоторое количество процессов и часть программы вне процессов.

Часть программы вне процессов соответствует комбинационной части схемы, т. е. жестко выполненным при построении схемы соеди­нениям выходов одних элементов со входами других. Например, если в этой части программы написано:

Ь <= с and d;
то транслятор сгенерирует вентиль “И”, входами которого являются сигналы «с» и «d», а выход представляет собой сигнал «Ь». Сигналам, которым присваиваются значения в этой части программы, можно присваивать значения только один раз. В самом деле, выход данного вентиля либо называется «Ь», либо не называется, никакого третьего варианта здесь быть не может.

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

Формально процесс представляет собой бесконечный цикл, в котором выполняется тело процесса. Очередной виток этого цикла запускается всякий раз, когда один из сигналов, перечисленных в заголовке процесса, меняет свое значение. Каждому сигналу, которому не присвоено значение вне процессов, можно присваивать значения в теле процесса, но только одного, и только один раз за одно срабатывание (виток цикла).

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

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

Например:

process SAMPLE_PROC ( b, с, d ) is
begin
    if c = '1' then
      a <= b;
    else
      a <= d;
    end if;
end process SAMPLE_PROC;

Вместо этого процесса можно было бы написать просто:

а <= ( b and с ) or (d and (not с));

Понятие «бесконечного цикла», который «срабатывает при каждом изменении одного из сигналов, перечисленных в заголовке», в данном случае представляется довольно искусственным, только затуманивающим существо дела. В результирующей схеме не появится никакой дискретно работающей логики, про которую можно было бы сказать, что за данную секунду она сработала, скажем, 100 миллионов раз.

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

Например:

process SAMPLE_PROC ( Clk ) is
begin
  if Clk'event and Clk = '1' then
    if c = '1' then
      a <= b;
    else
      a <= d;
    end if;
  end if;
end process SAMPLE_PROC;

Признаком того, что сигнал Clk является не просто логическим сигналом, но выходом тактового генератора, а тело процесса срабатывает дискретно, является третья строка примера. Синтаксически это просто условный оператор, на самом же деле — неделимая языковая конструкция, «видя» которую, транслятор понимает, что речь идет именно о триггерной, а не комбинационной логике. Если бы программист добавил, следуя формальным правилам языка, в заголовок этого процесса дополнительные сигналы по аналогии с первым примером, транслятор бы их при синтезе схемы просто проигнорировал.

Попытка авторов языка объединить в рамках единой языковой конструкции, формально определяемой и разъясняемой единообразно, два таких разных содержательных понятия предметной области, как комбинационная и триггерная логика, конечно, язык вовсе не украшает, но имеет свое объяснение. Единое понятие процесса, не разделяемое на два рассмотренных выше случая, является довольно естественным, если говорить о программном моделировании работы схемы средствами универсального процессора. Тем не менее, при написании на VHDL текстов, предназначенных для синтеза, а не только для моделирования, два рассмотренных случая применения языковой конструкции «процесс» совершенно необходимо четко различать. Один из способов такого различения, применяемый автором, состоит в том, чтобы просто никогда не пользоваться «комбинационными процессами». Далее при рассмотрении понятия процесса в VHDL будем говорить только о триггерной логике.

Вернемся к нашему второму примеру.

Строки с четвертой по седьмую описывают те действия, которые должны происходить по каждому переднему фронту сигнала Clk, т. е. при его переходе из 0 в 1. Эти действия состоят в присваивании сигналу «а» значения либо сигнала «Ь», либо сигнала «d», в зависимости от того, чему равно значение сигнала «с».

Присваивание сигналу «а» предусмотрено в этом процессе, следовательно, ни вне процессов, ни в каком-либо еще процессе этой программы, выполнять присваивание сигналу «а» уже нельзя. Очевидно, в итоговой схеме сигнал «а» станет триггером, все тактирование и управление которым должно быть сосредоточено в одной части схемы, тактируемой совершенно конкретным генератором синхроимпульсов. Разные же процессы, вообще говоря, тактируются и управляются по-разному.

Обратим внимание также на то, что на каждом витке цикла может сработать не более одного оператора присваивания нового значения сигналу «а». Например, запись:

if с = '1' then
  а <= Ь;
else
  а <= d;
end if;
if e = '0' then
  a <= f;
end if;
абсолютно недопустима. Это связано с тем, что время в схеме течет дискретно, за пределами актов срабатывания тела процесса никаких действий быть не может, а сам акт срабатывания представляет собой момент, не имеющий длительности. Из этого же, в свою очередь, следует, что все тело процесса, включая все проверки и все присваивания, выполняется одновременно! Но нельзя же, в самом деле, одновременно присвоить триггеру «а» и значение «f», и значение «b». Следовательно, в описываемой модели выполнения данная запись является недопустимой.

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

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

Присваивание значений сигналам в рамках процесса является отложенным на один виток выполнения цикла. Это — абстракция того факта, что тактируемому триггеру нужно время, равное одному такту, чтобы запомнить поданное на него значение. Таким образом, запись:

с <= '1';
if с = '0' then
вовсе не является бессмысленной. Она означает: «Сделать триггер «с», начиная со следующего срабатывания этого процесса, равным единице. Если же сейчас он равен нулю, то...» В дискретном времени, собственно, иначе и быть не может. Вслушаемся мысленно в типичное объяснение смысла оператора присваивания фоннеймановских языков: “Сделать левую часть равной тому, чему сейчас равна правая”. Здесь почти явно присутствует отсылка к понятию времени. Если же время дискретно, то, естественно, предписание «сделать» может относиться только к следующему моменту, ведь настоящий уже наступил.

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

Пусть время дискретно и, следовательно, все тело цикла — процесса выполняется одновременно. Но ведь тело процесса содержит условную логику. Значит, проверки, заданные в условных операторах, выполняются сначала, а соответствующие присваивания (или другие, вложенные проверки) — потом. Так все-таки, «потом» или «одновременно»?

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

Опыт автора показывает, что именно эта особенность модели выполнения, принятой в VHDL, дается осваивающим его специалистам особенно тяжело.

Из уже рассказанного должен быть ясен ответ на вопрос, который не очень внимательный читатель, возможно, готов задать, а именно — на вопрос о «go to». Этого вопроса в VHDL нет, как и самого «go to». И не потому, что авторы языка как-то особенно ревностно относятся к принципам структурного программирования, а просто потому, что в этой модели выполнения нет понятия «текущего, выполняемого в данный момент места программы». Все места программы выполняются одновременно во все моменты.

В языке предусмотрены понятия оператора цикла и вызываемых функций, синтаксически похожие на аналогичные понятия фоннейма-новских языков. В фоннеймановских языках оба эти понятия определяются в терминах модели последовательного выполнения операторов программы, которые, как мы только что видели, к модели выполнения VHDL не применимы. Циклы и функции VHDL являются просто макросами. Цикл «разворачивается» во время трансляции, при этом каждый виток цикла превращается в отдельный фрагмент схемы, выполняющийся в рамках процесса, в котором записан цикл. Вызов функции превращается при трансляции в подстановку на место вызова того фрагмента схемы, который получился при трансляции тела функции при заданных значениях аргументов.

Таким образом, многое из того, что в фоннеймановской программе происходит во времени, в VHDL просто «разворачивается» в пространстве, т. е. приводит к генерации соответствующих фрагментов схемы по так или иначе параметризованным «заготовкам».

Функциональным аналогом понятия фоннеймановской подпрограммы является в VHDL понятие компонента. Вызову подпрограммы соответствует конкретизация компонента (port map).

По смыслу компонент — это отдельно записанная и, возможно, отдельно транслируемая схема, связанная с внешним миром совершенно конкретным набором входных и выходных сигналов — «внешним разъемом». Конкретизация компонента — это «впаивание» экземпляра такой схемы с подключением к ее «внешнему разъему» собственных сигналов. Записывается такое «впаивание» вне процессов, поскольку действие это чисто комбинационное. Те или иные сигналы разрабатываемой схемы либо присоединены к «разъему» некоторого экземпляра указанного компонента, либо нет.

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

Помимо сигналов, которые, как мы убедились, выполняют в VHDL ту же роль, что переменные в фоннеймановском программировании, в VHDL есть дополнительные объекты, называемые переменными. Они имеют те же типы, что и сигналы, тоже объявляются и присваиваются. Присваивание переменным записывается не так, как присваивание сигналам, «:=», а не «<=». Переменные VHDL — это довольно странные программные объекты. На них не распространяется модель выполнения VHDL — они «умудряются» подчиняться фоннеймановской модели выполнения, т. е. присваивания им «выполняются» последовательно, по ходу текста программы, без задержки на такт, и могут быть многократными.

Как мы убедились выше, оборудованию, в которое транслируются тексты на VHDL, эта модель выполнения категорически не соответствует. Следовательно, аппарат переменных может быть (и действительно является) лишь вспомогательным средством оформления текста программы. Всякая попытка воспользоваться им так, как если бы триггеры действительно умели переключаться за один такт много раз, т. е. попытка записать с помощью переменных действия, не выразимые в принципе в терминах сигналов, ни к чему хорошему не приведет. Получится либо текст, который невозможно оттранслировать, либо текст, парадоксально не соответствующий замыслу программиста. Чтобы пользоваться этим аппаратом по назначению, не запутывая себя неосуществимой возможностью «на минуточку сменить модель выполнения», следует придерживаться при использовании переменных некоторых простых правил. Первое правило очевидно: переменными, по возможности, вообще не пользоваться. Второе правило: рассматривать их не как программные, а как алгебраические переменные, т. е. использовать исключительно в следующем стиле: «Обозначим выражение «а and b or not с» в данном месте программы как переменную X, и далее по тексту программы, впредь до переобозначения символа X, будем для краткости вместо «а and b or not с» везде писать X».

Упоминавшаяся нами выше аналогия между понятием компонента и понятием подпрограммы (или функции) фоннеймановских языков распространяется также на библиотеки стандартных компонентов. Стандартные, оттранслированные отдельно, распространяемые не в исходном, а в «объектном» виде готовые фрагменты схем на уровне языка оформляются как компоненты. Для типовых логических узлов, включаемых в некоторые FPGA в готовом виде, наряду с логическими элементами также существуют специальные библиотечные компоненты. При включении в программу «обычного» библиотечного компонента в соответствующем месте схемы строится схема из логических элементов, которая содержится в «объектном модуле» компонента. Если же включается (конкретизируется) специальный библиотечный компонент, то вставляется готовый логический узел.

Ясно, что наборы готовых логических узлов в разных FPGA бывают разными, как и компоненты, используемые для ссылки на эти узлы. Чтобы обеспечить, по возможности, переносимость текстов на VHDL с одних типов FPGA на другие, и при этом не потерять возможность использоваг ния сходных по функциям готовых логических узлов, разработчики трансляторов VHDL иногда применяют следующий «фокус».

Придумывается канонический для данного логического узла фрагмент текста на VHDL, который описывает функцию этого логического узла. Например, регистра сдвига, или блока двухпортовой памяти. Транслятор снабжается «распознавателем» в тексте исходной программы «похожих» фрагментов. Если такой фрагмент, похожий, с точки зрения транслятора, удается обнаружить в тексте программы, то транслятор поступает с ним, как с обращением к специальному библиотечному компоненту, т. е. не порождает обычным порядком схему из вентилей, а вставляет готовый узел. При этом в описании этой версии транслятора написано что-то вроде: «Если Вы хотите, чтобы Ваша схема использовала готовые блоки типа X, но не была привязана к данному типу FPGA, то вместо конкретизации специального библиотечного компонента BLOCK_X напишите такой текст:...».

В таких «условных», не транслируемых в логические элементы, фрагментах текста иногда разрешается делать то, чего в «обычной» части текста программы делать нельзя или крайне нежелательно. Например, в «условном» описании готового блока памяти можно адресовать элемент массива по динамическому индексу — ведь для готового блока памяти, в отличие от набора логических элементов, такая возможность является базовой.

Основная сложность использования такого рода «фокусов» в том, что они незначительно упрощают процесс разработки конкретных текстов, при этом значительно запутывая понимание системы в целом. В самом деле, как понять, достаточно ли похож данный фрагмент текста на типовой, транслируемый в готовый блок? Информация об этом приеме трансляции приведена здесь не в качестве примера привлекательной возможности, которой следует всячески пользоваться, а, в основном, для сведения при чтении документации. Автор настоящего текста в своих схемах такой возможностью старается не пользоваться. Для изоляции и минимизации частей схемы, которые потребуется переписать при смене типа FPGA, гораздо лучше пользоваться общепринятыми приемами структурного проектирования.

◀ Приложение 2.

 
 
 
 
 
 
 
 
  Тел. +7(499)220-79-72; E-mail: inform@kiam.ru  
▲