Pull to refresh

Comments 41

Наиболее интересная задача здесь — разработка такого компилятора и ЯВУ, который бы выдавал оптимизированный код (по какому-то критерию) и доказательство того, что на данном устройстве получить лучший код — невозможно.

А смысл?
Современные компиляторы (IAR, Keil, avr-gcc) выдают код, оптимизированный с большим набором ключей и параметров.
«Впихать невпихуемое», также как и использовать каждый такт считается при нынешних ценах моветоном.

Ну разве что на миллионной партии если каждый сэкономленный бакс пойдет в ваш личный карман.

На практике же разработка на ассемблере считается дурным тоном, если на то нет особых причин. А многие продвинутые разработчики перешли с си на с++ и на практике показывают, что оверхед если и есть, то небольшой (для современных контроллеров класса хотя бы Cortex-M), а на некоторых проектах получается даже выигрыш за счет большей структуризации.

Упс… пропустил…
ОЗУ нет, только 32 регистра общего назначения и стек

Тогда просится forth :)
Разумеется, я с вами согласен, так как человекочас работы программиста стоит много дороже тактов и ячеек памяти. Однако есть еще на вскидку три области, где экономия на тактах актуальна — программирование для развлечения/обучения, встраиваемые системы для жестких условий (космос, роботы для ликвидации аварий на АЭС и подобное) и жесткое энергосбережение.
Замечание в сторону — отсутствием экономии на тактах несознательные граждане доводят Андроид до посадки батареи за полсуток.
Про встраиваемые системы и программирование с преждевременной оптимизацией, а также экономии на байтах не надо — почитайте «историю одного байта». Всегда берут с необходимым запасом. И главные критерии здесь не малый размер и быстрота кода, а надёжность и предсказуемость.

Да ресурсы там ограничены, однако за код на месте векторов прерывания, и за отсутствие всех обработчиков вас там вряд ли похвалят. (Это если мы говорим про нормальную разработку а не «Back to Sovet Union»).
Форта не будет — стек реализован отдельно от регистров, в него можно поместить только три значения и этими значениями может быть только девятибитный указтатель инструкции (даташит, страница 9)
На С++ оверхэд есть, и большой, я с трудом впихал свой проект в память Cortex M3 (LPC1768), хотя предыдущая версия, написанная на С, размещалась без проблем. Больше всего был расход ОЗУ: кучи и стека, их С++-программа ест гораздо больше чистого С.

А ассемблер — зло. Неподдерживаемый и немодифицируемый код.
А ассемблер AVR это ещё большее зло, т.к. у него зачастую яркая несовместимость между моделями, не говоря уже о сериях МК.
Сложность поддержки и модификации кода в малой степени определяется языком — она определяется в первую очередь качеством документации и логичностью идей, выраженных в коде. В целом, нужно следовать советам Мартина Голдинга — «Пишите код так, как будто сопровождать его будет склонный к насилию психопат, который знает, где вы живёте».
Увы, на ассемблере труднее, следуя Кнуту, реализовывать грамотное программирование, но это расплата за тотальный контроль над оборудованием.

Более важно то, что ассемблер ставит жирный крест на переносимости. Однако история x86 — яркий пример того, как вовремя установленные владельцами платформы подпорки позволяют спасти положение. Увы, ценой технологической красоты.
Если вы пишете под микроконтроллер без ОС, на «голом железе», то вы имеете полный контроль над оборудованием и на С и на С++, т.к. все регистры, отображаемые на память, доступны. Если проект пишется под какую-либо ОС (RTOS), то часть аппаратных ресурсов может быть занята системой, и они могут быть не доступны напрямую, опять же независимо от языка.

Что касается документации, я придерживаюсь идеи самодокументируемого кода, то есть все переменные должны иметь ясные и развёрнутые имена, алгоритм должен ясно прослеживаться, никакого спагетти-кода. На ассемблере следовать этим принципам затруднительно.

Писать на асме не стоит затраченных усилий.
Уже при использовании языка высокого уровня приходится либо обкладываться документацией на компилятор, либо смотреть листинг, который этот компилятор сотворил. Иначе может оказаться так, что при входе в прерывание компилятор «на всякий случай» решит положить все 32 РОН на стек, что приведет к драматическому снижению скорости отклика на это прерывание.

Я бы не стал заявлять столь категорично — каждая конкретная задача требует своего инструмента.
Это так, если вам критичны микросекунды скорости отклика на прерывание. В моих приборах такой задачи не стояло, поэтому я листингов специально не смотрел, и даже если компилятор кладёт все регистры на стек, то и пусть себе. Хотя ассемблерный листинг в IAR виде сразу же при запуске, и проблем с его просмотром нет никаких. К тому же IAR имеет очень интеллектуальный оптимизатор.

Задачи, требующие очень быстрой и предсказуемой до такта реакции, лучше решать на DSP, и там реально имеет смысл писать на асме руками (особенно простые, но очень быстрые алгоритмы).
А есть люди, которые под тот же AVR пишут на плюсах и другим советуют.
Кстати, чего далеко ходить — ардуино. Фактически, обертка вокруг avr-g++
Тут скорее вопрос владения инструментом.
Да, разложение Фурье сигнала с АЦП (на частоте около 16 кГц) для ATMega8 я писал на C. Однако моментально напоролся на желание компилятора сохранять все РОН при входе в прерывания, из-за чего 16 кГц превратились в примерно 9. Желание было выявлено путем анализа ассемблерного листинга, компилятору была выписана строгая директива больше так не делать, проект был сдан.

Владение инструментом как раз и требует знания внутренней кухни компилятора вплоть до ассемблера.

В случае же с мелким контроллером без ОЗУ, GCC умывает руки:
image
Да, я знаю, что ардуиновские библиотеки написаны на плюсах. Ардуино предназначен для запуска небольших скетчей и быстрого прототипирования, не больше.
Добавлю ещё, что я совсем не против плюсов, в случаях, когда:
1. Позволяют ресурсы памяти
2. Код получается более простым и ясным, чем на С, а не наоборот.
Программирование на ассемблере является наиболее трудоемким способом получения программ, оптимизированных по размеру и скорости выполнения. Наиболее интересная задача здесь — разработка такого компилятора и ЯВУ, который бы выдавал оптимизированный код (по какому-то критерию) и доказательство того, что на данном устройстве получить лучший код — невозможно.


К сожалению, из проблемы останова следует невозможность существования алгоритма, который в общем случае генерирует программу минимального размера, эквивалентную заданной. Более того, не может существовать даже алгоритма, который генерирует минималтную программу, просто выводящую заданную строку.
Интуитивно чувствуется, что здесь палки в колеса поставит или упомянутая вами теорема с громким именем, или теорема Геделя о неполноте. Однако быть может имеет смысл поискать условия, при которых поиск всех эквивалентных программ сведется к перебору?
не может существовать даже алгоритма, который генерирует минималтную программу, просто выводящую заданную строку.

— прекрасный результат слепого применения теории: во первых, выглядит абсурдно, во — вторых, легко опровергается — делаем железку с одной инструкцией — «печатай эту самую строку», тогда программа будет состоять из одной этой инструкции.
Строку, очевидно, не наперёд заданную.
Ещё раз. Не существует алгоритма A, такого, что он для любого S находит B=A(S), такое что B()->S, и не существует алгоритма C, такого что C()->B и |C|<|B|.

На хабре была неплохая статья для человека, не знакомого близко с CS: habrahabr.ru/post/189742/
Вы утверждаете:
не может существовать даже алгоритма, который генерирует минималтную программу, просто выводящую заданную строку.

Далее, вы утверждаете:
Строку, очевидно, не наперёд заданную.

Близость к теоретической информатике (и любой другой сильной теории) требует в первую очередь ясного и последовательного изложения идей и результатов размышлений.

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

В частности, если мы имеем граф потока управления, и он не содержит циклов, или эквивалентными преобразованиями сводится к графу без циклов, то очевидно, что для данной программы мы сразу можем сказать — она завершится.
Давайте не будем из себя Бурбаки строить, а?

Понятно, что captain_obvious хотел сказать, что
¬∃f ∀s f(s)=g ∀h len(h) ⩾ len(g)
но будет ли вам легче это читать и понимать?

И да, разумеется, если мы в выражении вверху немного «пошевелим» кванторы, то выражение стант неверным. Отказ от циклов, в частности, сводит неразрешимую задачу к тривиальной.
Предлагаю спуститься с теоретических небес на практическую землю:

Утверждение: Единственная программа на компьютере, которая никогда не останавливается — операционная система (в том числе и драйверы, системные службы и так далее).

Критерий остановки всех этих компонент — отключение компьютера. Что логично, так как операционная система и системное ПО как раз и нужны для работы компьютера.

Прикладные же программы устроены так, что непременно завершатся:

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

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

Согласитесь, что навечно зависающая программа бесполезна как минимум?

Даже те ситуации, когда зацикливание неизбежно и выход из цикла зависит только от входных данных, которые априорно проверить невозможно (тут теорема Геделя о неполноте высовывается), будут охвачены сторожевым счетчиком «разумного числа итераций», исчерпание которого будет приводить к остановке программы с ошибкой.
Спор с SIGKILL ещё никого ни к чему хорошему не приводил…

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

Завершение выдергиванием штепселя (уничтожение машины Тьюринга etc) — не является завершением программы в терминах теоремы останова.
Поправка — навечно зависающая прикладная программа.
Они бывают интерактивными. Например, /bin/sh. Сидит и ждёт ввода от пользователя. Ждать может до скончания вечности.
Или пока ему не напишут exit.
Стоит отделить зацикливание в процессе ожидания некоего события (пакета по сети, активности пользователя, и так далее) от зацикливания на некорректных данных — когда извне программа уже ничего не ожидает, а продолжает вертеться в цикле.

Очевидно, что второй случай говорит об ошибке в программе, так как от ошибки в данных (или в окружении ОС) можно всегда застраховаться и корректно завершить работу.
Всё верно, заданную, но не наперёд.

В частных случаях, разумеется, можно придумывать различные паттерны, которые будут работать, но, вообще говоря,

Наиболее интересная задача здесь — разработка такого компилятора и ЯВУ, который бы выдавал оптимизированный код (по какому-то критерию) и доказательство того, что на данном устройстве получить лучший код — невозможно.


— такого не будет, если критерием считать размер программы.

Поскольку в этом комментарии я не написал ничего нового, считаю диалог завершённым.
О, этот маленький восьминогий жучок на самом деле не так уж плох, хоть и древен до обсолетности — у меня на нем сделаны несколько конструкций, от очень простых, до довольно заковыристых, использующих почти под завязку программную и регистровую память девайса, и практически всю его периферию — описания двух из них есть на хабре вот и вот.
Именно под такие цели Атмел и позиционирует этот замечательный контроллер. А его высокочастотный (25МГц) ШИМ дает еще больше свободы для творчества.
А дифференциальный АЦП с предусилителем и программной коррекцией нуля?
… помещен в контроллер специально для того, чтобы творить умные зарядные устройства, мониторы питания и приемники аналоговых сигналов.

Очень жаль, что Атмел отказалась от ATTiny15 — шестая студия о нем не знает, а фирма выпустила документ с рекомендациями о замене на ATTiny25
UFO just landed and posted this here
У меня как раз получилось все скачать с официального сайта — меня лишь попросили заполнить небольшую форму и верифицировали почту, прислав ссылку. После этого я смог скачать и шестую, и четвертую версии студии.
UFO just landed and posted this here
Там есть неприметная ссылка, ведущая в архив
UFO just landed and posted this here
Одна беда — Atmel больше не даёт скачать старые версии AVR Studio

А зачем, если есть расово верный Eclipse или Code::Blocks в качестве оболочки, а компилятор в любом случае avr-gcc aka winavr
А уж в линуксе сам бог велел.
Eclipse — это извините, пздц. Тормоза на каждом шаге. Конечно, машина была 2-ух башковое среднее решение, но чтоб так — это не. Лучше в блокноте писать код, чем в этом. Снес нахер и никогда больше не поставлю.
Студия замечательна тем, что содержит прекрасный симулятор/отладчик, с встроенным справочником по регистрам и периферии контроллера. То есть многие вопросы можно решить, глядя на подсказки студии, без зарывания в даташит.

С Эклипс другая проблема — я для разработки долгое время использовал старинный Dell Latitude CPx (только из-за наличия на нем более чем удобного для электронщика LPT)

image
(он засветился в одном из эпизодов Секретных материалов).

Так вот, этот прекрасный старикан просто не тянул столь прожорливую IDE, а с четвертой студией — справлялся.
Я искренне рад, что моя статья сподвигла автора того топика на исследование применения сторожевого таймера.

Вот только никакой надежды на авось нет — ну не будет прерывание INT0 работать, коль скоро оно выключено в GIMSK.
Я дополнил статью ссылками на рекорд, и даже (хоть и путем издевательства над контроллером), побил его, уменьшив прошивку до 10 байт — Контроллер встает, дойдя до конца программной памяти, исполняя одну и ту же инструкцию SBRS R31, 7 (ее опкод — 0xFFFF).
Sign up to leave a comment.

Articles