Если вы новичок в экосистеме Arm, то считайте это кратким введением в терминологию, которую вы могли видеть раньше, но понимаете не до конца.
Архитектура Arm — это семейство архитектур с набором упрощённых команд (Reduced Instruction Set Architecture, RISC) с режимами простой адресации. Обработка данных выполняется над регистровыми операндами, в противном случае используются загрузки и сохранения для перемещения данных в регистры и из них.
Arm Limited — это британская компания, занимающаяся разработкой и поддержкой архитектуры Arm.
ARM — это устаревшая аббревиатура Acorn RISC Machine, а позже — Advanced RISC Machines. Как мы увидим ниже, в случае развития архитектуры предыдущую терминологию иногда переименовывают.
The Arm Architectural Reference Manual for A-profile architecture, также называемое Arm ARM — это главное руководство по программированию архитектуры. Если вы что-то делаете с Arm, то, вероятно, держите под рукой этот документ.
Armv9 — это самое новое семейство архитектуры, в которое добавлены такие возможности, как новые масштабируемые векторные SIMD (SVE2) и матричные (SME/SME2) операции, а также функциональность трассировок.
Armv9.4-A — это последний набор расширений Armv9. Эти расширения задокументированы в Arm ARM. Некоторые расширения были опциональными при их внедрении, а многие стали обязательными в дальнейших ревизиях.
A в Armv9-A обозначает «Application Profile». Этот профиль поддерживает виртуальную память при помощи блоков управления памятью; скорее всего, вы обнаружите его в любых системах Arm, будь то телефон, ноутбук или сервер. Также есть профиль «R» для приложений с требованиями системы реального времени и профили «M», которые чаще всего используют в микроконтроллерах, где отсутствуют блоки управления памятью. A, R и M — это три архитектурных профиля.
AArch64 — это режим исполнения, ставший одним из самых серьёзных дополнений с появления ARMv8; он добавил поддержку 64-битных регистров (31 регистр общего назначения, специализированный 64-битный указатель стека, 64-битный счётчик команд, запись в который возможна только ветвлением или исключениями, а также имеющий нулевое значение псевдорегистра) и адресации. В то же время был создан режим исполнения AArch32 для работы с 32-битной легаси-функциональностью, знакомой разработчикам по ARMv7 (15 32-битных регистров общего назначения, отсутствующий SP, PC с возможностью записи).
Любопытно, что в Arm ARM не упоминается термин ARM64; похоже, его предпочитают Apple, Microsoft и Линус Торвальдс. В конечном итоге, это название логично: порт ядра Linux arm64 может исполнять код пользовательского пространства в режимах исполнения AArch64 или AArch32, хотя само ядро исключительно для AArch64).
Если вы хотите узнать о стандартах вызовов (то есть о том, каким регистрам передаются аргументы), применяемых в этих системах Arm, то можете прочитать Procedure Call Standard for the Arm Architecture (AAPCS), который опубликован с другой документацией, относящейся к ABI, здесь. После этой публикации предыдущие стандарты APCS и TPCS стали устаревшими. Платформы Apple определённым образом отклоняются от Arm ABI. У Microsoft тоже есть документация (начинающаяся с удобного списка определений, похожего на мой пост) по ABI компании для Windows.
A64 — это набор команд, добавленный в AArch64. На самом деле, это единственный набор команд, поддерживаемый AArch64. Хотя регистры в режиме исполнения AArch64 являются 64-битными, сами команды всё равно только 32-битные (фиксированной ширины). Теперь под A32 подразумевается старая ISA, которая тоже имела фиксированную 32-битную ширину, а под T32 подразумеваются смешанные 32-битные и 16-битные команды Thumb2. Возможно, вы знакомы с этими ISA, если работали с ARMv7 или более старыми устройствами. A64 разрывает связи с A32, это похожая, но иная ISA. Например, в A64 гораздо меньше команд с поддержкой предикации, чем в A32.
Ядро часто называют A78 или более формально Cortex-A78, не стоит путать это с A64. Arm проектирует архитектуру не только Arm, но и реализаций архитектуры, которые мы называем микроархитектурами. Часто упоминаются термины Cortex или
Neoverse, сопровождаемые числом, это спроектированные Arm микроархитектуры архитектуры Arm. Например, Cortex-A78 реализует расширения вплоть до ARMv8.3. В Википедии есть шаблон, являющийся кратким справочником по последним микроархитектурам Arm. Прежде чем подробнее говорить о микроархитектурах Arm, нужно обсудить топологии. DynamIQ (а до неё big.LITTLE) создана на основе идеи использования в многоядерных системах гетерогенных (разных) ядер вместо гомогенных (схожих) ядер. Не уверен, можно ли по-прежнему называть это симметричной многопроцессорностью. Преимущество такого дизайна заключается в хорошей гибкости в разных задачах в различное время. Когда нам нужно повысить производительность, мы хотим использовать мощные и энергозатратные процессоры out-of-order, но для снижения энергопотребления нам могут понадобиться более медленные ядра in-order (это позволит увеличить время работы от аккумулятора). Любопытно, что Intel делает нечто смутно похожее, внедрив производительные и эффективные ядра в свою микроархитектуру Alder Lake.
Изучив руководства Technical Reference Manual, опубликованные Arm для различных микроархитектур, мы можем наблюдать интересную эволюцию поддержки разных режимов исполнения относительно различных уровней исключений.
- A55: режимы исполнения AArch32 и AArch64 находятся на всех уровнях исключений (с EL0 по EL3).
- X1: режим исполнения AArch32 находится только на уровне исключений EL0. Режим исполнения AArch64 находится на всех уровнях исключений (с EL0 по EL3)
- X3: режим исполнения AArch64 находится на всех уровнях исключений, с EL0 по EL3. [То есть отсутствует поддержка AArch32.]
Если бы SoC состояла из гетерогенных ядер с разными уровнями поддержки AArch32, то это накладывало бы интересные ограничения на планировщик процессов операционной системы; невозможно запустить программу AArch32 в ядре, которое её не поддерживает!
Ниже представлены чуть более устаревшие термины. Если вы поддерживаете старые системы, они могут быть для вас релевантны.
ARM9 (не путать с версией архитектуры Armv9) — это семейство ядер, часть из которых реализует ARMv4t, а некоторые ARMv5.
StrongARM — это серия процессоров ARMv4, разработанная Digital Equipment Corporation; Intel приобрела эту интеллектуальную собственность в рамках судебного разбирательства и позже разработала собственную микроархитектуру ARMv5 под названием XScale. В конечном итоге Intel продала семейство SoC PXA, использовавшее XScale, компании Marvell. Можно пофантазировать, каким бы был мир, если бы Intel продолжила развивать XScale параллельно с Atom или вместо него.
ARMv4t привнесла набор сжатых команд под названием Thumb. Команды имели фиксированную 16-битную ширину (тем не менее, существовали и странности, например BL и BLX на самом деле кодировались как пара 16-битных команд; реализациям необходимо было обращать внимание на правильность работы возвратов исключений на случай, если исключение происходит посередине пары).
В ARMv6t2 появилась Thumb2, добавившая новые команды, в том числе команды шириной 32 бита для поддержки более широких immediate, новые суффиксы команд, чтобы различать узкие и широкие кодировки, а также Unified Assembly Language (UAL), который упростил написание ассемблерного кода, валидного на Arm или в режиме Thumb. Однако из-за этого Thumb больше не имел фиксированной ширины. Из-за внедрения режимов исполнения вместе с ARMv8 набор команд Thumb был переименован T32; когда эти команды только появились, термина T32 ещё не существовало!
Возможно, вам встретится термин aarch64be, используемый в контексте тулчейнов, он относится к big-endian. Arm поддерживал big-endian и little-endian со времён ARMv4, однако большинство платформ сегодня использует Arm в конфигурации little-endian. Big-endian чаще используется в сетевых устройствах, так как сетевой порядок байтов — это BE. -mlittle-endian
и -mbig-endian
— это флаги компилятора, которые можно использовать для управления генерацией кода. ARMv4 и v5 поддерживают порядок байтов шины BE-32. Код, скомпонованный с флагом --be32
, создавал код и данные в формате big-endian. В ARMv6 появился новый порядок байтов шины под названием BE-8. Флаг --be8
создавал код little-endian и данные big-endian (компилятор выдавал код big-endian для релоцируемых файлов при сборке с флагом -big-endian
, а затем компоновщик преобразовывал их в little endian при использовании --be8
. Это позволяло компиляторам ценой повышения сложности компоновщика не беспокоиться о переворачивающем порядок байтов коде, вне зависимости от используемого порядка байтов шины). У ARMv6 имелись оба порядка байтов шины, и BE-32, и BE-8 (более старый BE-32 стал опциональным), однако в ARMv7 поддержка BE-32 была убрана. В этом посте показано, почему BE-8 заменил BE-32; он упрощал поддержку систем с обоими форматами endian, если мы использовали команды little endian, а шина памяти при доступе изменяла порядок байтов. ELF использует идентификаторы форматов файлов elf64-littleaarch64, elf64-bigaarch64, elf32-littlearm и elf32-bigarm; однако эти идентификаторы не используются в ELF for the Arm {64-bit} Architecture.
Итак, это был краткий глоссарий распространённых терминов, связанных с экосистемой Arm. В следующем посте мы рассмотрим такие термины, как VFP, Neon, OABI и EABI, но пока этого достаточно.
Огромная благодарность моим друзьям Питеру Смиту, Кристофу Бейлсу и Марку Брауну из Arm, Арнду Бергманну из Linaro и Арду Бешовелю из Google за вычитку черновиков поста и полезные отзывы. По случайности, пока я редактировал этот пост, мой друг и коллега Фангри Сонг опередил меня, выпустив ещё один потрясающий пост, касающийся очень похожих тем.