Смекни!
smekni.com

Динамическая поддержка расширений процессора в кросс-системе (стр. 3 из 6)

Обмен данными между процессором и акселераторами осуществляется через разделяемую (общую) память (см. 2.1.1.1). Заметим, что дополнительная информация от процессора к акселератору может также поступать в виде параметров инструкции (см. 2.1.3.1). Заметим, что разные акселераторы не имеют доступа к локальной памяти друг друга.

Разделение доступа к общей памяти в нашей модели соответствует типу CREW (Common Read Exclusive Write). Это означает, что процессор и акселераторы могут одновременно (в рамках текущего такта) читать из ячейки памяти, однако одновременная запись запрещена. В рассматриваемой модели области памяти могут иметь задержку записи, характеризуемую скоростью доступа к памяти (см. 2.1.1.1). По умолчанию, все области памяти имеют задержку 1, то есть изменения могут быть прочитаны только на следующем такте (flip-flop модель). Заметим, что если задержка больше ноля, то возможна одновременная запись и чтение одной и той же ячейки, при чтении считывается предыдущее значение.

Команды акселератора могут занимать фиксированное или переменное (в зависимости от данных) число тактов. С точки зрения прикладного программиста (компилятора) существует три способа синхронизации вычислений основного процессора и результатов работы определенной команды акселератора:

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

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

Частным случаем пункта 2 является вызов акселератором прерывания основного процессора. Обработчик прерывания может прочитать результаты вычислений акселератора.

2.2. Средства описания конкретных моделей акселераторов

Для задания конкретной модели акселератора необходимо определить следующие параметры, множества и функции:

Соответствующие определения были даны в 2.1.1 и 2.1.2, где также было показано, что они однозначно задают все элементы абстрактной модели:

Для описания конкретных моделей акселераторов в ИСП РАН был разработан язык спецификации ISE (Instruction Set Extension). Кроме собственно спецификации соответствующих элементов конкретной модели акселератора (см. выше), в язык также входят средства описания дополнительной информации об ассемблерном синтаксисе команд акселератора, отображении ассемблерных команд в машинные коды и описание форматов для визуализации областей памяти в отладчике. Модель акселератора далее будет отождествляться со спецификацией этой модели на языке ISE.

2.2.1. Дескриптор структуры памяти

Существуют отдельные синтаксические конструкции для описания следующих типов областей памяти:

Памяти данных

Регистровые файлы

Одиночные регистры

С помощью этих конструкций можно задать дескриптор структуры памяти

(см. 2.1.1.1).

Пример. Структура памяти простого акселератора:

две памяти данных LDM и TM размером 2048 слов каждая с разрядностью 16 и 64 бита со скоростью доступа 3 такта

Регистровый файл GRF из двух 16-ти разрядных регистров GR0 и GR1

Одиночный регистр-аккумулятор ACR разрядностью 36 бит

DECLARE_MEMORY(INT(16, 3), 2048) LDM;

DECLARE_MEMORY(INT(64, 3), 2048) TM;

DECLARE_REGISTERS_FILE(INT(16), 2) GRF;

DECLARE_REGISTER(UINT(36)) ACR;

// debugging names and registers file structure

MEMORY(LDM, "Acc LDM");

MEMORY(TM, "Acc TM");

REGFILE_BEGIN(GRF, "General Registers")

REGISTER(0, "GR0");

REGISTER(1, "GR1");

REGFILE_END()

2.2.2. Описание поведения

К семантике поведения акселератора относятся следующие элементы модели mA: множество ресурсов RA, функция ресурсов rA, множество операций ΨA, множество дескрипторов команд IA и функция декодирования dA (вместе с CA).

2.2.2.1. Операции

Для задания операций из ΨA используется язык C++. Ячейки памяти акселератора доступны в качестве глобальных переменных (регистровые файлы и памяти в виде массивов). Для удобства описания могут объявляться собственные локальные переменные. Также могут быть использованы возможности специальной библиотеки (например, N-битные типы данных INT< N>, UINT< N>, типы данных с фиксированной точкой FIXED< I,F>, операции битовых манипуляций и т.п.). Используемые в операции ресурсы обозначаются в виде вызова функции UseResources(resources) (тем самым задается функция rA). В существующей реализации список используемых в данной операции ресурсов передаются в виде битовой строки, где каждый ресурс соответствует определенному биту. Множество ресурсов RA задается в виде перечисления (enum) со значениями элементов по степеням двойки:

enum Resources {MAC_ADDER=1, MAC_MULTIPLIER=2, ALU_ADDER=4};

Пример 1. Операция по сложению двух 36-ти разрядных чисел:

void ADD_36_36(INT<36>& res, INT<36> a, INT<36> b) {

UseResources(MAC_ADDER);

res = a + b;

}

Пример 2. Операция по перемножению двух 16-ти разрядных знаковых чисел:

void SMUL_16_16(INT<32>& res, INT<16> a, INT<16> b) {

UseResources();

res = a * b;

}

Заданная на C++ операция может быть оформлена в виде отдельной функции (см. примеры выше) или встраиваться непосредственно в тело функции поведения команды (см. примеры в 2.2.2.2).

2.2.2.2. Дескрипторы команд

Дескрипторы команд акселератора из IA задаются соответствующими функциями поведения команд. Функция поведения может принимать аргументы в виде параметров инструкции pi. Тем самым одна функция поведения может описывать набор дескрипторов (один дескриптор соответствует одному конкретному набору значений параметров). Тело функции поведения может описываться на языке C++. Отображение в операции для соответствующих значений состояния команды t неявно задается путем использования специальной функции FinishCycle(). Вызовы данной функции отделяют операции внутри функции поведения, относящиеся к последовательным тактам исполнения (значениям параметра t дескриптора команды). Для описания динамического характера выбора операций в зависимости от состояния акселератора (аргумент дескриптора s) в описании функции поведения команды допускается использование управляющих конструкций языка C, в частности циклов и ветвлений (см. пример 3 ниже). Вызов функции FinishCycle() означает окончание всех операций для текущего такта команды и соответствует управляющему действию next. Возврат из функции поведения команды соответствует управляющему действию end. Использо-вание такого решения позволяет эффективно описывать дескрипторы команд, тем самым определяя потактовое поведение команд акселератора.

Пример 1. Однотактовая команда перемещения между регистрами, содержащая единственную операцию, задаваемую конструкцией

GRF[greg] = LRF[lreg]:

ACC_FUNCTION Move_LREG_GREG(INT<4> lreg, INT<4> greg) {

GRF[greg] = LRF[lreg];

FinishCycle();

}

Пример 2. Двухтактовая команда перемножения и аккумуляции результата. На первом такте происходит перемножение операндов (операция SMUL_16_16 - см. пример 2 в 2.2.2.1), на втором аккумуляция результата (операция ADD_36_36 - см. пример 1 в 2.2.2.1):

ACC_FUNCTION MAC_LREG_GREG(INT<4> grs, INT<4> grt) {

SMUL_16_16 (mulres, GRF[grs], GRF[grt]);

FinishCycle();

ADD_36_36 (ACC, ACC, mulres);

FinishCycle();

}

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

Пример 3. Команда свертки векторов, расположенных в памятях DM0 и TM0. Длительность команды зависит от данных (длина векторов задается регистром LOOPREG). Заметим, что в теле цикла за один такт выполняются несколько операций, использующих непересекающиеся ресурсы. Для синхронизации с процессором используется механизм прерывания:

ACC_FUNCTION CONV_ACC_DM0_TM0(INT<4> dreg, INT<4> treg) {

SMUL_16_16 (mulres, DM0[AR[dreg]++], TM0[AR[treg]++]);

FinishCycle();

while (LOOPREG>0) {

ADD_36_36 (ACC, ACC, mulres);

SMUL_16_16 (mulres,

DM0[AR[dreg]++], TM0[AR[dreg]++]);

LOOPREG--;

FinishCycle();

}

ADD_36_36 (ACC, ACC, mulres);

InterruptProcessor();

FinishCycle();

}

2.2.2.3. Функция декодирования

Функция декодирования dA задается описанием множества пар из формата машинного слова команды и ссылки на функцию поведения команды:

INSTRUCTION(< format_string>, < invoker_name>);

Формат машинного слова команды задается строкой в следующем алфавите:

Битовые символы: '0' и '1'

Параметрические символы: 'A-Z' и 'a-z'

Групповой символ: '*'

Разделительный символ: '-'

Символы из пунктов 1-3 называются значимыми символами. Заметим, что число значимых символов в строке формата команды должно быть равно разрядности машинного слова в системе.

Непрерывная цепочка параметрических символов задает операнд. Декодер акселератора выделит указанные биты и передаст полученное значение в функцию поведения команды в виде параметра pi. Различные операнды разделяются групповым или разделительным символом. Операнды нумеруются в порядке справа налево.

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

Пример:

INSTRUCTION("11-**-0000-0000-0001-LREG-GREG", Move_LREG_GREG);

Функция поведения MoveLREG_GREG (см. пример 1 в 2.2.2.1) имеет два параметра по 4 бита каждый (LREG[4;7] и GREG[0;3]). Биты [20;21] могут принимать любые значения для данной команды (в данном примере эти биты относятся к коду акселератора и используются командой запуска акселератора основного процессора). Остальные биты фиксированы и составляют КОП инструкции аскелератора.

Заметим, что совокупность всех строк форматов машинного слова задает множество допустимых кодов инструкций данного акселератора (CA в 2.1.2).