Работа с DSP-ядрами
В документе приводится перечень DSP-ядер, используемых в процессорах серии «Мультикор», поясняются принципы работы с ними. Разъясняется взаимодействие CPU и DSP. Приведены примеры проектов для отладочной среды MCStudio 3M.
DSP-ядра процессоров серии «Мультикор»
DSP-ядра в составе процессоров серии «Мультикор» - разработка АО НПЦ «ЭЛВИС» и имеют обозначение ELcore-xx.
Перечень существ ующих ядер DSP
- ELcore-14 (в микросхеме 1892ВМ3Т),
- ELcore-24 (в микросхеме 1892ВМ2Я),
- ELcore-26 (в микросхемах 1892ВМ8Я, 1892ВМ5Я),
- ELcore-28 (в микросхеме 1892ВМ7Я),
- ELcore-30M (в микросхемах 1892ВМ10Я, 1892ВМ14Я, 1892ВМ15АФ).
- ELcore-50 (в микросхеме СКИФ).
DSP-ядра могут объединяться в кластеры. Например, ELcore-30M во всех чипах, в которых они присутствуют, объединены в кластеры DELcore-30M из двух таких ядер. Четыре ядра ELcore-28 - в кластер QELcore-28 в микросхеме 1892ВМ7Я. Ядро ELcore-26 в микросхеме 1892ВМ8Я в единственном экземпляре, а в 1892ВМ5Я их два.
Документы, рекомендуемые для ознакомления
- DSP-кластер DELcore-30M. Архитектура
- DSP-кластер DELcore-30M. Архитектура. Приложение 1. Базовая система инструкций
- DSP-кластер DELcore-30M. Архитектура. Приложение 2. Расширение системы инструкций
- Спецификация архитектурных отличий 2-ядерного DSP-кластера DELcore-30М
- DSP-ядро ELcore-30M. Перечень выявленных ограничений
- DSP-ядро ELcore-x4. Система инструкций
- DSP-ядро ELcore-26. Система инструкций
- Компилятор С/С++ Clang для DSP ELcore-30М. Руководство пользователя
- Компилятор С/С++ Clang для DSP ELcore-30M. Соглашение о вызовах
- MC Studio. Инструменты ядра DSP
- Микросхема интегральная 1892ВМ10Я. Руководство системного программиста «Прикладная библиотека»
- Компилятор C/С++ для процессора сигнальной обработки ELcore-50. Руководство программиста
- DSP-ядро Elcore50. Руководство пользователя блока VDMA
- DSP-ядро Elcore50. Руководство пользователя блока VMMU
- Elcore50. Список команд
- Техническое описание IP-блока EVENT_CTRL для DSP-ядра ELcore50
- DSP-ядро Elcore50. Руководство программиста
- Набор библиотек для DSP ELcore-50
Основные общие параметры
Общими особенностями DSP-ядер процессоров серии «Мультикор» являются гарвардская архитектура с внутренним параллелизмом по потокам обрабатываемых данных и их предназначение для вычислений и обработки информации в форматах с фиксированной и с плавающей точкой, поддержка инструкций с длинным командным словом (VLIW - Very Long Instruction Word) и возможность упаковки нескольких скалярных операций в одну команду.
Основные различия
Различия DSP-ядер представлены в сводной таблице, приведенной ниже.
Основные архитектурные характеристики DSP-ядер процессоров серии «Мультикор»
Тип DSP | Число SIMD секций в DSP | Число фаз конвейера | Значение IDR | Память программ (PRAM) | Память данных (XRAM,YRAM) |
---|---|---|---|---|---|
ELcore-14 | 1 | 3 | 0x0003 | PRAM 4Kx32 | XRAM-24Kx32 YRAM-12Kx32 |
ELcore-24 | 2 | 3 | 0x0013 | DSP0: PRAM 4Kx32 DSP1: PRAM 4Kx32 | XRAM-32Kx32 YRAM-12Kx32 |
ELcore-26 | 2 | 4 | 0x0115 | DSP0: PRAM 4Kx32 DSP1: PRAM 4Kx32 | DSP0 XRAM-8Kx32 YRAM-8Kx32 DSP1 XRAM 8Kx32 YRAM 8Kx32 |
ELcore-28 | 1 | 7 | 0xn309* | DSP0: PRAM 8Kx32 DSP1:PRAM 8Kx32 DSP2:PRAM 8Kx32 DSP3:PRAM 8Kx32 | DSP0 XYRAM 32Kx32 DSP1 XYRAM 32Kx32 DSP2 XYRAM 32Kx32 DSP3 XYRAM 32Kx32 |
ELcore-30M | 1 | 7 | 0xn108* | PRAM 4Kx32 | DSP0 XYRAM32Kx32 DSP1 XYRAM 32Kx32 |
n * - номер ядра
С системой инструкций и составом программно-доступных регистров можно ознакомиться в документах, представленных ниже: («DSP-кластер DELcore-30M.Архитектура», Базовая система инструкций Расширение системы инструкций). Сравнительные значения пиковой производительности DSP-ядер приведены в таблице ниже.
Таблица 2. Сравнительная таблица пиковой производительности DSP-ядер процессоров серии
DSP | ELcore-14 | ELcore-24 | ELcore-26 | ELcore-30M |
---|---|---|---|---|
Пиковая производительность по смеси арифметических операций (умножения, сложения, вычитания) | ||||
16-разр. фиксированная точка, оп/такт | 8 | 16 | 32 | 64 |
32-разр. плавающая точка, оп/такт | 3 | 6 | 12 | 16 |
32-разр. фиксированная точка, оп/такт | 4 | 8 | 16 | 16 |
8-разр. фиксированная точка, оп/такт | 18 | 36 | 82 | 96 |
Пиковая производительность по операции МАС (умножение + накопление) | ||||
16-разр. фиксированная точка, оп/такт | 2 | 4 | 8 | 16 |
32-разр. плавающая точка, оп/такт | 1 | 2 | 4 | 4 |
32-разр. фиксированная точка, оп/такт | 1 | 2 | 4 | 4 |
Пиковая производительность по операции СМАС (комплексное умножение с накоплением) | ||||
16-разр. фиксированная точка, оп/такт | — | — | — | 16 |
8-разр. фиксированная точка, оп/такт | 1 | 2 | 4 | 4 |
Взаимодействие CPU и DSP
Управление кластером DSP осуществляется CPU. DSP стартует «по команде» CPU (тогда как CPU стартует сразу по снятию сигнала Reset с микросхемы).
Для синхронизации работы DSP-ядер в кластере предусмотрено два механизма: механизм прерываний и механизм обменов через XBUF в синхронном режиме. При одновременном запросе на запись в одну и ту же ячейку буфера обмена XBUF приоритет отдается CPU.
DSP-ядра версий, созданных ранее ELcore-30M, не имели доступа к памяти за пределами XYRAM, в этом их возможности были ограничены. ELcore-30M может обращаться ко всем ресурсам процессора (внешняя и внутренняя памяти, регистры периферийных устройств). В целях совместимости адресация внутренней памяти DSP-кластера осталась без изменений.
Старт DSP-ядер
Регистр управления и состояния CSR_DSP доступен по чтению и записи и содержит биты управления кластером DSP-ядер. Запись «1» в разряд SYNSTART приводит к одновременному запуску DSP-ядер. Регистр управления и состояния DCSR содержит разряды управления, определяющие состояние и режим работы DSP-ядра, а также прерывания, формируемые DSP-ядром для обработки в RISC-ядре. Для запуска ядра необходимо записать «1» в бит «RUN» состояния исполнения программы. Пример запуска DSP-ядра см. в примере кода.
Каждое DSP-ядро может сформировать прерывание для другого ядра. Ядро, получившее прерывание, переходит в состояние «RUN», если было остановлено, и начинает исполнение подпрограммы, адрес которой хранится в специальном регистре этого ядра.
Доступ DSP-кластера к ресурсам процессора
Адресное пространство DSP находится в диапазоне адресов 0х00000000 – 0х000FFFFF при пословной адресации, которая применяется в ядрах DSP, что соответствует диапазону 0х00000000 – 0х003FFFFC при побайтовой адресации, используемой в адресном пространстве всей системы на кристалле.
Таким образом, обращаясь к адресам адресного пространства DSP (0х00000000 – 0х000FFFFF - пословная), ядро выполняет обращение к внутренней памяти кластера. В этом случае обращения в зависимости от адреса и номера DSP ядра могут направляться либо в ближний сегмент памяти данного ядра (быстрые обращения), либо в дальний сегмент памяти другого ядра (обращения через коммутатор кластера).
При обращениях к старшим адресам адресного пространства, лежащим вне адресного пространства DSP (0х000FFFFF - 0хFFFFFFFF в системе адресов DSP), обращение от DSP-ядра перенаправляется на глобальный коммутатор AXI и может быть направлено к любому адресуемому регистру или ячейке памяти, заисключением диапазона 0х00000000 – 0х003FFFFC (в системе адресов RISС-ядра). Важной особенностью внешних обращений DSP, о которой необходимо помнить программисту, является тот факт, что при переходе из адресного пространства DSP с пословной адресацией в глобальное пространство с побайтовой адресацией выполняется аппаратный сдвиг значения адресного указателя на 2 бита влево. Так, например, обращение DSP-ядра по значению A0 = 0x07F00001 приведет к обращению по физическому адресу 0x1FC00004.
DSP-кластер не имеет устройства управления памятью (MMU), поэтому работает с физическим, а не виртуальным адресом.
DSP адресует память 32-х разрядными словами, поэтому реальный физический адрес внешнего обращения получается сдвигом влево на два разряда текущего значения адресного указателя.
Примеры проектов, работающих с DSP-ядрами
Примеры ниже описывают работу с ядром ELcore-30M в составе микросхемы 1892ВМ10Я. Работа с другими ядрами и/или другими микросхемами осуществляется по схожим принципам, но имеет отличия в соответствии с особенностями архитектуры конкретного ядра и конкретной микросхемы.
Работа DSP-ядра под управлением CPU
В данной главе рассматривается пример вычисления DSP-ядром суммы двух величин. После выполнения вычисления DSP-ядро останавливается, устанавливается флаг в регистре запросов прерываний QSTR_DSP. В следующем фрагменте текста представлен код, выполняемый CPU-ядром.
Символы, используемые в DSP-ядре, но к которым нужен доступ из программы CPU, объявляются в коде CPU
как extern
:
#include "memory_nvcom_02t.h"
// Адрес начала программы DSP-ядра
extern int Start_DSP;
// Входные параметры - числа, которые DSP складывает
extern int InA;
extern int InB;
// Результат
extern int OutC;
main()
{
int InputA=5;
int InputB=2;
int OutputC;
// обнуляем управляющие регистры ядра DSP0
DCSR(0) = 0;
Далее производятся следующие действия:
- В программный счетчик ядра DSP0 кладется адрес начала программы DSP.
- Адрес для DSP0 получается из адреса программы DSP в адресном пространстве CPU-ядра вычитанием адреса начала PRAM0 – памяти программ ядра DSP0.
- Аналогично получаются адреса переменных – только вычитанием адреса памяти данных DSP0.
- Происходит сдвиг вправо на два байта – это деление на 4, так как у DSP-ядер словная адресация, а в CPU-ядре – байтовая.
PC(0)=((unsigned int)&Start_DSP - 0xb8440000)>>2;
A0(0)=((unsigned int)&InA - 0xb8400000)>>2;
A1(0)=((unsigned int)&InB - 0xb8400000)>>2;
A2(0)=((unsigned int)&OutC- 0xb8400000)>>2;
// записываем значения входных переменных в память DSP-ядра
InA=InputA;
InB=InputB;
// Запуск ядра DSP0 на исполнение записью бита DCSR0[14]
DCSR(0) = 0x4000;
Когда ядро DSP0 закончит исполнение программы, оно выполнит инструкцию «STOP». После выполнения данной инструкции DSP-ядро останавливается и выставляет бит DCSR0[3], который транслируется в QSTR_DSP[3]. Если при этом в единице будет бит MASKR_DSP[3] будет выставлен в «1», и будут разрешены прерывания от внутренних устройств процессора, произойдет прерывание. В данном примере происходит ожидание установки бита QSTR_DSP[3].
while( !(QSTR_DSP & (1<<3)) ) ;
Результат из памяти DSP-ядра в память CPU-ядра:
OutputC=OutC;
while (1);
} ;
Далее – код на ассемблере с инструкциями, выполняемыми DSP-ядром.
.text
Метки, которые должны использоваться за пределами данного файла (в рассматриваемом случае – CPU-ядром), должны объявляться глобальными:
.global Start_DSP
.global InA
.global InB
.global OutC
Start_DSP:
В регистр R0 кладется значение по адресу, на который указывает A0 (InA)
MOVE (A0),R0.L
В регистр R2 - значение по адресу, на который указывает A1 (InB)
MOVE (A1),R2.L
Сложение:
ADDL R2.L,R0.L; результат кладем по адресу A2 (OutC)
MOVE R0.L,(A2); все
STOP .data
InA: .word 0
InB: .word 0
OutC: .word 0
.end
Рисунок 1 иллюстрирует размещение адресов сегментов данных и кода в данном примере.

Работа двух DSP-ядер под управлением CPU
Ниже приведен пример проекта, который демонстрирует взаимодействие между CPU и двумя DSP-ядрами. CPU передает ядрам DSP0 и DSP1 по два числа, которые складываются друг с другом средствами DSP-ядер. Результат сохраняется в переменные DSP0_OutputC и DSP1_OutputC соответственно. Алгоритм проекта следующий:
- Задаются значения входных переменных.
- Настраиваются регистры DSP0 и DSP1.
- В регистр PC ядра DSP0 заносится адрес функции, производящей вычисление (DSP0_calculate()).
- Аналогично для DSP1.
- Запуск DSP0, запуск DSP1.
- По очереди ожидается событие останова DSP ядер.
- Передача вычисленных значений в переменные, расположенные в области памяти CPU-ядра.
Код для CPU:
/*********************************************************************
* CPU_DSP0_DSP1
* Демонстрирует взаимодействие между CPU- и DSP-ядрами
* Передает ядру DSP0 и DSP1 два числа, которые складываются
* средствами DSP-ядер. Результат сохраняется в переменные
* DSP0_OutputC и DSP1_OutputC соответственно
**********************************************************************/
#include "memory_nvcom_02t.h"
extern unsigned int DSP0_In_A;
extern unsigned int DSP0_In_B;
extern unsigned int DSP0_Out_C;
extern unsigned int DSP0_calculate;
extern unsigned int DSP1_In_A;
extern unsigned int DSP1_In_B;
extern unsigned int DSP1_Out_C;
extern unsigned int DSP1_calculate;
int main() {
unsigned int DSP0_InputA = 5;
unsigned int DSP0_InputB = 2;
unsigned int DSP0_OutputC;
unsigned int DSP1_InputA = 6;
unsigned int DSP1_InputB = 3;
unsigned int DSP1_OutputC;
DSP0_In_A = DSP0_InputA;
DSP0_In_B = DSP0_InputB;
DSP1_In_A = DSP1_InputA;
DSP1_In_B = DSP1_InputB;
// настройка регистров DSP0
DCSR(0) = 0;
SR(0) = 0;
// настройка регистров DSP1
DCSR(1) = 0;
SR(1) = 0;
// занесение в регистр PC ядра DSP0 адреса функции DSP0_calculate()
// память PRAM ядра DSP0 в адресном пространстве CPU-ядра начинается с // адреса 0xb844_0000
PC(0) = ((unsigned int) &DSP0_calculate - 0xb8440000) >> 2;
// занесение в регистр PC ядра DSP1 адреса функции DSP1_calculate()
// память PRAM ядра DSP1 в адресном пространстве CPU-ядра начинается с // адреса 0xb884_0000
// &DSP1_calculate - адрес функции в адресном пространстве CPU-ядра
// делим адрес на 4 (сдвиг на 2 бита вправо)
PC(1) = ((unsigned int) &DSP1_calculate - 0xb8840000) >> 2;
// запуск DSP0
DCSR(0) = 0x4000;
// запуск DSP1
DCSR(1) = 0x4000;
// Разряд QSTR_DSP[3] устанавливается в «1», если DSP0 выполнило STOP
while ((QSTR_DSP & 0x8)==0);
DSP0_OutputC = DSP0_Out_C;
// Разряд QSTR_DSP[11] устанавливается в «1», если DSP1 выполнило STOP
while ((QSTR_DSP & 0x800)==0);
DSP1_OutputC = DSP1_Out_C;
while (1);
return 0;
}
Далее – код на ассемблере с инструкциями, выполняемыми DSP-ядром DSP0:
.global DSP0_calculate
.global DSP0_In_A
.global DSP0_In_B
.global DSP0_Out_C
.text
DSP0_calculate:
MOVE DSP0_In_A,A0.S
MOVE DSP0_In_B,A1.S
MOVE DSP0_Out_C,A2.S
MOVE (A0),R0.L
MOVE (A1),R2.L
ADD R0,R2,R0
MOVE R0.L,(A2)
STOP
nop
nop
.data
DSP0_In_A: .word 0
DSP0_In_B: .word 0
DSP0_Out_C: .word 0
Далее – код на ассемблере с инструкциями, выполняемыми DSP-ядром DSP1:
.global DSP1_calculate
.global DSP1_In_A
.global DSP1_In_B
.global DSP1_Out_C
.text
DSP1_calculate:
MOVE DSP1_In_A,A0.S
MOVE DSP1_In_B,A1.S
MOVE DSP1_Out_C,A2.S
MOVE (A0),R0.L
MOVE (A1),R2.L
ADD R0,R2,R0
MOVE R0.L,(A2)
STOP
nop
nop
.data
DSP1_In_A: .word 0
DSP1_In_B: .word 0
DSP1_Out_C: .word 0
В кластере DELcore-30M память XYRAM для обеих DSP-ядер – общая. То есть, если производить запись или чтение по одинаковому адр есу из DSP0 и DSP1, то произойдет обращение к одной и той же ячейке памяти. Поэтому в настройках проекта («Options → Section») добавлено поле «Offset» для смещения секций данных для разных ядер.

Приведённый ниже рисунок иллюстрирует, по каким адресам в данном случае располагаются переменные (DSP0_In_A, DSP0_In_B, DSP0_Out_C, DSP1_In_A, DSP1_In_B,DSP1_Out_C).

Поскольку в данном случае поле DSP offset не используется, все переменные находятся в ближней для DSP0 области XYRAM. Для того чтобы расположить переменные DSP1_In_A, DSP1_In_B, DSP1_Out_C в области XYRAM ближней к DSP1 необходимо задать для них смещение 0x8000.
Демонстрация инструкций VLIW
VLIW (англ. very long instruction word — «очень длинная машинная команда»). Характеризуется тем, что одна инструкция процессора содержит несколько опера ций, которые должны выполняться параллельно. Параллельное выполнение инструкций возможно за счёт параллельного использования двух операционных устройств и двух коммутаторов данных. Длинная команда на входе процессора разделяется на 4 коротких. Каждая из 4 коротких команд предназначена для конкретного блока.
Вычислительные команды выполняются двумя операционными блоками OP1, OP2. Блоки OP1 и OP2 имеют различный набор вычислительных элементов. Некоторые инструкции могут быть выполнены только блоком OP1, некоторые только OP2. Часть инструкций может быть выполнена, как блоком OP1, так и блоком OP2. Возможность исполнения команды конкретным операционным блоком следует уточнить в документе Приложение 1. Базовая система инструкций.
При использовании двух команд пересылки, одна из команд должна выполнять пересылку данных из адреса, записанного в регистре Ax в регистр общего назначения, а другая из адреса, записанного в регистр AT в регистр R0.
Вычислительные инструкции могут быть выполнены параллельно если:
- Результат одной не зависит от результата другой;
- В длинной инструкции отсутствуют две инструкции которые могут быть выполнены только на одном операционном устройстве.
Приведенные ниже примеры кода демонстрируют лишь саму суть VLIW-инструкций, с точки зрения осмысленности приведенные сочетания операций оценивать не надо.
Две вычислительные инструкции
В этом разделе приведен пример параллельного выполнения DSP-ядром инструкций умножения и выбора наибольшего значения.
.text
.global Start_DSP
.global InA
.global InB
.global OutC
.global OutD
Start_DSP:
;в регистр R0 кладется значение по адресу, на который указывает A0 ;(InA),5
MOVE (A0),R0.L
; в регистр R2 - значение по адресу, на который указывает A1 (InB), 2
MOVE (A1),R2.L
; регистр R8 обнуление
MOVE 0,R8.L
; параллельно умножение и выбор наибольшего значения
MPUU R0,R2,R0.L MAX R0,R2,R8
; результат поиска максимума кладется по адресу A2 (OutC)
MOVE R8.L,(A2)
; результат поиска произведения кладется по адресу A3 (OutD)
MOVE R0.L,(A3)
Далее в коде выполняется переход DSP-ядра в состояние останова:
STOP
.data
InA: .word 0
InB: .word 0
OutC: .word 0
OutD: .word 0
.end