Сегодня аппаратура разрабатывается на высокоуровневых языках, области разработки аппаратуры и ПО стремятся к слиянию. В этой статье сделана попытка введения в разработку на Verilog для тех, кто пока что не сильно в теме (перевод [1]).
В ближайшем будущем разработчики встраиваемых систем будут способны взаимозаменяемо использовать железо и программное обеспечение в зависимости от того, какой из способов решения задач лучше поможет для реализации техзадания. До настоящего момента кривая сложности изучения вопроса разработки железа была слишком крута, чтобы в неё могли окунуться опытные разработчики встроенного ПО. Но этот барьер постепенно рушится из-за того, что языки программирования аппаратуры стремятся быть похожими на традиционные языки программирования. Также становятся доступными по цене недорогие демонстрационные платы, которые имеют на борту программируемую микросхему логики (это может быть мощная схема field-programmable gate array, FPGA или менее мощная CPLD), микропроцессор, имеются в наличии недорогие программаторы JTAG и бесплатные инструменты разработки (как например Xilinx ISE WebPack [2]). Все это позволяет разработчикам встраиваемого firmware начать изучать программирование цифровой аппаратуры.
В этой статье предоставлен пример, как выполнить новую разработку с использованием FPGA. Будет показана реализация широтно-импульсной модуляции, ШИМ (pulse width modulation, PWM) программно, и затем будет произведен портирование дизайна в логический блок, который может быть запущен в FPGA, и управляться программным обеспечением через отображенный на память интерфейс ввода/вывода (I/O). Вы можете повторить все действия в этой статье с любым китом разработки FPGA, которые предоставляют сегодня основные разработчики FPGA (особенно популярны Xilinx и Altera), и также в изобилии можно купить через Интернет в магазине AliExpress.
[Разделение между железом и ПО]
Есть несколько факторов, упрощающих для программистов участие в разработке аппаратуры. И для железа, и для ПО модули кода разрабатываются с использованием языков программирования. Как Вы знаете, язык C является общепринятым в мире разработки встраиваемого ПО (embedded software, или firmware). На стороне разработки железа Verilog часто является популярным выбором (хотя VHDL и Verilog оба одинаково популярны, и имеют каждый своих сторонников). Синтаксис и структура Verilog подобна языку C, что на примерах будет показано в этой статье.
В то же время железо стало доступно для простого обновления и изменения. Прошли времена, когда только поведение ПО можно было легко изменить путем внесения правки в код, перекомпиляции и загрузки нового исполняемого образа в память системы. Теперь примерно то же самое можно делать и для аппаратного обеспечения - можно быстро исправить исходный код, выполнить его повторный синтез, и загрузить сгенерированный поток бит конфигурации в память FPGA системы. Программируемая логика позволила в разработке встраиваемых систем так же быстро и просто менять аппаратуру, как это делалось с программным обеспечением. Другими словами, это добавляет гибкости и эффективности в разработке - появилось больше возможностей для реализации различных задач. Некоторые функции можно переложить на аппаратуру, а некоторые на программное обеспечение.
Инструменты разработки, доступные от производителей FPGA, предъявляют к разработчику минимум требований по знанию аппаратного обеспечения, чтобы применять программируемую логику, такую как FPGA, в разработке встраиваемых систем. Например, SOPC Builder от компании Altera позволяет разработчикам систем выбрать и сконфигурировать периферийные устройства из существующей библиотеки. Также можно добавить логику пользователя, чтобы подключить к ней периферийные устройства. С помощью программируемой логики и некоторыми знаниями специфики железа разработчики ПО могут в своих интересах использовать преимущества аппаратных средств, чтобы улучшить их проектируемые системы.
[Программная реализация PWM]
Контроллер PWM (ШИМ) генерирует поток импульсов, примерно таких, как показаны на рис. 1. ШИМ характеризуется периодом и длительностью импульса или скважностью, т. е. соотношением длительностей лог. 0 и лог. 1 в периоде. Скважность определяет уровень аналогового сигнала, который появляется на выходе ФНЧ. Рис. 1 показывает форму сигнала ШИМ со скважностью 33%, т. е. такая форма сигнала позволяет сформировать аналоговый сигнал с уровнем 33% от максимального.
Рис. 1. Форма выходного сигнала ШИМ.
ШИМ используется во многих приложениях, чаще всего для управления аналоговыми схемами. Из-за того, что цифровой сигнал ШИМ постоянно и достаточно часто меняет свое значение (конечно, в зависимости от периода ШИМ), то результирующий сигнал будет иметь некое среднее значение, зависящее от скважности, которое можно использовать для управления аналоговым устройством или для генерации звука. Например, поток импульсов ШИМ может быть отправлен на мотор, и его выходная мощность на валу будет пропорциональна скважности (от 0% до 100%). Если скважность увеличивается, мотор крутится быстрее, и наоборот, с понижением скважности мотор замедляется.
Обычно высокочастотный ШИМ удобнее всего реализовать аппаратно, потому что для формирования импульсов нужны постоянно (с каждым периодом) повторяющиеся простые действия. Большинство микроконтроллеров имеет для этого на борту специальные таймеры-счетчики. Программное обеспечение просто вычисляет интервалы времени лог. 0 или лог. 1 фиксированного периода, и передает их в аппаратуру, что позволяет менять скважность ШИМ программно.
Однако нет никаких причин не реализовать в некоторых случаях ШИМ чисто программно, например простым переключением уровня на ножке порта вывода. Запрограммировать такой ШИМ-контролер относительно просто, и это поможет нам в будущем при реализации того же ШИМ на Verilog. Листинг 1 показывает код программной реализации ШИМ на языке C.
Листинг 1. PWM-контроллер, работающий по принципу "bit-bang", т. е. дерганием логического уровня на ножке порта вывода.
// pulse_width: ширина импульса ШИМ
// period: период ШИМ
void pwmTask(uint32_t pulse_width, uint32_t period)
{
uint32_t time_on = pulse_width;
uint32_t time_off = period - pulse_width;
while (1)
{
pwm_output = 1;
sleep(time_on);
pwm_output = 0;
sleep(time_off);
}
}
На основе аргументов этой функции pulse_width и period вычисляется количество времени, когда выход pwm_output находится в состоянии лог. 1 и лог. 0. В бесконечном цикле выход pwm_output постоянно переключается, и в течение time_on единиц времени на выходе лог. 1, и в течение time_off единиц времени выход находится в состоянии лог. 0, что определяет скважность ШИМ на выходе и в конечном итоге средний уровень формируемого сигнала.
[Реализация ШИМ на Verilog]
Листинг 2 показывает простой модуль Verilog, реализующий 8-битный регистр с асинхронным сбросом. Вход регистра in присваивается выходу out по фронту нарастания тактового сигнала, кроме случаев спада сигнала сброса clr_n reset, тогда выходу назначается значение 0.
Листинг 2. Модуль Verilog для регистра с асинхронным сбросом.
module simple_register(in, out, clr_n, clk, a);
// Декларации портов.
input clr_n;
input clk;
input [7:0] in;
input a;
output [7:0] out;
// Декларации сигналов.
reg [7:0] out;
wire a;
// Реализация регистра с асинхронным сбросом.
always @(posedge clk or negedge clr_n)
begin
if (clr_n == 0) // то же самое можно записать как if (!clr_n)
out < = 0;
else
out < = in;
end
end
// Постоянное присваивание.
assign a = !out[0];
endmodule
При быстром взгляде на листинг Verilog можно заметить, что он похож на язык C. Точка с запятой используется в конце каждого оператора, и используются тот же формат для оформления комментариев (/* */ и //). Оператор == также используется для проверки эквивалентности. Конструкции if..then..else языка Verilog подобны языку C, кроме ключевых слов begin и end, которые используются вместо фигурных скобок. Фактически ключевые слова begin и end не обязательны для однострочных блоков, то же самое правило работает для однострочных блоков языка C. И Verilog, и C оба чувствительны к регистру текста кода.
Конечно, ключевое отличие между аппаратурой и программным обеспечением в том, как они работают. Разработка на основе железа состоит из множества элементов, работающих параллельно. Как только устройство включилось, каждый элемент аппаратуры начинает работу и постоянно выполняет свои функции. Конечно, в зависимости от логики управления и данных на входе некоторые элементы устройства могут не менять значения на своем выходе. Однако они все равно непрерывно "работают".
В отличие от этого поведения аппаратуры только малая часть всего программного обеспечения активна в каждый произвольный момент времени (даже если это многозадачная среда выполнения кода). Причина этого в том, что процессор, выполняющий код, только один, и в каждый момент времени он может выполнять только одну инструкцию. Остальную часть ПО можно считать "бездействующей", что коренным образом отличается от "остальной части" аппаратуры. Переменные могут существовать и хранить свое значения, однако большинство времени они не участвуют в какой-либо обработке. Эффект "параллельности" в работе ПО, когда процессор якобы одновременно выполняет несколько задач, заключается в постоянно повторяющемся, быстром выполнении разных участков кода.
Различия в поведении аппаратуры и ПО отражается в методах, которыми мы кодируем поведение аппаратуры и поведение программы. Программный код выполняется последовательно, так что каждая строка кода выполняется только после того, как была выполнена предыдущая строка (конечно исключая нелинейности, вносимые прерываниями или планировщиком задач операционной системы).
Модуль Verilog начинается с ключевого модуля module, за которым идет имя модуля и список его портов. Список портов это список имен всех входов и выходов модуля. Следующая секция кода содержит декларации этих портов. Обратите внимание, что все входы и выходы появляются как в круглых скобках после имени модуля, так и в теле модуля, начиная с его первой строки, в секции декларации портов.
На языке Verilog внутри модуля широко используется два типа сигналов: reg (регистр) и wire (сигнал, провод). Эти типы отличаются по своей функции. Все части кода, имеющие сигнал, имеют неявно декларированный wire с тем же именем. Таким образом, не требуется декларировать такие сигналы как wire. Тип reg будет хранить в себе последнее назначенное ему значение, так что нет необходимости всегда управлять его значением. Сигналы типа wire используют для асинхронной логики, и иногда подключаются к внешним сигналам. Из-за того, что reg хранит последнее свое значение, входы не могут декларироваться как reg. Вход можно поменять асинхронно в момент любого события модуля Verilog. Однако основное отличие wire от reg в том, что сигналы типа reg могут назначаться только в процедурных блоках (что это такое, обсудим позже) в то время как сигналы типа wire могут быть назначены значению только вне процедурных блоков. Оба этих типа сигналов могут появляться как слева, так и справа в выражении присваивания, и как внутри, так и снаружи процедурных блоков.
Важно понимать, что ключевое слово reg необязательно заставит компилятор зарезервировать в этом месте ячейку памяти (создать для этого сигнала триггер или регистр). Код в Листинге 2 имеет один внутренний сигнал типа reg, который имеет разрядность 8 бит и называется out. Этот модуль выводит reg потому, что таким способом пишется блок always (это один из типов процедурных блоков). Обратите внимание, что сигнал a это wire, так что ему можно присвоить значение только оператором постоянного присваивания, в то время как значение для типа reg назначается величина только в блоке always.
Блок always это блок процедурного типа, используемый для обновления сигналов только при возникновении каких-либо событий (когда какой-то сигнал поменяет свое значение). Группа выражений внутри круглых скобок оператора always называется списком чувствительности (sensitivity list). Он определяет, на какие сигналы срабатывает блок always, и он имеет форму:
(выражение1 or выражение2 ...)
Код внутри такого блока always выполняется всякий раз, когда любое из выражений в списке чувствительности примет значение true (вместо or может быть операция and, тогда все выражения должны быть true). Ключевые слова Verilog для обозначения события нарастания сигнала (от лог. 0 к лог. 1) и для события спада сигнала (от лог. 1 к лог. 0) это posedge и negedge соответственно. Они часто используются в списках чувствительности. В показанном примере блок always сработает (выполнятся операторы в его блоке), если произойдет положительный перепад сигнала clk или отрицательный перепад сигнала clr_n.
Чтобы вывести регистр, выход должен быть обновлен по фронту нарастания тактов (срез спада также будет работать, но чаще используется именно фронт). Добавление negedge clr_n осуществляет сброс регистра при спаде уровня сигнала clr_n. Не все списки чувствительности будут содержать в себе ключевые слова posedge или negedge, таким образом не всегда в полученной аппаратуре будет синтезирован настоящий регистр.
Внутри блока always первый оператор опрашивает, произошел ли спад сигнала clr_n. Если это так, то следующая строка кода устанавливает out в 0. Эти строки кода реализуют асинхронный сброс регистра по спаду сигнала clr_n. Оператор условия, где:
if (negedge clr_n and clk == 1)
... выполнит уже синхронный сброс, который зависит также и от уровня тактов.
Вы возможно заметили, что оператор присваивания внутри блока always и вне блока always оформляется по-разному. Постоянное присваивание (вне процедурного блока) использует ключевое слово assign, а внутри процедурного блока используются оператор < = для не блокирующего присваивания и оператор = для блокирующего присваивания.
В группе блокирующих присваиваний сначала обрабатывается первое присваивание, и только по его завершении выполняется следующее блокирующее присваивание. Этот процесс работает как последовательное выполнение операторов на языке C. С неблокирующими присваиваниями правая сторона всех присваиваний вычисляется и присваивается одновременно. Постоянное присваивание должно использовать блокирующее присваивание (иначе компилятор выдаст ошибку).
Чтобы сделать код менее подверженным ошибкам, рекомендуется использовать не блокирующие присваивания для всех присваиваний в блоке always с последовательной логикой (например для логики, которую Вы хотите реализовать как регистры). Большинство блоков always должно использовать не блокирующие операторы присваивания. Если блок always имеет полностью комбинаторную логику, тогда Вы захотите использовать блокирующие присваивания.
[Аппаратный ШИМ]
Часто первая задача, которую надо решить при создании аппаратного модуля с привязкой к карте памяти, это необходимость спроектировать карту регистров, к которым будет обращаться программное обеспечение при управлении аппаратурой. В случае ШИМ нужно иметь возможность программно установить период и ширину импульса ШИМ. В аппаратуре нужно реализовать счетчик, который будет просто считать такты системной частоты. Таким образом, это будут 2 регистра pulse_width и period, в обоих будут записываться единицы измерения времени в тактах системы. Таблица 1 показывает карту памяти для регистров модуля ШИМ.
Таблица 1. Register map для блока PWM.
Адрес |
Имя |
Разрядность |
Описание |
0 |
period |
32 бита |
Количество тактов за период сигнала ШИМ |
1 |
pulse_width |
32 бита |
Количество тактов длительности лог. 1 сигнала ШИМ |
Чтобы определить уровень выходного сигнала ШИМ, аппаратура может просто сравнить содержимое регистров period и pulse_width с постоянно работающим счетчиком.
Затем выберите порты для PWM, что в большинстве случаев делается на основе шинной архитектуры. Таблица 2 дает краткое описание сигналов для простой отображенной на память схемы PWM. Обратите внимание, что используется популярное соглашение об именовании, когда имена сигналов с активным нулевым уровнем получают суффикс "_n", что часто применяется для сигналов управления (таких как сброс или сигнал выборки). Сигналы write_n и clr_n из таблицы 2 имеют уровень активного лог. 0 (т. е. они срабатывают по спаду уровня).
Таблица 2. Порты для блока PWM.
Имя сигнала |
Направление |
Описание |
clk |
Вход |
Системные такты |
write_data[31:0] |
Вход |
Шина данных для записи (в регистры на карте памяти) |
cs |
Вход |
Chip Select (выборка, сигнал разрешения работы шины) |
write_n |
Вход |
Разрешение записи, активный уровень лог. 0 |
addr |
Вход |
Адрес (для выбора нужного регистра на карте памяти) |
clr_n |
Вход |
Сброс, активный уровень лог. 0 |
read_data[31:0] |
Выход |
Читаемые данные |
pwm_out |
Выход |
Генерируемый сигнал ШИМ |
Теперь, когда мы полностью определили внешний интерфейс для модуля аппаратуры PWM, можно начать писать код Verilog. Пример реализации аппаратного модуля ШИМ показан в Листинге 3.
Листинг 3. Аппаратная реализация PWM на Verilog.
module pwm (clk, write_data, cs, write_n, read_data, pwm_out);
// Декларации портов:
input clk;
input [31:0] write_data
input cs;
input write_n;
input addr,
input clr_n;
output [31:0] read_data;
output pwm_out;
// Декларации сигналов:
reg [31:0] period;
reg [31:0] pulse_width
reg [31:0] counter;
reg off;
reg [31:0] read_data;
wire period_en, pulse_width_en; // write enables
// Определение содержимого регистров period и pulse_width,
// включая доступ на запись в эти регистры:
always @(posedge clk or negedge clr_n)
begin
if (clr_n=0)
begin
period < = 32h000000000;
pulse_width < = 32h00000000;
end
else
begin
if(period_en)
period < = write_data [31:0];
else
period < = period;
if (pulse_width_en)
pulse_width < = write_data[31;0];
else
pulse_width < = pulse_width;
end
end
// Доступ на чтение для регистров period и pulse_width:
always @(addr or period or pulse_width)
if (addr == 0)
read_data = period;
else
read_data = pulse_width;
// Счетчик, который постоянно считает в течение периода ШИМ:
always @(posedge clk or negedge clr_n)
begin
if (clr_n == 0)
counter < = 0;
else
if (counter >= period - 1) // счет от 0 до (period-1)
counter < = 0;
else
counter < = counter += 1;
end
// Включение выхода, когда счетчик меньше, чем pulse_width; иначе
// выключение выхода. !off подключен к выходу ШИМ.
always @(posedge clk or negedge clr_n)
begin
if (clr_n == 0)
off < = 0;
else
if (counter >= pulse_width)
off < = 1;
else
if (counter == 0)
off < = 0;
else
off < = off;
end
// Сигналы разрешения записи для записи в регистры period и pulse_width:
assign period_en = cs & !write_n & !addr;
assign pulse_width_en = cs & !write_n & addr;
// Вывод сигнала ШИМ:
assign pwm_out = !off;
endmodule
Первые сигналы это декларации портов, описанные в таблице 2. После декларации портов идут декларации внутренних сигналов. Регистры, отображенные на память (memory-mapped), составляют интерфейс для доступа со стороны внешнего программного обеспечения (которое обычно работает на микроконтроллере). Они служат для изменения параметров ШИМ, и декларированы как reg. Код разрешает только 32-битный доступ к этим memory-mapped регистрам. Если Вам нужно реализовать 8-битный или 16-битный доступ, то необходимо поделить регистры на части (например, на четыре 8-битных регистра), и добавить логику для сигналов адресации этих регистров или для сигналов их выборки. Код Verilog, необходимый для такой реализации, получится очень простой. Все сигналы, которым присваиваются значения в блоках always, также декларируются как reg. Сигналы, декларированные как wire, используются как сигналы разрешения записи для регистров registers и pulse_width. Этим сигналам присваиваются значения с использованием операторов постоянного присваивания.
Остальная часть листинга содержит актуальный код. Здесь четыре блока always и несколько операторов присваивания в конце. Каждый блок always описывает поведение для одного сигнала или группы сигналов, которые имеют одинаковое базовое поведение (другими словами, используют ту же самую логику управления). Это чистый метод написания кода Verilog, который позволяет сохранить код удобочитаемым и менее подверженным ошибкам. Все блоки always имеют логику сброса, которая устанавливает сигнал (сигналы) в 0, когда активируется (переходит в лог. 0) сигнал clr_n. Хотя это не строго необходимо, однако является хорошей практикой разработки, гарантирующей наличие одинаковых известных начальных состояний сигналов при сбросе.
Первый блок always описывает поведение регистров на карте регистров (register map). Значение регистра write_data записывается в регистр period или регистр pulse_width, если выставлен соответствующий сигнал разрешения записи. Это единственный способ изменить значения любого из этих регистров. Сигналы разрешения записи определены в операторах постоянного присваивания, находящихся в конце файла. Сигналы разрешения записи для регистров period и pulse_width выставляются, когда выставлены главный сигнал разрешения записи и сигнал выборки кристалла (chip select); бит addr должен быть установлен в 0 для регистра period и в 1 для регистра pulse_width.
Второй блок always определяет чтение регистров на карте памяти. Регистр period будет находиться по базовому адресу периферийного устройства, и регистр pulse_width будет находиться на следующем 32-битном слове.
Третий и четвертый блоки always работают вместе, чтобы сформировать выходной сигнал ШИМ. Третий блок always реализует инкремент счетчика, который постоянно считает вверх до значения в регистре period, после чего сбрасывается в 0, и снова начинает считать вверх от нуля. Четвертый блок always сравнивает значение счетчика с регистром pulse_width. Когда значение счетчика меньше значения в pulse_width, выход ШИМ удерживается в лог. 1, иначе он устанавливается в лог. 0.
Одна вещь, которую следует иметь в виду - любой сигнал обязательно должен иметь определенное значение при всех возможных условиях. Это восходит к фундаментальному свойству поведения аппаратуры - она всегда работает. Например, в последнем блоке always (та часть, которая описывает сигнал off) последняя строка кода присваивает off самому себе. Это может выглядеть как минимум странным, но без этой строки значение off стало бы неопределенным для такого случая. Самый простой способ отследить подобные ситуации - убедиться, что в любой момент времени сигнал, который присваивается в ветке оператора if, также присваивается и в ветке оператора else.
[Доступ к аппаратуре ШИМ со стороны ПО]
Теперь, когда реализация аппаратуры на Verilog завершена, нужно организовать управление ШИМ через ПО, которое должно записывать регистры через карту памяти (register map). Вы можете использовать простую структуру данных с указателем, чтобы подключиться к регистрам в блоке ШИМ.
typedef volatile struct
{
uint32_t period;
uint32_t pulse_width;
} PWM;
Например, работу ШИМ можно отследить с помощью яркости подключенного к выходу контроллера ШИМ светодиода (LED). Переменная, которая названа pLED, имеющая тип PWM*, должна быть инициализирована базовым адресом контроллера ШИМ. Это абстрагирует аппаратуру ШИМ на структуру данных PWM. Запись в pLED->period установит или изменит period. Запись в pLED->pulse_width поменяет скважность, в результате чего яркость светодиода уменьшится или увеличится (кстати, запись в pLED->period также поменяет яркость, так как среднее значение на выходе шим зависит от скважности, т. е. от соотношения period/pulse_width). Если нужно получить мигание светодиода, то можно либо периодически перезаписывать значение period, устанавливая его то в 0, то в нужное значение, близкое к pulse_width, либо можно сделать период pulse_width достаточно большим, чтобы глаз человека успевал замечать мерцание светодиода, а значение period установить равным половине значения pulse_width.
Реализация на Verilog аппаратуры ШИМ, показанная в Листинге 3, была проверена на процессорной системе Altera Nios с программой, написанной на C, примерно так, как было описано выше. Altera SOPC Builder создает макрос, который упрощает совместную симуляцию проекта в ModelSim, симуляторе аппаратуры от Mentor Graphics. Используя симулятор ModelSim, можно увидеть диаграммы изменения сигналов ШИМ вместе с работой системы при выполнении кода C.
Листинг 4 показывает код C, используемый для генерации формы сигнала на рис. 2. Осциллограммы симулятора показывают поведение подходящих сигналов ШИМ. Код C записывает регистры PWM, чтобы создать выходной сигнал ШИМ с шириной импульса 4. Обратите внимание на начало осциллограммы, где сигналы cs и wr_n устанавливаются дважды - здесь мы записываем регистры period и pulse_width (сигнал адреса находится в лог. 0 при записи регистра period, и в лог. 1 при записи регистра pulse_width).
Листинг 4. Тестовое ПО, используемое для генерации осциллограмм симулятора на рис. 2.
void main(void)
{
PWM* const pLED = BASE_PWM_ADDRESS;
pLED->period = 5;
pLED->pulse_width = 4;
asm("nop");
asm("nop");
asm("nop");
pLED->pulse_width = 2;
}
Рис. 2. Диаграммы аппаратуры PWM, управляемой программным обеспечением.
После того, как новые значения были записаны в регистры, сигнал pwm_output начнет отражать это изменение. Затем в программе на C была добавлена некоторая задержка (инструкциями ассемблера NOP), чтобы можно было увидеть в симуляторе результаты изменения. В конце ширина импульса была изменена на 2 такта, и форма сигнала ШИМ поменяется в соответствии с периодом из 5 тактов.
[Берем лучшее из каждого мира]
Часть разработки встраиваемой системы - рационально разделить её на аппаратную и программную части, чтобы получить максимум выгоды от каждой. По мере развития средств разработки замена программного обеспечения на аппаратное и наоборот становится для разработчика все более прозрачной.
Если Вы поняли концепции, описанные в этой статье, то имеете начальные знания для старта разработки аппаратуры в FPGA, которую можно подключить к микропроцессорной системе в качестве внешней аппаратуры, после чего можно просто программно записывать в неё (или считывать) управляющие параметры (или данные). Поскольку некоторые алгоритмы работают намного быстрее на аппаратуре, чем в программном обеспечении, перевод алгоритма из программы на аппаратуру может значительно ускорить производительность системы и разгрузить процессор, и часто позволяет снизить энергопотребление прибора. Такая модификация системы известна как аппаратное ускорение. Это ключевая функция для процессоров, эффективно реализуемых в программируемой логике. В конце концов даже разработчик ПО имеет право улучшить производительность и эффективность системы с помощью аппаратного ускорения.
[Ссылки]
1. The C Programmers Guide to Verilog site:eetasia.com. 2. Программирование XC2C64A в среде Xilinx ISE WebPack. 3. Введение в Verilog. |