Skip to content

Лекция 8

Inspirate789 edited this page May 22, 2022 · 3 revisions

RISC-архитектура

Архитектура x86 относится к группе архитектур CISC.

Первые ПК создавались в эпоху, когда ЯВУ практически не было, 
поэтому люди стремились сделать как можно больше возможностей 
на аппаратном уровне (на уровне процессора), чтобы программисты, 
которые писали на ассемблере, могли пользоваться всеми аппаратными 
ресурсами ПК. Отсюда в x86 (начиная с 8086) базовый набор команд 
достаточно объёмный. Тут есть и строковые команды, и команды 
обработки упакованных двоично-десятичных чисел, и разнообразные 
арифметические команды, и разные способы адресации, и т.д.

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

И сейчас строковые команды такие

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

Другой вариант архитектуры, по которому позже пошли разработчики 
архитектуры ARM, - RISC...

Ранние архитектуры процессоров (комплексные, CISC (Complex instruction set computer)):

  • большее количество команд
  • разные способы адресации для упрощения написания программ на ассемблере
  • поддержка конструкций языков высокого уровня
    Недостатки: на практике многие возможности CISC используются компиляторами ЯВУ ограниченно, а их поддержка затратна.

RISC (reduced instruction set computer):

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

Семейство процессоров ARM

Свыше 90% рынка процессоров для мобильных устройств

ARMv1 – 1985 г. (примерно во времена процессора 80286)

Здесь есть понятия семейств процессоров, версий архитектуры и профайлов (направленность процессоров, т.е. то, подо что они заточены с точки зрения энергопотребления, производительности и т.д.).

Современные версии архитектуры - ARMv7, ARMv8.

Профайлы (обычно кодируются последней буквой в названии архитектуры):

  • Classic
  • Microcontroller
  • Real-time (специализирован под выполнение задач в режиме реального времени)
  • Application (самый распространённый, устанавливается в прикладных пользовательских устройствах)
Забегая вперёд в курс ОС:
Режимы реального времени делятся на 2 группы:
- Режимы мягкого реального времени: 
  для обработки звука или видео, т.е. воспроизведения файлов 
  с определённой скоростью без потерь и провалов. Если какие-то 
  потери всё-таки возникнут, то ничего страшного не произойдёт.
- Режимы жёсткого реального времени: что-то совсем строгое, где 
  требуется гарантированное время отклика, причём очень маленькое 
  (в пределах микросекунд). Требуется в каком-то оборудовании, где 
  нельзя потерять какой-то сигнал или не отдать вовремя команду 
  какому-нибудь приводу, потому что это может закончиться аварией.

Регистры общего назначения ARMv7:

  • R0-R12
  • R13SP (Stack Pointer)
  • R14LR (регистр связи) - используется при адресации и для быстрого вызова подпрограмм (см. далее)
  • R15PC (счётчик команд) - как IP, только не Instruction Pointer, а Program Counter
Вспомним защищённый режим в архитектуре x86, где нам необходимо 
сохранять регистры при переключении режима работы процессора на 
уровне ОС. Для аналогичных целей в архитектуре ARM (Семейство RISC), 
ввиду наличия в ней большего числа регистров, есть возможность 
физически раздваивать регистры.

Регистры R8R12 существуют в двух экземплярах:

  • для режима обработки быстрого прерывания (см. далее)
  • для остальных режимов Регистры LR и SP для каждого режима работы процессора свои (6-7 пар)

Режимы ARM

  • User mode — обычный режим выполнения программ (аналогично 3 кольцу защиты в x86). В этом режиме выполняется большинство программ.
  • Fast Interrupt (FIQ) — режим быстрого прерывания (меньшее время срабатывания).
  • Interrupt (IRQ) — основной режим прерывания.
  • System mode — защищённый режим для использования операционной системой. в нём работает ядро ОС.
  • Abort mode — режим, в который процессор переходит при возникновении ошибки доступа к памяти (доступ к данным или к инструкции на этапе prefetch конвейера). Аналогичен исключению в x86, возникающему при обращении к странице, которая выгружена из памяти.
  • Supervisor mode — привилегированный пользовательский режим.
  • Undefined mode — режим, в который процессор входит при попытке выполнить неизвестную ему инструкцию. По сути это исключение, если рассуждать в терминологии x86.

Наборы команд ARM

  • Базовый ARM (32-разрядные) - набор команд, созданный ещё в 1985
  • Thumb (16-разрядные, более производительные) - появились позже в целях оптимизации (занимают меньше места). По сути в них "завернули" базовые команды, частично ограничив их (присвоив им более короткие коды, в т.ч. за счёт сокращения операндов). Процессор выполняет их аналогично базовым, перекодировывая их "на лету".
  • Thumb2 (32-разрядные) - дополнение набора Thumb за счёт расширения до 32 бит и добавления новых команд
  • A64 (64-разрядные) - для 64-разрядных версий процессоров ARM. Речь о последнем поколении процессоров ARMv8, которое начало появляться с 2011 года (промышленные образцы появились позже)
В плане разрядности ARM отстаёт от x86 примерно на 10 лет.

Расширения ARM

  • VFP v1-v5 - аналог FPU в x86, предназначенный для работы с числами с плавающей запятой. Существует в разных версиях, которые чисто технически не особо отличаются как друг от друга, так и от FPU в x86
  • SIMD, NEON (Advanced SIMD), SVE - аналоги SSE/MMX в x86, предназначенные для поточной обработки данных
  • AES, SHA - расширения для работы с криптографией и хешами (поддержка быстрого шифрования)

Current Program Status Register (CPSR)

Аналогичен SR (Status Register) в x86.
Тут по сути состояние программы совмещено с регистром флагов (если рассуждать в терминологии x86). Тут флаги относятся к текущей программе и в отдельный регистр не выносятся. image
J (Jazelle bit) - технология, появившаяся в ARM-процессорах в последние годы, - аппаратная поддержка программ на языке Java на уровне процессора. Процессор помогает им выполняться и частично обрабатывает байт-код Java.

Это связано с тем, что процессоры ARM ставят в смартфоны, для которых 
большинство программ написано на Java (по крайней мере, если речь 
идёт об ОС Android). Поэтому разработчики железа решили развиваться 
в строну поддержки байт-кода Java на аппаратном уровне.

Быстрые (FIQ) и обычные (IRQ) прерывания

Fast interrupt - режим для быстрого получения данных от оборудования (сетевой карты, клавиатуры и т.д.), минимизирующий задержки:

  • скорость обработки выше (обрабатываются более легковесно);
  • допустима работа только одного обработчика единовременно (понятие реентерабельности не предусмотрено);
  • механизм используется для большинства аппаратных прерываний; Standart interrupt - все прочие прерывания (в т.ч. синхронные).

Команды ветвления B, BL, BLX

  • B (Branch) - переход (аналог JMP)
  • BL (Branch with link) - переход с сохранением адреса возврата в LR (что-то типа быстрого вызова процедуры), т.е. если мы не предполагаем рекурсии, а хотим куда-то прыгнуть и вернуться на место, то ARM даёт нам такую возможность
  • BLX - переход с переключением системы команд (Thumb, Thumb2 и т.д.)

Вызов программного прерывания

SWI (SoftWare Interrupt):

SWI immed_8 ; (0..255) - 256 возможных прерываний, как в x86

Переводит процессор в Supervisor mode, CPSR сохраняется в Supervisor Mode SPSR (специальный регистр привилегированного пользовательского режима), управление передаётся обработчику прерывания по адресу, который хранится в векторе прерываний.

Терминология другая, отличия [от x86] есть, но в целом идея 
низкоуровневого программирования похожа на то, что нам знакомо.

Архитектура VLIW. Эльбрус-8С

VLIW (Very Large Instruction Word) - продолжение идей RISC для многопроцессорных систем (когда в одном компьютере установлено несколько процессоров). Инструкции имеют большой размер (может доходить до десятков байт), так как в них явно (с множество параметров) указывается, что должно делать каждое ядро процессора.

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

Эльбрус-8С:

  • 8 ядер
  • в каждом ядре - 6 арифметико-логических каналов (здесь так называются устройства) со своими АЛУ и FPU, которые за один такт могут выполнять до 24 операций.
    Причём эти 6 каналов немного отличаются друг от друга по возможностям и функционалу, но базовые операции у них совпадают (складывать и вычитать умеют все).

Широкая команда Эльбруса

Широкая команда - набор элементарных операций, которые могут быть запущены на исполнение в одном такте.
Доступны:

  • 6 АЛУ (возможности различны)
  • Устройство передачи управления
  • 3 устройства для операций над предикатами (что-то типа битовых полей, т.е. регистров, которые интерпретируются как независимый набор битов, как регистр флагов в x86)
  • 6 квалифицирующих предикатов
  • 4 устройства асинхронного для команд чтения данных
  • 4 32-разрядных литерала (хранилища) для констант

Определяющие свойства архитектуры "Эльбрус"

  • Регистровый файл (рабочие регистры) - 256 регистров (32 для глобальных данных и 224 для стека процедур)
    • механизм регистровых окон: вызывающая подпрограмма из доступного ей окна (среди регистров в стеке процедур) выделяет вызываемой область в своём регистровом окне, т.е. отдаёт часть регистров своего окна; на начало такого окна указывает регистр WD
    • пространство регистров подвижной базы - пространство в текущем окне, на начало которого указывает регистр BR
  • Предикатный файл - 32 регистра со значениями true/false
  • Подготовка передачи управления (disp) - подготовка к переходам при ветвлении для исключения задержек выполнения программы, т.е. здесь мы не просто вызываем какую-то подпрограмму, а с помощью специальных команд готовим ветвление
  • Асинхронный доступ к массивам (можно провести параллель с SSE в x86, где мы можем обрабатывать массивы параллельно, но в рамках базовых команд и асинхронно)
Здесь вызов подпрограмм реализован не через стек в памяти, а 
через регистровый стек (организация подобна стеку регистров 
**FPU** **x86**), который так же поддерживает какую-то 
цепочку вызовов или рекурсию.

Я:  В чём идея 224 регистров стека процедур? Если нужно 
    больше вызовов, то как быть?)
ДА: Я под Эльбрус не программировал, не скажу. Наверное, 
    надо предполагать, что если потребуется более глубокая 
    рекурсия, то всё-таки задействуется память как-то.
Я:  Допустим)
ДА: Здесь имеется в виду какой-то основной режим работы 
    всё-таки. Ну или как-то надо выкручиваться ...

***
На сайте Эльбруса есть хорошая и доступная документация с описанием архитектуры.
...
"У них там своя какая-то система, свой какой-то там Linux. 
Из того, что рассказывали, помню идею о том, что можно там 
что-то параллельно выполнять (пытались прикладные программы 
параллельно запускать) и, условно, к одному системному 
блоку подключать сразу несколько мониторов, клавиатур и 
мышек и организовывать таким образом несколько рабочих мест 
на базе одной системы (одного системного блока)."
...
"Про производительность "Эльбрусов" очень много написано 
в интернете. На Хабре несколько статей было, где её 
в общем-то разносили в том плане, что это совершенно другая 
архитектура и обычные программы под неё эффективно 
скомпилировать очень сложно. Разработчики работают над 
созданием эффективного компилятора, но за счёт того, что 
архитектура в принципе перпендикулярна привычным для нас, 
то по каким-то общим тестам ничего хорошего пока не 
получается, хотя отдельные успехи есть..."
"А вообще, зачем такая архитектура? 
Откуда она появилась? 
Для чего такие инструкции? 
Зачем столько арифметико-логических каналов? ..."

"... Когда мы учились [на военной кафедре], лет 15 назад, 
нас учили для противоракетной обороны. ... . Было такое 
большое здание, был отдельный пункт наблюдения (управления), 
..., и всем этим управлял ещё советский компьютер 80-х годов, 
который представлял из себя несколько шкафов. Он , конечно, 
был уже не ламповый, а на транзисторах, но всё равно занимал 
большой машинный зал. Из отдельных ящичков платы выдвигались, 
заменялись ... 

Лет 15 назад ещё не паяли ничего, 
не ремонтировали в таком режиме. Но тогда уже переводили 
управление со старых "Эльбрусов" (Эльбрус-2) на новые.

Эльбрус - это (изначально) военная машина, предназначенная 
для управления большими боевыми системами (имеются в виду 
не те, которые на колёсах, а стационарные, предназначенные 
для наблюдения за чем-нибудь). Тогда их переводили на 
Эльбрус-90 МИКРО. Это персональная машина на базе Эльбрус-4 
(но это не точно). То есть примерно лет 10-15 назад от этих 
шкафов отказались, и чуть позже появились Эльбрус-8. 

Соответственно, раз у них изначально было военное назначение, 
то там специфика своя. Там нужно в режиме реального времени 
обсчитывать большие массивы различных чисел с большой точностью. 

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

Если так на это посмотреть, то становится понятно, почему здесь 
столько арифметико-логических каналов и сопроцессоров и почему 
нужны такие широкие инструкции. Они хорошо ложатся на задачи, 
где нужно много считать. А на какие-то прикладные/бытовые 
задачи (например, офисного пакета) это уже ложится не очень 
хорошо."

Java. Java virtual machine (JVM)

Переходим от аппаратного уровня к другим областям, где мы можем встретить слово "ассемблер".

Java - объектно-ориентированный язык программирования, разработанный компанией Sun Microsystems.

Приложения Java обычно транслируются не в машинный код, а в специальный (промежуточный) байт-код, поэтому они могут работать на любой компьютерной архитектуре, для которой существует реализация виртуальной Java-машины.
То есть программу можно скомпилировать на одном компьютере и перенести её бинарник на любой другой компьютер, независимо от того, какой процессор там используется и какая ОС там стоит.
Так можно делать за счёт того, что на целевой системе тоже будет виртуальная машина Java, которая этот байт-код будет выполнять. Получается, задачу "прослойки" (когда нужно скомпилировать программу под конкретную архитектуру) между программой и конкретным железом здесь выполняет не компилятор, а виртуальная машина Java, которая байт-код выполняет так, чтобы он работал на текущем конкретном компьютере.

Байт-код Java — набор инструкций, исполняемых виртуальной машиной Java (а не процессором). Каждый код операции байт-кода — один байт.

Группы инструкций:

  • загрузка и сохранение (например, ALOAD_0, ISTORE),
  • арифметические и логические операции (например, IADD, FCMPL),
  • преобразование типов (например, I2B, D2I),
  • создание и преобразование объекта (например, NEW, PUTFIELD),
  • управление стеком (например, DUP, POP),
  • операторы перехода (например, GOTO, IFEQ),
  • вызовы методов и возврат (например, INVOKESTATIC, IRETURN).
    javap - дизассемблер файлов классов Java. Эта штатная утилита идёт вместе с Java.
    Дальше мы посмотрели страницу с документацией.

Платформа .NET. CLR, CIL

.NET (2002) - платформа, основанная на CLR (Common Language Runtime, общеязыковая исполняющая среда).

CLR — исполняющая среда для байт-кода CIL (MSIL), в которой компилируются программы, написанные на .NET-совместимых языках программирования.

CIL (Common Intermediate Language) — «высокоуровневый ассемблер» виртуальной машины .NET, основанный на работе со стеком.

ldloc.0    // push local variable 0 onto stack
ldloc.1    // push local variable 1 onto stack
add        // pop and add the top two stack items then push the result 
           // onto the stack
stloc.0    // pop and store the top stack item to local variable 0

ildasm, ilasm - дизассемблер/ассемблер промежуточного языка (intermediate language)

WebAssembly (wasm)

WebAssembly — это бинарный формат инструкций (исполняются браузером) для стековой виртуальной машины, предназначенной для компиляции программ на ЯВУ (C, C++, C#, Go, TypeScript/AssemblyScript, Kotlin, Pascal, Rust, D, Erlang) для WEB.

Благодаря WebAssembly мы можем писать код для браузеров, для web-приложений (на стороне клиента) не на JavaScript, который браузеры по умолчанию понимают, а на других языках высокого уровня.

Пример:

image

Clone this wiki locally