NXP i.MX7D  программируемый сопроцессор ввода - вывода

Итак, вы написали программу для одного или нескольких каналов SDMA. Ассемблировали в бинарник.
Теперь необходимо загрузить его в память и стартовать на выполнение. Поехали.


	@ Работа практически любого модуля
	@ Начинается с тактирования
	MOV32 R0, CCM_BASE + CCGR72 @ SDMA clock gate
	SER R1
	STR R1, [R0]

	@ Базовый адрес SDMA
	MOV32 R0, SDMAARM_BASE

	@ Назначить приоритеты тем каналам
	@ Которые планируется использовать
	@ В диапазоне от 1 (младший) до 7 (старший)
	@ Чем выше номер, тем больше шансов получит канал
	MOV R1, 1 @ Номер приоритета
	STR R1, [R0, SDMA_CHNPRI0] @ Канал 0
	MOV R1, 2 @ Номер приоритета
	STR R1, [R0, SDMA_CHNPRI1] @ Канал 1
	MOV R1, 3 @ Номер приоритета
	STR R1, [R0, SDMA_CHNPRI2] @ Канал 2

	@ На этих каналах
	@ Активация будет только ручная
	MOV R1, 1<<0 + 1<<1 @ Нулевой и первый
	STR R1, [R0, EVTOVR]

	@ На этих каналах
	@ Активация будет только по прерываниям
	MOV R1, 1<<2 @ Второй канал SDMA
	STR R1, [R0, HOSTOVR]

	@ Настроить приём внешних прерываний
	MOV R1, 1<<2 @ На втором канале SDMA
	STR R1, [R0, CHNENBL31] @ Линия 31 (UART5 Tx FIFO)
	@ Можно подключить к любому каналу
	@ До 48 источников внешних событий (прерываний)


	@ =======================
	@ Загрузка программ в SDMA
	@ =======================

	@ Перейти в режим static
	LDR R1, [R0, SDMAARM_CONFIG]
	BIC R1, 0b11 << CSM
	STR R1, [R0, SDMAARM_CONFIG]

	@ Адрес листинга CCB
	MOV32 R1, CCB0
	STR R1, [R0, MC0PTR]

	@ Загрузить программы в память SDMA
	MOV R1, 1 << 0 @ Через нулевой канал
	STR R1, [R0, HSTART] @ Стартовать
	@ Дождаться завершения
	1:
	LDR R1, [R0, STOP_STAT]
	TST R1, 1
	BNE 1b @ если =1, значит ch0 ещё работает
		
Программы загружены. А вот с контекстами придётся повозиться. Мне так и не удалось реализовать загрузку контекстов через ch0. Поэтому был использован отладочный порт OnCE. Этот метод рекомендуется и в референсном мануале.

Кстати, метод OnCE позволит в будущем перестроить ch0 на выполнение любых ваших программ. Для этого просто загрузите в ch0 новый регистровый контекст. И вы получите в своё распоряжение все 32 канала! Проверено, работает!

	@ =======================
	@ Загрузка контекстов в SDMA
	@ =======================

	@ Войти в отладку OnCE
	MOV R1, 1
	STR R1, [R0, ONCE_ENB]
	@ Запросить режим отладки
	MOV R1, 5 @ 5=debug_rqst
	STR R1, [R0, ONCE_CMD]


	@ Цикл загрузки контекстов
	@ Один проход цикла загружает 1 слово в память контекстов
	@ И состоит из четырёх команд
	MOV32 R2, Контекст_sdma_01 @ Базовый адрес
	CLR R3 @ Обнулить счётчик загруженных слов

	1:
	@ Команда R1 <-> DATA
	MOV32 R1, 0x0800 + 24 * 1 @ Адрес во внутренней памяти sdma
	ADD R1, R3 @ Добавить смещение
	STR R1, [R0, ONCE_DATA] @ Поместить в порт DATA
	MOV R1, 1 @ Команда 1=dmov
	STR R1, [R0, ONCE_CMD] @ И переместить в R1
	@ Выполнить инструкцию MOV R0, R1
	MOV32 R1, 0x00000089 @ Код инструкции
	STR R1, [R0, ONCE_INSTR] @ Поместить в порт INSTR
	MOV R1, 2 @ 2=exec_once
	STR R1, [R0, ONCE_CMD] @ И выполнить её
	@ Команда R1 <-> DATA
	LDR R1, [R2], 4 @ Взять одно слово данных
	STR R1, [R0, ONCE_DATA] @ Поместить в порт DATA
	MOV R1, 1 @ Команда 1=dmov
	STR R1, [R0, ONCE_CMD] @ И переместить в R1
	@ Выполнить инструкцию ST R1, (R0, 0)
	MOV32 R1, 0x00005900 @ Код инструкции
	STR R1, [R0, ONCE_INSTR] @ Поместить в порт INSTR
	MOV R1, 2 @ 2=exec_once
	STR R1, [R0, ONCE_CMD] @ И выполнить её
	@ Счётчик загруженных слов
	INC R3 @ Увеличить на 1 слово
	CMP R3, 24*2 @ Загружаем 48 слов, для двух каналов
	BNE 1b @ Переход, если счётчик != 48


	@ Последний шаг
	@ Активировать SDMA
	MOV R1, 3 @ 3=run_core
	STR R1, [R0, ONCE_CMD]

	@ Завершить сеанс OnCE
	CLR R1
	STR R1, [R0, ONCE_ENB]
		

Основной набор содержит всё необходимое для написания программ и запуска их в камушке.
Заветный файл "sdma_init.asm" настраивает модуль. А файл "Карта скриптов.asm" размещает всю скриптовую канитель в прошивке. Файл "sdma.bat" ассемблирует код SDMA. Там же вы найдёте пару тестовых программ для ch1 и ch2.

Ассемблера для SDMA не существует! Ха-ха три раза! Всем салютики!

NXP даёт только коды и описание инструкций. Ассемблер делайте сами! Как хотите, так и делайте!

Поэтому энтузиастами был написан самопальный ассемблер на perl. Благодарим Элика за это.
Исходник был поправлен, добавлена улучшенная поддержка русского. Забирайте его тутъ.

В дальнейшем, исходник на perl был собран утилитой Perl2Exe. И получился полноценный однофайловый транслятор SDMA ассемблера для Windows. Не благодарите. Найти его можно в папке exe в стартовом комплекте. Размер конечно конский, потому что он включает в себя исполняемый perl с модулями и листинг программы.

Что сказать хорошего. SDMA - это прикосновение к вечному... Так делают настоящие и серьёзные вещи.
Весьма рекомендую его изучить и начать писать на ассемблере!

Ищем энтузиастов для написания статей по SDMA!

Документации к сожалению, очень мало. Хоть SDMA существуют уже с десяток лет и больше,
на русском языке вы не найдёте о нём ни слова...

А что бы не сбиться с толку, то поначалу вам пригодится следующая инфа.

Если вы всю жизнь писали на ассемблере для нормальных камушков, то здесь вам придётся немного пошевелить мозгами. И понять, как адресуются программа и данные во внутренней памяти SDMA.

Внутреннее ОЗУ является общим для сохранения регистровых контекстов, программ и данных.
Оно начинается с адреса 0x800 и имеет размер 0x800 (2048) 32-битных слов.
И теперь внимание - данные адресуются 32-битными словами,
а исполняемый код - 16-битными полусловами. (!)

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

Но и это ещё не всё. Так как ядро по своей природе 16-битное, то инструкции адресуются полусловами.
И PC с каждой инструкцией инкрементируется на единицу (!).

Ещё раз, внимательно: приращение счётчика данных на 1 означает переход к следующему 32-битному слову (а не байту!). Приращение счётчика команд (PC) на 1 означает переход к следующей исполняемой инструкции ассемблера.

Отсюда следует: если вы разместили программу в ОЗУ по адресу 0xC00, то счётчик команд будет видеть её как 0x1800. Именно этот адрес заносится в первую строку регистрового контекста.

Содержимое почти всего контекста, во время переключения каналов, считываются и сохраняются ядром автоматически. Таким образом реализуется многозадачность. Для контекстов зарезервировано 24 слова * 32 канала = 768 слов в самом начале ОЗУ. Память контекстов начинается с самого первого слова по адресу 0x800. И заканчивается 0xAFF.

Для программ и данных отводится вся оставшаяся часть ОЗУ, которая начинается на 0xB00 и заканчивается 0xFFF.

Таким образом, размещать программы и данные можно с адреса 0xB00. Счётчик команд видит этот адрес как 0xB00*2=0x1600, так как команды адресуются полусловами.

Нужно бы проверить.. Я не проверял. Но скорей всего, когда не все каналы задействованы, то свободную память, оставшуюся от регистровых контекстов, можно использовать для размещения программ (?)

Ну всё. Хватит. Ждём более полных статей по SDMA!