Материал: 6798

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

Часть I. Процессор Cortex-M3. Программирование на ассемблере - 4

57

Рисунок 26. Исходник на ассемблере

Универсальная функция inverseASM( ) получилась такого же размера как и первая inverseASM_1( ), а вот скорость её работы в несколько раз меньше; вычислять скорость мы научились в предыдущей лабораторной работе. Это и понятно, поскольку в первом случае за одинаковое количество тактов обрабатывается (читается, инвертируется, записывается) сразу по четыре байта, а во втором только один. Исходный код main(), откуда вызываются наши функции, находится в файле main2.c.

Понятие «эффективный код» требует уточнения. Желательно, чтобы этот код был максимально коротким и скоростным. В подавляющем большинстве случаев эти требования находятся в противоречии — их нельзя обеспечить одновременно. На вопросе оптимизации кода мы остановимся более подробно во второй части этой лабораторной работы. А сейчас в качестве упражнения предлагаем читателю доработать последнюю функцию inverseASM( ) так, чтобы она была не только универсальной, но достаточно скоростной.

ТУСУР, "Миландр"

Каф. ЭСАУ

Недяк С.П., Шаропин Ю.Б

Февраль 2017 г.

Часть I. Процессор Cortex-M3. Программирование на ассемблере - 4

58

Заключение 4.3 . При передаче параметров из функции на языке Си в функцию(процедуру) на ассемблере в нашем случае в регистре r0 передаётся первый параметр — адрес массива, а в регистре r1 передаётся второй параметр — число элементов массива.

4.4Обмен данными через общую область памяти. Глобальные переменные в Си-модуле.

В первой части этой лабораторной работы, п. 4.3 , мы осуществили обмен данными между функциями на Си и ассемблере через параметры функции. Сейчас решим следующую задачу.

В общей (видимой) области памяти объявить трёхмерный массив. С помощью ассемблерной функции инвертировать в нем каждый элемент.

Для достижения поставленной цели мы поступаем прежним способом — сначала пишем функцию на Си, а затем переводим её на ассемблер. Работу в ассемблере с трёхмерным массивом мы даже не рассматриваем, поскольку код в этом случае получается неэффективным — большим и медленным.

Рисунок 27. Функция inverseC_Gmem.

Получилась вот такая короткая функция inverseC_Gmem( ), которая работает с трёхмерным массивом A как с одномерным.

ТУСУР, "Миландр"

Каф. ЭСАУ

Недяк С.П., Шаропин Ю.Б

Февраль 2017 г.

Часть I. Процессор Cortex-M3. Программирование на ассемблере - 4

59

Её дизассемблирование выглядит так.

Рисунок 28. Дизассемблирование inverseC_Gmem

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

Глядя на рисунок 28, мы видим уже хорошо знакомый нам цикл побайтного инвертирования массива А, это код по адресам: 0x000001A8 … 0x000001B2. Он почти совпадает с прежним. Если r0 – индекс массива, r3 – регистр для ивертирования, тогда r1 будет адресом начала массива, поскольку [r1, r0] — это ничто иное как ссылка на адрес очередного инвертируемого байта. Этот адрес равен [ r1 ] + [ r0 ] - сумме значений в указанных регистрах.

Как же инициализируется r1? Этот регистр инициализируется такой инструкцией

LDR

r1, [pc, #0х20]

; @0x000001B8

Она предписывает загрузить в регистр r1 содержимое слова, находящегося по адресу на 0х20 больше чем текущий. А текущий, как известно, записан в счётчике команд РС. Конвейер??? В комментарии к инструкции LDR Keil любезно сообщает нам этот адрес — 0x000001B8. Остаётся только посмотреть, какое значение находится по этому адресу. Там у нас лежит константа 0х20000000. Именно по этому адресу располагается начало трёхмерного массива А. Этим значением инициализируется указатель АА (см. исходник inverseС_Gmem.с). Если на несколько секунд задержать курсор на переменной АА, то Keil

ТУСУР, "Миландр"

Каф. ЭСАУ

Недяк С.П., Шаропин Ю.Б

Февраль 2017 г.

Часть I. Процессор Cortex-M3. Программирование на ассемблере - 4

60

покажет её текущее значение. Естественно, это возможно, когда в сеансе отладки программа остановлена.

LDR — это так называемая псевдокоманда, т. е. она преобразуется из какого-то исходного текста на ассемблере в другую настоящую ассемблерную команду. Для того, чтобы определить, какой именно исходный текст ей соответствует, снова обратимся за консультацией к нашему виртуальному учителю Disassembly. Запустим программу на отладку и затем нажмём кнопку «Reset» - самая левая кнопка на панели инструментов. Мы увидим примерно следующее.

Рисунок 29 Псевдокоманда LDR

Здесь команде

LDR

LDR r0, [pc, #36]

соответствует оригинал (псевдокоманда)

LDR

R0, =__main

Ссылка __main объявлена как внешняя с помощью директивы IMPORT __main. В нашем случае вместо ссылки __main это будет, видимо, имя массива А.

Полученных знаний достаточно, чтобы написать функцию на ассемблере. Пробуем! Используя результат дизассемблирования и скелет для функций на ассемблере, создаём следующий код.

ТУСУР, "Миландр"

Каф. ЭСАУ

Недяк С.П., Шаропин Ю.Б

Февраль 2017 г.

Часть I. Процессор Cortex-M3. Программирование на ассемблере - 4

61

Рисунок 30. inverseASM_Gmem

Функцию inverseASM_Gmem включаем в проект и тестируем. Она успешно работает. Одно смущает — предупреждение при компиляции проекта:

..\..\src\ASM\inverseASM_Gmem.asm(27): warning: A1581W: Added 2 bytes of padding at address 0x16 — предупреждение: A1581W: Добавлено 2 прокладочных байта к адресу 0х16.

Что за байты, где этот адрес? Справочная система Keil-а и просмотр машинного кода, 0х16 — это один из адресов таблицы векторов прерывания, мало что дают. Хотя машинный код inverseASM_Gmem в точности совпадает с оригиналом inverseC_Gmem, в этом легко убедиться, сравнивая их в дизассемблере.

Впадаем в очередную программистскую прострацию — не знаем, что делать дальше. Одно из требований MISRA гласит, что проект должен компилироваться без предупреждающих сообщений, следовательно, работа в таком виде не может быть принята.

Самое эффективное средство в таких случаях — выспаться. Это совет не от авторов данного пособия, а от самого Норберта Винера, отца кибернетики. Мы лишь многократно испытали его реальное действие :)). Справедливости ради отметим, что Винер работал в отсутствии Интернета и Википедии.

Отдохнув, продолжаем. Ещё раз читаем предупреждение компилятора. Он нам выдал его, когда обрабатывал строку 27 исходника inverseASM_Gmem.asm. А в этой строке находится директива END. Уж она-то никак ошибкой (источником предупреждения) быть не может. Вспоминаем... У нас похожий код компилировался без предупреждений в функции inverseASM. Он отличается от теперяшнего всего лишь одной строкой, а именно

LDR

r1, =А

ТУСУР, "Миландр"

Каф. ЭСАУ

Недяк С.П., Шаропин Ю.Б

Февраль 2017 г.

Источник: https://studfile.net/preview/16438538/