![]() |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() |
Гибридный реконфигурируемый вычислитель. Руководствo программиста. С. С. Андреев, С. А. Дбар, А. О. Лацис, Е. А. Плоткина
Часть 4. Библиотечные компоненты и функции.Настоящая часть Руководства посвящена описанию библиотечных компонентов, представленных в языке Автокод, а также набору функций доступа к пользовательской логике, используемый управляющей программой для обращений к пользовательской логике. Под пользовательской логикой здесь подразумевается основной компонент схемы, ниже называемый просто схемой. Термин интерфейс схемы или интерфейсные регистры схемы означает порты схемы (в скобках указана разрядность порта):
1. Библиотечные компоненты пользовательской логики.Библиотечные компоненты – набор готовых схем, написанных либо на языке VHDL, либо сгенерированных САПР. По своему назначению они делятся на три категории: арифметические, хранящие (компоненты памяти) и компоненты управления интерфейсом. Каждый такой компонент может иметь некоторые параметры данных (разрядность входных и выходных данных, размер хранимого массива памяти и т. п.). К компонентам, уже сгенерированным САПР, относятся только арифметические компоненты, параметры данных в них задаются раз и навсегда во время генерации. Эти компоненты являются уникальными для каждой конкретной реализации базовой платформы. Компоненты памяти и управления интерфейсом написаны на VHDL, они не зависят от конкретной реализации базовой платформы. Параметры данных в них определяются аргументами, задаваемыми при вставке компонента в схему, как параметры генерации. В трансляторе Автокода VHD определены только компоненты памяти, в трансляторе Автокода Stream определены все библиотечные компоненты. Выражение "определены в трансляторе" означает включение данных компонентов в схему автоматически, т.е. при определенных условиях транслятор самостоятельно выполняет следующие действия: вносит в схему заголовок соответствующего компонента, создает переменные доступа к нему и включает в схему соединения портов компонента и переменных доступа к нему. Некоторые библиотечные компоненты не включаются транслятором в схему автоматически, но могут быть включены в нее явно. Использование таких библиотечных компонентов, не определенных в трансляторе, возможно только стандартным способом, а именно: 1. Объявление в разделе деклараций component <имя_компонента> 2. Включение в комбинационной части insert <имя_компонента> gen1 = param1 // параметры генерации, // если они определены в данном компоненте . . . .port1(reg1) // соединения портов с регистрами доступа . . . endinsert Информацию о любом библиотечном компоненте можно получить, воспользовавшись командой: component_info <-(a|b)> [опция] Ключ ‘-a’ >выдает информацию об арифметических компонентах (подробнее об опциях для этих комопнентов в следующей главе). Ключ ‘-b’ выдает информацию о компонентах памяти и управления. Опция может отсутствовать, в этом случае выдается список всех библиотечных компонентов памяти и управления интерфейсом. При указании имени компонента, на экран выводится описание заголовка данного компонента с комментариями. 1.1. Арифметические компоненты.В эту категорию входят компоненты, реализующие арифметические операции с плавающей точкой и некоторые операции с фиксированной точкой. Они либо сгенерированы САПР, либо являются производными от первых. В силу этого, все арифметические компоненты для каждой конкретной реализации базовой платформы уникальны. Арифметические компоненты работают в потоковом режиме, т.е. они на каждом такте способны принимать на вход новые значения операндов и, спустя N тактов, выдавать на каждом такте результаты операции. Величина N называется задержкой или латентностью компонента. Для компонентов, выполняющих поэлементные вычисления, результатом будет тоже поток, по длине равный входным потокам, но сдвинутым, относительно них, на N тактов. Для компонентов, выполняющих операции редукции, результат – одно число (для них задержка – это число тактов между поступлением последнего элемента входного потока и появлением результата операции). Результаты выполнения арифметических операций не должны иметь непосредственный выход на внешний разъем схемы, результаты их работы необходимо предварительно сохранить либо в блоках памяти ram, либо на регистрах. В именах арифметических компонентов фиксируется как разрядность базовой платформы (32, 64, 128), так и величина задержки конкретного компонента – N. Для каждой операции величина задержки может быть своя. Более того, для некоторых арифметических операций сгенерировано более одного компонента, с разной величиной задержки. Ниже приведен перечень арифметических компонентов, имеющих задержку N, для 64-разрядной арифметики:
Последние 4 компонента реализуют операции редукции для массивов данных с фиксированной точкой. Для получения информации о библиотечных арифметических компонентах следует выполнить команду: component_info -a <разрядность|имя_компонента> При задании разрядности – 32, 64 или 128, на экран выдется список всех арифметических компонентов указанной платформенной разрядности. При задании имени компонента (имя можно указывать как полностью, например, floating64_add_5, так и без указания задержки, например, floating64_add), на экран будет выведена полная информация о компоненте или компонентах, реализующих данную арифметическую операцию. Например, в результате выполнения команды: component_info –a floating64_add на экран будет выведена следующая информация: Назначение – сложение двух чисел, плавающий формат. Компоненты: floating64_add_4 // латентность = 4 floating64_add_7 // латентность = 7 Порты: направленность размер имя in 64 a // 1-й операнд in 64 b // 2-й операнд in 0 operation_nd // разрешение записи out 64 result // результат операции out 0 rdy // готовность результата in 0 clk // сигнал тактового генератора 1.2. Компоненты векторной памяти.Данные библиотечные компоненты предназначены для хранения массивов данных в блоках адресуемой оперативной памяти ПЛИС. Написаны они на VHDL, поэтому не зависят от конкретной реализации базовой платформы. Реализованы на базе блоков векторной памяти с двумя независимыми портами. Каждый порт имеет 4 шины: входные и выходные данные, адрес и сигнал разрешения записи. Разрядность входных/выходных данных указывается в объявлении, разрядность адреса = 24 бит, а сигнал разрешения = 1 бит. Режим записи в память: для записи значения по адресу требуется, чтобы на одном и том же такте на шине входных данных оказалось значение, на шине адреса - адрес, а на шире разрешения записи - единица. Записанное значение появится на шине выходных данных на следующем такте. Режим чтения из памяти: для чтения значения по адресу требуется, чтобы на некотором такте на шине адреса оказался адрес, а на шине разрешения записи - ноль. Прочитанное по указанному адресу значение появится на шине выходных данных на следующем такте. Компоненты векторной памяти включаются в схему автоматически, при трансляции объявлений блоков памяти типа ram в разделе деклараций. Объявление имеет вид: ram <SIZE> <name>(<TYPE>, <BL>, <VOL>) где
Значения SIZE, TYPE, BL и VOL используются транслятором для формирования параметров генерации при включении компонентов векторной памяти в схему. На данный момент определены следующие типы памяти. 1.2.1. Тип ramb – компонент HI_RAMB.Компонент реализован в виде двухпортового блока памяти с двумя независимыми портами 'a' и 'b'. Набор регистров доступа к памяти name типа ramb следующий: порт 'a':
порт 'b':
Данный компонент памяти является базовым, никаких ограничений на характер использования портов не накладывается, но в языке Автокод Stream предпочтительнее для записи данных использовать порт ‘a’. 1.2.2. Тип rams — компонент HI_RAMS_1p.Данный компонент является модификацией базового компонента HI_RAMB, в который добавлен еще один порт, позволяющий разделить обращение к памяти со стороны схемы (порты 'a' и 'b') с обращением со стороны входного интерфейса схемы (порт 'c').Порты ‘a’ и ’b’ имеют тот же набор регистров доступа, что и для типа ramb. Набор регистров доступа для порта ‘c’ следующий:
При записи схемы на Автокоде Stream все соединения регистров доступа компонента с интерфейсными регистрами схемы транслятор формирует самостоятельно. Имя памяти name должно быть указано в объявлении объекта “Memory”. Тип памяти rams следует использовать в схеме, кодгда обращения к памяти со стороны управляющей программы и со стороны схемы не пересекаются. При наличии единицы на регистрах name.enc или name.wec, внутрисхемное обращение к памяти блокируется. 1.2.3. Тип rams2 — компонент HI_RAMS_2p.По назначению и по набору регистров доступа совпадает с типом rams. Различие состоит в том, что данный компонент используется в схеме, когда разрядность данных, которые необходимо принять от управляющей программы или выдать в управляющую программу, равна половине платформенной разрядности. Например, при платформенной разрядности, равной 64, в схему необходимо записать массив данных формата int. В этом случае на каждом такте поступления данных в схему, в блоки памяти приходится записывать не 1, а 2 слова. 1.2.4. Тип ramd — компонент HI_RAMD_1p.Компонент является модификацией базового компонента HI_RAMB, в который добавлен дополнительный порт ‘c’ для коммуникаций с интерфейсными регистрами схемы. Тип памяти ramd предназначен для работы схемы в режиме подкачки: имеет двойную буферизацию, позволяющую совмещать обработку данных в схеме (внутренние обращения) с обменами данных между схемой и управляющей программой (внешние обращения). В каждый момент времени один буфер отдается внутрисхемной работе, а другой – обменам данными с управляющей программой. Наличие двойной буферизации в данном компоненте означает, что фактически объем резервируемой памяти будет в два раза больше заявленной. Тип памяти ramd имеет такой же набор регистров доступа, что и rams, но на регистр доступа name.enc подается не признак чтения, а сигнал переключения буферов памяти name. Данный сигнал формируется в основном компоненте управления интерфейсом SEL_INIT (порт ram_ticker), значение сигнала определяет, какой буфер памяти будет отдан внутрисхемной работе, а какой – работе с управляющей программой. При записи схемы на Автокоде Stream все соединения регистров доступа компонента с интерфейсными регистрами схемы транслятор формирует самостоятельно. Имя памяти должно быть указано в объявлении объекта “Memory”. 1.2.5. Тип ramd2 — компонент HI_RAMD_2p.Данный тип памяти предназначен для работы схемы в режиме подкачки, как и тип ramd, но используется для обмена с управляющей программой короткими словами (по аналогии с типом rams2). 1.3. Компоненты управления интерфейсом схемы.К этой категории относятся два компонента: SEL_INIT и BLOCKREG. Написаны они на VHDL, поэтому не зависят от конкретной реализации базовой платформы. Компоненты управления интерфейсом схемы предназначены для передачи данных из процессора в схему и обратно некоторым унифицированным образом. Для языка Автокод Stream был разработан протокол передачи данных с использованием регистров A и B. Этому протоколу следуют как управляющая программа, так и схема на Автокоде Stream. Со стороны управляющей программы протокол реализован в специальных функциях доступа. Со стороны схемы – компонентами управления интерфейсом. В общих чертах протокол взаимодействия заключается в следующем:
1.3.1. Описание компонента SEL_INIT.// параметры генерации: data_width // разрядность базовой платформы count_reg // число регистров, определенных в объекте “Register” count_ram // число блоков памяти ram, определенных в объекте “Memory” ram_size // двоичный>логарифм count_ram // перечень портов компонента с указанием направленности и разрядности: out 0 inic // выдача сигнала запуска рабочего цикла схемы out 32 par0 // выдача скалярного параметра argv[0] out 32 par1 // выдача скалярного параметра argv[1] out 32 par2 // выдача скалярного параметра argv[2] in data_width regA // прием данных с регистра REG_IN_A in data_width regB // прием данных с регистра REG_IN_B in 2 maskA // прием признака записи REG_WE_A in 2 maskB // прием признака записи REG_WE_B out 1 point_reg // выдача признака записи в блок параметров out count_ram point_in // дешифратор номеров памяти для записи данных out count_ram point_out // дешифратор номеров памяти для чтения данных out count_ram ram_ticker // переключатель буферов памяти в режиме подкачки in 0 Clk // сигнал тактового генератора in 0 Reset // сигнал начального сброса При записи схемы на Автокоде Stream данный компонент включается в схему автоматически. Предназначен для управления и коммутации данных, связанных с интерфейсными регистрами схемы:
Если в объявлении “Memory” нет массивов памяти типа ramd или ramd2, то данный порт игнорируется. 1.3.2. Описание компонента BLOCKREG.// параметры генерации: data_width // разрядность базовой платформы block_size // векторность блока параметров // перечень портов компонента с указанием направленности и разрядности: in data_width DI // прием данных с регистра DI out data_width*block_size DO // выходные данные in 1 PBR // признак обращения к блоку регистров, // берется с point_reg компонента SEL_INIT in 1 WEBR // признак записи данных WE in 0 Clk // сигнал тактового генератора Компонент предназначен для приема на векторный регистр argvblock(N) блока скалярных параметров. При записи схемы на Автокоде Stream данный компонент включается в схему автоматически при объявлении: BlockRegister::(a1, a2, …, aN)или BlockRegister::(N) Поскольку в языке VHDL порты компонента должны быть определены явно, и их количество нельзя задавать с помощью параметров генерации, то в данном компоненте все выходные параметры-скаляры объединены в один порт DO, разрядность которого задается в зависимости от их количества параметром генерации block_size. При включении данного компонента в схему порт DO подается на векторный регистр платформенной разрядности argvblock(N) при помощи функции join. Например, для платформенной разрядности=64 и количестве параметров=4, запись включения компонента BLOCKREG в схему имеет вид: reg 64 argvblock(4) // объявление в разделе деклараций векторного регистра и reg 1 avt_point_reg // регистра доступа к порту point_reg компонента SEL_INIT . . . . . insert BLOCKREG data_width = 64 block_size = 4 .DI(DI) .DO(255:0)(join(argvblock)) .PBR(avt_point_reg) .WEBR(WE) .Clk(Clk) endinsert Для передачи блока параметров со стороны процессора необходимо пользоваться функцией logic_put_block_reg(). Число передаваемых в блоке параметров должно быть строго фиксированным для данной задачи, передавать в схему всегда надо полный блок. 2. Функции доступа к пользовательской логике.Для передачи данных в схему и приема данных из схемы управляющая программа использует функции доступа к пользовательской логике. На стороне процессора определены 2 базовых типа данных:
Для 32-разрядной платформы:
Для 64-разрядной платформы:
Для 128-разрядной платформы:
При передаче скалярных параметров для всех трех типов платформ определены макросы упаковки данных, отключающие автоматическое преобразование типов при компиляции:
дополнительно для 128-разрядной платформы:
Весь набор функций доступа к пользовательской логике можно разделить на три категории: общего назначения, базовые и специальные. Функции общего назначения – это функции общей инициализации и управления. Они используются при написании схем и на Автокоде VHD, и на Автокоде Stream. Базовые функции – это функции обмена данными нижнего уровня, не зависящие от организации управления интерфейсом в пользовательской логике, используются только при написании схем на Автокоде VHD. Специальные функции созданы для реализации описанного выше протокола взаимодействия управляющей программы и схемы. При записи схемы на Автокоде Stream в программе надо использовать именно этот набор функций. 2.1. Функции общей инициализации и управления.Инициализация набора ускорителей:int init_coprocessor(int from, int to) Инициализировать и подготовить к использованию в данном процессе управляющей программы ускорители с номерами от from до to включительно. При успешном срабатывании возвращает 0. Текущим становится ускоритель с номером from. В схеме ничего не происходит. Выбор текущего ускорителя:void set_coprocessor(int current) Все последующие обращения к функциям передачи данных будут относиться к ускорителю номер current. Номер – глобальный, среди всех ускорителей данного компьютера, а не среди инициализированных данным процессом. В схеме ничего не происходит. Опрос текущего астрономического времени в секундах:double cputime(void) 2.2. Базовые функции доступа.Запись в память схемы:void to_coprocessor(int addr, void *data, int len)
Чтение из памяти схемы :void from_coprocessor(int addr, void *data, int len)
Функции записи в регистр :void to_register(int reg, WORD val)
void to_register_int(int reg, int val)
void to_register_masked(int reg, int nbit, WORD val)
void to_register_masked_int(int reg, int nbit, int val)
ЗАМЕЧАНИЕ. Номер сигнала готовности в программе соответствует в схеме номеру разряда в сигнале разрешения записи в регистр, считая младший разряд нулевым. Если в программе активирован нулевой сигнал, в схеме регистр разрешения записи будет равен единице, если первый - двум. Функции чтения из регистра:void from_register(int reg, WORD *res)
void from_register_int(int reg, int *res )
Значения аргумента reg в функциях обращения к регистрам – 6 или 7, что соответствует регистрам A или B во внешнем разъеме пользовательской логики. Функции с окончанием _int используются при работе с платформенной разрядностью 64 или 128. 2.3. Специальные функции доступа.Функции управления:void logic_init(int val)
void logic_wait( int tim, int *ans )
Функции обращения к регистрам схемы:void logic_put_block_reg( void *par, int count )
void logic_register( int addr, int val )
void logic_result( WORD *res )
Запись в память схемы:void logic_put(int ram, int addr, void *data, int len)
void logic_put_strided(int ram, int addr, void *data, int width, int height, int row)
Чтение из памяти схемы :void logic_get(int ram, int addr, void *data, int len)
void logic_get_strided( int ram, int addr, void *data, int width, int height, int row)
void logic_last_get( int ram, int addr, void *data, int len )
|
![]() |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Тел. +7(499)220-79-72; E-mail: inform@kiam.ru |