Записки "маньяка" или почему асм

Асм для stm32? Все сразу кричат — МАНЬЯК!!! Давайте разберемся. Асм для AVR — не маньяк. Но сразу поправляют — для быстрых фрагментов и не больших программ. Почему не больших? И где критерий большая программа или нет. Ведь на асме и не большая может весить десятки страниц. А большая под С вроде как и не очень для асма (по коду). Сложность восприятия асм текста? Так документировать и разбивать на блоки, файлы, драйвера никто не запрещает. Да и пишется много чего на макросах, что уже и на С смахивает. Возможность использовать чужие наработки, библиотеки. Тут да, облом. На асме и свои то наработки часто переделывать приходиться для разных avrок. Но лично я не люблю использовать чужие наработки. Могу подсмотреть прицип или еще что, но не копи/пасте. Зато сам сделал — всегда сможешь повторить. Что еще «шьют» в минус асму? Реализация хитрых протоколов, драйверов типа USB, IP и др. + скорость разработки. Ну насчет первого не знаю, не пробовал, да и для любительских разработок это не сильно актуально как и, кстати, второе, но кто знает, может и возьмусь со временем. Не буду расписывать плюсы авровского асма — тут все ясно. А вот стоит ли заниматься этим под stm32? Смотрим. Флэша больше, озу больше, переферии больше. Переферия вся стандартная, аккуратно разложена по блокам с одинаковыми смещениями под однотипные регистры. Если чего в проце нет — то и блок не используется. Конечно, поначалу пугает количество этих самых регистров, но вспомните, когда Вы увидели первый раз дат на мегу128. А ведь Вас тоже уверяли, что все не так страшно, что будем использовать только то, что нужно а остальное не трогаем. Так же поступаем и в котексах. Теперь непосредственно ассемблер. У рискового процессора и асм рисковый. Т.е. стандартные чтение-модификация-запись. Правда, разработчики старались помочь программистам и придумали разные прибамбасы типа бит-бэнда и регистров для установки/снятия битов, но чаще все равно чт-мод-зап. Сам асм вцелом мне показался «кумедным»(укр. что-то вроде веселый+интересный+смешной) — это слово сразу почему-то пришло на ум. Где-то вроде как избыток, а чего-то вроде как и не хватает. Но немного освоившись, я понял что этот асм довольно гибкий и мощный (+ в связке с хорошим макро-языком кейла). Можно, например, забыть о постоянных вычислениях адреса смещения в таблицах данных или переходов, о сохранении регистров в прерываниях, о сложных ветвлениях программы. Плюс работа с 32х битными регистрами и любой тебе и аккумулятор, и индексный, и базовый. Красота! Есть, конечно, ограничения, но не будем прерывать эйфорию. Работа с битовыми полями, быстрые умножения и деления, условные блоки! Ну почему я должен от этого отказаться и перейти на С. Зачем мне эти страшные CMSIS. Эти дебри порока и разврата! Если серьезно, я когда посмотрел код, созданный с помощью библиотеки — мне стало страшно. Но это еще не все! Мне очень не понравился код после «нормального» С. Вот тогда я и решил попробовать асм. Понравилось. Может и Вам понравится. Может не для заработать, а для души. Хотя, кто знает.
Теперь о том за что я бы три недели назад многое отдал — макет(заготовка) проекта. На компиляцию первого проекта с одним «nop» ушло два дня. Но давайте по порядку. Использеум Keil, поскольку жтаг у меня для него. По той же причине камень — 103C8. Сначала все как обычно. Новый прект + startup + CMSIS. Зачем библиотеки, а с ними стартап завязан. Когда перепишем стартап и библиотеки не нужно будет подключать. Дальше создаем не С файл main.c а асм файл main.s. Все как обычно подключаем к нужным группам. Открываем наш асм файл и пишем первую программу. Для начала отгородим себе «площадь» для работы: AREA. Затем экспортируем метку __main для стартапа. Затем сама прога — nop nop и nop (нет операции — кто не в курсе). И обязательно закрываем программу: END. Имеем:

 		AREA |header code|,CODE,READONLY
		ENTRY
		EXPORT __main
__main
                nop
                nop
                nop

                END

Компилим — F7. Все в порядке, хекс создан, размер кода: Program size: Code=68. 62 байтика ушло, видимо, стартапу и по 2 на каждый ноп. Запустим дебаг(Cntr+F5) и проследим (F11) путь проги по стартапу к нашим нопам. Да, следует отметить что кейл в асме строг. Все должно быть на своем месте — метки без пробелов(в начале) и двоеточий(в конце). Все что с пробелом спереди — или команда, или макрос. Теперь зациклим нашу программу.

 		AREA |header code|,CODE,READONLY
		ENTRY
		EXPORT __main
__main
		nop
		nop
		nop
metka1	        b metka1	;зацикливаем
		END

b это такая себе команда перехода.; — стандартно коментарий.
Теперь добавим область переменных и занесем туда несколько констант.

 		AREA |header code|,CODE,READONLY
		ENTRY
		EXPORT __main
__main
		ldr r0,=str0
		mov r1,#0xcb
		strb r1,[r0]		;0xCB -> [str0]

		mov r1,#0x1122
		strh r1,[r0,#1]		;0x1122 -> [str1]

		ldr r1,=0x33445566
		str r1,[r0,#3]		;0x33445566 -> [str2]

metka1	        b metka1	;зацикливаем

		AREA |header data|,DATA,READWRITE
str0	dcb 0
str1	dcw 0
str2	dcd 0

		END

Все очень просто, но как всегда везде есть нюансы. В командах загрузки ldr и сохранения str регистра, например, источник и приемник меняются местами, что поначалу дико, но зато удобно, а у mov есть ограничения. К тому же у команд могут быть суффиксы, влияющие на размер операнда, флаги, размер самих инструкций и условия их выполнения. Описание всего этого есть в мануалах на ядро (и на русском), поэтому не буду повторяться. Ну, пока все.

PS. Все, что написано выше, не является аксиомой или обучающим материалом, а есть лишь субъективным продуктом эксперементов. Все совпадения фрагментов кода и названий меток случайны.

Project: we.easyelectronics.ru/attachments/get/89
  • +4
  • 29 марта 2011, 23:08
  • psv
  • 1
Файлы в топике: test.zip

Комментарии (53)

RSS свернуть / развернуть
Лично мне было бы интересно увидеть расширенный курс под стм32 с ассемблером.
PS: не забудьте под кат статью убрать, а то огромная :)
0
Расширенный курс, считаю, не актуален т.к. с нуля в стм32 лучше не лезть, а тем кому надоели авр пик нужен больше первый толчок а не методичка по запуску
0
как убрать под кат?
0
используй тег
0
тег cut т.е. :)
0
тегом
0
<cut>

В справочной DIHALT всё отлично написал.
0
Ассемблер и Си — это просто инструменты в наших руках. Бесполезно возвышать одно над другим, нужно хорошо владеть обеими и грамотно использовать преимущества каждого. Вот тогда реально достигнуть высот в программировании МК :)
0
согласен, холивара не хочу просто пытаюсь объяснить, что этот асм не сложнее авровского, но гораздо удобнее
0
А с чего ему быть страшнее? Асмы все не страшные (ну может кроме х86, его хорошо только ICC знает, ну и еще VC). Правда, ассемблер ARM позабавнее (Cortex-M использует Thumb 2) — предикаты и все такое.
Алсо, чем он удобнее? Опять же, не вижу особой разницы.
0
А чем страшен х86? По моему самый удобный, или я просто привык к нему. Когда то под дос много чего писал
0
В нем команд — как в японском иероглифов (ЕМНИП, более 5к команд). И сложные правила оптимизации (которые, к тому же, досконально знают только инженеры Intel). Так что неудивительно, что ICC (Intel C Compiler) по эффективности кода запинывает даже матерых ассемблерщиков, притом иногда — в разы.
0
Ну дык даже на регистр идет четыре вида адресации, вот так много команд. Но запомнить их совершенно не сложно — не так уж там много мнемоник. И писать на асме х86 очень легко и приятно. ИМХО самый удобный из всех ассемблеров на котором я писал.
0
Ну, во первых, даже с учетом этого команд дохрена — это все-таки CISC, причем с десятком-другим расширений, иные из которых по сотне своих команд прибавляют. Не помню, овер5к их с учетом различных способов адресации или нет.
Во вторых, оптимизация от этого проще не становится. Архитектура нынешних процов довольно мутная, так что AFAIK тягаться в производительности с ICC очень сложно. Разве что на специфичных задачах. У RSDN в тестах был даже случай, когда ICC ничтоже сумнящеся поделил на ноль и выиграл на этом при оптимизации порядка 10 раз по производительности (причем выдав правильный результат). Эту ошибку в коде их теста только BCC заметил :)
Ну и в третьих да, писать на нем вполне хорошо, все 5к команд для этого не нужны, но смысл в том есть только в достаточно специфических задачах (либо для дельфистов, когда хочется оптимизировать какой-нить матан или потоковую обработку — оптимизатором DCC не блещет, а SIMD и вовсе не знает).
0
А мне Z80ый больше нравился. Правда Х86 по сравнению с 8080 был сильно переработан и тоже был достаточно удобен…
0
Полезно рассмотреть передачу/возврат аргументов из Си в функции на асме. ;)
0
  • avatar
  • Puff
  • 30 марта 2011, 10:03
конечно полезно, вот кто бы написал? сам бы глянул
0
Смотреть надо соглашение о вызовах в доках на компилер. Обычно используется нечто вроде register — аргументы распихиваются по регистрам (вроде начиная с R8 — это связано с особенностями Thumb, но не помню), что не влезло — в стек. Результат тоже в каком-то из регистров (R8 или R0 скорее всего). Конкретней можно узнать в доках на компилер (или заглянуть в ассемблерный листинг любой функции).
0
Ну сколько раз твердили миру… А мир не слушает.

Всё описанное в топике хорошо, но реализация структур данных на асме — имхо ещё то удовольствие. Если из простейшего — бинарное дерево и двусвязный список. Эти я ещё могу себе более-менее представить, а это размещение в памяти + функции для работы с ними. Но реализовывать например RB-tree или B+tree мне кажется лишним геморроем и будет делаться на C. ну или реализация таких смешных вещей как quicksort или heap sort… Их на C-то корректно реализовать непросто с первого раза и без багов, а на асме я честно говоря и не видел.

Дальше переносимость. Наработки бывают сделаны интересные и терять их при переходе с одного камня на другой неохота. Зря что ли C иногда называют «portable assembler»? Не зря. Если закладываться на портируемость и всё зависящее от камня вынести за тоненький уровень абстракции, то получается переносимая(с некоторыми вопросами конечно, но это в тонких моментах) библиотека. Если уж не между архитектурами, то в пределах одной архитектуры точно.

Ну и о нелюбви к чужому коду. Один факт замеченный многими и лично мной в том числе. В «своём» коде итоговое количество ошибок будет больше, нежели в том, что был взят «на стороне». Кроме случаев, когда этот код писало криворукое нечто, по иронии судьбы считающее себя программистом. Ну и такая мелочь как время… Когда пишешь за деньги, времени намного меньше и результат должен быть намного быстрее.
+1
со всем согласен. но я написал, что маньяк. просто люблю писать на асме и от С никого не отговариваю, а призываю любителей асма переходить на арм (а то кинулся было в эту сторону а примеров и нет)
0
У асма и С разные ниши, зачем спорить что лучше? Асм все равно знать желательно. И для локальных оптимизаций его даже на x86 еще применяют.
0
А я говорил что си лучше и точка? я показал области, где «чисто асмовый» программист мягко говоря задумается. О смысле жизни или о способе самоубийства — другой вопрос…
0
Давайте оставим холиварные рассуждения. Пусть автор продолжает начатое. Кому-то это интересно.
+1
  • avatar
  • Puff
  • 30 марта 2011, 13:37
Во. Позавчера только руки дошли до армов. И решил, также как и автор, начать с ассемблера. :) Начал с программинг мануала (PM0056) и с книги авторства Joseph Yiu. Также искал книгу ARM Assembly Language: Fundamentals and Techniques автор William Hohl — так и не нашел откуда стащить ее. Нашел ее на озоне, но там цена стоит 7355 рублей, хотя может это и ошибка…
0
После компиляции в Keil — Code=572, а не 68 как у автора… похоже что то не так сделал…
0
О, еще кто-то асм пробует. Обещаю, если пройдете весь путь — не пожалеете. А по поводу размера кода — не знаю, у меня настройки по умолчанию, может у Вас что-то из библиотеки попало. Посмотрите дебагером код — может лишнее найдете.
0
этот ассемблер для меня далеко не «первый» :) и гораздо бОльшая проблема не изучить новый ассемблер, а разобраться с фичами Keil. Слепил программулину на ассемблере, а вот стартануть в отладчике пока никак — выбрасывает на адрес 0х0000…
0
А я и имел ввиду асм арм. Забросил файлы проекта — может поможет.
0
… вроде разобрался
0
Хорошая статья. Продолжение asm+arm stm32 планируется?
0
Как насчет посмотреть все мои статьи. Дальше тоже планирую писать, но сейчас нет времени.
0
Верно ли, что cortex-m3 поддерживает не весь набор ассемблерных инструкций arm а только лишь часть набора инструкций которая называется thumb2?
0
Немного не так. Котексы поддерживают усовершенствованный набор инструкций, уменьшающий размер кода.
0
То есть размер кода уменьшается за счет отказа от некоторых суфиксных команд или команд поддерживающих условное исполнение?
0
Только Thumb-2, да. Это подмножество смеси ARM и Thumb. Т.е. часть команд 16-битные, часть 32-битные. Это позволяет получить некоторый компромисс между плотностью кода, обеспечиваемой Thumb, и скоростью его работы, обеспечиваемой более мощными инструкциями ARM. Чистый ARM чуть быстрее, чистый Thumb чуть плотнее.
0
Вот это обстоятельство немного огорчает. Ведь часто говорится, ARM ассемблер тем и хорош, что он как бы ближе к Си. А в Thumb2 эта черта завуалирована.
0
На МК место ценнее, чем скорость. Да и вообще, ассемблер под ними редко кого волнует. Обычно волнует вопрос «во сколько байт скомпилится вон тот кусок на С и как быстро будет работать». Thumb-2 позволяет добиться компромисса в этом вопросе, это хорошо.

А чем он ближе к С? Набор команд ARM — вполне обычный ассемблер, за двумя исключениями — он трехадресный и все команды условные. Но в Thumb-2 вроде тоже с условными командами неплохо.
0
У тебя постоянные проблемы с нехваткой флеши? Смени компилятор :)
Если серьезно, то выбрать что-то одно: или флешь или скорость, нельзя, так как на этот вопрос нет однозначного ответа, все зависит от задачи.
0
Вот потому они и выбрали компромисс.
0
* и конечно от ресурсов
0
а к каким группам в начале надо файл подключать, пишет not searching ARM libraries.
0
что то утомило чтение в начале статьи! надо бы отформатировать чтоль
0
Какие есть способы загрузки константы в регистр? Почему строка ldr 0x4200000C, #0x18 не работает?
0
На ARM7 это выглядело так:

   48:   int a=30, b=70;
 00000004  E3A0501E  MOV         R5,#0x1E
 00000008  ---- Variable 'a' assigned to Register 'R5' ----
 00000008  E3A04046  MOV         R4,#0x46
 0000000C  ---- Variable 'b' assigned to Register 'R4' ----
   49:   a=a+20;
 0000000C  E2855014  ADD         R5,R5,#0x0014 ; a
   50:   b=b-10;
 00000010  E244400A  SUB         R4,R4,#0x000A ; b
0
Спасибо, keil откомпилировал это без ошибок, только непонятно как записать константу, например, в регистр 0x4002100C
0
Вроде должна работать конструкция типа

          mov32 r5, 0xCCCC
          mov32 r3, 0x4002100C
          LDR R3,[R5]

но симулятор на нее не реагирует :(
0
Напиши на С и посмотри что компилер нагенерил. Я привел кусок листинга, сгенерированного кейлом. Или вообще перейди на С.
0
а с gnu asm не пробовали?
я поставил coIDE (она бесплатная) к ней компилятор sourcery.mentor.com/sgpp/lite/arm/portal/package9743/public/arm-none-eabi/arm-2011.09-69-arm-none-eabi.exe

как мне теперь откомпилировать асм файл?

пытаюсь компильнуть
.globl main
.data
main:
b Start

а в ответ ни ошибок, ни файла

compile:
[mkdir] Skipping C:\CoIDE\workspace\test2\Debug\bin because it already exists.
[mkdir] Skipping C:\CoIDE\workspace\test2\Debug\obj because it already exists.
[cc] 1 total files to be compiled.
[cc] arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -ffunction-sections -O0 -g3 -c -DM3 -IC:\CoIDE\workspace\test2 C:\CoIDE\workspace\test2\main.s
[cc] Starting link
[cc] arm-none-eabi-gcc -O0 -nostartfiles -Wl,-Map=test2.map -mcpu=cortex-m3 -mthumb -LC:\CoIDE\workspace\test2 -Wl,--gc-sections -Wl,-TC:\CoIDE\workspace\test2\link.ld -g -o test2.elf ..\obj\main.o
Program Size:
text data bss dec hex filename
0 0 0 0 0 test2.elf

BUILD SUCCESSFUL
Total time: 1 second

что делаю не так?
0
  • avatar
  • WitGo
  • 08 февраля 2012, 08:05
для GCC расширения файла очень важно. «s» значит асм-файл который не надо прогонять через препроцессор, а «S» — надо. К тому же у вас main объявлен в секции data, а должен в text
попробуйте
;main.S
.globl main
.test
main:
b Start

И откомпилировать ручками:
arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -c -o main.o main.S
0
Опечатался, конечно же надо

;main.S
.globl main
.section .text
main:
b Start
0
вот такое вот проходит
.syntax unified
  .cpu cortex-m3
  .fpu softvfp
  .thumb

  .section  .isr_vector,"a",%progbits
  .type  Vectors, %object
  .size  Vectors, .-Vectors

Vectors:
  .word  _eram 		@ Вершина Стека
  .word  main 		@ А тут Reset Handler

main:
 		b main
0
  • avatar
  • WitGo
  • 08 февраля 2012, 10:16
Люблю асм. Спасибо за статьи, буду тыкаться в Cortex.
0
(сразу предупреждаю: все комменты не читал)
плюсы асма:
+ компактный код
+ максимальная эффективность
(^^^ при достаточном знании разработчика)
плюсы С:
+ компактный код
+ максимальная эффективность
^^^^ при достаточном знании разработчика
ПЛЮС скорость разработки.
просто в сях надо знать чуть больше. зато профитов больше на порядки.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.