Еще тоскливее то, что в области RISC до сих пор все трансляторы на уровне 50тых — тупо трансляторы.
Даже тупо расчитать оптимальный JMP => SJMP/AJMP/LJMP в случае прямого прыжка не могут :D
Вы это про «трансляцию» ассемблера?
Сишный код нынешние компиляторы замечательно оптимизируют, порой смотришь на листинги и узнаешь много новых способов использования инструкций проца)
Безосновательное заявление, сравните что ли результат работы того же gcc при -O0 и -O2 для ARMовских архитектур. Для x86 понятное дело оптимизаторы работают лучше, но там и спрос другой.
Как-то странно у вас в микроконтроллеры попали только AVR, 8051 и PIC, а все остальное вы записали уже в «жирные» SoC.
А как же микроконтроллеры таких популярных ARM ядрах как ARM7TDMI, CORTEX M3, CORTEX M0?
Или для вас какой-нибудь LPC1114 это уже не микроконтроллер, а SoC?
Сейчас ARM глубоко проник в нишу мелких микроконтроллеров и принес за собой туда нормальные компиляторы.
ARM — это жирный контроллер. Очень жирный. Простите, но когда вам доступна 32битная адресация, 32битная арифметика, когда даже в Cortex-M0 уже есть 13 регистров общего назначения все-со-всеми, это уже далеко не RISC по возможностям, и да, он очень жЫрен.
Да и блин, когда у слабенького контроллера до 50 мегагерц рабочая частота…
То там оптимизации дааалеко не всегда нужны, кроме сложной математики.
Зато да, в таких ресурсах автоматическая оптимизация делается уже хорошо.
А теперь когда операции доступны только с одним регистром, стека почти нет, свободных ресурсов вообще — то есть когда оптимизатор нужен как воздух…
Да, насчет 51 согласен. В свое время отказались от него по той причине, что писать нужно было на ассемблере исключительно. Сишный код раздувало нереально. Но сейчас они почти не используются.
На pic коллега как-то переводил программу с ассемблера на си, не сказал бы, что она стала сильно больше места занимать или медленнее работать.
PS что называть микроконтроллер, а что SoC — отдельная тема. На электрониксе была как-то дискуссия — сошлись на том, что SoC — скорее маркетинговый термин, чем технический.
мик/сок — согласен, холивар, для себя я соком зову «жирные», с высокой производительностью, а миками как раз 51/pic/avr — то есть дохлятинку.
ну и по поводу 51го — мы всё на нем делаем (исторически сложилось) — их хватает за глаза и за уши. а вот отсутствие компиляторов… и все доступные трансляторы с асма — тоже тупее пробки. и это обидно.
Отличная статья. Язык изложения четкий и последовательный, легко для понимания. Пишите еще, автор! По этой теме же есть еще много чего сказать. Например: возможность выполнить уже выбранные и декодированные команды без ущерба для времени реакции на прерывание; delay slots и иже с ними.
АРМы бывают разные. Например, когда случается исключение в Cortex-M4, в регистр адреса возврата сохраняется адрес, который в конце обработчика нужно вручную уменьшить на 8 и записать в PC, если требуется повторить команду, и на 4, если команду повторять не нужно. То есть вполне возможно, что в явном виде АСК там нет. При этом точные прерывания этот процессор поддерживает (да даже ARM7TDMI поддерживает — например, к нему можно прикрутить внешний MMU).
Интереснее было бы посмотреть на реализацию прерываний в Cortex-R или Cortex-A. Минимальная длина конвейера в этих процессорах — восемь стадий, в отличие от трехстадийных Cortex-M, и я не очень представляю, как они могли бы работать без АСК.
Я думаю, что для абстрагирования от длины конвейера(и для программной совместимости) в ARM всегда присуствует только 2 «зафиксированных» шага перед точкой выполнения инструкции.
Но было бы интересно услышать мнение эксперта.
В своё врем удивило, как на процессорах типа TI C6000 (которые конвеерные, и могут выполнять, например, четыре команды одновременно) выполняется обработка прерываний. Так как сохранить состояние процессора (когда каждая из выполняемых команд находится в «промежуточном» состоянии) мягко говоря, сложно — то используется такой трюк. Все циклы, которые должны выполнятся в конвейере — выполняются с запрещёнными прерываниями. Но что делать, если цикл будет слишком долгий? Значит, все какие циклы будут разбиты на двойные циклы — снаружи с последовательностью: запретили прерывания, выполнили конвейеризованный код, разрешили прерывания, а внутри — всё быстро и оптимизированно.
Этот подход поддерживается самим компилятором C/C++ — у него есть отдельный параметр командной строки, «сколько тактов он имеет право работать на запрещённых прерываниях».
Циклы, в общем, ни при чём — просто в них чаще используется конвейерная оптимизация. Оно и понятно: линейный код всё равно в кэш не попадает, его приходится читать по мере выполнения, и запихивать 8 команд в один такт большого смысла нет. А так, зависит от программиста, какой код писать — устойчивый к прерываниям, или нет. Принцип устойчивого кода — нельзя использовать старое значение регистра, если в конвейере уже выполняется команда, которая через какое-то время поменяет его значение (например, загрузка из памяти).
По теме внутреннего устройства процессоров есть хорошая книга «Computer Architecture, Fifth Edition: A Quantitative Approach (The Morgan Kaufmann Series in Computer Architecture and Design) (5th Edition), 2011».
Был еще курс на coursera, который читал David Wentzlaff из принстона но сейчас его оттуда почему-то убрали.
Прерывания в конвейеризированных процессорах