Материал: 6798

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

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

47

Если поставить две точки останова в разных местах исследуемого кода, то взяв разность показателя States в этих точках, можно узнать время работы в «тиках» синхросигнала для участка кода программы между этими точками останова. Чтобы узнать время в секундах нужно эту разность разделить на тактовую частоту процессора Options for Taget → Xtal(MHz). В нашем примере это Xtal = 12.0 MHz.

Узнаем за какое время происходит запись трёх значений в регистры системного таймера

dt = ( 15894 – 15881 ) / 12e6 = 1.083e-6 c,

примерно за одну микросекунду.

После предварительного знакомства с машинным кодом, сгенерированным Keil-ом, сразу возникает вопрос — а нельзя ли его оптимизировать. Иногда это возможно. Например, в нашем случае смещение относительно базового регистра вычисляется отдельной командой

ADDS r0,r0,#4.

С точки зрения логики она лишняя, поскольку код

ADDS

r0,r0,#4

MOVS

r1, #0x0

STR

r1,[r0, #0x00]

эквивалентен такому

MOVS

r1, #0x0

STR

r1,[r0, #0x04]

имы аж на 25% можем увеличить скорость работы!

Авот с точки зрения практики вопрос об оптимальности остаётся открытым. Не всегда самый скоростной код оказывается рабочим для внешнего устройства. Если речь идёт

озаписи/чтении памяти данных, то наш код будет однозначно лучше, а вот если речь идёт о записи/чтении регистров внешних устройств, то более медленный код может иногда оказаться более надёжным. Можете объяснить почему?

Мы рассмотрели этот пример в качестве учебного. На практике для общения с внешними устройствами сейчас чаще пользуются стандартными библиотеками. Это выгодно не только с точки зрения переносимости программ, но и с точки зрения надёжности работы, поскольку библиотечный код, как правило, многократно тестирован. Но и из этого правила бывают исключения.

Итак, компилятор Keil-а оставляет нам обширное поле для творчества, осталось научиться кодировать на ассемблере. Чтобы узнать как оформляются функции на ассемблере, заглянем в стандартный файл нашего проекта startup_1901BC1F.s18 и в справочную систему Keil-a.

Мы не будем подробно описывать процесс добывания информации, это мы сделали в предыдущей лабораторной работе, и здесь он примерно такой же. Сразу приведём готовый ответ. Это файл скелетов функций на ассемблере skeleton.s и аналог нашего main() кода для работы с таймером setTimer.s.

В файле skeleton.s, рисунок 17, приведены два варианта оформления процедур (функций) на языке ассемблера. Первый вариант Skeleton1 для случая, когда из ассемблерной процедуры никакие другие функции не вызываются, а второй, Skeleton2, для случая, когда из данной процедуры вызывается ещё одна или несколько процедур(функций). Для примера мы вызвали Skeleton1.

18 Смотри сноску на стр. 45.

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

Каф. ЭСАУ

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

Февраль 2017 г.

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

48

Рисунок 18. Скелеты для asm-процедур

Рисунок 19. Установка системного таймера

В файле setTimer.s приведён исходный текст на ассемблере, выполняющий те же самые действия, что и наш прежний Си-код, работавший с таймером.

Включаем процедуру setTimer( ) в проект и проверяем насколько она получилась скоростной. Вывод неутешителен — setTimer( ) работает медленнее чем код, сформированный Keil-ом. Наш код, действительно, экономит 4 такта, но мы не учли

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

Каф. ЭСАУ

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

Февраль 2017 г.

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

49

накладные расходы на вызов самой функции setTimer( ) — 8 лишних тактов. Причём, это самый быстрый вариант вызова по skeleton1, а для варианта skeleton2 затраты на вызов функции будут ещё больше, поскольку в нём присутствуют ещё и затраты на сохранение регистров в стеке и затем извлечение сохранённых значений из стека.

Таким образом, если речь идёт о получении наиболее скоростного кода, то в нём желательно избегать вызовов функций. Язык ассемблера позволяет это делать при сохранении читаемости кода. Как именно, мы познакомимся в следующих лабораторных работах. В языках высокого уровня для этой цели существует очень эффективный приём — ассемблерные вставки. Пока в Keil-e не удалось этим воспользоваться.

3.4Заключение

Здесь мы привели пример выполнения лабораторной работы. Установили среду разработки Keil, создали проект и написали простейший текст на ассемблере. Попутно продолжили знакомиться с системой команд для ядра Cortex-M3. Заметим, что для того, чтобы обнаружить возможность оптимизации кода, никаких особых программистских изысков мы не использовали. Достаточно было просто внимательно читать документацию по микроконтроллеру. В нашем случае это знакомство с командами обращения к памяти.

Каждый студент получает или придумывает свой объект для исследования, точнее, свой фрагмент Си-кода, который нужно будет подробно описать в терминах системы команд микроконтроллера.

3.5Требования к содержанию отчёта

Те же самые, что и в предыдущей лабораторной работе (см. пункт 2.4 ).

3.6Контрольные вопросы

1.Как установить на компьютер Keil?

2.Как адаптировать эту среду для работы с определённой моделью микроконтроллера и определённым изготовителем, например, ф."Миландр"?

3.Как создать новый проект в среде Keil?

4.Как выбираются основные опции проекта?

5.Что такое симулятор и для чего он служит?

6.Что такое система команд микроконтроллера и для чего её нужно знать разработчику систем управления? Почему нельзя ограничиться только изучением языка верхнего уровня?

7.Расскажите о командах, которые вы изучили в ходе выполнения этой лабораторной работы.

8.Можно ли из процедуры на ассемблере вызвать функцию на Си?

9.Что такое JTAG?

10.По какой причине может не работать внутрисхемная отладка?

11.Что в себя включает понятие «оптимизация кода»?

12.Для чего служит директива WEAK? См. рисунок 19.

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

Каф. ЭСАУ

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

Февраль 2017 г.

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

50

4Интерфейс Си и ассемблера. Лабораторная работа № 3

Цель. Изучить способы обмена данными между модулями на языке Си и языке ассемблера.

4.1Введение

Интерфейс (interface(англ) - стык, взаимосвязь) в данном контексте означает исследование обмена данными между функциями на языке Си и ассемблерa. Существует два способа обмена — через общую (видимую) область памяти и через параметры функций. Какой из них эффективнее (быстрее), нужно решать для каждого отдельного случая. При этом необходимо помнить, что наиболее быстро осуществляется обмен данными между регистрами.

Как показала учебная практика, выполнить самостоятельно анализ обмена данными между Си и ассемблером для подавляющей массы студентов оказалось затруднительным. Поэтому мы выделяем эту тему в отдельную лабораторную работу.

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

Для архитектуры ARM есть свои особенности при обмене данными между функциями. Они даже регламентируются специальным документом IHI0042E_aapcs.pdf19 . Мы вам рекомендуем ознакомиться с ним на досуге. Сами же будем исследовать обмен данными, используя дизассемблер, поскольку эта методика работает на любых архитектурах.

АCortex мы воспринимаем здесь только как один из примеров.

В архитектуре INTEL при передаче данных через параметры используется только стек, а в архитектуре Cortex всё несколько сложнее — здесь используется и стек, и регистры. Если число параметров не превышает 4-х, то стек не используется вообще.

4.2Содержание работы

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

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

4.3Обмен данными через параметры функций

Вкачестве примера проделаем лабораторную работу, в своё время не выполненную одной из студенток 530-й группы. Кратко задание формулировалось следующим образом:

Передать 3-х мерный массив как параметр, инвертировать, возвратить результат.

Поскольку тема этой лабораторной работы «Интерфейс Си и ассемблера», то в развёрнутом виде задание будет формулироваться так:

Из функции на Си передать 3-х мерный массив как параметр в функцию на ассемблере, инвертировать в ней каждый элемент массива, возвратить результат.

19Procedure Call Standard for the ARM® Architecture. ARM IHI 0042E, current through ABI release 2.09. http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf

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

Каф. ЭСАУ

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

Февраль 2017 г.

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

51

4.3.1Выполнение работы

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

На рисунке 20 показано окно проекта и окно исходного кода программы.

Рисунок 20. Программа в среде Keil MDK_ARM

Если запустить теперь программу на отладку (как это сделать, мы узнали в прошлой лабораторной) и открыть окно дизассемблера, то увидим следующую картинку, рис.21.

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

Каф. ЭСАУ

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

Февраль 2017 г.

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